import { Controller, Get, Post, Body, Param, UseGuards, Query } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger'; import { JwtAuthGuard } from './guards/jwt-auth.guard'; import { AdminGuard } from './guards/admin.guard'; import { AuditService, AuditAction } from '../common/audit/audit.service'; import { UsersService } from '../users/users.service'; @ApiTags('auth-admin') @ApiBearerAuth() @UseGuards(JwtAuthGuard, AdminGuard) @Controller('auth/admin') export class AuthAdminController { constructor( private auditService: AuditService, private usersService: UsersService, ) {} @Get('audit-logs') @ApiOperation({ summary: 'Get audit logs (admin only)' }) @ApiResponse({ status: 200, description: 'Audit logs retrieved' }) async getAuditLogs( @Query('page') page: string = '1', @Query('limit') limit: string = '50', @Query('action') action?: AuditAction, @Query('userId') userId?: string ) { const pageNum = parseInt(page, 10); const limitNum = parseInt(limit, 10); const skip = (pageNum - 1) * limitNum; const where: any = {}; if (action) where.action = action; if (userId) where.userId = userId; const [logs, total] = await Promise.all([ this.auditService.prismaClient.auditLog.findMany({ where, include: { user: { select: { id: true, email: true, firstName: true, lastName: true, }, }, }, orderBy: { createdAt: 'desc' }, skip, take: limitNum, }), this.auditService.prismaClient.auditLog.count({ where }), ]); return { logs, pagination: { page: pageNum, limit: limitNum, total, totalPages: Math.ceil(total / limitNum), }, }; } @Post('unlock-account/:userId') @ApiOperation({ summary: 'Unlock user account (admin only)' }) @ApiResponse({ status: 200, description: 'Account unlocked' }) async unlockAccount(@Param('userId') userId: string) { const user = await this.usersService.findById(userId); if (!user) { throw new Error('User not found'); } await this.usersService.update(userId, { failedLoginAttempts: 0, lockedUntil: null, }); await this.auditService.log({ userId, action: AuditAction.ACCOUNT_UNLOCKED, resource: 'auth', details: { adminAction: true, email: user.email }, success: true, }); return { message: 'Account unlocked successfully' }; } @Get('security-stats') @ApiOperation({ summary: 'Get security statistics (admin only)' }) @ApiResponse({ status: 200, description: 'Security stats retrieved' }) async getSecurityStats() { const today = new Date(new Date().setHours(0, 0, 0, 0)); const [ totalUsers, lockedAccounts, failedLoginsToday, successfulLoginsToday, ] = await Promise.all([ this.auditService.prismaClient.user.count(), this.auditService.prismaClient.user.count({ where: { lockedUntil: { gt: new Date(), }, }, }), this.auditService.prismaClient.auditLog.count({ where: { action: AuditAction.LOGIN_FAILED, createdAt: { gte: today, }, }, }), this.auditService.prismaClient.auditLog.count({ where: { action: AuditAction.LOGIN_SUCCESS, createdAt: { gte: today, }, }, }), ]); return { totalUsers, lockedAccounts, failedLoginsToday, successfulLoginsToday, securityEventsToday: failedLoginsToday + successfulLoginsToday, }; } }