44 lines
1.5 KiB
TypeScript
44 lines
1.5 KiB
TypeScript
import { Role } from "@/types/types";
|
|
|
|
type PermissionResult<T extends Record<string, readonly string[]>> = {
|
|
[K in keyof T]: {
|
|
[A in T[K][number]]: boolean;
|
|
} & { all: boolean }; // Per-resource 'all'
|
|
} & { all: boolean }; // Global 'all'
|
|
|
|
// hasPermissions function with 'all' flags
|
|
export default function hasPermissions<
|
|
T extends Record<string, readonly string[]>,
|
|
>(roles: Role[], permissions: T): PermissionResult<T> {
|
|
// Build permissions set
|
|
const permissionsSet: Map<string, null> = new Map();
|
|
for (const role of roles) {
|
|
if (!role.permissions) continue;
|
|
for (const perm of role.permissions) {
|
|
const key = `${perm.resource}:${perm.action}`;
|
|
permissionsSet.set(key, null);
|
|
}
|
|
}
|
|
|
|
// Build result
|
|
const result = { all: true } as PermissionResult<T>; // Initialize global 'all' as true
|
|
let globalAll = true; // Track global state
|
|
|
|
for (const resource in permissions) {
|
|
const actions = permissions[resource];
|
|
let resourceAll = true; // Track per-resource state
|
|
|
|
result[resource] = { all: true } as any; // Initialize resource object
|
|
for (const action of actions) {
|
|
const hasPerm = permissionsSet.has(`${resource}:${action}`);
|
|
(result[resource] as Record<string, boolean>)[action] = hasPerm;
|
|
resourceAll = resourceAll && hasPerm; // Update resource 'all'
|
|
}
|
|
result[resource].all = resourceAll; // Set resource 'all'
|
|
globalAll = globalAll && resourceAll; // Update global 'all'
|
|
}
|
|
|
|
result.all = globalAll; // Set global 'all'
|
|
return result as PermissionResult<T>;
|
|
}
|