153 lines
3.9 KiB
Go
153 lines
3.9 KiB
Go
package useCases
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/audit"
|
|
"RenewCMS/internal/domain/author"
|
|
"RenewCMS/internal/domain/image"
|
|
"RenewCMS/internal/domain/user"
|
|
"context"
|
|
"strings"
|
|
)
|
|
|
|
type UpdateAuthorUseCase struct {
|
|
authors author.Repository
|
|
users user.Repository
|
|
images image.Repository
|
|
recorder audit.Recorder
|
|
}
|
|
|
|
func NewUpdateAuthorUseCase(authors author.Repository, users user.Repository, images image.Repository, recorder audit.Recorder) *UpdateAuthorUseCase {
|
|
return &UpdateAuthorUseCase{authors: authors, users: users, images: images, recorder: recorder}
|
|
}
|
|
|
|
func (u *UpdateAuthorUseCase) Update(ctx context.Context, id uint32, caller AuthorCaller, patch author.Patch) (author.Author, error) {
|
|
before, err := u.authors.Get(id)
|
|
if err != nil {
|
|
return author.Author{}, err
|
|
}
|
|
|
|
event := audit.NewEvent(audit.ActionAuthorEdit, audit.CategoryAuthors)
|
|
event.Target = authorTarget(before)
|
|
after, err := u.prepare(before, caller, patch)
|
|
if err != nil {
|
|
recordFailure(ctx, u.recorder, event, err)
|
|
return author.Author{}, err
|
|
}
|
|
|
|
changes := authorChanges(u.users, u.images, before, after)
|
|
if len(changes) == 0 {
|
|
return u.present(before, caller), nil
|
|
}
|
|
saved, err := u.authors.Update(after)
|
|
if err != nil {
|
|
recordFailure(ctx, u.recorder, event, err)
|
|
return author.Author{}, err
|
|
}
|
|
event.Target = authorTarget(saved)
|
|
event.Changes = changes
|
|
u.recorder.Record(ctx, event)
|
|
return u.present(saved, caller), nil
|
|
}
|
|
|
|
func (u *UpdateAuthorUseCase) present(a author.Author, caller AuthorCaller) author.Author {
|
|
if caller.isAdmin() {
|
|
return withUserEmail(u.users, a)
|
|
}
|
|
a.UserEmail = nil
|
|
return a
|
|
}
|
|
|
|
func (u *UpdateAuthorUseCase) prepare(before author.Author, caller AuthorCaller, patch author.Patch) (author.Author, error) {
|
|
if err := authorizeEdit(before, caller, patch); err != nil {
|
|
return author.Author{}, err
|
|
}
|
|
after := before
|
|
if patch.Name != nil {
|
|
after.Name = strings.TrimSpace(*patch.Name)
|
|
}
|
|
if patch.Bio != nil {
|
|
after.Bio = *patch.Bio
|
|
}
|
|
if patch.Website.Set {
|
|
after.Website = patch.Website.Value
|
|
}
|
|
if patch.SocialLinks != nil {
|
|
after.SocialLinks = *patch.SocialLinks
|
|
}
|
|
website, err := validateAuthorContent(after.Bio, after.Website, after.SocialLinks)
|
|
if err != nil {
|
|
return author.Author{}, err
|
|
}
|
|
after.Website = website
|
|
if err := u.applySlug(&after, patch); err != nil {
|
|
return author.Author{}, err
|
|
}
|
|
if err := u.applyAvatar(&after, patch); err != nil {
|
|
return author.Author{}, err
|
|
}
|
|
return after, u.applyLink(&after, patch)
|
|
}
|
|
|
|
func authorizeEdit(before author.Author, caller AuthorCaller, patch author.Patch) error {
|
|
if caller.isAdmin() {
|
|
return nil
|
|
}
|
|
if before.UserID == nil || *before.UserID != caller.UserID || patch.UserID.Set {
|
|
return author.ErrAuthorRights
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (u *UpdateAuthorUseCase) applySlug(after *author.Author, patch author.Patch) error {
|
|
if patch.Slug == nil || *patch.Slug == after.Slug {
|
|
return nil
|
|
}
|
|
if !author.IsValidSlug(*patch.Slug) {
|
|
return author.ErrInvalidSlug
|
|
}
|
|
taken, err := isSlugTaken(u.authors, *patch.Slug)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if taken {
|
|
return author.ErrSlugTaken
|
|
}
|
|
after.Slug = *patch.Slug
|
|
return nil
|
|
}
|
|
|
|
func (u *UpdateAuthorUseCase) applyAvatar(after *author.Author, patch author.Patch) error {
|
|
if !patch.AvatarID.Set {
|
|
return nil
|
|
}
|
|
if err := ensureImageExists(u.images, patch.AvatarID.Value); err != nil {
|
|
return err
|
|
}
|
|
after.AvatarID = patch.AvatarID.Value
|
|
return nil
|
|
}
|
|
|
|
func (u *UpdateAuthorUseCase) applyLink(after *author.Author, patch author.Patch) error {
|
|
if !patch.UserID.Set {
|
|
return nil
|
|
}
|
|
requested := patch.UserID.Value
|
|
if requested == nil {
|
|
after.UserID = nil
|
|
after.IsLinked = false
|
|
return nil
|
|
}
|
|
if after.UserID != nil {
|
|
if *after.UserID == *requested {
|
|
return nil
|
|
}
|
|
return author.ErrAuthorAlreadyLinked
|
|
}
|
|
if err := ensureUserCanBeLinked(u.users, u.authors, *requested); err != nil {
|
|
return err
|
|
}
|
|
after.UserID = requested
|
|
after.IsLinked = true
|
|
return nil
|
|
}
|