Skip to content

Commit

Permalink
Implement finalization tasks (CFM-31)
Browse files Browse the repository at this point in the history
  • Loading branch information
Benn Oshrin committed Nov 28, 2024
1 parent 4787fbd commit b72575f
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 30 deletions.
3 changes: 3 additions & 0 deletions app/resources/locales/en_US/enumeration.po
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,9 @@ msgstr "Duplicate"
msgid "PetitionStatusEnum.F"
msgstr "Finalized"

msgid "PetitionStatusEnum.FI"
msgstr "Finalizing"

msgid "PetitionStatusEnum.N"
msgstr "Denied"

Expand Down
3 changes: 3 additions & 0 deletions app/resources/locales/en_US/error.po
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@ msgstr "Enrollee Person not found in Petition {0}"
msgid "Petitions.enrollee_email"
msgstr "An Email Address for the Enrollee is required by this Enrollment Flow"

msgid "Petitions.status.finalizing"
msgstr "Petition {0} is not in Finalizing status"

msgid "Pipelines.plugin.notimpl"
msgstr "Pipeline plugin does not implement {0}"

Expand Down
68 changes: 61 additions & 7 deletions app/src/Controller/PetitionsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,18 +122,72 @@ public function continue(string $id) {
*/

public function finalize(string $id) {
// We split finalization up into several tasks, since we are constrained by browser and
// web server timeouts, and each step relies on plugins that might or might not behave
// as expected. We use an 'op' flag rather than separate actions in order to simplify
// the authorization logic (which is already custom for finalize).

// finalize: Tell all plugins to finalize
// assign: Assign Identifiers (if any)
// provision: Run provisioning, then set petition status to Finalized

$op = $this->requestParam('op');

$baseUrl = [
'controller' => 'petitions',
'action' => 'finalize',
$id
];

$token = $this->injectToken((int)$id);

if($token) {
$baseUrl['?']['token'] = $token;
}

if(!$op) {
$op = 'finalize';
}

try {
$this->Petitions->finalize((int)$id);
if($op == 'finalize') {
// Step 1
$this->Petitions->finalizePlugins((int)$id);

// Next operation is assign
$baseUrl['?']['op'] = 'assign';

return $this->redirect($baseUrl);
} elseif($op == 'assign') {
// Step 2
$this->Petitions->assignIdentifiers((int)$id);

// Next operation is provision
$baseUrl['?']['op'] = 'provision';

$this->Flash->success(__d('result', 'Petitions.finalized'));
return $this->redirect($baseUrl);
} elseif($op == 'provision') {
// Step 3
$this->Petitions->provision((int)$id);

// We only use the Redirect on Finalize URL (if specified) on success,
// since otherwise the Flash error won't render
// We're really done now, update the Petition status and redirect appropriately
// (This should be very fast and not require a separate page reload)
$this->Petitions->finalize((int)$id);

$petition = $this->Petitions->get((int)$id, ['contain' => ['EnrollmentFlows']]);
$this->Flash->success(__d('result', 'Petitions.finalized'));

// We only use the Redirect on Finalize URL (if specified) on success,
// since otherwise the Flash error won't render

$petition = $this->Petitions->get((int)$id, ['contain' => ['EnrollmentFlows']]);

if(!empty($petition->enrollment_flow->redirect_on_finalize)) {
return $this->redirect($petition->enrollment_flow->redirect_on_finalize);
}
} else {
// Unknown op, throw error

if(!empty($petition->enrollment_flow->redirect_on_finalize)) {
return $this->redirect($petition->enrollment_flow->redirect_on_finalize);
throw new \InvalidArgumentException(__d('error', 'unknown', $op));
}
}
catch(\Exception $e) {
Expand Down
1 change: 1 addition & 0 deletions app/src/Lib/Enum/PetitionStatusEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class PetitionStatusEnum extends StandardEnum {
const Duplicate = 'D2';
const Failed = 'XX';
const Finalized = 'F';
const Finalizing = 'FI';
const PendingAcceptance = 'PC';
const PendingApproval = 'PA';
const PendingVerification = 'PE';
Expand Down
21 changes: 21 additions & 0 deletions app/src/Lib/Enum/StandardEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,27 @@
use ReflectionClass;

class StandardEnum {
/**
* Get the localized text strings for the specified const.
*
* @since COmanage Registry v5.1.0
* @return string Localized const string
*/

public static function getLocalization(string $key): string {
// get_called_class() will return something like App\Lib\Enum\StatusEnum
// or CoreServer\Lib\Enum\RdbmsTypeEnum
$classBits = explode('\\', get_called_class(), 4);

if($classBits[0] == 'App') {
return __d('enumeration', $classBits[3].'.'.$key);
} else {
$pluginDomain = Inflector::underscore($classBits[0]);

return __d($pluginDomain, 'enumeration.'.$classBits[3].'.'.$key);
}
}

/**
* Get the localized text strings for the constants in the Enumeration.
*
Expand Down
9 changes: 7 additions & 2 deletions app/src/Lib/Traits/EnrollmentControllerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use Cake\Datasource\Exception\RecordNotFoundException;
use Cake\ORM\TableRegistry;
use \App\Lib\Enum\EnrollmentActorEnum;
use \App\Lib\Enum\PetitionStatusEnum;
use \App\Lib\Util\DeliveryUtilities;
use \App\Model\Entity\Petition;

Expand Down Expand Up @@ -339,7 +340,10 @@ protected function validateToken(Petition $petition): array|bool {

// We can't use $petition->useToken because we don't have a role

if(!empty($petition->token) && ($reqToken == $petition->token)) {
if(!empty($petition->token)
// Completed Petitions no longer accept tokens for authorization
&& !$petition->isComplete()
&& ($reqToken == $petition->token)) {
// Token match. The roles are whichever of petitioner and enrollee
// _don't_ have a Petition value.

Expand All @@ -351,7 +355,8 @@ protected function validateToken(Petition $petition): array|bool {
}

if(empty($petition->enrollee_identifier)
&& empty($petition->enrollee_person_id)) {
&& (empty($petition->enrollee_person_id)
|| $petition->status == PetitionStatusEnum::Finalizing)) {
$roles[] = EnrollmentActorEnum::Enrollee;
}

Expand Down
6 changes: 5 additions & 1 deletion app/src/Model/Entity/Petition.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public function isComplete(): bool {
PetitionStatusEnum::Duplicate,
PetitionStatusEnum::Failed,
PetitionStatusEnum::Finalized
// A Finalizing Petition is NOT complete
// PetitionStatusEnum::Finalizing
]);
}

Expand Down Expand Up @@ -105,7 +107,9 @@ public function useToken(string $actorRole): bool {
||
($actorRole == EnrollmentActorEnum::Enrollee
&& empty($this->enrollee_identifier)
&& empty($this->enrollee_person_id))) {
// Once finalization begins, we'll have an enrollee_person_id but they
// most likel won't be able to authenticate
&& (empty($this->enrollee_person_id) || $this->status == PetitionStatusEnum::Finalizing))) {
// Note presence of a token is not an indicator as to whether a token should be used
return true;
}
Expand Down
Loading

0 comments on commit b72575f

Please sign in to comment.