package handler import ( "encoding/json" "spider/internal/model" "spider/internal/store" "github.com/gin-gonic/gin" ) // AuditHandler handles audit log queries. type AuditHandler struct { store *store.Store } // List handles GET /audit-logs (admin only) func (h *AuditHandler) List(c *gin.Context) { page, pageSize, offset := parsePage(c) query := h.store.DB.Model(&model.AuditLog{}) if username := c.Query("username"); username != "" { query = query.Where("username = ?", username) } if action := c.Query("action"); action != "" { query = query.Where("action = ?", action) } if targetType := c.Query("target_type"); targetType != "" { query = query.Where("target_type = ?", targetType) } if targetID := c.Query("target_id"); targetID != "" { query = query.Where("target_id = ?", targetID) } if dateFrom := c.Query("date_from"); dateFrom != "" { query = query.Where("created_at >= ?", dateFrom) } if dateTo := c.Query("date_to"); dateTo != "" { query = query.Where("created_at <= ?", dateTo) } var total int64 query.Count(&total) var logs []model.AuditLog if err := query.Order("created_at DESC").Limit(pageSize).Offset(offset).Find(&logs).Error; err != nil { Fail(c, 500, err.Error()) return } PageOK(c, logs, total, page, pageSize) } // LogAudit records an audit log entry asynchronously. func LogAudit(s *store.Store, c *gin.Context, action, targetType, targetID string, detail interface{}) { username := c.GetString("username") ip := c.ClientIP() var detailJSON []byte if detail != nil { detailJSON, _ = json.Marshal(detail) } log := model.AuditLog{ Username: username, Action: action, TargetType: targetType, TargetID: targetID, Detail: detailJSON, IP: ip, } go s.DB.Create(&log) }