package handler import ( "net/http" "os" "path/filepath" "strings" "time" "vctp/internal/report" "vctp/server/models" ) // SnapshotRegenerateHourlyReports regenerates missing hourly snapshot XLSX reports on disk. // @Summary Regenerate hourly snapshot reports // @Description Regenerates XLSX reports for hourly snapshots when the report files are missing or empty. // @Tags snapshots // @Produce json // @Success 200 {object} models.SnapshotRegenerateReportsResponse "Regeneration summary" // @Failure 500 {object} models.ErrorResponse "Server error" // @Router /api/snapshots/regenerate-hourly-reports [post] func (h *Handler) SnapshotRegenerateHourlyReports(w http.ResponseWriter, r *http.Request) { ctx := r.Context() reportsDir := strings.TrimSpace(h.Settings.Values.Settings.ReportsDir) if reportsDir == "" { reportsDir = "/var/lib/vctp/reports" } if err := os.MkdirAll(reportsDir, 0o755); err != nil { h.Logger.Error("failed to create reports directory", "error", err, "path", reportsDir) writeJSONError(w, http.StatusInternalServerError, "failed to create reports directory") return } start := time.Unix(0, 0) end := time.Now().AddDate(10, 0, 0) // sufficiently in the future to include all records records, err := report.SnapshotRecordsWithFallback(ctx, h.Database, "hourly", "inventory_hourly_", "epoch", start, end) if err != nil { h.Logger.Error("failed to list hourly snapshots", "error", err) writeJSONError(w, http.StatusInternalServerError, "failed to list hourly snapshots") return } var regenerated, skipped, errors int for _, rec := range records { dest := filepath.Join(reportsDir, rec.TableName+".xlsx") if info, err := os.Stat(dest); err == nil && info.Size() > 0 { skipped++ continue } if _, err := report.SaveTableReport(h.Logger, h.Database, ctx, rec.TableName, reportsDir, h.Settings); err != nil { errors++ h.Logger.Warn("failed to regenerate hourly report", "table", rec.TableName, "error", err) continue } regenerated++ } resp := models.SnapshotRegenerateReportsResponse{ Status: "OK", Total: len(records), Regenerated: regenerated, Skipped: skipped, Errors: errors, ReportsDir: reportsDir, SnapshotType: "hourly", } writeJSON(w, http.StatusOK, resp) }