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(); 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 = { 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); }