diff --git a/app/plugins/TermsAgreer/resources/locales/en_US/terms_agreer.po b/app/plugins/TermsAgreer/resources/locales/en_US/terms_agreer.po index b2c8b8cda..35da383df 100644 --- a/app/plugins/TermsAgreer/resources/locales/en_US/terms_agreer.po +++ b/app/plugins/TermsAgreer/resources/locales/en_US/terms_agreer.po @@ -43,15 +43,6 @@ 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" diff --git a/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc b/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc index 159fe00ee..594b74e61 100644 --- a/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc +++ b/app/plugins/TermsAgreer/templates/AgreementCollectors/dispatch.inc @@ -1,6 +1,7 @@ element('flash', []); - -// Make the Form fields editable -$this->Field->enableFormEditMode(); -?> - -

- -Form->create(null, [ - 'id' => 'agreement-form', - 'type' => 'post' -]); - - -?> - - - - - - - - - - - - - - - - -
- - - - url)): // We have a URL based T&C ?> - - - element('TermsAgreer.agreeDialog', ['vv_tc' => $tc]); ?> - - -
- 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'] - ) - ?> -
-
- - - \ No newline at end of file +// This dispatch uses the same user interface as the core TermsAndConditions/tandcs.inc template. +include ROOT . DS . 'templates' . DS . 'TermsAndConditions' . DS . 'tandcs.inc'; \ No newline at end of file diff --git a/app/resources/locales/en_US/information.po b/app/resources/locales/en_US/information.po index 6f75d1a43..f9350f928 100644 --- a/app/resources/locales/en_US/information.po +++ b/app/resources/locales/en_US/information.po @@ -183,6 +183,15 @@ msgstr "Report for " msgid "table.list" msgstr "{0} List" +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}" diff --git a/app/src/Controller/TermsAndConditionsController.php b/app/src/Controller/TermsAndConditionsController.php index c7f49501b..19bcaaf41 100644 --- a/app/src/Controller/TermsAndConditionsController.php +++ b/app/src/Controller/TermsAndConditionsController.php @@ -35,6 +35,8 @@ use Cake\Utility\Hash; use \App\Lib\Enum\ProvisioningContextEnum; use \App\Lib\Enum\TAndCStatusEnum; +use TermsAgreer\TermsAgreerPlugin; +use TermsAgreer\Lib\Enum\TAndCEnrollmentModeEnum; class TermsAndConditionsController extends StandardController { public array $paginate = [ @@ -146,8 +148,8 @@ public function review() { // Before we get started, see if a return parameter was requested, and if so if it is permitted. // If so, we'll override any current return URL. We check the return URL here rather than when // we're done because URLs stored by AppController are not subject to the allow list check. - - $returnUrl = $this->request->getQuery('return'); + $request = $this->getRequest(); + $returnUrl = $request->getQuery('return'); if(!empty($returnUrl)) { $returnUrl = base64_decode($returnUrl); @@ -160,7 +162,7 @@ public function review() { if(preg_match($u, $returnUrl)) { // The requested URL is permitted, so store it in the session, potentially overriding // the original return URL - $this->request->getSession()->write('TAndC.return', $returnUrl); + $request->getSession()->write('TAndC.return', $returnUrl); break; } } @@ -181,23 +183,66 @@ public function review() { $status = $this->TermsAndConditions->status((int)$personId); - // If there is nothing left to do, redirect to the original request - $done = true; + if($request->is('post')) { + // Walk the set of $status['tandc']s and look for an agreement in the POST data. + $data = $request->getData(); + + $ok = true; + + foreach($status as $s) { + // The post data is keyed on the string "tc" appended to the T&C id, + // and the expected value is "1". + + $key = "tc".$s['tandc']->id; + + if(!isset($data[$key]) || $data[$key] != "1") { + $ok = false; - foreach($status as $s) { - if($s['status'] != TAndCStatusEnum::Agreed) { - $done = false; - break; + $this->Flash->error(__d('terms_agreer','error.TAndCAgreement.missing', [$s['tandc']->description, $tc->id])); + } } - } - if($done) { - return $this->redirect($this->request->getSession()->read('TAndC.return')); + if($ok) { + foreach($status as $s) { + $this->log("TCiD: " . $s['tandc']->id); + try { + $this->TermsAndConditions->TAndCAgreements->record( + termsAndConditionsId: (int)$s['tandc']->id, + personId: $personId, + actorPersonId: $personId, + identifier: $this->getRequest()->getSession()->read('Auth.external.user') + ); + + // Request provisioning on success + + $this->llog('trace', "Requesting provisioning after T&C Agreement for Person " . $personId); + + $People = TableRegistry::getTableLocator()->get('People'); + + $People->requestProvisioning( + id: (int)$personId, + context: ProvisioningContextEnum::Automatic + ); + } catch(\Exception $e) { + $this->Flash->error($e->getMessage()); + return $this->generateRedirect(null); + } + } + + // Set the flash message + $this->Flash->success(__d('result', 'TermsAndConditions.recorded')); + + // redirect to the original request + return $this->redirect($request->getSession()->read('TAndC.return')); + } } $this->set('vv_tandc_statuses', $status); $this->set('vv_person_id', (int)$personId); + // The default mode for CO and platform wide T&Cs is "Explicit Consent" + $this->set('vv_tandc_mode', TAndCEnrollmentModeEnum::ExplicitConsent); + $this->set('vv_title', __d('controller', 'TermsAndConditions', 99)); } diff --git a/app/src/Model/Table/TermsAndConditionsTable.php b/app/src/Model/Table/TermsAndConditionsTable.php index c5e334a11..9f6a8ec2a 100644 --- a/app/src/Model/Table/TermsAndConditionsTable.php +++ b/app/src/Model/Table/TermsAndConditionsTable.php @@ -78,6 +78,7 @@ public function initialize(array $config): void { $this->setAllowLookupPrimaryLink(['agree', 'proxy', 'revoke']); $this->setAllowLookupRelatedPrimaryLink(['status' => ['person_id']]); $this->setAllowUnkeyedPrimaryLink(['review']); + $this->setAllowEmptyPrimaryLink(['review']); $this->setIndexContains([ 'MostlyStaticPages' @@ -181,15 +182,16 @@ public function status(int $personId): array { // any outdated T&C, we'll pull those separately, below. $tandc = $this->find() + ->contain('MostlyStaticPages') ->where([ - 'co_id' => $person->co_id, - 'status' => SuspendableStatusEnum::Active, + 'TermsAndConditions.co_id' => $person->co_id, + 'TermsAndConditions.status' => SuspendableStatusEnum::Active, 'OR' => [ - 'cou_id IS NULL', - 'cou_id IN' => array_values($couIds) + 'TermsAndConditions.cou_id IS NULL', + 'TermsAndConditions.cou_id IN' => array_values($couIds) ] ]) - ->order('ordr ASC') + ->orderBy(['TermsAndConditions.ordr' => 'ASC']) ->all(); if(!empty($tandc)) { diff --git a/app/templates/TermsAndConditions/review.php b/app/templates/TermsAndConditions/review.php index 49e5c255d..4ec9296a0 100644 --- a/app/templates/TermsAndConditions/review.php +++ b/app/templates/TermsAndConditions/review.php @@ -1,32 +1,33 @@
@@ -35,68 +36,22 @@
-element('flash') // Flash messages ?> - - +element('flash') // Flash messages ?> + +Form->create(null); // We don't need an object for this form ?>
- - - - - - - - - - - - - - - - - - - - -
getName()]); ?>
-
-
- id; - $action_args['vv_actions'] = []; - - if($t['status'] != TAndCStatusEnum::Agreed) { - // T&C that are not current can be agreed to - - $action_args['vv_actions'][] = [ - 'order' => $this->Menu->getMenuOrder('Default'), - 'icon' => 'signature', - 'url' => [ - 'controller' => 'terms_and_conditions', - 'action' => 'agree', - $t['tandc']->id - ], - 'label' => __d('operation', 'agree'), - 'confirm' => [ - 'dg_body_txt' => __d('operation', 'TermsAndConditions.agree.confirm'), - 'dg_confirm_btn' => __d('operation', 'confirm') - ] - ]; - } + +
- if(!empty($action_args['vv_actions'])) { - print $this->element('menuAction', $action_args); - } - ?> -
- description; ?> - -
identifier ?? "" ?>created) - ? $this->Time->nice($t['agreement']->created, $vv_tz) - : ""; - ?>
+
+
+Form->end(); ?> \ No newline at end of file diff --git a/app/templates/TermsAndConditions/tandcs.inc b/app/templates/TermsAndConditions/tandcs.inc new file mode 100644 index 000000000..ed9bc8dfc --- /dev/null +++ b/app/templates/TermsAndConditions/tandcs.inc @@ -0,0 +1,210 @@ +element('flash', []); + + // Make the Form fields editable + $this->Field->enableFormEditMode(); +?> + +

