package api import ( "encoding/json" "fmt" "net/http" "strconv" "archivmail/internal/audit" ) // handlePurge deletes all mails whose retention period has expired. // POST /api/admin/purge — superadmin only (PROJ-34). func (s *Server) handlePurge(w http.ResponseWriter, r *http.Request) { deleted, err := s.store.Purge(r.Context()) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]interface{}{ "deleted": deleted, }) } // handleGetRetention returns the global retention config and per-tenant overrides. // GET /api/admin/retention — superadmin only. func (s *Server) handleGetRetention(w http.ResponseWriter, r *http.Request) { tenants, err := s.tenantStore.List(r.Context()) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]interface{}{ "global_retention_days": s.globalRetentionDays, "tenants": tenants, }) } // handleSetTenantRetention sets retention_days for a specific tenant. // PUT /api/admin/tenant/{id}/retention — superadmin only. func (s *Server) handleSetTenantRetention(w http.ResponseWriter, r *http.Request) { idStr := r.PathValue("id") tenantID, err := strconv.ParseInt(idStr, 10, 64) if err != nil { writeError(w, http.StatusBadRequest, "invalid tenant id") return } var body struct { RetentionDays int `json:"retention_days"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { writeError(w, http.StatusBadRequest, "invalid body") return } if err := s.tenantStore.SetRetentionDays(r.Context(), tenantID, body.RetentionDays); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } sess := sessionFromCtx(r.Context()) if s.audlog != nil { s.audlog.Log(audit.Entry{ EventType: "tenant_retention_changed", Username: sess.Username, IPAddress: s.remoteIP(r), Success: true, Detail: fmt.Sprintf("tenant_id=%d retention_days=%d", tenantID, body.RetentionDays), }) } writeJSON(w, http.StatusOK, map[string]interface{}{"ok": true}) }