AutorÃa | Ultima modificación | Ver Log |
<?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 the external API functions functions for the Data Privacy tool.** @package tool_dataprivacy* @copyright 2018 Jun Pataleta* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/namespace tool_dataprivacy;defined('MOODLE_INTERNAL') || die();require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/dataprivacy/lib.php');use context_helper;use context_system;use context_user;use core\notification;use core_user;use core_external\external_api;use core_external\external_function_parameters;use core_external\external_multiple_structure;use core_external\external_single_structure;use core_external\external_value;use core_external\external_warnings;use moodle_exception;use required_capability_exception;use tool_dataprivacy\external\category_exporter;use tool_dataprivacy\external\data_request_exporter;use tool_dataprivacy\external\purpose_exporter;use tool_dataprivacy\output\data_registry_page;/*** Class external.** The external API for the Data Privacy tool.** @copyright 2017 Jun Pataleta* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/class external extends external_api {/*** Parameter description for cancel_data_request().** @since Moodle 3.5* @return external_function_parameters*/public static function cancel_data_request_parameters() {return new external_function_parameters(['requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED)]);}/*** Cancel a data request.** @since Moodle 3.5* @param int $requestid The request ID.* @return array* @throws invalid_persistent_exception* @throws coding_exception* @throws invalid_parameter_exception* @throws restricted_context_exception*/public static function cancel_data_request($requestid) {global $USER;$warnings = [];$params = external_api::validate_parameters(self::cancel_data_request_parameters(), ['requestid' => $requestid]);$requestid = $params['requestid'];// Validate context and access to manage the registry.$context = context_user::instance($USER->id);self::validate_context($context);// Ensure the request exists.$select = 'id = :id AND (userid = :userid OR requestedby = :requestedby)';$params = ['id' => $requestid, 'userid' => $USER->id, 'requestedby' => $USER->id];$requests = data_request::get_records_select($select, $params);$requestexists = count($requests) === 1;$result = false;if ($requestexists) {$request = reset($requests);$datasubject = $request->get('userid');if ($datasubject !== (int) $USER->id) {// The user is not the subject. Check that they can cancel this request.if (!api::can_create_data_request_for_user($datasubject)) {$forusercontext = \context_user::instance($datasubject);throw new required_capability_exception($forusercontext,'tool/dataprivacy:makedatarequestsforchildren', 'nopermissions', '');}}// TODO: Do we want a request to be non-cancellable past a certain point? E.g. When it's already approved/processing.$result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_CANCELLED);} else {$warnings[] = ['item' => $requestid,'warningcode' => 'errorrequestnotfound','message' => get_string('errorrequestnotfound', 'tool_dataprivacy')];}return ['result' => $result,'warnings' => $warnings];}/*** Parameter description for cancel_data_request().** @since Moodle 3.5* @return \core_external\external_description*/public static function cancel_data_request_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'The processing result'),'warnings' => new external_warnings()]);}/*** Parameter description for contact_dpo().** @since Moodle 3.5* @return external_function_parameters*/public static function contact_dpo_parameters() {return new external_function_parameters(['message' => new external_value(PARAM_TEXT, 'The user\'s message to the Data Protection Officer(s)', VALUE_REQUIRED)]);}/*** Make a general enquiry to a DPO.** @since Moodle 3.5* @param string $message The message to be sent to the DPO.* @return array* @throws coding_exception* @throws invalid_parameter_exception* @throws invalid_persistent_exception* @throws restricted_context_exception* @throws dml_exception* @throws moodle_exception*/public static function contact_dpo($message) {global $USER;$warnings = [];$params = external_api::validate_parameters(self::contact_dpo_parameters(), ['message' => $message]);$message = $params['message'];// Validate context.$userid = $USER->id;$context = context_user::instance($userid);self::validate_context($context);// Lodge the request.$datarequest = new data_request();// The user the request is being made for.$datarequest->set('userid', $userid);// The user making the request.$datarequest->set('requestedby', $userid);// Set status.$datarequest->set('status', api::DATAREQUEST_STATUS_PENDING);// Set request type.$datarequest->set('type', api::DATAREQUEST_TYPE_OTHERS);// Set request comments.$datarequest->set('comments', $message);// Store subject access request.$datarequest->create();// Get the list of the site Data Protection Officers.$dpos = api::get_site_dpos();// Email the data request to the Data Protection Officer(s)/Admin(s).$result = true;foreach ($dpos as $dpo) {$sendresult = api::notify_dpo($dpo, $datarequest);if (!$sendresult) {$result = false;$warnings[] = ['item' => $dpo->id,'warningcode' => 'errorsendingtodpo','message' => get_string('errorsendingmessagetodpo', 'tool_dataprivacy',fullname($dpo))];}}return ['result' => $result,'warnings' => $warnings];}/*** Parameter description for contact_dpo().** @since Moodle 3.5* @return \core_external\external_description*/public static function contact_dpo_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'The processing result'),'warnings' => new external_warnings()]);}/*** Parameter description for mark_complete().** @since Moodle 3.5.2* @return external_function_parameters*/public static function mark_complete_parameters() {return new external_function_parameters(['requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED)]);}/*** Mark a user's general enquiry's status as complete.** @since Moodle 3.5.2* @param int $requestid The request ID of the general enquiry.* @return array* @throws coding_exception* @throws invalid_parameter_exception* @throws invalid_persistent_exception* @throws restricted_context_exception* @throws dml_exception* @throws moodle_exception*/public static function mark_complete($requestid) {global $USER;$warnings = [];$params = external_api::validate_parameters(self::mark_complete_parameters(), ['requestid' => $requestid,]);$requestid = $params['requestid'];// Validate context and access to manage the registry.$context = context_system::instance();self::validate_context($context);api::check_can_manage_data_registry();$message = get_string('markedcomplete', 'tool_dataprivacy');// Update the data request record.if ($result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_COMPLETE, $USER->id, $message)) {// Add notification in the session to be shown when the page is reloaded on the JS side.notification::success(get_string('requestmarkedcomplete', 'tool_dataprivacy'));}return ['result' => $result,'warnings' => $warnings];}/*** Parameter description for mark_complete().** @since Moodle 3.5.2* @return \core_external\external_description*/public static function mark_complete_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'The processing result'),'warnings' => new external_warnings()]);}/*** Parameter description for get_data_request().** @since Moodle 3.5* @return external_function_parameters*/public static function get_data_request_parameters() {return new external_function_parameters(['requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED)]);}/*** Fetch the details of a user's data request.** @since Moodle 3.5* @param int $requestid The request ID.* @return array* @throws coding_exception* @throws dml_exception* @throws invalid_parameter_exception* @throws restricted_context_exception* @throws moodle_exception*/public static function get_data_request($requestid) {global $PAGE;$warnings = [];$params = external_api::validate_parameters(self::get_data_request_parameters(), ['requestid' => $requestid]);$requestid = $params['requestid'];// Validate context.$context = context_system::instance();self::validate_context($context);$requestpersistent = new data_request($requestid);require_capability('tool/dataprivacy:managedatarequests', $context);$exporter = new data_request_exporter($requestpersistent, ['context' => $context]);$renderer = $PAGE->get_renderer('tool_dataprivacy');$result = $exporter->export($renderer);return ['result' => $result,'warnings' => $warnings];}/*** Parameter description for get_data_request().** @since Moodle 3.5* @return \core_external\external_description*/public static function get_data_request_returns() {return new external_single_structure(['result' => data_request_exporter::get_read_structure(),'warnings' => new external_warnings()]);}/*** Parameter description for approve_data_request().** @since Moodle 3.5* @return external_function_parameters*/public static function approve_data_request_parameters() {return new external_function_parameters(['requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED)]);}/*** Approve a data request.** @since Moodle 3.5* @param int $requestid The request ID.* @return array* @throws coding_exception* @throws dml_exception* @throws invalid_parameter_exception* @throws restricted_context_exception* @throws moodle_exception*/public static function approve_data_request($requestid) {$warnings = [];$params = external_api::validate_parameters(self::approve_data_request_parameters(), ['requestid' => $requestid]);$requestid = $params['requestid'];// Validate context.$context = context_system::instance();self::validate_context($context);require_capability('tool/dataprivacy:managedatarequests', $context);// Ensure the request exists.$requestexists = data_request::record_exists($requestid);$result = false;if ($requestexists) {$result = api::approve_data_request($requestid);// Add notification in the session to be shown when the page is reloaded on the JS side.notification::success(get_string('requestapproved', 'tool_dataprivacy'));} else {$warnings[] = ['item' => $requestid,'warningcode' => 'errorrequestnotfound','message' => get_string('errorrequestnotfound', 'tool_dataprivacy')];}return ['result' => $result,'warnings' => $warnings];}/*** Parameter description for approve_data_request().** @since Moodle 3.5* @return \core_external\external_description*/public static function approve_data_request_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'The processing result'),'warnings' => new external_warnings()]);}/*** Parameter description for bulk_approve_data_requests().** @since Moodle 3.5* @return external_function_parameters*/public static function bulk_approve_data_requests_parameters() {return new external_function_parameters(['requestids' => new external_multiple_structure(new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED))]);}/*** Bulk approve bulk data request.** @since Moodle 3.5* @param array $requestids Array consisting the request ID's.* @return array* @throws coding_exception* @throws dml_exception* @throws invalid_parameter_exception* @throws restricted_context_exception* @throws moodle_exception*/public static function bulk_approve_data_requests($requestids) {$warnings = [];$result = false;$params = external_api::validate_parameters(self::bulk_approve_data_requests_parameters(), ['requestids' => $requestids]);$requestids = $params['requestids'];// Validate context.$context = context_system::instance();self::validate_context($context);require_capability('tool/dataprivacy:managedatarequests', $context);foreach ($requestids as $requestid) {// Ensure the request exists.$requestexists = data_request::record_exists($requestid);if ($requestexists) {api::approve_data_request($requestid);} else {$warnings[] = ['item' => $requestid,'warningcode' => 'errorrequestnotfound','message' => get_string('errorrequestnotfound', 'tool_dataprivacy')];}}if (empty($warnings)) {$result = true;// Add notification in the session to be shown when the page is reloaded on the JS side.notification::success(get_string('requestsapproved', 'tool_dataprivacy'));}return ['result' => $result,'warnings' => $warnings];}/*** Parameter description for bulk_approve_data_requests().** @since Moodle 3.5* @return \core_external\external_description*/public static function bulk_approve_data_requests_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'The processing result'),'warnings' => new external_warnings()]);}/*** Parameter description for deny_data_request().** @since Moodle 3.5* @return external_function_parameters*/public static function deny_data_request_parameters() {return new external_function_parameters(['requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED)]);}/*** Deny a data request.** @since Moodle 3.5* @param int $requestid The request ID.* @return array* @throws coding_exception* @throws dml_exception* @throws invalid_parameter_exception* @throws restricted_context_exception* @throws moodle_exception*/public static function deny_data_request($requestid) {$warnings = [];$params = external_api::validate_parameters(self::deny_data_request_parameters(), ['requestid' => $requestid]);$requestid = $params['requestid'];// Validate context.$context = context_system::instance();self::validate_context($context);require_capability('tool/dataprivacy:managedatarequests', $context);// Ensure the request exists.$requestexists = data_request::record_exists($requestid);$result = false;if ($requestexists) {$result = api::deny_data_request($requestid);// Add notification in the session to be shown when the page is reloaded on the JS side.notification::success(get_string('requestdenied', 'tool_dataprivacy'));} else {$warnings[] = ['item' => $requestid,'warningcode' => 'errorrequestnotfound','message' => get_string('errorrequestnotfound', 'tool_dataprivacy')];}return ['result' => $result,'warnings' => $warnings];}/*** Parameter description for deny_data_request().** @since Moodle 3.5* @return \core_external\external_description*/public static function deny_data_request_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'The processing result'),'warnings' => new external_warnings()]);}/*** Parameter description for bulk_deny_data_requests().** @since Moodle 3.5* @return external_function_parameters*/public static function bulk_deny_data_requests_parameters() {return new external_function_parameters(['requestids' => new external_multiple_structure(new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED))]);}/*** Bulk deny data requests.** @since Moodle 3.5* @param array $requestids Array consisting of request ID's.* @return array* @throws coding_exception* @throws dml_exception* @throws invalid_parameter_exception* @throws restricted_context_exception* @throws moodle_exception*/public static function bulk_deny_data_requests($requestids) {$warnings = [];$result = false;$params = external_api::validate_parameters(self::bulk_deny_data_requests_parameters(), ['requestids' => $requestids]);$requestids = $params['requestids'];// Validate context.$context = context_system::instance();self::validate_context($context);require_capability('tool/dataprivacy:managedatarequests', $context);foreach ($requestids as $requestid) {// Ensure the request exists.$requestexists = data_request::record_exists($requestid);if ($requestexists) {api::deny_data_request($requestid);} else {$warnings[] = ['item' => $requestid,'warningcode' => 'errorrequestnotfound','message' => get_string('errorrequestnotfound', 'tool_dataprivacy')];}}if (empty($warnings)) {$result = true;// Add notification in the session to be shown when the page is reloaded on the JS side.notification::success(get_string('requestsdenied', 'tool_dataprivacy'));}return ['result' => $result,'warnings' => $warnings];}/*** Parameter description for bulk_deny_data_requests().** @since Moodle 3.5* @return \core_external\external_description*/public static function bulk_deny_data_requests_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'The processing result'),'warnings' => new external_warnings()]);}/*** Parameter description for get_data_request().** @since Moodle 3.5* @return external_function_parameters*/public static function get_users_parameters() {return new external_function_parameters(['query' => new external_value(PARAM_TEXT, 'The search query', VALUE_REQUIRED)]);}/*** Fetch the details of a user's data request.** @since Moodle 3.5* @param string $query The search request.* @return array* @throws required_capability_exception* @throws dml_exception* @throws invalid_parameter_exception* @throws restricted_context_exception*/public static function get_users($query) {global $DB;$params = external_api::validate_parameters(self::get_users_parameters(), ['query' => $query]);$query = $params['query'];// Validate context.$context = context_system::instance();self::validate_context($context);require_capability('tool/dataprivacy:managedatarequests', $context);$userfieldsapi = \core_user\fields::for_name();$allusernames = $userfieldsapi->get_sql('', false, '', '', false)->selects;// Exclude admins and guest user.$excludedusers = array_keys(get_admins()) + [guest_user()->id];$sort = 'lastname ASC, firstname ASC';$fields = 'id,' . $allusernames;// TODO Does not support custom user profile fields (MDL-70456).$extrafields = \core_user\fields::get_identity_fields($context, false);if (!empty($extrafields)) {$fields .= ',' . implode(',', $extrafields);}list($sql, $params) = users_search_sql($query, '', USER_SEARCH_STARTS_WITH, $extrafields, $excludedusers);$users = $DB->get_records_select('user', $sql, $params, $sort, $fields, 0, 30);$useroptions = [];foreach ($users as $user) {$useroption = (object)['id' => $user->id,'fullname' => fullname($user)];$useroption->extrafields = [];foreach ($extrafields as $extrafield) {// Sanitize the extra fields to prevent potential XSS exploit.$useroption->extrafields[] = (object)['name' => $extrafield,'value' => s($user->$extrafield)];}$useroptions[$user->id] = $useroption;}return $useroptions;}/*** Parameter description for get_users().** @since Moodle 3.5* @return \core_external\external_description* @throws coding_exception*/public static function get_users_returns() {return new external_multiple_structure(new external_single_structure(['id' => new external_value(core_user::get_property_type('id'), 'ID of the user'),'fullname' => new external_value(core_user::get_property_type('firstname'), 'The fullname of the user'),'extrafields' => new external_multiple_structure(new external_single_structure(['name' => new external_value(PARAM_TEXT, 'Name of the extrafield.'),'value' => new external_value(PARAM_TEXT, 'Value of the extrafield.')]), 'List of extra fields', VALUE_OPTIONAL)]));}/*** Parameter description for create_purpose_form().** @since Moodle 3.5* @return external_function_parameters*/public static function create_purpose_form_parameters() {return new external_function_parameters(['jsonformdata' => new external_value(PARAM_RAW, 'The data to create the purpose, encoded as a json array')]);}/*** Creates a data purpose from form data.** @since Moodle 3.5* @param string $jsonformdata* @return array*/public static function create_purpose_form($jsonformdata) {global $PAGE;$warnings = [];$params = external_api::validate_parameters(self::create_purpose_form_parameters(), ['jsonformdata' => $jsonformdata]);// Validate context and access to manage the registry.self::validate_context(\context_system::instance());api::check_can_manage_data_registry();$serialiseddata = json_decode($params['jsonformdata']);$data = array();parse_str($serialiseddata, $data);$purpose = new \tool_dataprivacy\purpose(0);$mform = new \tool_dataprivacy\form\purpose(null, ['persistent' => $purpose], 'post', '', null, true, $data);$validationerrors = true;if ($validateddata = $mform->get_data()) {$purpose = api::create_purpose($validateddata);$validationerrors = false;} else if ($errors = $mform->is_validated()) {throw new moodle_exception('generalerror');}$exporter = new purpose_exporter($purpose, ['context' => \context_system::instance()]);return ['purpose' => $exporter->export($PAGE->get_renderer('core')),'validationerrors' => $validationerrors,'warnings' => $warnings];}/*** Returns for create_purpose_form().** @since Moodle 3.5* @return external_single_structure*/public static function create_purpose_form_returns() {return new external_single_structure(['purpose' => purpose_exporter::get_read_structure(),'validationerrors' => new external_value(PARAM_BOOL, 'Were there validation errors', VALUE_REQUIRED),'warnings' => new external_warnings()]);}/*** Parameter description for delete_purpose().** @since Moodle 3.5* @return external_function_parameters*/public static function delete_purpose_parameters() {return new external_function_parameters(['id' => new external_value(PARAM_INT, 'The purpose ID', VALUE_REQUIRED)]);}/*** Deletes a data purpose.** @since Moodle 3.5* @param int $id The ID.* @return array* @throws invalid_persistent_exception* @throws coding_exception* @throws invalid_parameter_exception*/public static function delete_purpose($id) {global $USER;$params = external_api::validate_parameters(self::delete_purpose_parameters(), ['id' => $id]);// Validate context and access to manage the registry.self::validate_context(\context_system::instance());api::check_can_manage_data_registry();$result = api::delete_purpose($params['id']);return ['result' => $result,'warnings' => []];}/*** Parameter description for delete_purpose().** @since Moodle 3.5* @return external_single_structure*/public static function delete_purpose_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'The processing result'),'warnings' => new external_warnings()]);}/*** Parameter description for create_category_form().** @since Moodle 3.5* @return external_function_parameters*/public static function create_category_form_parameters() {return new external_function_parameters(['jsonformdata' => new external_value(PARAM_RAW, 'The data to create the category, encoded as a json array')]);}/*** Creates a data category from form data.** @since Moodle 3.5* @param string $jsonformdata* @return array*/public static function create_category_form($jsonformdata) {global $PAGE;$warnings = [];$params = external_api::validate_parameters(self::create_category_form_parameters(), ['jsonformdata' => $jsonformdata]);// Validate context and access to manage the registry.self::validate_context(\context_system::instance());api::check_can_manage_data_registry();$serialiseddata = json_decode($params['jsonformdata']);$data = array();parse_str($serialiseddata, $data);$category = new \tool_dataprivacy\category(0);$mform = new \tool_dataprivacy\form\category(null, ['persistent' => $category], 'post', '', null, true, $data);$validationerrors = true;if ($validateddata = $mform->get_data()) {$category = api::create_category($validateddata);$validationerrors = false;} else if ($errors = $mform->is_validated()) {throw new moodle_exception('generalerror');}$exporter = new category_exporter($category, ['context' => \context_system::instance()]);return ['category' => $exporter->export($PAGE->get_renderer('core')),'validationerrors' => $validationerrors,'warnings' => $warnings];}/*** Returns for create_category_form().** @since Moodle 3.5* @return external_single_structure*/public static function create_category_form_returns() {return new external_single_structure(['category' => category_exporter::get_read_structure(),'validationerrors' => new external_value(PARAM_BOOL, 'Were there validation errors', VALUE_REQUIRED),'warnings' => new external_warnings()]);}/*** Parameter description for delete_category().** @since Moodle 3.5* @return external_function_parameters*/public static function delete_category_parameters() {return new external_function_parameters(['id' => new external_value(PARAM_INT, 'The category ID', VALUE_REQUIRED)]);}/*** Deletes a data category.** @since Moodle 3.5* @param int $id The ID.* @return array* @throws invalid_persistent_exception* @throws coding_exception* @throws invalid_parameter_exception*/public static function delete_category($id) {global $USER;$params = external_api::validate_parameters(self::delete_category_parameters(), ['id' => $id]);// Validate context and access to manage the registry.self::validate_context(\context_system::instance());api::check_can_manage_data_registry();$result = api::delete_category($params['id']);return ['result' => $result,'warnings' => []];}/*** Parameter description for delete_category().** @since Moodle 3.5* @return external_single_structure*/public static function delete_category_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'The processing result'),'warnings' => new external_warnings()]);}/*** Parameter description for set_contextlevel_form().** @since Moodle 3.5* @return external_function_parameters*/public static function set_contextlevel_form_parameters() {return new external_function_parameters(['jsonformdata' => new external_value(PARAM_RAW, 'The context level data, encoded as a json array')]);}/*** Creates a data category from form data.** @since Moodle 3.5* @param string $jsonformdata* @return array*/public static function set_contextlevel_form($jsonformdata) {global $PAGE;$warnings = [];$params = external_api::validate_parameters(self::set_contextlevel_form_parameters(), ['jsonformdata' => $jsonformdata]);// Validate context and access to manage the registry.self::validate_context(\context_system::instance());api::check_can_manage_data_registry();$serialiseddata = json_decode($params['jsonformdata']);$data = array();parse_str($serialiseddata, $data);$contextlevel = $data['contextlevel'];$customdata = \tool_dataprivacy\form\contextlevel::get_contextlevel_customdata($contextlevel);$mform = new \tool_dataprivacy\form\contextlevel(null, $customdata, 'post', '', null, true, $data);if ($validateddata = $mform->get_data()) {$contextlevel = api::set_contextlevel($validateddata);} else if ($errors = $mform->is_validated()) {$warnings[] = json_encode($errors);}if ($contextlevel) {$result = true;} else {$result = false;}return ['result' => $result,'warnings' => $warnings];}/*** Returns for set_contextlevel_form().** @since Moodle 3.5* @return external_single_structure*/public static function set_contextlevel_form_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'Whether the data was properly set or not'),'warnings' => new external_warnings()]);}/*** Parameter description for set_context_form().** @since Moodle 3.5* @return external_function_parameters*/public static function set_context_form_parameters() {return new external_function_parameters(['jsonformdata' => new external_value(PARAM_RAW, 'The context level data, encoded as a json array')]);}/*** Creates a data category from form data.** @since Moodle 3.5* @param string $jsonformdata* @return array*/public static function set_context_form($jsonformdata) {global $PAGE;$warnings = [];$params = external_api::validate_parameters(self::set_context_form_parameters(), ['jsonformdata' => $jsonformdata]);// Validate context and access to manage the registry.self::validate_context(\context_system::instance());api::check_can_manage_data_registry();$serialiseddata = json_decode($params['jsonformdata']);$data = array();parse_str($serialiseddata, $data);$context = context_helper::instance_by_id($data['contextid']);$customdata = \tool_dataprivacy\form\context_instance::get_context_instance_customdata($context);$mform = new \tool_dataprivacy\form\context_instance(null, $customdata, 'post', '', null, true, $data);if ($validateddata = $mform->get_data()) {api::check_can_manage_data_registry($validateddata->contextid);$context = api::set_context_instance($validateddata);} else if ($errors = $mform->is_validated()) {$warnings[] = json_encode($errors);throw new moodle_exception('generalerror');}if ($context) {$result = true;} else {$result = false;}return ['result' => $result,'warnings' => $warnings];}/*** Returns for set_context_form().** @since Moodle 3.5* @return external_single_structure*/public static function set_context_form_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'Whether the data was properly set or not'),'warnings' => new external_warnings()]);}/*** Parameter description for tree_extra_branches().** @since Moodle 3.5* @return external_function_parameters*/public static function tree_extra_branches_parameters() {return new external_function_parameters(['contextid' => new external_value(PARAM_INT, 'The context id to expand'),'element' => new external_value(PARAM_ALPHA, 'The element we are interested on')]);}/*** Returns tree extra branches.** @since Moodle 3.5* @param int $contextid* @param string $element* @return array*/public static function tree_extra_branches($contextid, $element) {$params = external_api::validate_parameters(self::tree_extra_branches_parameters(), ['contextid' => $contextid,'element' => $element,]);$context = context_helper::instance_by_id($params['contextid']);self::validate_context($context);api::check_can_manage_data_registry($context->id);switch ($params['element']) {case 'course':$branches = data_registry_page::get_courses_branch($context);break;case 'module':$branches = data_registry_page::get_modules_branch($context);break;case 'block':$branches = data_registry_page::get_blocks_branch($context);break;default:throw new \moodle_exception('Unsupported element provided.');}return ['branches' => $branches,'warnings' => [],];}/*** Returns for tree_extra_branches().** @since Moodle 3.5* @return external_single_structure*/public static function tree_extra_branches_returns() {return new external_single_structure(['branches' => new external_multiple_structure(self::get_tree_node_structure(true)),'warnings' => new external_warnings()]);}/*** Parameters for confirm_contexts_for_deletion().** @since Moodle 3.5* @return external_function_parameters*/public static function confirm_contexts_for_deletion_parameters() {return new external_function_parameters(['ids' => new external_multiple_structure(new external_value(PARAM_INT, 'Expired context record ID', VALUE_REQUIRED),'Array of expired context record IDs', VALUE_DEFAULT, []),]);}/*** Confirm a given array of expired context record IDs** @since Moodle 3.5* @param int[] $ids Array of record IDs from the expired contexts table.* @return array* @throws coding_exception* @throws dml_exception* @throws invalid_parameter_exception* @throws restricted_context_exception*/public static function confirm_contexts_for_deletion($ids) {$warnings = [];$params = external_api::validate_parameters(self::confirm_contexts_for_deletion_parameters(), ['ids' => $ids]);$ids = $params['ids'];// Validate context and access to manage the registry.self::validate_context(\context_system::instance());api::check_can_manage_data_registry();$result = true;if (!empty($ids)) {$expiredcontextstoapprove = [];// Loop through the deletion of expired contexts and their children if necessary.foreach ($ids as $id) {$expiredcontext = new expired_context($id);$targetcontext = context_helper::instance_by_id($expiredcontext->get('contextid'));if (!$targetcontext instanceof \context_user) {// Fetch this context's child contexts. Make sure that all of the child contexts are flagged for deletion.// User context children do not need to be considered.$childcontexts = $targetcontext->get_child_contexts();foreach ($childcontexts as $child) {if ($expiredchildcontext = expired_context::get_record(['contextid' => $child->id])) {// Add this child context to the list for approval.$expiredcontextstoapprove[] = $expiredchildcontext;} else {// This context has not yet been flagged for deletion.$result = false;$message = get_string('errorcontexthasunexpiredchildren', 'tool_dataprivacy',$targetcontext->get_context_name(false));$warnings[] = ['item' => 'tool_dataprivacy_ctxexpired','warningcode' => 'errorcontexthasunexpiredchildren','message' => $message];// Exit the process.break 2;}}}$expiredcontextstoapprove[] = $expiredcontext;}// Proceed with the approval if everything's in order.if ($result) {// Mark expired contexts as approved for deletion.foreach ($expiredcontextstoapprove as $expired) {// Only mark expired contexts that are pending approval.if ($expired->get('status') == expired_context::STATUS_EXPIRED) {api::set_expired_context_status($expired, expired_context::STATUS_APPROVED);}}}} else {// We don't have anything to process.$result = false;$warnings[] = ['item' => 'tool_dataprivacy_ctxexpired','warningcode' => 'errornoexpiredcontexts','message' => get_string('errornoexpiredcontexts', 'tool_dataprivacy')];}return ['result' => $result,'warnings' => $warnings];}/*** Returns for confirm_contexts_for_deletion().** @since Moodle 3.5* @return external_single_structure*/public static function confirm_contexts_for_deletion_returns() {return new external_single_structure(['result' => new external_value(PARAM_BOOL, 'Whether the record was properly marked for deletion or not'),'warnings' => new external_warnings()]);}/*** 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);api::check_can_manage_data_registry();// 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);api::check_can_manage_data_registry();$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).** @since Moodle 3.5* @param bool $allowchildbranches* @return array*/private static function get_tree_node_structure($allowchildbranches = true) {$fields = ['text' => new external_value(PARAM_RAW, 'The node text', VALUE_REQUIRED),'expandcontextid' => new external_value(PARAM_INT, 'The contextid this node expands', VALUE_REQUIRED),'expandelement' => new external_value(PARAM_ALPHA, 'What element is this node expanded to', VALUE_REQUIRED),'contextid' => new external_value(PARAM_INT, 'The node contextid', VALUE_REQUIRED),'contextlevel' => new external_value(PARAM_INT, 'The node contextlevel', VALUE_REQUIRED),'expanded' => new external_value(PARAM_INT, 'Is it expanded', VALUE_REQUIRED),];if ($allowchildbranches) {// Passing false as we will not have more than 1 sub-level.$fields['branches'] = new external_multiple_structure(self::get_tree_node_structure(false),'Children node structure',VALUE_OPTIONAL);} else {// We will only have 1 sub-level and we don't want an infinite get_tree_node_structure, this is a hacky// way to prevent this infinite loop when calling get_tree_node_structure recursively.$fields['branches'] = new external_multiple_structure(new external_value(PARAM_TEXT,'Nothing really, it will always be an empty array',VALUE_OPTIONAL));}return new external_single_structure($fields, 'Node structure', VALUE_OPTIONAL);}}