package useCases import ( "RenewCMS/internal/domain/audit" "RenewCMS/internal/domain/image" "RenewCMS/internal/domain/site" "context" ) type UpdateSiteUseCase struct { siteRepository site.Repository imageRepository image.Repository recorder audit.Recorder } func NewUpdateSiteUseCase(siteRepository site.Repository, imageRepository image.Repository, recorder audit.Recorder) *UpdateSiteUseCase { return &UpdateSiteUseCase{siteRepository, imageRepository, recorder} } func (u *UpdateSiteUseCase) Update(ctx context.Context, id uint32, patch site.Patch) (site.Site, error) { before, err := u.siteRepository.Get(id) if err != nil { return site.Site{}, err } event := audit.NewEvent(audit.ActionSiteEdit, audit.CategorySites) event.Target = siteTarget(before) after, err := u.apply(before, patch) if err != nil { recordFailure(ctx, u.recorder, event, err) return site.Site{}, err } changes := u.changes(before, after) if len(changes) == 0 { return before, nil } saved, err := u.siteRepository.Update(after) if err != nil { recordFailure(ctx, u.recorder, event, err) return site.Site{}, err } event.Target = siteTarget(saved) event.Changes = changes u.recorder.Record(ctx, event) return saved, nil } func (u *UpdateSiteUseCase) apply(before site.Site, patch site.Patch) (site.Site, error) { after := before if patch.IsDefault != nil { return site.Site{}, site.ErrUseSetDefault } if patch.Key != nil && *patch.Key != before.Key { return site.Site{}, site.ErrKeyImmutable } if patch.Name != nil { after.Name = *patch.Name } if patch.BaseURL != nil { baseURL, err := site.NormalizeBaseURL(*patch.BaseURL) if err != nil { return site.Site{}, err } after.BaseURL = baseURL } if patch.DefaultRobots != nil { after.DefaultRobots = *patch.DefaultRobots } if patch.Locale.Set { locale, err := site.NormalizeLocale(patch.Locale.Value) if err != nil { return site.Site{}, err } after.Locale = locale } if patch.DefaultSocialImageID.Set { if err := ensureImageExists(u.imageRepository, patch.DefaultSocialImageID.Value); err != nil { return site.Site{}, err } after.DefaultSocialImageID = patch.DefaultSocialImageID.Value } if patch.SiteName != nil { after.SiteName = *patch.SiteName } if patch.TitleTemplate != nil { if err := site.ValidateTitleTemplate(*patch.TitleTemplate); err != nil { return site.Site{}, err } after.TitleTemplate = *patch.TitleTemplate } if patch.DefaultDescription != nil { after.DefaultDescription = *patch.DefaultDescription } return after, nil } func (u *UpdateSiteUseCase) changes(before site.Site, after site.Site) []audit.Change { changes := []audit.Change{} changes = audit.AppendTextChange(changes, audit.FieldName, before.Name, after.Name) changes = audit.AppendTextChange(changes, audit.FieldBaseURL, before.BaseURL, after.BaseURL) changes = audit.AppendTextChange(changes, audit.FieldDefaultRobots, before.DefaultRobots, after.DefaultRobots) changes = audit.AppendTextChange(changes, audit.FieldLocale, localeLabel(before.Locale), localeLabel(after.Locale)) if !sameImage(before.DefaultSocialImageID, after.DefaultSocialImageID) { changes = append(changes, audit.TextChange(audit.FieldSocialImage, imageLabel(u.imageRepository, before.DefaultSocialImageID), imageLabel(u.imageRepository, after.DefaultSocialImageID))) } changes = audit.AppendTextChange(changes, audit.FieldSiteName, before.SiteName, after.SiteName) changes = audit.AppendTextChange(changes, audit.FieldTitleTemplate, before.TitleTemplate, after.TitleTemplate) changes = audit.AppendTextChange(changes, audit.FieldDefaultDescription, before.DefaultDescription, after.DefaultDescription) return changes } func sameImage(a *uint32, b *uint32) bool { if a == nil || b == nil { return a == b } return *a == *b }