Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files Browse the repository at this point in the history
Resend Confirmation Code
Ioannis committed Mar 3, 2025
1 parent 435fd31 commit 4847ed8
Showing 13 changed files with 683 additions and 139 deletions.
53 changes: 53 additions & 0 deletions app/plugins/CoreEnroller/config/routes.php
@@ -0,0 +1,53 @@
<?php
/**
* ApiSource plugin specific routes.
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry-plugins
* @since COmanage Registry v5.0.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

use Cake\Routing\Route\DashedRoute;

// In general, we're probably trying to set up API routes if we're doing
// something within a plugin, but not necessarily. API routes are a subset
// of Cake routes, so either can be specified here.

// Core Enroller


$routes->plugin(
'CoreEnroller',
['path' => '/core-enroller/'],
function ($routes) {
$routes->setRouteClass(DashedRoute::class);

$routes->get(
'email-verifiers/resend',
[
'plugin' => 'CoreEnroller',
'controller' => 'EmailVerifiers',
'action' => 'resend',
])
->setPass(['id'])
->setPatterns(['id' => '[0-9]+']);
}
);
22 changes: 20 additions & 2 deletions app/plugins/CoreEnroller/resources/locales/en_US/core_enroller.po
@@ -98,7 +98,22 @@ msgid "information.EmailVerifiers.A"
msgstr "The following email addresses have been found in this Petition. You must verify all of them in order to proceed to the next Enrollment Step."

msgid "information.EmailVerifiers.code_sent"
msgstr "A code has been sent to {0}. Please enter it below. You may also request a new code if you haven't received it after a few minutes, or cancel verification and return to the list of available Email Addresses."
msgstr "A code has been sent to <strong>{0}</strong>. Please enter it below. You may also request a new code if you haven't received it after a few minutes, or cancel verification and return to the list of available Email Addresses."

msgid "information.EmailVerifiers.resend-pre-text"
msgstr "Didn't receive the code?"

msgid "information.EmailVerifiers.resend"
msgstr "Resend"

msgid "information.EmailVerifiers.sending"
msgstr "Sending"

msgid "information.EmailVerifiers.success"
msgstr "New Code Submitted!"

msgid "information.EmailVerifiers.abort"
msgstr "Abort"

msgid "field.AttributeCollectors.valid_through.default.after.desc"
msgstr "Days After Finalization"
@@ -257,4 +272,7 @@ msgid "result.InvitationAccepters.declined"
msgstr "Invitation Declined at {0}"

msgid "result.InvitationAccepters.none"
msgstr "No response to invitation yet"
msgstr "No response to invitation yet"

msgid "op.EmailVerifiers.verify"
msgstr "Verify Email"
@@ -29,11 +29,13 @@

namespace CoreEnroller\Controller;

use Cake\ORM\TableRegistry;
use App\Controller\StandardEnrollerController;
use App\Lib\Enum\PetitionStatusEnum;
use App\Lib\Util\StringUtilities;
use Cake\Http\Exception\BadRequestException;
use Cake\ORM\TableRegistry;
use CoreEnroller\Lib\Enum\VerificationModeEnum;
use \App\Lib\Enum\HttpStatusCodesEnum;

class EmailVerifiersController extends StandardEnrollerController {
public $paginate = [
@@ -60,9 +62,58 @@ public function beforeRender(\Cake\Event\EventInterface $event) {
$this->set('vv_bc_parent_primarykey', $this->EmailVerifiers->EnrollmentFlowSteps->getPrimaryKey());
}

if ($this->getRequest()->getQuery("op") == "verify" || $this->getRequest()->getQuery("op") == "index") {
// This will suppress the default behavior. By default, we print the submit button in the
// unorderedList.php element. But for the verify view we want to override and customize
$this->set('suppress_submit', true);
}

return parent::beforeRender($event);
}

/**
* Resend the email verification request.
*
* @param string $id Email Verifier ID
* @throws BadRequestException If the request is not AJAX
* @throws \InvalidArgumentException If required query parameters are missing
* @return void
* @since COmanage Registry v5.1.0
*/
public function resend($id)
{

$this->viewBuilder()->setClassName('Json');

if (!$this->getRequest()->is('ajax')) {
throw new BadRequestException(__('Bad Request'));
}

if (!$this->getRequest()->getQuery('petition_id') || !$this->getRequest()->getQuery('m')) {
throw new \InvalidArgumentException(__('error', 'invalid.request'));
}

// Generate a Verification request and send it
$Petitions = TableRegistry::getTableLocator()->get('Petitions');
$petition = $Petitions->get($this->getRequest()->getQuery('petition_id'));
$cfg = $this->EmailVerifiers->get($id);
$mail = StringUtilities::urlbase64decode($this->requestParam('m'));
$status = $this->EmailVerifiers->sendVerificationRequest($cfg, $petition, $mail, true);

if ($status) {
return $this->response
->withType('application/json')
->withStatus(HttpStatusCodesEnum::HTTP_OK)
->withStringBody(json_encode(['status' => 'ok']));
}


return $this->response
->withType('application/json')
->withStatus(HttpStatusCodesEnum::HTTP_INTERNAL_SERVER_ERROR)
->withStringBody(json_encode(['status' => 'failed']));
}

