Files
vctp2/server/handler/snapshotAggregate.go
Nathan Coad b9ab34db0a
All checks were successful
continuous-integration/drone/push Build is passing
bugfix reports
2026-01-14 13:51:30 +11:00

97 lines
3.3 KiB
Go

package handler
import (
"context"
"encoding/json"
"net/http"
"strings"
"time"
"vctp/internal/tasks"
)
// SnapshotAggregateForce forces regeneration of a daily or monthly summary table.
// @Summary Force snapshot aggregation
// @Description Forces regeneration of a daily or monthly summary table for a specified date or month.
// @Tags snapshots
// @Produce json
// @Param type query string true "Aggregation type: daily or monthly"
// @Param date query string true "Daily date (YYYY-MM-DD) or monthly date (YYYY-MM)"
// @Success 200 {object} map[string]string "Aggregation complete"
// @Failure 400 {object} map[string]string "Invalid request"
// @Failure 500 {object} map[string]string "Server error"
// @Router /api/snapshots/aggregate [post]
func (h *Handler) SnapshotAggregateForce(w http.ResponseWriter, r *http.Request) {
snapshotType := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("type")))
dateValue := strings.TrimSpace(r.URL.Query().Get("date"))
startedAt := time.Now()
if snapshotType == "" || dateValue == "" {
h.Logger.Warn("Snapshot aggregation request missing parameters",
"type", snapshotType,
"date", dateValue,
)
writeJSONError(w, http.StatusBadRequest, "type and date are required")
return
}
ctx := context.Background()
ct := &tasks.CronTask{
Logger: h.Logger,
Database: h.Database,
Settings: h.Settings,
}
switch snapshotType {
case "daily":
parsed, err := time.Parse("2006-01-02", dateValue)
if err != nil {
h.Logger.Warn("Snapshot aggregation invalid daily date format", "date", dateValue)
writeJSONError(w, http.StatusBadRequest, "date must be YYYY-MM-DD")
return
}
h.Logger.Info("Starting daily snapshot aggregation", "date", parsed.Format("2006-01-02"), "force", true)
if err := ct.AggregateDailySummary(ctx, parsed, true); err != nil {
h.Logger.Error("Daily snapshot aggregation failed", "date", parsed.Format("2006-01-02"), "error", err)
writeJSONError(w, http.StatusInternalServerError, err.Error())
return
}
case "monthly":
parsed, err := time.Parse("2006-01", dateValue)
if err != nil {
h.Logger.Warn("Snapshot aggregation invalid monthly date format", "date", dateValue)
writeJSONError(w, http.StatusBadRequest, "date must be YYYY-MM")
return
}
h.Logger.Info("Starting monthly snapshot aggregation", "date", parsed.Format("2006-01"), "force", true)
if err := ct.AggregateMonthlySummary(ctx, parsed, true); err != nil {
h.Logger.Error("Monthly snapshot aggregation failed", "date", parsed.Format("2006-01"), "error", err)
writeJSONError(w, http.StatusInternalServerError, err.Error())
return
}
default:
h.Logger.Warn("Snapshot aggregation invalid type", "type", snapshotType)
writeJSONError(w, http.StatusBadRequest, "type must be daily or monthly")
return
}
h.Logger.Info("Snapshot aggregation completed",
"type", snapshotType,
"date", dateValue,
"duration", time.Since(startedAt),
)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
})
}
func writeJSONError(w http.ResponseWriter, status int, message string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": message,
})
}