feat: media duplicate purge, part 1 of 3: persisted purge settings and the purge API
This commit is contained in:
1 parent
161ddc0f7d
commit
e82d0ce254
25 files changed
+2459
-41
No files matched your search
@@ -19,12 +19,16 @@ import (
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
CreateUseCase *useCases.CreateImageUseCase
|
||||
ListUseCase *useCases.ListMediaUseCase
|
||||
RenameUseCase *useCases.RenameMediaUseCase
|
||||
DeleteUseCase *useCases.DeleteMediaUseCase
|
||||
MergeUseCase *useCases.MergeMediaUseCase
|
||||
UsageUseCase *useCases.GetMediaUsageUseCase
|
||||
CreateUseCase *useCases.CreateImageUseCase
|
||||
ListUseCase *useCases.ListMediaUseCase
|
||||
RenameUseCase *useCases.RenameMediaUseCase
|
||||
DeleteUseCase *useCases.DeleteMediaUseCase
|
||||
MergeUseCase *useCases.MergeMediaUseCase
|
||||
UsageUseCase *useCases.GetMediaUsageUseCase
|
||||
PurgeSettingsUseCase *useCases.GetPurgeSettingsUseCase
|
||||
UpdatePurgeSettingsUseCase *useCases.UpdatePurgeSettingsUseCase
|
||||
PreviewPurgeUseCase *useCases.PreviewPurgeUseCase
|
||||
RunPurgeUseCase *useCases.RunPurgeUseCase
|
||||
}
|
||||
|
||||
type RenameRequest struct {
|
||||
@@ -74,14 +78,18 @@ type mergeResponse struct {
|
||||
Merged int `json:"merged"`
|
||||
}
|
||||
|
||||
func NewHandler(create *useCases.CreateImageUseCase, list *useCases.ListMediaUseCase, rename *useCases.RenameMediaUseCase, deleteUseCase *useCases.DeleteMediaUseCase, merge *useCases.MergeMediaUseCase, usage *useCases.GetMediaUsageUseCase) *Handler {
|
||||
func NewHandler(create *useCases.CreateImageUseCase, list *useCases.ListMediaUseCase, rename *useCases.RenameMediaUseCase, deleteUseCase *useCases.DeleteMediaUseCase, merge *useCases.MergeMediaUseCase, usage *useCases.GetMediaUsageUseCase, purgeSettings *useCases.GetPurgeSettingsUseCase, updatePurgeSettings *useCases.UpdatePurgeSettingsUseCase, previewPurge *useCases.PreviewPurgeUseCase, runPurge *useCases.RunPurgeUseCase) *Handler {
|
||||
return &Handler{
|
||||
CreateUseCase: create,
|
||||
ListUseCase: list,
|
||||
RenameUseCase: rename,
|
||||
DeleteUseCase: deleteUseCase,
|
||||
MergeUseCase: merge,
|
||||
UsageUseCase: usage,
|
||||
CreateUseCase: create,
|
||||
ListUseCase: list,
|
||||
RenameUseCase: rename,
|
||||
DeleteUseCase: deleteUseCase,
|
||||
MergeUseCase: merge,
|
||||
UsageUseCase: usage,
|
||||
PurgeSettingsUseCase: purgeSettings,
|
||||
UpdatePurgeSettingsUseCase: updatePurgeSettings,
|
||||
PreviewPurgeUseCase: previewPurge,
|
||||
RunPurgeUseCase: runPurge,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
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"`
|
||||
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(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,
|
||||
FailedGroups: result.FailedGroups,
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user