feat: Integrate audit logging for various operations
- Added audit logging functionality across multiple controllers, including menu, user, department, flow, screen, and table management. - Implemented logging for create, update, and delete actions, capturing relevant details such as company code, user information, and changes made. - Enhanced the category tree service with a new endpoint to check if category values are in use, improving data integrity checks. - Updated routes to include new functionalities and ensure proper logging for batch operations and individual record changes. - This integration improves traceability and accountability for data modifications within the application.
This commit is contained in:
139
backend-node/src/controllers/auditLogController.ts
Normal file
139
backend-node/src/controllers/auditLogController.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { Response } from "express";
|
||||
import { AuthenticatedRequest } from "../middleware/authMiddleware";
|
||||
import { auditLogService } from "../services/auditLogService";
|
||||
import { query } from "../database/db";
|
||||
import logger from "../utils/logger";
|
||||
|
||||
export const getAuditLogs = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const userCompanyCode = req.user?.companyCode;
|
||||
const isSuperAdmin = userCompanyCode === "*";
|
||||
|
||||
const {
|
||||
companyCode,
|
||||
userId,
|
||||
resourceType,
|
||||
action,
|
||||
tableName,
|
||||
dateFrom,
|
||||
dateTo,
|
||||
search,
|
||||
page,
|
||||
limit,
|
||||
} = req.query;
|
||||
|
||||
const result = await auditLogService.queryLogs(
|
||||
{
|
||||
companyCode: (companyCode as string) || (isSuperAdmin ? undefined : userCompanyCode),
|
||||
userId: userId as string,
|
||||
resourceType: resourceType as string,
|
||||
action: action as string,
|
||||
tableName: tableName as string,
|
||||
dateFrom: dateFrom as string,
|
||||
dateTo: dateTo as string,
|
||||
search: search as string,
|
||||
page: page ? parseInt(page as string, 10) : 1,
|
||||
limit: limit ? parseInt(limit as string, 10) : 50,
|
||||
},
|
||||
isSuperAdmin
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result.data,
|
||||
total: result.total,
|
||||
page: page ? parseInt(page as string, 10) : 1,
|
||||
limit: limit ? parseInt(limit as string, 10) : 50,
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("감사 로그 조회 실패", { error: error.message });
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: "감사 로그 조회 중 오류가 발생했습니다.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const getAuditLogStats = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const userCompanyCode = req.user?.companyCode;
|
||||
const isSuperAdmin = userCompanyCode === "*";
|
||||
const { companyCode, days } = req.query;
|
||||
|
||||
const targetCompany = isSuperAdmin
|
||||
? (companyCode as string) || undefined
|
||||
: userCompanyCode;
|
||||
|
||||
const stats = await auditLogService.getStats(
|
||||
targetCompany,
|
||||
days ? parseInt(days as string, 10) : 30
|
||||
);
|
||||
|
||||
res.json({ success: true, data: stats });
|
||||
} catch (error: any) {
|
||||
logger.error("감사 로그 통계 조회 실패", { error: error.message });
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: "감사 로그 통계 조회 중 오류가 발생했습니다.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const getAuditLogUsers = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const userCompanyCode = req.user?.companyCode;
|
||||
const isSuperAdmin = userCompanyCode === "*";
|
||||
const { companyCode } = req.query;
|
||||
|
||||
const conditions: string[] = ["LOWER(u.status) = 'active'"];
|
||||
const params: any[] = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
if (!isSuperAdmin) {
|
||||
conditions.push(`u.company_code = $${paramIndex++}`);
|
||||
params.push(userCompanyCode);
|
||||
} else if (companyCode) {
|
||||
conditions.push(`u.company_code = $${paramIndex++}`);
|
||||
params.push(companyCode);
|
||||
}
|
||||
|
||||
if (!isSuperAdmin) {
|
||||
conditions.push(`u.company_code != '*'`);
|
||||
}
|
||||
|
||||
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
||||
|
||||
const users = await query<{ user_id: string; user_name: string; count: number }>(
|
||||
`SELECT
|
||||
u.user_id,
|
||||
u.user_name,
|
||||
COALESCE(sal.log_count, 0)::int as count
|
||||
FROM user_info u
|
||||
LEFT JOIN (
|
||||
SELECT user_id, COUNT(*) as log_count
|
||||
FROM system_audit_log
|
||||
GROUP BY user_id
|
||||
) sal ON u.user_id = sal.user_id
|
||||
${whereClause}
|
||||
ORDER BY count DESC, u.user_name ASC`,
|
||||
params
|
||||
);
|
||||
|
||||
res.json({ success: true, data: users });
|
||||
} catch (error: any) {
|
||||
logger.error("감사 로그 사용자 목록 조회 실패", { error: error.message });
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: "사용자 목록 조회 중 오류가 발생했습니다.",
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user