mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
110 lines
3.1 KiB
TypeScript
110 lines
3.1 KiB
TypeScript
import { ForbiddenException } from '@nestjs/common';
|
|
import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type';
|
|
|
|
import { FREIGHT_PERMS } from '../seed/freight-permissions.registry';
|
|
|
|
const SUPER_ADMIN_ROLE = 'super_admin';
|
|
const ORGANIZATION_ADMIN_ROLE = 'organization_admin';
|
|
|
|
type PermissionLike = { key?: string };
|
|
type MeLikeUser = {
|
|
roles?: { key?: string }[];
|
|
permissions?: PermissionLike[];
|
|
employee?:
|
|
| {
|
|
position?: { permissions?: PermissionLike[] };
|
|
delegatedPositions?: { permissions?: PermissionLike[] }[];
|
|
}
|
|
| {
|
|
positions?: { permissions?: PermissionLike[] }[];
|
|
}[]
|
|
| null;
|
|
};
|
|
|
|
export function isSuperAdmin(user: MeLikeUser | null | undefined): boolean {
|
|
if (!user?.roles?.length) return false;
|
|
return user.roles.some((r) => r.key === SUPER_ADMIN_ROLE);
|
|
}
|
|
|
|
export function isOrganizationAdmin(user: MeLikeUser | null | undefined): boolean {
|
|
if (!user?.roles?.length) return false;
|
|
return user.roles.some((r) => r.key === ORGANIZATION_ADMIN_ROLE);
|
|
}
|
|
|
|
export function isFreightApprovalAdmin(user: MeLikeUser | null | undefined): boolean {
|
|
return isSuperAdmin(user) || isOrganizationAdmin(user);
|
|
}
|
|
|
|
/** Flat permission keys from JWT / session user (roles + position permissions). */
|
|
export function collectPermissionKeys(user: MeLikeUser | null | undefined): string[] {
|
|
if (!user) return [];
|
|
|
|
const keys = new Set<string>();
|
|
|
|
for (const p of user.permissions ?? []) {
|
|
if (p.key) keys.add(p.key);
|
|
}
|
|
|
|
const employee = user.employee;
|
|
if (!employee) {
|
|
return [...keys];
|
|
}
|
|
|
|
if (Array.isArray(employee)) {
|
|
for (const emp of employee) {
|
|
for (const pos of emp.positions ?? []) {
|
|
for (const p of pos.permissions ?? []) {
|
|
if (p.key) keys.add(p.key);
|
|
}
|
|
}
|
|
}
|
|
return [...keys];
|
|
}
|
|
|
|
for (const p of employee.position?.permissions ?? []) {
|
|
if (p.key) keys.add(p.key);
|
|
}
|
|
for (const delegated of employee.delegatedPositions ?? []) {
|
|
for (const p of delegated.permissions ?? []) {
|
|
if (p.key) keys.add(p.key);
|
|
}
|
|
}
|
|
|
|
return [...keys];
|
|
}
|
|
|
|
export function hasFreightPermission(
|
|
user: MeLikeUser | null | undefined,
|
|
permissionKey: string,
|
|
): boolean {
|
|
if (!user) return false;
|
|
if (isSuperAdmin(user)) return true;
|
|
return collectPermissionKeys(user).includes(permissionKey);
|
|
}
|
|
|
|
export function assertFreightPermission(
|
|
user: TCurrentUser | MeLikeUser | null | undefined,
|
|
permissionKey: string,
|
|
): void {
|
|
if (hasFreightPermission(user, permissionKey)) return;
|
|
throw new ForbiddenException(`Missing permission: ${permissionKey}`);
|
|
}
|
|
|
|
const APPROVE_ROLE_PERMISSION: Record<string, string> = {
|
|
LINE_STAFF: FREIGHT_PERMS.bookings.approveLineStaff,
|
|
DIRECTOR: FREIGHT_PERMS.bookings.approveDirector,
|
|
CEO: FREIGHT_PERMS.bookings.approveCeo,
|
|
};
|
|
|
|
export function assertCanApproveBookingStep(
|
|
user: TCurrentUser | MeLikeUser | null | undefined,
|
|
requiredRole: string,
|
|
): void {
|
|
if (isFreightApprovalAdmin(user)) return;
|
|
const perm = APPROVE_ROLE_PERMISSION[requiredRole];
|
|
if (!perm) {
|
|
throw new ForbiddenException(`Unknown approval role: ${requiredRole}`);
|
|
}
|
|
assertFreightPermission(user, perm);
|
|
}
|