Files
goodgo-platform/apps/api/src/modules/auth/presentation/guards/roles.guard.ts
Ho Ngoc Hai 312532b1cb fix(api): resolve NestJS DI + ValidationPipe bugs from type-only imports
- Remove `type` modifier from imports used as DI constructor params
  across ~235 files (@Injectable, @Controller, @Module, @Catch,
  @CommandHandler, @QueryHandler, @EventsHandler, @WebSocketGateway).
  TypeScript emitDecoratorMetadata strips type-only imports, leaving
  Reflect.metadata with Function placeholder and breaking Nest DI.
- Fix controllers: DTOs used with @Body/@Query/@Param must be runtime
  imports so ValidationPipe can whitelist properties. Previously
  returned 400 "property X should not exist" on every request.
- Register ProjectsModule in AppModule (was defined but never wired).
- Add approve()/reject() methods to TransferListingEntity referenced by
  ModerateTransferListingHandler.
- Export BankTransferConfirmedEvent from payments barrel for
  subscription activation handler.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:50:30 +07:00

42 lines
1.3 KiB
TypeScript

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<UserRole[]>(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;
}
}