MDL-62026 tool_dataprivacy: Allow manual completion of general enquiries

This commit is contained in:
Jun Pataleta
2018-07-10 12:30:56 +08:00
parent c7d148dc20
commit ef7f7cfdf8
15 changed files with 277 additions and 87 deletions
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","tool_dataprivacy/events"],function(a,b,c,d,e,f){var g=!1,h={APPROVE_BUTTON:'[data-action="approve"]',DENY_BUTTON:'[data-action="deny"]'},i=function(a){d.call(this,a),this.getFooter().find(h.APPROVE_BUTTON).length||b.exception({message:"No approve button found"}),this.getFooter().find(h.DENY_BUTTON).length||b.exception({message:"No deny button found"})};return i.TYPE="tool_dataprivacy-data_request",i.prototype=Object.create(d.prototype),i.prototype.constructor=i,i.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this),this.getModal().on(c.events.activate,h.APPROVE_BUTTON,function(b,c){var d=a.Event(f.approve);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this)),this.getModal().on(c.events.activate,h.DENY_BUTTON,function(b,c){var d=a.Event(f.deny);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this))},g||(e.register(i.TYPE,i,"tool_dataprivacy/data_request_modal"),g=!0),i});
define(["jquery","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","tool_dataprivacy/events"],function(a,b,c,d,e,f){var g=!1,h={APPROVE_BUTTON:'[data-action="approve"]',DENY_BUTTON:'[data-action="deny"]',COMPLETE_BUTTON:'[data-action="complete"]'},i=function(a){d.call(this,a)};return i.TYPE="tool_dataprivacy-data_request",i.prototype=Object.create(d.prototype),i.prototype.constructor=i,i.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this),this.getModal().on(c.events.activate,h.APPROVE_BUTTON,function(b,c){var d=a.Event(f.approve);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this)),this.getModal().on(c.events.activate,h.DENY_BUTTON,function(b,c){var d=a.Event(f.deny);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this)),this.getModal().on(c.events.activate,h.COMPLETE_BUTTON,function(b,c){var d=a.Event(f.complete);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this))},g||(e.register(i.TYPE,i,"tool_dataprivacy/data_request_modal"),g=!0),i});
+1 -1
View File
@@ -1 +1 @@
define([],function(){return{approve:"tool_dataprivacy-data_request:approve",deny:"tool_dataprivacy-data_request:deny"}});
define([],function(){return{approve:"tool_dataprivacy-data_request:approve",deny:"tool_dataprivacy-data_request:deny",complete:"tool_dataprivacy-data_request:complete"}});
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events","core/templates","tool_dataprivacy/data_request_modal","tool_dataprivacy/events"],function(a,b,c,d,e,f,g,h,i){function j(a,g){var h=[],j="";switch(a){case i.approve:h=[{key:"approverequest",component:"tool_dataprivacy"},{key:"confirmapproval",component:"tool_dataprivacy"}],j="tool_dataprivacy_approve_data_request";break;case i.deny:h=[{key:"denyrequest",component:"tool_dataprivacy"},{key:"confirmdenial",component:"tool_dataprivacy"}],j="tool_dataprivacy_deny_data_request"}var k="";d.get_strings(h).then(function(a){k=a[0];var b=a[1];return e.create({title:k,body:b,type:e.types.SAVE_CANCEL})}).then(function(a){return a.setSaveButtonText(k),a.getRoot().on(f.save,function(){var a={requestid:g},d={methodname:j,args:a};b.call([d])[0].done(function(a){a.result?window.location.reload():c.addNotification({message:a.warnings[0].message,type:"error"})}).fail(c.exception)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a}).done(function(a){a.show()}).fail(c.exception)}var k={APPROVE_REQUEST:'[data-action="approve"]',DENY_REQUEST:'[data-action="deny"]',VIEW_REQUEST:'[data-action="view"]'},l=function(){this.registerEvents()};return l.prototype.registerEvents=function(){a(k.VIEW_REQUEST).click(function(d){d.preventDefault();var k=a(this).data("requestid"),l={requestid:k},m={methodname:"tool_dataprivacy_get_data_request",args:l},n=b.call([m]),o="",p=e.types.DEFAULT;a.when(n[0]).then(function(a){return a.result?(2==a.result.status&&(p=h.TYPE),o=a.result.typename,g.render("tool_dataprivacy/request_details",a.result)):(c.addNotification({message:a.warnings[0].message,type:"error"}),!1)}).then(function(a){return e.create({title:o,body:a,type:p,large:!0}).then(function(a){return a.getRoot().on(i.approve,function(){j(i.approve,k)}),a.getRoot().on(i.deny,function(){j(i.deny,k)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a})}).done(function(a){a.show()}).fail(c.exception)}),a(k.APPROVE_REQUEST).click(function(b){b.preventDefault();var c=a(this).data("requestid");j(i.approve,c)}),a(k.DENY_REQUEST).click(function(b){b.preventDefault();var c=a(this).data("requestid");j(i.deny,c)})},l});
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events","core/templates","tool_dataprivacy/data_request_modal","tool_dataprivacy/events"],function(a,b,c,d,e,f,g,h,i){function j(a,b){var g=[],h="",j={requestid:b};switch(a){case i.approve:g=[{key:"approverequest",component:"tool_dataprivacy"},{key:"confirmapproval",component:"tool_dataprivacy"}],h="tool_dataprivacy_approve_data_request";break;case i.deny:g=[{key:"denyrequest",component:"tool_dataprivacy"},{key:"confirmdenial",component:"tool_dataprivacy"}],h="tool_dataprivacy_deny_data_request";break;case i.complete:g=[{key:"markcomplete",component:"tool_dataprivacy"},{key:"confirmcompletion",component:"tool_dataprivacy"}],h="tool_dataprivacy_mark_complete"}var l="";d.get_strings(g).then(function(a){l=a[0];var b=a[1];return e.create({title:l,body:b,type:e.types.SAVE_CANCEL})}).then(function(a){a.setSaveButtonText(l),a.getRoot().on(f.save,function(){k(h,j)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a.show()})["catch"](c.exception)}function k(a,d){var e={methodname:a,args:d};b.call([e])[0].done(function(a){a.result?window.location.reload():c.addNotification({message:a.warnings[0].message,type:"error"})}).fail(c.exception)}var l={APPROVE_REQUEST:'[data-action="approve"]',DENY_REQUEST:'[data-action="deny"]',VIEW_REQUEST:'[data-action="view"]',MARK_COMPLETE:'[data-action="complete"]'},m=function(){this.registerEvents()};return m.prototype.registerEvents=function(){a(l.VIEW_REQUEST).click(function(d){d.preventDefault();var l=a(this).data("requestid"),m={requestid:l},n={methodname:"tool_dataprivacy_get_data_request",args:m},o=b.call([n]);a.when(o[0]).then(function(a){return a.result?a.result:(c.addNotification({message:a.warnings[0].message,type:"error"}),!1)}).then(function(a){var b=g.render("tool_dataprivacy/request_details",a),c={approvedeny:a.approvedeny,canmarkcomplete:a.canmarkcomplete};return e.create({title:a.typename,body:b,type:h.TYPE,large:!0,templateContext:c})}).then(function(a){a.getRoot().on(i.approve,function(){j(i.approve,l)}),a.getRoot().on(i.deny,function(){j(i.deny,l)}),a.getRoot().on(i.complete,function(){var a={requestid:l};k("tool_dataprivacy_mark_complete",a)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a.show()})["catch"](c.exception)}),a(l.APPROVE_REQUEST).click(function(b){b.preventDefault();var c=a(this).data("requestid");j(i.approve,c)}),a(l.DENY_REQUEST).click(function(b){b.preventDefault();var c=a(this).data("requestid");j(i.deny,c)}),a(l.MARK_COMPLETE).click(function(b){b.preventDefault(),j(i.complete,a(this).data("requestid"))})},m});
@@ -29,6 +29,7 @@ define(['jquery', 'core/notification', 'core/custom_interaction_events', 'core/m
var SELECTORS = {
APPROVE_BUTTON: '[data-action="approve"]',
DENY_BUTTON: '[data-action="deny"]',
COMPLETE_BUTTON: '[data-action="complete"]'
};
/**
@@ -38,14 +39,6 @@ define(['jquery', 'core/notification', 'core/custom_interaction_events', 'core/m
*/
var ModalDataRequest = function(root) {
Modal.call(this, root);
if (!this.getFooter().find(SELECTORS.APPROVE_BUTTON).length) {
Notification.exception({message: 'No approve button found'});
}
if (!this.getFooter().find(SELECTORS.DENY_BUTTON).length) {
Notification.exception({message: 'No deny button found'});
}
};
ModalDataRequest.TYPE = 'tool_dataprivacy-data_request';
@@ -80,6 +73,16 @@ define(['jquery', 'core/notification', 'core/custom_interaction_events', 'core/m
data.originalEvent.preventDefault();
}
}.bind(this));
this.getModal().on(CustomEvents.events.activate, SELECTORS.COMPLETE_BUTTON, function(e, data) {
var completeEvent = $.Event(DataPrivacyEvents.complete);
this.getRoot().trigger(completeEvent, this);
if (!completeEvent.isDefaultPrevented()) {
this.hide();
data.originalEvent.preventDefault();
}
}.bind(this));
};
// Automatically register with the modal registry the first time this module is imported so that you can create modals
+1
View File
@@ -26,5 +26,6 @@ define([], function() {
return {
approve: 'tool_dataprivacy-data_request:approve',
deny: 'tool_dataprivacy-data_request:deny',
complete: 'tool_dataprivacy-data_request:complete'
};
});
@@ -39,11 +39,13 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates, Modal
* @type {{APPROVE_REQUEST: string}}
* @type {{DENY_REQUEST: string}}
* @type {{VIEW_REQUEST: string}}
* @type {{MARK_COMPLETE: string}}
*/
var ACTIONS = {
APPROVE_REQUEST: '[data-action="approve"]',
DENY_REQUEST: '[data-action="deny"]',
VIEW_REQUEST: '[data-action="view"]'
VIEW_REQUEST: '[data-action="view"]',
MARK_COMPLETE: '[data-action="complete"]'
};
/**
@@ -73,16 +75,9 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates, Modal
};
var promises = Ajax.call([request]);
var modalTitle = '';
var modalType = ModalFactory.types.DEFAULT;
$.when(promises[0]).then(function(data) {
if (data.result) {
// Check if the status is awaiting approval.
if (data.result.status == 2) {
modalType = ModalDataRequest.TYPE;
}
modalTitle = data.result.typename;
return Templates.render('tool_dataprivacy/request_details', data.result);
return data.result;
}
// Fail.
Notification.addNotification({
@@ -91,35 +86,51 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates, Modal
});
return false;
}).then(function(html) {
}).then(function(data) {
var body = Templates.render('tool_dataprivacy/request_details', data);
var templateContext = {
approvedeny: data.approvedeny,
canmarkcomplete: data.canmarkcomplete
};
return ModalFactory.create({
title: modalTitle,
body: html,
type: modalType,
large: true
}).then(function(modal) {
// Handle approve event.
modal.getRoot().on(DataPrivacyEvents.approve, function() {
showConfirmation(DataPrivacyEvents.approve, requestId);
});
// Handle deny event.
modal.getRoot().on(DataPrivacyEvents.deny, function() {
showConfirmation(DataPrivacyEvents.deny, requestId);
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
return modal;
title: data.typename,
body: body,
type: ModalDataRequest.TYPE,
large: true,
templateContext: templateContext
});
}).done(function(modal) {
}).then(function(modal) {
// Handle approve event.
modal.getRoot().on(DataPrivacyEvents.approve, function() {
showConfirmation(DataPrivacyEvents.approve, requestId);
});
// Handle deny event.
modal.getRoot().on(DataPrivacyEvents.deny, function() {
showConfirmation(DataPrivacyEvents.deny, requestId);
});
// Handle send event.
modal.getRoot().on(DataPrivacyEvents.complete, function() {
var params = {
'requestid': requestId
};
handleSave('tool_dataprivacy_mark_complete', params);
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
// Show the modal!
modal.show();
}).fail(Notification.exception);
return;
}).catch(Notification.exception);
});
$(ACTIONS.APPROVE_REQUEST).click(function(e) {
@@ -135,6 +146,11 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates, Modal
var requestId = $(this).data('requestid');
showConfirmation(DataPrivacyEvents.deny, requestId);
});
$(ACTIONS.MARK_COMPLETE).click(function(e) {
e.preventDefault();
showConfirmation(DataPrivacyEvents.complete, $(this).data('requestid'));
});
};
/**
@@ -146,6 +162,9 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates, Modal
function showConfirmation(action, requestId) {
var keys = [];
var wsfunction = '';
var params = {
'requestid': requestId
};
switch (action) {
case DataPrivacyEvents.approve:
keys = [
@@ -173,6 +192,19 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates, Modal
];
wsfunction = 'tool_dataprivacy_deny_data_request';
break;
case DataPrivacyEvents.complete:
keys = [
{
key: 'markcomplete',
component: 'tool_dataprivacy'
},
{
key: 'confirmcompletion',
component: 'tool_dataprivacy'
}
];
wsfunction = 'tool_dataprivacy_mark_complete';
break;
}
var modalTitle = '';
@@ -189,26 +221,7 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates, Modal
// Handle save event.
modal.getRoot().on(ModalEvents.save, function() {
// Confirm the request.
var params = {
'requestid': requestId
};
var request = {
methodname: wsfunction,
args: params
};
Ajax.call([request])[0].done(function(data) {
if (data.result) {
window.location.reload();
} else {
Notification.addNotification({
message: data.warnings[0].message,
type: 'error'
});
}
}).fail(Notification.exception);
handleSave(wsfunction, params);
});
// Handle hidden event.
@@ -217,9 +230,39 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates, Modal
modal.destroy();
});
return modal;
}).done(function(modal) {
modal.show();
return;
}).catch(Notification.exception);
}
/**
* Calls a web service function and reloads the page on success and shows a notification.
* Displays an error notification, otherwise.
*
* @param {String} wsfunction The web service function to call.
* @param {Object} params The parameters for the web service functoon.
*/
function handleSave(wsfunction, params) {
// Confirm the request.
var request = {
methodname: wsfunction,
args: params
};
Ajax.call([request])[0].done(function(data) {
if (data.result) {
// On success, reload the page so that the data request table will be updated.
// TODO: Probably in the future, better to reload the table or the target data request via AJAX.
window.location.reload();
} else {
// Add the notification.
Notification.addNotification({
message: data.warnings[0].message,
type: 'error'
});
}
}).fail(Notification.exception);
}
+17 -2
View File
@@ -24,6 +24,7 @@
namespace tool_dataprivacy;
use coding_exception;
use context_course;
use context_system;
use core\invalid_persistent_exception;
use core\message\message;
@@ -426,7 +427,22 @@ class api {
if ($dpoid) {
$datarequest->set('dpo', $dpoid);
}
$datarequest->set('dpocomment', $comment);
// Update the comment if necessary.
if (!empty(trim($comment))) {
$params = [
'date' => userdate(time()),
'comment' => $comment
];
$commenttosave = get_string('datecomment', 'tool_dataprivacy', $params);
// Check if there's an existing DPO comment.
$currentcomment = trim($datarequest->get('dpocomment'));
if ($currentcomment) {
// Append the new comment to the current comment and give them 1 line space in between.
$commenttosave = $currentcomment . PHP_EOL . PHP_EOL . $commenttosave;
}
$datarequest->set('dpocomment', $commenttosave);
}
return $datarequest->update();
}
@@ -521,7 +537,6 @@ class api {
* @param data_request $request The data request
* @return int|false
* @throws coding_exception
* @throws dml_exception
* @throws moodle_exception
*/
public static function notify_dpo($dpo, data_request $request) {
+74 -3
View File
@@ -31,6 +31,7 @@ use context_helper;
use context_system;
use context_user;
use core\invalid_persistent_exception;
use core\notification;
use core_user;
use dml_exception;
use external_api;
@@ -144,7 +145,7 @@ class external extends external_api {
}
/**
* Deny a data request.
* Make a general enquiry to a DPO.
*
* @since Moodle 3.5
* @param string $message The message to be sent to the DPO.
@@ -210,7 +211,7 @@ class external extends external_api {
}
/**
* Parameter description for deny_data_request().
* Parameter description for contact_dpo().
*
* @since Moodle 3.5
* @return external_description
@@ -222,6 +223,70 @@ class external extends external_api {
]);
}
/**
* Parameter description for mark_complete().
*
* @since Moodle 3.5.2
* @return external_function_parameters
*/
public static function mark_complete_parameters() {
return new external_function_parameters([
'requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED)
]);
}
/**
* Mark a user's general enquiry's status as complete.
*
* @since Moodle 3.5.2
* @param int $requestid The request ID of the general enquiry.
* @return array
* @throws coding_exception
* @throws invalid_parameter_exception
* @throws invalid_persistent_exception
* @throws restricted_context_exception
* @throws dml_exception
* @throws moodle_exception
*/
public static function mark_complete($requestid) {
global $USER;
$warnings = [];
$params = external_api::validate_parameters(self::mark_complete_parameters(), [
'requestid' => $requestid,
]);
$requestid = $params['requestid'];
// Validate context.
$context = context_system::instance();
self::validate_context($context);
$message = get_string('markedcomplete', 'tool_dataprivacy');
// Update the data request record.
if ($result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_COMPLETE, $USER->id, $message)) {
// Add notification in the session to be shown when the page is reloaded on the JS side.
notification::success(get_string('requestmarkedcomplete', 'tool_dataprivacy'));
}
return [
'result' => $result,
'warnings' => $warnings
];
}
/**
* Parameter description for mark_complete().
*
* @since Moodle 3.5.2
* @return external_description
*/
public static function mark_complete_returns() {
return new external_single_structure([
'result' => new external_value(PARAM_BOOL, 'The processing result'),
'warnings' => new external_warnings()
]);
}
/**
* Parameter description for get_data_request().
*
@@ -258,9 +323,9 @@ class external extends external_api {
// Validate context.
$context = context_system::instance();
self::validate_context($context);
$requestpersistent = new data_request($requestid);
require_capability('tool/dataprivacy:managedatarequests', $context);
$requestpersistent = new data_request($requestid);
$exporter = new data_request_exporter($requestpersistent, ['context' => $context]);
$renderer = $PAGE->get_renderer('tool_dataprivacy');
$result = $exporter->export($renderer);
@@ -326,6 +391,9 @@ class external extends external_api {
$result = false;
if ($requestexists) {
$result = api::approve_data_request($requestid);
// Add notification in the session to be shown when the page is reloaded on the JS side.
notification::success(get_string('requestapproved', 'tool_dataprivacy'));
} else {
$warnings[] = [
'item' => $requestid,
@@ -395,6 +463,9 @@ class external extends external_api {
$result = false;
if ($requestexists) {
$result = api::deny_data_request($requestid);
// Add notification in the session to be shown when the page is reloaded on the JS side.
notification::success(get_string('requestdenied', 'tool_dataprivacy'));
} else {
$warnings[] = [
'item' => $requestid,
@@ -102,6 +102,16 @@ class data_request_exporter extends persistent_exporter {
'optional' => true,
'default' => false
],
'approvedeny' => [
'type' => PARAM_BOOL,
'optional' => true,
'default' => false
],
'canmarkcomplete' => [
'type' => PARAM_BOOL,
'optional' => true,
'default' => false
],
];
}
@@ -140,14 +150,19 @@ class data_request_exporter extends persistent_exporter {
$values['messagehtml'] = text_to_html($this->persistent->get('comments'));
$values['typename'] = helper::get_request_type_string($this->persistent->get('type'));
$values['typenameshort'] = helper::get_shortened_request_type_string($this->persistent->get('type'));
$requesttype = $this->persistent->get('type');
$values['typename'] = helper::get_request_type_string($requesttype);
$values['typenameshort'] = helper::get_shortened_request_type_string($requesttype);
$values['canreview'] = false;
$values['approvedeny'] = false;
$values['statuslabel'] = helper::get_request_status_string($this->persistent->get('status'));
switch ($this->persistent->get('status')) {
case api::DATAREQUEST_STATUS_PENDING:
$values['statuslabelclass'] = 'label-default';
// Request can be manually completed for general enquiry requests.
$values['canmarkcomplete'] = $requesttype == api::DATAREQUEST_TYPE_OTHERS;
break;
case api::DATAREQUEST_STATUS_PREPROCESSING:
$values['statuslabelclass'] = 'label-default';
@@ -156,6 +171,8 @@ class data_request_exporter extends persistent_exporter {
$values['statuslabelclass'] = 'label-info';
// DPO can review the request once it's ready.
$values['canreview'] = true;
// Whether the DPO can approve or deny the request.
$values['approvedeny'] = in_array($requesttype, [api::DATAREQUEST_TYPE_EXPORT, api::DATAREQUEST_TYPE_DELETE]);
break;
case api::DATAREQUEST_STATUS_APPROVED:
$values['statuslabelclass'] = 'label-info';
@@ -180,16 +180,32 @@ class data_requests_table extends table_sql {
$actiontext = get_string('viewrequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
if ($status == api::DATAREQUEST_STATUS_AWAITING_APPROVAL) {
// Approve.
$actiondata['data-action'] = 'approve';
$actiontext = get_string('approverequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
switch ($status) {
case api::DATAREQUEST_STATUS_PENDING:
// Add action to mark a general enquiry request as complete.
if ($data->type == api::DATAREQUEST_TYPE_OTHERS) {
$actiondata['data-action'] = 'complete';
$nameemail = (object)[
'name' => $data->foruser->fullname,
'email' => $data->foruser->email
];
$actiondata['data-requestid'] = $data->id;
$actiondata['data-replytoemail'] = get_string('nameemail', 'tool_dataprivacy', $nameemail);
$actiontext = get_string('markcomplete', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
}
break;
case api::DATAREQUEST_STATUS_AWAITING_APPROVAL:
// Approve.
$actiondata['data-action'] = 'approve';
$actiontext = get_string('approverequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
// Deny.
$actiondata['data-action'] = 'deny';
$actiontext = get_string('denyrequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
// Deny.
$actiondata['data-action'] = 'deny';
$actiontext = get_string('denyrequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
break;
}
$actionsmenu = new action_menu($actions);
@@ -82,6 +82,7 @@ class my_data_requests_page implements renderable, templatable {
$requestid = $request->get('id');
$status = $request->get('status');
$userid = $request->get('userid');
$type = $request->get('type');
$usercontext = context_user::instance($userid, IGNORE_MISSING);
if (!$usercontext) {
@@ -107,7 +108,8 @@ class my_data_requests_page implements renderable, templatable {
$item->statuslabelclass = 'label-success';
$item->statuslabel = get_string('statuscomplete', 'tool_dataprivacy');
$cancancel = false;
$candownload = true;
// Show download links only for export-type data requests.
$candownload = $type == api::DATAREQUEST_TYPE_EXPORT;
break;
case api::DATAREQUEST_STATUS_CANCELLED:
case api::DATAREQUEST_STATUS_REJECTED:
+10
View File
@@ -43,6 +43,16 @@ $functions = [
'ajax' => true,
'loginrequired' => true,
],
'tool_dataprivacy_mark_complete' => [
'classname' => 'tool_dataprivacy\external',
'methodname' => 'mark_complete',
'classpath' => '',
'description' => 'Mark a user\'s general enquiry as complete',
'type' => 'write',
'capabilities' => 'tool/dataprivacy:managedatarequests',
'ajax' => true,
'loginrequired' => true,
],
'tool_dataprivacy_get_data_request' => [
'classname' => 'tool_dataprivacy\external',
'methodname' => 'get_data_request',
@@ -46,6 +46,7 @@ $string['categoryupdated'] = 'Category updated';
$string['close'] = 'Close';
$string['compliant'] = 'Compliant';
$string['confirmapproval'] = 'Do you really want to approve this data request?';
$string['confirmcompletion'] = 'Do you really want to mark this user enquiry as complete?';
$string['confirmcontextdeletion'] = 'Do you really want to confirm the deletion of the selected contexts? This will also delete all of the user data for their respective sub-contexts.';
$string['confirmdenial'] = 'Do you really want deny this data request?';
$string['contactdataprotectionofficer'] = 'Contact the privacy officer';
@@ -70,6 +71,7 @@ $string['dataregistryinfo'] = 'The data registry enables categories (types of da
$string['datarequestcreatedforuser'] = 'Data request created for {$a}';
$string['datarequestemailsubject'] = 'Data request: {$a}';
$string['datarequests'] = 'Data requests';
$string['datecomment'] = '[{$a->date}]: ' . PHP_EOL . ' {$a->comment}';
$string['daterequested'] = 'Date requested';
$string['daterequesteddetail'] = 'Date requested:';
$string['defaultsinfo'] = 'Default categories and purposes are applied to all newly created instances.';
@@ -151,6 +153,8 @@ $string['httpwarning'] = 'Any data downloaded from this site may not be encrypte
$string['inherit'] = 'Inherit';
$string['lawfulbases'] = 'Lawful bases';
$string['lawfulbases_help'] = 'Select at least one option that will serve as the lawful basis for processing personal data. For details on these lawful bases, please see <a href="https://gdpr-info.eu/art-6-gdpr/" target="_blank">GDPR Art. 6.1</a>';
$string['markcomplete'] = 'Mark as complete';
$string['markedcomplete'] = 'Your enquiry has been marked as complete by the privacy officer.';
$string['messageprovider:contactdataprotectionofficer'] = 'Data requests';
$string['messageprovider:datarequestprocessingresults'] = 'Data request processing results';
$string['messageprovider:notifyexceptions'] = 'Data requests exceptions notifications';
@@ -197,12 +201,15 @@ $string['purposeslist'] = 'List of data purposes';
$string['purposeupdated'] = 'Purpose updated';
$string['replyto'] = 'Reply to';
$string['requestactions'] = 'Actions';
$string['requestapproved'] = 'The request has been approved';
$string['requestby'] = 'Requested by';
$string['requestbydetail'] = 'Requested by:';
$string['requestcomments'] = 'Comments';
$string['requestcomments_help'] = 'This box enables you to enter any further details about your data request.';
$string['requestdenied'] = 'The request has been denied';
$string['requestemailintro'] = 'You have received a data request:';
$string['requestfor'] = 'Requesting for';
$string['requestmarkedcomplete'] = 'The request has been marked as complete';
$string['requeststatus'] = 'Status';
$string['requestsubmitted'] = 'Your request has been submitted to the privacy officer';
$string['requesttype'] = 'Type';
@@ -35,7 +35,12 @@
}}
{{< core/modal }}
{{$footer}}
<button type="button" class="btn btn-primary" data-action="approve">{{#str}} approve, tool_dataprivacy {{/str}}</button>
<button type="button" class="btn btn-secondary" data-action="deny">{{#str}} deny, tool_dataprivacy {{/str}}</button>
{{#approvedeny}}
<button type="button" class="btn btn-primary" data-action="approve">{{#str}} approve, tool_dataprivacy {{/str}}</button>
<button type="button" class="btn btn-secondary" data-action="deny">{{#str}} deny, tool_dataprivacy {{/str}}</button>
{{/approvedeny}}
{{#canmarkcomplete}}
<button type="button" class="btn btn-primary" data-action="complete">{{#str}} markcomplete, tool_dataprivacy {{/str}}</button>
{{/canmarkcomplete}}
{{/footer}}
{{/ core/modal }}
+1 -1
View File
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die;
$plugin->version = 2018051401;
$plugin->version = 2018051402;
$plugin->requires = 2018050800; // Moodle 3.5dev (Build 2018031600) and upwards.
$plugin->component = 'tool_dataprivacy';