- 新增日志管理模块:操作日志、登录日志、数据变更日志 - 新增敏感词过滤器 (sanitizer) - 新增日志异步写入管理器 - 新增日志定时清理服务 - 优化帖子相关服务和上传服务
216 lines
5.9 KiB
Go
216 lines
5.9 KiB
Go
package handler
|
|
|
|
import (
|
|
"strconv"
|
|
"time"
|
|
|
|
"carrot_bbs/internal/pkg/response"
|
|
"carrot_bbs/internal/repository"
|
|
"carrot_bbs/internal/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// AdminLogHandler 管理后台日志处理器
|
|
type AdminLogHandler struct {
|
|
operationLogService service.OperationLogService
|
|
loginLogService service.LoginLogService
|
|
dataChangeLogService service.DataChangeLogService
|
|
}
|
|
|
|
// NewAdminLogHandler 创建管理后台日志处理器
|
|
func NewAdminLogHandler(
|
|
operationLogService service.OperationLogService,
|
|
loginLogService service.LoginLogService,
|
|
dataChangeLogService service.DataChangeLogService,
|
|
) *AdminLogHandler {
|
|
return &AdminLogHandler{
|
|
operationLogService: operationLogService,
|
|
loginLogService: loginLogService,
|
|
dataChangeLogService: dataChangeLogService,
|
|
}
|
|
}
|
|
|
|
// GetOperationLogs 获取操作日志列表
|
|
// GET /api/v1/admin/logs/operations
|
|
func (h *AdminLogHandler) GetOperationLogs(c *gin.Context) {
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
|
|
filters := repository.LogFilter{
|
|
UserID: c.Query("user_id"),
|
|
Operation: c.Query("operation"),
|
|
TargetType: c.Query("target_type"),
|
|
TargetID: c.Query("target_id"),
|
|
Status: c.Query("status"),
|
|
IP: c.Query("ip"),
|
|
StartTime: c.Query("start_time"),
|
|
EndTime: c.Query("end_time"),
|
|
}
|
|
|
|
logs, total, err := h.operationLogService.GetOperationLogs(c.Request.Context(), filters, page, pageSize)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to get operation logs")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"logs": logs,
|
|
"pagination": gin.H{
|
|
"page": page,
|
|
"page_size": pageSize,
|
|
"total": total,
|
|
},
|
|
})
|
|
}
|
|
|
|
// GetLoginLogs 获取登录日志列表
|
|
// GET /api/v1/admin/logs/logins
|
|
func (h *AdminLogHandler) GetLoginLogs(c *gin.Context) {
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
|
|
filters := repository.LoginFilter{
|
|
UserID: c.Query("user_id"),
|
|
Event: c.Query("event"),
|
|
Result: c.Query("result"),
|
|
FailReason: c.Query("fail_reason"),
|
|
LoginType: c.Query("login_type"),
|
|
IP: c.Query("ip"),
|
|
}
|
|
|
|
if startTime := c.Query("start_time"); startTime != "" {
|
|
if t, err := time.Parse(time.RFC3339, startTime); err == nil {
|
|
filters.StartTime = t
|
|
}
|
|
}
|
|
|
|
if endTime := c.Query("end_time"); endTime != "" {
|
|
if t, err := time.Parse(time.RFC3339, endTime); err == nil {
|
|
filters.EndTime = t
|
|
}
|
|
}
|
|
|
|
logs, total, err := h.loginLogService.GetLoginLogs(c.Request.Context(), filters, page, pageSize)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to get login logs")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"logs": logs,
|
|
"pagination": gin.H{
|
|
"page": page,
|
|
"page_size": pageSize,
|
|
"total": total,
|
|
},
|
|
})
|
|
}
|
|
|
|
// GetDataChangeLogs 获取数据变更日志列表
|
|
// GET /api/v1/admin/logs/data-changes
|
|
func (h *AdminLogHandler) GetDataChangeLogs(c *gin.Context) {
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
|
|
filters := repository.DataChangeFilter{
|
|
UserID: c.Query("user_id"),
|
|
OperatorID: c.Query("operator_id"),
|
|
ChangeType: c.Query("change_type"),
|
|
TargetType: c.Query("target_type"),
|
|
OperatorType: c.Query("operator_type"),
|
|
IP: c.Query("ip"),
|
|
StartTime: c.Query("start_time"),
|
|
EndTime: c.Query("end_time"),
|
|
}
|
|
|
|
logs, total, err := h.dataChangeLogService.GetDataChangeLogs(c.Request.Context(), filters, page, pageSize)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to get data change logs")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"logs": logs,
|
|
"pagination": gin.H{
|
|
"page": page,
|
|
"page_size": pageSize,
|
|
"total": total,
|
|
},
|
|
})
|
|
}
|
|
|
|
// GetLogStatistics 获取日志统计
|
|
// GET /api/v1/admin/logs/statistics
|
|
func (h *AdminLogHandler) GetLogStatistics(c *gin.Context) {
|
|
startTime := c.DefaultQuery("start_time", "")
|
|
endTime := c.DefaultQuery("end_time", "")
|
|
|
|
operationStats, err := h.operationLogService.GetStatistics(c.Request.Context(), startTime, endTime)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to get operation log statistics")
|
|
return
|
|
}
|
|
|
|
loginStats, err := h.loginLogService.GetStatistics(c.Request.Context(), startTime, endTime)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to get login log statistics")
|
|
return
|
|
}
|
|
|
|
dataChangeStats, err := h.dataChangeLogService.GetStatistics(c.Request.Context(), startTime, endTime)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to get data change log statistics")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"operation_logs": operationStats,
|
|
"login_logs": loginStats,
|
|
"data_change_logs": dataChangeStats,
|
|
})
|
|
}
|
|
|
|
// ExportLogs 导出日志
|
|
// GET /api/v1/admin/logs/export
|
|
func (h *AdminLogHandler) ExportLogs(c *gin.Context) {
|
|
logType := c.Query("type")
|
|
startTime := c.Query("start_time")
|
|
endTime := c.Query("end_time")
|
|
|
|
switch logType {
|
|
case "operation":
|
|
logs, _, err := h.operationLogService.GetOperationLogsByTimeRange(c.Request.Context(), startTime, endTime, 1, 10000)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to export operation logs")
|
|
return
|
|
}
|
|
response.Success(c, gin.H{
|
|
"type": "operation",
|
|
"logs": logs,
|
|
})
|
|
case "login":
|
|
logs, _, err := h.loginLogService.GetLoginLogs(c.Request.Context(), repository.LoginFilter{}, 1, 10000)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to export login logs")
|
|
return
|
|
}
|
|
response.Success(c, gin.H{
|
|
"type": "login",
|
|
"log": logs,
|
|
})
|
|
case "data_change":
|
|
logs, _, err := h.dataChangeLogService.GetDataChangeLogs(c.Request.Context(), repository.DataChangeFilter{}, 1, 10000)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to export data change logs")
|
|
return
|
|
}
|
|
response.Success(c, gin.H{
|
|
"type": "data_change",
|
|
"log": logs,
|
|
})
|
|
default:
|
|
response.Error(c, 400, "invalid log type")
|
|
}
|
|
}
|