diff --git a/admin/tool/dataprivacy/classes/api.php b/admin/tool/dataprivacy/classes/api.php
index e73a34c0e79..10889a915ec 100644
--- a/admin/tool/dataprivacy/classes/api.php
+++ b/admin/tool/dataprivacy/classes/api.php
@@ -227,25 +227,24 @@ class api {
* @param int $foruser The user whom the request is being made for.
* @param int $type The request type.
* @param string $comments Request comments.
+ * @param int $creationmethod The creation method of the data request.
* @return data_request
* @throws invalid_persistent_exception
* @throws coding_exception
*/
- public static function create_data_request($foruser, $type, $comments = '') {
- global $USER;
+ public static function create_data_request($foruser, $type, $comments = '',
+ $creationmethod = data_request::DATAREQUEST_CREATION_MANUAL) {
+ global $USER, $ADMIN;
$datarequest = new data_request();
// The user the request is being made for.
$datarequest->set('userid', $foruser);
- $requestinguser = $USER->id;
- // Check when the user is making a request on behalf of another.
- if ($requestinguser != $foruser) {
- if (self::is_site_dpo($requestinguser)) {
- // The user making the request is a DPO. Should be fine.
- $datarequest->set('dpo', $requestinguser);
- }
- }
+ // The cron is considered to be a guest user when it creates a data request.
+ // NOTE: This should probably be changed. We should leave the default value for $requestinguser if
+ // the request is not explicitly created by a specific user.
+ $requestinguser = (isguestuser() && $creationmethod == data_request::DATAREQUEST_CREATION_AUTO) ?
+ $ADMIN->id : $USER->id;
// The user making the request.
$datarequest->set('requestedby', $requestinguser);
// Set status.
diff --git a/admin/tool/dataprivacy/classes/data_request.php b/admin/tool/dataprivacy/classes/data_request.php
index 92c8c1ff243..997642261fa 100644
--- a/admin/tool/dataprivacy/classes/data_request.php
+++ b/admin/tool/dataprivacy/classes/data_request.php
@@ -37,6 +37,12 @@ class data_request extends persistent {
/** The table name this persistent object maps to. */
const TABLE = 'tool_dataprivacy_request';
+ /** Data request created manually. */
+ const DATAREQUEST_CREATION_MANUAL = 0;
+
+ /** Data request created automatically. */
+ const DATAREQUEST_CREATION_AUTO = 1;
+
/**
* Return the definition of the properties of this model.
*
@@ -111,6 +117,14 @@ class data_request extends persistent {
'type' => PARAM_INT,
'default' => FORMAT_PLAIN
],
+ 'creationmethod' => [
+ 'default' => self::DATAREQUEST_CREATION_MANUAL,
+ 'choices' => [
+ self::DATAREQUEST_CREATION_MANUAL,
+ self::DATAREQUEST_CREATION_AUTO
+ ],
+ 'type' => PARAM_INT
+ ],
];
}
diff --git a/admin/tool/dataprivacy/classes/task/delete_existing_deleted_users.php b/admin/tool/dataprivacy/classes/task/delete_existing_deleted_users.php
new file mode 100644
index 00000000000..a0787477ea1
--- /dev/null
+++ b/admin/tool/dataprivacy/classes/task/delete_existing_deleted_users.php
@@ -0,0 +1,88 @@
+.
+
+/**
+ * Scheduled task to create delete data request for pre-existing deleted users.
+ *
+ * @package tool_dataprivacy
+ * @copyright 2018 Mihail Geshoski
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_dataprivacy\task;
+
+use core\task\scheduled_task;
+use tool_dataprivacy\api;
+use tool_dataprivacy\data_request;
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/dataprivacy/lib.php');
+
+/**
+ * Scheduled task to create delete data request for pre-existing deleted users.
+ *
+ * @package tool_dataprivacy
+ * @copyright 2018 Mihail Geshoski
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class delete_existing_deleted_users extends scheduled_task {
+
+ /**
+ * Returns the task name.
+ *
+ * @return string
+ */
+ public function get_name() {
+ return get_string('deleteexistingdeleteduserstask', 'tool_dataprivacy');
+ }
+
+ /**
+ * Run the task to delete expired data request files and update request statuses.
+ *
+ */
+ public function execute() {
+ global $DB;
+
+ // Select all deleted users that do not have any delete data requests created for them.
+ $sql = "SELECT DISTINCT(u.id)
+ FROM {user} u
+ LEFT JOIN {tool_dataprivacy_request} r
+ ON u.id = r.userid
+ WHERE u.deleted = ?
+ AND (r.id IS NULL
+ OR r.type != ?)";
+
+ $params = [
+ 1,
+ api::DATAREQUEST_TYPE_DELETE
+ ];
+
+ $deletedusers = $DB->get_records_sql($sql, $params);
+ $createdrequests = 0;
+
+ foreach ($deletedusers as $user) {
+ api::create_data_request($user->id, api::DATAREQUEST_TYPE_DELETE,
+ get_string('datarequestcreatedfromscheduledtask', 'tool_dataprivacy'),
+ data_request::DATAREQUEST_CREATION_AUTO);
+ $createdrequests++;
+ }
+
+ if ($createdrequests > 0) {
+ mtrace($createdrequests . ' delete data request(s) created for existing deleted users');
+ }
+ }
+}
diff --git a/admin/tool/dataprivacy/classes/task/initiate_data_request_task.php b/admin/tool/dataprivacy/classes/task/initiate_data_request_task.php
index 70402f48f4b..d35f9176ef9 100644
--- a/admin/tool/dataprivacy/classes/task/initiate_data_request_task.php
+++ b/admin/tool/dataprivacy/classes/task/initiate_data_request_task.php
@@ -70,27 +70,6 @@ class initiate_data_request_task extends adhoc_task {
return;
}
- $requestedby = $datarequest->get('requestedby');
- $valid = true;
- $comment = '';
- $foruser = $datarequest->get('userid');
- if ($foruser != $requestedby) {
- if (!$valid = api::can_create_data_request_for_user($foruser, $requestedby)) {
- $params = (object)[
- 'requestedby' => $requestedby,
- 'userid' => $foruser
- ];
- $comment = get_string('errornocapabilitytorequestforothers', 'tool_dataprivacy', $params);
- mtrace($comment);
- }
- }
- // Reject the request outright if it's invalid.
- if (!$valid) {
- $dpo = $datarequest->get('dpo');
- api::update_request_status($requestid, api::DATAREQUEST_STATUS_REJECTED, $dpo, $comment);
- return;
- }
-
// Update the status of this request as pre-processing.
mtrace('Generating the contexts containing personal data for the user...');
api::update_request_status($requestid, api::DATAREQUEST_STATUS_PREPROCESSING);
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 c44b661d97f..802f61af70d 100644
--- a/admin/tool/dataprivacy/classes/task/process_data_request_task.php
+++ b/admin/tool/dataprivacy/classes/task/process_data_request_task.php
@@ -76,7 +76,6 @@ class process_data_request_task extends adhoc_task {
// Get the user details now. We might not be able to retrieve it later if it's a deletion processing.
$foruser = core_user::get_user($request->userid);
- $usercontext = \context_user::instance($foruser->id);
// Update the status of this request as pre-processing.
mtrace('Processing request...');
@@ -84,6 +83,14 @@ class process_data_request_task extends adhoc_task {
$completestatus = api::DATAREQUEST_STATUS_COMPLETE;
if ($request->type == api::DATAREQUEST_TYPE_EXPORT) {
+ // Get the user context.
+ $usercontext = \context_user::instance($foruser->id, IGNORE_MISSING);
+ if (!$usercontext) {
+ mtrace("Request {$requestid} cannot be processed due to a missing user context instance for the user
+ with ID {$foruser->id}. Skipping...");
+ return;
+ }
+
// Get the collection of approved_contextlist objects needed for core_privacy data export.
$approvedclcollection = api::get_approved_contextlist_collection_for_request($requestpersistent);
@@ -191,12 +198,19 @@ class process_data_request_task extends adhoc_task {
// Send message to the user involved.
if ($notifyuser) {
+ $messagesent = false;
if ($emailonly) {
- email_to_user($foruser, $dpo, $subject, $message->fullmessage, $messagehtml);
+ // Do not sent an email if the user has been deleted. The user email has been previously deleted.
+ if (!$foruser->deleted) {
+ $messagesent = email_to_user($foruser, $dpo, $subject, $message->fullmessage, $messagehtml);
+ }
} else {
- message_send($message);
+ $messagesent = message_send($message);
+ }
+
+ if ($messagesent) {
+ mtrace('Message sent to user: ' . $messagetextdata['username']);
}
- mtrace('Message sent to user: ' . $messagetextdata['username']);
}
// Send to requester as well in some circumstances.
diff --git a/admin/tool/dataprivacy/db/install.xml b/admin/tool/dataprivacy/db/install.xml
index e3402693b8f..2d4a01a9591 100644
--- a/admin/tool/dataprivacy/db/install.xml
+++ b/admin/tool/dataprivacy/db/install.xml
@@ -19,6 +19,7 @@
+
diff --git a/admin/tool/dataprivacy/db/tasks.php b/admin/tool/dataprivacy/db/tasks.php
index 5ee3a19aa17..e3bedd695ab 100644
--- a/admin/tool/dataprivacy/db/tasks.php
+++ b/admin/tool/dataprivacy/db/tasks.php
@@ -50,5 +50,13 @@ $tasks = array(
'day' => '*',
'dayofweek' => '*',
'month' => '*'
+ ), array(
+ 'classname' => 'tool_dataprivacy\task\delete_existing_deleted_users',
+ 'blocking' => 0,
+ 'minute' => 'R',
+ 'hour' => 'R',
+ 'day' => '*',
+ 'dayofweek' => '*',
+ 'month' => '*'
),
);
diff --git a/admin/tool/dataprivacy/db/upgrade.php b/admin/tool/dataprivacy/db/upgrade.php
index a5c3d2170b4..1ac5b3358bf 100644
--- a/admin/tool/dataprivacy/db/upgrade.php
+++ b/admin/tool/dataprivacy/db/upgrade.php
@@ -265,5 +265,17 @@ function xmldb_tool_dataprivacy_upgrade($oldversion) {
upgrade_plugin_savepoint(true, 2017111354, 'tool', 'dataprivacy');
}
+ if ($oldversion < 2017111356) {
+ // Define field sensitivedatareasons to be added to tool_dataprivacy_purpose.
+ $table = new xmldb_table('tool_dataprivacy_request');
+ $field = new xmldb_field('creationmethod', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, 0, 'timemodified');
+ // Conditionally launch add field sensitivedatareasons.
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+ // Dataprivacy savepoint reached.
+ upgrade_plugin_savepoint(true, 2017111356, 'tool', 'dataprivacy');
+ }
+
return true;
}
diff --git a/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php b/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php
index 43f4e24dc13..bd426c5d979 100644
--- a/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php
+++ b/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php
@@ -80,6 +80,7 @@ $string['dataregistryinfo'] = 'The data registry enables categories (types of da
$string['dataretentionexplanation'] = 'This summary shows the default categories and purposes for retaining user data. Certain areas may have more specific categories and purposes than those listed here.';
$string['dataretentionsummary'] = 'Data retention summary';
$string['datarequestcreatedforuser'] = 'Data request created for {$a}';
+$string['datarequestcreatedfromscheduledtask'] = 'Automatically created from a scheduled task (pre-existing deleted user).';
$string['datarequestemailsubject'] = 'Data request: {$a}';
$string['datarequests'] = 'Data requests';
$string['datecomment'] = '[{$a->date}]: ' . PHP_EOL . ' {$a->comment}';
@@ -93,6 +94,7 @@ $string['deletedefaults'] = 'Delete defaults: {$a}';
$string['deletedefaultsconfirmation'] = 'Are you sure you want to delete the default category and purpose for {$a} modules?';
$string['deleteexpiredcontextstask'] = 'Delete expired contexts';
$string['deleteexpireddatarequeststask'] = 'Delete expired data request export files';
+$string['deleteexistingdeleteduserstask'] = 'Create delete data request for pre-existing deleted users';
$string['deletemyaccount'] = 'Delete my account';
$string['deletepurpose'] = 'Delete purpose';
$string['deletepurposetext'] = 'Are you sure you want to delete the purpose \'{$a}\'?';
diff --git a/admin/tool/dataprivacy/tests/api_test.php b/admin/tool/dataprivacy/tests/api_test.php
index f0617d9aae5..ec6c171fdba 100644
--- a/admin/tool/dataprivacy/tests/api_test.php
+++ b/admin/tool/dataprivacy/tests/api_test.php
@@ -608,7 +608,6 @@ class tool_dataprivacy_api_testcase extends advanced_testcase {
$datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, $comment);
$this->assertEquals($user->id, $datarequest->get('userid'));
$this->assertEquals($USER->id, $datarequest->get('requestedby'));
- $this->assertEquals($USER->id, $datarequest->get('dpo'));
$this->assertEquals(api::DATAREQUEST_TYPE_EXPORT, $datarequest->get('type'));
$this->assertEquals(api::DATAREQUEST_STATUS_PENDING, $datarequest->get('status'));
$this->assertEquals($comment, $datarequest->get('comments'));
diff --git a/admin/tool/dataprivacy/version.php b/admin/tool/dataprivacy/version.php
index 689204cd710..04ddf6ec72c 100644
--- a/admin/tool/dataprivacy/version.php
+++ b/admin/tool/dataprivacy/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die;
-$plugin->version = 2017111355;
+$plugin->version = 2017111356;
$plugin->requires = 2017111304.00; // Moodle 3.4.4 (Build: 20180517) and upwards.
$plugin->component = 'tool_dataprivacy';