Merge branch 'MDL-62554-master' of git://github.com/junpataleta/moodle
This commit is contained in:
@@ -0,0 +1 @@
|
||||
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events","core/templates"],function(a,b,c,d,e,f,g){function h(b,d,h,j,k,l,m,n){null!==h&&l.forEach(function(a){a.id===h&&(a.selected=!0)}),null!==j&&m.forEach(function(a){a.id===j&&(a.selected=!0)});var o={contextlevel:d,categoryoptions:l,purposeoptions:m};null!==n&&n.length&&(null===k?o.newactivitydefaults=!0:n.forEach(function(a){k===a.name&&(a.selected=!0)}),o.modemodule=!0,o.activityoptions=n),e.create({title:b,body:g.render("tool_dataprivacy/category_purpose_form",o),type:e.types.SAVE_CANCEL,large:!0}).then(function(b){return b.getRoot().on(f.save,function(){var b=a("#activity"),c="undefined"!=typeof b?b.val():null,d=a("#override"),e="undefined"!=typeof d&&d.is(":checked");i(a("#contextlevel").val(),a("#category").val(),a("#purpose").val(),c,e)}),b.getRoot().on(f.hidden,function(){b.destroy()}),b.show(),b})["catch"](c.exception)}function i(a,c,d,e,f){var g={methodname:"tool_dataprivacy_set_context_defaults",args:{contextlevel:a,category:c,purpose:d,override:f,activity:e}};b.call([g])[0].done(function(a){a.result&&window.location.reload()})}var j={EDIT_LEVEL_DEFAULTS:'[data-action="edit-level-defaults"]',NEW_ACTIVITY_DEFAULTS:'[data-action="new-activity-defaults"]',EDIT_ACTIVITY_DEFAULTS:'[data-action="edit-activity-defaults"]',DELETE_ACTIVITY_DEFAULTS:'[data-action="delete-activity-defaults"]'},k=-1,l=function(){this.registerEvents()};return l.prototype.registerEvents=function(){a(j.EDIT_LEVEL_DEFAULTS).click(function(e){e.preventDefault();var f=a(this),g=f.data("contextlevel"),i=f.data("category"),j=f.data("purpose"),k=[{methodname:"tool_dataprivacy_get_category_options",args:{}},{methodname:"tool_dataprivacy_get_purpose_options",args:{}}],l=b.call(k),m=d.get_string("editdefaults","tool_dataprivacy",a("#defaults-header").text());a.when(l[0],l[1],m).then(function(a,b,c){var d=a.options,e=b.options;return h(c,g,i,j,null,d,e,null),!0})["catch"](c.exception)}),a(j.NEW_ACTIVITY_DEFAULTS).click(function(e){e.preventDefault();var f=a(this),g=f.data("contextlevel"),i=[{methodname:"tool_dataprivacy_get_category_options",args:{}},{methodname:"tool_dataprivacy_get_purpose_options",args:{}},{methodname:"tool_dataprivacy_get_activity_options",args:{nodefaults:!0}}],j=b.call(i),k=d.get_string("addnewdefaults","tool_dataprivacy");a.when(j[0],j[1],j[2],k).then(function(a,b,c,d){var e=a.options,f=b.options,i=c.options;return h(d,g,null,null,null,e,f,i),!0})["catch"](c.exception)}),a(j.EDIT_ACTIVITY_DEFAULTS).click(function(e){e.preventDefault();var f=a(this),g=f.data("contextlevel"),i=f.data("category"),j=f.data("purpose"),k=f.data("activityname"),l=[{methodname:"tool_dataprivacy_get_category_options",args:{}},{methodname:"tool_dataprivacy_get_purpose_options",args:{}},{methodname:"tool_dataprivacy_get_activity_options",args:{}}],m=b.call(l),n=d.get_string("editmoduledefaults","tool_dataprivacy");a.when(m[0],m[1],m[2],n).then(function(a,b,c,d){var e=a.options,f=b.options,l=c.options;return h(d,g,i,j,k,e,f,l),!0})["catch"](c.exception)}),a(j.DELETE_ACTIVITY_DEFAULTS).click(function(b){b.preventDefault();var h=a(this),j=h.data("contextlevel"),l=h.data("activityname"),m=h.data("activitydisplayname"),n=k,o=k;e.create({title:d.get_string("deletedefaults","tool_dataprivacy",m),body:g.render("tool_dataprivacy/delete_activity_defaults",{activityname:m}),type:e.types.SAVE_CANCEL,large:!0}).then(function(a){return a.setSaveButtonText(d.get_string("delete")),a.getRoot().on(f.save,function(){i(j,n,o,l,!1)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a.show(),!0})["catch"](c.exception)})},{init:function(){return new l}}});
|
||||
@@ -0,0 +1,315 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* AMD module for data registry defaults actions.
|
||||
*
|
||||
* @module tool_dataprivacy/defaultsactions
|
||||
* @package tool_dataprivacy
|
||||
* @copyright 2018 Jun Pataleta
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define([
|
||||
'jquery',
|
||||
'core/ajax',
|
||||
'core/notification',
|
||||
'core/str',
|
||||
'core/modal_factory',
|
||||
'core/modal_events',
|
||||
'core/templates'],
|
||||
function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates) {
|
||||
|
||||
/**
|
||||
* List of action selectors.
|
||||
*
|
||||
* @type {{EDIT_LEVEL_DEFAULTS: string}}
|
||||
* @type {{NEW_ACTIVITY_DEFAULTS: string}}
|
||||
* @type {{EDIT_ACTIVITY_DEFAULTS: string}}
|
||||
* @type {{DELETE_ACTIVITY_DEFAULTS: string}}
|
||||
*/
|
||||
var ACTIONS = {
|
||||
EDIT_LEVEL_DEFAULTS: '[data-action="edit-level-defaults"]',
|
||||
NEW_ACTIVITY_DEFAULTS: '[data-action="new-activity-defaults"]',
|
||||
EDIT_ACTIVITY_DEFAULTS: '[data-action="edit-activity-defaults"]',
|
||||
DELETE_ACTIVITY_DEFAULTS: '[data-action="delete-activity-defaults"]'
|
||||
};
|
||||
|
||||
/** @type {{INHERIT: Number}} **/
|
||||
var INHERIT = -1;
|
||||
|
||||
/**
|
||||
* DefaultsActions class.
|
||||
*/
|
||||
var DefaultsActions = function() {
|
||||
this.registerEvents();
|
||||
};
|
||||
|
||||
/**
|
||||
* Register event listeners.
|
||||
*/
|
||||
DefaultsActions.prototype.registerEvents = function() {
|
||||
$(ACTIONS.EDIT_LEVEL_DEFAULTS).click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var button = $(this);
|
||||
var contextLevel = button.data('contextlevel');
|
||||
var category = button.data('category');
|
||||
var purpose = button.data('purpose');
|
||||
|
||||
// Get options.
|
||||
var requests = [
|
||||
{methodname: 'tool_dataprivacy_get_category_options', args: {}},
|
||||
{methodname: 'tool_dataprivacy_get_purpose_options', args: {}}
|
||||
];
|
||||
|
||||
var promises = Ajax.call(requests);
|
||||
var titlePromise = Str.get_string('editdefaults', 'tool_dataprivacy', $('#defaults-header').text());
|
||||
$.when(promises[0], promises[1], titlePromise).then(function(categoryResponse, purposeResponse, title) {
|
||||
var categories = categoryResponse.options;
|
||||
var purposes = purposeResponse.options;
|
||||
showDefaultsFormModal(title, contextLevel, category, purpose, null, categories, purposes, null);
|
||||
|
||||
return true;
|
||||
}).catch(Notification.exception);
|
||||
});
|
||||
|
||||
$(ACTIONS.NEW_ACTIVITY_DEFAULTS).click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var button = $(this);
|
||||
var contextLevel = button.data('contextlevel');
|
||||
|
||||
// Get options.
|
||||
var requests = [
|
||||
{methodname: 'tool_dataprivacy_get_category_options', args: {}},
|
||||
{methodname: 'tool_dataprivacy_get_purpose_options', args: {}},
|
||||
{methodname: 'tool_dataprivacy_get_activity_options', args: {'nodefaults': true}}
|
||||
];
|
||||
|
||||
var promises = Ajax.call(requests);
|
||||
var titlePromise = Str.get_string('addnewdefaults', 'tool_dataprivacy');
|
||||
|
||||
$.when(promises[0], promises[1], promises[2], titlePromise).then(
|
||||
function(categoryResponse, purposeResponse, activityResponse, title) {
|
||||
var categories = categoryResponse.options;
|
||||
var purposes = purposeResponse.options;
|
||||
var activities = activityResponse.options;
|
||||
|
||||
showDefaultsFormModal(title, contextLevel, null, null, null, categories, purposes, activities);
|
||||
|
||||
return true;
|
||||
|
||||
}).catch(Notification.exception);
|
||||
}
|
||||
);
|
||||
|
||||
$(ACTIONS.EDIT_ACTIVITY_DEFAULTS).click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var button = $(this);
|
||||
var contextLevel = button.data('contextlevel');
|
||||
var category = button.data('category');
|
||||
var purpose = button.data('purpose');
|
||||
var activity = button.data('activityname');
|
||||
|
||||
// Get options.
|
||||
var requests = [
|
||||
{methodname: 'tool_dataprivacy_get_category_options', args: {}},
|
||||
{methodname: 'tool_dataprivacy_get_purpose_options', args: {}},
|
||||
{methodname: 'tool_dataprivacy_get_activity_options', args: {}}
|
||||
];
|
||||
|
||||
var promises = Ajax.call(requests);
|
||||
var titlePromise = Str.get_string('editmoduledefaults', 'tool_dataprivacy');
|
||||
|
||||
$.when(promises[0], promises[1], promises[2], titlePromise).then(
|
||||
function(categoryResponse, purposeResponse, activityResponse, title) {
|
||||
var categories = categoryResponse.options;
|
||||
var purposes = purposeResponse.options;
|
||||
var activities = activityResponse.options;
|
||||
|
||||
showDefaultsFormModal(title, contextLevel, category, purpose, activity, categories, purposes, activities);
|
||||
|
||||
return true;
|
||||
|
||||
}).catch(Notification.exception);
|
||||
}
|
||||
);
|
||||
|
||||
$(ACTIONS.DELETE_ACTIVITY_DEFAULTS).click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var button = $(this);
|
||||
var contextLevel = button.data('contextlevel');
|
||||
var activity = button.data('activityname');
|
||||
var activityDisplayName = button.data('activitydisplayname');
|
||||
// Set category and purpose to inherit (-1).
|
||||
var category = INHERIT;
|
||||
var purpose = INHERIT;
|
||||
|
||||
ModalFactory.create({
|
||||
title: Str.get_string('deletedefaults', 'tool_dataprivacy', activityDisplayName),
|
||||
body: Templates.render('tool_dataprivacy/delete_activity_defaults', {"activityname": activityDisplayName}),
|
||||
type: ModalFactory.types.SAVE_CANCEL,
|
||||
large: true
|
||||
}).then(function(modal) {
|
||||
modal.setSaveButtonText(Str.get_string('delete'));
|
||||
|
||||
// Handle save event.
|
||||
modal.getRoot().on(ModalEvents.save, function() {
|
||||
setContextDefaults(contextLevel, category, purpose, activity, false);
|
||||
});
|
||||
|
||||
// Handle hidden event.
|
||||
modal.getRoot().on(ModalEvents.hidden, function() {
|
||||
// Destroy when hidden.
|
||||
modal.destroy();
|
||||
});
|
||||
|
||||
modal.show();
|
||||
|
||||
return true;
|
||||
}).catch(Notification.exception);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepares and renders the modal for setting the defaults for the given context level/plugin.
|
||||
*
|
||||
* @param {String} title The modal's title.
|
||||
* @param {Number} contextLevel The context level to set defaults for.
|
||||
* @param {Number} category The current category ID.
|
||||
* @param {Number} purpose The current purpose ID.
|
||||
* @param {String} activity The plugin name of the activity. Optional.
|
||||
* @param {Array} categoryOptions The list of category options.
|
||||
* @param {Array} purposeOptions The list of purpose options.
|
||||
* @param {Array} activityOptions The list of activity options. Optional.
|
||||
*/
|
||||
function showDefaultsFormModal(title, contextLevel, category, purpose, activity,
|
||||
categoryOptions, purposeOptions, activityOptions) {
|
||||
|
||||
if (category !== null) {
|
||||
categoryOptions.forEach(function(currentValue) {
|
||||
if (currentValue.id === category) {
|
||||
currentValue.selected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (purpose !== null) {
|
||||
purposeOptions.forEach(function(currentValue) {
|
||||
if (currentValue.id === purpose) {
|
||||
currentValue.selected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var templateContext = {
|
||||
"contextlevel": contextLevel,
|
||||
"categoryoptions": categoryOptions,
|
||||
"purposeoptions": purposeOptions
|
||||
};
|
||||
|
||||
// Check the activityOptions parameter that was passed.
|
||||
if (activityOptions !== null && activityOptions.length) {
|
||||
// Check the activity parameter that was passed.
|
||||
if (activity === null) {
|
||||
// We're setting a new defaults for a module.
|
||||
templateContext.newactivitydefaults = true;
|
||||
|
||||
} else {
|
||||
// Edit mode. Set selection.
|
||||
activityOptions.forEach(function(currentValue) {
|
||||
if (activity === currentValue.name) {
|
||||
currentValue.selected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
templateContext.modemodule = true;
|
||||
templateContext.activityoptions = activityOptions;
|
||||
}
|
||||
|
||||
ModalFactory.create({
|
||||
title: title,
|
||||
body: Templates.render('tool_dataprivacy/category_purpose_form', templateContext),
|
||||
type: ModalFactory.types.SAVE_CANCEL,
|
||||
large: true
|
||||
}).then(function(modal) {
|
||||
|
||||
// Handle save event.
|
||||
modal.getRoot().on(ModalEvents.save, function() {
|
||||
var activity = $('#activity');
|
||||
var activityVal = typeof activity !== 'undefined' ? activity.val() : null;
|
||||
var override = $('#override');
|
||||
var overrideVal = typeof override !== 'undefined' ? override.is(':checked') : false;
|
||||
|
||||
setContextDefaults($('#contextlevel').val(), $('#category').val(), $('#purpose').val(), activityVal, overrideVal);
|
||||
});
|
||||
|
||||
// Handle hidden event.
|
||||
modal.getRoot().on(ModalEvents.hidden, function() {
|
||||
// Destroy when hidden.
|
||||
modal.destroy();
|
||||
});
|
||||
|
||||
modal.show();
|
||||
|
||||
return modal;
|
||||
}).catch(Notification.exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a the tool_dataprivacy_set_context_defaults WS function.
|
||||
*
|
||||
* @param {Number} contextLevel The context level.
|
||||
* @param {Number} category The category ID.
|
||||
* @param {Number} purpose The purpose ID.
|
||||
* @param {String} activity The plugin name of the activity module.
|
||||
* @param {Boolean} override Whether to override custom instances.
|
||||
*/
|
||||
function setContextDefaults(contextLevel, category, purpose, activity, override) {
|
||||
var request = {
|
||||
methodname: 'tool_dataprivacy_set_context_defaults',
|
||||
args: {
|
||||
'contextlevel': contextLevel,
|
||||
'category': category,
|
||||
'purpose': purpose,
|
||||
'override': override,
|
||||
'activity': activity
|
||||
}
|
||||
};
|
||||
|
||||
Ajax.call([request])[0].done(function(data) {
|
||||
if (data.result) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return /** @alias module:tool_dataprivacy/defaultsactions */ {
|
||||
// Public variables and functions.
|
||||
|
||||
/**
|
||||
* Initialise the module.
|
||||
*
|
||||
* @method init
|
||||
* @return {DefaultsActions}
|
||||
*/
|
||||
'init': function() {
|
||||
return new DefaultsActions();
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -24,7 +24,7 @@
|
||||
namespace tool_dataprivacy;
|
||||
|
||||
use coding_exception;
|
||||
use context_course;
|
||||
use context_helper;
|
||||
use context_system;
|
||||
use core\invalid_persistent_exception;
|
||||
use core\message\message;
|
||||
@@ -1141,4 +1141,91 @@ class api {
|
||||
|
||||
return $approvedcollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the default category and purpose for a given context level (and optionally, a plugin).
|
||||
*
|
||||
* @param int $contextlevel The context level.
|
||||
* @param int $categoryid The ID matching the category.
|
||||
* @param int $purposeid The ID matching the purpose record.
|
||||
* @param int $activity The name of the activity that we're making a defaults configuration for.
|
||||
* @param bool $override Whether to override the purpose/categories of existing instances to these defaults.
|
||||
* @return boolean True if set/unset config succeeds. Otherwise, it throws an exception.
|
||||
*/
|
||||
public static function set_context_defaults($contextlevel, $categoryid, $purposeid, $activity = null, $override = false) {
|
||||
global $DB;
|
||||
|
||||
self::check_can_manage_data_registry();
|
||||
|
||||
// Get the class name associated with this context level.
|
||||
$classname = context_helper::get_class_for_level($contextlevel);
|
||||
list($purposevar, $categoryvar) = data_registry::var_names_from_context($classname, $activity);
|
||||
|
||||
// Check the default category to be set.
|
||||
if ($categoryid == context_instance::INHERIT) {
|
||||
unset_config($categoryvar, 'tool_dataprivacy');
|
||||
|
||||
} else {
|
||||
// Make sure the given category ID exists first.
|
||||
$categorypersistent = new category($categoryid);
|
||||
$categorypersistent->read();
|
||||
|
||||
// Then set the new default value.
|
||||
set_config($categoryvar, $categoryid, 'tool_dataprivacy');
|
||||
}
|
||||
|
||||
// Check the default purpose to be set.
|
||||
if ($purposeid == context_instance::INHERIT) {
|
||||
// If the defaults is set to inherit, just unset the config value.
|
||||
unset_config($purposevar, 'tool_dataprivacy');
|
||||
|
||||
} else {
|
||||
// Make sure the given purpose ID exists first.
|
||||
$purposepersistent = new purpose($purposeid);
|
||||
$purposepersistent->read();
|
||||
|
||||
// Then set the new default value.
|
||||
set_config($purposevar, $purposeid, 'tool_dataprivacy');
|
||||
}
|
||||
|
||||
// Unset instances that have been assigned with custom purpose and category, if override was specified.
|
||||
if ($override) {
|
||||
// We'd like to find context IDs that we want to unset.
|
||||
$statements = ["SELECT c.id as contextid FROM {context} c"];
|
||||
// Based on this context level.
|
||||
$params = ['contextlevel' => $contextlevel];
|
||||
|
||||
if ($contextlevel == CONTEXT_MODULE) {
|
||||
// If we're deleting module context instances, we need to make sure the instance ID is in the course modules table.
|
||||
$statements[] = "JOIN {course_modules} cm ON cm.id = c.instanceid";
|
||||
// And that the module is listed on the modules table.
|
||||
$statements[] = "JOIN {modules} m ON m.id = cm.module";
|
||||
|
||||
if ($activity) {
|
||||
// If we're overriding for an activity module, make sure that the context instance matches that activity.
|
||||
$statements[] = "AND m.name = :modname";
|
||||
$params['modname'] = $activity;
|
||||
}
|
||||
}
|
||||
// Make sure this context instance exists in the tool_dataprivacy_ctxinstance table.
|
||||
$statements[] = "JOIN {tool_dataprivacy_ctxinstance} tdc ON tdc.contextid = c.id";
|
||||
// And that the context level of this instance matches the given context level.
|
||||
$statements[] = "WHERE c.contextlevel = :contextlevel";
|
||||
|
||||
// Build our SQL query by gluing the statements.
|
||||
$sql = implode("\n", $statements);
|
||||
|
||||
// Get the context records matching our query.
|
||||
$contextids = $DB->get_fieldset_sql($sql, $params);
|
||||
|
||||
// Delete the matching context instances.
|
||||
foreach ($contextids as $contextid) {
|
||||
if ($instance = context_instance::get_record_by_contextid($contextid, false)) {
|
||||
self::unset_context_instance($instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,10 +28,7 @@
|
||||
namespace tool_dataprivacy;
|
||||
|
||||
use coding_exception;
|
||||
use tool_dataprivacy\purpose;
|
||||
use tool_dataprivacy\category;
|
||||
use tool_dataprivacy\contextlevel;
|
||||
use tool_dataprivacy\context_instance;
|
||||
use core\persistent;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -57,13 +54,22 @@ class data_registry {
|
||||
/**
|
||||
* Returns purpose and category var names from a context class name
|
||||
*
|
||||
* @param string $classname
|
||||
* @param string $classname The context level's class.
|
||||
* @param string $pluginname The name of the plugin associated with the context level.
|
||||
* @return string[]
|
||||
*/
|
||||
public static function var_names_from_context($classname) {
|
||||
public static function var_names_from_context($classname, $pluginname = '') {
|
||||
$pluginname = trim($pluginname);
|
||||
if (!empty($pluginname)) {
|
||||
$categoryvar = $classname . '_' . $pluginname . '_category';
|
||||
$purposevar = $classname . '_' . $pluginname . '_purpose';
|
||||
} else {
|
||||
$categoryvar = $classname . '_category';
|
||||
$purposevar = $classname . '_purpose';
|
||||
}
|
||||
return [
|
||||
$classname . '_purpose',
|
||||
$classname . '_category',
|
||||
$purposevar,
|
||||
$categoryvar
|
||||
];
|
||||
}
|
||||
|
||||
@@ -72,17 +78,31 @@ class data_registry {
|
||||
*
|
||||
* The caller code is responsible of checking that $contextlevel is an integer.
|
||||
*
|
||||
* @param int $contextlevel
|
||||
* @return int|false[]
|
||||
* @param int $contextlevel The context level.
|
||||
* @param string $pluginname The name of the plugin associated with the context level.
|
||||
* @return int[]|false[]
|
||||
*/
|
||||
public static function get_defaults($contextlevel) {
|
||||
public static function get_defaults($contextlevel, $pluginname = '') {
|
||||
|
||||
$classname = \context_helper::get_class_for_level($contextlevel);
|
||||
list($purposevar, $categoryvar) = self::var_names_from_context($classname);
|
||||
list($purposevar, $categoryvar) = self::var_names_from_context($classname, $pluginname);
|
||||
|
||||
$purposeid = get_config('tool_dataprivacy', $purposevar);
|
||||
$categoryid = get_config('tool_dataprivacy', $categoryvar);
|
||||
|
||||
if (!empty($pluginname)) {
|
||||
list($purposevar, $categoryvar) = self::var_names_from_context($classname);
|
||||
// If the plugin-level doesn't have a default purpose set, try the context level.
|
||||
if ($purposeid === false) {
|
||||
$purposeid = get_config('tool_dataprivacy', $purposevar);
|
||||
}
|
||||
|
||||
// If the plugin-level doesn't have a default category set, try the context level.
|
||||
if ($categoryid === false) {
|
||||
$categoryid = get_config('tool_dataprivacy', $categoryvar);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($purposeid)) {
|
||||
$purposeid = false;
|
||||
}
|
||||
@@ -197,9 +217,15 @@ class data_registry {
|
||||
// Use the context level value as we don't allow people to set specific instances values.
|
||||
return self::get_effective_contextlevel_value($context->contextlevel, $element);
|
||||
} else {
|
||||
// Check if we need to pass the plugin name of an activity.
|
||||
$forplugin = '';
|
||||
if ($context->contextlevel == CONTEXT_MODULE) {
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($context->instanceid);
|
||||
$forplugin = $cm->modname;
|
||||
}
|
||||
// Use the default context level value.
|
||||
list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category(
|
||||
$context->contextlevel
|
||||
$context->contextlevel, false, false, $forplugin
|
||||
);
|
||||
return self::get_element_instance($element, $$fieldname);
|
||||
}
|
||||
@@ -283,14 +309,15 @@ class data_registry {
|
||||
* Returns the effective default purpose and category for a context level.
|
||||
*
|
||||
* @param int $contextlevel
|
||||
* @param int $forcedpurposevalue Use this value as if this was this context level purpose.
|
||||
* @param int $forcedcategoryvalue Use this value as if this was this context level category.
|
||||
* @param int|bool $forcedpurposevalue Use this value as if this was this context level purpose.
|
||||
* @param int|bool $forcedcategoryvalue Use this value as if this was this context level category.
|
||||
* @param string $activity The plugin name of the activity.
|
||||
* @return int[]
|
||||
*/
|
||||
public static function get_effective_default_contextlevel_purpose_and_category($contextlevel, $forcedpurposevalue = false,
|
||||
$forcedcategoryvalue = false) {
|
||||
$forcedcategoryvalue = false, $activity = '') {
|
||||
|
||||
list($purposeid, $categoryid) = self::get_defaults($contextlevel);
|
||||
list($purposeid, $categoryid) = self::get_defaults($contextlevel, $activity);
|
||||
|
||||
// Honour forced values.
|
||||
if ($forcedpurposevalue) {
|
||||
|
||||
@@ -1110,6 +1110,287 @@ class external extends external_api {
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for set_context_defaults().
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function set_context_defaults_parameters() {
|
||||
return new external_function_parameters([
|
||||
'contextlevel' => new external_value(PARAM_INT, 'The context level', VALUE_REQUIRED),
|
||||
'category' => new external_value(PARAM_INT, 'The default category for the given context level', VALUE_REQUIRED),
|
||||
'purpose' => new external_value(PARAM_INT, 'The default purpose for the given context level', VALUE_REQUIRED),
|
||||
'activity' => new external_value(PARAM_PLUGIN, 'The plugin name of the activity', VALUE_DEFAULT, null),
|
||||
'override' => new external_value(PARAM_BOOL, 'Whether to override existing instances with the defaults', VALUE_DEFAULT,
|
||||
false),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the default category and purpose for a given context level (and optionally, a plugin).
|
||||
*
|
||||
* @param int $contextlevel The context level.
|
||||
* @param int $category The ID matching the category.
|
||||
* @param int $purpose The ID matching the purpose record.
|
||||
* @param int $activity The name of the activity that we're making a defaults configuration for.
|
||||
* @param bool $override Whether to override the purpose/categories of existing instances to these defaults.
|
||||
* @return array
|
||||
*/
|
||||
public static function set_context_defaults($contextlevel, $category, $purpose, $activity, $override) {
|
||||
$warnings = [];
|
||||
|
||||
$params = external_api::validate_parameters(self::set_context_defaults_parameters(), [
|
||||
'contextlevel' => $contextlevel,
|
||||
'category' => $category,
|
||||
'purpose' => $purpose,
|
||||
'activity' => $activity,
|
||||
'override' => $override,
|
||||
]);
|
||||
$contextlevel = $params['contextlevel'];
|
||||
$category = $params['category'];
|
||||
$purpose = $params['purpose'];
|
||||
$activity = $params['activity'];
|
||||
$override = $params['override'];
|
||||
|
||||
// Validate context.
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
|
||||
// Set the context defaults.
|
||||
$result = api::set_context_defaults($contextlevel, $category, $purpose, $activity, $override);
|
||||
|
||||
return [
|
||||
'result' => $result,
|
||||
'warnings' => $warnings
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns for set_context_defaults().
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function set_context_defaults_returns() {
|
||||
return new external_single_structure([
|
||||
'result' => new external_value(PARAM_BOOL, 'Whether the context defaults were successfully set or not'),
|
||||
'warnings' => new external_warnings()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for get_category_options().
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function get_category_options_parameters() {
|
||||
return new external_function_parameters([
|
||||
'includeinherit' => new external_value(PARAM_BOOL, 'Include option "Inherit"', VALUE_DEFAULT, true),
|
||||
'includenotset' => new external_value(PARAM_BOOL, 'Include option "Not set"', VALUE_DEFAULT, false),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of data category options containing category IDs as keys and the category name for the value.
|
||||
*
|
||||
* @param bool $includeinherit Whether to include the "Inherit" option.
|
||||
* @param bool $includenotset Whether to include the "Not set" option.
|
||||
* @return array
|
||||
*/
|
||||
public static function get_category_options($includeinherit, $includenotset) {
|
||||
$warnings = [];
|
||||
|
||||
$params = self::validate_parameters(self::get_category_options_parameters(), [
|
||||
'includeinherit' => $includeinherit,
|
||||
'includenotset' => $includenotset
|
||||
]);
|
||||
$includeinherit = $params['includeinherit'];
|
||||
$includenotset = $params['includenotset'];
|
||||
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
|
||||
$categories = api::get_categories();
|
||||
$options = data_registry_page::category_options($categories, $includenotset, $includeinherit);
|
||||
$categoryoptions = [];
|
||||
foreach ($options as $id => $name) {
|
||||
$categoryoptions[] = [
|
||||
'id' => $id,
|
||||
'name' => $name,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'options' => $categoryoptions,
|
||||
'warnings' => $warnings
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns for get_category_options().
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function get_category_options_returns() {
|
||||
$optiondefinition = new external_single_structure(
|
||||
[
|
||||
'id' => new external_value(PARAM_INT, 'The category ID'),
|
||||
'name' => new external_value(PARAM_TEXT, 'The category name'),
|
||||
]
|
||||
);
|
||||
|
||||
return new external_single_structure([
|
||||
'options' => new external_multiple_structure($optiondefinition),
|
||||
'warnings' => new external_warnings()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for get_purpose_options().
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function get_purpose_options_parameters() {
|
||||
return new external_function_parameters([
|
||||
'includeinherit' => new external_value(PARAM_BOOL, 'Include option "Inherit"', VALUE_DEFAULT, true),
|
||||
'includenotset' => new external_value(PARAM_BOOL, 'Include option "Not set"', VALUE_DEFAULT, false),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of data storage purposes containing purpose IDs as keys and the purpose name for the value.
|
||||
*
|
||||
* @param bool $includeinherit Whether to include the "Inherit" option.
|
||||
* @param bool $includenotset Whether to include the "Not set" option.
|
||||
* @return array
|
||||
*/
|
||||
public static function get_purpose_options($includeinherit, $includenotset) {
|
||||
$warnings = [];
|
||||
|
||||
$params = self::validate_parameters(self::get_category_options_parameters(), [
|
||||
'includeinherit' => $includeinherit,
|
||||
'includenotset' => $includenotset
|
||||
]);
|
||||
$includeinherit = $params['includeinherit'];
|
||||
$includenotset = $params['includenotset'];
|
||||
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
|
||||
$purposes = api::get_purposes();
|
||||
$options = data_registry_page::purpose_options($purposes, $includenotset, $includeinherit);
|
||||
$purposeoptions = [];
|
||||
foreach ($options as $id => $name) {
|
||||
$purposeoptions[] = [
|
||||
'id' => $id,
|
||||
'name' => $name,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'options' => $purposeoptions,
|
||||
'warnings' => $warnings
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns for get_purpose_options().
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function get_purpose_options_returns() {
|
||||
$optiondefinition = new external_single_structure(
|
||||
[
|
||||
'id' => new external_value(PARAM_INT, 'The purpose ID'),
|
||||
'name' => new external_value(PARAM_TEXT, 'The purpose name'),
|
||||
]
|
||||
);
|
||||
|
||||
return new external_single_structure([
|
||||
'options' => new external_multiple_structure($optiondefinition),
|
||||
'warnings' => new external_warnings()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for get_activity_options().
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function get_activity_options_parameters() {
|
||||
return new external_function_parameters([
|
||||
'nodefaults' => new external_value(PARAM_BOOL, 'Whether to fetch all activities or only those without defaults',
|
||||
VALUE_DEFAULT, false),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of activity options for setting data registry defaults.
|
||||
*
|
||||
* @param boolean $nodefaults If false, it will fetch all of the activities. Otherwise, it will only fetch the activities
|
||||
* that don't have defaults yet (e.g. when adding a new activity module defaults).
|
||||
* @return array
|
||||
*/
|
||||
public static function get_activity_options($nodefaults) {
|
||||
$warnings = [];
|
||||
|
||||
$params = self::validate_parameters(self::get_activity_options_parameters(), [
|
||||
'nodefaults' => $nodefaults,
|
||||
]);
|
||||
$nodefaults = $params['nodefaults'];
|
||||
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
|
||||
// Get activity module plugin info.
|
||||
$pluginmanager = \core_plugin_manager::instance();
|
||||
$modplugins = $pluginmanager->get_enabled_plugins('mod');
|
||||
$modoptions = [];
|
||||
|
||||
// Get the module-level defaults. data_registry::get_defaults falls back to this when there are no activity defaults.
|
||||
list($levelpurpose, $levelcategory) = data_registry::get_defaults(CONTEXT_MODULE);
|
||||
foreach ($modplugins as $name) {
|
||||
// Check if we have default purpose and category for this module if we want don't want to fetch everything.
|
||||
if ($nodefaults) {
|
||||
list($purpose, $category) = data_registry::get_defaults(CONTEXT_MODULE, $name);
|
||||
// Compare this with the module-level defaults.
|
||||
if ($purpose !== $levelpurpose || $category !== $levelcategory) {
|
||||
// If the defaults for this activity has been already set, there's no need to add this in the list of options.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$displayname = $pluginmanager->plugin_name('mod_' . $name);
|
||||
$modoptions[] = (object)[
|
||||
'name' => $name,
|
||||
'displayname' => $displayname
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'options' => $modoptions,
|
||||
'warnings' => $warnings
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns for get_category_options().
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function get_activity_options_returns() {
|
||||
$optionsdefinition = new external_single_structure(
|
||||
[
|
||||
'name' => new external_value(PARAM_TEXT, 'The plugin name of the activity'),
|
||||
'displayname' => new external_value(PARAM_TEXT, 'The display name of the activity'),
|
||||
]
|
||||
);
|
||||
|
||||
return new external_single_structure([
|
||||
'options' => new external_multiple_structure($optionsdefinition),
|
||||
'warnings' => new external_warnings()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the structure of a tree node (link + child branches).
|
||||
*
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace tool_dataprivacy\external;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use core\external\persistent_exporter;
|
||||
use tool_dataprivacy\category;
|
||||
use tool_dataprivacy\context_instance;
|
||||
|
||||
/**
|
||||
* Class for exporting field data.
|
||||
@@ -53,4 +55,25 @@ class category_exporter extends persistent_exporter {
|
||||
'context' => 'context',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function that fetches a category name from the given ID.
|
||||
*
|
||||
* @param int $categoryid The category ID. Could be INHERIT (false, -1), NOT_SET (0), or the actual ID.
|
||||
* @return string The purpose name.
|
||||
*/
|
||||
public static function get_name($categoryid) {
|
||||
global $PAGE;
|
||||
if ($categoryid === false || $categoryid == context_instance::INHERIT) {
|
||||
return get_string('inherit', 'tool_dataprivacy');
|
||||
} else if ($categoryid == context_instance::NOTSET) {
|
||||
return get_string('notset', 'tool_dataprivacy');
|
||||
} else {
|
||||
$purpose = new category($categoryid);
|
||||
$output = $PAGE->get_renderer('tool_dataprivacy');
|
||||
$exporter = new self($purpose, ['context' => \context_system::instance()]);
|
||||
$data = $exporter->export($output);
|
||||
return $data->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ use core\external\persistent_exporter;
|
||||
use DateInterval;
|
||||
use Exception;
|
||||
use renderer_base;
|
||||
use tool_dataprivacy\context_instance;
|
||||
use tool_dataprivacy\purpose;
|
||||
|
||||
/**
|
||||
@@ -143,4 +144,25 @@ class purpose_exporter extends persistent_exporter {
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function that fetches a purpose name from the given ID.
|
||||
*
|
||||
* @param int $purposeid The purpose ID. Could be INHERIT (false, -1), NOT_SET (0), or the actual ID.
|
||||
* @return string The purpose name.
|
||||
*/
|
||||
public static function get_name($purposeid) {
|
||||
global $PAGE;
|
||||
if ($purposeid === false || $purposeid == context_instance::INHERIT) {
|
||||
return get_string('inherit', 'tool_dataprivacy');
|
||||
} else if ($purposeid == context_instance::NOTSET) {
|
||||
return get_string('notset', 'tool_dataprivacy');
|
||||
} else {
|
||||
$purpose = new purpose($purposeid);
|
||||
$output = $PAGE->get_renderer('tool_dataprivacy');
|
||||
$exporter = new self($purpose, ['context' => \context_system::instance()]);
|
||||
$data = $exporter->export($output);
|
||||
return $data->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This file contains the defaults form.
|
||||
*
|
||||
* @package tool_dataprivacy
|
||||
* @copyright 2018 David Monllao
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_dataprivacy\form;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use \tool_dataprivacy\output\data_registry_page;
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/dataprivacy/lib.php');
|
||||
|
||||
/**
|
||||
* Context levels defaults form.
|
||||
*
|
||||
* @package tool_dataprivacy
|
||||
* @copyright 2018 David Monllao
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class defaults extends \moodleform {
|
||||
|
||||
/**
|
||||
* Define the form.
|
||||
*/
|
||||
public function definition() {
|
||||
global $OUTPUT;
|
||||
|
||||
$mform = $this->_form;
|
||||
$mform->setDisableShortforms();
|
||||
|
||||
$notification = $OUTPUT->notification(get_string('defaultsinfo', 'tool_dataprivacy'),
|
||||
\core\output\notification::NOTIFY_INFO);
|
||||
$mform->addElement('html', $notification);
|
||||
|
||||
foreach ($this->_customdata['levels'] as $level => $classname) {
|
||||
|
||||
$mform->addElement('header', $classname . '-header',
|
||||
get_string('contextlevelname' . $level, 'tool_dataprivacy'));
|
||||
|
||||
list($purposevar, $categoryvar) = \tool_dataprivacy\data_registry::var_names_from_context($classname);
|
||||
|
||||
$includeinherit = true;
|
||||
if ($level == CONTEXT_SYSTEM) {
|
||||
$includeinherit = false;
|
||||
}
|
||||
|
||||
$categoryoptions = data_registry_page::category_options($this->_customdata['categories'], false, $includeinherit);
|
||||
$purposeoptions = data_registry_page::category_options($this->_customdata['purposes'], false, $includeinherit);
|
||||
|
||||
$mform->addElement('select', $categoryvar, get_string('category', 'tool_dataprivacy'), $categoryoptions);
|
||||
$mform->addHelpButton($categoryvar, 'categorydefault', 'tool_dataprivacy');
|
||||
$mform->setType($categoryvar, PARAM_INT);
|
||||
|
||||
$mform->addElement('select', $purposevar, get_string('purpose', 'tool_dataprivacy'), $purposeoptions);
|
||||
$mform->addHelpButton($purposevar, 'purposedefault', 'tool_dataprivacy');
|
||||
$mform->setType($purposevar, PARAM_INT);
|
||||
}
|
||||
|
||||
$this->add_action_buttons(true, get_string('savechanges'));
|
||||
}
|
||||
}
|
||||
@@ -425,7 +425,7 @@ class data_registry_page implements renderable, templatable {
|
||||
/**
|
||||
* From a list of purpose persistents to a list of id => name purposes.
|
||||
*
|
||||
* @param \tool_dataprivacy\purpose $purposes
|
||||
* @param \tool_dataprivacy\purpose[] $purposes
|
||||
* @param bool $includenotset
|
||||
* @param bool $includeinherit
|
||||
* @return string[]
|
||||
@@ -442,7 +442,7 @@ class data_registry_page implements renderable, templatable {
|
||||
/**
|
||||
* From a list of category persistents to a list of id => name categories.
|
||||
*
|
||||
* @param \tool_dataprivacy\category $categories
|
||||
* @param \tool_dataprivacy\category[] $categories
|
||||
* @param bool $includenotset
|
||||
* @param bool $includeinherit
|
||||
* @return string[]
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class containing data for the data registry defaults.
|
||||
*
|
||||
* @package tool_dataprivacy
|
||||
* @copyright 2018 Jun Pataleta
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_dataprivacy\output;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use action_menu_link_primary;
|
||||
use coding_exception;
|
||||
use moodle_exception;
|
||||
use moodle_url;
|
||||
use renderable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use templatable;
|
||||
use tool_dataprivacy\data_registry;
|
||||
use tool_dataprivacy\external\category_exporter;
|
||||
use tool_dataprivacy\external\purpose_exporter;
|
||||
|
||||
/**
|
||||
* Class containing data for the data registry defaults.
|
||||
*
|
||||
* @copyright 2018 Jun Pataleta
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class defaults_page implements renderable, templatable {
|
||||
|
||||
/** @var int $mode The display mode. */
|
||||
protected $mode = null;
|
||||
|
||||
/** @var int $category The default category for the given mode. */
|
||||
protected $category = null;
|
||||
|
||||
/** @var int $purpose The default purpose for the given mode. */
|
||||
protected $purpose = null;
|
||||
|
||||
/** @var stdClass[] $otherdefaults Other defaults for the given mode. */
|
||||
protected $otherdefaults = [];
|
||||
|
||||
/** @var bool $canedit Whether editing is allowed. */
|
||||
protected $canedit = false;
|
||||
|
||||
/**
|
||||
* Construct this renderable.
|
||||
*
|
||||
* @param int $mode The display mode.
|
||||
* @param int $category The default category for the given mode.
|
||||
* @param int $purpose The default purpose for the given mode.
|
||||
* @param stdClass[] $otherdefaults Other defaults for the given mode.
|
||||
* @param bool $canedit Whether editing is allowed.
|
||||
*/
|
||||
public function __construct($mode, $category, $purpose, $otherdefaults = [], $canedit = false) {
|
||||
$this->mode = $mode;
|
||||
$this->category = $category;
|
||||
$this->purpose = $purpose;
|
||||
$this->otherdefaults = $otherdefaults;
|
||||
$this->canedit = $canedit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
* @return stdClass
|
||||
* @throws coding_exception
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
public function export_for_template(renderer_base $output) {
|
||||
$data = new stdClass();
|
||||
|
||||
// Set tab URLs.
|
||||
$coursecaturl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_COURSECAT]);
|
||||
$courseurl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_COURSE]);
|
||||
$moduleurl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_MODULE]);
|
||||
$blockurl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_BLOCK]);
|
||||
$data->coursecaturl = $coursecaturl;
|
||||
$data->courseurl = $courseurl;
|
||||
$data->moduleurl = $moduleurl;
|
||||
$data->blockurl = $blockurl;
|
||||
|
||||
// Set display mode.
|
||||
switch ($this->mode) {
|
||||
case CONTEXT_COURSECAT:
|
||||
$data->modecoursecat = true;
|
||||
break;
|
||||
case CONTEXT_COURSE:
|
||||
$data->modecourse = true;
|
||||
break;
|
||||
case CONTEXT_MODULE:
|
||||
$data->modemodule = true;
|
||||
break;
|
||||
case CONTEXT_BLOCK:
|
||||
$data->modeblock = true;
|
||||
break;
|
||||
default:
|
||||
$data->modecoursecat = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set config variables.
|
||||
$configname = \context_helper::get_class_for_level($this->mode);
|
||||
list($purposevar, $categoryvar) = data_registry::var_names_from_context($configname);
|
||||
$data->categoryvar = $categoryvar;
|
||||
$data->purposevar = $purposevar;
|
||||
|
||||
// Set default category.
|
||||
$data->categoryid = $this->category;
|
||||
$data->category = category_exporter::get_name($this->category);
|
||||
|
||||
// Set default purpose.
|
||||
$data->purposeid = $this->purpose;
|
||||
$data->purpose = purpose_exporter::get_name($this->purpose);
|
||||
|
||||
// Set other defaults.
|
||||
$otherdefaults = [];
|
||||
$url = new moodle_url('#');
|
||||
foreach ($this->otherdefaults as $pluginname => $values) {
|
||||
$defaults = [
|
||||
'name' => $values->name,
|
||||
'category' => category_exporter::get_name($values->category),
|
||||
'purpose' => purpose_exporter::get_name($values->purpose),
|
||||
];
|
||||
if ($this->canedit) {
|
||||
$actions = [];
|
||||
// Edit link.
|
||||
$editattrs = [
|
||||
'data-action' => 'edit-activity-defaults',
|
||||
'data-contextlevel' => $this->mode,
|
||||
'data-activityname' => $pluginname,
|
||||
'data-category' => $values->category,
|
||||
'data-purpose' => $values->purpose,
|
||||
];
|
||||
$editlink = new action_menu_link_primary($url, new \pix_icon('t/edit', get_string('edit')),
|
||||
get_string('edit'), $editattrs);
|
||||
$actions[] = $editlink->export_for_template($output);
|
||||
|
||||
// Delete link.
|
||||
$deleteattrs = [
|
||||
'data-action' => 'delete-activity-defaults',
|
||||
'data-contextlevel' => $this->mode,
|
||||
'data-activityname' => $pluginname,
|
||||
'data-activitydisplayname' => $values->name,
|
||||
];
|
||||
$deletelink = new action_menu_link_primary($url, new \pix_icon('t/delete', get_string('delete')),
|
||||
get_string('delete'), $deleteattrs);
|
||||
$actions[] = $deletelink->export_for_template($output);
|
||||
|
||||
$defaults['actions'] = $actions;
|
||||
}
|
||||
$otherdefaults[] = (object)$defaults;
|
||||
}
|
||||
$data->otherdefaults = $otherdefaults;
|
||||
|
||||
$data->canedit = $this->canedit;
|
||||
$data->contextlevel = $this->mode;
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -173,4 +173,44 @@ $functions = [
|
||||
'ajax' => true,
|
||||
'loginrequired' => true,
|
||||
],
|
||||
'tool_dataprivacy_set_context_defaults' => [
|
||||
'classname' => 'tool_dataprivacy\external',
|
||||
'methodname' => 'set_context_defaults',
|
||||
'classpath' => '',
|
||||
'description' => 'Updates the default category and purpose for a given context level (and optionally, a plugin)',
|
||||
'type' => 'write',
|
||||
'capabilities' => 'tool/dataprivacy:managedataregistry',
|
||||
'ajax' => true,
|
||||
'loginrequired' => true,
|
||||
],
|
||||
'tool_dataprivacy_get_category_options' => [
|
||||
'classname' => 'tool_dataprivacy\external',
|
||||
'methodname' => 'get_category_options',
|
||||
'classpath' => '',
|
||||
'description' => 'Fetches a list of data category options',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'tool/dataprivacy:managedataregistry',
|
||||
'ajax' => true,
|
||||
'loginrequired' => true,
|
||||
],
|
||||
'tool_dataprivacy_get_purpose_options' => [
|
||||
'classname' => 'tool_dataprivacy\external',
|
||||
'methodname' => 'get_purpose_options',
|
||||
'classpath' => '',
|
||||
'description' => 'Fetches a list of data storage purpose options',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'tool/dataprivacy:managedataregistry',
|
||||
'ajax' => true,
|
||||
'loginrequired' => true,
|
||||
],
|
||||
'tool_dataprivacy_get_activity_options' => [
|
||||
'classname' => 'tool_dataprivacy\external',
|
||||
'methodname' => 'get_activity_options',
|
||||
'classpath' => '',
|
||||
'description' => 'Fetches a list of activity options',
|
||||
'type' => 'read',
|
||||
'capabilities' => 'tool/dataprivacy:managedataregistry',
|
||||
'ajax' => true,
|
||||
'loginrequired' => true,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -32,47 +32,39 @@ $title = get_string('setdefaults', 'tool_dataprivacy');
|
||||
|
||||
\tool_dataprivacy\page_helper::setup($url, $title, 'dataregistry');
|
||||
|
||||
$levels = \context_helper::get_all_levels();
|
||||
// They are set through the context level site and user.
|
||||
unset($levels[CONTEXT_SYSTEM]);
|
||||
unset($levels[CONTEXT_USER]);
|
||||
$mode = optional_param('mode', CONTEXT_COURSECAT, PARAM_INT);
|
||||
$classname = context_helper::get_class_for_level($mode);
|
||||
list($purposevar, $categoryvar) = \tool_dataprivacy\data_registry::var_names_from_context($classname);
|
||||
$purpose = get_config('tool_dataprivacy', $purposevar);
|
||||
$category = get_config('tool_dataprivacy', $categoryvar);
|
||||
|
||||
$customdata = [
|
||||
'levels' => $levels,
|
||||
'purposes' => \tool_dataprivacy\api::get_purposes(),
|
||||
'categories' => \tool_dataprivacy\api::get_categories(),
|
||||
];
|
||||
$form = new \tool_dataprivacy\form\defaults($PAGE->url->out(false), $customdata);
|
||||
$otherdefaults = [];
|
||||
if ($mode == CONTEXT_MODULE) {
|
||||
// Get activity module plugin info.
|
||||
$pluginmanager = core_plugin_manager::instance();
|
||||
$modplugins = $pluginmanager->get_enabled_plugins('mod');
|
||||
|
||||
$toform = new stdClass();
|
||||
foreach ($levels as $level => $classname) {
|
||||
list($purposevar, $categoryvar) = \tool_dataprivacy\data_registry::var_names_from_context($classname);
|
||||
$toform->{$purposevar} = get_config('tool_dataprivacy', $purposevar);
|
||||
$toform->{$categoryvar} = get_config('tool_dataprivacy', $categoryvar);
|
||||
}
|
||||
$form->set_data($toform);
|
||||
|
||||
$returnurl = new \moodle_url('/admin/tool/dataprivacy/dataregistry.php');
|
||||
if ($form->is_cancelled()) {
|
||||
redirect($returnurl);
|
||||
} else if ($data = $form->get_data()) {
|
||||
|
||||
foreach ($levels as $level => $classname) {
|
||||
|
||||
list($purposevar, $categoryvar) = \tool_dataprivacy\data_registry::var_names_from_context($classname);
|
||||
|
||||
if (isset($data->{$purposevar})) {
|
||||
set_config($purposevar, $data->{$purposevar}, 'tool_dataprivacy');
|
||||
}
|
||||
if (isset($data->{$categoryvar})) {
|
||||
set_config($categoryvar, $data->{$categoryvar}, 'tool_dataprivacy');
|
||||
foreach ($modplugins as $name) {
|
||||
list($purposevar, $categoryvar) = \tool_dataprivacy\data_registry::var_names_from_context($classname, $name);
|
||||
$plugincategory = get_config('tool_dataprivacy', $categoryvar);
|
||||
$pluginpurpose = get_config('tool_dataprivacy', $purposevar);
|
||||
if ($plugincategory === false && $pluginpurpose === false) {
|
||||
// If no purpose and category has been set for this plugin, then there's no need to show this on the list.
|
||||
continue;
|
||||
}
|
||||
|
||||
$displayname = $pluginmanager->plugin_name('mod_' . $name);
|
||||
$otherdefaults[$name] = (object)[
|
||||
'name' => $displayname,
|
||||
'category' => $plugincategory,
|
||||
'purpose' => $pluginpurpose,
|
||||
];
|
||||
}
|
||||
redirect($returnurl, get_string('defaultssaved', 'tool_dataprivacy'),
|
||||
0, \core\output\notification::NOTIFY_SUCCESS);
|
||||
}
|
||||
|
||||
$defaultspage = new \tool_dataprivacy\output\defaults_page($mode, $category, $purpose, $otherdefaults, true);
|
||||
|
||||
$output = $PAGE->get_renderer('tool_dataprivacy');
|
||||
echo $output->header();
|
||||
$form->display();
|
||||
echo $output->render_from_template('tool_dataprivacy/defaults_page', $defaultspage->export_for_template($output));
|
||||
echo $output->footer();
|
||||
|
||||
@@ -28,6 +28,7 @@ $string['pluginname'] = 'Data privacy';
|
||||
$string['pluginname_help'] = 'Data privacy plugin';
|
||||
$string['activitiesandresources'] = 'Activities and resources';
|
||||
$string['addcategory'] = 'Add category';
|
||||
$string['addnewdefaults'] = 'Add a new module default';
|
||||
$string['addpurpose'] = 'Add purpose';
|
||||
$string['approve'] = 'Approve';
|
||||
$string['approverequest'] = 'Approve request';
|
||||
@@ -76,9 +77,12 @@ $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.';
|
||||
$string['defaultsinfo'] = 'Default categories and purposes are applied to all new and existing instances where a value is not set.';
|
||||
$string['defaultswarninginfo'] = 'Warning: Changing these defaults may affect the retention period of existing instances.';
|
||||
$string['deletecategory'] = 'Delete category';
|
||||
$string['deletecategorytext'] = 'Are you sure you want to delete the category \'{$a}\'?';
|
||||
$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 files from completed data requests that have expired';
|
||||
$string['deletepurpose'] = 'Delete purpose';
|
||||
@@ -95,6 +99,8 @@ $string['dporolemapping_desc'] = 'The privacy officer can manage data requests.
|
||||
$string['editcategories'] = 'Edit categories';
|
||||
$string['editcategory'] = 'Edit category';
|
||||
$string['editcategories'] = 'Edit categories';
|
||||
$string['editdefaults'] = 'Edit defaults: {$a}';
|
||||
$string['editmoduledefaults'] = 'Edit module defaults';
|
||||
$string['editpurpose'] = 'Edit purpose';
|
||||
$string['editpurposes'] = 'Edit purposes';
|
||||
$string['effectiveretentionperiodcourse'] = '{$a} (after the course end date)';
|
||||
@@ -185,6 +191,7 @@ $string['nopurposes'] = 'There are no purposes yet';
|
||||
$string['nosubjectaccessrequests'] = 'There are no data requests that you need to act on';
|
||||
$string['nosystemdefaults'] = 'Site purpose and category have not yet been defined.';
|
||||
$string['notset'] = 'Not set (use the default value)';
|
||||
$string['overrideinstances'] = 'Reset instances with custom values';
|
||||
$string['pluginregistry'] = 'Plugin privacy registry';
|
||||
$string['pluginregistrytitle'] = 'Plugin privacy compliance registry';
|
||||
$string['privacy'] = 'Privacy';
|
||||
|
||||
@@ -28,3 +28,7 @@ dd a.contactdpo {
|
||||
[data-region="data-requests-table"] .moodle-actionmenu {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.context-level-view {
|
||||
margin: 1em;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template tool_dataprivacy/category_purpose_form
|
||||
|
||||
Manage data registry defaults.
|
||||
|
||||
Classes required for JS:
|
||||
|
||||
Data attributes required for JS:
|
||||
|
||||
Context variables required for this template:
|
||||
* actionurl String The action URL.
|
||||
* contextlevel Number - The context level.
|
||||
* modemodule Boolean - Whether to display the activity select element.
|
||||
* activityoptions Array - An array of objects for the activity select element.
|
||||
* categoryoptions Array - An array of objects for the category select element.
|
||||
* purposeoptions Array - An array of objects for the purpose select element.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"actionurl": "#",
|
||||
"contextlevel": 70,
|
||||
"newactivitydefaults": true,
|
||||
"modemodule": true,
|
||||
"activityoptions": [
|
||||
{ "name": "assign", "displayname": "Assignment" },
|
||||
{ "name": "forum", "displayname": "Forum", "selected": true },
|
||||
{ "name": "lesson", "displayname": "Lesson" },
|
||||
{ "name": "quiz", "displayname": "Quiz" }
|
||||
],
|
||||
"categoryoptions": [
|
||||
{ "id": 1, "name": "Category 1" },
|
||||
{ "id": 2, "name": "Category 2", "selected": true },
|
||||
{ "id": 3, "name": "Category 3" }
|
||||
],
|
||||
"purposeoptions": [
|
||||
{ "id": 1, "name": "Purpose 1" },
|
||||
{ "id": 2, "name": "Purpose 2" },
|
||||
{ "id": 3, "name": "Purpose 3", "selected": true }
|
||||
]
|
||||
}
|
||||
}}
|
||||
|
||||
<div class="alert alert-warning" role="alert">
|
||||
{{#str}}defaultswarninginfo, tool_dataprivacy{{/str}}
|
||||
</div>
|
||||
<form method="post" action="{{actionurl}}" id="category_purpose_form">
|
||||
<input type="hidden" value="{{contextlevel}}" id="contextlevel" />
|
||||
{{#modemodule}}
|
||||
<div class="form-group">
|
||||
<label for="activity">{{#str}}activitymodule{{/str}}</label>
|
||||
{{^newactivitydefaults}}
|
||||
<input type="hidden" id="activity" value="{{#activityoptions}}{{#selected}}{{name}}{{/selected}}{{/activityoptions}}" />
|
||||
{{/newactivitydefaults}}
|
||||
<select class="form-control" {{#newactivitydefaults}}id="activity" {{/newactivitydefaults}}{{^newactivitydefaults}}disabled{{/newactivitydefaults}}>
|
||||
{{#activityoptions}}
|
||||
<option value="{{name}}" {{#selected}}selected{{/selected}}>{{displayname}}</option>
|
||||
{{/activityoptions}}
|
||||
</select>
|
||||
</div>
|
||||
{{/modemodule}}
|
||||
<div class="form-group">
|
||||
<label for="category">{{#str}}category, tool_dataprivacy{{/str}}</label>
|
||||
<select class="form-control" id="category">
|
||||
{{#categoryoptions}}
|
||||
<option value="{{id}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/categoryoptions}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="purpose">{{#str}}purpose, tool_dataprivacy{{/str}}</label>
|
||||
<select class="form-control" id="purpose">
|
||||
{{#purposeoptions}}
|
||||
<option value="{{id}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/purposeoptions}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="1" id="override">
|
||||
<label class="form-check-label" for="override">
|
||||
{{#str}}overrideinstances, tool_dataprivacy{{/str}}
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,74 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template tool_dataprivacy/defaults_display
|
||||
|
||||
Renders the current default category and purpose.
|
||||
|
||||
Classes required for JS:
|
||||
|
||||
Data attributes required for JS:
|
||||
|
||||
Context variables required for this template:
|
||||
* contextlevel Number - The context level.
|
||||
* categoryid Number - The category ID.
|
||||
* purposeid Number - The purpose ID.
|
||||
* category String - The category name.
|
||||
* purpose String - The purpose name.
|
||||
* canedit Boolean - Whether this is being rendered for editing purposes.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"category": "Awesome default category",
|
||||
"categoryid": 1,
|
||||
"purpose": "Awesome default purpose",
|
||||
"purposeid": 2,
|
||||
"canedit": true,
|
||||
"contextlevel": 70
|
||||
}
|
||||
}}
|
||||
<div class="row-fluid rtl-compatible m-t-1 m-b-1">
|
||||
<div class="col-md-9 span9">
|
||||
<div class="row-fluid rtl-compatible m-t-1 m-b-1">
|
||||
<div class="col-md-3 span3">
|
||||
<strong>{{#str}}category, tool_dataprivacy{{/str}}</strong>
|
||||
</div>
|
||||
<div class="col-md-9 span9">
|
||||
{{category}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid rtl-compatible m-t-1 m-b-1">
|
||||
<div class="col-md-3 span3">
|
||||
<strong>{{#str}}purpose, tool_dataprivacy{{/str}}</strong>
|
||||
</div>
|
||||
<div class="col-md-9 span9">
|
||||
{{purpose}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 span3 align-self-center">
|
||||
{{#canedit}}
|
||||
<button class="btn btn-default" {{!
|
||||
}}data-action="edit-level-defaults" {{!
|
||||
}}data-contextlevel="{{contextlevel}}" {{!
|
||||
}}data-category="{{categoryid}}" {{!
|
||||
}}data-purpose="{{purposeid}}">
|
||||
{{#str}}edit{{/str}}
|
||||
</button>
|
||||
{{/canedit}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,147 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template tool_dataprivacy/defaults_page
|
||||
|
||||
Manage data registry defaults.
|
||||
|
||||
Classes required for JS:
|
||||
|
||||
Data attributes required for JS:
|
||||
|
||||
Context variables required for this template:
|
||||
* contextlevel Number - The context level.
|
||||
* modecoursecat Boolean - Whether we're displaying defaults for course categories.
|
||||
* modecourse Boolean - Whether we're displaying defaults for courses.
|
||||
* modemodule Boolean - Whether we're displaying defaults for activity modules.
|
||||
* modeblock Boolean - Whether we're displaying defaults for blocks.
|
||||
* coursecaturl String - The URL for the course category defaults tab.
|
||||
* courseurl String - The URL for the course defaults tab.
|
||||
* moduleurl String - The URL for the activity module defaults tab.
|
||||
* blockurl String - The URL for the block defaults tab.
|
||||
* purposeid Number - The purpose ID for this context level.
|
||||
* canedit Boolean - Whether this is being rendered for editing purposes.
|
||||
* categoryid Number - The ID of the default category for this context level.
|
||||
* purposeid Number - The ID of the default purpose for this context level.
|
||||
* category String - The category name.
|
||||
* purpose String - The purpose name.
|
||||
* otherdefaults Array - An array containing the defaults for the activity modules.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"contextlevel": 70,
|
||||
"modecoursecat": false,
|
||||
"modecourse": false,
|
||||
"modemodule": true,
|
||||
"modeblock": false,
|
||||
"coursecaturl": "#",
|
||||
"courseurl": "#",
|
||||
"moduleurl": "#",
|
||||
"blockurl": "#",
|
||||
"category": "Awesome default category",
|
||||
"purpose": "Awesome default purpose",
|
||||
"canedit": true,
|
||||
"otherdefaults": [
|
||||
{
|
||||
"name": "Assignment",
|
||||
"category": "Category for activity modules",
|
||||
"purpose": "Assessments"
|
||||
},
|
||||
{
|
||||
"name": "Forum",
|
||||
"category": "Category for activity modules",
|
||||
"purpose": "Social interactions"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-tabs card-header-tabs">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#modecoursecat}}active{{/modecoursecat}}" href="{{coursecaturl}}">{{#str}}categories{{/str}}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#modecourse}}active{{/modecourse}}" href="{{courseurl}}">{{#str}}courses{{/str}}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#modemodule}}active{{/modemodule}}" href="{{moduleurl}}">{{#str}}activitymodules{{/str}}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#modeblock}}active{{/modeblock}}" href="{{blockurl}}">{{#str}}blocks{{/str}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body context-level-view">
|
||||
<div class="alert alert-primary" role="alert">
|
||||
{{#str}}defaultsinfo, tool_dataprivacy{{/str}}
|
||||
</div>
|
||||
<h4 class="card-title" id="defaults-header">
|
||||
{{#modecoursecat}}{{#str}}categories{{/str}}{{/modecoursecat}}
|
||||
{{#modecourse}}{{#str}}courses{{/str}}{{/modecourse}}
|
||||
{{#modemodule}}{{#str}}activitymodules{{/str}}{{/modemodule}}
|
||||
{{#modeblock}}{{#str}}blocks{{/str}}{{/modeblock}}
|
||||
</h4>
|
||||
<div>
|
||||
{{> tool_dataprivacy/defaults_display}}
|
||||
{{#canedit}}
|
||||
{{#modemodule}}
|
||||
<button class="btn btn-primary" data-action="new-activity-defaults" data-contextlevel="{{contextlevel}}">
|
||||
{{#str}}addnewdefaults, tool_dataprivacy{{/str}}
|
||||
</button>
|
||||
{{/modemodule}}
|
||||
{{/canedit}}
|
||||
{{#modemodule}}
|
||||
<table class="m-t-1 table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th scope="col">{{#str}}category, tool_dataprivacy{{/str}}</th>
|
||||
<th scope="col">{{#str}}purpose, tool_dataprivacy{{/str}}</th>
|
||||
{{#canedit}}
|
||||
<th scope="col">{{#str}}actions{{/str}}</th>
|
||||
{{/canedit}}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#otherdefaults}}
|
||||
<tr>
|
||||
<th scope="row">{{name}}</th>
|
||||
<td>{{category}}</td>
|
||||
<td>{{purpose}}</td>
|
||||
{{#canedit}}
|
||||
<td>
|
||||
{{#actions}}
|
||||
{{> core/action_menu_link}}
|
||||
{{/actions}}
|
||||
</td>
|
||||
{{/canedit}}
|
||||
</tr>
|
||||
{{/otherdefaults}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/modemodule}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#js}}
|
||||
// Initialise the JS.
|
||||
require(['tool_dataprivacy/defaultsactions'], function(ActionsMod) {
|
||||
ActionsMod.init();
|
||||
});
|
||||
{{/js}}
|
||||
@@ -0,0 +1,41 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template tool_dataprivacy/delete_activity_defaults
|
||||
|
||||
Renders the confirmation.
|
||||
|
||||
Classes required for JS:
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* activityname String - The activity name.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"activityname": "Assignment"
|
||||
}
|
||||
}}
|
||||
|
||||
<div class="alert alert-warning" role="alert">
|
||||
{{#str}}defaultswarninginfo, tool_dataprivacy{{/str}}
|
||||
</div>
|
||||
<div>
|
||||
{{#str}}deletedefaultsconfirmation, tool_dataprivacy, {{activityname}}{{/str}}
|
||||
</div>
|
||||
@@ -1321,6 +1321,164 @@ class tool_dataprivacy_api_testcase extends advanced_testcase {
|
||||
$this->assertEquals($data->contexts->used, $contextids, '', 0.0, 10, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for \tool_dataprivacy_api_testcase::test_set_context_defaults
|
||||
*/
|
||||
public function set_context_defaults_provider() {
|
||||
$contextlevels = [
|
||||
[CONTEXT_COURSECAT],
|
||||
[CONTEXT_COURSE],
|
||||
[CONTEXT_MODULE],
|
||||
[CONTEXT_BLOCK],
|
||||
];
|
||||
$paramsets = [
|
||||
[true, true, false, false], // Inherit category and purpose, Not for activity, Don't override.
|
||||
[true, false, false, false], // Inherit category but not purpose, Not for activity, Don't override.
|
||||
[false, true, false, false], // Inherit purpose but not category, Not for activity, Don't override.
|
||||
[false, false, false, false], // Don't inherit both category and purpose, Not for activity, Don't override.
|
||||
[false, false, false, true], // Don't inherit both category and purpose, Not for activity, Override instances.
|
||||
];
|
||||
$data = [];
|
||||
foreach ($contextlevels as $level) {
|
||||
foreach ($paramsets as $set) {
|
||||
$data[] = array_merge($level, $set);
|
||||
}
|
||||
if ($level == CONTEXT_MODULE) {
|
||||
// Add a combination where defaults for activity is being set.
|
||||
$data[] = [CONTEXT_MODULE, false, false, true, false];
|
||||
$data[] = [CONTEXT_MODULE, false, false, true, true];
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for \tool_dataprivacy\api::set_context_defaults()
|
||||
*
|
||||
* @dataProvider set_context_defaults_provider
|
||||
* @param int $contextlevel The context level
|
||||
* @param bool $inheritcategory Whether to set category value as INHERIT.
|
||||
* @param bool $inheritpurpose Whether to set purpose value as INHERIT.
|
||||
* @param bool $foractivity Whether to set defaults for an activity.
|
||||
* @param bool $override Whether to override instances.
|
||||
*/
|
||||
public function test_set_context_defaults($contextlevel, $inheritcategory, $inheritpurpose, $foractivity, $override) {
|
||||
$this->setAdminUser();
|
||||
|
||||
$generator = $this->getDataGenerator();
|
||||
|
||||
// Generate course cat, course, block, assignment, forum instances.
|
||||
$coursecat = $generator->create_category();
|
||||
$course = $generator->create_course(['category' => $coursecat->id]);
|
||||
$block = $generator->create_block('online_users');
|
||||
$assign = $generator->create_module('assign', ['course' => $course->id]);
|
||||
$forum = $generator->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$coursecatcontext = context_coursecat::instance($coursecat->id);
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
$blockcontext = context_block::instance($block->id);
|
||||
|
||||
list($course, $assigncm) = get_course_and_cm_from_instance($assign->id, 'assign');
|
||||
list($course, $forumcm) = get_course_and_cm_from_instance($forum->id, 'forum');
|
||||
$assigncontext = context_module::instance($assigncm->id);
|
||||
$forumcontext = context_module::instance($forumcm->id);
|
||||
|
||||
// Generate purposes and categories.
|
||||
$category1 = api::create_category((object)['name' => 'Test category 1']);
|
||||
$category2 = api::create_category((object)['name' => 'Test category 2']);
|
||||
$purpose1 = api::create_purpose((object)[
|
||||
'name' => 'Test purpose 1', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a'
|
||||
]);
|
||||
$purpose2 = api::create_purpose((object)[
|
||||
'name' => 'Test purpose 2', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a'
|
||||
]);
|
||||
|
||||
// Assign purposes and categories to contexts.
|
||||
$coursecatctxinstance = api::set_context_instance((object) [
|
||||
'contextid' => $coursecatcontext->id,
|
||||
'purposeid' => $purpose1->get('id'),
|
||||
'categoryid' => $category1->get('id'),
|
||||
]);
|
||||
$coursectxinstance = api::set_context_instance((object) [
|
||||
'contextid' => $coursecontext->id,
|
||||
'purposeid' => $purpose1->get('id'),
|
||||
'categoryid' => $category1->get('id'),
|
||||
]);
|
||||
$blockctxinstance = api::set_context_instance((object) [
|
||||
'contextid' => $blockcontext->id,
|
||||
'purposeid' => $purpose1->get('id'),
|
||||
'categoryid' => $category1->get('id'),
|
||||
]);
|
||||
$assignctxinstance = api::set_context_instance((object) [
|
||||
'contextid' => $assigncontext->id,
|
||||
'purposeid' => $purpose1->get('id'),
|
||||
'categoryid' => $category1->get('id'),
|
||||
]);
|
||||
$forumctxinstance = api::set_context_instance((object) [
|
||||
'contextid' => $forumcontext->id,
|
||||
'purposeid' => $purpose1->get('id'),
|
||||
'categoryid' => $category1->get('id'),
|
||||
]);
|
||||
|
||||
$categoryid = $inheritcategory ? context_instance::INHERIT : $category2->get('id');
|
||||
$purposeid = $inheritpurpose ? context_instance::INHERIT : $purpose2->get('id');
|
||||
$activity = '';
|
||||
if ($contextlevel == CONTEXT_MODULE && $foractivity) {
|
||||
$activity = 'assign';
|
||||
}
|
||||
$result = api::set_context_defaults($contextlevel, $categoryid, $purposeid, $activity, $override);
|
||||
$this->assertTrue($result);
|
||||
|
||||
$targetctxinstance = false;
|
||||
switch ($contextlevel) {
|
||||
case CONTEXT_COURSECAT:
|
||||
$targetctxinstance = $coursecatctxinstance;
|
||||
break;
|
||||
case CONTEXT_COURSE:
|
||||
$targetctxinstance = $coursectxinstance;
|
||||
break;
|
||||
case CONTEXT_MODULE:
|
||||
$targetctxinstance = $assignctxinstance;
|
||||
break;
|
||||
case CONTEXT_BLOCK:
|
||||
$targetctxinstance = $blockctxinstance;
|
||||
break;
|
||||
}
|
||||
$this->assertNotFalse($targetctxinstance);
|
||||
|
||||
// Check the context instances.
|
||||
$instanceexists = context_instance::record_exists($targetctxinstance->get('id'));
|
||||
if ($override) {
|
||||
// If overridden, context instances on this context level would have been deleted.
|
||||
$this->assertFalse($instanceexists);
|
||||
|
||||
// Check forum context instance.
|
||||
$forumctxexists = context_instance::record_exists($forumctxinstance->get('id'));
|
||||
if ($contextlevel != CONTEXT_MODULE || $foractivity) {
|
||||
// The forum context instance won't be affected in this test if:
|
||||
// - The overridden defaults are not for context modules.
|
||||
// - Only the defaults for assign have been set.
|
||||
$this->assertTrue($forumctxexists);
|
||||
} else {
|
||||
// If we're overriding for the whole course module context level,
|
||||
// then this forum context instance will be deleted as well.
|
||||
$this->assertFalse($forumctxexists);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the context instance record remains.
|
||||
$this->assertTrue($instanceexists);
|
||||
}
|
||||
|
||||
// Check defaults.
|
||||
list($defaultpurpose, $defaultcategory) = data_registry::get_defaults($contextlevel, $activity);
|
||||
if (!$inheritpurpose) {
|
||||
$this->assertEquals($purposeid, $defaultpurpose);
|
||||
}
|
||||
if (!$inheritcategory) {
|
||||
$this->assertEquals($categoryid, $defaultcategory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform setup for the test_add_request_contexts_with_status_xxxxx tests.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Step definitions to generate database fixtures for the data privacy tool.
|
||||
*
|
||||
* @package tool_dataprivacy
|
||||
* @category test
|
||||
* @copyright 2018 Jun Pataleta
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
|
||||
use Behat\Gherkin\Node\TableNode as TableNode;
|
||||
use Behat\Behat\Tester\Exception\PendingException as PendingException;
|
||||
use tool_dataprivacy\api;
|
||||
|
||||
/**
|
||||
* Step definitions to generate database fixtures for the data privacy tool.
|
||||
*
|
||||
* @package tool_dataprivacy
|
||||
* @category test
|
||||
* @copyright 2018 Jun Pataleta
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_tool_dataprivacy extends behat_base {
|
||||
|
||||
/**
|
||||
* Each element specifies:
|
||||
* - The data generator suffix used.
|
||||
* - The required fields.
|
||||
* - The mapping between other elements references and database field names.
|
||||
* @var array
|
||||
*/
|
||||
protected static $elements = array(
|
||||
'categories' => array(
|
||||
'datagenerator' => 'category',
|
||||
'required' => array()
|
||||
),
|
||||
'purposes' => array(
|
||||
'datagenerator' => 'purpose',
|
||||
'required' => array()
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates the specified element. More info about available elements in http://docs.moodle.org/dev/Acceptance_testing#Fixtures.
|
||||
*
|
||||
* @Given /^the following data privacy "(?P<element_string>(?:[^"]|\\")*)" exist:$/
|
||||
*
|
||||
* @param string $elementname The name of the entity to add
|
||||
* @param TableNode $data
|
||||
*/
|
||||
public function the_following_data_categories_exist($elementname, TableNode $data) {
|
||||
|
||||
// Now that we need them require the data generators.
|
||||
require_once(__DIR__.'/../../../../../lib/phpunit/classes/util.php');
|
||||
|
||||
if (empty(self::$elements[$elementname])) {
|
||||
throw new PendingException($elementname . ' data generator is not implemented');
|
||||
}
|
||||
|
||||
$datagenerator = testing_util::get_data_generator();
|
||||
$dataprivacygenerator = $datagenerator->get_plugin_generator('tool_dataprivacy');
|
||||
|
||||
$elementdatagenerator = self::$elements[$elementname]['datagenerator'];
|
||||
$requiredfields = self::$elements[$elementname]['required'];
|
||||
if (!empty(self::$elements[$elementname]['switchids'])) {
|
||||
$switchids = self::$elements[$elementname]['switchids'];
|
||||
}
|
||||
|
||||
foreach ($data->getHash() as $elementdata) {
|
||||
|
||||
// Check if all the required fields are there.
|
||||
foreach ($requiredfields as $requiredfield) {
|
||||
if (!isset($elementdata[$requiredfield])) {
|
||||
throw new Exception($elementname . ' requires the field ' . $requiredfield . ' to be specified');
|
||||
}
|
||||
}
|
||||
|
||||
// Switch from human-friendly references to ids.
|
||||
if (isset($switchids)) {
|
||||
foreach ($switchids as $element => $field) {
|
||||
$methodname = 'get_' . $element . '_id';
|
||||
|
||||
// Not all the switch fields are required, default vars will be assigned by data generators.
|
||||
if (isset($elementdata[$element])) {
|
||||
// Temp $id var to avoid problems when $element == $field.
|
||||
$id = $this->{$methodname}($elementdata[$element]);
|
||||
unset($elementdata[$element]);
|
||||
$elementdata[$field] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preprocess the entities that requires a special treatment.
|
||||
if (method_exists($this, 'preprocess_' . $elementdatagenerator)) {
|
||||
$elementdata = $this->{'preprocess_' . $elementdatagenerator}($elementdata);
|
||||
}
|
||||
|
||||
// Creates element.
|
||||
$methodname = 'create_' . $elementdatagenerator;
|
||||
if (method_exists($dataprivacygenerator, $methodname)) {
|
||||
// Using data generators directly.
|
||||
$dataprivacygenerator->{$methodname}($elementdata);
|
||||
|
||||
} else if (method_exists($this, 'process_' . $elementdatagenerator)) {
|
||||
// Using an alternative to the direct data generator call.
|
||||
$this->{'process_' . $elementdatagenerator}($elementdata);
|
||||
} else {
|
||||
throw new PendingException($elementname . ' data generator is not implemented');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data category and data storage purpose for the site.
|
||||
*
|
||||
* @Given /^I set the site category and purpose to "(?P<category_string>(?:[^"]|\\")*)" and "(?P<purpose_string>(?:[^"]|\\")*)"$/
|
||||
*
|
||||
* @param string $category The ID of the category to be set for the instance.
|
||||
* @param string $purpose The ID of the purpose to be set for the instance.
|
||||
*/
|
||||
public function i_set_the_site_category_and_purpose($category, $purpose) {
|
||||
$category = \tool_dataprivacy\category::get_record(['name' => $category]);
|
||||
$purpose = \tool_dataprivacy\purpose::get_record(['name' => $purpose]);
|
||||
$data = (object)[
|
||||
'contextlevel' => CONTEXT_SYSTEM,
|
||||
'categoryid' => $category->get('id'),
|
||||
'purposeid' => $purpose->get('id'),
|
||||
];
|
||||
api::set_contextlevel($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data category and data storage purpose for a course category instance.
|
||||
*
|
||||
* @Given /^I set the category and purpose for the course category "(?P<categoryname_string>(?:[^"]|\\")*)" to "(?P<category_string>(?:[^"]|\\")*)" and "(?P<purpose_string>(?:[^"]|\\")*)"$/
|
||||
*
|
||||
* @param string $name The instance name. It should match the name or the idnumber.
|
||||
* @param string $category The ID of the category to be set for the instance.
|
||||
* @param string $purpose The ID of the purpose to be set for the instance.
|
||||
*/
|
||||
public function i_set_the_category_and_purpose_for_course_category($name, $category, $purpose) {
|
||||
global $DB;
|
||||
|
||||
$params = [
|
||||
'name' => $name,
|
||||
'idnumber' => $name,
|
||||
];
|
||||
$select = 'name = :name OR idnumber = :idnumber';
|
||||
$coursecatid = $DB->get_field_select('course_categories', 'id', $select, $params, MUST_EXIST);
|
||||
$context = context_coursecat::instance($coursecatid);
|
||||
|
||||
$this->set_category_and_purpose($context->id, $category, $purpose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data category and data storage purpose for a course instance.
|
||||
*
|
||||
* @Given /^I set the category and purpose for the course "(?P<coursename_string>(?:[^"]|\\")*)" to "(?P<category_string>(?:[^"]|\\")*)" and "(?P<purpose_string>(?:[^"]|\\")*)"$/
|
||||
*
|
||||
* @param string $name The instance name. It should match the fullname or the shortname, or the idnumber.
|
||||
* @param string $category The ID of the category to be set for the instance.
|
||||
* @param string $purpose The ID of the purpose to be set for the instance.
|
||||
*/
|
||||
public function i_set_the_category_and_purpose_for_course($name, $category, $purpose) {
|
||||
global $DB;
|
||||
|
||||
$params = [
|
||||
'shortname' => $name,
|
||||
'fullname' => $name,
|
||||
'idnumber' => $name,
|
||||
];
|
||||
$select = 'shortname = :shortname OR fullname = :fullname OR idnumber = :idnumber';
|
||||
$courseid = $DB->get_field_select('course', 'id', $select, $params, MUST_EXIST);
|
||||
$context = context_course::instance($courseid);
|
||||
|
||||
$this->set_category_and_purpose($context->id, $category, $purpose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data category and data storage purpose for a course instance.
|
||||
*
|
||||
* @Given /^I set the category and purpose for the "(?P<activityname_string>(?:[^"]|\\")*)" "(?P<activitytype_string>(?:[^"]|\\")*)" in course "(?P<coursename_string>(?:[^"]|\\")*)" to "(?P<category_string>(?:[^"]|\\")*)" and "(?P<purpose_string>(?:[^"]|\\")*)"$/
|
||||
*
|
||||
* @param string $name The instance name. It should match the name of the activity.
|
||||
* @param string $type The activity type. E.g. assign, quiz, forum, etc.
|
||||
* @param string $coursename The course name. It should match the fullname or the shortname, or the idnumber.
|
||||
* @param string $category The ID of the category to be set for the instance.
|
||||
* @param string $purpose The ID of the purpose to be set for the instance.
|
||||
*/
|
||||
public function i_set_the_category_and_purpose_for_activity($name, $type, $coursename, $category, $purpose) {
|
||||
global $DB;
|
||||
|
||||
$params = [
|
||||
'shortname' => $coursename,
|
||||
'fullname' => $coursename,
|
||||
'idnumber' => $coursename,
|
||||
];
|
||||
$select = 'shortname = :shortname OR fullname = :fullname OR idnumber = :idnumber';
|
||||
$courseid = $DB->get_field_select('course', 'id', $select, $params, MUST_EXIST);
|
||||
|
||||
$cmid = null;
|
||||
$cms = get_coursemodules_in_course($type, $courseid);
|
||||
foreach ($cms as $cm) {
|
||||
if ($cm->name === $name || $cm->idnumber === $name) {
|
||||
$cmid = $cm->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($cmid === null) {
|
||||
throw new coding_exception("Activity module '{$name}' of type '{$type}' not found!");
|
||||
}
|
||||
$context = context_module::instance($cmid);
|
||||
|
||||
$this->set_category_and_purpose($context->id, $category, $purpose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data category and data storage purpose for a course instance.
|
||||
*
|
||||
* @Given /^I set the category and purpose for the "(?P<blockname_string>(?:[^"]|\\")*)" block in the "(?P<coursename_string>(?:[^"]|\\")*)" course to "(?P<category_string>(?:[^"]|\\")*)" and "(?P<purpose_string>(?:[^"]|\\")*)"$/
|
||||
*
|
||||
* @param string $name The instance name. It should match the name of the block. (e.g. online_users)
|
||||
* @param string $coursename The course name. It should match the fullname or the shortname, or the idnumber.
|
||||
* @param string $category The ID of the category to be set for the instance.
|
||||
* @param string $purpose The ID of the purpose to be set for the instance.
|
||||
*/
|
||||
public function i_set_the_category_and_purpose_for_block($name, $coursename, $category, $purpose) {
|
||||
global $DB;
|
||||
|
||||
$params = [
|
||||
'shortname' => $coursename,
|
||||
'fullname' => $coursename,
|
||||
'idnumber' => $coursename,
|
||||
];
|
||||
$select = 'shortname = :shortname OR fullname = :fullname OR idnumber = :idnumber';
|
||||
$courseid = $DB->get_field_select('course', 'id', $select, $params, MUST_EXIST);
|
||||
|
||||
// Fetch the course context.
|
||||
$coursecontext = context_course::instance($courseid);
|
||||
|
||||
// Fetch the block record and context.
|
||||
$blockid = $DB->get_field('block_instances', 'id', ['blockname' => $name, 'parentcontextid' => $coursecontext->id]);
|
||||
$context = context_block::instance($blockid);
|
||||
|
||||
// Set the category and purpose.
|
||||
$this->set_category_and_purpose($context->id, $category, $purpose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the category and purpose for a context instance.
|
||||
*
|
||||
* @param int $contextid The context ID.
|
||||
* @param int $categoryname The category name.
|
||||
* @param int $purposename The purpose name.
|
||||
* @throws coding_exception
|
||||
*/
|
||||
protected function set_category_and_purpose($contextid, $categoryname, $purposename) {
|
||||
$category = \tool_dataprivacy\category::get_record(['name' => $categoryname]);
|
||||
$purpose = \tool_dataprivacy\purpose::get_record(['name' => $purposename]);
|
||||
|
||||
api::set_context_instance((object) [
|
||||
'contextid' => $contextid,
|
||||
'purposeid' => $purpose->get('id'),
|
||||
'categoryid' => $category->get('id'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
@tool @tool_dataprivacy @javascript
|
||||
Feature: Manage data registry defaults
|
||||
As the privacy officer
|
||||
In order to manage the data registry
|
||||
I need to be able to manage the default data categories and data storage purposes for various context levels.
|
||||
|
||||
Background:
|
||||
Given I log in as "admin"
|
||||
And the following "categories" exist:
|
||||
| name | idnumber | category |
|
||||
| Science and technology | scitech | |
|
||||
| Physics | st-phys | scitech |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Fundamentals of physics 1 | Physics 101 | st-phys |
|
||||
And the following "activities" exist:
|
||||
| activity | name | idnumber | course |
|
||||
| assign | Assignment 1 | assign1 | Physics 101 |
|
||||
| forum | Forum 1 | forum1 | Physics 101 |
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| online_users | Course | Physics 101 | course-view-* | site-post |
|
||||
And the following data privacy "categories" exist:
|
||||
| name |
|
||||
| Site category |
|
||||
| Category 1 |
|
||||
| Category 2 |
|
||||
And the following data privacy "purposes" exist:
|
||||
| name | retentionperiod |
|
||||
| Site purpose | P10Y |
|
||||
| Purpose 1 | P3Y |
|
||||
| Purpose 2 | P5Y |
|
||||
And I set the site category and purpose to "Site category" and "Site purpose"
|
||||
|
||||
Scenario: Set course category data registry defaults
|
||||
Given I set the category and purpose for the course category "scitech" to "Category 2" and "Purpose 2"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Set defaults" "link"
|
||||
And I should see "Inherit"
|
||||
And I should not see "Add a new module default"
|
||||
And I press "Edit"
|
||||
And I set the field "Category" to "Category 1"
|
||||
And I set the field "Purpose" to "Purpose 1"
|
||||
When I press "Save changes"
|
||||
Then I should see "Category 1"
|
||||
And I should see "Purpose 1"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Science and technology" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Category 2"
|
||||
And the field "purposeid" matches value "Purpose 2"
|
||||
And I should see "5 years"
|
||||
|
||||
Scenario: Set course category data registry defaults with override
|
||||
Given I set the category and purpose for the course category "scitech" to "Category 2" and "Purpose 2"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Set defaults" "link"
|
||||
And I should see "Inherit"
|
||||
And I should not see "Add a new module default"
|
||||
And I press "Edit"
|
||||
And I set the field "Category" to "Category 1"
|
||||
And I set the field "Purpose" to "Purpose 1"
|
||||
And I click on "Reset instances with custom values" "checkbox"
|
||||
When I press "Save changes"
|
||||
Then I should see "Category 1"
|
||||
And I should see "Purpose 1"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Science and technology" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Not set (use the default value)"
|
||||
And the field "purposeid" matches value "Not set (use the default value)"
|
||||
And I should see "3 years"
|
||||
|
||||
Scenario: Set course data registry defaults
|
||||
Given I set the category and purpose for the course "Physics 101" to "Category 2" and "Purpose 2"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Set defaults" "link"
|
||||
And I click on "Courses" "link"
|
||||
And I should see "Inherit"
|
||||
And I should not see "Add a new module default"
|
||||
And I press "Edit"
|
||||
And I set the field "Category" to "Category 1"
|
||||
And I set the field "Purpose" to "Purpose 1"
|
||||
When I press "Save changes"
|
||||
Then I should see "Category 1"
|
||||
And I should see "Purpose 1"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Science and technology" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Courses" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Physics 101" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Category 2"
|
||||
And the field "purposeid" matches value "Purpose 2"
|
||||
And I should see "5 years (after the course end date)"
|
||||
|
||||
Scenario: Set course data registry defaults with override
|
||||
Given I set the category and purpose for the course "Physics 101" to "Category 2" and "Purpose 2"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Set defaults" "link"
|
||||
And I click on "Courses" "link"
|
||||
And I should see "Inherit"
|
||||
And I should not see "Add a new module default"
|
||||
And I press "Edit"
|
||||
And I set the field "Category" to "Category 1"
|
||||
And I set the field "Purpose" to "Purpose 1"
|
||||
And I click on "Reset instances with custom values" "checkbox"
|
||||
When I press "Save changes"
|
||||
Then I should see "Category 1"
|
||||
And I should see "Purpose 1"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Science and technology" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Courses" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Physics 101" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Not set (use the default value)"
|
||||
And the field "purposeid" matches value "Not set (use the default value)"
|
||||
And I should see "3 years (after the course end date)"
|
||||
|
||||
Scenario: Set module level data registry defaults
|
||||
Given I set the category and purpose for the "assign1" "assign" in course "Physics 101" to "Category 2" and "Purpose 2"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Set defaults" "link"
|
||||
And I click on "Activity modules" "link"
|
||||
And I should see "Inherit"
|
||||
And I should see "Add a new module default"
|
||||
And I press "Edit"
|
||||
And I set the field "Category" to "Category 1"
|
||||
And I set the field "Purpose" to "Purpose 1"
|
||||
When I press "Save changes"
|
||||
Then I should see "Category 1"
|
||||
And I should see "Purpose 1"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Science and technology" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Courses" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Physics 101" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Activities and resources" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Assignment 1 (Assignment)" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Category 2"
|
||||
And the field "purposeid" matches value "Purpose 2"
|
||||
And I should see "5 years (after the course end date)"
|
||||
|
||||
Scenario: Set module level data registry defaults with override
|
||||
Given I set the category and purpose for the "assign1" "assign" in course "Physics 101" to "Category 2" and "Purpose 2"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Set defaults" "link"
|
||||
And I click on "Activity modules" "link"
|
||||
And I should see "Inherit"
|
||||
And I should see "Add a new module default"
|
||||
And I press "Edit"
|
||||
And I set the field "Category" to "Category 1"
|
||||
And I set the field "Purpose" to "Purpose 1"
|
||||
And I click on "Reset instances with custom values" "checkbox"
|
||||
When I press "Save changes"
|
||||
Then I should see "Category 1"
|
||||
And I should see "Purpose 1"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Science and technology" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Courses" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Physics 101" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Activities and resources" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Assignment 1 (Assignment)" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Not set (use the default value)"
|
||||
And the field "purposeid" matches value "Not set (use the default value)"
|
||||
And I click on "Forum 1 (Forum)" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Not set (use the default value)"
|
||||
And the field "purposeid" matches value "Not set (use the default value)"
|
||||
And I should see "3 years (after the course end date)"
|
||||
|
||||
Scenario: Set data registry defaults for an activity module
|
||||
Given I set the category and purpose for the "assign1" "assign" in course "Physics 101" to "Category 2" and "Purpose 2"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Set defaults" "link"
|
||||
And I click on "Activity modules" "link"
|
||||
And I should see "Inherit"
|
||||
And I should see "Add a new module default"
|
||||
And I press "Add a new module default"
|
||||
And I set the field "Activity module" to "Assignment"
|
||||
And I set the field "Category" to "Category 1"
|
||||
And I set the field "Purpose" to "Purpose 1"
|
||||
When I press "Save changes"
|
||||
Then I should see "Category 1" in the "Assignment" "table_row"
|
||||
And I should see "Purpose 1" in the "Assignment" "table_row"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Science and technology" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Courses" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Physics 101" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Activities and resources" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Assignment 1 (Assignment)" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Category 2"
|
||||
And the field "purposeid" matches value "Purpose 2"
|
||||
And I should see "5 years (after the course end date)"
|
||||
|
||||
Scenario: Set data registry defaults for an activity module with override
|
||||
Given I set the category and purpose for the "assign1" "assign" in course "Physics 101" to "Category 2" and "Purpose 2"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Set defaults" "link"
|
||||
And I click on "Activity modules" "link"
|
||||
And I should see "Inherit"
|
||||
And I should see "Add a new module default"
|
||||
And I press "Add a new module default"
|
||||
And I set the field "Activity module" to "Assignment"
|
||||
And I set the field "Category" to "Category 1"
|
||||
And I set the field "Purpose" to "Purpose 1"
|
||||
And I click on "Reset instances with custom values" "checkbox"
|
||||
When I press "Save changes"
|
||||
Then I should see "Category 1" in the "Assignment" "table_row"
|
||||
And I should see "Purpose 1" in the "Assignment" "table_row"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Science and technology" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Courses" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Physics 101" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Activities and resources" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Assignment 1 (Assignment)" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Not set (use the default value)"
|
||||
And the field "purposeid" matches value "Not set (use the default value)"
|
||||
And I should see "3 years (after the course end date)"
|
||||
|
||||
Scenario: Set block category data registry defaults
|
||||
Given I set the category and purpose for the "online_users" block in the "Physics 101" course to "Category 2" and "Purpose 2"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Set defaults" "link"
|
||||
And I click on "Blocks" "link"
|
||||
And I should see "Inherit"
|
||||
And I should not see "Add a new module default"
|
||||
And I press "Edit"
|
||||
And I set the field "Category" to "Category 1"
|
||||
And I set the field "Purpose" to "Purpose 1"
|
||||
When I press "Save changes"
|
||||
Then I should see "Category 1"
|
||||
And I should see "Purpose 1"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Science and technology" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Courses" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Physics 101" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Blocks" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Online users" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Category 2"
|
||||
And the field "purposeid" matches value "Purpose 2"
|
||||
And I should see "5 years (after the course end date)"
|
||||
|
||||
Scenario: Set course category data registry defaults with override
|
||||
Given I set the category and purpose for the "online_users" block in the "Physics 101" course to "Category 2" and "Purpose 2"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Set defaults" "link"
|
||||
And I click on "Blocks" "link"
|
||||
And I should see "Inherit"
|
||||
And I should not see "Add a new module default"
|
||||
And I press "Edit"
|
||||
And I set the field "Category" to "Category 1"
|
||||
And I set the field "Purpose" to "Purpose 1"
|
||||
And I click on "Reset instances with custom values" "checkbox"
|
||||
When I press "Save changes"
|
||||
Then I should see "Category 1"
|
||||
And I should see "Purpose 1"
|
||||
And I navigate to "Users > Privacy and policies > Data registry" in site administration
|
||||
And I click on "Science and technology" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Courses" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Physics 101" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Blocks" "link"
|
||||
And I wait until the page is ready
|
||||
And I click on "Online users" "link"
|
||||
And I wait until the page is ready
|
||||
And the field "categoryid" matches value "Not set (use the default value)"
|
||||
And the field "purposeid" matches value "Not set (use the default value)"
|
||||
And I should see "3 years (after the course end date)"
|
||||
@@ -28,6 +28,7 @@ global $CFG;
|
||||
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
|
||||
|
||||
use tool_dataprivacy\api;
|
||||
use tool_dataprivacy\context_instance;
|
||||
use tool_dataprivacy\external;
|
||||
|
||||
/**
|
||||
@@ -282,4 +283,281 @@ class tool_dataprivacy_external_testcase extends externallib_advanced_testcase {
|
||||
$this->expectException(dml_missing_record_exception::class);
|
||||
external::get_data_request($this->requestid + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for \tool_dataprivacy\external::set_context_defaults()
|
||||
* when called by a user that doesn't have the manage registry capability.
|
||||
*/
|
||||
public function test_set_context_defaults_no_capability() {
|
||||
$generator = $this->getDataGenerator();
|
||||
$user = $generator->create_user();
|
||||
$this->setUser($user);
|
||||
$this->expectException(required_capability_exception::class);
|
||||
external::set_context_defaults(CONTEXT_COURSECAT, context_instance::INHERIT, context_instance::INHERIT, '', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for \tool_dataprivacy\external::set_context_defaults().
|
||||
*
|
||||
* We're just checking the module context level here to test the WS function.
|
||||
* More testing is done in \tool_dataprivacy_api_testcase::test_set_context_defaults().
|
||||
*
|
||||
* @dataProvider get_options_provider
|
||||
* @param bool $modulelevel Whether defaults are to be applied on the module context level or for an activity only.
|
||||
* @param bool $override Whether to override instances.
|
||||
*/
|
||||
public function test_set_context_defaults($modulelevel, $override) {
|
||||
$this->setAdminUser();
|
||||
$generator = $this->getDataGenerator();
|
||||
|
||||
// Generate course cat, course, block, assignment, forum instances.
|
||||
$coursecat = $generator->create_category();
|
||||
$course = $generator->create_course(['category' => $coursecat->id]);
|
||||
$assign = $generator->create_module('assign', ['course' => $course->id]);
|
||||
list($course, $assigncm) = get_course_and_cm_from_instance($assign->id, 'assign');
|
||||
$assigncontext = context_module::instance($assigncm->id);
|
||||
|
||||
// Generate purpose and category.
|
||||
$category1 = api::create_category((object)['name' => 'Test category 1']);
|
||||
$category2 = api::create_category((object)['name' => 'Test category 2']);
|
||||
$purpose1 = api::create_purpose((object)[
|
||||
'name' => 'Test purpose 1', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a'
|
||||
]);
|
||||
$purpose2 = api::create_purpose((object)[
|
||||
'name' => 'Test purpose 2', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a'
|
||||
]);
|
||||
|
||||
// Set a custom purpose and ID for this assignment instance.
|
||||
$assignctxinstance = api::set_context_instance((object) [
|
||||
'contextid' => $assigncontext->id,
|
||||
'purposeid' => $purpose1->get('id'),
|
||||
'categoryid' => $category1->get('id'),
|
||||
]);
|
||||
|
||||
$modulename = $modulelevel ? 'assign' : '';
|
||||
$categoryid = $category2->get('id');
|
||||
$purposeid = $purpose2->get('id');
|
||||
$result = external::set_context_defaults(CONTEXT_MODULE, $categoryid, $purposeid, $modulename, $override);
|
||||
|
||||
// Extract the result.
|
||||
$return = external_api::clean_returnvalue(external::set_context_defaults_returns(), $result);
|
||||
$this->assertTrue($return['result']);
|
||||
|
||||
// Check the assignment context instance.
|
||||
$instanceexists = context_instance::record_exists($assignctxinstance->get('id'));
|
||||
if ($override) {
|
||||
// The custom assign instance should have been deleted.
|
||||
$this->assertFalse($instanceexists);
|
||||
} else {
|
||||
// The custom assign instance should still exist.
|
||||
$this->assertTrue($instanceexists);
|
||||
}
|
||||
|
||||
// Check the saved defaults.
|
||||
list($savedpurpose, $savedcategory) = \tool_dataprivacy\data_registry::get_defaults(CONTEXT_MODULE, $modulename);
|
||||
$this->assertEquals($categoryid, $savedcategory);
|
||||
$this->assertEquals($purposeid, $savedpurpose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for \tool_dataprivacy\external::get_category_options()
|
||||
* when called by a user that doesn't have the manage registry capability.
|
||||
*/
|
||||
public function test_get_category_options_no_capability() {
|
||||
$generator = $this->getDataGenerator();
|
||||
$user = $generator->create_user();
|
||||
$this->setUser($user);
|
||||
$this->expectException(required_capability_exception::class);
|
||||
external::get_category_options(true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for \tool_dataprivacy_external_testcase::test_XX_options().
|
||||
*/
|
||||
public function get_options_provider() {
|
||||
return [
|
||||
[false, false],
|
||||
[false, true],
|
||||
[true, false],
|
||||
[true, true],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for \tool_dataprivacy\external::get_category_options().
|
||||
*
|
||||
* @dataProvider get_options_provider
|
||||
* @param bool $includeinherit Whether "Inherit" would be included to the options.
|
||||
* @param bool $includenotset Whether "Not set" would be included to the options.
|
||||
*/
|
||||
public function test_get_category_options($includeinherit, $includenotset) {
|
||||
$this->setAdminUser();
|
||||
|
||||
// Prepare our expected options.
|
||||
$expectedoptions = [];
|
||||
if ($includeinherit) {
|
||||
$expectedoptions[] = [
|
||||
'id' => context_instance::INHERIT,
|
||||
'name' => get_string('inherit', 'tool_dataprivacy'),
|
||||
];
|
||||
}
|
||||
|
||||
if ($includenotset) {
|
||||
$expectedoptions[] = [
|
||||
'id' => context_instance::NOTSET,
|
||||
'name' => get_string('notset', 'tool_dataprivacy'),
|
||||
];
|
||||
}
|
||||
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$category = api::create_category((object)['name' => 'Category ' . $i]);
|
||||
$expectedoptions[] = [
|
||||
'id' => $category->get('id'),
|
||||
'name' => $category->get('name'),
|
||||
];
|
||||
}
|
||||
|
||||
// Call the WS function.
|
||||
$result = external::get_category_options($includeinherit, $includenotset);
|
||||
|
||||
// Extract the options.
|
||||
$return = (object) external_api::clean_returnvalue(external::get_category_options_returns(), $result);
|
||||
$options = $return->options;
|
||||
|
||||
// Make sure everything checks out.
|
||||
$this->assertCount(count($expectedoptions), $options);
|
||||
foreach ($options as $option) {
|
||||
$this->assertContains($option, $expectedoptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for \tool_dataprivacy\external::get_purpose_options()
|
||||
* when called by a user that doesn't have the manage registry capability.
|
||||
*/
|
||||
public function test_get_purpose_options_no_capability() {
|
||||
$generator = $this->getDataGenerator();
|
||||
$user = $generator->create_user();
|
||||
$this->setUser($user);
|
||||
$this->expectException(required_capability_exception::class);
|
||||
external::get_category_options(true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for \tool_dataprivacy\external::get_purpose_options().
|
||||
*
|
||||
* @dataProvider get_options_provider
|
||||
* @param bool $includeinherit Whether "Inherit" would be included to the options.
|
||||
* @param bool $includenotset Whether "Not set" would be included to the options.
|
||||
*/
|
||||
public function test_get_purpose_options($includeinherit, $includenotset) {
|
||||
$this->setAdminUser();
|
||||
|
||||
// Prepare our expected options.
|
||||
$expectedoptions = [];
|
||||
if ($includeinherit) {
|
||||
$expectedoptions[] = [
|
||||
'id' => context_instance::INHERIT,
|
||||
'name' => get_string('inherit', 'tool_dataprivacy'),
|
||||
];
|
||||
}
|
||||
|
||||
if ($includenotset) {
|
||||
$expectedoptions[] = [
|
||||
'id' => context_instance::NOTSET,
|
||||
'name' => get_string('notset', 'tool_dataprivacy'),
|
||||
];
|
||||
}
|
||||
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$purpose = api::create_purpose((object)[
|
||||
'name' => 'Purpose ' . $i, 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a'
|
||||
]);
|
||||
$expectedoptions[] = [
|
||||
'id' => $purpose->get('id'),
|
||||
'name' => $purpose->get('name'),
|
||||
];
|
||||
}
|
||||
|
||||
// Call the WS function.
|
||||
$result = external::get_purpose_options($includeinherit, $includenotset);
|
||||
|
||||
// Extract the options.
|
||||
$return = (object) external_api::clean_returnvalue(external::get_purpose_options_returns(), $result);
|
||||
$options = $return->options;
|
||||
|
||||
// Make sure everything checks out.
|
||||
$this->assertCount(count($expectedoptions), $options);
|
||||
foreach ($options as $option) {
|
||||
$this->assertContains($option, $expectedoptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for \tool_dataprivacy_external_testcase::get_activity_options().
|
||||
*/
|
||||
public function get_activity_options_provider() {
|
||||
return [
|
||||
[false, false, true],
|
||||
[false, true, true],
|
||||
[true, false, true],
|
||||
[true, true, true],
|
||||
[false, false, false],
|
||||
[false, true, false],
|
||||
[true, false, false],
|
||||
[true, true, false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for \tool_dataprivacy\external::get_activity_options().
|
||||
*
|
||||
* @dataProvider get_activity_options_provider
|
||||
* @param bool $inheritcategory Whether the category would be set to "Inherit".
|
||||
* @param bool $inheritpurpose Whether the purpose would be set to "Inherit".
|
||||
* @param bool $nodefaults Whether to fetch only activities that don't have defaults.
|
||||
*/
|
||||
public function test_get_activity_options($inheritcategory, $inheritpurpose, $nodefaults) {
|
||||
$this->setAdminUser();
|
||||
|
||||
$category = api::create_category((object)['name' => 'Test category']);
|
||||
$purpose = api::create_purpose((object)[
|
||||
'name' => 'Test purpose ', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a'
|
||||
]);
|
||||
$categoryid = $category->get('id');
|
||||
$purposeid = $purpose->get('id');
|
||||
|
||||
if ($inheritcategory) {
|
||||
$categoryid = context_instance::INHERIT;
|
||||
}
|
||||
if ($inheritpurpose) {
|
||||
$purposeid = context_instance::INHERIT;
|
||||
}
|
||||
|
||||
// Set the context default for the assignment module.
|
||||
api::set_context_defaults(CONTEXT_MODULE, $categoryid, $purposeid, 'assign');
|
||||
|
||||
// Call the WS function.
|
||||
$result = external::get_activity_options($nodefaults);
|
||||
|
||||
// Extract the options.
|
||||
$return = (object) external_api::clean_returnvalue(external::get_activity_options_returns(), $result);
|
||||
$options = $return->options;
|
||||
|
||||
// Make sure the options list is not empty.
|
||||
$this->assertNotEmpty($options);
|
||||
|
||||
$pluginwithdefaults = [
|
||||
'name' => 'assign',
|
||||
'displayname' => get_string('pluginname', 'assign')
|
||||
];
|
||||
|
||||
// If we don't want plugins with defaults to be listed or if both of the category and purpose are set to inherit,
|
||||
// the assign module should be listed.
|
||||
if (!$nodefaults || ($inheritcategory && $inheritpurpose)) {
|
||||
$this->assertContains($pluginwithdefaults, $options);
|
||||
} else {
|
||||
$this->assertNotContains($pluginwithdefaults, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Data privacy tool data generator.
|
||||
*
|
||||
* @package tool_dataprivacy
|
||||
* @category test
|
||||
* @copyright 2018 Jun Pataleta
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use tool_dataprivacy\api;
|
||||
use tool_dataprivacy\category;
|
||||
use tool_dataprivacy\purpose;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Data privacy tool data generator class.
|
||||
*
|
||||
* @package tool_dataprivacy
|
||||
* @category test
|
||||
* @copyright 2018 Jun Pataleta
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_dataprivacy_generator extends component_generator_base {
|
||||
|
||||
/** @var int Number of created categories. */
|
||||
protected $categorycount = 0;
|
||||
|
||||
/** @var int Number of created purposes. */
|
||||
protected $purposecount = 0;
|
||||
|
||||
/**
|
||||
* Reset process.
|
||||
*
|
||||
* Do not call directly.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reset() {
|
||||
$this->categorycount = 0;
|
||||
$this->purposecount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new category.
|
||||
*
|
||||
* @param array|stdClass $record
|
||||
* @return category
|
||||
*/
|
||||
public function create_category($record = null) {
|
||||
$this->categorycount++;
|
||||
$i = $this->categorycount;
|
||||
$record = (object)$record;
|
||||
|
||||
if (!isset($record->name)) {
|
||||
$record->name = "Test purpose $i";
|
||||
}
|
||||
|
||||
if (!isset($record->description)) {
|
||||
$record->description = "{$record->name} description";
|
||||
}
|
||||
|
||||
$category = api::create_category($record);
|
||||
|
||||
return $category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new purpose.
|
||||
*
|
||||
* @param array|stdClass $record
|
||||
* @return purpose
|
||||
*/
|
||||
public function create_purpose($record = null) {
|
||||
$this->purposecount++;
|
||||
$i = $this->purposecount;
|
||||
$record = (object)$record;
|
||||
|
||||
if (!isset($record->name)) {
|
||||
$record->name = "Test purpose $i";
|
||||
}
|
||||
|
||||
if (!isset($record->description)) {
|
||||
$record->description = "{$record->name} $i description";
|
||||
}
|
||||
|
||||
if (!isset($record->retentionperiod)) {
|
||||
$record->retentionperiod = 'PT1M';
|
||||
}
|
||||
|
||||
if (!isset($record->lawfulbases)) {
|
||||
$record->lawfulbases = 'gdpr_art_6_1_a';
|
||||
}
|
||||
|
||||
$purpose = api::create_purpose($record);
|
||||
|
||||
return $purpose;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$plugin->version = 2018082100;
|
||||
$plugin->version = 2018091000;
|
||||
$plugin->requires = 2018050800; // Moodle 3.5dev (Build 2018031600) and upwards.
|
||||
$plugin->component = 'tool_dataprivacy';
|
||||
|
||||
Reference in New Issue
Block a user