CoolCMS API

UserRolePolicy
in package

FinalYes

Gates over user roles: pure decisions without DB (the data comes from {@see \App\UI\Api\System\Models\Managers\UserManager}).

  • Role changes (self::assignmentRefusal()):
    • only a caller holding the "set roles" privilege (:Api:System:User:setRoles, granted to the admin role only) may change the role set of a user. Without it any change of the set is refused, adding and removing alike, even with a forged POST; saving with the same set (or without meta.roleIds) passes. The right to edit the user (other fields) was already checked by the Api gate of the save action;
    • a role with assignable = 0 (owner, receiver, guest: implicit or conditional grants) is assigned by nobody, neither a privileged caller nor internal code; removing a mistakenly created link is allowed (with the privilege);
    • an unknown role id is not assigned (it would end in a foreign key failure);
    • the baseline when creating is the roles a new account gets by itself (set_after_registration); a caller without the privilege may send only those (or nothing), otherwise [] would silently drop the default roles;
    • $canSetRoles === null means no caller (cron/CLI calls the manager directly, the audience was not evaluated) and the privilege is not checked (same boundary as FieldAudienceContext).
  • Protected role (protect_last_holder = 1, currently admin):
    • self::lastHolderRefusal(): the role cannot be removed from its last active holder and that account cannot be deactivated, banned or canceled (self::deactivationRefusal() does the same in bulk via updateColumns);
    • self::deleteRefusal(): the last active holder cannot be deleted. The caller's own account is never deleted. Applies to every caller including internal code. "Active" means an activated, non-banned, non-canceled account without a pending cancellation request (counted by UserRelationManager).

Table of Contents

Methods

assignmentRefusal()  : Result|null
deactivationRefusal()  : Result|null
Refuses a bulk deactivation / ban / cancellation request (`updateColumns`) when the affected accounts are all the active holders of some protected role.
defaultRoleIds()  : array<int, int>
Roles a new account gets by itself ({@see \App\UI\Api\System\Models\Managers\UserRelationManager::grantDefaultRoles()}).
deleteRefusal()  : Result|null
ids()  : array<int, int>
Returns unique positive integer ids (same normalization as the set-based link sync).
lastHolderRefusal()  : Result|null
Refuses an account save that would leave a protected role without its last active holder: removing that role (`USER_ROLE_LAST_HOLDER_BLOCKED`), or deactivating / banning / canceling the account that still holds it (`USER_DEACTIVATE_LAST_HOLDER_BLOCKED`).
deactivateRefusal()  : Result
roleLosingAllHolders()  : int|null
Returns the first protected role whose active holders are all among `$userIds` (and at least one is).

Methods

assignmentRefusal()

public static assignmentRefusal(array<int, int> $currentIds, array<string|int, mixed> $requestedIds, array<int, array{assignable: bool, default: bool, protectLastHolder: bool}> $roles, bool $isInsert, bool|null $canSetRoles) : Result|null
Parameters
$currentIds : array<int, int>

roles the target account has now (ignored when creating)

$requestedIds : array<string|int, mixed>

requested resulting set (meta.roleIds)

$roles : array<int, array{assignable: bool, default: bool, protectLastHolder: bool}>

role catalog (id to flags)

$isInsert : bool
$canSetRoles : bool|null

whether the caller holds :Api:System:User:setRoles; null = internal code without a caller

Return values
Result|null

deactivationRefusal()

Refuses a bulk deactivation / ban / cancellation request (`updateColumns`) when the affected accounts are all the active holders of some protected role.

public static deactivationRefusal(array<string|int, mixed> $userIds, array<int, array<int, int>> $activeHoldersByRole) : Result|null
Parameters
$userIds : array<string|int, mixed>
$activeHoldersByRole : array<int, array<int, int>>
Return values
Result|null

defaultRoleIds()

Roles a new account gets by itself ({@see \App\UI\Api\System\Models\Managers\UserRelationManager::grantDefaultRoles()}).

public static defaultRoleIds(array<int, array{assignable: bool, default: bool, protectLastHolder: bool}> $roles) : array<int, int>
Parameters
$roles : array<int, array{assignable: bool, default: bool, protectLastHolder: bool}>
Return values
array<int, int>

deleteRefusal()

public static deleteRefusal(array<string|int, mixed> $deleteIds, int|null $callerId, array<int, array<int, int>> $activeHoldersByRole) : Result|null
Parameters
$deleteIds : array<string|int, mixed>

ids of the accounts to delete

$callerId : int|null

signed-in caller (null = internal code / anonymous)

$activeHoldersByRole : array<int, array<int, int>>

protected role to ids of its active holders

Return values
Result|null

ids()

Returns unique positive integer ids (same normalization as the set-based link sync).

public static ids(array<string|int, mixed> $values) : array<int, int>
Parameters
$values : array<string|int, mixed>
Return values
array<int, int>

lastHolderRefusal()

Refuses an account save that would leave a protected role without its last active holder: removing that role (`USER_ROLE_LAST_HOLDER_BLOCKED`), or deactivating / banning / canceling the account that still holds it (`USER_DEACTIVATE_LAST_HOLDER_BLOCKED`).

public static lastHolderRefusal(int $userId, array<int, int> $currentIds, array<string|int, mixed>|null $requestedIds, bool $staysActive, array<int, array<int, int>> $activeHoldersByRole) : Result|null
Parameters
$userId : int
$currentIds : array<int, int>

roles the account has now

$requestedIds : array<string|int, mixed>|null

requested resulting set; null = roles unchanged

$staysActive : bool

whether the account stays active after the save (activated, non-banned, non-canceled)

$activeHoldersByRole : array<int, array<int, int>>

protected role to ids of its active holders

Return values
Result|null

roleLosingAllHolders()

Returns the first protected role whose active holders are all among `$userIds` (and at least one is).

private static roleLosingAllHolders(array<int, int> $userIds, array<int, array<int, int>> $activeHoldersByRole) : int|null
Parameters
$userIds : array<int, int>
$activeHoldersByRole : array<int, array<int, int>>
Return values
int|null
On this page

Search results