MDL-62309 tool_policy: Optional policies can be declined by the user
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).
This commit is contained in:
@@ -1006,7 +1006,7 @@ class api {
|
||||
* @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') {
|
||||
@@ -1020,29 +1020,35 @@ class api {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -99,11 +104,23 @@ class page_agreedocs implements renderable, templatable {
|
||||
}
|
||||
|
||||
$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);
|
||||
@@ -120,25 +137,30 @@ class page_agreedocs implements renderable, templatable {
|
||||
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')
|
||||
@@ -205,16 +227,25 @@ class page_agreedocs implements renderable, templatable {
|
||||
*/
|
||||
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');
|
||||
@@ -377,18 +408,24 @@ class page_agreedocs implements renderable, templatable {
|
||||
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');
|
||||
}
|
||||
}
|
||||
@@ -396,8 +433,10 @@ class page_agreedocs implements renderable, templatable {
|
||||
} 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;
|
||||
}
|
||||
|
||||
@@ -169,10 +169,18 @@ class page_viewdoc implements renderable, templatable {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -39,15 +39,30 @@ require(__DIR__.'/../../../config.php');
|
||||
$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');
|
||||
}
|
||||
|
||||
@@ -67,7 +82,7 @@ if (!$haspermissionagreedocs) {
|
||||
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');
|
||||
|
||||
@@ -79,6 +79,7 @@ $string['filterpolicy'] = 'Policy: {$a}';
|
||||
$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';
|
||||
|
||||
@@ -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">
|
||||
@@ -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>
|
||||
@@ -106,6 +124,7 @@
|
||||
<li><small>{{{.}}}</small></li>
|
||||
{{/versionbehalfsagreed}}
|
||||
</ul>
|
||||
{{/optional}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user