feat: bpn as single source of truth for role and hotel code assignments

This commit is contained in:
Björn Fromme
2026-08-18 11:33:42 +02:00
parent 1fd0fbc21e
commit f0e850978b
17 changed files with 818 additions and 198 deletions
+22 -11
View File
@@ -161,6 +161,7 @@ class MyEpAuthenticator extends AbstractAuthenticator
$isTeamer = in_array('ROLE_TEAMER', $claimedRoles, true);
$pendingRoles = $this->userDataHandler->toPendingRoles($claimedRoles);
$hotelCodes = $this->collectHotelCodes($userinfo);
$user = $this->findLocalUser($userinfo);
@@ -177,23 +178,20 @@ class MyEpAuthenticator extends AbstractAuthenticator
return $user;
}
// Update existing user, leaving granted roles and hotel codes alone: they are
// imported once on creation and managed manually afterwards. Only the
// privilege-free markers and ROLE_TEAMER track MyE&P on every login.
// Update existing user. MyE&P leads here exactly as BusPro does on the other login
// path - the shared policy in UserDataHandler withdraws what is no longer claimed
// and marks administrative claims for approval rather than granting them.
if (null !== $user) {
$this->refreshBusProIds($user, $userinfo);
$this->userDataHandler->refreshPendingRoles($user, $pendingRoles);
if (true === $isTeamer) {
$this->userDataHandler->grantTeamerRole($user);
}
$this->userDataHandler->syncRoles($user, $claimedRoles);
$this->userDataHandler->syncHotelCodes($user, $hotelCodes);
$this->entityManager->flush();
return $user;
}
return $this->createLocalUser($userinfo, $pendingRoles, $isTeamer);
return $this->createLocalUser($userinfo, $pendingRoles, $isTeamer, $hotelCodes);
}
/**
@@ -233,6 +231,19 @@ class MyEpAuthenticator extends AbstractAuthenticator
return $claimedRoles;
}
/**
* The houses MyE&P reports for this person. Read on both the create and the update
* path, since they are led by the identity provider just like the roles are.
*
* @return string[]
*/
private function collectHotelCodes(array $userinfo): array
{
$profile = is_array($userinfo['profile'] ?? null) ? $userinfo['profile'] : [];
return is_array($profile['hotel_codes'] ?? null) ? array_values($profile['hotel_codes']) : [];
}
/**
* Matches the local account on the BusPro ids first and falls back to the email, the
* same precedence UserDataHandler::findLocalUser() applies to a BusPro login, so that
@@ -300,8 +311,9 @@ class MyEpAuthenticator extends AbstractAuthenticator
/**
* @param string[] $pendingRoles
* @param string[] $hotelCodes
*/
private function createLocalUser(array $userinfo, array $pendingRoles, bool $isTeamer): ?User
private function createLocalUser(array $userinfo, array $pendingRoles, bool $isTeamer, array $hotelCodes): ?User
{
$addressId = $userinfo['address_id'] ?? null;
$personId = $userinfo['person_id'] ?? null;
@@ -318,7 +330,6 @@ class MyEpAuthenticator extends AbstractAuthenticator
}
$profile = is_array($userinfo['profile'] ?? null) ? $userinfo['profile'] : [];
$hotelCodes = is_array($profile['hotel_codes'] ?? null) ? $profile['hotel_codes'] : [];
$user = new User();
$user