Skip to content

Commit

Permalink
MDL-62309 tool_policy: Optional policies can be declined by the user
Browse files Browse the repository at this point in the history
For optional policies, we provide a radio selector to let the user
choose the acceptance status on the consent page. For policies displayed
on their own page, we display a link to decline the policy.

The way how we pass the list of policy version ids to index.php has
changed so that we can now not only pass the list of ids, but also the
actual acceptance status (accepted / declined).
  • Loading branch information
mudrd8mz committed Oct 22, 2018
1 parent faf4222 commit 5348b1e
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 32 deletions.
28 changes: 17 additions & 11 deletions admin/tool/policy/classes/api.php
Expand Up @@ -1006,7 +1006,7 @@ public static function revoke_acceptance($policyversionid, $userid, $note = null
* @param \core\event\user_created $event
*/
public static function create_acceptances_user_created(\core\event\user_created $event) {
global $CFG, $DB;
global $USER, $CFG, $DB;

// Do nothing if not set as the site policies handler.
if (empty($CFG->sitepolicyhandler) || $CFG->sitepolicyhandler !== 'tool_policy') {
Expand All @@ -1020,29 +1020,35 @@ public static function create_acceptances_user_created(\core\event\user_created
if (!$user->policyagreed) {
return;
}
// Remove the presignup cache after the user account is created.

// Cleanup our bits in the presignup cache (we can not rely on them at this stage any more anyway).
$cache = \cache::make('core', 'presignup');
$cache->delete('tool_policy_userpolicyagreed');
$cache->delete('tool_policy_viewedpolicies');
$cache->delete('tool_policy_policyversionidsagreed');

// Get all active policies.
$currentpolicyversions = static::get_current_versions_ids(policy_version::AUDIENCE_LOGGEDIN);
// Save active policies as accepted by the user.
if (!empty($currentpolicyversions)) {
// Mark all compulsory policies as implicitly accepted during the signup.
if ($policyversions = static::list_current_versions(policy_version::AUDIENCE_LOGGEDIN)) {
$acceptances = array();
foreach ($currentpolicyversions as $policy) {
$now = time();
foreach ($policyversions as $policyversion) {
if ($policyversion->optional == policy_version::AGREEMENT_OPTIONAL) {
continue;
}
$acceptances[] = array(
'policyversionid' => $policy,
'policyversionid' => $policyversion->id,
'userid' => $userid,
'status' => 1,
'lang' => $lang,
'usermodified' => 0,
'timecreated' => time(),
'timemodified' => time()
'usermodified' => isset($USER->id) ? $USER->id : 0,
'timecreated' => $now,
'timemodified' => $now,
);
}
$DB->insert_records('tool_policy_acceptances', $acceptances);
}

static::update_policyagreed($userid);
}

/**
Expand Down
65 changes: 52 additions & 13 deletions admin/tool/policy/classes/output/page_agreedocs.php
Expand Up @@ -57,6 +57,9 @@ class page_agreedocs implements renderable, templatable {
/** @var array $agreedocs List of policy identifiers which the user has agreed using the form. */
protected $agreedocs = null;

/** @var array $declinedocs List of policy identifiers that the user declined. */
protected $declinedocs = null;

/** @var string $action Form action to identify when user agreeds policies. */
protected $action = null;

Expand All @@ -80,15 +83,17 @@ class page_agreedocs implements renderable, templatable {
*
* @param array $listdocs List of policy version ids that were displayed to the user to agree with.
* @param array $agreedocs List of policy version ids that the user actually agreed with.
* @param array $declinedocs List of policy version ids that the user declined.
* @param int $behalfid The userid to accept the policy versions as (such as child's id).
* @param string $action Form action to identify when user agreeds policies.
*/
public function __construct(array $listdocs, array $agreedocs = [], $behalfid = 0, $action = null) {
public function __construct(array $listdocs, array $agreedocs = [], array $declinedocs = [], $behalfid = 0, $action = null) {
global $USER;
$realuser = manager::get_realuser();

$this->listdocs = $listdocs;
$this->agreedocs = $agreedocs;
$this->declinedocs = $declinedocs;
$this->action = $action;
$this->isexistinguser = isloggedin() && !isguestuser();

Expand All @@ -99,11 +104,23 @@ public function __construct(array $listdocs, array $agreedocs = [], $behalfid =
}

$this->policies = api::list_current_versions(policy_version::AUDIENCE_LOGGEDIN);

if (!$this->isexistinguser) {
// During the signup, show compulsory policies only.
foreach ($this->policies as $ix => $policyversion) {
if ($policyversion->optional == policy_version::AGREEMENT_OPTIONAL) {
unset($this->policies[$ix]);
}
}
$this->policies = array_values($this->policies);
}

if (empty($this->behalfid)) {
$userid = $USER->id;
} else {
$userid = $this->behalfid;
}

$this->accept_and_revoke_policies();
$this->prepare_global_page_access($userid);
$this->prepare_user_acceptances($userid);
Expand All @@ -120,25 +137,30 @@ protected function accept_and_revoke_policies() {
if ($this->isexistinguser) {
// Existing user.
if (!empty($this->action) && confirm_sesskey()) {
// The form has been sent. Update policies acceptances according to $this->agreedocs.
// The form has been sent, update policies acceptances.
$lang = current_language();
// Accept / revoke policies.
$acceptversionids = array();
$acceptversionids = [];
$declineversionids = [];

foreach ($this->policies as $policy) {
if (in_array($policy->id, $this->listdocs)) {
if (in_array($policy->id, $this->agreedocs)) {
// Save policy version doc to accept it.
$acceptversionids[] = $policy->id;
} else if (in_array($policy->id, $this->declinedocs)) {
$declineversionids[] = $policy->id;
} else {
// If the policy was displayed but not agreed, revoke the eventually given acceptance.
// If the policy was displayed but not answered, revoke the eventually given acceptance.
api::revoke_acceptance($policy->id, $this->behalfid);
}
}
}
// Accept all policy docs saved in $acceptversionids.

api::accept_policies($acceptversionids, $this->behalfid, null, $lang);
api::decline_policies($declineversionids, $this->behalfid, null, $lang);

// Show a message to let know the user he/she must agree all the policies.
if (count($acceptversionids) != count($this->policies)) {
if ((count($acceptversionids) + count($declineversionids)) != count($this->policies)) {
$message = (object) [
'type' => 'error',
'text' => get_string('mustagreetocontinue', 'tool_policy')
Expand Down Expand Up @@ -205,16 +227,25 @@ protected function accept_and_revoke_policies() {
*/
protected function redirect_to_policies($userid, $returnurl = null) {

// Make a list of all policies that the user has not accepted yet.
// Make a list of all policies that the user has not answered yet.
$allpolicies = $this->policies;

if ($this->isexistinguser) {
$acceptances = api::get_user_acceptances($userid);
foreach ($allpolicies as $ix => $policy) {
if (api::is_user_version_accepted($userid, $policy->id, $acceptances)) {
$isaccepted = api::is_user_version_accepted($userid, $policy->id, $acceptances);
if ($isaccepted) {
// The user has accepted this policy, do not show it again.
unset($allpolicies[$ix]);
} else if ($isaccepted === false && $policy->optional == policy_version::AGREEMENT_OPTIONAL) {
// The user declined this policy but the agreement was optional, do not show it.
unset($allpolicies[$ix]);
} else {
// The user has not answered the policy yet, or the agreement is compulsory. Show it.
continue;
}
}

} else {
$presignupcache = \cache::make('core', 'presignup');
$acceptances = $presignupcache->get('tool_policy_policyversionidsagreed');
Expand Down Expand Up @@ -377,27 +408,35 @@ protected function prepare_user_acceptances($userid) {
if ($this->isexistinguser) {
// Existing user.
$versionagreed = false;
$versiondeclined = false;
$acceptances = api::get_user_acceptances($userid);
$policy->versionacceptance = api::get_user_version_acceptance($userid, $policy->id, $acceptances);
if (!empty($policy->versionacceptance)) {
// The policy version has ever been agreed. Check if status = 1 to know if still is accepted.
$versionagreed = $policy->versionacceptance->status;
// The policy version has ever been replied to before. Check if status = 1 to know if still is accepted.
if ($policy->versionacceptance->status) {
$versionagreed = true;
} else {
$versiondeclined = true;
}
if ($versionagreed) {
if ($policy->versionacceptance->lang != $lang) {
// Add a message because this version has been accepted in a different language than the current one.
$policy->versionlangsagreed = get_string('policyversionacceptedinotherlang', 'tool_policy');
}
if ($policy->versionacceptance->usermodified != $userid && $USER->id == $userid) {
// Add a message because this version has been accepted in behalf of current user.
$usermodified = $policy->versionacceptance->usermodified;
if ($usermodified && $usermodified != $userid && $USER->id == $userid) {
// Add a message because this version has been accepted on behalf of current user.
$policy->versionbehalfsagreed = get_string('policyversionacceptedinbehalf', 'tool_policy');
}
}
}
} else {
// New user.
$versionagreed = in_array($policy->id, $this->agreedocs);
$versiondeclined = false;
}
$policy->versionagreed = $versionagreed;
$policy->versiondeclined = $versiondeclined;
$policy->policylink = html_writer::link($policy->url, $policy->name);
$policy->policymodal = $policymodal;
}
Expand Down
10 changes: 9 additions & 1 deletion admin/tool/policy/classes/output/page_viewdoc.php
Expand Up @@ -169,10 +169,18 @@ public function export_for_template(renderer_base $output) {
unset($data->returnurl);
$data->accepturl = (new moodle_url('/admin/tool/policy/index.php', [
'listdoc[]' => $this->policy->id,
'agreedoc[]' => $this->policy->id,
'status'.$this->policy->id => 1,
'submit' => 'accept',
'sesskey' => sesskey(),
]))->out(false);
if ($this->policy->optional == policy_version::AGREEMENT_OPTIONAL) {
$data->declineurl = (new moodle_url('/admin/tool/policy/index.php', [
'listdoc[]' => $this->policy->id,
'status'.$this->policy->id => 0,
'submit' => 'decline',
'sesskey' => sesskey(),
]))->out(false);
}
}
}

Expand Down
23 changes: 19 additions & 4 deletions admin/tool/policy/index.php
Expand Up @@ -19,7 +19,7 @@
*
* Script parameters:
* listdoc=<array> List of policy version ids that were displayed to the user to accept.
* agreedoc=<array> List of policy version ids that were accepted by the user.
* statusXX=<int> Acceptance status to be set for the policy version with id XX.
* behalfid=<id> The user id to view the policy version as (such as child's id).
*
* @package tool_policy
Expand All @@ -39,15 +39,30 @@
$submit = optional_param('submit', null, PARAM_NOTAGS);
$cancel = optional_param('cancel', null, PARAM_NOTAGS);
$listdocs = optional_param_array('listdoc', [], PARAM_INT);
$agreedocs = optional_param_array('agreedoc', [], PARAM_INT);
$behalfid = optional_param('userid', null, PARAM_INT);

$agreedocs = [];
$declinedocs = [];

foreach ($listdocs as $pvid) {
$status = optional_param('status'.$pvid, null, PARAM_INT);
if ($status === 1) {
$agreedocs[] = $pvid;
} else if ($status === 0) {
$declinedocs[] = $pvid;
}
}

$listdocs = array_values(array_unique($listdocs));
$agreedocs = array_values(array_unique($agreedocs));
$declinedocs = array_values(array_unique($declinedocs));

$PAGE->set_context(context_system::instance());
$PAGE->set_pagelayout('standard');
$PAGE->set_url('/admin/tool/policy/index.php');
$PAGE->set_popup_notification_allowed(false);

if (array_diff($agreedocs, $listdocs)) {
if (array_diff($agreedocs, $listdocs) || array_diff($declinedocs, $listdocs)) {
throw new moodle_exception('invalidaccessparameter');
}

Expand All @@ -67,7 +82,7 @@
if (!$behalfid && \core\session\manager::is_loggedinas()) {
$behalfid = $USER->id;
}
$outputpage = new \tool_policy\output\page_agreedocs($listdocs, $agreedocs, $behalfid, $submit);
$outputpage = new \tool_policy\output\page_agreedocs($listdocs, $agreedocs, $declinedocs, $behalfid, $submit);
}

$output = $PAGE->get_renderer('tool_policy');
Expand Down
1 change: 1 addition & 0 deletions admin/tool/policy/lang/en/tool_policy.php
Expand Up @@ -79,6 +79,7 @@
$string['guestconsent:continue'] = 'Continue';
$string['guestconsentmessage'] = 'If you continue browsing this website, you agree to our policies:';
$string['iagree'] = 'I agree to the {$a}';
$string['idontagree'] = 'No thanks, I do not agree';
$string['iagreetothepolicy'] = 'Give consent';
$string['inactivate'] = 'Set status to "Inactive"';
$string['inactivating'] = 'Inactivating a policy';
Expand Down
25 changes: 22 additions & 3 deletions admin/tool/policy/templates/page_agreedocs.mustache
Expand Up @@ -80,6 +80,8 @@

{{#policies}}

<input value="{{id}}" name="listdoc[]" type="hidden">

<div class="agreedoc-policy clearfix m-t-2 m-b-1">
<h3>{{{name}}}</h3>
<div class="agreedoc-content">
Expand All @@ -90,11 +92,27 @@
{{# str }}refertofullpolicytext, tool_policy, {{{policymodal}}} {{/ str }}
</div>
<div class="agreedoc-form m-t-1">
{{#optional}}
<div class="agreedoc-radios">
<div class="agreedoc-radios-1">
<label>
<input type="radio" name="status{{id}}" value="1" {{#versionagreed}}checked="{{.}}"{{/versionagreed}}>
{{# str }}iagree, tool_policy, {{{name}}} {{/ str }}
</label>
</div>
<div class="agreedoc-radios-0">
<label>
<input type="radio" name="status{{id}}" value="0" {{#versiondeclined}}checked="{{.}}"{{/versiondeclined}}>
{{# str }}idontagree, tool_policy, {{{name}}} {{/ str }}
</label>
</div>
</div>
{{/optional}}
{{^optional}}
<div class="agreedoc-checkbox">
<label>
<input value="{{id}}" name="listdoc[]" type="hidden" >
<input value="{{id}}" name="agreedoc[]" {{#versionagreed}}checked="{{.}}"{{/versionagreed}} type="checkbox">
<strong>{{# str }}iagree, tool_policy, {{{name}}} {{/ str }}</strong>
<input value="1" name="status{{id}}" {{#versionagreed}}checked="{{.}}"{{/versionagreed}} type="checkbox">
{{# str }}iagree, tool_policy, {{{name}}} {{/ str }}
<i class="icon fa fa-exclamation-circle text-danger fa-fw" title="{{# str }} required {{/ str }}" ></i>
</label>
</div>
Expand All @@ -106,6 +124,7 @@
<li><small>{{{.}}}</small></li>
{{/versionbehalfsagreed}}
</ul>
{{/optional}}
</div>
</div>
</div>
Expand Down
3 changes: 3 additions & 0 deletions admin/tool/policy/templates/page_viewdoc.mustache
Expand Up @@ -92,6 +92,9 @@
{{#accepturl}}
<a role="button" href="{{accepturl}}" class="btn btn-primary">{{#str}} iagree, tool_policy, {{{policy.name}}} {{/str}}</a>
{{/accepturl}}
{{#declineurl}}
<a role="button" href="{{declineurl}}" class="btn btn-link">{{#str}} idontagree, tool_policy, {{{policy.name}}} {{/str}}</a>
{{/declineurl}}

<div class="pull-right">
<a href="#top">
Expand Down

0 comments on commit 5348b1e

Please sign in to comment.