/**
* Dispatch an Enrollment Flow Step.
*
55 changes: 36 additions & 19 deletions app/plugins/CoreEnroller/src/Model/Table/EmailVerifiersTable.php
@@ -85,7 +85,7 @@ public function initialize(array $config): void {

$this->setPrimaryLink('enrollment_flow_step_id');
$this->setRequiresCO(true);
$this->setAllowLookupPrimaryLink(['dispatch', 'display']);
$this->setAllowLookupPrimaryLink(['dispatch', 'display', 'resend']);

// All the tabs share the same configuration in the ModelTable file
$this->setTabsConfig(
@@ -112,6 +112,14 @@ public function initialize(array $config): void {
'type' => 'select',
'model' => 'MessageTemplates',
'where' => ['context' => \App\Lib\Enum\MessageTemplateContextEnum::Verification]
],
'cosettings' => [
'type' => 'auxiliary',
'model' => 'CoSettings'
],
'types' => [
'type' => 'auxiliary',
'model' => 'Types'
]
]);

@@ -122,6 +130,7 @@ public function initialize(array $config): void {
'dispatch' => true,
'display' => true,
'edit' => ['platformAdmin', 'coAdmin'],
'resend' => true,
'view' => ['platformAdmin', 'coAdmin']
],
// Actions that operate over a table (ie: do not require an $id)
@@ -412,8 +421,10 @@ public function prepare(
public function sendVerificationRequest(
EmailVerifier $emailVerifier,
Petition $petition,
string $mail
) {
string $mail,
bool $resend = false,
): bool
{
// First check if there is already an existing Petition Verification.
// If so, use that to get the existing Verification.

@@ -427,21 +438,7 @@ public function sendVerificationRequest(
])
->first();

if(!empty($pVerification)) {
// Request a new code

$this->llog('debug', "Sending replacement verification code to $mail for Petition " . $petition->id);

$verificationId = $Verifications->requestCodeForPetition(
$petition->id,
$mail,
$emailVerifier->message_template_id,
$emailVerifier->request_validity,
$pVerification->verification_id
);

// There's nothing to update in the Petition Verification
} else {
if (empty($pVerification)) {
// Request Verification and create an associated Petition Verification

$this->llog('debug', "Sending verification code to $mail for Petition " . $petition->id);
@@ -458,8 +455,28 @@ public function sendVerificationRequest(
'petition_id' => $petition->id,
'mail' => $mail,
'verification_id' => $verificationId
]));
]));
return true;
}

if ($resend) {
// Request a new code

$this->llog('debug', "Sending replacement verification code to $mail for Petition " . $petition->id);

$verificationId = $Verifications->requestCodeForPetition(
$petition->id,
$mail,
$emailVerifier->message_template_id,
$emailVerifier->request_validity,
$pVerification->verification_id
);
// There's nothing to update in the Petition Verification

return true;
}

return false;
}

/**
130 changes: 15 additions & 115 deletions app/plugins/CoreEnroller/templates/EmailVerifiers/dispatch.inc
@@ -27,121 +27,21 @@

declare(strict_types = 1);

use CoreEnroller\Lib\Enum\VerificationModeEnum;
use App\Lib\Util\StringUtilities;

print $this->element('flash', []);

// This view is intended to work with dispatch
if($vv_action == 'dispatch') {
if($vv_op == 'index') {
// Render the list of known email addresses and their verification statuses.
// The configuration drives how many email addresses are required to complete this step.

print '<p>';

if($vv_all_done) {
print __d('core_enroller', 'information.EmailVerifiers.done');
} else {
switch($vv_config->mode) {
case VerificationModeEnum::All:
print __d('core_enroller', 'information.EmailVerifiers.A');
break;
case VerificationModeEnum::None:
print __d('core_enroller', 'information.EmailVerifiers.0');
break;
case VerificationModeEnum::One:
if($vv_minimum_met) {
print __d('core_enroller', 'information.EmailVerifiers.1.met');
} else {
print __d('core_enroller', 'information.EmailVerifiers.1.none');
}
break;
}
}

print '</p>';

print '
<table id="verifications-table" class="index-table list-mode">
<thead>
<tr>
<th>' . __d('controller', 'EmailAddresses', [1]) . '</th>
<th>' . __d('field', 'status') . '</th>
</tr>
</thead>
</tbody>
';

foreach(array_keys($vv_email_addresses) as $addr) {
$verified = isset($vv_verified_addresses[$addr]) && $vv_verified_addresses[$addr];

$button = "";

if(!$verified) {
// We're already in a form here, so we need to use a GET URL to not mess things up.
// This also means we need to manually insert the token and petition ID, which is
// a bit duplicative with templates/Standard/dispatch.php

$url = [
'plugin' => 'CoreEnroller',
'controller' => 'email_verifiers',
'action' => 'dispatch',
$vv_config->id,
'?' => [
'op' => 'verify',
'petition_id' => $vv_petition->id,
// We base64 encode the address partly to not have bare email addresses in URLs
// and partly to avoid special characters (like dots) messing up the URL
'm' => StringUtilities::urlbase64encode($addr)
]
];

if(isset($vv_token_ok) && $vv_token_ok && !empty($vv_petition->token)) {
$url['?']['token'] = $vv_petition->token;
}

$button = $this->Html->link(__d('operation', 'verify'), $url);
}

print '
<tr>
<td>' . $addr . '</td>
<td>' . __d('result', ($verified ? 'verified' : 'verified.not')) . $button . '</td>
</tr>
';
}

print '
</tbody>
</table>
';

if($vv_minimum_met) {
$this->Field->enableFormEditMode();

print $this->Form->hidden('op', ['default' => 'finish']);
}
} elseif($vv_op == 'verify') {
if(!empty($vv_verify_address)) {
// Render a form prompting for the code that was sent to the Enrollee

print __d('core_enroller', 'information.EmailVerifiers.code_sent', [$vv_verify_address]);

$this->Field->enableFormEditMode();

print $this->Form->hidden('op', ['default' => 'verify']);
print $this->Form->hidden('co_id', ['default' => $vv_cur_co->id]);
print $this->Form->hidden('m', ['default' => StringUtilities::urlbase64encode($vv_verify_address)]);

print $this->element('form/listItem', [
'arguments' => [
'fieldName' => 'code',
'fieldLabel' => "Code", //__d('field', 'mail')
'fieldOptions' => [
'required' => true
]
]]);
}
}
}
if ($vv_action !== 'dispatch') {
return;
}

if ($vv_op == 'index') {
$this->set('vv_include_cancel', false);
$this->set('vv_submit_button_label', __d('operation', 'finish'));
print $this->element('CoreEnroller.emailVerifiers/list');
} elseif ($vv_op == 'verify') {
$this->set('vv_submit_button_label', __d('core_enroller', 'op.EmailVerifiers.verify'));
$this->set('vv_include_cancel', true);
print $this->element('CoreEnroller.emailVerifiers/verify');
} else {
print __d('error', 'something.went.wrong');
}
127 changes: 127 additions & 0 deletions app/plugins/CoreEnroller/templates/element/emailVerifiers/list.php
@@ -0,0 +1,127 @@
<?php
/**
* COmanage Registry Email Verifiers Petition Fields
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry
* @since COmanage Registry v5.1.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

declare(strict_types = 1);

use CoreEnroller\Lib\Enum\VerificationModeEnum;
use App\Lib\Util\StringUtilities;

// Render the list of known email addresses and their verification statuses.
// The configuration drives how many email addresses are required to complete this step.

$title = '';
if($vv_all_done) {
$title = __d('core_enroller', 'information.EmailVerifiers.done');
} else {
$title = match ($vv_config->mode) {
VerificationModeEnum::All => __d('core_enroller', 'information.EmailVerifiers.A'),
VerificationModeEnum::None => __d('core_enroller', 'information.EmailVerifiers.0'),
VerificationModeEnum::One => $vv_minimum_met
? __d('core_enroller', 'information.EmailVerifiers.1.met')
: __d('core_enroller', 'information.EmailVerifiers.1.none'),
default => 'Unknown Verification Mode' // Optional fallback for unexpected cases
};

}

?>
<p><?= $title ?></p>
<table id="verifications-table" class="index-table list-mode">
<thead>
<tr>
<th><?= __d('controller', 'EmailAddresses', [1]) ?></th>
<th><?= __d('field', 'status') ?></th>
</tr>
</thead>
</tbody>

<?php foreach(array_keys($vv_email_addresses) as $addr): ?>
<?php
$verified = isset($vv_verified_addresses[$addr]) && $vv_verified_addresses[$addr];

$button = "";

if(!$verified) {
// We're already in a form here, so we need to use a GET URL to not mess things up.
// This also means we need to manually insert the token and petition ID, which is
// a bit duplicative with templates/Standard/dispatch.php

$url = [
'plugin' => 'CoreEnroller',
'controller' => 'email_verifiers',
'action' => 'dispatch',
$vv_config->id,
'?' => [
'op' => 'verify',
'petition_id' => $vv_petition->id,
// We base64 encode the address partly to not have bare email addresses in URLs
// and partly to avoid special characters (like dots) messing up the URL
'm' => StringUtilities::urlbase64encode($addr)
]
];

if(isset($vv_token_ok) && $vv_token_ok && !empty($vv_petition->token)) {
$url['?']['token'] = $vv_petition->token;
}

$materialIcon = '<em class="material-symbols" aria-hidden="true">check</em>';
$button = $this->Html->link(
$materialIcon . ' ' . __d('operation', 'verify'),
$url,
[
'class' => 'btn btn-sm btn-tertiary float-end',
'escape' => false,
]
);
}
?>

<tr>
<td><?= $addr ?></td>
<td>
<?php if($verified): ?>
<?= __d('result', 'verified') ?>
<?php else: ?>
<span class="mr-1 badge bg-warning unverified"><?= __d('field', 'unverified')?></span>
<?= $button; ?>
<?php endif; ?>
</td>
</tr>
</tbody>
</table>

<?php

if($vv_minimum_met || count($vv_email_addresses) === 0) {
$this->Field->enableFormEditMode();

print $this->Form->hidden('op', ['default' => 'finish']);

print $this->element('form/submit', ['label' => $vv_submit_button_label]);
}
?>
<?php endforeach; ?>
@@ -0,0 +1,185 @@
<?php
/**
* COmanage Registry Resend Confirmation Link Vue.js component
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry
* @since COmanage Registry v5.1.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/


declare(strict_types = 1);

/*
* Required:
* - $htmlId
* - $containerClasses
* - $vv_config
* - $m (encoded email)
* - $petitionId
* */

