Files
basic-erp/apps/web/src/app/features/admin/permissions-model.ts
T

56 lines
2.3 KiB
TypeScript
Raw Normal View History

import { type MenuModule, isPathAllowed } from '@basic-erp/sap-types';
/** Lo que el administrador marca en pantalla para un usuario. */
export interface Selection {
/** Acceso total (`*`). */
all: boolean;
/** Rutas de menú marcadas (incluye las cubiertas por un patrón `/modulo/*`). */
paths: ReadonlySet<string>;
/** Patrones que no corresponden a ninguna pantalla actual (ej. de una versión futura): se conservan tal cual. */
extras: readonly string[];
}
/** Módulos que se otorgan con casillas; "Administración" solo llega con acceso total. */
export const grantableModules = (menu: readonly MenuModule[]): readonly MenuModule[] => menu.filter((m) => m.id !== 'admin');
export function toSelection(patterns: readonly string[], menu: readonly MenuModule[]): Selection {
const all = patterns.includes('*');
const known = menu.flatMap((m) => m.items.map((i) => i.path));
const paths = new Set(known.filter((p) => !all && isPathAllowed(patterns, p)));
const extras = patterns.filter((p) => p !== '*' && !known.some((k) => isPathAllowed([p], k)));
return { all, paths, extras };
}
/**
* Patrones a guardar: `*` si es acceso total; si no, `/modulo/*` cuando están todas las pantallas
* del módulo y rutas sueltas en otro caso, más los patrones desconocidos conservados.
*/
export function toPatterns(sel: Selection, menu: readonly MenuModule[]): string[] {
if (sel.all) return ['*'];
const out: string[] = [];
for (const m of grantableModules(menu)) {
const checked = m.items.filter((i) => sel.paths.has(i.path));
if (checked.length === m.items.length && m.items.length > 0) out.push(`/${m.id}/*`);
else out.push(...checked.map((i) => i.path));
}
return [...out, ...sel.extras];
}
export function togglePath(sel: Selection, path: string, on: boolean): Selection {
const paths = new Set(sel.paths);
if (on) paths.add(path);
else paths.delete(path);
return { ...sel, paths };
}
export function toggleModule(sel: Selection, module: MenuModule, on: boolean): Selection {
const paths = new Set(sel.paths);
for (const i of module.items) {
if (on) paths.add(i.path);
else paths.delete(i.path);
}
return { ...sel, paths };
}
export const samePatterns = (a: readonly string[], b: readonly string[]): boolean =>
a.length === b.length && [...a].sort().every((p, i) => p === [...b].sort()[i]);