+ +Form->create(null, [ + 'id' => 'agreement-form', + 'type' => 'post' + ]); + + +?> + + + + + + + + + + + + + + $tc): ?> + + + + + + + + + + + + +
getName()]); ?>
+ + identifier ?? "" ?>created) + ? $this->Time->nice($vv_tandc_statuses[$i]['agreement']->created, $vv_tz) + : ""; + ?> + + url)): // We have a URL based T&C ?> + + + element('tandcAgreeDialog', ['vv_tc' => $tc]); ?> + + +
+ Form->checkbox( + 'tc'.$tc['id'], + [ + 'id' => 'tc'.$tc['id'], + 'class' => 'form-check-input tc-agree-checkbox', + 'checked' => !empty($vv_tandc_statuses) && $vv_tandc_statuses[$i]['status'] == 'Y' ? true : false, + ] + ) . + $this->Form->label( + 'tc'.$tc['id'], + __d('operation','agree'), + [ + 'class' => 'form-check-label' + ] + ) + ?> +
+
+ + \ No newline at end of file diff --git a/app/templates/element/javascript.php b/app/templates/element/javascript.php index fa80a4b2d..7c5afe4e8 100644 --- a/app/templates/element/javascript.php +++ b/app/templates/element/javascript.php @@ -339,8 +339,8 @@ } }); - // Add a .nospin class to all on-page cake error and warning links - $(".cake-error a").addClass('nospin'); + // Add a .nospin class to all on-page cake error and warning links (and debugging accordions) + $(".cake-error a, a.cake-debug-collapse").addClass('nospin'); // Add loading animation when a form is submitted, when any item with a "spin" class is clicked, // or on any anchor tag lacking the .nospin class. We do not automatically add this to buttons diff --git a/app/plugins/TermsAgreer/templates/element/agreeDialog.php b/app/templates/element/tandcAgreeDialog.php similarity index 96% rename from app/plugins/TermsAgreer/templates/element/agreeDialog.php rename to app/templates/element/tandcAgreeDialog.php index 0d710126d..63e384a90 100644 --- a/app/plugins/TermsAgreer/templates/element/agreeDialog.php +++ b/app/templates/element/tandcAgreeDialog.php @@ -52,14 +52,14 @@