authenticator( $this->crmAttributes([Role::ADMIN, Role::TEAMER, Role::GROUPS_ADMIN], ['SSL', 'SSL']), null, $persisted, ); $user = $this->loadUser($authenticator); self::assertSame($persisted, $user); self::assertSame(['ROLE_USER', Role::TEAMER], $user->getRoles()); self::assertSame(['SSL'], $user->getHotelCodes()); } public function testExistingAccountKeepsThePrivilegedRolesAnAdministratorAssigned(): void { $existing = (new User('teamer@example.org')) ->setRoles([Role::TEAMER, Role::GROUPS_MANAGER]) ->setHotelCodes(['DKS']) ; $persisted = null; $authenticator = $this->authenticator( $this->crmAttributes([Role::ADMIN, Role::CUSTOMER], ['SSL']), $existing, $persisted, ); $user = $this->loadUser($authenticator); self::assertNull($persisted, 'an existing account must not be persisted again'); // ROLE_TEAMER is gone with its CRM selection, ROLE_ADMIN is still not honoured, and the // administrator-granted ROLE_GROUPS_MANAGER survives. self::assertSame(['ROLE_USER', Role::CUSTOMER, Role::GROUPS_MANAGER], $user->getRoles()); self::assertSame(['DKS'], $user->getHotelCodes(), 'hotel codes stay administrator-managed'); self::assertNotNull($user->getLastLoginAt(), 'the rest of the profile is still synced'); } public function testRoleGainedInBusProIsGrantedOnLogin(): void { $existing = (new User('teamer@example.org'))->setRoles([Role::CUSTOMER]); $persisted = null; $authenticator = $this->authenticator( $this->crmAttributes([Role::TEAMER], []), $existing, $persisted, ); // The case myep-team depends on: somebody becomes a Teamer after their account exists. self::assertSame(['ROLE_USER', Role::TEAMER], $this->loadUser($authenticator)->getRoles()); } public function testAccountWithoutAnyRoleIsHealedOnLogin(): void { $existing = new User('teamer@example.org'); $persisted = null; $authenticator = $this->authenticator( $this->crmAttributes([Role::TEAMER], []), $existing, $persisted, ); self::assertSame(['ROLE_USER', Role::TEAMER], $this->loadUser($authenticator)->getRoles()); } /** * @param string[] $roles * @param string[] $hotelCodes */ private function crmAttributes(array $roles, array $hotelCodes): CrmAttributes { $attributes = new CrmAttributes(); $attributes->roles = $roles; $attributes->hotelCodes = $hotelCodes; return $attributes; } private function authenticator(CrmAttributes $crmAttributes, ?User $existing, ?User &$persisted): BpnAuthenticator { $personalData = new PersonalData(); $personalData->personId = 42; $personalData->addressId = 4711; $apiClient = $this->createMock(ApiClient::class); $apiClient->method('getPersonalData')->willReturn($personalData); $apiClient->method('getCrmAttributes')->willReturn($crmAttributes); $repository = $this->createMock(EntityRepository::class); $repository->method('findOneBy')->willReturn($existing); $entityManager = $this->createMock(EntityManagerInterface::class); $entityManager->method('getRepository')->willReturn($repository); $entityManager ->method('persist') ->willReturnCallback(static function (object $entity) use (&$persisted): void { $persisted = $entity; }) ; $crypt = $this->createMock(Crypt::class); $crypt->method('encrypt')->willReturn('encrypted'); $completenessChecker = $this->createMock(ProfileCompletenessChecker::class); $completenessChecker->method('isComplete')->willReturn(true); return new BpnAuthenticator( $this->createMock(UrlGeneratorInterface::class), $apiClient, $entityManager, $crypt, $completenessChecker, $this->createMock(LoggerInterface::class), ); } private function loadUser(BpnAuthenticator $authenticator): User { $request = new Request(); $request->request->set('_username', 'teamer@example.org'); $request->request->set('_password', 'secret'); $badge = $authenticator->authenticate($request)->getBadge(UserBadge::class); self::assertInstanceOf(UserBadge::class, $badge); $user = $badge->getUser(); self::assertInstanceOf(User::class, $user); return $user; } }