feat: Users API, ownership transfer and removal of the legacy role string
This commit is contained in:
1 parent
094df63a7f
commit
80f7037d3a
124 files changed
+4644
-824
No files matched your search
@@ -0,0 +1,103 @@
|
||||
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 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type OwnershipPredecessor struct {
|
||||
ID uint32 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Role RoleRef `json:"role"`
|
||||
}
|
||||
|
||||
type OwnershipTransfer struct {
|
||||
Owner OwnershipSuccessor `json:"owner"`
|
||||
FormerOwner OwnershipPredecessor `json:"former_owner"`
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
Reference in new issue
Block a user