MDL-62062 tool_policy: Let manager/dpo withdraw consent to policies

The policies can be revoked by clicking the "Agreed [on behalf]" ticks.
A message has been added also to explain users they must contact to
the DPO if they want to withdraw their consent to policies.
This commit is contained in:
Sara Arjona 2018-05-03 13:27:04 +02:00
parent 3d34aa5c29
commit 461b1931c0
12 changed files with 260 additions and 43 deletions

View File

@ -15,7 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Accept policies on behalf of users (non-JS version)
* Accept or revoke policies on behalf of users (non-JS version)
*
* @package tool_policy
* @copyright 2018 Marina Glancy
@ -28,6 +28,7 @@ require_once($CFG->dirroot.'/user/editlib.php');
$userids = optional_param_array('userids', null, PARAM_INT);
$versionids = optional_param_array('versionids', null, PARAM_INT);
$returnurl = optional_param('returnurl', null, PARAM_LOCALURL);
$action = optional_param('action', null, PARAM_ALPHA);
require_login();
if (isguestuser()) {
@ -48,7 +49,7 @@ if ($returnurl) {
}
// Initialise the form, this will also validate users, versions and check permission to accept policies.
$form = new \tool_policy\form\accept_policy(null,
['versionids' => $versionids, 'userids' => $userids, 'showbuttons' => true]);
['versionids' => $versionids, 'userids' => $userids, 'showbuttons' => true, 'action' => $action]);
$form->set_data(['returnurl' => $returnurl]);
if ($form->is_cancelled()) {
@ -58,8 +59,14 @@ if ($form->is_cancelled()) {
redirect($returnurl);
}
if ($action == 'revoke') {
$title = get_string('revokedetails', 'tool_policy');
} else {
$title = get_string('consentdetails', 'tool_policy');
}
$output = $PAGE->get_renderer('tool_policy');
echo $output->header();
echo $output->heading(get_string('consentdetails', 'tool_policy'));
echo $output->heading($title);
$form->display();
echo $output->footer();

View File

@ -1 +1 @@
define(["jquery","core/str","core/modal_factory","core/modal_events","core/notification","core/fragment","core/ajax","core/yui"],function(a,b,c,d,e,f,g,h){"use strict";var i=function(a){this.contextid=a,this.init()};return i.prototype.modal=null,i.prototype.contextid=-1,i.prototype.stringKeys=[{key:"consentdetails",component:"tool_policy"},{key:"iagreetothepolicy",component:"tool_policy"},{key:"selectusersforconsent",component:"tool_policy"},{key:"ok"}],i.prototype.init=function(){var c=a("a[data-action=acceptmodal]");c.on("click",function(b){b.preventDefault();var c=a(b.currentTarget).attr("href"),d=c.slice(c.indexOf("?")+1);this.showFormModal(d)}.bind(this)),c=a("form[data-action=acceptmodal]"),c.on("submit",function(d){if(d.preventDefault(),a(d.currentTarget).find('input[type=checkbox][name="userids[]"]:checked').length){var f=a(d.currentTarget).serialize();this.showFormModal(f,c)}else b.get_strings(this.stringKeys).done(function(a){e.alert("",a[2],a[3])})}.bind(this))},i.prototype.showFormModal=function(a,d){b.get_strings(this.stringKeys).done(function(b){c.create({type:c.types.SAVE_CANCEL,title:b[0],body:""},d).done(function(c){this.modal=c,this.setupFormModal(a,b[1])}.bind(this))}.bind(this)).fail(e.exception)},i.prototype.setupFormModal=function(a,b){var c=this.modal;c.setLarge(),c.setSaveButtonText(b),c.getRoot().on(d.hidden,this.destroy.bind(this)),c.setBody(this.getBody(a)),c.getRoot().on(d.save,this.submitForm.bind(this)),c.getRoot().on("submit","form",this.submitFormAjax.bind(this)),c.show()},i.prototype.getBody=function(a){"undefined"==typeof a&&(a={});var b={jsonformdata:JSON.stringify(a)};return f.loadFragment("tool_policy","accept_on_behalf",this.contextid,b)},i.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize(),c=g.call([{methodname:"tool_policy_submit_accept_on_behalf",args:{jsonformdata:JSON.stringify(b)}}]);c[0].done(function(a){a.validationerrors?this.modal.setBody(this.getBody(b)):this.close()}.bind(this)).fail(e.exception)},i.prototype.submitForm=function(a){a.preventDefault(),this.modal.getRoot().find("form").submit()},i.prototype.close=function(){this.destroy(),document.location.reload()},i.prototype.destroy=function(){h.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()}),this.modal.destroy()},{getInstance:function(a){return new i(a)}}});
define(["jquery","core/str","core/modal_factory","core/modal_events","core/notification","core/fragment","core/ajax","core/yui"],function(a,b,c,d,e,f,g,h){"use strict";var i=function(a){this.contextid=a,this.init()};return i.prototype.modal=null,i.prototype.contextid=-1,i.prototype.stringKeys=[{key:"consentdetails",component:"tool_policy"},{key:"iagreetothepolicy",component:"tool_policy"},{key:"selectusersforconsent",component:"tool_policy"},{key:"ok"},{key:"revokedetails",component:"tool_policy"},{key:"irevokethepolicy",component:"tool_policy"}],i.prototype.init=function(){var c=a("a[data-action=acceptmodal]");c.on("click",function(b){b.preventDefault();var c=a(b.currentTarget).attr("href"),d=c.slice(c.indexOf("?")+1);this.showFormModal(d)}.bind(this)),c=a("form[data-action=acceptmodal]"),c.on("submit",function(d){if(d.preventDefault(),a(d.currentTarget).find('input[type=checkbox][name="userids[]"]:checked').length){var f=a(d.currentTarget).serialize();this.showFormModal(f,c)}else b.get_strings(this.stringKeys).done(function(a){e.alert("",a[2],a[3])})}.bind(this))},i.prototype.showFormModal=function(a,d){for(var f,g=a.split("&"),h=0;h<g.length;h++){var i=g[h].split("=");"action"==i[0]&&(f=i[1])}b.get_strings(this.stringKeys).done(function(b){var e,g;"revoke"==f?(e=b[4],g=b[5]):(e=b[0],g=b[1]),c.create({type:c.types.SAVE_CANCEL,title:e,body:""},d).done(function(b){this.modal=b,this.setupFormModal(a,g)}.bind(this))}.bind(this)).fail(e.exception)},i.prototype.setupFormModal=function(a,b){var c=this.modal;c.setLarge(),c.setSaveButtonText(b),c.getRoot().on(d.hidden,this.destroy.bind(this)),c.setBody(this.getBody(a)),c.getRoot().on(d.save,this.submitForm.bind(this)),c.getRoot().on("submit","form",this.submitFormAjax.bind(this)),c.show()},i.prototype.getBody=function(a){"undefined"==typeof a&&(a={});var b={jsonformdata:JSON.stringify(a)};return f.loadFragment("tool_policy","accept_on_behalf",this.contextid,b)},i.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize(),c=g.call([{methodname:"tool_policy_submit_accept_on_behalf",args:{jsonformdata:JSON.stringify(b)}}]);c[0].done(function(a){a.validationerrors?this.modal.setBody(this.getBody(b)):this.close()}.bind(this)).fail(e.exception)},i.prototype.submitForm=function(a){a.preventDefault(),this.modal.getRoot().find("form").submit()},i.prototype.close=function(){this.destroy(),document.location.reload()},i.prototype.destroy=function(){h.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()}),this.modal.destroy()},{getInstance:function(a){return new i(a)}}});

