Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d0dcd25
Rename TermsAndConditions entity URL accessor to document_url to pres…
Ioannis Sep 28, 2026
0729aef
Improve UI/UX for Terms and Conditions Review (CFM-501)
arlen Jun 15, 2026
ce38fbc
Move common code and language strings from TermsAgreer plugin to core…
arlen Jun 18, 2026
f32d86b
Further cleanup to Terms and Conditions (CFM-501)
arlen Jun 26, 2026
5eb95ff
Fix preview link to TandC Mostly Static Page (CFM-501)
arlen Jun 26, 2026
00e4f4d
Add JavaScript nonce to TandC script tag (CFM-501)
arlen Jun 28, 2026
082342e
Implement ajax UI for CO-level Terms and Conditions agreements (CFM-501)
arlen Jul 15, 2026
e41e2e0
Simplify TermsAndConditionsController::review() now that ajax is used…
arlen Aug 10, 2026
20d8802
Move ajax request check from maybeEnforceTAndCs() to beforeFilter() (…
arlen Aug 20, 2026
7e6ad79
Add inline-alert feature (CFM-501)
arlen Aug 27, 2026
4805e90
Improve T&C (and all) mobile rendering (CFM-501)
arlen Aug 30, 2026
3b62d0e
Ensure elements under #main can overflow when necessary (CFM-501)
arlen Sep 3, 2026
e0f62b8
Ensure hover state underlines ignore icons (CFM-501)
arlen Sep 4, 2026
f201720
Move TAndCEnrollmentModeEnum to core TAndCAgreementModeEnum (CFM-510)
arlen Sep 16, 2026
49258d9
Ensure TermsAndConditionsController includes vv_base_url (CFM-501)
arlen Sep 28, 2026
9edae67
Create separate API for recording T&C (CFM-553)
arlen Sep 29, 2026
1c24f70
Fix Mostly Static Page link from T&C index view (CFM-501)
arlen Sep 29, 2026
f0f5894
Use enumerations rather than direct values in TandC templates (CFM-501)
arlen Oct 1, 2026
2c4fdd4
Split recordTAndC into two separate actions, one for the Model Specif…
arlen Oct 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions app/config/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,11 @@
->setPatterns(['id' => '[0-9]+']);
$builder->post(
'/terms_and_conditions/record/{id}',
['controller' => 'ApiV2', 'action' => 'recordTAndC', 'model' => 'terms_and_conditions'])
->setPass(['id'])
// The standard API effectively acts as a CO Administrator (AR-ApiUser-2), and so we
// allow the client to assert both the subject and actor for T&C Agreement. This is NOT
// true for the AJAX API, below.
['controller' => 'ApiV2', 'action' => 'recordTAndC', 'model' => 'terms_and_conditions', 'trusted' => true])
->setPass(['id', 'trusted'])
->setPatterns(['id' => '[0-9]+']);
// These establish the usual CRUD options on all models:
$builder->delete(
Expand Down Expand Up @@ -142,9 +145,19 @@ function (RouteBuilder $builder) {
['controller' => 'ApiV2', 'action' => 'generateApiKey', 'model' => 'api_users'])
->setPass(['id'])
->setPatterns(['id' => '[0-9]+']);
$builder->post(
'/terms_and_conditions/record/{id}',
['controller' => 'ApiV2', 'action' => 'recordTAndC', 'model' => 'terms_and_conditions'])
->setPass(['id'])
->setPatterns(['id' => '[0-9]+']);
$builder->get(
'/people/pick',
['controller' => 'ApiV2', 'action' => 'pick', 'model' => 'people']);
$builder->post(
'/terms_and_conditions/record/{id}',
['controller' => 'ApiV2', 'action' => 'recordTAndC', 'model' => 'terms_and_conditions'])
->setPass(['id'])
->setPatterns(['id' => '[0-9]+']);
// These establish the usual CRUD options on all models:
$builder->delete(
'/{model}/{id}', ['controller' => 'ApiV2', 'action' => 'delete'])
Expand Down
23 changes: 16 additions & 7 deletions app/plugins/CoreEnroller/templates/element/emailVerifiers/list.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,23 @@
?>

<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; ?>
<div class="cell-first-content">
<?= $addr ?>
</div>
</td>
<td>
<div class="cell-label">
<?= __d('field', 'status') ?>
</div>
<div class="cell-content">
<?php if($verified): ?>
<?= __d('result', 'verified') ?>
<?php else: ?>
<span class="mr-1 badge bg-warning unverified"><?= __d('field', 'unverified')?></span>
<?= $button; ?>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
Expand Down
31 changes: 19 additions & 12 deletions app/plugins/OrcidSource/templates/element/preview.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,25 @@
?>

<table id="orcid-source-preview-table" class="index-table list-mode">
<thead>
<tr>
<th><?= __d('field', 'identifier') ?></th>
<th><?= __d('field', 'value') ?></th>
</tr>
</thead>
<thead>
<tr>
<th><?= __d('field', 'identifier') ?></th>
<th><?= __d('field', 'value') ?></th>
</tr>
</thead>

<tbody>
<tr>
<td><?= __d('orcid_source', 'information.orcid_source.identifier') ?></td>
<td><?= $vv_orcid ?></td>
</tr>
</tbody>
<tbody>
<tr>
<td>
<div class="cell-first-content">
<?= __d('orcid_source', 'information.orcid_source.identifier') ?>
</div>
</td>
<td>
<div class="cell-label"><?= __d('field', 'value') ?></div>
<div class="cell-content"><?= $vv_orcid ?></div>
</td>
</tr>
</tbody>
</table>

12 changes: 0 additions & 12 deletions app/plugins/TermsAgreer/resources/locales/en_US/terms_agreer.po
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,9 @@ msgstr "Ignore"
msgid "enumeration.TAndCEnrollmentModeEnum.IC"
msgstr "Implied Consent"

msgid "error.TAndCAgreement.missing"
msgstr "Did not receive agreement for \"{0}\" (T&C {1})"

msgid "field.AgreementCollectors.t_and_c_mode"
msgstr "Terms and Conditions Mode"

msgid "information.AgreementCollectors.external"
msgstr "These Terms and Conditions will be loaded in an external browser window. After review, you must return to this window and click \"Agree\" to continue."

msgid "information.AgreementCollectors.review"
msgstr "You must review and agree to these Terms and Conditions before continuing."

msgid "information.AgreementCollectors.review.tc"
msgstr "Review Terms & Conditions"

msgid "result.AgreementCollectors.ignored"
msgstr "Terms and Conditions collection disabled"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@

use App\Controller\StandardEnrollerController;
use App\Lib\Enum\SuspendableStatusEnum;
use App\Lib\Enum\TAndCAgreementModeEnum;
use Cake\ORM\TableRegistry;
use TermsAgreer\Lib\Enum\TAndCEnrollmentModeEnum;

class AgreementCollectorsController extends StandardEnrollerController {
protected array $paginate = [
Expand All @@ -58,7 +58,7 @@ public function dispatch(string $id) {

$cfg = $this->AgreementCollectors->get($id);

if($cfg->t_and_c_mode == TAndCEnrollmentModeEnum::Ignore) {
if($cfg->t_and_c_mode == TAndCAgreementModeEnum::Ignore) {
// If the Plugin is set to Ignore, we simply skip this step and move on.

return $this->finishStep(
Expand Down Expand Up @@ -119,7 +119,7 @@ public function dispatch(string $id) {
if(!isset($data[$key]) || $data[$key] != "1") {
$ok = false;

$this->Flash->error(__d('terms_agreer','error.TAndCAgreement.missing', [$tc->description, $tc->id]));
$this->Flash->error(__d('error','TermsAndConditions.agreement.missing', [$tc->description, $tc->id]));
}
}

Expand Down
170 changes: 3 additions & 167 deletions app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
/**
* COmanage Registry T&C Agreement Colectors Petition Fields
* COmanage Registry T&C Agreement Collectors Petition Fields
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
Expand All @@ -25,169 +25,5 @@
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

declare(strict_types = 1);

use \TermsAgreer\Lib\Enum\TAndCEnrollmentModeEnum;

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

// Make the Form fields editable
$this->Field->enableFormEditMode();
?>

<p><?= __d('terms_agreer', 'information.AgreementCollectors.review') ?></p>

<?php

// Begin the form
print $this->Form->create(null, [
'id' => 'agreement-form',
'type' => 'post'
]);


?>

<table>
<tr>
<th><?= __d('controller','TermsAndConditions',[99]) ?></th>
<th class="center"><?= __d('operation','review') ?></th>
<th><?= __d('operation','agreement') ?></th>
</tr>

<?php foreach($vv_tandc as $tc): ?>
<tr class="<?= !empty($tc->url) ? 'tc-url' : 'tc-msp' ?>">
<td>
<?= $tc['description'] ?>
</td>
<td class="center">
<button
data-tc-id="tc<?= $tc['id'] ?>"
class="btn btn-primary btn-sm tc-review-button"
type="button">
<?= __d('operation','review') ?>
</button>
<?php if(!empty($tc->url)): // We have a URL based T&C ?>
<button
data-tc-id="tc<?= $tc['id'] ?>"
id="tc<?= $tc['id'] ?>-window-launcher"
class="tc-window-launcher invisible"
data-tc-url="<?= $tc->url ?>"
type="button">
<?= __d('operation','review') . ' tc' . $tc['id'] ?>
</button>
<?php else: // We have a Mostly Static Page based T&C ?>
<?= $this->element('TermsAgreer.agreeDialog', ['vv_tc' => $tc]); ?>
<?php endif; ?>
</td>
<td>
<div class="form-check tc-agree">
<?=
$this->Form->checkbox(
'tc'.$tc['id'],
['id' => 'tc'.$tc['id'], 'class' => 'form-check-input tc-agree-checkbox']
) .
$this->Form->label(
'tc'.$tc['id'],
__d('operation','agree'),
['class' => 'form-check-label']
)
?>
</div>
</td>
</tr>
<?php endforeach; ?>

</table>


<script nonce="<?= $vv_js_nonce ?>">
// Iterate over our T&Cs to see if they're all checked.
function checkAgreements(mode) {
let allAgreed = true;
$('.tc-agree-checkbox').each(function() {
if(!$(this).prop('checked')) {
allAgreed = false;
if(mode == 'EC') {
// We're in Explicit Consent mode, so disable
// the current checkbox; its T&C must be reviewed.
$(this).prop('disabled', true);
}
}
});

// Enable / disable the "Continue" button.
if(allAgreed) {
$('.submit input[type="submit"]').prop('disabled', false);
} else {
$('.submit input[type="submit"]').prop('disabled', true);
}
}

// On page load: check agreement states and attach event handlers.
$(function() {
// Explicit Consent mode ("EC") will disable "I Agree" checkboxes until review.
const tcmode = '<?= $vv_tandc_mode ?>';

// Run on first load.
checkAgreements(tcmode);

// Handle "Review" button for URL-based terms and conditions.
$('tr.tc-url button.tc-review-button').click(function(e) {
e.preventDefault();
jsConfirmGeneric(
'<?= __d('terms_agreer', 'information.AgreementCollectors.external') ?>',
'',
$(this).attr('data-tc-id')+'-window-launcher',
'<?= __d('operation','continue') ?>',
'<?= __d('operation','cancel') ?>',
'<?= __d('terms_agreer','information.AgreementCollectors.review.tc') ?>'
);
});

// Launch the external window for URL-based terms and conditions
$('tr.tc-url button.tc-window-launcher').click(function(e) {
e.preventDefault();

// Calculate window size based on screen size so that we
// can handle mobile and to center the window.
const winWidth = window.outerWidth / 1.5;
const winHeight = window.outerHeight / 1.5;
const left = window.screenLeft + ((window.outerWidth - winWidth) / 2);
const top = window.screenTop + ((window.outerHeight - winHeight) / 2);

// Launch the T&C window with the external URL
let tandcExternalWindow = window.open(
$(this).attr('data-tc-url'),
'tandcExternalWindow',
'width=' + winWidth + ',height=' + winHeight + ',left=' + left + ',top=' + top +
',resizable=yes,scrollbars=yes,toolbar=no,menubar=no,location=no,status=no'
);

// Enable the T&C checkbox
$('#'+$(this).attr('data-tc-id')).prop('disabled', false);
});

// Handle "Review" button for Mostly Static Page-based terms and conditions.
// Clicking this will reveal the T&C agree dialog.
$('tr.tc-msp button.tc-review-button').click(function(e) {
e.preventDefault();
$('#'+$(this).attr('data-tc-id')+'-agree-dialog').modal('show');
});

// Handle "Agree" button click from MSP Dialog
$('.tc-agree-button').click(function(e) {
// Enable and check the T&C checkbox
$('#'+$(this).attr('data-tc-id'))
.prop('checked', true)
.prop('disabled', false)
.trigger('change');
});

// Check agreements when a checkbox is clicked.
// If all are checked, we'll enable "Continue".
$('.tc-agree-checkbox').change(function() {
checkAgreements(tcmode);
});
});
</script>
// This dispatch uses the same user interface as the core TermsAndConditions/tandcs.inc template.
include ROOT . DS . 'templates' . DS . 'TermsAndConditions' . DS . 'tandcs.inc';
6 changes: 6 additions & 0 deletions app/resources/locales/en_US/error.po
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,12 @@ msgstr "No outgoing SMTP Server configuration found"
msgid "TermsAndConditions.document.one"
msgstr "Exactly one of Mostly Static Page or URL must be specified"

msgid "TermsAndConditions.agreement.missing"
msgstr "Did not receive agreement for \"{0}\" (T&C {1})"

msgid "TermsAndConditions.agreement.failed"
msgstr "Failed to record agreement. Please try again or check with your administrator."

msgid "TermsAndConditions.revoke.none"
msgstr "No Agreements available to revoke"

Expand Down
11 changes: 10 additions & 1 deletion app/resources/locales/en_US/information.po
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,16 @@ msgid "table.list"
msgstr "{0} List"

msgid "TermsAndConditions.desc.old"
msgstr "{0} (Agreement is to an older definition)"
msgstr "Agreement is to an older definition"

msgid "tandc.review"
msgstr "You must review and agree to these Terms and Conditions before continuing."

msgid "tandc.review.dialog.title"
msgstr "Review Terms & Conditions"

msgid "tandc.review.external"
msgstr "These Terms and Conditions will be loaded in an external browser window. After review, you must return to this window and click \"Agree\" to continue."

msgid "ug.tasks.post"
msgstr "Executing post-database tasks for version {0}"
Expand Down
Loading