- Removed deprecated files and components from the BFF application, including various auth and catalog services, enhancing code clarity. - Updated package.json scripts for better organization and streamlined development processes. - Refactored portal components to improve structure and maintainability, including the removal of unused files and components. - Enhanced type definitions and imports across the application for consistency and clarity.
145 lines
3.9 KiB
TypeScript
145 lines
3.9 KiB
TypeScript
import {
|
|
Controller,
|
|
Get,
|
|
Post,
|
|
Param,
|
|
UseGuards,
|
|
Query,
|
|
BadRequestException,
|
|
} from "@nestjs/common";
|
|
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from "@nestjs/swagger";
|
|
import { AdminGuard } from "./guards/admin.guard";
|
|
import { AuditService, AuditAction } from "@bff/infra/audit/audit.service";
|
|
import { UsersService } from "@bff/modules/users/users.service";
|
|
|
|
@ApiTags("auth-admin")
|
|
@ApiBearerAuth()
|
|
@UseGuards(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;
|
|
|
|
if (Number.isNaN(pageNum) || Number.isNaN(limitNum) || pageNum < 1 || limitNum < 1) {
|
|
throw new BadRequestException("Invalid pagination parameters");
|
|
}
|
|
|
|
const where: { action?: AuditAction; userId?: string } = {};
|
|
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 BadRequestException("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,
|
|
};
|
|
}
|
|
}
|