diff --git a/service-api/app/features/context/Integration/LpaContext.php b/service-api/app/features/context/Integration/LpaContext.php
index 3d8e535002..10a438715b 100644
--- a/service-api/app/features/context/Integration/LpaContext.php
+++ b/service-api/app/features/context/Integration/LpaContext.php
@@ -24,6 +24,7 @@
use DateInterval;
use DateTime;
use DateTimeImmutable;
+use DateTimeInterface;
use DateTimeZone;
use Exception;
use Fig\Http\Message\StatusCodeInterface;
@@ -2785,6 +2786,8 @@ public function iProvideTheDetailsFromAValidPaperLPAWhichIHaveAlreadyAddedToMyAc
'Id' => $this->userLpaActorToken,
'ActorId' => $this->actorLpaId,
'UserId' => $this->userId,
+ 'Updated' => (new DateTime('2020-01-01'))->format(DateTimeInterface::ATOM),
+ 'DueBy' => (new DateTime('2020-01-01'))->format(DateTimeInterface::ATOM),
]
),
]
@@ -2812,15 +2815,18 @@ public function iProvideTheDetailsFromAValidPaperLPAWhichIHaveAlreadyAddedToMyAc
if ($this->container->get(FeatureEnabled::class)('save_older_lpa_requests')) {
$expectedResponse = [
- 'donor' => [
+ 'donor' => [
'uId' => $this->lpa->donor->uId,
'firstname' => $this->lpa->donor->firstname,
'middlenames' => $this->lpa->donor->middlenames,
'surname' => $this->lpa->donor->surname,
],
- 'caseSubtype' => $this->lpa->caseSubtype,
- 'lpaActorToken' => $this->userLpaActorToken,
- 'activationKeyDueDate' => null,
+ 'caseSubtype' => $this->lpa->caseSubtype,
+ 'lpaActorToken' => $this->userLpaActorToken,
+ // would normally expect for this to be a string but this integration test intercepts before it's
+ // rendered to an error response.
+ 'activationKeyDueDate' => new DateTime('2020-01-01'),
+ 'activationKeyRequestedDate' => new DateTime('2020-01-01'),
];
} else {
$expectedResponse = [
@@ -2854,7 +2860,9 @@ public function iProvideTheDetailsFromAValidPaperLPAWhichIHaveAlreadyAddedToMyAc
*/
public function iProvideTheDetailsFromAValidPaperLPAWhichIHaveAlreadyRequestedAnActivationKeyFor(): void
{
- $createdDate = (new DateTime())->modify('-14 days');
+ $createdDate = new DateTimeImmutable('-14 days');
+ $dueByDate = (new DateTimeImmutable('+9 days'))->format(DateTimeInterface::ATOM);
+ $updatedDate = (new DateTimeImmutable('-1 days'))->format(DateTimeInterface::ATOM);
$data = [
'reference_number' => (int) $this->lpaUid,
@@ -2897,6 +2905,8 @@ public function iProvideTheDetailsFromAValidPaperLPAWhichIHaveAlreadyRequestedAn
'ActorId' => $this->actorLpaId,
'UserId' => $this->userId,
'ActivateBy' => 123456789,
+ 'DueBy' => $dueByDate,
+ 'Updated' => $updatedDate,
]
),
]
@@ -2911,14 +2921,7 @@ public function iProvideTheDetailsFromAValidPaperLPAWhichIHaveAlreadyRequestedAn
$this->lpa
);
- $codeExists = new stdClass();
- $createdDate = (new DateTime())->modify('-14 days');
-
- $activationKeyDueDate = DateTimeImmutable::createFromMutable($createdDate);
- $activationKeyDueDate = $activationKeyDueDate
- ->add(new DateInterval('P10D'))
- ->format('Y-m-d');
-
+ $codeExists = new stdClass();
$codeExists->Created = $createdDate->format('Y-m-d');
$this->pactPostInteraction(
@@ -2933,14 +2936,15 @@ public function iProvideTheDetailsFromAValidPaperLPAWhichIHaveAlreadyRequestedAn
);
$expectedResponse = [
- 'donor' => [
+ 'donor' => [
'uId' => $this->lpa->donor->uId,
'firstname' => $this->lpa->donor->firstname,
'middlenames' => $this->lpa->donor->middlenames,
'surname' => $this->lpa->donor->surname,
],
- 'caseSubtype' => $this->lpa->caseSubtype,
- 'activationKeyDueDate' => $activationKeyDueDate,
+ 'caseSubtype' => $this->lpa->caseSubtype,
+ 'activationKeyDueDate' => new DateTimeImmutable($dueByDate),
+ 'activationKeyRequestedDate' => new DateTimeImmutable($updatedDate),
];
$addOlderLpa = $this->container->get(AddAccessForAllLpa::class);
diff --git a/service-api/app/src/App/src/DataAccess/DynamoDb/DynamoHydrateTrait.php b/service-api/app/src/App/src/DataAccess/DynamoDb/DynamoHydrateTrait.php
index 6ec54685c0..49c5b23ac2 100644
--- a/service-api/app/src/App/src/DataAccess/DynamoDb/DynamoHydrateTrait.php
+++ b/service-api/app/src/App/src/DataAccess/DynamoDb/DynamoHydrateTrait.php
@@ -4,9 +4,9 @@
namespace App\DataAccess\DynamoDb;
+use App\DataAccess\ValueObjects\DateTimeImmutable;
use Aws\DynamoDb\Marshaler;
use Aws\Result;
-use DateTime;
use Exception;
use UnexpectedValueException;
@@ -67,7 +67,7 @@ private function extractData(array $resultItem, array $dateFields = []): array
$thisVal = $marshaler->unmarshalValue($value);
if (in_array($key, $dateFields)) {
- $thisVal = new DateTime($thisVal);
+ $thisVal = new DateTimeImmutable($thisVal);
}
$item[$key] = $thisVal;
diff --git a/service-api/app/src/App/src/DataAccess/DynamoDb/UserLpaActorMap.php b/service-api/app/src/App/src/DataAccess/DynamoDb/UserLpaActorMap.php
index 90f44e38ea..7d1be28d5c 100644
--- a/service-api/app/src/App/src/DataAccess/DynamoDb/UserLpaActorMap.php
+++ b/service-api/app/src/App/src/DataAccess/DynamoDb/UserLpaActorMap.php
@@ -19,6 +19,8 @@ class UserLpaActorMap implements UserLpaActorMapInterface
{
use DynamoHydrateTrait;
+ private const DATE_FIELDS = ['Added', 'ActivatedOn', 'DueBy', 'Updated'];
+
public function __construct(
private DynamoDbClient $client,
private string $userLpaActorTable,
@@ -44,7 +46,7 @@ public function get(string $lpaActorToken): ?array
]
);
- $codeData = $this->getData($result, ['Added']);
+ $codeData = $this->getData($result, self::DATE_FIELDS);
$codeData = !empty($codeData) ? $codeData : null;
if ($codeData === null) {
@@ -79,6 +81,7 @@ public function create(
'UserId' => ['S' => $userId],
'SiriusUid' => ['S' => $siriusUid],
'Added' => ['S' => $added->format(DateTimeInterface::ATOM)],
+ 'Updated' => ['S' => $added->format(DateTimeInterface::ATOM)],
];
if ($actorId !== null) {
@@ -146,7 +149,7 @@ public function delete(string $lpaActorToken): array
]
);
- return $this->getData($response);
+ return $this->getData($response, self::DATE_FIELDS);
}
/**
@@ -156,18 +159,19 @@ public function delete(string $lpaActorToken): array
*/
public function activateRecord(string $lpaActorToken, string $actorId, string $activationCode): array
{
- $current = new DateTimeImmutable('now', new DateTimeZone('Etc/UTC'));
+ $current = new DateTimeImmutable('now', new DateTimeZone('Etc/UTC'));
$activatedTime = $current->format(DateTimeInterface::ATOM);
$response = $this->client->updateItem(
[
- 'TableName' => $this->userLpaActorTable,
- 'Key' => [
+ 'TableName' => $this->userLpaActorTable,
+ 'Key' => [
'Id' => [
'S' => $lpaActorToken,
],
],
- 'UpdateExpression' => 'set ActorId = :a, ActivationCode = :b, ActivatedOn = :c remove ActivateBy, DueBy',
+ 'UpdateExpression'
+ => 'set ActorId = :a, ActivationCode = :b, ActivatedOn = :c, Updated = :d remove ActivateBy, DueBy',
'ExpressionAttributeValues' => [
':a' => [
'N' => $actorId,
@@ -178,12 +182,15 @@ public function activateRecord(string $lpaActorToken, string $actorId, string $a
':c' => [
'S' => $activatedTime,
],
+ ':d' => [
+ 'S' => $activatedTime,
+ ],
],
'ReturnValues' => 'ALL_NEW',
]
);
- return $this->getData($response);
+ return $this->getData($response, self::DATE_FIELDS);
}
/**
@@ -206,7 +213,7 @@ public function getByUserId(string $userId): ?array
]
);
- return $this->getDataCollection($result, ['Added']);
+ return $this->getDataCollection($result, self::DATE_FIELDS);
}
/**
@@ -220,7 +227,7 @@ public function updateRecord(
DateInterval $intervalTillDue,
?string $actorId,
): array {
- $now = new DateTimeImmutable();
+ $now = new DateTimeImmutable('now', new DateTimeZone('Etc/UTC'));
$expiry = $now->add($expiryInterval);
$dueBy = $now->add($intervalTillDue);
@@ -231,20 +238,21 @@ public function updateRecord(
'S' => $lpaActorToken,
],
],
- 'UpdateExpression' => 'set ActivateBy = :a, DueBy = :b',
+ 'UpdateExpression' => 'set ActivateBy = :a, DueBy = :b, Updated = :c',
'ExpressionAttributeValues' => [
':a' => ['N' => (string) $expiry->getTimestamp()],
':b' => ['S' => $dueBy->format(DateTimeInterface::ATOM)],
+ ':c' => ['S' => $now->format(DateTimeInterface::ATOM)],
],
'ReturnValues' => 'ALL_NEW',
];
if ($actorId !== null) {
- $updateRequest['UpdateExpression'] = $updateRequest['UpdateExpression'] . ', ActorId = :c';
- $updateRequest['ExpressionAttributeValues'][':c'] = ['N' => $actorId];
+ $updateRequest['UpdateExpression'] = $updateRequest['UpdateExpression'] . ', ActorId = :d';
+ $updateRequest['ExpressionAttributeValues'][':d'] = ['N' => $actorId];
}
$response = $this->client->updateItem($updateRequest);
- return $this->getData($response);
+ return $this->getData($response, self::DATE_FIELDS);
}
}
diff --git a/service-api/app/src/App/src/DataAccess/ValueObjects/DateTimeImmutable.php b/service-api/app/src/App/src/DataAccess/ValueObjects/DateTimeImmutable.php
new file mode 100644
index 0000000000..ab2747d292
--- /dev/null
+++ b/service-api/app/src/App/src/DataAccess/ValueObjects/DateTimeImmutable.php
@@ -0,0 +1,21 @@
+format(DateTimeInterface::ATOM);
+ }
+}
diff --git a/service-api/app/src/App/src/Service/Lpa/AccessForAllLpaService.php b/service-api/app/src/App/src/Service/Lpa/AccessForAllLpaService.php
index d0bad60462..a61101e2a2 100644
--- a/service-api/app/src/App/src/Service/Lpa/AccessForAllLpaService.php
+++ b/service-api/app/src/App/src/Service/Lpa/AccessForAllLpaService.php
@@ -10,7 +10,8 @@
use App\Exception\ApiException;
use App\Service\Features\FeatureEnabled;
use DateInterval;
-use DateTime;
+use DateTimeImmutable;
+use DateTimeInterface;
use Psr\Log\LoggerInterface;
class AccessForAllLpaService
@@ -33,16 +34,16 @@ public function __construct(
*
* @param string $lpaId
* @param string $actorId
- * @return DateTime|null
+ * @return DateTimeInterface|null
*/
- public function hasActivationCode(string $lpaId, string $actorId): ?DateTime
+ public function hasActivationCode(string $lpaId, string $actorId): ?DateTimeInterface
{
$response = $this->actorCodes->checkActorHasCode($lpaId, $actorId);
if (is_null($response->getData()['Created'])) {
return null;
}
- $createdDate = DateTime::createFromFormat('Y-m-d', $response->getData()['Created']);
+ $createdDate = DateTimeImmutable::createFromFormat('Y-m-d', $response->getData()['Created']);
$this->logger->notice(
'Activation key exists for actor {actorId} on LPA {lpaId}',
diff --git a/service-api/app/src/App/src/Service/Lpa/AddAccessForAllLpa.php b/service-api/app/src/App/src/Service/Lpa/AddAccessForAllLpa.php
index 88424fc02b..1a064f418e 100644
--- a/service-api/app/src/App/src/Service/Lpa/AddAccessForAllLpa.php
+++ b/service-api/app/src/App/src/Service/Lpa/AddAccessForAllLpa.php
@@ -12,9 +12,12 @@
use Exception;
use Psr\Log\LoggerInterface;
use App\Service\Features\FeatureEnabled;
+use DateTimeInterface;
class AddAccessForAllLpa
{
+ private const CODE_ARRIVAL_INTERVAL = 'P10D';
+
/**
* @param FindActorInLpa $findActorInLpa
* @param LpaService $lpaService
@@ -69,10 +72,10 @@ private function existentCodeNotActivated(
(string) $resolvedActor['actor']['uId'],
);
- if ($hasActivationCode instanceof DateTime) {
- $activationKeyDueDate = DateTimeImmutable::createFromMutable($hasActivationCode);
+ if ($hasActivationCode instanceof DateTimeInterface) {
+ $activationKeyDueDate = DateTimeImmutable::createFromInterface($hasActivationCode);
$activationKeyDueDate = $activationKeyDueDate
- ->add(new DateInterval('P10D'))
+ ->add(new DateInterval(self::CODE_ARRIVAL_INTERVAL))
->format('Y-m-d');
}
}
@@ -80,9 +83,10 @@ private function existentCodeNotActivated(
throw new BadRequestException(
'Activation key already requested for LPA',
[
- 'donor' => $lpaAddedData['donor'],
- 'caseSubtype' => $lpaAddedData['caseSubtype'],
- 'activationKeyDueDate' => $activationKeyDueDate,
+ 'donor' => $lpaAddedData['donor'],
+ 'caseSubtype' => $lpaAddedData['caseSubtype'],
+ 'activationKeyDueDate' => $activationKeyDueDate,
+ 'activationKeyRequestedDate' => $lpaAddedData['activationKeyRequestedDate'],
],
);
}
@@ -112,10 +116,10 @@ private function processActivationCode(
(string) $resolvedActor['actor']['uId']
);
- if ($hasActivationCode instanceof DateTime) {
- $activationKeyDueDate = DateTimeImmutable::createFromMutable($hasActivationCode);
+ if ($hasActivationCode instanceof DateTimeInterface) {
+ $activationKeyDueDate = DateTimeImmutable::createFromInterface($hasActivationCode);
$activationKeyDueDate = $activationKeyDueDate
- ->add(new DateInterval('P10D'))
+ ->add(new DateInterval(self::CODE_ARRIVAL_INTERVAL))
->format('Y-m-d');
throw new BadRequestException(
diff --git a/service-api/app/src/App/src/Service/Lpa/LpaAlreadyAdded.php b/service-api/app/src/App/src/Service/Lpa/LpaAlreadyAdded.php
index 487d076c5a..ade7007fce 100644
--- a/service-api/app/src/App/src/Service/Lpa/LpaAlreadyAdded.php
+++ b/service-api/app/src/App/src/Service/Lpa/LpaAlreadyAdded.php
@@ -53,22 +53,24 @@ private function populateLpaRecord(array $record, string $userId): ?array
}
$response = [
- 'donor' => [
+ 'donor' => [
'uId' => $lpa['lpa']['donor']['uId'],
'firstname' => $lpa['lpa']['donor']['firstname'],
'middlenames' => $lpa['lpa']['donor']['middlenames'],
'surname' => $lpa['lpa']['donor']['surname'],
],
- 'caseSubtype' => $lpa['lpa']['caseSubtype'],
- 'lpaActorToken' => $record['Id'],
- 'activationKeyDueDate' => $lpa['activationKeyDueDate'] ?? null,
+ 'caseSubtype' => $lpa['lpa']['caseSubtype'],
+ 'lpaActorToken' => $record['Id'],
+ 'activationKeyDueDate' => $lpa['activationKeyDueDate'] ?? null,
+ 'activationKeyRequestedDate' => $lpa['activationKeyRequestedDate'] ?? null,
];
if (array_key_exists('ActivateBy', $record)) {
$response['notActivated'] = true;
}
- return $response;
+ // filtering removes all falsy values - including null.
+ return array_filter($response);
}
/**
diff --git a/service-api/app/src/App/src/Service/Lpa/LpaService.php b/service-api/app/src/App/src/Service/Lpa/LpaService.php
index a87b7532b0..29c7414df4 100644
--- a/service-api/app/src/App/src/Service/Lpa/LpaService.php
+++ b/service-api/app/src/App/src/Service/Lpa/LpaService.php
@@ -1,5 +1,7 @@
viewerCodesRepository = $viewerCodesRepository;
- $this->viewerCodeActivityRepository = $viewerCodeActivityRepository;
- $this->lpaRepository = $lpaRepository;
- $this->userLpaActorMapRepository = $userLpaActorMapRepository;
- $this->logger = $logger;
- $this->actorCodes = $actorCodes;
- $this->resolveActor = $resolveActor;
- $this->getAttorneyStatus = $getAttorneyStatus;
- $this->isValidLpa = $isValidLpa;
- $this->getTrustCorporationStatus = $getTrustCorporationStatus;
}
/**
* Get an LPA using the ID value
*
* @param string $uid Sirius uId of LPA to fetch
- *
* @return ?LpaInterface A processed LPA data transfer object
*/
public function getByUid(string $uid): ?LpaInterface
@@ -78,7 +53,7 @@ public function getByUid(string $uid): ?LpaInterface
if ($lpaData['attorneys'] !== null) {
$lpaData['original_attorneys'] = $lpaData['attorneys'];
- $lpaData['activeAttorneys'] = array_values(
+ $lpaData['activeAttorneys'] = array_values(
array_filter($lpaData['attorneys'], function ($attorney) {
return ($this->getAttorneyStatus)($attorney) === self::ACTIVE_ATTORNEY;
})
@@ -87,7 +62,7 @@ public function getByUid(string $uid): ?LpaInterface
if ($lpaData['attorneys'] !== null) {
$lpaData['original_attorneys'] = $lpaData['attorneys'];
- $lpaData['inactiveAttorneys'] = array_values(
+ $lpaData['inactiveAttorneys'] = array_values(
array_filter($lpaData['attorneys'], function ($attorney) {
return ($this->getAttorneyStatus)($attorney) === self::INACTIVE_ATTORNEY;
})
@@ -110,7 +85,6 @@ public function getByUid(string $uid): ?LpaInterface
*
* @param string $token UserLpaActorToken that map an LPA to a user account
* @param string $userId The user account ID that must correlate to the $token
- *
* @return ?array A structure that contains processed LPA data and metadata
*/
public function getByUserLpaActorToken(string $token, string $userId): ?array
@@ -132,15 +106,16 @@ public function getByUserLpaActorToken(string $token, string $userId): ?array
unset($lpaData['original_attorneys']);
$result = [
- 'user-lpa-actor-token' => $map['Id'],
- 'date' => $lpa->getLookupTime()->format('c'),
- 'lpa' => $lpaData,
- 'activationKeyDueDate' => $map['DueBy'] ?? null
+ 'user-lpa-actor-token' => $map['Id'],
+ 'date' => $lpa->getLookupTime()->format('c'),
+ 'lpa' => $lpaData,
+ 'activationKeyDueDate' => $map['DueBy'] ?? null,
+ 'activationKeyRequestedDate' => $map['Updated'] ?? null,
];
// If an actor has been stored against an LPA then attempt to resolve it from the API return
if (isset($map['ActorId'])) {
- $actor = ($this->resolveActor)($lpaData, $map['ActorId']);
+ $actor = ($this->resolveActor)($lpaData, (string) $map['ActorId']);
// If an active attorney is not found then we should not return an lpa
$result['actor'] = $actor;
@@ -148,7 +123,8 @@ public function getByUserLpaActorToken(string $token, string $userId): ?array
// Extract and return only LPA's where status is Registered or Cancelled
if (($this->isValidLpa)($lpaData)) {
- return $result;
+ // remove falsy values (i.e. nulls)
+ return array_filter($result);
}
// LPA was found but is not valid for use.
@@ -159,7 +135,6 @@ public function getByUserLpaActorToken(string $token, string $userId): ?array
* Return all LPAs for the given user_id
*
* @param string $userId User account ID to fetch LPAs for
- *
* @return array An array of LPA data structures containing processed LPA data and metadata
*/
public function getAllForUser(string $userId): array
@@ -178,7 +153,6 @@ public function getAllForUser(string $userId): array
* Return all LPAs for the given user_id
*
* @param string $userId User account ID to fetch LPA and Requests for
- *
* @return array An array of LPA data structures containing processed LPA data and metadata
*/
public function getAllLpasAndRequestsForUser(string $userId): array
@@ -195,7 +169,6 @@ public function getAllLpasAndRequestsForUser(string $userId): array
* @param string $viewerCode A code that directly maps to an LPA
* @param string $donorSurname The surname of the donor that must correlate to the $viewerCode
* @param ?string $organisation An organisation name that will be recorded as used against the $viewerCode
- *
* @return ?array A structure that contains processed LPA data and metadata
*/
public function getByViewerCode(string $viewerCode, string $donorSurname, ?string $organisation = null): ?array
@@ -212,7 +185,8 @@ public function getByViewerCode(string $viewerCode, string $donorSurname, ?strin
//---
// Check donor's surname
-
+ // TODO: [UML-2852] this check is naive and subject to the same issues as our actor matching with
+ // regards to apostrophes in surnames.
if (
is_null($lpa)
|| !isset($lpa->getData()['donor']['surname'])
@@ -255,26 +229,19 @@ public function getByViewerCode(string $viewerCode, string $donorSurname, ?strin
$lpaData = $lpa->getData();
unset($lpaData['original_attorneys']);
- $lpaData = [
- 'date' => $lpa->getLookupTime()->format('c'),
- 'expires' => $viewerCodeData['Expires']->format('c'),
+ return [
+ 'date' => $lpa->getLookupTime()->format('c'),
+ 'expires' => $viewerCodeData['Expires']->format('c'),
'organisation' => $viewerCodeData['Organisation'],
- 'lpa' => $lpaData,
+ 'lpa' => $lpaData,
];
-
- if (isset($viewerCodeData['Cancelled'])) {
- $lpaData['cancelled'] = $viewerCodeData['Cancelled']->format('c');
- }
-
- return $lpaData;
}
/**
* @param $lpaActorMaps Map of LPAs from Dynamo
- *
* @return array an array with formatted LPA results
*/
- private function lookupAndFormatLpas($lpaActorMaps): array
+ private function lookupAndFormatLpas(array $lpaActorMaps): array
{
$lpaUids = array_column($lpaActorMaps, 'SiriusUid');
@@ -296,7 +263,7 @@ private function lookupAndFormatLpas($lpaActorMaps): array
}
$lpaData = $lpa->getData();
- $actor = ($this->resolveActor)($lpaData, $item['ActorId']);
+ $actor = ($this->resolveActor)($lpaData, (string) $item['ActorId']);
$added = $item['Added']->format('Y-m-d H:i:s');
unset($lpaData['original_attorneys']);
@@ -305,10 +272,10 @@ private function lookupAndFormatLpas($lpaActorMaps): array
if (($this->isValidLpa)($lpaData)) {
$result[$item['Id']] = [
'user-lpa-actor-token' => $item['Id'],
- 'date' => $lpa->getLookupTime()->format('c'),
- 'actor' => $actor,
- 'lpa' => $lpaData,
- 'added' => $added,
+ 'date' => $lpa->getLookupTime()->format('c'),
+ 'actor' => $actor,
+ 'lpa' => $lpaData,
+ 'added' => $added,
];
}
}
diff --git a/service-api/app/test/AppTest/DataAccess/DynamoDb/ActorCodesTest.php b/service-api/app/test/AppTest/DataAccess/DynamoDb/ActorCodesTest.php
index 4b53a8f5b5..426defafb6 100644
--- a/service-api/app/test/AppTest/DataAccess/DynamoDb/ActorCodesTest.php
+++ b/service-api/app/test/AppTest/DataAccess/DynamoDb/ActorCodesTest.php
@@ -6,7 +6,7 @@
use App\DataAccess\DynamoDb\ActorCodes;
use Aws\DynamoDb\DynamoDbClient;
-use DateTime;
+use DateTimeInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
@@ -74,7 +74,7 @@ public function can_lookup_a_code(): void
$this->assertEquals($testCode, $result['ActorCode']);
$this->assertEquals($testSiriusUid, $result['SiriusUid']);
$this->assertEquals($testActive, $result['Active']);
- $this->assertInstanceOf(DateTime::class, $result['Expires']);
+ $this->assertInstanceOf(DateTimeInterface::class, $result['Expires']);
$this->assertEquals($testExpires, $result['Expires']->format('c'));
$this->assertEquals($testActorId, $result['ActorLpaId']);
}
diff --git a/service-api/app/test/AppTest/DataAccess/DynamoDb/UserLpaActorMapTest.php b/service-api/app/test/AppTest/DataAccess/DynamoDb/UserLpaActorMapTest.php
index ead8505b92..83a813f648 100644
--- a/service-api/app/test/AppTest/DataAccess/DynamoDb/UserLpaActorMapTest.php
+++ b/service-api/app/test/AppTest/DataAccess/DynamoDb/UserLpaActorMapTest.php
@@ -9,8 +9,8 @@
use Aws\DynamoDb\DynamoDbClient;
use Aws\DynamoDb\Exception\DynamoDbException;
use DateInterval;
-use DateTime;
use DateTimeImmutable;
+use DateTimeInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
@@ -94,7 +94,7 @@ public function can_lookup_a_token(): void
$this->assertEquals($testToken, $result['Id']);
$this->assertEquals($testSiriusUid, $result['SiriusUid']);
$this->assertEquals($testUserId, $result['UserId']);
- $this->assertInstanceOf(DateTime::class, $result['Added']);
+ $this->assertInstanceOf(DateTimeInterface::class, $result['Added']);
$this->assertEquals($testAdded, $result['Added']->format('c'));
$this->assertEquals($testActorId, $result['ActorId']);
}
@@ -421,29 +421,29 @@ public function can_activate_record(): void
$this->assertArrayHasKey('UpdateExpression', $data);
$this->assertEquals(
- 'set ActorId = :a, ActivationCode = :b, ActivatedOn = :c remove ActivateBy, DueBy',
+ 'set ActorId = :a, ActivationCode = :b, ActivatedOn = :c, Updated = :d remove ActivateBy, DueBy',
$data['UpdateExpression']
);
return true;
}))->willReturn($this->createAWSResult([
'Item' => [
- 'Id' => [
+ 'Id' => [
'S' => $testToken,
],
- 'SiriusUid' => [
+ 'SiriusUid' => [
'S' => $testSiriusUid,
],
- 'Added' => [
+ 'Added' => [
'S' => $testAdded,
],
- 'ActorId' => [
+ 'ActorId' => [
'S' => $testActorId,
],
- 'UserId' => [
+ 'UserId' => [
'S' => $testUserId,
],
- 'ActivatedOn' => [
+ 'ActivatedOn' => [
'S' => $testActivated,
],
],
@@ -530,7 +530,7 @@ public function can_get_all_lpas_for_user(): void
$this->assertEquals($testSiriusUid, $item['SiriusUid']);
$this->assertEquals($testActorId, $item['ActorId']);
- $this->assertInstanceOf(DateTime::class, $item['Added']);
+ $this->assertInstanceOf(DateTimeInterface::class, $item['Added']);
$this->assertEquals($testAdded, $item['Added']->format('c'));
}
@@ -557,7 +557,10 @@ public function can_update_record(): void
$this->assertEquals(['Id' => ['S' => $testToken]], $data['Key']);
$this->assertArrayHasKey('UpdateExpression', $data);
- $this->assertEquals('set ActivateBy = :a, DueBy = :b, ActorId = :c', $data['UpdateExpression']);
+ $this->assertEquals(
+ 'set ActivateBy = :a, DueBy = :b, Updated = :c, ActorId = :d',
+ $data['UpdateExpression']
+ );
$this->assertArrayHasKey(':a', $data['ExpressionAttributeValues']);
$this->assertArrayHasKey('N', $data['ExpressionAttributeValues'][':a']);
@@ -588,7 +591,7 @@ public function can_update_record(): void
'N' => $expiry,
],
'DueBy' => [
- 'S' => 'P2W',
+ 'S' => (new DateTimeImmutable('+2 weeks'))->format(DateTimeInterface::ATOM),
],
],
]
@@ -629,7 +632,7 @@ public function can_update_record_without_actorId(): void
$this->assertEquals(['Id' => ['S' => $testToken]], $data['Key']);
$this->assertArrayHasKey('UpdateExpression', $data);
- $this->assertEquals('set ActivateBy = :a, DueBy = :b', $data['UpdateExpression']);
+ $this->assertEquals('set ActivateBy = :a, DueBy = :b, Updated = :c', $data['UpdateExpression']);
$this->assertArrayHasKey(':a', $data['ExpressionAttributeValues']);
$this->assertArrayHasKey('N', $data['ExpressionAttributeValues'][':a']);
@@ -638,7 +641,7 @@ public function can_update_record_without_actorId(): void
$this->assertArrayHasKey(':b', $data['ExpressionAttributeValues']);
$this->assertArrayHasKey('S', $data['ExpressionAttributeValues'][':b']);
- $this->assertArrayNotHasKey(':c', $data['ExpressionAttributeValues']);
+ $this->assertArrayNotHasKey(':d', $data['ExpressionAttributeValues']);
return true;
}))->willReturn($this->createAWSResult(
@@ -663,7 +666,7 @@ public function can_update_record_without_actorId(): void
'N' => $expiry,
],
'DueBy' => [
- 'S' => 'P2W',
+ 'S' => (new DateTimeImmutable('+2 weeks'))->format(DateTimeInterface::ATOM),
],
],
]
@@ -675,7 +678,12 @@ public function can_update_record_without_actorId(): void
$this->prophesize(LoggerInterface::class)->reveal(),
);
- $renew = $userLpaActorMapRepo->updateRecord($testToken, new DateInterval('P1Y'), new DateInterval('P2W'), null);
+ $renew = $userLpaActorMapRepo->updateRecord(
+ $testToken,
+ new DateInterval('P1Y'),
+ new DateInterval('P2W'),
+ null
+ );
$this->assertEquals($testToken, $renew['Id']);
}
}
diff --git a/service-api/app/test/AppTest/Service/Lpa/AddAccessForAllLpaTest.php b/service-api/app/test/AppTest/Service/Lpa/AddAccessForAllLpaTest.php
index 4cae9fe62f..e704941ef3 100644
--- a/service-api/app/test/AppTest/Service/Lpa/AddAccessForAllLpaTest.php
+++ b/service-api/app/test/AppTest/Service/Lpa/AddAccessForAllLpaTest.php
@@ -18,6 +18,7 @@
use DateInterval;
use DateTime;
use DateTimeImmutable;
+use DateTimeInterface;
use Fig\Http\Message\StatusCodeInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
@@ -178,25 +179,27 @@ public function older_lpa_lookup_throws_an_exception_if_lpa_already_requested():
{
$createdDate = (new DateTime())->modify('-14 days');
- $activationKeyDueDate = DateTimeImmutable::createFromMutable($createdDate);
- $activationKeyDueDate = $activationKeyDueDate
+ $activationKeyRequestedDate = DateTimeImmutable::createFromMutable($createdDate);
+ $activationKeyDueDate = $activationKeyRequestedDate
->add(new DateInterval('P10D'))
- ->format('Y-m-d');
+ ->format(DateTimeInterface::ATOM);
$this->featureEnabledProphecy
->__invoke('dont_send_lpas_registered_after_sep_2019_to_cleansing_team')
->willReturn(false);
+
$alreadyAddedData = [
- 'donor' => [
+ 'donor' => [
'uId' => '12345',
'firstname' => 'Example',
'middlenames' => 'Donor',
'surname' => 'Person',
],
- 'caseSubtype' => 'hw',
- 'lpaActorToken' => 'qwerty-54321',
- 'activationKeyDueDate' => null,
- 'notActivated' => true,
+ 'caseSubtype' => 'hw',
+ 'lpaActorToken' => 'qwerty-54321',
+ 'activationKeyDueDate' => $activationKeyDueDate,
+ 'activationKeyRequestedDate' => $activationKeyRequestedDate,
+ 'notActivated' => true,
];
$this->lpaAlreadyAddedProphecy
@@ -221,9 +224,10 @@ public function older_lpa_lookup_throws_an_exception_if_lpa_already_requested():
$expectedException = new BadRequestException(
'Activation key already requested for LPA',
[
- 'donor' => $this->resolvedActor['donor'],
- 'caseSubtype' => $this->resolvedActor['caseSubtype'],
- 'activationKeyDueDate' => $activationKeyDueDate,
+ 'donor' => $this->resolvedActor['donor'],
+ 'caseSubtype' => $this->resolvedActor['caseSubtype'],
+ 'activationKeyDueDate' => $activationKeyDueDate,
+ 'activationKeyRequestedDate' => $activationKeyRequestedDate,
]
);
diff --git a/service-api/app/test/AppTest/Service/Lpa/LpaAlreadyAddedTest.php b/service-api/app/test/AppTest/Service/Lpa/LpaAlreadyAddedTest.php
index 53854e595a..f3b2875766 100644
--- a/service-api/app/test/AppTest/Service/Lpa/LpaAlreadyAddedTest.php
+++ b/service-api/app/test/AppTest/Service/Lpa/LpaAlreadyAddedTest.php
@@ -114,6 +114,7 @@ public function returns_not_activated_flag_if_lpa_requested_but_not_active(): vo
'Id' => $this->userLpaActorToken,
'SiriusUid' => $this->lpaUid,
'ActivateBy' => (new DateTimeImmutable('now'))->format('Y-m-d H:i:s'),
+ 'DueBy' => '0000-00-00T00:00:00+00:00',
],
]
);
@@ -122,8 +123,8 @@ public function returns_not_activated_flag_if_lpa_requested_but_not_active(): vo
->getByUserLpaActorToken($this->userLpaActorToken, $this->userId)
->willReturn(
[
- 'user-lpa-actor-token' => $this->userLpaActorToken,
- 'lpa' => [
+ 'user-lpa-actor-token' => $this->userLpaActorToken,
+ 'lpa' => [
'uId' => $this->lpaUid,
'caseSubtype' => 'hw',
'donor' => [
@@ -132,24 +133,26 @@ public function returns_not_activated_flag_if_lpa_requested_but_not_active(): vo
'middlenames' => '',
'surname' => 'Person',
],
- 'activationKeyDueDate' => null,
],
+ 'activationKeyDueDate' => '0000-00-00T00:00:00+00:00',
+ 'activationKeyRequestedDate' => '0000-00-00T00:00:00+00:00',
]
);
$lpaAddedData = ($this->getLpaAlreadyAddedService())($this->userId, $this->lpaUid);
$this->assertEquals(
[
- 'donor' => [
+ 'donor' => [
'uId' => '700000000444',
'firstname' => 'Another',
'middlenames' => '',
'surname' => 'Person',
],
- 'caseSubtype' => 'hw',
- 'lpaActorToken' => $this->userLpaActorToken,
- 'notActivated' => true,
- 'activationKeyDueDate' => null,
+ 'caseSubtype' => 'hw',
+ 'lpaActorToken' => $this->userLpaActorToken,
+ 'notActivated' => true,
+ 'activationKeyDueDate' => '0000-00-00T00:00:00+00:00',
+ 'activationKeyRequestedDate' => '0000-00-00T00:00:00+00:00',
],
$lpaAddedData
);
@@ -254,8 +257,13 @@ public function returns_lpa_data_if_lpa_is_already_added(): void
->willReturn(
[
[
- 'Id' => $this->userLpaActorToken,
- 'SiriusUid' => $this->lpaUid,
+ 'Id' => $this->userLpaActorToken,
+ 'UserId' => $this->userId,
+ 'SiriusUid' => $this->lpaUid,
+ 'Added' => '0000-00-00T00:00:00+00:00',
+ 'Updated' => '0000-00-00T00:00:00+00:00',
+ 'ActivateBy' => '0000-00-00T00:00:00+00:00',
+ 'DueBy' => '0000-00-00T00:00:00+00:00',
],
]
);
@@ -264,8 +272,8 @@ public function returns_lpa_data_if_lpa_is_already_added(): void
->getByUserLpaActorToken($this->userLpaActorToken, $this->userId)
->willReturn(
[
- 'user-lpa-actor-token' => $this->userLpaActorToken,
- 'lpa' => [
+ 'user-lpa-actor-token' => $this->userLpaActorToken,
+ 'lpa' => [
'uId' => $this->lpaUid,
'caseSubtype' => 'hw',
'donor' => [
@@ -275,21 +283,25 @@ public function returns_lpa_data_if_lpa_is_already_added(): void
'surname' => 'Person',
],
],
+ 'activationKeyDueDate' => '0000-00-00T00:00:00+00:00',
+ 'activationKeyRequestedDate' => '0000-00-00T00:00:00+00:00',
]
);
$lpaAddedData = ($this->getLpaAlreadyAddedService())($this->userId, $this->lpaUid);
$this->assertEquals(
[
- 'donor' => [
+ 'donor' => [
'uId' => '700000000444',
'firstname' => 'Another',
'middlenames' => '',
'surname' => 'Person',
],
- 'caseSubtype' => 'hw',
- 'lpaActorToken' => $this->userLpaActorToken,
- 'activationKeyDueDate' => null,
+ 'caseSubtype' => 'hw',
+ 'lpaActorToken' => $this->userLpaActorToken,
+ 'notActivated' => true,
+ 'activationKeyDueDate' => '0000-00-00T00:00:00+00:00',
+ 'activationKeyRequestedDate' => '0000-00-00T00:00:00+00:00',
],
$lpaAddedData
);
diff --git a/service-front/app/features/actor-add-an-older-lpa.feature b/service-front/app/features/actor-add-an-older-lpa.feature
index 84ea62f8ac..b2a1596f5e 100644
--- a/service-front/app/features/actor-add-an-older-lpa.feature
+++ b/service-front/app/features/actor-add-an-older-lpa.feature
@@ -73,6 +73,12 @@ Feature: Add an older LPA
When I request for a new activation key again
Then I am told a new activation key is posted to the provided postcode
+ @ui @integration
+ Scenario: The user cannot request a new key on the same day as another attempt
+ Given I have already requested an activation key that day
+ When I request an activation key for my lpa
+ Then I am told that I cannot request another activation key on the same day
+
@ui @integration
Scenario: The user is unable to request key for an LPA that they have already added
Given I am on the add an older LPA page
diff --git a/service-front/app/features/context/Integration/LpaContext.php b/service-front/app/features/context/Integration/LpaContext.php
index ccf33d5364..15e6b9e416 100644
--- a/service-front/app/features/context/Integration/LpaContext.php
+++ b/service-front/app/features/context/Integration/LpaContext.php
@@ -23,6 +23,8 @@
use Common\Service\Lpa\ViewerCodeService;
use Common\Service\Notify\NotifyService;
use DateTime;
+use DateTimeImmutable;
+use DateTimeInterface;
use Fig\Http\Message\StatusCodeInterface;
use GuzzleHttp\Handler\MockHandler;
use PHPUnit\Framework\Assert;
@@ -1444,7 +1446,7 @@ public function iReceiveAnEmailConfirmingActivationKeyRequest()
*/
public function iAmToldThatIHaveAnActivationKeyForThisLPAAndWhereToFindIt()
{
- $createdDate = (new DateTime())->modify('-14 days');
+ $createdDate = (new DateTimeImmutable())->modify('-14 days')->format(DateTimeInterface::ATOM);
// API call for requesting activation code
$this->apiFixtures->append(
@@ -1452,18 +1454,18 @@ public function iAmToldThatIHaveAnActivationKeyForThisLPAAndWhereToFindIt()
StatusCodeInterface::STATUS_BAD_REQUEST,
json_encode(
[
- 'title' => 'Bad Request',
+ 'title' => 'Bad Request',
'details' => 'LPA has an activation key already',
- 'data' => [
- 'donor' => [
- 'uId' => $this->lpa['donor']['uId'],
- 'firstname' => $this->lpa['donor']['firstname'],
+ 'data' => [
+ 'donor' => [
+ 'uId' => $this->lpa['donor']['uId'],
+ 'firstname' => $this->lpa['donor']['firstname'],
'middlenames' => $this->lpa['donor']['middlenames'],
- 'surname' => $this->lpa['donor']['surname'],
+ 'surname' => $this->lpa['donor']['surname'],
],
- 'caseSubtype' => $this->lpa['caseSubtype'],
- 'activationKeyDueDate' => $createdDate->format('c')
- ]
+ 'caseSubtype' => $this->lpa['caseSubtype'],
+ 'activationKeyDueDate' => $createdDate,
+ ],
]
),
self::ADD_OLDER_LPA_VALIDATE
@@ -1474,7 +1476,7 @@ public function iAmToldThatIHaveAnActivationKeyForThisLPAAndWhereToFindIt()
$result = $addOlderLpa->validate(
$this->userIdentity,
- intval($this->referenceNo),
+ (int) $this->referenceNo,
$this->userFirstname,
$this->userSurname,
DateTime::createFromFormat('Y-m-d', $this->userDob),
@@ -1490,7 +1492,7 @@ public function iAmToldThatIHaveAnActivationKeyForThisLPAAndWhereToFindIt()
$keyExistsDTO = new ActivationKeyExists();
$keyExistsDTO->setDonor($donor);
$keyExistsDTO->setCaseSubtype($this->lpa['caseSubtype']);
- $keyExistsDTO->setDueDate($createdDate->format('c'));
+ $keyExistsDTO->setDueDate(new DateTimeImmutable($createdDate));
$response = new AccessForAllApiResult(
AccessForAllResult::HAS_ACTIVATION_KEY,
diff --git a/service-front/app/features/context/UI/BaseUiContext.php b/service-front/app/features/context/UI/BaseUiContext.php
index f9ba082b2c..e413411e4e 100644
--- a/service-front/app/features/context/UI/BaseUiContext.php
+++ b/service-front/app/features/context/UI/BaseUiContext.php
@@ -6,10 +6,9 @@
use Acpr\Behat\Psr\Context\Psr11MinkAwareContext;
use Acpr\Behat\Psr\Context\RuntimeMinkContext;
-use Amp\Process\Internal\Posix\Handle;
-use App\Service\ApiClient\Client;
use Aws\MockHandler as AwsMockHandler;
use Aws\Result;
+use Behat\Behat\Hook\Scope\AfterScenarioScope;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use Behat\MinkExtension\Context\MinkContext;
use Behat\MinkExtension\Context\RawMinkContext;
@@ -17,16 +16,12 @@
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
-use GuzzleHttp\Psr7\Response;
-use GuzzleHttp\Psr7\Stream;
use Laminas\Stratigility\Middleware\ErrorHandler;
-use PHPUnit\Framework\ExpectationFailedException;
+use Monolog\Handler\TestHandler;
+use Monolog\Logger;
use Psr\Container\ContainerInterface;
-use Psr\Http\Client\ClientInterface;
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
+use Psr\Log\LoggerInterface;
-use function DI\get;
use function random_bytes;
require_once __DIR__ . '/../../../vendor/phpunit/phpunit/src/Framework/Assert/Functions.php';
@@ -53,9 +48,10 @@ public function setContainer(ContainerInterface $container): void
$this->container = $container;
//Create handler stack and push to container
- $mockHandler = $container->get(MockHandler::class);
+ $mockHandler = $container->get(MockHandler::class);
$handlerStack = HandlerStack::create($mockHandler);
- $history = Middleware::history($this->mockClientHistoryContainer);
+ $history = Middleware::history($this->mockClientHistoryContainer);
+
$handlerStack->push($history);
$handlerStack->remove('http_errors');
$handlerStack->remove('cookies');
@@ -71,28 +67,52 @@ public function setContainer(ContainerInterface $container): void
/**
* @BeforeScenario
*/
- public function gatherContexts(BeforeScenarioScope $scope)
+ public function gatherContexts(BeforeScenarioScope $scope): void
{
$environment = $scope->getEnvironment();
- $this->ui = $environment->getContext(MinkContext::class);
+ $this->ui = $environment->getContext(MinkContext::class);
}
/**
* @BeforeScenario
*/
- public function seedFixtures()
+ public function seedFixtures(): void
{
// KMS is polled for encryption data on first page load
$this->awsFixtures->append(
new Result(
[
- 'Plaintext' => random_bytes(32),
- 'CiphertextBlob' => random_bytes(32)
+ 'Plaintext' => random_bytes(32),
+ 'CiphertextBlob' => random_bytes(32),
]
)
);
}
+ /**
+ * @AfterScenario
+ */
+ public function outputLogsOnFailure(AfterScenarioScope $scope): void
+ {
+ $logger = $this->container->get(LoggerInterface::class);
+
+ if ($logger instanceof Logger) {
+ /** @var TestHandler $testHandler */
+ $testHandler = array_filter(
+ $logger->getHandlers(),
+ fn ($handler) => $handler instanceof TestHandler
+ )[0];
+
+ if (!$scope->getTestResult()->isPassed()) {
+ foreach ($testHandler->getRecords() as $record) {
+ print_r($record['formatted']);
+ }
+ }
+
+ $logger->reset();
+ }
+ }
+
/**
* @AfterScenario
*/
@@ -100,5 +120,4 @@ public function resetSharedState(): void
{
SharedState::getInstance()->reset();
}
-
}
diff --git a/service-front/app/features/context/UI/RequestActivationKeyContext.php b/service-front/app/features/context/UI/RequestActivationKeyContext.php
index 46f6581b34..768b8fd03f 100644
--- a/service-front/app/features/context/UI/RequestActivationKeyContext.php
+++ b/service-front/app/features/context/UI/RequestActivationKeyContext.php
@@ -9,8 +9,9 @@
use BehatTest\Context\BaseUiContextTrait;
use BehatTest\Context\ContextUtilities;
use DateTime;
+use DateTimeImmutable;
+use DateTimeInterface;
use Fig\Http\Message\StatusCodeInterface;
-use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\Assert;
use Psr\Http\Message\RequestInterface;
@@ -35,8 +36,8 @@ class RequestActivationKeyContext implements Context
use ActorContext;
use BaseUiContextTrait;
- private const ADD_OLDER_LPA_VALIDATE = 'AddOlderLpa::validate';
- private const ADD_OLDER_LPA_CONFIRM = 'AddOlderLpa::confirm';
+ private const ADD_ACCESS_FOR_ALL_LPA_VALIDATE = 'AddAccessForAllLpa::validate';
+ private const ADD_ACCESS_FOR_ALL_LPA_CONFIRM = 'AddAccessForAllLpa::confirm';
private const CLEANSE_LPA_CLEANSE = 'CleanseLpa::cleanse';
/**
@@ -53,6 +54,14 @@ public function iAmTakenToTheCheckAnswersPage()
$this->ui->assertPageAddress('/lpa/request-code/check-answers');
}
+ /**
+ * @Then /^I am told that I cannot request another activation key on the same day$/
+ */
+ public function iAmToldThatICannotRequestAnotherActivationKeyOnTheSameDay()
+ {
+ $this->ui->assertPageContainsText("You've already asked for an activation key for this LPA today");
+ }
+
/**
* @Given /^I am told that I have already requested an activation key for this LPA$/
*/
@@ -111,6 +120,14 @@ public function iAmAskedForTheAttorneyDetails()
$this->ui->assertPageContainsText('Attorney details');
}
+ /**
+ * @Given /^I have already requested an activation key that day$/
+ */
+ public function iHaveAlreadyRequestedAnActivationKeyThatDay()
+ {
+ $this->keyAlreadyRequestedToday = true;
+ }
+
/**
* @When /^I provide the attorney details$/
*/
@@ -173,13 +190,54 @@ public function iRequestAnActivationKey()
'data' => [],
]
),
- self::ADD_OLDER_LPA_VALIDATE,
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE,
)
);
$this->iPressTheContinueButton();
}
+ /**
+ * @When /^I request an activation key for my lpa$/
+ */
+ public function iRequestAnActivationKeyForMyLpa()
+ {
+ // completes the request journey up until the check details page
+ $this->iHaveRequestedAnActivationKeyWithValidDetails();
+
+ $data = [
+ 'donor' => [
+ 'uId' => $this->lpa->donor->uId,
+ 'firstname' => $this->lpa->donor->firstname,
+ 'middlenames' => $this->lpa->donor->middlenames,
+ 'surname' => $this->lpa->donor->surname,
+ ],
+ 'caseSubtype' => $this->lpa->caseSubtype,
+ 'lpaActorToken' => $this->userLpaActorToken,
+ 'activationKeyDueDate' => (new DateTimeImmutable('+1 week'))->format(DateTimeInterface::ATOM),
+ ];
+
+ if (isset($this->keyAlreadyRequestedToday)) {
+ $date = new DateTimeImmutable('today');
+ $data['activationKeyRequestedDate'] = $date->format(DateTimeInterface::ATOM);
+ }
+
+ $this->apiFixtures->append(
+ ContextUtilities::newResponse(
+ StatusCodeInterface::STATUS_BAD_REQUEST,
+ json_encode(
+ [
+ 'title' => 'Bad request',
+ 'details' => 'Activation key already requested for LPA',
+ 'data' => $data,
+ ]
+ ),
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE,
+ )
+ );
+ $this->iPressTheContinueButton();
+ }
+
/**
* @When /^I request an activation key for an LPA that already exists in my account$/
*/
@@ -205,7 +263,7 @@ public function iRequestAnActivationKeyThatAlreadyExists()
]
]
),
- self::ADD_OLDER_LPA_VALIDATE,
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE,
)
);
$this->iPressTheContinueButton();
@@ -608,7 +666,7 @@ public function iConfirmDetailsShownToMeOfTheFoundLPAAreCorrect()
ContextUtilities::newResponse(
StatusCodeInterface::STATUS_NO_CONTENT,
json_encode([]),
- self::ADD_OLDER_LPA_CONFIRM
+ self::ADD_ACCESS_FOR_ALL_LPA_CONFIRM
)
);
@@ -926,7 +984,7 @@ public function iProvideDetailsFromAnLpaRegisteredBeforeSept2019()
'data' => [],
]
),
- self::ADD_OLDER_LPA_VALIDATE
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE
)
);
}
@@ -949,7 +1007,7 @@ public function iProvideDetailsThatDoNotMatchAValidPaperDocument()
'data' => [],
]
),
- self::ADD_OLDER_LPA_VALIDATE
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE
)
);
}
@@ -972,7 +1030,7 @@ public function iProvideAnLPANumberThatDoesNotExist()
'data' => [],
]
),
- self::ADD_OLDER_LPA_VALIDATE
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE
)
);
}
@@ -1039,7 +1097,7 @@ public function iProvideTheDetailsFromAValidPaperDocument()
'role' => 'donor',
]
),
- self::ADD_OLDER_LPA_VALIDATE
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE
)
);
} else {
@@ -1064,7 +1122,7 @@ public function iProvideTheDetailsFromAValidPaperDocument()
],
]
),
- self::ADD_OLDER_LPA_VALIDATE
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE
)
);
}
@@ -1096,7 +1154,7 @@ public function iProvideTheDetailsFromAValidPaperLPAWhichIHaveAlreadyAddedToMyAc
],
]
),
- self::ADD_OLDER_LPA_VALIDATE
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE
)
);
}
@@ -1196,7 +1254,7 @@ public function iRequestForANewActivationKeyAgain()
ContextUtilities::newResponse(
StatusCodeInterface::STATUS_NO_CONTENT,
json_encode([]),
- self::ADD_OLDER_LPA_CONFIRM
+ self::ADD_ACCESS_FOR_ALL_LPA_CONFIRM
)
);
@@ -1494,18 +1552,21 @@ public function iProvideTheDetailsFromAValidPaperLPAWhichIHaveAlreadyRequestedAn
'title' => 'Bad request',
'details' => 'Activation key already requested for LPA',
'data' => [
- 'donor' => [
+ 'donor' => [
'uId' => $this->lpa->donor->uId,
'firstname' => $this->lpa->donor->firstname,
'middlenames' => $this->lpa->donor->middlenames,
'surname' => $this->lpa->donor->surname,
],
- 'caseSubtype' => $this->lpa->caseSubtype,
- 'activationKeyDueDate' => '2022-01-30',
+ 'caseSubtype' => $this->lpa->caseSubtype,
+ 'activationKeyDueDate'
+ => (new DateTimeImmutable('+5 days'))->format(DateTimeInterface::ATOM),
+ 'activationKeyRequestedDate'
+ => (new DateTimeImmutable('-9 days'))->format(DateTimeInterface::ATOM),
],
]
),
- self::ADD_OLDER_LPA_VALIDATE
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE
)
);
@@ -1526,7 +1587,7 @@ public function iProvideDetailsDetailsOfAnLpaThatIsNotRegistered()
ContextUtilities::newResponse(
StatusCodeInterface::STATUS_NOT_FOUND,
json_encode([]),
- self::ADD_OLDER_LPA_VALIDATE
+ self::ADD_ACCESS_FOR_ALL_LPA_VALIDATE
)
);
}
@@ -1590,7 +1651,7 @@ public function iConfirmDetailsOfTheFoundLpaAreCorrect()
],
]
),
- self::ADD_OLDER_LPA_CONFIRM
+ self::ADD_ACCESS_FOR_ALL_LPA_CONFIRM
)
);
@@ -1615,7 +1676,7 @@ public function iConfirmDetailsOfTheFoundLpaAreCorrect()
],
]
),
- self::ADD_OLDER_LPA_CONFIRM
+ self::ADD_ACCESS_FOR_ALL_LPA_CONFIRM
)
);
diff --git a/service-front/app/src/Actor/src/Handler/RequestActivationKey/CheckYourAnswersHandler.php b/service-front/app/src/Actor/src/Handler/RequestActivationKey/CheckYourAnswersHandler.php
index 85c09896c1..7cf7f07007 100644
--- a/service-front/app/src/Actor/src/Handler/RequestActivationKey/CheckYourAnswersHandler.php
+++ b/service-front/app/src/Actor/src/Handler/RequestActivationKey/CheckYourAnswersHandler.php
@@ -17,14 +17,17 @@
Traits\User,
UserAware};
use Common\Service\Features\FeatureEnabled;
+use Common\Service\Lpa\AccessForAllApiResult;
use Common\Service\Lpa\AddAccessForAllLpa;
use Common\Service\Lpa\LocalisedDate;
use Common\Service\Lpa\Response\AccessForAllResult;
+use Common\Service\Lpa\Response\ActivationKeyExists;
use Common\Service\Session\RemoveAccessForAllSessionValues;
use Common\Workflow\State;
use Common\Workflow\StateNotInitialisedException;
use Common\Workflow\WorkflowState;
use Common\Workflow\WorkflowStep;
+use DateTimeImmutable;
use Laminas\Diactoros\Response\HtmlResponse;
use Mezzio\Authentication\{AuthenticationInterface, UserInterface};
use Mezzio\Helper\UrlHelper;
@@ -64,6 +67,46 @@ public function __construct(
$this->setAuthenticator($authenticator);
}
+ public function keyRequestedToday(
+ ServerRequestInterface $request,
+ AccessForAllApiResult $result,
+ ): HtmlResponse {
+ /** @var ActivationKeyExists $resultData */
+ $resultData = $result->getData();
+
+ // The user has already requested a key today.
+ if ($resultData->getRequestedDate()?->diff(new DateTimeImmutable('today'))->days === 0) {
+ return new HtmlResponse(
+ $this->renderer->render(
+ 'actor::already-requested-activation-key-today',
+ [
+ 'user' => $this->user,
+ 'dueDate' => $resultData->getDueDate(),
+ 'donor' => $resultData->getDonor(),
+ 'caseSubtype' => $resultData->getCaseSubtype(),
+ ]
+ )
+ );
+ }
+
+ $form = new CreateNewActivationKey($this->getCsrfGuard($request), true);
+ $form->setAttribute(
+ 'action',
+ $this->urlHelper->generate('lpa.confirm-activation-key-generation')
+ );
+
+ return new HtmlResponse(
+ $this->renderer->render(
+ 'actor::already-requested-activation-key',
+ [
+ 'user' => $this->user,
+ 'dueDate' => $resultData->getDueDate(),
+ 'form' => $form,
+ ]
+ )
+ );
+ }
+
/**
* @param ServerRequestInterface $request
* @return ResponseInterface
@@ -169,44 +212,19 @@ public function handlePost(ServerRequestInterface $request): ResponseInterface
$this->urlHelper->generate('lpa.confirm-activation-key-generation')
);
- $activationKeyDueDate = date(
- 'Y-m-d',
- strtotime(($result->getData()->getDueDate()))
- );
-
return new HtmlResponse(
$this->renderer->render(
'actor::already-have-activation-key',
[
'user' => $this->user,
- 'dueDate' => $activationKeyDueDate,
+ 'dueDate' => $result->getData()->getDueDate(),
'form' => $form,
]
)
);
case AccessForAllResult::KEY_ALREADY_REQUESTED:
- $form = new CreateNewActivationKey($this->getCsrfGuard($request), true);
- $form->setAttribute(
- 'action',
- $this->urlHelper->generate('lpa.confirm-activation-key-generation')
- );
-
- $activationKeyDueDate = date(
- 'Y-m-d',
- strtotime(($result->getData()->getDueDate()))
- );
-
- return new HtmlResponse(
- $this->renderer->render(
- 'actor::already-requested-activation-key',
- [
- 'user' => $this->user,
- 'dueDate' => $activationKeyDueDate,
- 'form' => $form,
- ]
- )
- );
+ return $this->keyRequestedToday($request, $result);
case AccessForAllResult::DOES_NOT_MATCH:
if (($this->featureEnabled)('allow_older_lpas')) {
diff --git a/service-front/app/src/Actor/templates/actor/already-requested-activation-key-today.html.twig b/service-front/app/src/Actor/templates/actor/already-requested-activation-key-today.html.twig
new file mode 100644
index 0000000000..ca40a9a4b6
--- /dev/null
+++ b/service-front/app/src/Actor/templates/actor/already-requested-activation-key-today.html.twig
@@ -0,0 +1,50 @@
+{% extends '@actor/layout.html.twig' %}
+
+{% block html_title %}{% trans %}You've already asked for an activation key for this LPA today{% endtrans %} - {{ parent() }}{% endblock %}
+
+{% block content %}
+
+
+ {{ include('@partials/account-bar.html.twig') }}
+ {{ include('@partials/welsh-switch.html.twig') }}
+
+
+
+
+
{% trans %}You've already asked for an activation key for this LPA today{% endtrans %}
+
+
+
+
-
+ {% trans %}Donor name{% endtrans %}
+
+ -
+ {{ actor_name(donor) }}
+
+
+
+
-
+ {% trans %}Type of LPA{% endtrans %}
+
+ -
+ {% if caseSubtype|lower == "pfa" %}
+ {% trans %}Property and finance{% endtrans %}
+ {% else %}
+ {% trans %}Health and welfare{% endtrans %}
+ {% endif %}
+
+
+
+
+
{% trans %}We'll post you a letter with your activation key for this LPA. It will be sent to the address we have for you on our records. We send the key by post because it's more secure.{% endtrans %}
+
{% trans with {'%dueDate%' : lpa_date(dueDate)} %}You should hear from us or get the activation key letter by %dueDate%. If not, please contact us.{% endtrans %}
+
+
+ {% trans %}Back to your LPAs{% endtrans %}
+
+
+
+
+ {{ include('@actor/partials/new-use-service.html.twig') }}
+
+{% endblock %}
diff --git a/service-front/app/src/Common/src/Service/Lpa/AddAccessForAllLpa.php b/service-front/app/src/Common/src/Service/Lpa/AddAccessForAllLpa.php
index 8b10b1a2a1..78affd5b16 100644
--- a/service-front/app/src/Common/src/Service/Lpa/AddAccessForAllLpa.php
+++ b/service-front/app/src/Common/src/Service/Lpa/AddAccessForAllLpa.php
@@ -12,6 +12,7 @@
use Common\Service\Lpa\Response\Parse\ParseActivationKeyExists;
use Common\Service\Lpa\Response\Parse\ParseLpaAlreadyAdded;
use DateTimeInterface;
+use Exception;
use Fig\Http\Message\StatusCodeInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
@@ -48,6 +49,16 @@ public function __construct(
) {
}
+ /**
+ * @param string $userToken
+ * @param int $lpaUid
+ * @param string $firstnames
+ * @param string $lastname
+ * @param DateTimeInterface $dob
+ * @param string $postcode
+ * @return AccessForAllApiResult
+ * @throws Exception
+ */
public function validate(
string $userToken,
int $lpaUid,
@@ -160,6 +171,7 @@ public function confirm(
* @param string $message
* @param array $additionalData
* @return AccessForAllApiResult
+ * @throws Exception
*/
private function badRequestReturned(int $lpaUid, string $message, array $additionalData): AccessForAllApiResult
{
diff --git a/service-front/app/src/Common/src/Service/Lpa/Response/ActivationKeyExists.php b/service-front/app/src/Common/src/Service/Lpa/Response/ActivationKeyExists.php
index f2edb137e8..1e61080292 100644
--- a/service-front/app/src/Common/src/Service/Lpa/Response/ActivationKeyExists.php
+++ b/service-front/app/src/Common/src/Service/Lpa/Response/ActivationKeyExists.php
@@ -5,12 +5,14 @@
namespace Common\Service\Lpa\Response;
use Common\Entity\CaseActor;
+use DateTimeInterface;
class ActivationKeyExists extends Response
{
protected CaseActor $donor;
protected string $caseSubtype;
- protected string $activationKeyDueDate;
+ protected ?DateTimeInterface $activationKeyDueDate;
+ protected ?DateTimeInterface $activationKeyRequestedDate;
public function getDonor(): ?CaseActor
{
@@ -22,11 +24,16 @@ public function getCaseSubtype(): ?string
return $this->caseSubtype;
}
- public function getDueDate(): ?string
+ public function getDueDate(): ?DateTimeInterface
{
return $this->activationKeyDueDate;
}
+ public function getRequestedDate(): ?DateTimeInterface
+ {
+ return $this->activationKeyRequestedDate;
+ }
+
public function setDonor(CaseActor $donor): void
{
$this->donor = $donor;
@@ -37,8 +44,13 @@ public function setCaseSubtype(string $caseSubtype): void
$this->caseSubtype = $caseSubtype;
}
- public function setDueDate(string $activationKeyDueDate): void
+ public function setDueDate(DateTimeInterface $activationKeyDueDate): void
{
$this->activationKeyDueDate = $activationKeyDueDate;
}
+
+ public function setRequestedDate(DateTimeInterface $activationKeyRequestedDate): void
+ {
+ $this->activationKeyRequestedDate = $activationKeyRequestedDate;
+ }
}
diff --git a/service-front/app/src/Common/src/Service/Lpa/Response/Parse/ParseActivationKeyExists.php b/service-front/app/src/Common/src/Service/Lpa/Response/Parse/ParseActivationKeyExists.php
index 07b8217f2f..d3e68588b2 100644
--- a/service-front/app/src/Common/src/Service/Lpa/Response/Parse/ParseActivationKeyExists.php
+++ b/service-front/app/src/Common/src/Service/Lpa/Response/Parse/ParseActivationKeyExists.php
@@ -6,6 +6,8 @@
use Common\Service\Lpa\LpaFactory;
use Common\Service\Lpa\Response\ActivationKeyExists;
+use DateTimeImmutable;
+use DateTimeInterface;
use Exception;
use InvalidArgumentException;
@@ -22,7 +24,12 @@ public function __construct(private LpaFactory $lpaFactory)
}
/**
- * @param array{donor: array, caseSubtype: string} $data
+ * @param array{
+ * donor: array,
+ * caseSubtype: string,
+ * activationKeyDueDate: ?string,
+ * activationKeyRequestedDate: ?string
+ * } $data
* @return ActivationKeyExists
* @throws Exception
*/
@@ -39,7 +46,21 @@ public function __invoke(array $data): ActivationKeyExists
$response->setCaseSubtype($data['caseSubtype']);
if (isset($data['activationKeyDueDate'])) {
- $response->setDueDate($data['activationKeyDueDate']);
+ $response->setDueDate(
+ DateTimeImmutable::createFromFormat(
+ DateTimeInterface::ATOM,
+ $data['activationKeyDueDate']
+ )
+ );
+ }
+
+ if (isset($data['activationKeyRequestedDate'])) {
+ $response->setRequestedDate(
+ DateTimeImmutable::createFromFormat(
+ DateTimeInterface::ATOM,
+ $data['activationKeyRequestedDate']
+ )
+ );
}
return $response;
diff --git a/service-front/app/test/CommonTest/Service/Lpa/Response/ActivationKeyExistsResponseTest.php b/service-front/app/test/CommonTest/Service/Lpa/Response/ActivationKeyExistsResponseTest.php
index bb78e706dc..352816f317 100644
--- a/service-front/app/test/CommonTest/Service/Lpa/Response/ActivationKeyExistsResponseTest.php
+++ b/service-front/app/test/CommonTest/Service/Lpa/Response/ActivationKeyExistsResponseTest.php
@@ -6,6 +6,7 @@
use Common\Entity\CaseActor;
use Common\Service\Lpa\Response\ActivationKeyExists;
+use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
class ActivationKeyExistsResponseTest extends TestCase
@@ -30,10 +31,10 @@ public function it_allows_donor_name_and_lpa_type_to_be_set_and_get()
$dto = new ActivationKeyExists();
$dto->setDonor($donor);
$dto->setCaseSubtype('pfa');
- $dto->setDueDate('2021-12-06');
+ $dto->setDueDate(new DateTimeImmutable('2021-12-06'));
$this->assertEquals($donor, $dto->getDonor());
$this->assertEquals('pfa', $dto->getCaseSubtype());
- $this->assertEquals('2021-12-06', $dto->getDueDate());
+ $this->assertEquals('2021-12-06', $dto->getDueDate()->format('Y-m-d'));
}
}
diff --git a/service-front/app/test/CommonTest/Service/Lpa/Response/Parse/ParseActivationKeyExistsResponseTest.php b/service-front/app/test/CommonTest/Service/Lpa/Response/Parse/ParseActivationKeyExistsResponseTest.php
index 70b9747932..c33f852069 100644
--- a/service-front/app/test/CommonTest/Service/Lpa/Response/Parse/ParseActivationKeyExistsResponseTest.php
+++ b/service-front/app/test/CommonTest/Service/Lpa/Response/Parse/ParseActivationKeyExistsResponseTest.php
@@ -25,14 +25,15 @@ class ParseActivationKeyExistsResponseTest extends TestCase
public function setUp(): void
{
$this->response = [
- 'donor' => [
+ 'donor' => [
'uId' => '12345',
'firstname' => 'Example',
'middlenames' => 'Donor',
'surname' => 'Person',
],
- 'caseSubtype' => 'hw',
- 'activationKeyDueDate' => '2021-12-06',
+ 'caseSubtype' => 'hw',
+ 'activationKeyDueDate' => '2021-12-06T00:00:00+00:00',
+ 'activationKeyRequestedDate' => '2021-12-06T00:00:00+00:00',
];
$this->donor = new CaseActor();
@@ -57,7 +58,8 @@ public function it_creates_a_dto_from_array_data()
$this->assertInstanceOf(ActivationKeyExists::class, $result);
$this->assertEquals($this->donor, $result->getDonor());
$this->assertEquals('hw', $result->getCaseSubtype());
- $this->assertEquals('2021-12-06', $result->getDueDate());
+ $this->assertEquals('2021-12-06', $result->getDueDate()->format('Y-m-d'));
+ $this->assertEquals('2021-12-06', $result->getRequestedDate()->format('Y-m-d'));
}
/** @test */