feat: bpn as single source of truth for role and hotel code assignments
This commit is contained in:
@@ -72,9 +72,9 @@ class UserDataHandlerTest extends TestCase
|
||||
[User::PENDING_ROLES['ROLE_ADMIN'], User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
];
|
||||
|
||||
yield 'manager takes precedence over house manager' => [
|
||||
yield 'manager and house manager yield both markers, the roles stand on their own' => [
|
||||
(new CrmAttributesResponse())->setManager(true)->setHouseManager(true),
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER'], User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
||||
];
|
||||
|
||||
yield 'house manager and teamer' => [
|
||||
@@ -105,10 +105,10 @@ class UserDataHandlerTest extends TestCase
|
||||
[User::PENDING_ROLES['ROLE_ADMIN']],
|
||||
];
|
||||
|
||||
yield 'manager takes precedence over house manager' => [
|
||||
yield 'manager and house manager are marked independently' => [
|
||||
['ROLE_HOUSE_MANAGER', 'ROLE_MANAGER'],
|
||||
(new CrmAttributesResponse())->setManager(true)->setHouseManager(true),
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER'], User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
||||
];
|
||||
|
||||
yield 'house manager' => [
|
||||
@@ -172,14 +172,16 @@ class UserDataHandlerTest extends TestCase
|
||||
$profileResponse,
|
||||
true,
|
||||
['team' => ['selected' => true]],
|
||||
['ROLE_ADMIN', 'ROLE_TEAMER'],
|
||||
['DKS'],
|
||||
);
|
||||
|
||||
$this->assertSame('New', $user->getFirstName());
|
||||
$this->assertSame('Lastname', $user->getLastName());
|
||||
$this->assertSame('[email protected]', $user->getEmail());
|
||||
|
||||
// roles and hotel codes are imported on creation only and stay under manual control
|
||||
$this->assertSame(['XYZ'], $user->getHotelCodes());
|
||||
// the CRM leads: the still claimed role survives, the houses are replaced by its own
|
||||
$this->assertSame(['DKS'], $user->getHotelCodes());
|
||||
$this->assertTrue($user->hasRole('ROLE_ADMIN'));
|
||||
|
||||
$this->assertSame('New', $teamer->getFirstName());
|
||||
@@ -225,44 +227,51 @@ class UserDataHandlerTest extends TestCase
|
||||
{
|
||||
yield 'marker is added when the CRM claims a manager' => [
|
||||
['ROLE_TEAMER'],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
['ROLE_MANAGER', 'ROLE_TEAMER'],
|
||||
['ROLE_TEAMER'],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
];
|
||||
|
||||
yield 'marker is dropped when the CRM attribute is gone' => [
|
||||
[User::PENDING_ROLES['ROLE_HOUSE_MANAGER'], 'ROLE_TEAMER'],
|
||||
[],
|
||||
['ROLE_TEAMER'],
|
||||
['ROLE_TEAMER'],
|
||||
[],
|
||||
];
|
||||
|
||||
yield 'an approved role is never marked again' => [
|
||||
['ROLE_MANAGER'],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
['ROLE_MANAGER'],
|
||||
['ROLE_MANAGER'],
|
||||
[],
|
||||
];
|
||||
|
||||
yield 'a claim beyond the approved role stays pending' => [
|
||||
['ROLE_MANAGER'],
|
||||
[User::PENDING_ROLES['ROLE_ADMIN'], User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
['ROLE_ADMIN', 'ROLE_MANAGER'],
|
||||
['ROLE_MANAGER'],
|
||||
[User::PENDING_ROLES['ROLE_ADMIN']],
|
||||
];
|
||||
|
||||
yield 'the claimed role changes' => [
|
||||
[User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
['ROLE_MANAGER'],
|
||||
[],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
];
|
||||
|
||||
yield 'granted roles are untouched without any claim' => [
|
||||
['ROLE_ADMIN'],
|
||||
yield 'a granted role is revoked once the CRM stops claiming it' => [
|
||||
['ROLE_ADMIN', 'ROLE_TEAMER'],
|
||||
['ROLE_TEAMER'],
|
||||
['ROLE_TEAMER'],
|
||||
[],
|
||||
['ROLE_ADMIN'],
|
||||
];
|
||||
|
||||
yield 'a manager who is also a house manager is marked for both' => [
|
||||
[],
|
||||
['ROLE_MANAGER', 'ROLE_HOUSE_MANAGER'],
|
||||
[],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER'], User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -277,15 +286,18 @@ class UserDataHandlerTest extends TestCase
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], [User::PENDING_ROLES['ROLE_ADMIN']]);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], ['ROLE_ADMIN', 'ROLE_TEAMER']);
|
||||
|
||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||
$this->assertSame([User::PENDING_ROLES['ROLE_ADMIN']], $user->getPendingRoles());
|
||||
}
|
||||
|
||||
public function testUpdateLocalUserKeepsTheTeamerRoleOfSomebodyTheCrmNoLongerReportsAsTeamer(): void
|
||||
/**
|
||||
* ROLE_TEAMER needs no approval, but it is not exempt from the sync either: the CRM
|
||||
* leads, so the role goes when the attribute does.
|
||||
*/
|
||||
public function testUpdateLocalUserWithdrawsTheTeamerRoleOfSomebodyTheCrmNoLongerReportsAsTeamer(): void
|
||||
{
|
||||
// the role may have been granted manually and must survive a login
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
@@ -294,9 +306,9 @@ class UserDataHandlerTest extends TestCase
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], []);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], ['ROLE_ADMIN']);
|
||||
|
||||
$this->assertSame(['ROLE_ADMIN', 'ROLE_TEAMER'], $user->getAssignedRoles());
|
||||
$this->assertSame(['ROLE_ADMIN'], $user->getAssignedRoles());
|
||||
}
|
||||
|
||||
public function testUpdateLocalUserGrantsTheTeamerRoleOnlyOnce(): void
|
||||
@@ -309,11 +321,131 @@ class UserDataHandlerTest extends TestCase
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], []);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], ['ROLE_TEAMER']);
|
||||
|
||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||
}
|
||||
|
||||
/**
|
||||
* ROLE_SUPER_ADMIN is not a stored role but a flag getRoles() turns into one, so
|
||||
* revoking ROLE_ADMIN has to take it down explicitly - otherwise the highest privilege
|
||||
* in the application would outlive the role it depends on.
|
||||
*/
|
||||
public function testUpdateLocalUserTakesTheSuperAdminFlagDownWithRoleAdmin(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
->setEmail('[email protected]')
|
||||
->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER'])
|
||||
->setSuperAdmin(true)
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], ['ROLE_TEAMER']);
|
||||
|
||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||
$this->assertFalse($user->isSuperAdmin());
|
||||
$this->assertFalse($user->hasRole('ROLE_SUPER_ADMIN'));
|
||||
}
|
||||
|
||||
public function testUpdateLocalUserKeepsTheSuperAdminFlagOfAStillClaimedAdmin(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
->setEmail('[email protected]')
|
||||
->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER'])
|
||||
->setSuperAdmin(true)
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], ['ROLE_ADMIN']);
|
||||
|
||||
$this->assertTrue($user->isSuperAdmin());
|
||||
$this->assertTrue($user->hasRole('ROLE_SUPER_ADMIN'));
|
||||
}
|
||||
|
||||
public function testUpdateLocalUserReplacesTheHotelCodesWithTheOnesTheCrmReports(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
->setEmail('[email protected]')
|
||||
->setRoles(['ROLE_HOUSE_MANAGER'])
|
||||
->setHotelCodes(['SSL'])
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], ['ROLE_HOUSE_MANAGER'], ['DKS']);
|
||||
|
||||
$this->assertSame(['DKS'], $user->getHotelCodes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Approval is the one place a role is granted at all, and it can only ever grant a role
|
||||
* the CRM already claims - the marker is what says so.
|
||||
*/
|
||||
public function testApproveRoleGrantsTheRoleAndClearsItsMarker(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
->setEmail('[email protected]')
|
||||
->setRoles([
|
||||
'ROLE_TEAMER',
|
||||
User::PENDING_ROLES['ROLE_ADMIN'],
|
||||
User::PENDING_ROLES['ROLE_HOUSE_MANAGER'],
|
||||
])
|
||||
;
|
||||
|
||||
$this->entityManager->expects($this->once())->method('flush');
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
|
||||
$this->assertTrue($handler->approveRole($user, 'ROLE_ADMIN'));
|
||||
$this->assertSame(['ROLE_TEAMER', 'ROLE_ADMIN'], $user->getAssignedRoles());
|
||||
|
||||
// the other nomination is untouched: one decision at a time
|
||||
$this->assertSame([User::PENDING_ROLES['ROLE_HOUSE_MANAGER']], $user->getPendingRoles());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider unapprovableRoleProvider
|
||||
*/
|
||||
public function testApproveRoleRefusesARoleWithoutANomination(array $roles, string $role): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
->setEmail('[email protected]')
|
||||
->setRoles($roles)
|
||||
;
|
||||
|
||||
$this->entityManager->expects($this->never())->method('flush');
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
|
||||
$this->assertFalse($handler->approveRole($user, $role));
|
||||
$this->assertEqualsCanonicalizing(
|
||||
$roles,
|
||||
[...$user->getAssignedRoles(), ...$user->getPendingRoles()],
|
||||
);
|
||||
}
|
||||
|
||||
public static function unapprovableRoleProvider(): iterable
|
||||
{
|
||||
yield 'the CRM never claimed it' => [['ROLE_TEAMER'], 'ROLE_MANAGER'];
|
||||
|
||||
yield 'a different role is nominated' => [[User::PENDING_ROLES['ROLE_MANAGER']], 'ROLE_ADMIN'];
|
||||
|
||||
yield 'already granted, so there is no marker left' => [['ROLE_ADMIN'], 'ROLE_ADMIN'];
|
||||
|
||||
yield 'teamer has no nomination to approve' => [['ROLE_TEAMER'], 'ROLE_TEAMER'];
|
||||
|
||||
yield 'not a role at all' => [[User::PENDING_ROLES['ROLE_ADMIN']], 'ROLE_SUPER_ADMIN'];
|
||||
}
|
||||
|
||||
public function testDisableForRevokedCrmRolesBlocksTheUserAndDropsThePendingMarkers(): void
|
||||
{
|
||||
$user = (new User())
|
||||
|
||||
Reference in New Issue
Block a user