View File

@ -71,6 +71,14 @@ define(['jquery', 'core/str', 'core/modal_factory', 'core/modal_events', 'core/n
},
{
key: 'ok'
},
{
key: 'revokedetails',
component: 'tool_policy'
},
{
key: 'irevokethepolicy',
component: 'tool_policy'
}
];
@ -111,16 +119,33 @@ define(['jquery', 'core/str', 'core/modal_factory', 'core/modal_events', 'core/n
* @param {object} triggerElement The trigger HTML jQuery object
*/
AcceptOnBehalf.prototype.showFormModal = function(formData, triggerElement) {
var action;
var params = formData.split('&');
for (var i = 0; i < params.length; i++) {
var pair = params[i].split('=');
if (pair[0] == 'action') {
action = pair[1];
}
}
// Fetch the title string.
Str.get_strings(this.stringKeys).done(function(strings) {
var title;
var saveText;
if (action == 'revoke') {
title = strings[4];
saveText = strings[5];
} else {
title = strings[0];
saveText = strings[1];
}
// Create the modal.
ModalFactory.create({
type: ModalFactory.types.SAVE_CANCEL,
title: strings[0],
title: title,
body: ''
}, triggerElement).done(function(modal) {
this.modal = modal;
this.setupFormModal(formData, strings[1]);
this.setupFormModal(formData, saveText);
}.bind(this));
}.bind(this))
.fail(Notification.exception);

View File

@ -813,6 +813,39 @@ class api {
}
}
/**
* Checks if user can revoke policies for themselves or on behalf of another user
*
* @param int $userid
* @param bool $throwexception
* @return bool
*/
public static function can_revoke_policies($userid = null, $throwexception = false) {
global $USER;
if (!isloggedin() || isguestuser()) {
if ($throwexception) {
throw new \moodle_exception('noguest');
} else {
return false;
}
}
if (!$userid) {
$userid = $USER->id;
}
// At the moment, current users can't revoke their own policies.
// Check capability to revoke on behalf as the real user.
$realuser = manager::get_realuser();
$usercontext = \context_user::instance($userid);
if ($throwexception) {
require_capability('tool/policy:acceptbehalf', $usercontext, $realuser);
return;
} else {
return has_capability('tool/policy:acceptbehalf', $usercontext, $realuser);
}
}
/**
* Accepts the current revisions of all policies that the user has not yet accepted
*

View File

@ -32,7 +32,7 @@ defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot.'/lib/formslib.php');
/**
* Represents the form for accepting a policy.
* Represents the form for accepting or revoking a policy.
*
* @package tool_policy
* @copyright 2018 Marina Glancy
@ -53,9 +53,10 @@ class accept_policy extends \moodleform {
if (empty($this->_customdata['versionids']) || !is_array($this->_customdata['versionids'])) {
throw new \moodle_exception('missingparam', '', '', 'versionids');
}
$revoke = (!empty($this->_customdata['action']) && $this->_customdata['action'] == 'revoke');
$userids = clean_param_array($this->_customdata['userids'], PARAM_INT);
$versionids = clean_param_array($this->_customdata['versionids'], PARAM_INT);
$usernames = $this->validate_and_get_users($userids);
$usernames = $this->validate_and_get_users($userids, $revoke);
$versionnames = $this->validate_and_get_versions($versionids);
foreach ($usernames as $userid => $name) {
@ -75,13 +76,23 @@ class accept_policy extends \moodleform {
$mform->addElement('static', 'policy', get_string('acceptancepolicies', 'tool_policy'),
join(', ', $versionnames));
$mform->addElement('static', 'ack', '', get_string('acceptanceacknowledgement', 'tool_policy'));
if ($revoke) {
$mform->addElement('static', 'ack', '', get_string('revokeacknowledgement', 'tool_policy'));
$mform->addElement('hidden', 'action', 'revoke');
$mform->setType('action', PARAM_ALPHA);
} else {
$mform->addElement('static', 'ack', '', get_string('acceptanceacknowledgement', 'tool_policy'));
}
$mform->addElement('textarea', 'note', get_string('acceptancenote', 'tool_policy'));
$mform->setType('note', PARAM_NOTAGS);
if (!empty($this->_customdata['showbuttons'])) {
$this->add_action_buttons(true, get_string('iagreetothepolicy', 'tool_policy'));
if ($revoke) {
$this->add_action_buttons(true, get_string('irevokethepolicy', 'tool_policy'));
} else {
$this->add_action_buttons(true, get_string('iagreetothepolicy', 'tool_policy'));
}
}
$PAGE->requires->js_call_amd('tool_policy/policyactions', 'init');
@ -91,9 +102,10 @@ class accept_policy extends \moodleform {
* Validate userids and return usernames
*
* @param array $userids
* @param boolean $revoke True if policies will be revoked; false when policies will be accepted.
* @return array (userid=>username)
*/
protected function validate_and_get_users($userids) {
protected function validate_and_get_users($userids, $revoke = false) {
global $DB;
$usernames = [];
list($sql, $params) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
@ -112,7 +124,11 @@ class accept_policy extends \moodleform {
throw new \moodle_exception('noguest');
}
\context_helper::preload_from_record($user);
api::can_accept_policies($userid, true);
if ($revoke) {
api::can_revoke_policies($userid, true);
} else {
api::can_accept_policies($userid, true);
}
$usernames[$userid] = fullname($user);
}
return $usernames;
@ -148,8 +164,15 @@ class accept_policy extends \moodleform {
*/
public function process() {
if ($data = $this->get_data()) {
$revoke = (!empty($data->action) && $data->action == 'revoke');
foreach ($data->userids as $userid) {
\tool_policy\api::accept_policies($data->versionids, $userid, $data->note);
if ($revoke) {
foreach ($data->versionids as $versionid) {
\tool_policy\api::revoke_acceptance($versionid, $userid, $data->note);
}
} else {
\tool_policy\api::accept_policies($data->versionids, $userid, $data->note);
}
}
}
}

View File

@ -50,6 +50,9 @@ class acceptances implements renderable, templatable {
/** @var moodle_url */
protected $returnurl;
/** @var bool */
protected $canrevoke;
/**
* Contructor.
*
@ -59,6 +62,7 @@ class acceptances implements renderable, templatable {
public function __construct($userid, $returnurl = null) {
$this->userid = $userid;
$this->returnurl = $returnurl ? (new moodle_url($returnurl))->out(false) : null;
$this->canrevoke = \tool_policy\api::can_revoke_policies($this->userid);
}
/**
@ -72,6 +76,7 @@ class acceptances implements renderable, templatable {
$data->hasonbehalfagreements = false;
$data->pluginbaseurl = (new moodle_url('/admin/tool/policy'))->out(false);
$data->returnurl = $this->returnurl;
$data->canrevoke = $this->canrevoke;
// Get the list of policies and versions that current user is able to see
// and the respective acceptance records for the selected user.

View File

@ -59,6 +59,9 @@ class user_agreement implements \templatable, \renderable {
/** @var bool */
protected $canaccept;
/** @var bool */
protected $canrevoke;
/**
* user_agreement constructor
*
@ -68,8 +71,10 @@ class user_agreement implements \templatable, \renderable {
* @param array $versions list of versions (id=>name)
* @param bool $onbehalf whether at least one version was accepted by somebody else on behalf of the user
* @param bool $canaccept does the current user have permission to accept the policy on behalf of user $userid
* @param bool $canrevoke does the current user have permission to revoke the policy on behalf of user $userid
*/
public function __construct($userid, $accepted, moodle_url $pageurl, $versions, $onbehalf = false, $canaccept = null) {
public function __construct($userid, $accepted, moodle_url $pageurl, $versions, $onbehalf = false,
$canaccept = null, $canrevoke = null) {
$this->userid = $userid;
$this->onbehalf = $onbehalf;
$this->pageurl = $pageurl;
@ -79,6 +84,9 @@ class user_agreement implements \templatable, \renderable {
if (count($this->accepted) < count($this->versions) && $canaccept === null) {
$this->canaccept = \tool_policy\api::can_accept_policies($this->userid);
}
if (count($this->accepted) == count($this->versions) && $canrevoke === null) {
$this->canrevoke = \tool_policy\api::can_revoke_policies($this->userid);
}
}
/**
@ -92,6 +100,7 @@ class user_agreement implements \templatable, \renderable {
'status' => count($this->accepted) == count($this->versions),
'onbehalf' => $this->onbehalf,
'canaccept' => $this->canaccept,
'canrevoke' => $this->canrevoke,
];
if (!$data['status'] && $this->canaccept) {
$linkparams = ['userids[0]' => $this->userid];
@ -101,6 +110,15 @@ class user_agreement implements \templatable, \renderable {
$linkparams['returnurl'] = $this->pageurl->out_as_local_url(false);
$link = new \moodle_url('/admin/tool/policy/accept.php', $linkparams);
$data['acceptlink'] = $link->out(false);
} else if ($data['status'] && $this->canrevoke) {
$linkparams = ['userids[0]' => $this->userid];
foreach (array_keys($this->versions) as $versionid) {
$linkparams["versionids[{$versionid}]"] = $versionid;
}
$linkparams['returnurl'] = $this->pageurl->out_as_local_url(false);
$linkparams['action'] = 'revoke';
$link = new \moodle_url('/admin/tool/policy/accept.php', $linkparams);
$data['revokelink'] = $link->out(false);
}
$data['singleversion'] = count($this->versions) == 1;
if ($data['singleversion']) {

View File

@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();
$string['acceptanceacknowledgement'] = 'I acknowledge that consents to these policies have been acquired';
$string['acceptanceacknowledgement'] = 'I acknowledge that I have received the user\'s request to consent on the abovementioned policy on behalf of the user.';
$string['acceptancecount'] = '{$a->agreedcount} of {$a->policiescount}';
$string['acceptancenote'] = 'Remarks';
$string['acceptancepolicies'] = 'Policies';
@ -39,12 +39,22 @@ $string['activateconfirm'] = '<p>You are about to activate policy <em>\'{$a->nam
$string['activateconfirmyes'] = 'Activate';
$string['agreed'] = 'Agreed';
$string['agreedby'] = 'Agreed by';
$string['agreedno'] = 'Not agreed';
$string['agreednowithlink'] = 'Not agreed, click to agree to "{$a}"';
$string['agreednowithlinkall'] = 'Not agreed, click to agree to all policies';
$string['agreedon'] = 'Agreed on';
$string['agreedyes'] = 'Agreed';
$string['agreedyesonbehalf'] = 'Agreed on behalf of';
$string['agreedyesonbehalfwithlink'] = 'Agreed on behalf of, click to withdraw consent to "{$a}"';
$string['agreedyesonbehalfwithlinkall'] = 'Agreed on behalf of, click to withdraw consent to all policies"';
$string['agreedyeswithlink'] = 'Agreed, click to withdraw consent to "{$a}"';
$string['agreedyeswithlinkall'] = 'Agreed, click to withdraw consent to all policies';
$string['agreepolicies'] = 'Please agree to the following policies';
$string['backtotop'] = 'Back to top';
$string['consentbulk'] = 'Consent';
$string['consentdetails'] = 'Consent details';
$string['consentdetails'] = 'Agree on behalf of the user';
$string['consentpagetitle'] = 'Consent';
$string['contactdpo'] = 'For questions regarding the policies please contact the Data Protection Officer.';
$string['dataproc'] = 'Personal data processing';
$string['deleting'] = 'Deleting a version';
$string['deleteconfirm'] = '<p>Are you sure you want to delete policy <em>\'{$a->name}\'</em>?</p><p>This operation can not be undone.</p>';
@ -67,12 +77,13 @@ $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['iagreetothepolicy'] = 'I agree to the policy';
$string['iagreetothepolicy'] = 'Agree';
$string['inactivate'] = 'Set status to "Inactive"';
$string['inactivating'] = 'Inactivating a policy';
$string['inactivatingconfirm'] = '<p>You are about to inactivate policy <em>\'{$a->name}\'</em> version <em>\'{$a->revision}\'</em>.</p><p>The policy will not apply until some version is made the current one.</p>';
$string['inactivatingconfirmyes'] = 'Inactivate';
$string['invalidversionid'] = 'There is no policy with this identifier!';
$string['irevokethepolicy'] = 'Withdraw consent';
$string['minorchange'] = 'Minor change';
$string['minorchangeinfo'] = 'Minor changes do not amend the meaning of the policy text, terms or conditions. Users do not need to reconfirm their consent.';
$string['managepolicies'] = 'Manage policies';
@ -128,6 +139,8 @@ $string['privacy:metadata:acceptances:note'] = 'Any comments added by the user w
$string['privacysettings'] = 'Privacy settings';
$string['readpolicy'] = 'Please read our {$a}';
$string['refertofullpolicytext'] = 'Please refer to the full {$a} text if you would like to review.';
$string['revokeacknowledgement'] = 'I acknowledge that I have received the user\'s request to withdraw consent on the abovementioned policy on behalf of the user.';
$string['revokedetails'] = 'Withdraw user\'s consent';
$string['save'] = 'Save';
$string['saveasdraft'] = 'Save as draft';
$string['selectuser'] = 'Select user {$a}';
@ -146,8 +159,3 @@ $string['userpolicysettings'] = 'Policies';
$string['usersaccepted'] = 'Agreements';
$string['viewarchived'] = 'View previous versions';
$string['viewconsentpageforuser'] = 'Viewing this page on behalf of {$a}';
$string['agreedno'] = 'Not agreed';
$string['agreednowithlink'] = 'Not agreed, click to agree to "{$a}"';
$string['agreednowithlinkall'] = 'Not agreed, click to agree to all policies';
$string['agreedyes'] = 'Agreed';
$string['agreedyesonbehalf'] = 'Agreed on behalf of';

View File

@ -31,6 +31,7 @@
Example context (json):
{
"hasonbehalfagreements": true,
"canrevoke": true,
"policies": [
{
"versions": [
@ -70,6 +71,10 @@
]
}
}}
{{^canrevoke}}
<div class="alert alert-info">{{#str}} contactdpo, tool_policy {{/str}}</div>
{{/canrevoke}}
<table class="generaltable fullwidth">
<thead>
<tr>

View File

@ -36,20 +36,47 @@
"status": false,
"onbehalf": false,
"canaccept": true,
"canrevoke": true,
"acceptlink": "/",
"revokelink": "/",
"singleversion": false,
"versionname": ""
}
}}
{{#status}}
{{#canrevoke}}
{{#singleversion}}
{{#onbehalf}}
<a href="{{revokelink}}" data-action="acceptmodal">{{#pix}}agreedyesonbehalf, tool_policy,
{{#str}} agreedyesonbehalfwithlink, tool_policy, {{{versionname}}} {{/str}}{{/pix}}</a>
{{/onbehalf}}
{{^onbehalf}}
<a href="{{revokelink}}" data-action="acceptmodal">{{#pix}}agreedyes, tool_policy,
{{#str}} agreedyeswithlink, tool_policy, {{{versionname}}} {{/str}}{{/pix}}</a>
{{/onbehalf}}
{{/singleversion}}
{{^singleversion}}
{{#onbehalf}}
<a href="{{revokelink}}" data-action="acceptmodal">{{#pix}}agreedyesonbehalf, tool_policy,
{{#str}} agreedyesonbehalfwithlinkall, tool_policy {{/str}}{{/pix}}</a>
{{/onbehalf}}
{{^onbehalf}}
<a href="{{revokelink}}" data-action="acceptmodal">{{#pix}}agreedyes, tool_policy,
{{#str}} agreedyeswithlinkall, tool_policy {{/str}}{{/pix}}</a>
{{/onbehalf}}
{{/singleversion}}
{{/canrevoke}}
{{#onbehalf}}
<span>{{#pix}}agreedyesonbehalf, tool_policy, {{#str}} agreedyesonbehalf, tool_policy {{/str}}{{/pix}}</span>
{{/onbehalf}}
{{^onbehalf}}
<span>{{#pix}}agreedyes, tool_policy, {{#str}} agreedyes, tool_policy {{/str}}{{/pix}}</span>
{{/onbehalf}}
{{^canrevoke}}
{{#onbehalf}}
<span>{{#pix}}agreedyesonbehalf, tool_policy, {{#str}} agreedyesonbehalf, tool_policy {{/str}}{{/pix}}</span>
{{/onbehalf}}
{{^onbehalf}}
<span>{{#pix}}agreedyes, tool_policy, {{#str}} agreedyes, tool_policy {{/str}}{{/pix}}</span>
{{/onbehalf}}
{{/canrevoke}}
{{/status}}
{{^status}}
{{#canaccept}}
{{#singleversion}}

View File

@ -368,6 +368,72 @@ class tool_policy_api_testcase extends advanced_testcase {
$this->assertTrue(api::can_user_view_policy_version($policy3, null, $parent->id));
}
/**
* Test behaviour of the {@link api::can_revoke_policies()} method.
*/
public function test_can_revoke_policies() {
global $CFG;
$this->resetAfterTest();
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$child = $this->getDataGenerator()->create_user();
$parent = $this->getDataGenerator()->create_user();
$officer = $this->getDataGenerator()->create_user();
$manager = $this->getDataGenerator()->create_user();
$syscontext = context_system::instance();
$childcontext = context_user::instance($child->id);
$roleminorid = create_role('Digital minor', 'digiminor', 'Not old enough to accept site policies themselves');
$roleparentid = create_role('Parent', 'parent', 'Can accept policies on behalf of their child');
$roleofficerid = create_role('Policy officer', 'policyofficer', 'Can see all acceptances but can\'t edit policy documents');
$rolemanagerid = create_role('Policy manager', 'policymanager', 'Can manage policy documents');
assign_capability('tool/policy:accept', CAP_PROHIBIT, $roleminorid, $syscontext->id);
assign_capability('tool/policy:acceptbehalf', CAP_ALLOW, $roleparentid, $syscontext->id);
assign_capability('tool/policy:acceptbehalf', CAP_ALLOW, $roleofficerid, $syscontext->id);
assign_capability('tool/policy:viewacceptances', CAP_ALLOW, $roleofficerid, $syscontext->id);
assign_capability('tool/policy:acceptbehalf', CAP_ALLOW, $rolemanagerid, $syscontext->id);
assign_capability('tool/policy:managedocs', CAP_ALLOW, $rolemanagerid, $syscontext->id);
role_assign($roleminorid, $child->id, $syscontext->id);
// Becoming a parent is easy. Being a good one is difficult.
role_assign($roleparentid, $parent->id, $childcontext->id);
role_assign($roleofficerid, $officer->id, $syscontext->id);
role_assign($rolemanagerid, $manager->id, $syscontext->id);
accesslib_clear_all_caches_for_unit_testing();
// Prepare a policy document with some versions.
list($policy1, $policy2, $policy3) = $this->create_versions(3);
// Normally users do not have access to revoke policies.
$this->setUser($user);
$this->assertFalse(api::can_revoke_policies($user->id));
$this->setUser($child);
$this->assertFalse(api::can_revoke_policies($child->id));
// The parent can revoke the policy on behalf of her child (but not her own policies).
$this->setUser($parent);
$this->assertFalse(api::can_revoke_policies($parent->id));
$this->assertTrue(api::can_revoke_policies($child->id));
// Officers and managers can revoke everything.
$this->setUser($officer);
$this->assertTrue(api::can_revoke_policies($officer->id));
$this->assertTrue(api::can_revoke_policies($child->id));
$this->assertTrue(api::can_revoke_policies($parent->id));
$this->assertTrue(api::can_revoke_policies($manager->id));
$this->setUser($manager);
$this->assertTrue(api::can_revoke_policies($manager->id));
$this->assertTrue(api::can_revoke_policies($child->id));
$this->assertTrue(api::can_revoke_policies($parent->id));
$this->assertTrue(api::can_revoke_policies($officer->id));
}
/**
* Test {@link api::fix_revision_values()} behaviour.
*/

View File

@ -58,12 +58,12 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I navigate to "Privacy and policies > Manage policies" in site administration
And I click on "1 of 4 (25%)" "link" in the "This site policy" "table_row"
And I click on "Not agreed" "link" in the "User One" "table_row"
Then I should see "Consent details"
Then I should see "Agree on behalf of the user"
And I should see "User One"
And I should see "This site policy"
And I should see "I acknowledge that consents to these policies have been acquired"
And I should see "I acknowledge that I have received the user's request to consent on the abovementioned policy on behalf of the user."
And I set the field "Remarks" to "Consent received from a parent"
And I press "I agree to the policy"
And I press "Agree"
And "Agreed on behalf of" "icon" should exist in the "User One" "table_row"
And "Max Manager" "link" should exist in the "User One" "table_row"
And "Consent received from a parent" "text" should exist in the "User One" "table_row"
@ -83,12 +83,12 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I navigate to "Privacy and policies > Manage policies" in site administration
And I click on "1 of 4 (25%)" "link" in the "This site policy" "table_row"
And I click on "Not agreed" "link" in the "User One" "table_row"
Then I should see "Consent details"
Then I should see "Agree on behalf of the user"
And I should see "User One"
And I should see "This site policy"
And I should see "I acknowledge that consents to these policies have been acquired"
And I should see "I acknowledge that I have received the user's request to consent on the abovementioned policy on behalf of the user."
And I set the field "Remarks" to "Consent received from a parent"
And I press "I agree to the policy"
And I press "Agree"
And "Agreed on behalf of" "icon" should exist in the "User One" "table_row"
And "Max Manager" "link" should exist in the "User One" "table_row"
And "Consent received from a parent" "text" should exist in the "User One" "table_row"
@ -150,12 +150,12 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I press "Next"
And I navigate to "Privacy and policies > User agreements" in site administration
And I click on "Not agreed, click to agree to \"This site policy\"" "link" in the "User One" "table_row"
Then I should see "Consent details"
Then I should see "Agree on behalf of the user"
And I should see "User One"
And I should see "This site policy"
And I should see "I acknowledge that consents to these policies have been acquired"
And I should see "I acknowledge that I have received the user's request to consent on the abovementioned policy on behalf of the user."
And I set the field "Remarks" to "Consent received from a parent"
And I press "I agree to the policy"
And I press "Agree"
And "Agreed on behalf of" "icon" should exist in the "User One" "table_row"
And "Not agreed, click to agree to \"This privacy policy\"" "icon" should exist in the "User One" "table_row"
And I click on "1 of 2" "link" in the "User One" "table_row"
@ -183,12 +183,12 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I press "Next"
And I navigate to "Privacy and policies > User agreements" in site administration
And I click on "Not agreed, click to agree to \"This site policy\"" "link" in the "User One" "table_row"
Then I should see "Consent details"
Then I should see "Agree on behalf of the user"
And I should see "User One"
And I should see "This site policy"
And I should see "I acknowledge that consents to these policies have been acquired"
And I should see "I acknowledge that I have received the user's request to consent on the abovementioned policy on behalf of the user."
And I set the field "Remarks" to "Consent received from a parent"
And I press "I agree to the policy"
And I press "Agree"
And "Agreed on behalf of" "icon" should exist in the "User One" "table_row"
And "Not agreed, click to agree to \"This privacy policy\"" "icon" should exist in the "User One" "table_row"
And I click on "1 of 2" "link" in the "User One" "table_row"
@ -248,12 +248,12 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I navigate to "Privacy and policies > Manage policies" in site administration
And I click on "1 of 4 (25%)" "link" in the "This site policy" "table_row"
And I click on "Not agreed" "link" in the "User One" "table_row"
Then I should see "Consent details"
Then I should see "Agree on behalf of the user"
And I should see "User One"
And I should see "This site policy"
And I should see "I acknowledge that consents to these policies have been acquired"
And I should see "I acknowledge that I have received the user's request to consent on the abovementioned policy on behalf of the user."
And I set the field "Remarks" to "Consent received from a parent"
And I press "I agree to the policy"
And I press "Agree"
And "Agreed on behalf of" "icon" should exist in the "User One" "table_row"
And "Max Manager" "link" should not exist in the "User One" "table_row"
And "Admin User" "link" should exist in the "User One" "table_row"