diff --git a/admin/tool/dataprivacy/classes/api.php b/admin/tool/dataprivacy/classes/api.php index 454731965fe..4cff2c13b39 100644 --- a/admin/tool/dataprivacy/classes/api.php +++ b/admin/tool/dataprivacy/classes/api.php @@ -786,6 +786,18 @@ class api { return true; } + /** + * Check if user has permission to create data download request for themselves + * + * @param int|null $userid + * @return bool + */ + public static function can_create_data_download_request_for_self(int $userid = null): bool { + global $USER; + $userid = $userid ?: $USER->id; + return has_capability('tool/dataprivacy:downloadownrequest', \context_user::instance($userid), $userid); + } + /** * Check if user has permisson to create data deletion request for themselves. * @@ -847,7 +859,7 @@ class api { $usercontext = \context_user::instance($userid); // If it's your own and you have the right capability, you can download it. - if ($userid == $downloaderid && has_capability('tool/dataprivacy:downloadownrequest', $usercontext, $downloaderid)) { + if ($userid == $downloaderid && self::can_create_data_download_request_for_self($downloaderid)) { return true; } // If you can download anyone's in that context, you can download it. diff --git a/admin/tool/dataprivacy/createdatarequest.php b/admin/tool/dataprivacy/createdatarequest.php index a81df118777..c9589871596 100644 --- a/admin/tool/dataprivacy/createdatarequest.php +++ b/admin/tool/dataprivacy/createdatarequest.php @@ -96,6 +96,11 @@ if ($data = $mform->get_data()) { throw new moodle_exception('nopermissions', 'error', '', get_string('errorcannotrequestdeleteforother', 'tool_dataprivacy')); } + } else if ($data->type == \tool_dataprivacy\api::DATAREQUEST_TYPE_EXPORT) { + if ($data->userid == $USER->id && !\tool_dataprivacy\api::can_create_data_download_request_for_self()) { + throw new moodle_exception('nopermissions', 'error', '', + get_string('errorcannotrequestexportforself', 'tool_dataprivacy')); + } } \tool_dataprivacy\api::create_data_request($data->userid, $data->type, $data->comments); diff --git a/admin/tool/dataprivacy/createdatarequest_form.php b/admin/tool/dataprivacy/createdatarequest_form.php index af2f3aabf11..d02cebee98b 100644 --- a/admin/tool/dataprivacy/createdatarequest_form.php +++ b/admin/tool/dataprivacy/createdatarequest_form.php @@ -97,10 +97,11 @@ class tool_dataprivacy_data_request_form extends \core\form\persistent { $mform->setType('userid', PARAM_INT); // Subject access request type. - $options = [ - api::DATAREQUEST_TYPE_EXPORT => get_string('requesttypeexport', 'tool_dataprivacy'), - api::DATAREQUEST_TYPE_DELETE => get_string('requesttypedelete', 'tool_dataprivacy') - ]; + $options = []; + if ($this->manage || api::can_create_data_download_request_for_self()) { + $options[api::DATAREQUEST_TYPE_EXPORT] = get_string('requesttypeexport', 'tool_dataprivacy'); + } + $options[api::DATAREQUEST_TYPE_DELETE] = get_string('requesttypedelete', 'tool_dataprivacy'); $mform->addElement('select', 'type', get_string('requesttype', 'tool_dataprivacy'), $options); $mform->addHelpButton('type', 'requesttype', 'tool_dataprivacy'); @@ -174,7 +175,7 @@ class tool_dataprivacy_data_request_form extends \core\form\persistent { $errors['type'] = get_string('errorrequestalreadyexists', 'tool_dataprivacy'); } - // Check if current user can create data deletion request. + // Check if current user can create data requests. if ($data->type == api::DATAREQUEST_TYPE_DELETE) { if ($userid == $USER->id) { if (!api::can_create_data_deletion_request_for_self()) { @@ -184,6 +185,10 @@ class tool_dataprivacy_data_request_form extends \core\form\persistent { && !api::can_create_data_deletion_request_for_children($userid)) { $errors['type'] = get_string('errorcannotrequestdeleteforother', 'tool_dataprivacy'); } + } else if ($data->type == api::DATAREQUEST_TYPE_EXPORT) { + if ($userid == $USER->id && !api::can_create_data_download_request_for_self()) { + $errors['type'] = get_string('errorcannotrequestexportforself', 'tool_dataprivacy'); + } } return $errors; diff --git a/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php b/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php index bdc47afdddf..4a8e3ff279f 100644 --- a/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php +++ b/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php @@ -135,6 +135,7 @@ $string['effectiveretentionperioduser'] = '{$a} (since the last time the user ac $string['emailsalutation'] = 'Dear {$a},'; $string['errorcannotrequestdeleteforself'] = 'You don\'t have permission to create deletion request for yourself.'; $string['errorcannotrequestdeleteforother'] = 'You don\'t have permission to create deletion request for this user.'; +$string['errorcannotrequestexportforself'] = 'You don\'t have permission to create export request for yourself.'; $string['errorcontactdpodisabled'] = 'The option to contact the privacy officer is disabled.'; $string['errorinvalidrequestcomments'] = 'The comments field may contain plain text only.'; $string['errorinvalidrequestcreationmethod'] = 'Invalid request creation method!'; diff --git a/admin/tool/dataprivacy/lib.php b/admin/tool/dataprivacy/lib.php index 25091fddf8c..0ef70eb8880 100644 --- a/admin/tool/dataprivacy/lib.php +++ b/admin/tool/dataprivacy/lib.php @@ -68,8 +68,9 @@ function tool_dataprivacy_myprofile_navigation(tree $tree, $user, $iscurrentuser // Check if the user has an ongoing data export request. $hasexportrequest = \tool_dataprivacy\api::has_ongoing_request($user->id, \tool_dataprivacy\api::DATAREQUEST_TYPE_EXPORT); - // Show data export link only if the user doesn't have an ongoing data export request. - if (!$hasexportrequest) { + // Show data export link only if the user doesn't have an ongoing data export request and has permission + // to download own data. + if (!$hasexportrequest && \tool_dataprivacy\api::can_create_data_download_request_for_self()) { $exportparams = ['type' => \tool_dataprivacy\api::DATAREQUEST_TYPE_EXPORT]; $exporturl = new moodle_url('/admin/tool/dataprivacy/createdatarequest.php', $exportparams); $exportnode = new core_user\output\myprofile\node('privacyandpolicies', 'requestdataexport', diff --git a/admin/tool/dataprivacy/tests/api_test.php b/admin/tool/dataprivacy/tests/api_test.php index 840d64fcad2..733d27c9d2b 100644 --- a/admin/tool/dataprivacy/tests/api_test.php +++ b/admin/tool/dataprivacy/tests/api_test.php @@ -26,6 +26,7 @@ use tool_dataprivacy\task\process_data_request_task; * API tests. * * @package tool_dataprivacy + * @covers \tool_dataprivacy\api * @copyright 2018 Jun Pataleta * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -2174,6 +2175,27 @@ class api_test extends \advanced_testcase { return $request; } + /** + * Test whether user can create data download request for themselves + */ + public function test_can_create_data_download_request_for_self(): void { + global $DB; + + $this->resetAfterTest(); + + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + + // The default user role allows for the creation of download data requests. + $this->assertTrue(api::can_create_data_download_request_for_self()); + + // Prohibit that capability. + $userrole = $DB->get_field('role', 'id', ['shortname' => 'user'], MUST_EXIST); + assign_capability('tool/dataprivacy:downloadownrequest', CAP_PROHIBIT, $userrole, \context_user::instance($user->id)); + + $this->assertFalse(api::can_create_data_download_request_for_self()); + } + /** * Test user cannot create data deletion request for themselves if they don't have * "tool/dataprivacy:requestdelete" capability. diff --git a/admin/tool/dataprivacy/upgrade.txt b/admin/tool/dataprivacy/upgrade.txt new file mode 100644 index 00000000000..e96eb68a0a7 --- /dev/null +++ b/admin/tool/dataprivacy/upgrade.txt @@ -0,0 +1,6 @@ +This file describes API changes in /admin/tool/dataprivacy/* +Information provided here is intended especially for developers. + +=== 4.1 === +* New `api::can_create_data_download_request_for_self` method for determining whether user has permission to create their + own data download requests