package useCases import ( "RenewCMS/internal/domain/audit" "RenewCMS/internal/domain/author" "RenewCMS/internal/domain/image" "RenewCMS/internal/domain/user" "context" "strings" ) type CreateAuthorUseCase struct { authors author.Repository users user.Repository images image.Repository recorder audit.Recorder } type CreateAuthorCommand struct { Name string Slug string Bio string AvatarID *uint32 Website *string SocialLinks []author.SocialLink UserID *uint32 } func NewCreateAuthorUseCase(authors author.Repository, users user.Repository, images image.Repository, recorder audit.Recorder) *CreateAuthorUseCase { return &CreateAuthorUseCase{authors: authors, users: users, images: images, recorder: recorder} } func (u *CreateAuthorUseCase) Create(ctx context.Context, command CreateAuthorCommand) (author.Author, error) { command.Name = strings.TrimSpace(command.Name) event := audit.NewEvent(audit.ActionAuthorCreate, audit.CategoryAuthors) event.Target = audit.Target{Type: audit.TargetAuthor, Name: command.Name} created, err := u.create(command) if err != nil { recordFailure(ctx, u.recorder, event, err) return author.Author{}, err } event.Target = authorTarget(created) u.recorder.Record(ctx, event) return withUserEmail(u.users, created), nil } func (u *CreateAuthorUseCase) create(command CreateAuthorCommand) (author.Author, error) { website, err := validateAuthorContent(command.Bio, command.Website, command.SocialLinks) if err != nil { return author.Author{}, err } if err := ensureImageExists(u.images, command.AvatarID); err != nil { return author.Author{}, err } if command.UserID != nil { if err := ensureUserCanBeLinked(u.users, u.authors, *command.UserID); err != nil { return author.Author{}, err } } slug, err := u.slugFor(command) if err != nil { return author.Author{}, err } links := command.SocialLinks if links == nil { links = []author.SocialLink{} } return u.authors.Create(author.Author{ Name: command.Name, Slug: slug, Bio: command.Bio, AvatarID: command.AvatarID, Website: website, SocialLinks: links, UserID: command.UserID, IsLinked: command.UserID != nil, }) } func (u *CreateAuthorUseCase) slugFor(command CreateAuthorCommand) (string, error) { slug := command.Slug if slug == "" { slug = author.GenerateSlug(command.Name) } if !author.IsValidSlug(slug) { return "", author.ErrInvalidSlug } taken, err := isSlugTaken(u.authors, slug) if err != nil { return "", err } if taken { return "", author.ErrSlugTaken } return slug, nil } func validateAuthorContent(bio string, website *string, links []author.SocialLink) (*string, error) { if err := author.ValidateBio(bio); err != nil { return nil, err } if err := author.ValidateLinks(links); err != nil { return nil, err } return author.NormalizeWebsite(website) }