// Load my helper functions
$vueHelper = $this->loadHelper('Vue');

$relativeUrl = "core-enroller/email-verifiers/resend/$vv_config->id"
. '?'
. "petition_id=$petitionId"
. "&m=$emailAddress"

?>

<script type="module">
import MiniLoader from "<?= $this->Url->script('comanage/components/common/mini-loader.js')?>?time=<?= time() ?>";

const app = Vue.createApp({
data() {
return {
error: '',
message: '', // Message to show (success or error)
loading: false, // Loading state for the fetch request
controller: null, // AbortController instance,
txt: JSON.parse('<?= json_encode($vueHelper->locales()) ?>'),
app: {
coId: <?= $vv_cur_co->id ?>,
types: <?= json_encode($types) ?>,
cosettings: <?= json_encode($cosettings) ?>
},
api: {
webroot: '<?= $this->request->getAttribute('webroot') ?>',
// co_id query parameter is required since it is the People's primary link
resendCode: `<?= $this->request->getAttribute('webroot') . $relativeUrl ?>`
},
txtPlugin: {
'resendPreText': "<?= __d('core_enroller','information.EmailVerifiers.resend-pre-text') ?>",
'resend': '<?= __d('core_enroller','information.EmailVerifiers.resend') ?>',
'abort': '<?= __d('core_enroller','information.EmailVerifiers.abort') ?>',
'sending': '<?= __d('core_enroller','information.EmailVerifiers.sending') ?>',
'success': '<?= __d('core_enroller','information.EmailVerifiers.success') ?>',
}
}
},
components: {
MiniLoader
},
methods: {
async fetchData() {
this.message = ""; // Clear any previous messages/errors
this.error = '';
this.loading = true; // Set loading state to true

// Create a new AbortController instance
this.controller = new AbortController();

const apiUrl = this.api.resendCode; // Replace this URL with your API endpoint

let request_init = {
headers: new Headers({
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json',
}),
method: 'GET',
signal: this.controller.signal,
}
// AJAX Request
let requestObj = new Request(apiUrl, request_init);

try {
// Perform the fetch request with signal
const response = await fetch(requestObj);

// Check if the response is successful
if (!response.ok) {
throw new Error(`Error: ${response.status} - ${response.statusText}`);
}

const data = await response.json();
this.message = this.txtPlugin.success;
} catch (error) {
// Handle fetch errors
if (error.name === "AbortError") {
// If fetch was aborted
this.error = "Request aborted.";
} else {
this.error = `Request Failed: ${error.message}`;
}
} finally {
this.loading = false; // Reset the loading state
}
},
abortRequest() {
// Abort the ongoing fetch request, if any
if (this.controller) {
this.controller.abort();
this.controller = null;
}
},
},
computed: {
getMiniLoaderClasses: function() {
return "co-loading-mini-container d-inline ms-1"
},
getAlertClasses: function() {
if (this.error) {
return "alert alert-danger alert-dismissible co-alert"
} else if (this.message) {
return "alert alert-success alert-dismissible co-alert"
} else {
return "alert alert-info alert-dismissible co-alert"
}
}
},
template: `
<!-- Display Success or Error Message -->
<div v-if="message || error" class="alert-container mb-3" id="flash-messages">
<div :class="getAlertClasses" role="alert">
<div class="alert-body d-flex align-items-center">
<span class="alert-title d-flex align-items-center">
<span v-if="error" class="material-symbols-outlined alert-icon">report_problem</span>
<span v-if="message" class="material-symbols-outlined alert-icon">check_circle</span>
</span>
<span v-if="error" class="alert-message">{{ error }}</span>
<span v-if="message" class="alert-message">{{ message }}</span>
<span class="alert-button">
<button type="button" class="btn-close nospin" data-bs-dismiss="alert" aria-label="Close"></button>
</span>
</div>
</div>
</div>
<div v-if="!loading">
<span class="me-1">{{ txtPlugin.resendPreText }}</span>
<a href="#" class="spin" @click="fetchData">{{ txtPlugin.resend }}</a>
</div>
<div v-if="loading">
<span class="me-1">{{ txtPlugin.sending }}</span>
<MiniLoader :isLoading="loading" :classes="getMiniLoaderClasses"/>
</div>
`
});


