diff --git a/admin/tool/dataprivacy/amd/build/defaultsactions.min.js b/admin/tool/dataprivacy/amd/build/defaultsactions.min.js
new file mode 100644
index 00000000000..b8f0bc3738d
--- /dev/null
+++ b/admin/tool/dataprivacy/amd/build/defaultsactions.min.js
@@ -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}}});
\ No newline at end of file
diff --git a/admin/tool/dataprivacy/amd/src/defaultsactions.js b/admin/tool/dataprivacy/amd/src/defaultsactions.js
new file mode 100644
index 00000000000..76cbb89ae91
--- /dev/null
+++ b/admin/tool/dataprivacy/amd/src/defaultsactions.js
@@ -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 .
+
+/**
+ * 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();
+ }
+ };
+});
diff --git a/admin/tool/dataprivacy/classes/api.php b/admin/tool/dataprivacy/classes/api.php
index 6ee970733d7..8e89c23a308 100644
--- a/admin/tool/dataprivacy/classes/api.php
+++ b/admin/tool/dataprivacy/classes/api.php
@@ -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,89 @@ 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.
+ $contextinstances = $DB->get_records_sql($sql, $params);
+
+ // Delete the matching context instances by passing an instance record without the purpose and instance.
+ foreach ($contextinstances as $instance) {
+ self::set_context_instance($instance);
+ }
+ }
+
+ return true;
+ }
}
diff --git a/admin/tool/dataprivacy/classes/data_registry.php b/admin/tool/dataprivacy/classes/data_registry.php
index 1fac2f5756c..b8613ff8f00 100644
--- a/admin/tool/dataprivacy/classes/data_registry.php
+++ b/admin/tool/dataprivacy/classes/data_registry.php
@@ -57,13 +57,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,13 +81,14 @@ 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);
diff --git a/admin/tool/dataprivacy/classes/external.php b/admin/tool/dataprivacy/classes/external.php
index e14e0726900..2b6ee23f8e5 100644
--- a/admin/tool/dataprivacy/classes/external.php
+++ b/admin/tool/dataprivacy/classes/external.php
@@ -1110,6 +1110,304 @@ 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, 'Expired context record ID', 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();
+ $categoryoptions = [];
+ if ($includeinherit) {
+ $categoryoptions[] = [
+ 'id' => context_instance::INHERIT,
+ 'name' => get_string('inherit', 'tool_dataprivacy'),
+ ];
+ }
+ if ($includenotset) {
+ $categoryoptions[] = [
+ 'id' => context_instance::NOTSET,
+ 'name' => get_string('notset', 'tool_dataprivacy'),
+ ];
+ }
+ foreach ($categories as $category) {
+ $categoryoptions[] = [
+ 'id' => $category->get('id'),
+ 'name' => $category->get('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();
+ $purposeoptions = [];
+ if ($includeinherit) {
+ $purposeoptions[] = [
+ 'id' => context_instance::INHERIT,
+ 'name' => get_string('inherit', 'tool_dataprivacy'),
+ ];
+ }
+ if ($includenotset) {
+ $purposeoptions[] = [
+ 'id' => context_instance::NOTSET,
+ 'name' => get_string('notset', 'tool_dataprivacy'),
+ ];
+ }
+ foreach ($purposes as $purpose) {
+ $purposeoptions[] = [
+ 'id' => $purpose->get('id'),
+ 'name' => $purpose->get('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_plugins_of_type('mod');
+ $modoptions = [];
+ foreach ($modplugins as $plugin) {
+ // 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, $plugin->name);
+ if ($purpose !== false || $category !== false) {
+ // If so, skip it.
+ continue;
+ }
+ }
+
+ $modoptions[] = (object)[
+ 'name' => $plugin->name,
+ 'displayname' => $plugin->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).
*
diff --git a/admin/tool/dataprivacy/classes/local/helper.php b/admin/tool/dataprivacy/classes/local/helper.php
index 36dd93aac2b..d1960082f9b 100644
--- a/admin/tool/dataprivacy/classes/local/helper.php
+++ b/admin/tool/dataprivacy/classes/local/helper.php
@@ -27,6 +27,9 @@ defined('MOODLE_INTERNAL') || die();
use coding_exception;
use moodle_exception;
use tool_dataprivacy\api;
+use tool_dataprivacy\category;
+use tool_dataprivacy\context_instance;
+use tool_dataprivacy\purpose;
/**
* Class containing helper functions for the data privacy tool.
@@ -209,4 +212,38 @@ class helper {
}
return $options;
}
+
+ /**
+ * Fetches a category name from the given ID.
+ *
+ * @param int $category The category ID. Could be INHERIT (false, -1), NOT_SET (0), or the actual ID.
+ * @return string The category name.
+ */
+ public static function get_category_name($category) {
+ if ($category === false || $category == context_instance::INHERIT) {
+ return get_string('inherit', 'tool_dataprivacy');
+ } else if ($category == context_instance::NOTSET) {
+ return get_string('notset', 'tool_dataprivacy');
+ } else {
+ $category = new category($category);
+ return format_string($category->get('name'));
+ }
+ }
+
+ /**
+ * Fetches a purpose name from the given ID.
+ *
+ * @param int $purpose The purpose ID. Could be INHERIT (false, -1), NOT_SET (0), or the actual ID.
+ * @return string The purpose name.
+ */
+ public static function get_purpose_name($purpose) {
+ if ($purpose === false || $purpose == context_instance::INHERIT) {
+ return get_string('inherit', 'tool_dataprivacy');
+ } else if ($purpose == context_instance::NOTSET) {
+ return get_string('notset', 'tool_dataprivacy');
+ } else {
+ $purpose = new purpose($purpose);
+ return format_string($purpose->get('name'));
+ }
+ }
}
diff --git a/admin/tool/dataprivacy/classes/output/defaults_page.php b/admin/tool/dataprivacy/classes/output/defaults_page.php
new file mode 100644
index 00000000000..16907dd54c9
--- /dev/null
+++ b/admin/tool/dataprivacy/classes/output/defaults_page.php
@@ -0,0 +1,151 @@
+.
+
+/**
+ * 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 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\local\helper;
+
+/**
+ * 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 = helper::get_category_name($this->category);
+
+ // Set default purpose.
+ $data->purposeid = $this->purpose;
+ $data->purpose = helper::get_purpose_name($this->purpose);
+
+ // Set other defaults.
+ $otherdefaults = [];
+ foreach ($this->otherdefaults as $pluginname => $values) {
+ $defaults = [
+ 'activityname' => $pluginname,
+ 'name' => $values->name,
+ 'categoryid' => $values->category,
+ 'category' => helper::get_category_name($values->category),
+ 'purposeid' => $values->purpose,
+ 'purpose' => helper::get_purpose_name($values->purpose),
+ ];
+ $otherdefaults[] = (object)$defaults;
+ }
+ $data->otherdefaults = $otherdefaults;
+
+ $data->canedit = $this->canedit;
+ $data->contextlevel = $this->mode;
+
+ return $data;
+ }
+}
diff --git a/admin/tool/dataprivacy/db/services.php b/admin/tool/dataprivacy/db/services.php
index 9c71e8c4dc2..b9e60774b14 100644
--- a/admin/tool/dataprivacy/db/services.php
+++ b/admin/tool/dataprivacy/db/services.php
@@ -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,
+ ],
];
diff --git a/admin/tool/dataprivacy/defaults.php b/admin/tool/dataprivacy/defaults.php
index d936ba221d6..24b2862b5b1 100644
--- a/admin/tool/dataprivacy/defaults.php
+++ b/admin/tool/dataprivacy/defaults.php
@@ -32,47 +32,37 @@ $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_plugins_of_type('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 $plugin) {
+ list($purposevar, $categoryvar) = \tool_dataprivacy\data_registry::var_names_from_context($classname, $plugin->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;
}
+ $otherdefaults[$plugin->name] = (object)[
+ 'name' => $plugin->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();
diff --git a/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php b/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php
index eb2c97fc83c..682dc99ac14 100644
--- a/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php
+++ b/admin/tool/dataprivacy/lang/en/tool_dataprivacy.php
@@ -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';
diff --git a/admin/tool/dataprivacy/templates/category_purpose_form.mustache b/admin/tool/dataprivacy/templates/category_purpose_form.mustache
new file mode 100644
index 00000000000..c5d0ed4bea6
--- /dev/null
+++ b/admin/tool/dataprivacy/templates/category_purpose_form.mustache
@@ -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 .
+}}
+{{!
+ @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 }
+ ]
+ }
+}}
+
+
+ {{#str}}defaultswarninginfo, tool_dataprivacy{{/str}}
+
+
diff --git a/admin/tool/dataprivacy/templates/defaults_display.mustache b/admin/tool/dataprivacy/templates/defaults_display.mustache
new file mode 100644
index 00000000000..1abce61f68b
--- /dev/null
+++ b/admin/tool/dataprivacy/templates/defaults_display.mustache
@@ -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 .
+}}
+{{!
+ @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
+ }
+}}
+
+
+
+
+ {{#str}}category, tool_dataprivacy{{/str}}
+
+
+ {{category}}
+
+
+
+
+ {{#str}}purpose, tool_dataprivacy{{/str}}
+
+
+ {{purpose}}
+
+
+
+
+ {{#canedit}}
+
+ {{#str}}edit{{/str}}
+
+ {{/canedit}}
+
+
diff --git a/admin/tool/dataprivacy/templates/defaults_page.mustache b/admin/tool/dataprivacy/templates/defaults_page.mustache
new file mode 100644
index 00000000000..c7777c1428c
--- /dev/null
+++ b/admin/tool/dataprivacy/templates/defaults_page.mustache
@@ -0,0 +1,152 @@
+{{!
+ 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 .
+}}
+{{!
+ @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"
+ }
+ ]
+ }
+}}
+
+
+
+
+
+
+ {{#str}}defaultsinfo, tool_dataprivacy{{/str}}
+
+
+
+ {{> tool_dataprivacy/defaults_display}}
+ {{#canedit}}
+ {{#modemodule}}
+
+ {{#str}}addnewdefaults, tool_dataprivacy{{/str}}
+
+ {{/modemodule}}
+ {{/canedit}}
+ {{#modemodule}}
+
+ {{/modemodule}}
+
+
+
+
+{{#js}}
+// Initialise the JS.
+require(['tool_dataprivacy/defaultsactions'], function(ActionsMod) {
+ ActionsMod.init();
+});
+{{/js}}
diff --git a/admin/tool/dataprivacy/templates/delete_activity_defaults.mustache b/admin/tool/dataprivacy/templates/delete_activity_defaults.mustache
new file mode 100644
index 00000000000..c0220d3164d
--- /dev/null
+++ b/admin/tool/dataprivacy/templates/delete_activity_defaults.mustache
@@ -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 .
+}}
+{{!
+ @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"
+ }
+}}
+
+
+ {{#str}}defaultswarninginfo, tool_dataprivacy{{/str}}
+
+
+ {{#str}}deletedefaultsconfirmation, tool_dataprivacy, {{activityname}}{{/str}}
+