diff --git a/admin/tool/dataprivacy/classes/api.php b/admin/tool/dataprivacy/classes/api.php index 9f1177f0ce0..2c18ac713d0 100644 --- a/admin/tool/dataprivacy/classes/api.php +++ b/admin/tool/dataprivacy/classes/api.php @@ -1087,12 +1087,16 @@ class api { // Create the approved contextlist collection object. $approvedcollection = new contextlist_collection($collection->get_userid()); + $isconfigured = data_registry::defaults_set(); foreach ($collection as $contextlist) { $contextids = []; foreach ($contextlist as $context) { - if (self::DATAREQUEST_TYPE_DELETE == $type) { + if ($isconfigured && self::DATAREQUEST_TYPE_DELETE == $type) { // Data can only be deleted from it if the context is either expired, or unprotected. + // Note: We can only check whether a context is expired or unprotected if the site is configured and + // defaults are set appropriately. If they are not, we treat all contexts as though they are + // unprotected. $purpose = static::get_effective_context_purpose($context); if (!expired_contexts_manager::is_context_expired_or_unprotected_for_user($context, $foruser)) { continue; diff --git a/admin/tool/dataprivacy/classes/task/process_data_request_task.php b/admin/tool/dataprivacy/classes/task/process_data_request_task.php index f3f87a221d5..7b9fad33b0d 100644 --- a/admin/tool/dataprivacy/classes/task/process_data_request_task.php +++ b/admin/tool/dataprivacy/classes/task/process_data_request_task.php @@ -74,11 +74,9 @@ class process_data_request_task extends adhoc_task { return; } - // If no site purpose is defined, reject requests since they cannot be processed. if (!\tool_dataprivacy\data_registry::defaults_set()) { - api::update_request_status($requestid, api::DATAREQUEST_STATUS_REJECTED); - mtrace('No site purpose defined. Request ' . $requestid . ' rejected.'); - return; + // Warn if no site purpose is defined. + mtrace('Warning: No purpose is defined at the system level. Deletion will delete all.'); } // Grab the manager. diff --git a/admin/tool/dataprivacy/datarequests.php b/admin/tool/dataprivacy/datarequests.php index ec6b9c2b1c5..331dd1960df 100644 --- a/admin/tool/dataprivacy/datarequests.php +++ b/admin/tool/dataprivacy/datarequests.php @@ -38,6 +38,10 @@ $title = get_string('datarequests', 'tool_dataprivacy'); echo $OUTPUT->header(); echo $OUTPUT->heading($title); +if (!\tool_dataprivacy\data_registry::defaults_set()) { + \core\notification::error(get_string('systemconfignotsetwarning', 'tool_dataprivacy')); +} + if (\tool_dataprivacy\api::is_site_dpo($USER->id)) { $filtersapplied = optional_param_array('request-filters', [-1], PARAM_NOTAGS); $filterscleared = optional_param('filters-cleared', 0, PARAM_INT); diff --git a/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php b/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php index 96fa63b0a03..86b1799db44 100644 --- a/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php +++ b/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php @@ -307,6 +307,7 @@ $string['statusrejected'] = 'Rejected'; $string['subjectscope'] = 'Subject scope'; $string['subjectscope_help'] = 'The subject scope lists the roles which may be assigned in this context.'; $string['summary'] = 'Registry configuration summary'; +$string['systemconfignotsetwarning'] = 'A site purpose and category have not been defined. When these are not defined, all data will be removed when processing deletion requests.'; $string['user'] = 'User'; $string['userlistnoncompliant'] = 'Userlist provider missing'; $string['userlistexplanation'] = 'This plugin has the base provider but should also implement the userlist provider for full support of privacy functionality.'; diff --git a/admin/tool/dataprivacy/tests/api_test.php b/admin/tool/dataprivacy/tests/api_test.php index e9bd9f50d33..8e60223b96e 100644 --- a/admin/tool/dataprivacy/tests/api_test.php +++ b/admin/tool/dataprivacy/tests/api_test.php @@ -1635,6 +1635,48 @@ class tool_dataprivacy_api_testcase extends advanced_testcase { ]; } + /** + * Test that delete requests do not filter out protected purpose contexts if the the site is properly configured. + */ + public function test_get_approved_contextlist_collection_for_collection_delete_course_no_site_config() { + $this->resetAfterTest(); + + $user = $this->getDataGenerator()->create_user(); + + $course = $this->getDataGenerator()->create_course(['startdate' => time() - YEARSECS, 'enddate' => time() - YEARSECS]); + $coursecontext = \context_course::instance($course->id); + + $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]); + list(, $forumcm) = get_course_and_cm_from_instance($forum->id, 'forum'); + $contextforum = \context_module::instance($forumcm->id); + + $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); + + // Create the initial contextlist. + $initialcollection = new \core_privacy\local\request\contextlist_collection($user->id); + + $contextlist = new \core_privacy\local\request\contextlist(); + $contextlist->add_from_sql('SELECT id FROM {context} WHERE id = :contextid', ['contextid' => $coursecontext->id]); + $contextlist->set_component('tool_dataprivacy'); + $initialcollection->add_contextlist($contextlist); + + $contextlist = new \core_privacy\local\request\contextlist(); + $contextlist->add_from_sql('SELECT id FROM {context} WHERE id = :contextid', ['contextid' => $contextforum->id]); + $contextlist->set_component('mod_forum'); + $initialcollection->add_contextlist($contextlist); + + $collection = api::get_approved_contextlist_collection_for_collection( + $initialcollection, $user, api::DATAREQUEST_TYPE_DELETE); + + $this->assertCount(2, $collection); + + $list = $collection->get_contextlist_for_component('tool_dataprivacy'); + $this->assertCount(1, $list); + + $list = $collection->get_contextlist_for_component('mod_forum'); + $this->assertCount(1, $list); + } + /** * Test that delete requests do not filter out protected purpose contexts if they are already expired. */