import { Injectable, type CanActivate, type ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { type UserRole } from '@prisma/client'; import { LoggerService } from '@modules/shared'; import { ROLES_KEY } from '../decorators/roles.decorator'; @Injectable() export class RolesGuard implements CanActivate { constructor( private readonly reflector: Reflector, private readonly logger: LoggerService, ) {} 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; const hasRole = requiredRoles.includes(user?.role); if (!hasRole) { const ip = request.ip || request.headers?.['x-forwarded-for'] || 'unknown'; const handler = context.getHandler().name; const controller = context.getClass().name; this.logger.warn( `Access denied: userId=${user?.sub ?? 'unknown'}, role=${user?.role ?? 'none'}, ` + `required=${requiredRoles.join(',')}, action=${controller}.${handler}, ip=${ip}`, 'RolesGuard', ); } return hasRole; } }