Skip to content

Commit

Permalink
MDL-66752 tool_dataprivacy: Add automatic data request approval feature
Browse files Browse the repository at this point in the history
  • Loading branch information
junpataleta committed Jan 6, 2020
1 parent a6b2363 commit 12c1e8b
Show file tree
Hide file tree
Showing 12 changed files with 293 additions and 41 deletions.
66 changes: 59 additions & 7 deletions admin/tool/dataprivacy/classes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,20 @@ public static function create_data_request($foruser, $type, $comments = '',
// The user making the request.
$datarequest->set('requestedby', $requestinguser);
// Set status.
$datarequest->set('status', self::DATAREQUEST_STATUS_AWAITING_APPROVAL);
$status = self::DATAREQUEST_STATUS_AWAITING_APPROVAL;
if (self::is_automatic_request_approval_on($type)) {
// Set status to approved if automatic data request approval is enabled.
$status = self::DATAREQUEST_STATUS_APPROVED;
// Set the privacy officer field if the one making the data request is a privacy officer.
if (self::is_site_dpo($requestinguser)) {
$datarequest->set('dpo', $requestinguser);
}
// Mark this request as system approved.
$datarequest->set('systemapproved', true);
// No need to notify privacy officer(s) about automatically approved data requests.
$notify = false;
}
$datarequest->set('status', $status);
// Set request type.
$datarequest->set('type', $type);
// Set request comments.
Expand All @@ -269,13 +282,22 @@ public static function create_data_request($foruser, $type, $comments = '',
// Store subject access request.
$datarequest->create();

// Queue the ad-hoc task for automatically approved data requests.
if ($status == self::DATAREQUEST_STATUS_APPROVED) {
$userid = null;
if ($type == self::DATAREQUEST_TYPE_EXPORT) {
$userid = $foruser;
}
self::queue_data_request_task($datarequest->get('id'), $userid);
}

if ($notify) {
// Get the list of the site Data Protection Officers.
$dpos = api::get_site_dpos();
$dpos = self::get_site_dpos();

// Email the data request to the Data Protection Officer(s)/Admin(s).
foreach ($dpos as $dpo) {
api::notify_dpo($dpo, $datarequest);
self::notify_dpo($dpo, $datarequest);
}
}

Expand Down Expand Up @@ -624,12 +646,11 @@ public static function approve_data_request($requestid) {
$result = self::update_request_status($requestid, self::DATAREQUEST_STATUS_APPROVED, $USER->id);

// Fire an ad hoc task to initiate the data request process.
$task = new process_data_request_task();
$task->set_custom_data(['requestid' => $requestid]);
$userid = null;
if ($request->get('type') == self::DATAREQUEST_TYPE_EXPORT) {
$task->set_userid($request->get('userid'));
$userid = $request->get('userid');
}
manager::queue_adhoc_task($task, true);
self::queue_data_request_task($requestid, $userid);

return $result;
}
Expand Down Expand Up @@ -1277,4 +1298,35 @@ public static function format_retention_period(\DateInterval $interval) : string

return $formattedtime;
}

/**
* Whether automatic data request approval is turned on or not for the given request type.
*
* @param int $type The request type.
* @return bool
*/
public static function is_automatic_request_approval_on(int $type): bool {
switch ($type) {
case self::DATAREQUEST_TYPE_EXPORT:
return !empty(get_config('tool_dataprivacy', 'automaticdataexportapproval'));
case self::DATAREQUEST_TYPE_DELETE:
return !empty(get_config('tool_dataprivacy', 'automaticdatadeletionapproval'));
}
return false;
}

/**
* Creates an ad-hoc task for the data request.
*
* @param int $requestid The data request ID.
* @param int $userid Optional. The user ID to run the task as, if necessary.
*/
public static function queue_data_request_task(int $requestid, int $userid = null): void {
$task = new process_data_request_task();
$task->set_custom_data(['requestid' => $requestid]);
if ($userid) {
$task->set_userid($userid);
}
manager::queue_adhoc_task($task, true);
}
}
4 changes: 4 additions & 0 deletions admin/tool/dataprivacy/classes/data_request.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ protected static function define_properties() {
'type' => PARAM_INT,
'default' => FORMAT_PLAIN
],
'systemapproved' => [
'default' => false,
'type' => PARAM_BOOL,
],
'creationmethod' => [
'default' => self::DATAREQUEST_CREATION_MANUAL,
'choices' => [
Expand Down
18 changes: 12 additions & 6 deletions admin/tool/dataprivacy/classes/task/process_data_request_task.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,20 @@ public function execute() {
mtrace('The processing of the user data request has been completed...');

// Create message to notify the user regarding the processing results.
$dpo = core_user::get_user($request->dpo);
$message = new message();
$message->courseid = $SITE->id;
$message->component = 'tool_dataprivacy';
$message->name = 'datarequestprocessingresults';
$message->userfrom = $dpo;
$message->replyto = $dpo->email;
$message->replytoname = fullname($dpo);
if (empty($request->dpo)) {
// Use the no-reply user as the sender if the privacy officer is not set. This is the case for automatically
// approved requests.
$fromuser = core_user::get_noreply_user();
} else {
$fromuser = core_user::get_user($request->dpo);
$message->replyto = $fromuser->email;
$message->replytoname = fullname($fromuser);
}
$message->userfrom = $fromuser;

$typetext = null;
// Prepare the context data for the email message body.
Expand Down Expand Up @@ -219,7 +225,7 @@ public function execute() {
if ($emailonly) {
// 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);
$messagesent = email_to_user($foruser, $fromuser, $subject, $message->fullmessage, $messagehtml);
}
} else {
$messagesent = message_send($message);
Expand Down Expand Up @@ -265,7 +271,7 @@ public function execute() {

// Send message.
if ($emailonly) {
email_to_user($requestedby, $dpo, $subject, $message->fullmessage, $messagehtml);
email_to_user($requestedby, $fromuser, $subject, $message->fullmessage, $messagehtml);
} else {
message_send($message);
}
Expand Down
4 changes: 4 additions & 0 deletions admin/tool/dataprivacy/createdatarequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@
if ($manage) {
$foruser = core_user::get_user($data->userid);
$redirectmessage = get_string('datarequestcreatedforuser', 'tool_dataprivacy', fullname($foruser));
} else if (\tool_dataprivacy\api::is_automatic_request_approval_on($data->type)) {
// Let the user know that the request has been submitted and will be processed soon.
$redirectmessage = get_string('approvedrequestsubmitted', 'tool_dataprivacy');
} else {
// Let the user know that the request has been submitted to the privacy officer.
$redirectmessage = get_string('requestsubmitted', 'tool_dataprivacy');
}
redirect($returnurl, $redirectmessage);
Expand Down
3 changes: 2 additions & 1 deletion admin/tool/dataprivacy/db/install.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="admin/tool/dataprivacy/db" VERSION="20181107" COMMENT="XMLDB file for Moodle tool/dataprivacy"
<XMLDB PATH="admin/tool/dataprivacy/db" VERSION="20191217" COMMENT="XMLDB file for Moodle tool/dataprivacy"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
>
Expand All @@ -16,6 +16,7 @@
<FIELD NAME="dpo" TYPE="int" LENGTH="10" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="The user ID of the Data Protection Officer who is reviewing th request"/>
<FIELD NAME="dpocomment" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="DPO's comments (e.g. reason for rejecting the request, etc.)"/>
<FIELD NAME="dpocommentformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="systemapproved" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="usermodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The user who created/modified this request object"/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The time this data request was created"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The last time this data request was updated"/>
Expand Down
15 changes: 15 additions & 0 deletions admin/tool/dataprivacy/db/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -322,5 +322,20 @@ function xmldb_tool_dataprivacy_upgrade($oldversion) {
// Automatically generated Moodle v3.8.0 release upgrade line.
// Put any upgrade step following this.

if ($oldversion < 2019121700) {

// Define field systemapproved to be added to tool_dataprivacy_request.
$table = new xmldb_table('tool_dataprivacy_request');
$field = new xmldb_field('systemapproved', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0', 'dpocommentformat');

// Conditionally launch add field systemapproved.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}

// Dataprivacy savepoint reached.
upgrade_plugin_savepoint(true, 2019121700, 'tool', 'dataprivacy');
}

return true;
}
5 changes: 5 additions & 0 deletions admin/tool/dataprivacy/lang/en/tool_dataprivacy.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@
$string['addnewdefaults'] = 'Add a new module default';
$string['addpurpose'] = 'Add purpose';
$string['approve'] = 'Approve';
$string['approvedrequestsubmitted'] = 'Your request has been submitted and will be processed soon';
$string['approverequest'] = 'Approve request';
$string['automaticdatadeletionapproval'] = 'Automatic data deletion request approval';
$string['automaticdatadeletionapproval_desc'] = 'If enabled, data deletion requests are automatically approved.<br/>Note that the automatic approval will only apply to new data deletion requests with this setting enabled. Existing data deletion requests pending approval will still have to be manually approved by the privacy officer.';
$string['automaticdataexportapproval'] = 'Automatic data export request approval';
$string['automaticdataexportapproval_desc'] = 'If enabled, data export requests are automatically approved.<br/>Note that the automatic approval will only apply to new data export requests with this setting enabled. Existing data export requests pending approval will still have to be manually approved by the privacy officer.';
$string['automaticdeletionrequests'] = 'Create automatic data deletion requests';
$string['automaticdeletionrequests_desc'] = 'If enabled, a data deletion request will be created automatically for any user accounts deleted manually.';
$string['bulkapproverequests'] = 'Approve requests';
Expand Down
10 changes: 10 additions & 0 deletions admin/tool/dataprivacy/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@
new lang_string('contactdataprotectionofficer_desc', 'tool_dataprivacy'), 0)
);

$privacysettings->add(new admin_setting_configcheckbox('tool_dataprivacy/automaticdataexportapproval',
new lang_string('automaticdataexportapproval', 'tool_dataprivacy'),
new lang_string('automaticdataexportapproval_desc', 'tool_dataprivacy'), 0)
);

$privacysettings->add(new admin_setting_configcheckbox('tool_dataprivacy/automaticdatadeletionapproval',
new lang_string('automaticdatadeletionapproval', 'tool_dataprivacy'),
new lang_string('automaticdatadeletionapproval_desc', 'tool_dataprivacy'), 0)
);

// Automatically create delete data request for users upon user deletion.
// Automatically create delete data request for pre-existing deleted users.
// Enabled by default.
Expand Down
Loading

0 comments on commit 12c1e8b

Please sign in to comment.