app.use(primevue.config.default, {unstyled: true});

// Mount the component and provide a global reference for this app instance.
window.<?= str_replace('-', '', $htmlId) ?> = app.mount("#<?= $htmlId ?>-container");
</script>

<div id="<?= $htmlId ?>-container" class="<?= $containerClasses ?>"></div>
@@ -0,0 +1,91 @@
<?php
/**
* COmanage Registry Verify Email
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry
* @since COmanage Registry v5.1.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

declare(strict_types = 1);

use App\Lib\Util\StringUtilities;

if(empty($vv_verify_address)) {
print __d('core_enroller', 'information.EmailVerifiers.done');
return;
}

// Render a form prompting for the code that was sent to the Enrollee

print __d('core_enroller', 'information.EmailVerifiers.code_sent', [$vv_verify_address]);

$this->Field->enableFormEditMode();

$m = StringUtilities::urlbase64encode($vv_verify_address);

print $this->Form->hidden('op', ['default' => 'verify']);
print $this->Form->hidden('co_id', ['default' => $vv_cur_co->id]);
print $this->Form->hidden('m', ['default' => $m]);

print $this->element('form/listItem', [
'arguments' => [
'fieldName' => 'code',
'fieldLabel' => "Code", //__d('field', 'mail')
'fieldOptions' => [
'required' => true
]
]]);

$resendLink = $this->Html->link(
__d('core_enroller', 'Resend'),
['controller' => 'email_verifiers', 'action' => 'resend', $vv_verify_address],
['class' => 'text-primary']
);

?>
<?php if($this->Field->isEditable()): ?>
<li class="fields-submit">
<div class="field">
<div class="field-name">
<span class="required">* <?= __d('field', 'required') ?></span>
</div>
<div class="field-info">
<?= $this->Form->submit($vv_submit_button_label) ?>
<?php if(!empty($vv_include_cancel)): ?>
<button type="button" onclick="history.back()" class="btn btn-cancel">
<?= __d('operation','cancel') ?>
</button>
<?php endif; ?>
</div>
</div>
</li>
<?php endif; ?>

<!-- Resend Link - SPA module -->
<?= $this->element('CoreEnroller.emailVerifiers/resendLinkSpa', [
'htmlId' => 'resend-link',
'petitionId' => $vv_petition->id,
'containerClasses' => 'border-top border-1 pt-2 text-center text-muted',
'emailAddress' => $m,
'vv_config' => $vv_config,
]) ?>

6 changes: 6 additions & 0 deletions app/resources/locales/en_US/error.po
@@ -214,6 +214,9 @@ msgstr "{0} must be provided"
msgid "invalid"
msgstr "Invalid value \"{0}\""

msgid "invalid.request"
msgstr "Invalid Request"

msgid "javascript.copy"
msgstr "Could not copy."

@@ -364,6 +367,9 @@ msgstr "No type defined for table \"{0}\" column \"{1}\""
msgid "schema.parse"
msgstr "Failed to parse file {0}"

msgid "something.went.wrong"
msgstr "Ooops... Something went wrong."

msgid "setup.co.comanage"
msgstr "Failed to setup COmanage CO"

3 changes: 3 additions & 0 deletions app/resources/locales/en_US/operation.po
@@ -180,6 +180,9 @@ msgstr "Sync Record to CO"
msgid "filter"
msgstr "Filter"

msgid "finish"
msgstr "Finish"

msgid "first"
msgstr "First"

2 changes: 1 addition & 1 deletion app/src/Command/TransmogrifyCommand.php
@@ -620,7 +620,7 @@ public function execute(Arguments $args, ConsoleIo $io) {
$err = 0;

// Loop over each row from the inbound table.
while($row = $stmt->fetch()) {
while($row = $stmt->fetchAssociative()) {
if(!empty($row[ $this->tables[$t]['displayField'] ])) {
$io->verbose("$t " . $row[ $this->tables[$t]['displayField'] ]);
}
87 changes: 87 additions & 0 deletions app/src/Lib/Enum/HttpStatusCodesEnum.php
@@ -0,0 +1,87 @@
<?php

/**
* COmanage Registry HTTP Statis Codes Enum
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry
* @since COmanage Registry v5.1.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

declare(strict_types = 1);

namespace App\Lib\Enum;

// XXX [REF]https://httpstatuses.com
class HttpStatusCodesEnum extends StandardEnum
{
// [Informational 1xx]
const HTTP_CONTINUE = 100;
const HTTP_SWITCHING_PROTOCOLS = 101;

// [Successful 2xx]
const HTTP_OK = 200;
const HTTP_CREATED = 201;
const HTTP_ACCEPTED = 202;
const HTTP_NONAUTHORITATIVE_INFORMATION = 203;
const HTTP_NO_CONTENT = 204;
const HTTP_RESET_CONTENT = 205;
const HTTP_PARTIAL_CONTENT = 206;

// [Redirection 3xx]
const HTTP_MULTIPLE_CHOICES = 300;
const HTTP_MOVED_PERMANENTLY = 301;
const HTTP_FOUND = 302;
const HTTP_SEE_OTHER = 303;
const HTTP_NOT_MODIFIED = 304;
const HTTP_USE_PROXY = 305;
const HTTP_UNUSED = 306;
const HTTP_TEMPORARY_REDIRECT = 307;

// [Client Error 4xx]
const errorCodesBeginAt = 400;
const HTTP_BAD_REQUEST = 400;
const HTTP_UNAUTHORIZED = 401;
const HTTP_PAYMENT_REQUIRED = 402;
const HTTP_FORBIDDEN = 403;
const HTTP_NOT_FOUND = 404;
const HTTP_METHOD_NOT_ALLOWED = 405;
const HTTP_NOT_ACCEPTABLE = 406;
const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
const HTTP_REQUEST_TIMEOUT = 408;
const HTTP_CONFLICT = 409;
const HTTP_GONE = 410;
const HTTP_LENGTH_REQUIRED = 411;
const HTTP_PRECONDITION_FAILED = 412;
const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
const HTTP_REQUEST_URI_TOO_LONG = 414;
const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
const HTTP_EXPECTATION_FAILED = 417;

// [Server Error 5xx]
const HTTP_INTERNAL_SERVER_ERROR = 500;
const HTTP_NOT_IMPLEMENTED = 501;
const HTTP_BAD_GATEWAY = 502;
const HTTP_SERVICE_UNAVAILABLE = 503;
const HTTP_GATEWAY_TIMEOUT = 504;
const HTTP_VERSION_NOT_SUPPORTED = 505;
}
8 changes: 7 additions & 1 deletion app/templates/Standard/dispatch.php
@@ -31,6 +31,10 @@
$modelsName = $this->name;
// $tablename = models
$tableName = \Cake\Utility\Inflector::tableize(\Cake\Utility\Inflector::singularize($this->name));
// Populate the AutoViewVars. These are the same we do for the EnrollmentAttributes configuration view
$this->Petition->populateAutoViewVars();
// We just populated the AutoViewVars. Add them to the current context
extract($this->viewVars);

// $vv_template_path will be set for plugins
$templatePath = $vv_template_path ?? ROOT . DS . 'templates' . DS . $modelsName;
@@ -76,7 +80,9 @@
// Set the Include file name
// Will be used by the unorderedList element below
$this->set('vv_fields_inc', 'dispatch.inc');
$this->set('vv_submit_button_label', __d('operation', 'continue'));
if (empty($vv_submit_button_label)) {
$this->set('vv_submit_button_label', __d('operation', 'continue'));
}

// By default, the form will POST to the current controller
// Note we need to open the form for view so Cake will autopopulate values

0 comments on commit 4847ed8

Please sign in to comment.