package useCases import ( "RenewCMS/internal/domain/audit" "RenewCMS/internal/domain/contenttype" "RenewCMS/internal/domain/role" "RenewCMS/internal/domain/user" "context" "errors" ) type RemoveUserUseCase struct { users user.Repository roles role.Repository contentTypes contenttype.Repository recorder audit.Recorder } type RemoveUserCommand struct { Caller ContentCaller TargetID uint32 ExpectedRoleID uint32 } func NewRemoveUserUseCase(users user.Repository, roles role.Repository, contentTypes contenttype.Repository, recorder audit.Recorder) *RemoveUserUseCase { return &RemoveUserUseCase{users: users, roles: roles, contentTypes: contentTypes, recorder: recorder} } func (u *RemoveUserUseCase) Remove(ctx context.Context, command RemoveUserCommand) error { if command.ExpectedRoleID == 0 { return role.ErrUnknownRole } target, err := u.users.Get(command.TargetID) if err != nil { return err } if err := u.check(command, target); err != nil { return err } event := audit.NewEvent(audit.ActionUserRemove, audit.CategoryUsers) event.Target = audit.NewTarget(audit.TargetUser, target.ID, target.Username) if err := u.users.DeleteIfRole(target.ID, command.ExpectedRoleID); err != nil { u.recordWriteFailure(ctx, event, err) return err } u.recorder.Record(ctx, event) return nil } func (u *RemoveUserUseCase) check(command RemoveUserCommand, target user.User) error { if target.ID == command.Caller.UserID { return role.ErrOwnRole } if target.RoleID != command.ExpectedRoleID { return user.ErrRoleChanged } held, err := resolveRole(u.roles, target) if errors.Is(err, role.ErrRoleNotFound) { return nil } if err != nil { return err } if held.Locked { return role.ErrRoleLocked } typeKeys, err := allowedTypeKeys(u.contentTypes) if err != nil { return err } return ensureCoveredBy(command.Caller, typeKeys, held) } func (u *RemoveUserUseCase) recordWriteFailure(ctx context.Context, event audit.Event, err error) { if errors.Is(err, user.ErrRoleChanged) || errors.Is(err, user.ErrUserNotFound) { return } recordFailure(ctx, u.recorder, event, err) }