Assist_Design/apps/bff/src/auth/auth-admin.controller.ts

138 lines
3.7 KiB
TypeScript
Raw Normal View History

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,
};
}
}