From ca37ab65b7a54eafce9b3a21bc1a3e0a2518c48e Mon Sep 17 00:00:00 2001 From: Ian Lindsay Date: Tue, 29 Oct 2024 09:18:12 +0000 Subject: [PATCH] feat: welcome page for external users with terms and conditions VOL-5664 --- .../module/Api/config/command-map.config.php | 1 + .../Api/config/validation-map/user.config.php | 1 + .../Domain/CommandHandler/User/AgreeTerms.php | 46 ++++++ .../User/RegisterConsultantAndOperator.php | 18 ++- .../User/RegisterUserSelfserve.php | 5 + .../QueryHandler/MyAccount/MyAccount.php | 1 + .../Api/src/Entity/User/AbstractUser.php | 33 ++++ app/api/module/Api/src/Entity/User/User.php | 12 ++ .../CommandHandler/User/AgreeTermsTest.php | 63 ++++++++ .../RegisterConsultantAndOperatorTest.php | 11 +- .../User/RegisterUserSelfserveTest.php | 42 +++-- .../Api/src/Entity/User/UserEntityTest.php | 8 + app/selfserve/module/Olcs/Module.php | 4 + .../module/Olcs/config/module.config.php | 15 ++ .../Olcs/src/Controller/WelcomeController.php | 59 +++++++ .../Controller/WelcomeControllerFactory.php | 24 +++ .../src/Form/Model/Fieldset/AgreeTerms.php | 28 ++++ .../Form/Model/Fieldset/ContinueOrSignOut.php | 37 +++++ .../Olcs/src/Form/Model/Form/AgreeTerms.php | 28 ++++ .../Olcs/src/Mvc/TermsAgreedListener.php | 73 +++++++++ .../src/Mvc/TermsAgreedListenerFactory.php | 20 +++ .../module/Olcs/view/pages/welcome.phtml | 23 +++ .../Olcs/src/Mvc/TermsAgreedListenerTest.php | 144 ++++++++++++++++++ 23 files changed, 680 insertions(+), 16 deletions(-) create mode 100644 app/api/module/Api/src/Domain/CommandHandler/User/AgreeTerms.php create mode 100644 app/api/test/module/Api/src/Domain/CommandHandler/User/AgreeTermsTest.php create mode 100644 app/selfserve/module/Olcs/src/Controller/WelcomeController.php create mode 100644 app/selfserve/module/Olcs/src/Controller/WelcomeControllerFactory.php create mode 100644 app/selfserve/module/Olcs/src/Form/Model/Fieldset/AgreeTerms.php create mode 100644 app/selfserve/module/Olcs/src/Form/Model/Fieldset/ContinueOrSignOut.php create mode 100644 app/selfserve/module/Olcs/src/Form/Model/Form/AgreeTerms.php create mode 100644 app/selfserve/module/Olcs/src/Mvc/TermsAgreedListener.php create mode 100644 app/selfserve/module/Olcs/src/Mvc/TermsAgreedListenerFactory.php create mode 100644 app/selfserve/module/Olcs/view/pages/welcome.phtml create mode 100644 app/selfserve/test/Olcs/src/Mvc/TermsAgreedListenerTest.php diff --git a/app/api/module/Api/config/command-map.config.php b/app/api/module/Api/config/command-map.config.php index 8295e33f77..ce4dced300 100644 --- a/app/api/module/Api/config/command-map.config.php +++ b/app/api/module/Api/config/command-map.config.php @@ -375,6 +375,7 @@ TransferCommand\User\DeletePartner::class => CommandHandler\User\DeletePartner::class, TransferCommand\User\UpdateUserLastLoginAt::class => CommandHandler\User\UpdateUserLastLoginAt::class, TransferCommand\User\RegisterConsultantAndOperator::class => CommandHandler\User\RegisterConsultantAndOperator::class, + TransferCommand\User\AgreeTerms::class => CommandHandler\User\AgreeTerms::class, // Transfer - Team TransferCommand\Team\CreateTeam::class => CommandHandler\Team\CreateTeam::class, diff --git a/app/api/module/Api/config/validation-map/user.config.php b/app/api/module/Api/config/validation-map/user.config.php index 899962ecf7..ae5e12c612 100644 --- a/app/api/module/Api/config/validation-map/user.config.php +++ b/app/api/module/Api/config/validation-map/user.config.php @@ -41,4 +41,5 @@ CommandHandler\User\UpdateUserSelfserve::class => CanManageUser::class, CommandHandler\User\UpdateUserSelfserveFactory::class => CanManageUser::class, CommandHandler\User\UpdateUserLastLoginAt::class => NotIsAnonymousUser::class, + CommandHandler\User\AgreeTerms::class => IsExternalUser::class, ]; diff --git a/app/api/module/Api/src/Domain/CommandHandler/User/AgreeTerms.php b/app/api/module/Api/src/Domain/CommandHandler/User/AgreeTerms.php new file mode 100644 index 0000000000..225979f526 --- /dev/null +++ b/app/api/module/Api/src/Domain/CommandHandler/User/AgreeTerms.php @@ -0,0 +1,46 @@ +getCurrentUser()->getId(); + + /** + * @var UserRepository $repo + * @var User $user + */ + $repo = $this->getRepo(); + + $user = $repo->fetchById($userId); + $user->agreeTermsAndConditions(); + $repo->save($user); + + $this->clearUserCaches([$userId]); + + $this->result->addId('User', $userId); + $this->result->addMessage(self::SUCCESS_MSG); + + return $this->result; + } +} diff --git a/app/api/module/Api/src/Domain/CommandHandler/User/RegisterConsultantAndOperator.php b/app/api/module/Api/src/Domain/CommandHandler/User/RegisterConsultantAndOperator.php index b7a8044299..209d0787bd 100644 --- a/app/api/module/Api/src/Domain/CommandHandler/User/RegisterConsultantAndOperator.php +++ b/app/api/module/Api/src/Domain/CommandHandler/User/RegisterConsultantAndOperator.php @@ -10,6 +10,7 @@ use Dvsa\Olcs\Api\Domain\CommandHandler\AbstractUserCommandHandler; use Dvsa\Olcs\Api\Domain\CommandHandler\TransactionedInterface; use Dvsa\Olcs\Api\Entity\User\Role as RoleEntity; +use Dvsa\Olcs\Api\Entity\User\User as UserEntity; use Dvsa\Olcs\Transfer\Command\CommandInterface; use Dvsa\Olcs\Transfer\Command\User\RegisterUserSelfserve as RegisterUserSelfServeCommand; @@ -20,8 +21,12 @@ final class RegisterConsultantAndOperator extends AbstractUserCommandHandler imp public function handleCommand(CommandInterface $command) { + //because this is being created by a transport consultant the operator admin will need to agree terms + $operatorDetails = $command->getOperatorDetails(); + $operatorDetails['createdByConsultant'] = true; + // Register the operator first, a new Org will be created. - $this->result->merge($this->handleSideEffect(RegisterUserSelfServeCommand::create($command->getOperatorDetails()))); + $this->result->merge($this->handleSideEffect(RegisterUserSelfServeCommand::create($operatorDetails))); // Get the newly created user entity $user = $this->getRepo()->fetchById($this->result->getId('user')); @@ -32,10 +37,19 @@ public function handleCommand(CommandInterface $command) $this->result->merge($this->handleSideEffect(RegisterUserSelfServeCommand::create($consultantDetails))); - // Get the new consultant user entity and set the correct role. + /** + * Get the new consultant user entity and set the correct role + * + * @var UserEntity $consultantUser + * @var RoleEntity $operatorTcRole + */ $consultantUser = $this->getRepo()->fetchById($this->result->getId('user')); $operatorTcRole = $this->getRepo('Role')->fetchByRole(RoleEntity::ROLE_OPERATOR_TC); $consultantUser->setRoles(new ArrayCollection([$operatorTcRole])); + + //the consultant has already accepted terms and conditions + $consultantUser->agreeTermsAndConditions(); + $this->getRepo()->save($consultantUser); return $this->result; } diff --git a/app/api/module/Api/src/Domain/CommandHandler/User/RegisterUserSelfserve.php b/app/api/module/Api/src/Domain/CommandHandler/User/RegisterUserSelfserve.php index 7a86c11c5e..4436e0d42f 100644 --- a/app/api/module/Api/src/Domain/CommandHandler/User/RegisterUserSelfserve.php +++ b/app/api/module/Api/src/Domain/CommandHandler/User/RegisterUserSelfserve.php @@ -89,6 +89,11 @@ public function handleCommand(CommandInterface $command) ) ); + //if the user wasn't created by a transport consultant + if ($command->getCreatedByConsultant() !== true) { + $user->agreeTermsAndConditions(); + } + $result = new Result(); $this->getRepo()->save($user); diff --git a/app/api/module/Api/src/Domain/QueryHandler/MyAccount/MyAccount.php b/app/api/module/Api/src/Domain/QueryHandler/MyAccount/MyAccount.php index 7735845b55..86394b6c06 100644 --- a/app/api/module/Api/src/Domain/QueryHandler/MyAccount/MyAccount.php +++ b/app/api/module/Api/src/Domain/QueryHandler/MyAccount/MyAccount.php @@ -95,6 +95,7 @@ public function handleQuery(QueryInterface $query) $result = $this->result( $user, [ + 'termsAgreed', 'team', 'transportManager', 'partnerContactDetails', diff --git a/app/api/module/Api/src/Entity/User/AbstractUser.php b/app/api/module/Api/src/Entity/User/AbstractUser.php index 2d3ad24058..cd62e2d139 100644 --- a/app/api/module/Api/src/Entity/User/AbstractUser.php +++ b/app/api/module/Api/src/Entity/User/AbstractUser.php @@ -205,6 +205,15 @@ abstract class AbstractUser implements BundleSerializableInterface, JsonSerializ */ protected $translateToWelsh = 0; + /** + * Terms agreed + * + * @var boolean + * + * @ORM\Column(type="boolean", name="terms_agreed", nullable=false, options={"default": 0}) + */ + protected $termsAgreed = 0; + /** * Transport manager * @@ -303,6 +312,30 @@ public function getAccountDisabled() return $this->accountDisabled; } + /** + * Set the terms agreed + * + * @param boolean $termsAgreed new value being set + * + * @return User + */ + public function setTermsAgreed($termsAgreed) + { + $this->termsAgreed = $termsAgreed; + + return $this; + } + + /** + * Get the terms agreed + * + * @return boolean + */ + public function getTermsAgreed() + { + return $this->termsAgreed; + } + /** * Set the contact details * diff --git a/app/api/module/Api/src/Entity/User/User.php b/app/api/module/Api/src/Entity/User/User.php index 526e4a413e..e67b6a5557 100644 --- a/app/api/module/Api/src/Entity/User/User.php +++ b/app/api/module/Api/src/Entity/User/User.php @@ -765,4 +765,16 @@ public function canResetPassword(): bool //disabled users can't reset return !$this->isDisabled(); } + + public function agreeTermsAndConditions(): User + { + $this->termsAgreed = true; + + return $this; + } + + public function hasAgreedTermsAndConditions(): bool + { + return $this->termsAgreed; + } } diff --git a/app/api/test/module/Api/src/Domain/CommandHandler/User/AgreeTermsTest.php b/app/api/test/module/Api/src/Domain/CommandHandler/User/AgreeTermsTest.php new file mode 100644 index 0000000000..dae7bfb143 --- /dev/null +++ b/app/api/test/module/Api/src/Domain/CommandHandler/User/AgreeTermsTest.php @@ -0,0 +1,63 @@ +sut = new AgreeTerms(); + $this->mockRepo('User', UserRepository::class); + + $this->mockedSmServices = [ + AuthorizationService::class => m::mock(AuthorizationService::class), + CacheEncryption::class => m::mock(CacheEncryption::class), + ]; + + parent::setUp(); + } + + public function testHandleCommand() + { + $userId = 999; + + $command = Cmd::create([]); + + $loggedInUser = m::mock(UserEntity::class); + $loggedInUser->expects('getId')->andReturn($userId); + + $this->mockedSmServices[AuthorizationService::class]->expects('getIdentity->getUser') + ->andReturn($loggedInUser); + + $this->mockedSmServices[CacheEncryption::class]->expects('removeCustomItems') + ->with(CacheEncryption::USER_ACCOUNT_IDENTIFIER, [$userId]); + + $userFromRepo = m::mock(UserEntity::class); + $userFromRepo->expects('agreeTermsAndConditions')->withNoArgs(); + + $this->repoMap['User']->expects('fetchById')->with($userId)->andReturn($userFromRepo); + $this->repoMap['User']->expects('save')->with($userFromRepo); + + $expectedResult = [ + 'id' => [ + 'User' => $userId, + ], + 'messages' => [ + 0 => AgreeTerms::SUCCESS_MSG + ], + ]; + + $this->assertEquals($expectedResult, $this->sut->handleCommand($command)->toArray()); + } +} diff --git a/app/api/test/module/Api/src/Domain/CommandHandler/User/RegisterConsultantAndOperatorTest.php b/app/api/test/module/Api/src/Domain/CommandHandler/User/RegisterConsultantAndOperatorTest.php index 307820442a..4c07a131a5 100644 --- a/app/api/test/module/Api/src/Domain/CommandHandler/User/RegisterConsultantAndOperatorTest.php +++ b/app/api/test/module/Api/src/Domain/CommandHandler/User/RegisterConsultantAndOperatorTest.php @@ -1,5 +1,7 @@ 'Operator Org',]; + $operatorDetails = ['organisationName' => 'Operator Org']; + $operatorModifiedDetails = ['organisationName' => 'Operator Org', 'createdByConsultant' => true]; $command = RegisterConsultantAndOperatorCommand::create( [ @@ -41,7 +44,7 @@ public function testHandleCommand() $this->expectedSideEffect( RegisterUserSelfServeCommand::class, - $operatorDetails, + $operatorModifiedDetails, $operatorResult ); @@ -70,6 +73,8 @@ public function testHandleCommand() ->once() ->andReturnSelf(); + $consultant->expects('agreeTermsAndConditions')->withNoArgs(); + $this->repoMap['User']->shouldReceive('save')->with($consultant); $mockRole = m::mock(Role::class); diff --git a/app/api/test/module/Api/src/Domain/CommandHandler/User/RegisterUserSelfserveTest.php b/app/api/test/module/Api/src/Domain/CommandHandler/User/RegisterUserSelfserveTest.php index 9f9165e377..0f66e81f8a 100644 --- a/app/api/test/module/Api/src/Domain/CommandHandler/User/RegisterUserSelfserveTest.php +++ b/app/api/test/module/Api/src/Domain/CommandHandler/User/RegisterUserSelfserveTest.php @@ -1,8 +1,6 @@ 'Org Name', 'businessType' => OrganisationEntity::ORG_TYPE_SOLE_TRADER, + 'createdByConsultant' => $createdByConsultant, ]; $command = Cmd::create($data); @@ -184,13 +181,20 @@ function (UserEntity $user) use (&$savedUser, $userId) { $savedUser->getContactDetails()->getEmailAddress() ); + //if record created by a consultant terms won't have been agreed, if created by the operator, they will be + $this->assertEquals( + !$createdByConsultant, + $savedUser->hasAgreedTermsAndConditions() + ); + $this->assertEquals(UserEntity::USER_TYPE_OPERATOR, $savedUser->getUserType()); } /** * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * @dataProvider dpHandleCommand */ - public function testHandleCommandWithLicence() + public function testHandleCommandWithLicence(bool $createdByConsultant): void { $userId = 111; $licId = 222; @@ -205,6 +209,7 @@ public function testHandleCommandWithLicence() ], ], 'licenceNumber' => 'licNo', + 'createdByConsultant' => $createdByConsultant, ]; $command = Cmd::create($data); @@ -311,10 +316,25 @@ function (UserEntity $user) use (&$savedUser, $userId) { $savedUser->getContactDetails()->getEmailAddress() ); + //if record created by a consultant terms won't have been agreed, if created by the operator, they will be + $this->assertEquals( + !$createdByConsultant, + $savedUser->hasAgreedTermsAndConditions() + ); + $this->assertEquals(UserEntity::USER_TYPE_OPERATOR, $savedUser->getUserType()); } - public function testHandleCommandThrowsIncorrectOrgException() + public function dpHandleCommand(): array + { + return [ + [true], + [false], + ]; + } + + + public function testHandleCommandThrowsIncorrectOrgException(): void { $this->expectException(\Dvsa\Olcs\Api\Domain\Exception\BadRequestException::class); @@ -344,7 +364,7 @@ public function testHandleCommandThrowsIncorrectOrgException() $this->sut->handleCommand($command); } - public function testHandleCommandThrowsUsernameExistsException() + public function testHandleCommandThrowsUsernameExistsException(): void { $this->expectException(\Dvsa\Olcs\Api\Domain\Exception\ValidationException::class); @@ -367,7 +387,7 @@ public function testHandleCommandThrowsUsernameExistsException() $this->sut->handleCommand($command); } - public function testHandleCommandThrowsExceptionWhenUnableToStoreUser() + public function testHandleCommandThrowsExceptionWhenUnableToStoreUser(): void { $data = [ 'loginId' => 'login_id', diff --git a/app/api/test/module/Api/src/Entity/User/UserEntityTest.php b/app/api/test/module/Api/src/Entity/User/UserEntityTest.php index 7ae0272ca0..e3495ad221 100644 --- a/app/api/test/module/Api/src/Entity/User/UserEntityTest.php +++ b/app/api/test/module/Api/src/Entity/User/UserEntityTest.php @@ -1409,4 +1409,12 @@ public function dpOperatorAdminRoles(): array [RoleEntity::ROLE_OPERATOR_TC], ]; } + + public function testAgreeTermsAndConditions(): void + { + $user = new Entity('pid', Entity::USER_TYPE_OPERATOR); + $this->assertFalse($user->hasAgreedTermsAndConditions()); + $user->agreeTermsAndConditions(); + $this->assertTrue($user->hasAgreedTermsAndConditions()); + } } diff --git a/app/selfserve/module/Olcs/Module.php b/app/selfserve/module/Olcs/Module.php index 182021927e..266cc024e4 100644 --- a/app/selfserve/module/Olcs/Module.php +++ b/app/selfserve/module/Olcs/Module.php @@ -8,6 +8,7 @@ use Laminas\Session\Container; use Laminas\Session\SessionManager; use Laminas\Validator\AbstractValidator; +use Olcs\Mvc\TermsAgreedListener; /** * Module.php @@ -64,6 +65,9 @@ public function onBootstrap(MvcEvent $e) $cookieListener = $sm->get('CookieListener'); $cookieListener->attach($eventManager, 2); + $termsAgreedListener = $sm->get(TermsAgreedListener::class); + $termsAgreedListener->attach($eventManager, 3); + $this->initSession( [ 'remember_me_seconds' => 86400, diff --git a/app/selfserve/module/Olcs/config/module.config.php b/app/selfserve/module/Olcs/config/module.config.php index 4ef08163e2..0411aa1f05 100644 --- a/app/selfserve/module/Olcs/config/module.config.php +++ b/app/selfserve/module/Olcs/config/module.config.php @@ -45,6 +45,7 @@ use Olcs\Controller\SessionTimeoutController; use Olcs\Controller\UserForgotUsernameController; use Olcs\Controller\UserRegistrationController; +use Olcs\Controller\WelcomeController; use Olcs\Form\Element\SearchDateRangeFieldset; use Olcs\Form\Element\SearchDateRangeFieldsetFactory; use Olcs\Form\Element\SearchFilterFieldset; @@ -54,6 +55,8 @@ use Olcs\FormService\Form\Lva as LvaFormService; use Olcs\Logging\Log\Processor\CorrelationId; use Olcs\Logging\Log\Processor\CorrelationIdFactory; +use Olcs\Mvc\TermsAgreedListener; +use Olcs\Mvc\TermsAgreedListenerFactory; use Olcs\Service\Cookie as CookieService; use Olcs\Service\Data as DataService; use Olcs\Service\Processing as ProcessingService; @@ -108,6 +111,16 @@ ] ] ], + 'welcome' => [ + 'type' => Segment::class, + 'options' => [ + 'route' => '/welcome[/]', + 'defaults' => [ + 'controller' => WelcomeController::class, + 'action' => 'generic', + ], + ], + ], 'cookies' => [ 'type' => 'segment', 'options' => [ @@ -1412,6 +1425,7 @@ \Olcs\Controller\Licence\Vehicle\Reprint\ReprintLicenceVehicleDiscConfirmationController::class => \Olcs\Controller\Licence\Vehicle\Reprint\ReprintLicenceVehicleDiscConfirmationControllerFactory::class, Olcs\Controller\ConversationsController::class => Olcs\Controller\Factory\ConversationsControllerFactory::class, PromptController::class => \Olcs\Controller\PromptControllerFactory::class, + WelcomeController::class => \Olcs\Controller\WelcomeControllerFactory::class, // Process Signature from GOV.UK Account \Olcs\Controller\SignatureVerificationController::class => \Olcs\Controller\SignatureVerificationControllerFactory::class, // LVA Controller Factories @@ -1498,6 +1512,7 @@ \Laminas\Cache\Service\StorageCacheAbstractServiceFactory::class, ], 'factories' => [ + TermsAgreedListener::class => TermsAgreedListenerFactory::class, 'CookieListener' => \Olcs\Mvc\CookieListenerFactory::class, 'CookieBannerListener' => \Olcs\Mvc\CookieBannerListenerFactory::class, 'CookieAcceptAllSetCookieGenerator' => CookieService\AcceptAllSetCookieGeneratorFactory::class, diff --git a/app/selfserve/module/Olcs/src/Controller/WelcomeController.php b/app/selfserve/module/Olcs/src/Controller/WelcomeController.php new file mode 100644 index 0000000000..1c01e2c696 --- /dev/null +++ b/app/selfserve/module/Olcs/src/Controller/WelcomeController.php @@ -0,0 +1,59 @@ + 'pages/welcome', + ]; + + protected $formConfig = [ + 'generic' => [ + 'confirmationForm' => [ + 'formClass' => AgreeTermsForm::class + ] + ] + ]; + + protected $postConfig = [ + 'generic' => [ + 'command' => AgreeTermsCmd::class, + 'step' => 'index', + 'saveAndReturnStep' => 'index', + ], + ]; + + public function __construct( + TranslationHelperService $translationHelper, + FormHelperService $formHelper, + TableFactory $tableBuilder, + MapperManager $mapperManager + ) { + parent::__construct($translationHelper, $formHelper, $tableBuilder, $mapperManager); + } + + /** + * @return Response|void + */ + public function checkConditionalDisplay() + { + if (isset($this->postParams['form-actions']['signOut'])) { + return $this->conditionalDisplayNotMet('auth/logout'); + } + + if ($this->currentUser()->getIdentity()->hasAgreedTerms()) { + return $this->conditionalDisplayNotMet('index'); + } + } +} diff --git a/app/selfserve/module/Olcs/src/Controller/WelcomeControllerFactory.php b/app/selfserve/module/Olcs/src/Controller/WelcomeControllerFactory.php new file mode 100644 index 0000000000..76cc592230 --- /dev/null +++ b/app/selfserve/module/Olcs/src/Controller/WelcomeControllerFactory.php @@ -0,0 +1,24 @@ +get(TranslationHelperService::class); + $formHelper = $container->get(FormHelperService::class); + $tableBuilder = $container->get(TableFactory::class); + $mapperManager = $container->get(MapperManager::class); + return new WelcomeController($translationHelper, $formHelper, $tableBuilder, $mapperManager); + } +} diff --git a/app/selfserve/module/Olcs/src/Form/Model/Fieldset/AgreeTerms.php b/app/selfserve/module/Olcs/src/Form/Model/Fieldset/AgreeTerms.php new file mode 100644 index 0000000000..b83a1e9cab --- /dev/null +++ b/app/selfserve/module/Olcs/src/Form/Model/Fieldset/AgreeTerms.php @@ -0,0 +1,28 @@ +listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'onDispatch'], $priority); + } + + /** + * {@inheritdoc} + * + * @return ResponseInterface|void + */ + public function onDispatch(MvcEvent $e) + { + $request = $e->getRequest(); + + if (!($request instanceof HttpRequest)) { + return; + } + + if (in_array($e->getRouteMatch()->getMatchedRouteName(), self::EXCLUDED_ROUTES )) { + return; + } + + $user = $this->identityProvider->getIdentity(); + + if ($user->isAnonymous() || $user->isNotIdentified() || $user->hasAgreedTerms()) { + return; + } + + $redirectUrl = $this->urlHelper->fromRoute( self::ROUTE_WELCOME); + $response = $e->getResponse(); + $responseHeaders = $response->getHeaders(); + + $responseHeaders->addHeaderLine('Location', $redirectUrl); + $response->setStatusCode(303); + + return $response; + } +} diff --git a/app/selfserve/module/Olcs/src/Mvc/TermsAgreedListenerFactory.php b/app/selfserve/module/Olcs/src/Mvc/TermsAgreedListenerFactory.php new file mode 100644 index 0000000000..ce0bd01ea0 --- /dev/null +++ b/app/selfserve/module/Olcs/src/Mvc/TermsAgreedListenerFactory.php @@ -0,0 +1,20 @@ +get(JWTIdentityProvider::class), + $container->get('Helper\Url') + ); + } +} diff --git a/app/selfserve/module/Olcs/view/pages/welcome.phtml b/app/selfserve/module/Olcs/view/pages/welcome.phtml new file mode 100644 index 0000000000..e7d37e9007 --- /dev/null +++ b/app/selfserve/module/Olcs/view/pages/welcome.phtml @@ -0,0 +1,23 @@ +partial( + '/partials/page-header-continuation.phtml', + [ + 'pageTitle' => $this->translate('user.welcome.title'), + 'pageSubTitle'=> $this->translate('user.welcome.subtitle'), + 'backUrl' => false, + ] +); +?> + +
+
+ flashMessengerAll(); + + if (isset($this->form)): + echo $this->formErrors($this->form); + echo $this->form($this->form); + endif; + ?> +
+
diff --git a/app/selfserve/test/Olcs/src/Mvc/TermsAgreedListenerTest.php b/app/selfserve/test/Olcs/src/Mvc/TermsAgreedListenerTest.php new file mode 100644 index 0000000000..dfc3654c5d --- /dev/null +++ b/app/selfserve/test/Olcs/src/Mvc/TermsAgreedListenerTest.php @@ -0,0 +1,144 @@ +identityProvider = m::mock(JWTIdentityProvider::class); + $this->urlHelper = m::mock(UrlHelperService::class); + + $this->sut = new TermsAgreedListener($this->identityProvider, $this->urlHelper); + } + + public function testAttach(): void + { + $priority = 999; + $em = m::mock(EventManagerInterface::class); + $em->expects('attach')->with(MvcEvent::EVENT_DISPATCH, [$this->sut, 'onDispatch'], $priority); + + $this->sut->attach($em, $priority); + } + + public function testOnDispatchNonHttp(): void + { + $request = m::mock(\StdClass::class); + $event = m::mock(MvcEvent::class); + $event->expects('getRequest')->withNoArgs()->andReturn($request); + + $this->sut->onDispatch($event); + } + + /** + * @dataProvider dpExcludedRoute + */ + public function testOnDispatchExcludedRoute($route): void + { + $this->sut->onDispatch( + $this->getEvent($route) + ); + } + + public function dpExcludedRoute(): array + { + return [ + [TermsAgreedListener::ROUTE_WELCOME], + ['auth/logout'], + ['terms-and-conditions'] + ]; + } + + public function testOnDispatchAnonymousUser(): void + { + $user = m::mock(User::class); + $user->expects('isAnonymous')->withNoArgs()->andReturnTrue(); + $this->identityProvider->expects('getIdentity')->withNoArgs()->andReturn($user); + + $this->sut->onDispatch( + $this->getEvent() + ); + } + + public function testOnDispatchNotIdentifiedUser(): void + { + $user = m::mock(User::class); + $user->expects('isAnonymous')->withNoArgs()->andReturnFalse(); + $user->expects('isNotIdentified')->withNoArgs()->andReturnTrue(); + $this->identityProvider->expects('getIdentity')->withNoArgs()->andReturn($user); + + $this->sut->onDispatch( + $this->getEvent() + ); + } + + public function testOnDispatchTermsAgreed(): void + { + $user = m::mock(User::class); + $user->expects('isAnonymous')->withNoArgs()->andReturnFalse(); + $user->expects('isNotIdentified')->withNoArgs()->andReturnFalse(); + $user->expects('hasAgreedTerms')->withNoArgs()->andReturnTrue(); + + $this->identityProvider->expects('getIdentity')->withNoArgs()->andReturn($user); + + $this->sut->onDispatch( + $this->getEvent() + ); + } + + public function testOnDispatchTermsNotAgreed(): void + { + $user = m::mock(User::class); + $user->expects('isAnonymous')->withNoArgs()->andReturnFalse(); + $user->expects('isNotIdentified')->withNoArgs()->andReturnFalse(); + $user->expects('hasAgreedTerms')->withNoArgs()->andReturnFalse(); + + $this->identityProvider->expects('getIdentity')->withNoArgs()->andReturn($user); + + $redirectUrl = 'http://url'; + $this->urlHelper->expects('fromRoute')->with(TermsAgreedListener::ROUTE_WELCOME)->andReturn($redirectUrl); + + $responseHeaders = m::mock(Headers::class); + $responseHeaders->expects('addHeaderLine')->with('Location', $redirectUrl); + + $response = m::mock(ResponseInterface::class); + $response->expects('getHeaders')->withNoArgs()->andReturn($responseHeaders); + $response->expects('setStatusCode')->with(303); + + $event = $this->getEvent(); + $event->expects('getResponse')->withNoArgs()->andReturn($response); + + $this->assertEquals($response, $this->sut->onDispatch($event)); + } + + private function getEvent($route = 'route'): m\MockInterface&m\LegacyMockInterface + { + $request = m::mock(Request::class); + + $event = m::mock(MvcEvent::class); + $event->expects('getRequest')->withNoArgs()->andReturn($request); + $event->expects('getRouteMatch->getMatchedRouteName')->withNoArgs()->andReturn($route); + + return $event; + } +}