package useCases import ( "RenewCMS/internal/domain/audit" "RenewCMS/internal/domain/contenttype" "RenewCMS/internal/domain/role" "RenewCMS/internal/domain/user" "context" "errors" ) type ReassignRoleMembersUseCase struct { roles role.Repository users user.Repository contentTypes contenttype.Repository recorder audit.Recorder } type ReassignRoleMembersCommand struct { Caller ContentCaller SourceID uint32 TargetID uint32 } func NewReassignRoleMembersUseCase(roles role.Repository, users user.Repository, contentTypes contenttype.Repository, recorder audit.Recorder) *ReassignRoleMembersUseCase { return &ReassignRoleMembersUseCase{roles, users, contentTypes, recorder} } func (u *ReassignRoleMembersUseCase) Reassign(ctx context.Context, command ReassignRoleMembersCommand) (int, error) { source, err := u.roles.Get(command.SourceID) if err != nil { return 0, err } if err := u.checkSource(command.Caller, source); err != nil { return 0, err } target, err := u.checkTarget(command, source) if err != nil { return 0, err } event := audit.NewEvent(audit.ActionRoleReassign, audit.CategoryRoles) event.Target = roleTarget(source) event.Params[audit.ParamFrom] = source.ID event.Params[audit.ParamTo] = command.TargetID event.Params[audit.ParamToName] = target.Name event.Params[audit.ParamMoved] = 0 moved, err := u.roles.ReassignMembers(source.ID, command.TargetID) if err != nil { recordRoleWriteFailure(ctx, u.recorder, event, err) return 0, err } if moved > 0 { event.Params[audit.ParamMoved] = moved u.recorder.Record(ctx, event) } return moved, nil } func (u *ReassignRoleMembersUseCase) checkSource(caller ContentCaller, source role.Role) error { if err := ensureEditable(source); err != nil { return err } if err := ensureNotBuiltIn(source); err != nil { return err } if err := ensureNotOwnRole(u.roles, u.users, caller, source); err != nil { return err } return ensureCovered(caller, u.contentTypes, source) } func (u *ReassignRoleMembersUseCase) checkTarget(command ReassignRoleMembersCommand, source role.Role) (role.Role, error) { if command.TargetID == 0 || command.TargetID == source.ID { return role.Role{}, role.ErrInvalidReassign } target, err := u.roles.Get(command.TargetID) if errors.Is(err, role.ErrRoleNotFound) { return role.Role{}, role.ErrReassignTargetNotFound } if err != nil { return role.Role{}, err } if target.Locked { return role.Role{}, role.ErrInvalidReassign } if err := ensureCovered(command.Caller, u.contentTypes, target); err != nil { return role.Role{}, err } return target, nil }