feat: Authors feature backend (and upgraded deprecated mods)
This commit is contained in:
1 parent
a11338094e
commit
b34a173d83
103 files changed
+6454
-240
No files matched your search
@@ -0,0 +1,80 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/audit"
|
||||
"RenewCMS/internal/domain/author"
|
||||
"RenewCMS/internal/domain/user"
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const maxOwnSlugAttempts = 50
|
||||
|
||||
type CreateMyAuthorUseCase struct {
|
||||
authors author.Repository
|
||||
users user.Repository
|
||||
recorder audit.Recorder
|
||||
}
|
||||
|
||||
func NewCreateMyAuthorUseCase(authors author.Repository, users user.Repository, recorder audit.Recorder) *CreateMyAuthorUseCase {
|
||||
return &CreateMyAuthorUseCase{authors: authors, users: users, recorder: recorder}
|
||||
}
|
||||
|
||||
func (u *CreateMyAuthorUseCase) Create(ctx context.Context, userID uint32) (author.Author, error) {
|
||||
caller, err := u.users.Get(userID)
|
||||
if err != nil {
|
||||
return author.Author{}, err
|
||||
}
|
||||
name := authorNameOf(caller)
|
||||
event := audit.NewEvent(audit.ActionAuthorCreate, audit.CategoryAuthors)
|
||||
event.Target = audit.Target{Type: audit.TargetAuthor, Name: name}
|
||||
created, err := u.create(caller, name)
|
||||
if err != nil {
|
||||
recordFailure(ctx, u.recorder, event, err)
|
||||
return author.Author{}, err
|
||||
}
|
||||
event.Target = authorTarget(created)
|
||||
u.recorder.Record(ctx, event)
|
||||
return created, nil
|
||||
}
|
||||
|
||||
func authorNameOf(caller user.User) string {
|
||||
name := strings.TrimSpace(caller.DisplayName)
|
||||
if name == "" {
|
||||
name = strings.TrimSpace(caller.Username)
|
||||
}
|
||||
runes := []rune(name)
|
||||
return string(runes[:min(len(runes), author.MaxNameRunes)])
|
||||
}
|
||||
|
||||
func (u *CreateMyAuthorUseCase) create(caller user.User, name string) (author.Author, error) {
|
||||
_, err := u.authors.GetByUserID(caller.ID)
|
||||
if err == nil {
|
||||
return author.Author{}, author.ErrUserAlreadyLinked
|
||||
}
|
||||
if !errors.Is(err, author.ErrAuthorNotFound) {
|
||||
return author.Author{}, err
|
||||
}
|
||||
return u.createWithFreeSlug(caller.ID, name)
|
||||
}
|
||||
|
||||
func (u *CreateMyAuthorUseCase) createWithFreeSlug(userID uint32, name string) (author.Author, error) {
|
||||
base := author.GenerateSlug(name)
|
||||
for attempt := 1; attempt <= maxOwnSlugAttempts; attempt++ {
|
||||
slug := author.SlugWithSuffix(base, attempt)
|
||||
taken, err := isSlugTaken(u.authors, slug)
|
||||
if err != nil {
|
||||
return author.Author{}, err
|
||||
}
|
||||
if taken {
|
||||
continue
|
||||
}
|
||||
created, err := u.authors.Create(author.Author{Name: name, Slug: slug, SocialLinks: []author.SocialLink{}, UserID: &userID, IsLinked: true})
|
||||
if errors.Is(err, author.ErrSlugTaken) {
|
||||
continue
|
||||
}
|
||||
return created, err
|
||||
}
|
||||
return author.Author{}, author.ErrSlugTaken
|
||||
}
|
||||
Reference in new issue
Block a user