Spaces:
Build error
Build error
| /** | |
| * Access Control List utility functions for role-based permissions | |
| * @import { UserData } from '../plugins/authentication.js' | |
| */ | |
| import { getFileDataById } from './file-data-utils.js' | |
| /** | |
| * Checks if user has one or more specific roles | |
| * @param {UserData|null} user - User object | |
| * @param {string|string[]} role - Role name or array of role names | |
| * @returns {boolean} | |
| * @note If user has "*" in their roles array, they match any role check | |
| */ | |
| export function userHasRole(user, role) { | |
| if (!user || !user.roles) { | |
| return false | |
| } | |
| // Wildcard "*" in user's roles grants access to any role check | |
| if (user.roles.includes('*')) { | |
| return true | |
| } | |
| if (Array.isArray(role)) { | |
| return role.some(r => user.roles.includes(r)) | |
| } | |
| return user.roles.includes(role) | |
| } | |
| /** | |
| * Checks if user has all specified roles | |
| * @param {UserData|null} user - User object | |
| * @param {string[]} roles - Array of role names | |
| * @returns {boolean} | |
| * @note If user has "*" in their roles array, they match any role check | |
| */ | |
| export function userHasAllRoles(user, roles) { | |
| if (!user || !user.roles || !Array.isArray(roles)) { | |
| return false | |
| } | |
| // Wildcard "*" in user's roles grants access to any role check | |
| if (user.roles.includes('*')) { | |
| return true | |
| } | |
| return roles.every(role => user.roles.includes(role)) | |
| } | |
| /** | |
| * Checks if user is an admin | |
| * @param {UserData|null} user - User object | |
| * @returns {boolean} | |
| */ | |
| export function userIsAdmin(user) { | |
| return userHasRole(user, 'admin') | |
| } | |
| /** | |
| * Checks if user owns a resource | |
| * @param {UserData|null} user - User object | |
| * @param {string|null} owner - Owner username | |
| * @returns {boolean} | |
| */ | |
| export function userOwnsResource(user, owner) { | |
| if (!user || !owner) { | |
| return false | |
| } | |
| return user.username === owner | |
| } | |
| /** | |
| * Checks if user can access a resource based on ownership or admin privileges | |
| * @param {UserData|null} user - User object | |
| * @param {string|null} owner - Resource owner username | |
| * @returns {boolean} | |
| */ | |
| export function userCanAccessOwnedResource(user, owner) { | |
| return userIsAdmin(user) || userOwnsResource(user, owner) | |
| } | |
| /** | |
| * Gets all roles for a user as an array | |
| * @param {UserData|null} user - User object | |
| * @returns {string[]} | |
| */ | |
| export function getUserRoles(user) { | |
| return user?.roles || [] | |
| } | |
| /** | |
| * Checks if user has any roles at all | |
| * @param {UserData|null} user - User object | |
| * @returns {boolean} | |
| */ | |
| export function userHasAnyRole(user) { | |
| return (user?.roles?.length ?? 0) > 0 | |
| } | |
| /** | |
| * Filters an array of roles to only include those the user has | |
| * @param {UserData|null} user - User object | |
| * @param {string[]} roles - Array of role names to filter | |
| * @returns {string[]} | |
| */ | |
| export function filterUserRoles(user, roles) { | |
| if (!user || !user.roles || !Array.isArray(roles)) { | |
| return [] | |
| } | |
| return roles.filter(role => user.roles.includes(role)) | |
| } | |
| /** | |
| * Creates a permission checker function for a specific role | |
| * @param {string} role - Role name | |
| * @returns {function(UserData|null): boolean} | |
| */ | |
| export function createRoleChecker(role) { | |
| return (user) => userHasRole(user, role) | |
| } | |
| /** | |
| * Creates a permission checker function for multiple roles (OR logic) | |
| * @param {string[]} roles - Array of role names | |
| * @returns {function(UserData|null): boolean} | |
| */ | |
| export function createAnyRoleChecker(roles) { | |
| return (user) => userHasRole(user, roles) | |
| } | |
| /** | |
| * Creates a permission checker function for multiple roles (AND logic) | |
| * @param {string[]} roles - Array of role names | |
| * @returns {function(UserData|null): boolean} | |
| */ | |
| export function createAllRolesChecker(roles) { | |
| return (user) => userHasAllRoles(user, roles) | |
| } | |
| /** | |
| * Checks if user has reviewer role | |
| * @param {UserData|null} user - User object | |
| * @returns {boolean} | |
| */ | |
| export function userHasReviewerRole(user) { | |
| if (!user) return false | |
| return userHasRole(user, 'reviewer') | |
| } | |
| /** | |
| * Checks if user has annotator role | |
| * @param {UserData|null} user - User object | |
| * @returns {boolean} | |
| */ | |
| export function userHasAnnotatorRole(user) { | |
| if (!user) return false | |
| return userHasRole(user, 'annotator') | |
| } | |
| /** | |
| * Checks if a file hash represents a gold file | |
| * @param {string} hash - The file hash identifier | |
| * @returns {boolean} | |
| */ | |
| export function isGoldFile(hash) { | |
| if (!hash) return false | |
| try { | |
| const fileData = getFileDataById(hash) | |
| if (!fileData) return false | |
| // For artifacts, check is_gold_standard property | |
| if (fileData.type === 'artifact') { | |
| return fileData.item.is_gold_standard === true | |
| } | |
| return false | |
| } catch (error) { | |
| console.warn(`Error checking if file is gold: ${String(error)}`) | |
| return false | |
| } | |
| } | |
| /** | |
| * Checks if a file hash represents a version file | |
| * @param {string} hash - The file hash identifier | |
| * @returns {boolean} | |
| */ | |
| export function isVersionFile(hash) { | |
| if (!hash) return false | |
| try { | |
| const fileData = getFileDataById(hash) | |
| if (!fileData) return false | |
| // For artifacts, check that it's NOT a gold standard (i.e., it's a version) | |
| if (fileData.type === 'artifact') { | |
| return fileData.item.is_gold_standard === false | |
| } | |
| return false | |
| } catch (error) { | |
| console.warn(`Error checking if file is version: ${String(error)}`) | |
| return false | |
| } | |
| } | |
| /** | |
| * Checks if user can edit a document based on permissions and file type | |
| * @param {UserData|null} user - Current user object | |
| * @param {{visibility: string, editability: string, owner: string|null}} permissions - Document permissions | |
| * @param {string} [fileId] - Optional file ID to check file type restrictions | |
| * @returns {boolean} | |
| */ | |
| export function canEditDocumentWithPermissions(user, permissions, fileId) { | |
| if (!user) { | |
| return false | |
| } | |
| // Admin users can edit everything | |
| if (userIsAdmin(user)) { | |
| return true | |
| } | |
| // Check role-based file type restrictions | |
| if (fileId) { | |
| if (isGoldFile(fileId) && !userHasReviewerRole(user)) { | |
| return false | |
| } | |
| if (isVersionFile(fileId) && !userHasAnnotatorRole(user) && !userHasReviewerRole(user)) { | |
| return false | |
| } | |
| } | |
| // Check visibility permissions ('collection' or 'owner') | |
| if (permissions.visibility === 'owner' && permissions.owner !== user.username) { | |
| // Reviewers can still view owner-only documents | |
| if (!userHasReviewerRole(user)) { | |
| return false | |
| } | |
| } | |
| // Check editability permissions ('collection' or 'owner') | |
| if (permissions.editability === 'owner' && permissions.owner !== user.username) { | |
| // In owner-only editability, only owner can edit (reviewers cannot to prevent accidental overwriting) | |
| return false | |
| } | |
| return true | |
| } | |
| /** | |
| * Checks if user can view a document based on permissions | |
| * @param {UserData|null} user - Current user object | |
| * @param {{visibility: string, owner: string|null}} permissions - Document permissions | |
| * @returns {boolean} | |
| */ | |
| export function canViewDocumentWithPermissions(user, permissions) { | |
| // Admin users can view everything | |
| if (user && userIsAdmin(user)) { | |
| return true | |
| } | |
| // Reviewers can view everything | |
| if (user && userHasReviewerRole(user)) { | |
| return true | |
| } | |
| // Collection-visible documents can be viewed by anyone with collection access | |
| if (permissions.visibility === 'collection') { | |
| return true | |
| } | |
| // Owner-only documents only viewable by owner | |
| if (permissions.visibility === 'owner') { | |
| if (!user) return false | |
| return permissions.owner === user.username | |
| } | |
| return false | |
| } | |
| /** | |
| * Checks if user can edit a file based on access control metadata | |
| * @param {UserData|null} user - Current user object | |
| * @param {string} fileId - The file identifier (hash) | |
| * @returns {boolean} | |
| */ | |
| export function canEditFile(user, fileId) { | |
| try { | |
| if (!user) { | |
| return false | |
| } | |
| // Admin users can edit everything | |
| if (userIsAdmin(user)) { | |
| return true | |
| } | |
| // Check role-based file type restrictions | |
| if (isGoldFile(fileId) && !userHasReviewerRole(user)) { | |
| return false | |
| } | |
| if (isVersionFile(fileId) && !userHasAnnotatorRole(user) && !userHasReviewerRole(user)) { | |
| return false | |
| } | |
| // Get file metadata for additional access control checks | |
| const fileData = getFileDataById(fileId) | |
| if (!fileData || fileData.type === 'source' || !('metadata' in fileData.item) || !fileData.item.metadata?.access_control) { | |
| // No metadata found or no access control info - role-based restrictions already checked above | |
| console.debug('No access control metadata found for file') | |
| return true | |
| } | |
| const { visibility, editability, owner } = fileData.item.metadata.access_control | |
| // Check visibility permissions ('collection' or 'owner') | |
| if (visibility === 'owner' && owner !== user.username) { | |
| if (!userHasReviewerRole(user)) { | |
| return false | |
| } | |
| } | |
| // Check editability permissions ('collection' or 'owner') | |
| if (editability === 'owner' && owner !== user.username) { | |
| // In owner-only editability, only owner can edit | |
| return false | |
| } | |
| return true | |
| } catch (error) { | |
| console.warn(`Error checking file access permissions: ${String(error)}`) | |
| // Default to allowing edit on error to avoid breaking functionality | |
| return true | |
| } | |
| } |