feat: pending roles from crm to be confirmed by superadmins

This commit is contained in:
Björn Fromme committed 2026-08-10 12:26:21 +02:00
1 parent 681734533f
commit b01c2e84c7
26 files changed
+907 -150

No files matched your search

+79 -14
View File
@@ -19,18 +19,19 @@ class UserDataHandler
) {
}
public function collectRoles(CrmAttributesResponse $crmAttributes, ?string $preferredRole): array
/**
* Collects the roles to grant on initial user creation.
*
* Administrative roles are deliberately not importable: they may only be granted
* manually by a super admin, so that nobody can escalate their own privileges via
* the BusPro CRM. They are imported as pending markers instead, which grant nothing
* but mark the user for approval. ROLE_TEAMER carries no privileges of its own and
* is granted directly.
*/
public function collectRoles(CrmAttributesResponse $crmAttributes): array
{
// Collect user's roles from CRM attributes
$roles = [];
if ($crmAttributes->isAdmin() && (null === $preferredRole || 'admin' === $preferredRole)) {
$roles[] = 'ROLE_ADMIN';
} elseif ($crmAttributes->isManager() && (null === $preferredRole || 'manager' === $preferredRole)) {
$roles[] = 'ROLE_MANAGER';
} elseif ($crmAttributes->isHouseManager() && (null === $preferredRole || 'house_manager' === $preferredRole)) {
$roles[] = 'ROLE_HOUSE_MANAGER';
}
$roles = $this->collectPendingRoles($crmAttributes);
if ($crmAttributes->isTeamer()) {
$roles[] = 'ROLE_TEAMER';
@@ -39,6 +40,26 @@ class UserDataHandler
return $roles;
}
/**
* Collects the pending markers for the administrative roles claimed in the CRM.
*/
public function collectPendingRoles(CrmAttributesResponse $crmAttributes): array
{
$roles = [];
if ($crmAttributes->isAdmin()) {
$roles[] = User::PENDING_ROLES['ROLE_ADMIN'];
}
if ($crmAttributes->isManager()) {
$roles[] = User::PENDING_ROLES['ROLE_MANAGER'];
} elseif ($crmAttributes->isHouseManager()) {
$roles[] = User::PENDING_ROLES['ROLE_HOUSE_MANAGER'];
}
return $roles;
}
public function findLocalUser(ProfileResponse $profileResponse): ?User
{
// Check if user is already present in local database
@@ -141,22 +162,31 @@ class UserDataHandler
return $user;
}
/**
* Updates an existing user from BusPro data.
*
* Roles and hotel codes are imported once on user creation only and are managed
* manually afterwards, so they are intentionally left untouched here. The only
* exception are the privilege-free pending markers, which keep tracking the
* administrative roles claimed in the CRM.
*
* @param string[] $claimedRoles pending markers as returned by collectPendingRoles()
*/
public function updateLocalUser(
User $user,
ProfileResponse $profileResponse,
array $roles,
bool $isTeamer = false,
array $crmSelections = [],
array $hotelCodes = [],
array $claimedRoles = [],
): void {
$user
->setFirstName($profileResponse->getFirstName())
->setLastName($profileResponse->getName())
->setEmail($profileResponse->getCommunication()->getEmail())
->setRoles($roles)
->setHotelCodes($hotelCodes)
;
$this->refreshPendingRoles($user, $claimedRoles);
if (true === $isTeamer) {
$address = Address::fromApiResponse($profileResponse);
$communication = Communication::fromApiResponse($profileResponse);
@@ -187,4 +217,39 @@ class UserDataHandler
$this->entityManager->flush();
}
/**
* Keeps the pending markers in sync with the administrative roles claimed in the CRM.
* The markers grant no privileges, so tracking them on every login is safe: only a
* super admin can turn one into an actual role, and an already granted role is never
* marked as pending again.
*
* @param string[] $claimedRoles
*/
private function refreshPendingRoles(User $user, array $claimedRoles): void
{
// an approved role needs no marker anymore
$grantedRoles = $user->getAssignedRoles();
$pendingRoles = array_values(array_filter(
$claimedRoles,
static fn (string $pendingRole): bool => false === in_array(
array_search($pendingRole, User::PENDING_ROLES, true),
$grantedRoles,
true,
),
));
if ($pendingRoles === $user->getPendingRoles()) {
return;
}
// getAssignedRoles() returns the manually assignable roles without the markers
$user->setRoles([...$grantedRoles, ...$pendingRoles]);
$this->logger->info('Refresh pending roles', [
'user_id' => $user->getId(),
'user_email' => $user->getEmail(),
'pending_roles' => $pendingRoles,
]);
}
}