feat: sync non-privileged BusPro roles on every login

This commit is contained in:
Björn Fromme
2026-08-12 17:47:15 +02:00
parent 490acc2e8b
commit 7a82127494
4 changed files with 116 additions and 11 deletions
+44
View File
@@ -13,6 +13,12 @@ namespace App\Security;
*/
final class Role
{
/**
* The role every account holds implicitly. User::getRoles() prepends it and it is never
* stored, so it has to be filtered out wherever a role set is written back.
*/
public const USER = 'ROLE_USER';
public const ADMIN = 'ROLE_ADMIN';
public const MANAGER = 'ROLE_MANAGER';
public const TEAMER = 'ROLE_TEAMER';
@@ -66,6 +72,44 @@ final class Role
return [] === $importable ? [self::CUSTOMER] : $importable;
}
/**
* The non-privileged half of a role set: what BpnAuthenticator syncs from the BusPro CRM.
*
* @param string[] $roles
*
* @return string[]
*/
public static function syncedOnly(array $roles): array
{
return array_values(array_diff($roles, self::PRIVILEGED, [self::USER]));
}
/**
* The privileged half: what an administrator granted in /admin/user.
*
* @param string[] $roles
*
* @return string[]
*/
public static function privilegedOnly(array $roles): array
{
return array_values(array_intersect($roles, self::PRIVILEGED));
}
/**
* Reassembles a complete role set from its two owners. Both sides are filtered, so a
* privileged role can never arrive through the synced half and vice versa.
*
* @param string[] $synced
* @param string[] $privileged
*
* @return string[]
*/
public static function combine(array $synced, array $privileged): array
{
return array_values(array_unique([...self::syncedOnly($synced), ...self::privilegedOnly($privileged)]));
}
/**
* @return array<string, string> role => label
*/