Skip to content

Commit

Permalink
Uml 1643 force activation key (pt4) (#1146)
Browse files Browse the repository at this point in the history
* Refactor retry of db write and UUID creation to be a part of the DB mapper service

* Remove code that reappeared in merge.

* Add lpa-actor token to the validateRequest method.

* Add some error catching/correction

* A letter request now updates an existing record if specified.

* Pass the existing record token through if found.

* Tidy up logging

* Remove token from return if not discovered in resolution.

* Improve test coverage

* Update 'already-have-key' form to have the appropriate buttons.

* Improve testing coverage of the record update

* Update service-api/app/src/App/src/Service/Lpa/AddOlderLpa.php

Co-authored-by: lukejolliffe <84718230+lukejolliffe@users.noreply.github.com>
  • Loading branch information
cooperaj and lukejolliffe committed Oct 19, 2021
1 parent 0ffeb68 commit 1824537
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 23 deletions.
7 changes: 7 additions & 0 deletions service-api/app/features/actor-add-an-older-lpa.feature
Expand Up @@ -35,6 +35,13 @@ Feature: Add an older LPA
And a letter is requested containing a one time use code
And A record of my activation key request is saved

@integration @acceptance @pact @ff:save_older_lpa_requests:true
Scenario: The user can re-request an older LPA be added to their account and we update the record in our DB
Given I have previously requested the addition of a paper LPA to my account
When I repeat my request for an activation key
Then a repeat request for a letter containing a one time use code is made
And a record of my activation key request is updated

@integration @acceptance @pact
Scenario: The user cannot add an older LPA to their account that does not exist
Given I am on the add an older LPA page
Expand Down
136 changes: 136 additions & 0 deletions service-api/app/features/context/Acceptance/LpaContext.php
Expand Up @@ -33,6 +33,14 @@ class LpaContext implements Context
use BaseAcceptanceContextTrait;
use SetupEnv;

/**
* @Given I have previously requested the addition of a paper LPA to my account
*/
public function iHavePreviouslyRequestedTheAdditionOfAPaperLPAToMyAccount()
{
// Not necessary for this context
}

/**
* @Given /^A record of my activation key request is not saved$/
*/
Expand All @@ -54,6 +62,25 @@ public function aRecordOfMyActivationKeyRequestIsSaved()
assertArrayHasKey('ActivateBy', $lastCommand->toArray()['Item']);
}

/**
* @Then /^a record of my activation key request is updated/
*/
public function aRecordOfMyActivationKeyRequestIsUpdated()
{
$dt = (new DateTime('now'))->add(new \DateInterval('P1Y'));

$lastCommand = $this->awsFixtures->getLastCommand();
assertEquals($lastCommand->getName(), 'UpdateItem');
assertEquals($lastCommand->toArray()['TableName'], 'user-actor-lpa-map');
assertEquals($lastCommand->toArray()['Key']['Id'], ['S' => '111222333444']);
assertEquals(
intval($lastCommand->toArray()['ExpressionAttributeValues'][':a']['N']),
$dt->getTimestamp(),
'',
5
);
}

/**
* @Then /^A record of the LPA requested is saved to the database$/
*/
Expand Down Expand Up @@ -2378,6 +2405,114 @@ public function iAmOnTheAddAnOlderLPAPage()
// Not needed for this context
}

/**
* @Then /^a repeat request for a letter containing a one time use code is made$/
*/
public function aRepeatRequestForALetterContainingAOneTimeUseCodeIsMade()
{
//UserLpaActorMap: getByUserId
$this->awsFixtures->append(
new Result(
[
'Items' => [
$this->marshalAwsResultData(
[
'Id' => $this->userLpaActorToken,
'UserId' => $this->base->userAccountId,
'SiriusUid' => $this->lpaUid,
'ActorId' => $this->actorId,
'Added' => (new DateTime())->format('Y-m-d\TH:i:s.u\Z'),
'ActivateBy' => (new DateTime())->add(new \DateInterval('P1Y'))->getTimestamp()
]
),
]
]
)
);

//UserLpaActorMap: get
$this->awsFixtures->append(
new Result(
[
'Item' => $this->marshalAwsResultData(
[
'Id' => $this->userLpaActorToken,
'UserId' => $this->base->userAccountId,
'SiriusUid' => $this->lpaUid,
'ActorId' => $this->actorId,
'Added' => (new DateTime())->format('Y-m-d\TH:i:s.u\Z'),
'ActivateBy' => (new DateTime())->add(new \DateInterval('P1Y'))->getTimestamp()
]
),
]
)
);

// LpaRepository::get
$this->apiFixtures->get('/v1/use-an-lpa/lpas/' . $this->lpaUid)
->respondWith(
new Response(
StatusCodeInterface::STATUS_OK,
[],
json_encode($this->lpa)
)
);

// Done twice due to our codes interdependencies
// LpaRepository::get
$this->apiFixtures->get('/v1/use-an-lpa/lpas/' . $this->lpaUid)
->respondWith(
new Response(
StatusCodeInterface::STATUS_OK,
[],
json_encode($this->lpa)
)
);

// request a code to be generated and letter to be sent
$this->apiFixtures->post('/v1/use-an-lpa/lpas/requestCode')
->respondWith(
new Response(
StatusCodeInterface::STATUS_NO_CONTENT,
[]
)
);

$this->awsFixtures->append(
new Result(
[
'Item' => $this->marshalAwsResultData(
[
'Id' => $this->userLpaActorToken,
'UserId' => $this->base->userAccountId,
'SiriusUid' => $this->lpaUid,
'ActorId' => $this->actorId,
'Added' => (new DateTime())->format('Y-m-d\TH:i:s.u\Z')
]
),
]
)
);

// API call to request an activation key
$this->apiPatch(
'/v1/older-lpa/confirm',
[
'reference_number' => $this->lpaUid,
'first_names' => $this->userFirstnames,
'last_name' => $this->userSurname,
'dob' => $this->userDob,
'postcode' => $this->userPostCode,
'force_activation_key' => true
],
[
'user-token' => $this->base->userAccountId,
]
);

$this->ui->assertSession()->statusCodeEquals(StatusCodeInterface::STATUS_NO_CONTENT);
}

