- Introduce interfaces for all major services (JWT, PostAI, Comment, Message, Notification, QRCodeLogin, Upload, Vote, etc.) to support dependency inversion. - Move query parameters from `internal/dto` to a new `internal/query` package to separate request payloads from data transfer objects. - Refactor `internal/router` to use embedded `RouterDeps` for cleaner dependency management. - Decouple handlers from repositories by injecting services instead of direct repository access, ensuring proper layering. - Improve database initialization by moving it from `internal/model` to `internal/database`. - Optimize message decryption by implementing a more efficient `BatchDecrypt` method in `MessageEncryptor` using a worker pool. - Enhance error handling and security by implementing fail-fast checks for encryption key length during startup. - Clean up unused code, including the `avatar` package and several unused DTOs.
216 lines
5.9 KiB
Go
216 lines
5.9 KiB
Go
package handler
|
|
|
|
import (
|
|
"strconv"
|
|
"time"
|
|
|
|
"with_you/internal/pkg/response"
|
|
"with_you/internal/query"
|
|
"with_you/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 := query.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 := query.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 := query.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(), query.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(), query.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")
|
|
}
|
|
}
|