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

104 lines
2.9 KiB
Go

package useCases
import (
"RenewCMS/internal/domain/audit"
"RenewCMS/internal/domain/role"
"RenewCMS/internal/domain/user"
"context"
"errors"
)
type TransferOwnershipUseCase struct {
users user.Repository
roles role.Repository
recorder audit.Recorder
}
type TransferOwnershipCommand struct {
Caller ContentCaller
UserID uint32
ConfirmEmail string
}
type OwnershipSuccessor struct {
ID uint32
Name string
}
type OwnershipPredecessor struct {
ID uint32
Name string
Role RoleRef
}
type OwnershipTransfer struct {
Owner OwnershipSuccessor
FormerOwner OwnershipPredecessor
}
func NewTransferOwnershipUseCase(users user.Repository, roles role.Repository, recorder audit.Recorder) *TransferOwnershipUseCase {
return &TransferOwnershipUseCase{users: users, roles: roles, recorder: recorder}
}
var transferRefusals = []error{user.ErrRoleChanged, user.ErrInvalidTransfer, user.ErrUserNotFound}
func (u *TransferOwnershipUseCase) Transfer(ctx context.Context, command TransferOwnershipCommand) (OwnershipTransfer, error) {
successor, err := u.successor(command)
if err != nil {
return OwnershipTransfer{}, err
}
former, err := u.users.Get(command.Caller.UserID)
if err != nil {
return OwnershipTransfer{}, err
}
ownerRole, err := builtInRole(u.roles, role.OwnerName)
if err != nil {
return OwnershipTransfer{}, err
}
adminRole, err := builtInRole(u.roles, role.AdminName)
if err != nil {
return OwnershipTransfer{}, err
}
event := audit.NewEvent(audit.ActionUserTransferOwnership, audit.CategoryUsers)
event.Security = true
event.Target = audit.NewTarget(audit.TargetUser, successor.ID, successor.Username)
if err := u.users.TransferOwnership(former.ID, successor.ID, ownerRole.ID, adminRole.ID); err != nil {
u.recordWriteFailure(ctx, event, err)
return OwnershipTransfer{}, err
}
event.Params[audit.ParamFrom] = former.ID
event.Params[audit.ParamTo] = successor.ID
u.recorder.Record(ctx, event)
return OwnershipTransfer{
Owner: OwnershipSuccessor{ID: successor.ID, Name: successor.NameOrUsername()},
FormerOwner: OwnershipPredecessor{ID: former.ID, Name: former.NameOrUsername(), Role: NewRoleRef(adminRole)},
}, nil
}
func (u *TransferOwnershipUseCase) successor(command TransferOwnershipCommand) (user.User, error) {
successor, err := u.users.Get(command.UserID)
if errors.Is(err, user.ErrUserNotFound) {
return user.User{}, user.ErrInvalidTransfer
}
if err != nil {
return user.User{}, err
}
if successor.ID == command.Caller.UserID || !successor.IsVerified {
return user.User{}, user.ErrInvalidTransfer
}
if successor.Email != command.ConfirmEmail {
return user.User{}, user.ErrConfirmationMismatch
}
return successor, nil
}
func (u *TransferOwnershipUseCase) recordWriteFailure(ctx context.Context, event audit.Event, err error) {
for _, refusal := range transferRefusals {
if errors.Is(err, refusal) {
return
}
}
recordFailure(ctx, u.recorder, event, err)
}