/**
* @Then /^a letter is requested containing a one time use code$/
*/
Expand Down Expand Up @@ -2844,6 +2979,7 @@ public function iLostTheLetterContainingMyActivationKey()

/**
* @When /^I request for a new activation key again$/
* @When /^I repeat my request for an activation key$/
*/
public function iRequestForANewActivationKeyAgain()
{
Expand Down
68 changes: 63 additions & 5 deletions service-api/app/features/context/Integration/LpaContext.php
Expand Up @@ -64,6 +64,14 @@ class LpaContext extends BaseIntegrationContext
private RemoveLpa $deleteLpa;
private LpaService $lpaService;

/**
* @Given I have previously requested the addition of a paper LPA to my account
*/
public function iHavePreviouslyRequestedTheAdditionOfAPaperLPAToMyAccount()
{
// Not necessary for this context
}

/**
* @Then /^a letter is requested containing a one time use code$/
*/
Expand Down Expand Up @@ -94,6 +102,36 @@ public function aLetterIsRequestedContainingAOneTimeUseCode()
}
}

/**
* @Then /^a repeat request for a letter containing a one time use code is made$/
*/
public function aRepeatRequestForALetterContainingAOneTimeUseCodeIsMade()
{
// Lpas::requestLetter
$this->pactPostInteraction(
$this->apiGatewayPactProvider,
'/v1/use-an-lpa/lpas/requestCode',
[
'case_uid' => (int)$this->lpaUid,
'actor_uid' => (int)$this->actorLpaId,
],
StatusCodeInterface::STATUS_NO_CONTENT
);

if ($this->container->get(FeatureEnabled::class)('save_older_lpa_requests')) {
// Update activation key request in the DB
$this->awsFixtures->append(new Result([]));
}

$olderLpaService = $this->container->get(OlderLpaService::class);

try {
$olderLpaService->requestAccessByLetter($this->lpaUid, $this->actorLpaId, $this->userId, '00-0-0-0-00');
} catch (ApiException $exception) {
throw new Exception('Failed to request access code letter');
}
}

/**
* @Then /^A record of my activation key request is saved$/
*/
Expand All @@ -106,6 +144,25 @@ public function aRecordOfMyActivationKeyRequestIsSaved()
assertArrayHasKey('ActivateBy', $lastCommand->toArray()['Item']);
}

/**
* @Then /^a record of my activation key request is updated/
*/
public function aRecordOfMyActivationKeyRequestIsUpdated()
{
$dt = (new DateTime('now'))->add(new \DateInterval('P1Y'));

$lastCommand = $this->awsFixtures->getLastCommand();
assertEquals($lastCommand->getName(), 'UpdateItem');
assertEquals($lastCommand->toArray()['TableName'], 'user-actor-lpa-map');
assertEquals($lastCommand->toArray()['Key']['Id'], ['S' => '00-0-0-0-00']);
assertEquals(
intval($lastCommand->toArray()['ExpressionAttributeValues'][':a']['N']),
$dt->getTimestamp(),
'',
5
);
}

/**
* @Then /^A record of my activation key request is not saved$/
*/
Expand Down Expand Up @@ -2288,6 +2345,7 @@ public function iShouldHaveAnOptionToRegenerateAnActivationKeyForTheOldLPAIWantT

