package handlers import ( "net/http" "strconv" "time" "github.com/leolionad58/ticketbot/internal/db" ) // AuditHandler serves GET /audit. type AuditHandler struct { AuditRepo *db.AuditLogRepo Renderer *Renderer } // auditActions lists all known audit action constants for the filter dropdown. var auditActions = []string{ db.AuditCreatePanel, db.AuditUpdatePanel, db.AuditDeletePanel, db.AuditCreateType, db.AuditUpdateType, db.AuditDeleteType, db.AuditReorderTypes, db.AuditUpdateConvoc, db.AuditSendPanelDiscord, db.AuditDeletePanelMsg, db.AuditRevokeSession, db.AuditRevokeAllSess, db.AuditAdminLogin, db.AuditAdminLoginFail, db.AuditAdminLocked, } type auditData struct { baseData Entries []*db.AuditLogEntry Total int Page int Pages int Actions []string // Filter values FAdminID string FAction string FFrom string FTo string } // HandleList serves GET /audit. func (h *AuditHandler) HandleList(w http.ResponseWriter, r *http.Request) { ctx := r.Context() base := h.Renderer.base(r, "audit") q := r.URL.Query() fAdminID := q.Get("admin_id") fAction := q.Get("action") fFrom := q.Get("from") fTo := q.Get("to") page, _ := strconv.Atoi(q.Get("page")) if page < 1 { page = 1 } var adminID int64 if fAdminID != "" { adminID, _ = strconv.ParseInt(fAdminID, 10, 64) } filter := db.AuditFilter{ AdminID: adminID, Action: fAction, } if fFrom != "" { if t, err := time.Parse("2006-01-02", fFrom); err == nil { filter.From = t } } if fTo != "" { if t, err := time.Parse("2006-01-02", fTo); err == nil { filter.To = t.Add(24*time.Hour - time.Second) } } const pageSize = 50 entries, total, err := h.AuditRepo.List(ctx, filter, page, pageSize) if err != nil { http.Error(w, "db error: "+err.Error(), http.StatusInternalServerError) return } pages := total / pageSize if total%pageSize != 0 { pages++ } if pages < 1 { pages = 1 } h.Renderer.Page(w, "audit", auditData{ baseData: base, Entries: entries, Total: total, Page: page, Pages: pages, Actions: auditActions, FAdminID: fAdminID, FAction: fAction, FFrom: fFrom, FTo: fTo, }) }