package media import ( "RenewCMS/api/pkg/apperr" validator "RenewCMS/api/pkg/validator" "RenewCMS/internal/domain/purge" "RenewCMS/internal/infrastructure/useCases" "encoding/json" "errors" "io" "net/http" "time" ) type PurgeSettingsRequest struct { AutoPurgeEnabled *bool `json:"auto_purge_enabled"` AutoPurgeIntervalDays *int `json:"auto_purge_interval_days" validate:"omitempty,gte=1,lte=365"` } type PurgeRunRequest struct { Fingerprint *string `json:"fingerprint"` } type purgeSettingsResponse struct { AutoPurgeEnabled bool `json:"auto_purge_enabled"` AutoPurgeIntervalDays int `json:"auto_purge_interval_days"` LastPurgeAt *time.Time `json:"last_purge_at"` LastPurgeMerged int `json:"last_purge_merged"` LastPurgeArticlesUpdated int `json:"last_purge_articles_updated"` EnabledAt *time.Time `json:"enabled_at"` NextPurgeAt *time.Time `json:"next_purge_at"` } type purgePreviewGroupResponse struct { KeepID uint32 `json:"keep_id"` Filename string `json:"filename"` URL string `json:"url"` UsedIn int `json:"used_in"` Merged int `json:"merged"` } type purgePreviewResponse struct { Groups int `json:"groups"` Copies int `json:"copies"` Articles int `json:"articles"` List []purgePreviewGroupResponse `json:"list"` More int `json:"more"` Fingerprint string `json:"fingerprint"` } type purgeRunResponse struct { GroupsTotal int `json:"groups_total"` GroupsPurged int `json:"groups_purged"` Merged int `json:"merged"` ArticlesUpdated int `json:"articles_updated"` SitesUpdated int `json:"sites_updated"` AuthorsUpdated int `json:"authors_updated"` FailedGroups int `json:"failed_groups"` } func toPurgeSettingsResponse(settings purge.Settings) purgeSettingsResponse { return purgeSettingsResponse{ AutoPurgeEnabled: settings.AutoPurgeEnabled, AutoPurgeIntervalDays: settings.AutoPurgeIntervalDays, LastPurgeAt: settings.LastPurgeAt, LastPurgeMerged: settings.LastPurgeMerged, LastPurgeArticlesUpdated: settings.LastPurgeArticlesUpdated, EnabledAt: settings.EnabledAt, NextPurgeAt: settings.NextPurgeAt(), } } func writePurgeError(w http.ResponseWriter, err error) { switch { case errors.Is(err, purge.ErrInvalidPurgeInterval): http.Error(w, apperr.PurgeIntervalErrorMessage, http.StatusBadRequest) case errors.Is(err, purge.ErrPurgeConflict): http.Error(w, apperr.PurgeConflictErrorMessage, http.StatusConflict) case errors.Is(err, purge.ErrPurgeBusy): http.Error(w, apperr.PurgeBusyErrorMessage, http.StatusConflict) default: writeInternalServerError(w) } } func (h *Handler) GetPurgeSettings(w http.ResponseWriter, _ *http.Request) { settings, err := h.PurgeSettingsUseCase.Get() if err != nil { writePurgeError(w, err) return } writeJSON(w, http.StatusOK, toPurgeSettingsResponse(settings)) } func (h *Handler) UpdatePurgeSettings(w http.ResponseWriter, r *http.Request) { var request PurgeSettingsRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest) return } if err := validator.Validate.Struct(request); err != nil { http.Error(w, apperr.PurgeIntervalErrorMessage, http.StatusBadRequest) return } settings, err := h.UpdatePurgeSettingsUseCase.Update(useCases.UpdatePurgeSettingsCommand{ AutoPurgeEnabled: request.AutoPurgeEnabled, AutoPurgeIntervalDays: request.AutoPurgeIntervalDays, }) if err != nil { writePurgeError(w, err) return } writeJSON(w, http.StatusOK, toPurgeSettingsResponse(settings)) } func (h *Handler) PreviewPurge(w http.ResponseWriter, _ *http.Request) { preview, err := h.PreviewPurgeUseCase.Preview() if err != nil { writePurgeError(w, err) return } list := make([]purgePreviewGroupResponse, 0, len(preview.List)) for _, group := range preview.List { list = append(list, purgePreviewGroupResponse{ KeepID: group.KeepID, Filename: group.Filename, URL: group.URL, UsedIn: group.UsedIn, Merged: group.Merged, }) } writeJSON(w, http.StatusOK, purgePreviewResponse{ Groups: preview.Groups, Copies: preview.Copies, Articles: preview.Articles, List: list, More: preview.More, Fingerprint: preview.Fingerprint, }) } func (h *Handler) RunPurge(w http.ResponseWriter, r *http.Request) { raw, err := io.ReadAll(r.Body) if err != nil { http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest) return } var request PurgeRunRequest if len(raw) > 0 { if err := json.Unmarshal(raw, &request); err != nil { http.Error(w, apperr.BodyErrorMessage, http.StatusBadRequest) return } } result, err := h.RunPurgeUseCase.Run(r.Context(), request.Fingerprint) if err != nil { writePurgeError(w, err) return } writeJSON(w, http.StatusOK, purgeRunResponse{ GroupsTotal: result.GroupsTotal, GroupsPurged: result.GroupsPurged, Merged: result.Merged, ArticlesUpdated: result.ArticlesUpdated, SitesUpdated: result.SitesUpdated, AuthorsUpdated: result.AuthorsUpdated, FailedGroups: result.FailedGroups, }) }