/**
* @When /^I request for a new activation key again$/
* @When /^I repeat my request for an activation key$/
*/
public function iRequestForANewActivationKeyAgain()
{
Expand Down Expand Up @@ -2529,11 +2587,11 @@ public function iProvideDetailsDetailsOfAnLpaThatIsNotRegistered()
$this->lpa->status = 'Pending';

$data = [
'reference_number' => $this->lpaUid,
'dob' => $this->userDob,
'postcode' => $this->userPostCode,
'first_names' => $this->userFirstname,
'last_name' => $this->userSurname,
'reference_number' => $this->lpaUid,
'dob' => $this->userDob,
'postcode' => $this->userPostCode,
'first_names' => $this->userFirstname,
'last_name' => $this->userSurname,
];

//UserLpaActorMap: getAllForUser
Expand Down
Expand Up @@ -68,7 +68,8 @@ public function handle(ServerRequestInterface $request): ResponseInterface
$this->olderLpaService->requestAccessByLetter(
(string) $requestData['reference_number'],
$lpaMatchResponse['actor']['uId'],
$userId
$userId,
$lpaMatchResponse['lpaActorToken'] ?? null
);

return new EmptyResponse();
Expand Down
9 changes: 7 additions & 2 deletions service-api/app/src/App/src/Service/Lpa/AddOlderLpa.php
Expand Up @@ -6,8 +6,8 @@

use App\Exception\BadRequestException;
use App\Exception\NotFoundException;
use Psr\Log\LoggerInterface;
use DateTime;
use Psr\Log\LoggerInterface;

class AddOlderLpa
{
Expand Down Expand Up @@ -59,7 +59,8 @@ public function __construct(
public function validateRequest(string $userId, array $matchData): array
{
// Check if it's been added to the users account already
if (null !== $lpaAddedData = ($this->lpaAlreadyAdded)($userId, (string) $matchData['reference_number'])) {
$lpaAddedData = ($this->lpaAlreadyAdded)($userId, (string) $matchData['reference_number']);
if ($lpaAddedData !== null) {
if (!array_key_exists('notActivated', $lpaAddedData)) {
$this->logger->notice(
'User {id} attempted to request a key for the LPA {uId} which already exists in their account',
Expand Down Expand Up @@ -111,6 +112,10 @@ public function validateRequest(string $userId, array $matchData): array
];
}

if ($token = $lpaAddedData['lpaActorToken'] ?? null) {
$resolvedActor['lpaActorToken'] = $token;
}

$resolvedActor['caseSubtype'] = $lpaData['caseSubtype'];
$resolvedActor['donor'] = [
'uId' => $lpaData['donor']['uId'],
Expand Down
35 changes: 29 additions & 6 deletions service-api/app/src/App/src/Service/Lpa/OlderLpaService.php
Expand Up @@ -79,15 +79,26 @@ private function removeLpa(string $requestId)
* address of the specified actor with a new one-time-use registration code.
* This will allow them to add the LPA to their UaLPA account.
*
* @param string $uid Sirius uId for an LPA
* @param string $actorUid uId of an actor on that LPA
* @param string $userId
* In order to preserve some semblance of atomicity to the required steps they're
* carried out in a reverse order, with the one item we cannot revert carried out
* last.
*
* @param string $uid Sirius uId for an LPA
* @param string $actorUid uId of an actor on that LPA
* @param string $userId The user ID of an actor in the ualpa database
* @param string|null $existingRecordId If an existing LPA record has been stored this is the ID
*/
public function requestAccessByLetter(string $uid, string $actorUid, string $userId): void
{
public function requestAccessByLetter(
string $uid,
string $actorUid,
string $userId,
?string $existingRecordId = null
): void {
$recordId = null;
if (($this->featureEnabled)('save_older_lpa_requests')) {
$recordId = $this->userLpaActorMap->create($userId, $uid, $actorUid, 'P1Y');
if ($existingRecordId === null) {
$recordId = $this->userLpaActorMap->create($userId, $uid, $actorUid, 'P1Y');
}
}

$uidInt = (int)$uid;
Expand Down Expand Up @@ -116,5 +127,17 @@ public function requestAccessByLetter(string $uid, string $actorUid, string $use
}
throw $apiException;
}

/**
* This is the exception to the method documentation. We cannot easily roll this alteration
* back so we'll do it last. The potential is that this operation could fail even though
* the API request worked. That being the case the users record will not have
* an up to date ActivateBy column. This isn't the end of the world.
*/
if (($this->featureEnabled)('save_older_lpa_requests')) {
if ($existingRecordId !== null) {
$this->userLpaActorMap->renewActivationPeriod($existingRecordId, 'P1Y');
}
}
}
}
Expand Up @@ -218,6 +218,7 @@ public function older_lpa_lookup_successful_if_lpa_already_requested_but_force_f
'caseSubtype' => 'pfa',
'actor' => $this->lpaData['donor'],
'role' => 'donor',
'lpaActorToken' => 'qwerty-54321',
'donor' => [
'uId' => $this->lpaData['donor']['uId'],
'firstname' => 'Donor',
Expand Down

0 comments on commit 1824537

Please sign in to comment.