Files
RenewCMS/internal/infrastructure/useCases/CreateMyAuthor.go
T

81 lines
2.3 KiB
Go

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
}