package useCases import ( "RenewCMS/internal/domain/audit" "RenewCMS/internal/domain/hash" "RenewCMS/internal/domain/invite" "RenewCMS/internal/domain/user" "context" "errors" "strings" "time" ) type AcceptInviteUseCase struct { userRepository user.Repository inviteRepository invite.Repository hasher hash.Hasher recorder audit.Recorder } type AcceptInviteCommand struct { Code string Username string Password string } func NewAcceptInviteUseCase(userRepository user.Repository, inviteRepository invite.Repository, hasher hash.Hasher, recorder audit.Recorder) *AcceptInviteUseCase { return &AcceptInviteUseCase{userRepository, inviteRepository, hasher, recorder} } func (a *AcceptInviteUseCase) AcceptInvite(ctx context.Context, command AcceptInviteCommand) (user.User, error) { event := audit.NewEvent(audit.ActionInviteAccept, audit.CategoryUsers) now := time.Now() pending, err := findUsableInvite(a.inviteRepository, a.hasher, command.Code, now) if err != nil { a.recordRefusal(ctx, event, command, err) return user.User{}, err } event.Target = inviteTarget(pending) created, err := a.accept(command, pending, now) if err != nil { a.recordRefusal(ctx, event, command, err) return user.User{}, err } event.Actor = audit.UserActor(created) a.recorder.Record(ctx, event) return created, nil } func (a *AcceptInviteUseCase) recordRefusal(ctx context.Context, event audit.Event, command AcceptInviteCommand, cause error) { event.Actor = audit.AnonymousActor(command.Username) recordFailure(ctx, a.recorder, event, cause) } func (a *AcceptInviteUseCase) accept(command AcceptInviteCommand, pending invite.Invite, now time.Time) (user.User, error) { if a.emailHasAccount(pending.Email) { if _, err := findUsableInvite(a.inviteRepository, a.hasher, command.Code, now); err != nil { return user.User{}, err } return user.User{}, invite.ErrEmailHasAccount } if err := a.ensureUsernameFree(command.Username); err != nil { return user.User{}, err } hashedPassword, err := a.hasher.Hash(command.Password) if err != nil { return user.User{}, err } createdUser, err := a.inviteRepository.AcceptWithUser(pending.ID, now, user.User{ Username: command.Username, Password: hashedPassword, Email: pending.Email, IsVerified: true, Role: user.RoleAdmin, }) if errors.Is(err, invite.ErrInviteNotFound) { return user.User{}, invite.ErrInviteInvalid } if err != nil { return user.User{}, err } return createdUser, nil } func (a *AcceptInviteUseCase) emailHasAccount(email string) bool { for _, existingUser := range a.userRepository.GetAll() { if strings.EqualFold(existingUser.Email, email) { return true } } return false } func (a *AcceptInviteUseCase) ensureUsernameFree(username string) error { _, err := a.userRepository.GetByUsername(username) if err == nil { return user.ErrUsernameTaken } if errors.Is(err, user.ErrUserNotFound) { return nil } return err }