import { CanActivate, ExecutionContext, ForbiddenException, Injectable, } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { Role } from './role.enum'; import { ROLES_KEY } from './roles.decorator'; import { AuthenticatedRequest } from '../auth/authenticated-request'; /// Checks the caller holds one of the required roles, scoped to the KC in the /// request (route param `kcId`, falling back to body.kcId). LEITUNGSTEAM /// memberships are global and satisfy any KC scope. @Injectable() export class RolesGuard implements CanActivate { constructor(private readonly reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const requiredRoles = this.reflector.getAllAndOverride(ROLES_KEY, [ context.getHandler(), context.getClass(), ]); if (!requiredRoles || requiredRoles.length === 0) { return true; } const request = context.switchToHttp().getRequest(); const user = request.user; if (!user) { throw new ForbiddenException('Not authenticated'); } const kcId = request.params?.kcId ?? request.body?.kcId; const hasRole = user.memberships.some((membership) => { if (!requiredRoles.includes(membership.role)) { return false; } if (membership.role === Role.LEITUNGSTEAM) { return true; } return kcId ? membership.kcId === kcId : true; }); if (!hasRole) { throw new ForbiddenException('Insufficient role for this KC'); } return true; } }