elearning/Backend/src/controllers/AuditController.ts
JakkrapartXD 108f1b73f2 feat: integrate audit logging across authentication, course management, and user operations
Add comprehensive audit trail tracking by integrating auditService throughout the application. Track user authentication (LOGIN, REGISTER), course lifecycle (CREATE, APPROVE_COURSE, REJECT_COURSE, ENROLL), content management (CREATE/DELETE Chapter/Lesson), file operations (UPLOAD_FILE, DELETE_FILE for videos and attachments), password management (CHANGE_PASSWORD, RESET_PASSWORD), user role updates (UPDATE
2026-02-05 17:35:37 +07:00

182 lines
6.4 KiB
TypeScript

import { Get, Path, Query, Request, Response, Route, Security, SuccessResponse, Tags, Delete } from 'tsoa';
import { ValidationError } from '../middleware/errorHandler';
import { auditService } from '../services/audit.service';
import { AuditAction } from '@prisma/client';
import {
ListAuditLogsResponse,
AuditLogResponse,
AuditLogStats,
} from '../types/audit.types';
@Route('api/admin/audit-logs')
@Tags('Admin/AuditLogs')
export class AuditController {
/**
* ดึงรายการ audit logs ทั้งหมด
* Get all audit logs with filters and pagination
* @param userId - กรองตาม user ID
* @param action - กรองตาม action type
* @param entityType - กรองตาม entity type (Course, User, Lesson, etc.)
* @param entityId - กรองตาม entity ID
* @param startDate - วันที่เริ่มต้น (ISO format)
* @param endDate - วันที่สิ้นสุด (ISO format)
* @param page - หน้าที่ต้องการ
* @param limit - จำนวนรายการต่อหน้า
*/
@Get('')
@Security('jwt', ['admin'])
@SuccessResponse('200', 'Audit logs retrieved successfully')
@Response('401', 'Unauthorized')
@Response('403', 'Forbidden - Admin only')
public async getAuditLogs(
@Request() request: any,
@Query() userId?: number,
@Query() action?: AuditAction,
@Query() entityType?: string,
@Query() entityId?: number,
@Query() startDate?: string,
@Query() endDate?: string,
@Query() page?: number,
@Query() limit?: number
): Promise<ListAuditLogsResponse> {
const token = request.headers.authorization?.replace('Bearer ', '');
if (!token) {
throw new ValidationError('No token provided');
}
return await auditService.getLogs({
userId,
action,
entityType,
entityId,
startDate: startDate ? new Date(startDate) : undefined,
endDate: endDate ? new Date(endDate) : undefined,
page: page || 1,
limit: limit || 50,
});
}
/**
* ดึง audit log by ID
* Get audit log detail by ID
* @param logId - รหัส audit log
*/
@Get('{logId}')
@Security('jwt', ['admin'])
@SuccessResponse('200', 'Audit log retrieved successfully')
@Response('401', 'Unauthorized')
@Response('403', 'Forbidden - Admin only')
@Response('404', 'Audit log not found')
public async getAuditLogById(
@Request() request: any,
@Path() logId: number
): Promise<AuditLogResponse> {
const token = request.headers.authorization?.replace('Bearer ', '');
if (!token) {
throw new ValidationError('No token provided');
}
const log = await auditService.getLogById(logId);
if (!log) {
throw new ValidationError('Audit log not found');
}
return log;
}
/**
* ดึงสถิติ audit logs สำหรับ dashboard
* Get audit log statistics for admin dashboard
*/
@Get('stats/summary')
@Security('jwt', ['admin'])
@SuccessResponse('200', 'Audit stats retrieved successfully')
@Response('401', 'Unauthorized')
@Response('403', 'Forbidden - Admin only')
public async getAuditStats(@Request() request: any): Promise<AuditLogStats> {
const token = request.headers.authorization?.replace('Bearer ', '');
if (!token) {
throw new ValidationError('No token provided');
}
return await auditService.getStats();
}
/**
* ดึง history ของ entity เฉพาะ
* Get audit history for a specific entity
* @param entityType - ประเภท entity (Course, User, Lesson, etc.)
* @param entityId - รหัส entity
*/
@Get('entity/{entityType}/{entityId}')
@Security('jwt', ['admin'])
@SuccessResponse('200', 'Entity history retrieved successfully')
@Response('401', 'Unauthorized')
@Response('403', 'Forbidden - Admin only')
public async getEntityHistory(
@Request() request: any,
@Path() entityType: string,
@Path() entityId: number
): Promise<AuditLogResponse[]> {
const token = request.headers.authorization?.replace('Bearer ', '');
if (!token) {
throw new ValidationError('No token provided');
}
return await auditService.getEntityHistory(entityType, entityId);
}
/**
* ดึง activity ของ user เฉพาะ
* Get activity logs for a specific user
* @param userId - รหัส user
* @param limit - จำนวนรายการ
*/
@Get('user/{userId}/activity')
@Security('jwt', ['admin'])
@SuccessResponse('200', 'User activity retrieved successfully')
@Response('401', 'Unauthorized')
@Response('403', 'Forbidden - Admin only')
public async getUserActivity(
@Request() request: any,
@Path() userId: number,
@Query() limit?: number
): Promise<AuditLogResponse[]> {
const token = request.headers.authorization?.replace('Bearer ', '');
if (!token) {
throw new ValidationError('No token provided');
}
return await auditService.getUserActivity(userId, limit || 50);
}
/**
* ลบ audit logs เก่า (maintenance)
* Delete old audit logs for maintenance
* @param days - ลบ logs ที่เก่ากว่ากี่วัน
*/
@Delete('cleanup')
@Security('jwt', ['admin'])
@SuccessResponse('200', 'Old logs deleted successfully')
@Response('401', 'Unauthorized')
@Response('403', 'Forbidden - Admin only')
public async deleteOldLogs(
@Request() request: any,
@Query() days: number = 90
): Promise<{ deleted: number; message: string }> {
const token = request.headers.authorization?.replace('Bearer ', '');
if (!token) {
throw new ValidationError('No token provided');
}
if (days < 30) {
throw new ValidationError('Cannot delete logs newer than 30 days');
}
const deleted = await auditService.deleteOldLogs(days);
return {
deleted,
message: `Deleted ${deleted} audit logs older than ${days} days`,
};
}
}