import { Permission, ProjectRoles } from "@vertesia/common" import { ErrorBox, useFetch } from "@vertesia/ui/core" import { UserSession, useUserSession } from "@vertesia/ui/session" import { createContext, useContext, useMemo } from "react" import { useUITranslation } from '../../i18n/index.js'; import { isAnyOf } from "./helpers" type ListRolesResponse = { name: ProjectRoles, permissions: Permission[] }[]; export class UserPermissions { system_roles: ListRolesResponse; // all roles defined in the system roles: Set; // all roles of the current user permissions: Set; // all permissions of the current user constructor(session: UserSession, roles: ListRolesResponse) { if (!session.authToken) { throw new Error('No auth token found in user session') } this.system_roles = roles; const userRoles = new Set(session.authToken.account_roles || []); if (session.authToken.project_roles) { for (const role of session.authToken.project_roles) { userRoles.add(role); } } this.roles = userRoles; // build a temporary role to permissions map const map: Record = {}; for (const role of roles) { map[role.name] = role.permissions; } const permissions = new Set(); for (const role of userRoles) { const rolePermissions = map[role]; if (rolePermissions) { for (const permission of rolePermissions) { permissions.add(permission); } } } this.permissions = permissions; } hasPermission(permission: string | string[]) { if (typeof permission === 'string') { return this.permissions.has(permission); } else if (isAnyOf(permission as Permission[])) { return permission.some(p => this.permissions.has(p)); } else { // all of for (const p of permission) { if (!this.permissions.has(p)) { return false; } } return true; } } } const UserPermissionsContext = createContext(undefined) export { UserPermissionsContext } export function useUserPermissions() { const perms = useContext(UserPermissionsContext); if (!perms) { throw new Error('UserPermissionContext cannot be used outside UserPermissionProvider') } return perms; } interface UserPermissionProviderProps { children: React.ReactNode } export function UserPermissionProvider({ children }: UserPermissionProviderProps) { const { t } = useUITranslation(); const session = useUserSession(); const { data, error, isLoading } = useFetch(() => { if (session.user) { return session.client.iam.roles.list(); } else { return Promise.resolve(undefined); } }, [session.user]); const perms = useMemo(() => { if (session.authToken && data && !isLoading) { return new UserPermissions(session, data); } else { return undefined; } }, [session, data, isLoading]); if (error) { return {error.message} } return perms && ( {children} ) }