See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401] [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Data privacy plugin library 19 * @package tool_dataprivacy 20 * @copyright 2018 onwards Jun Pataleta 21 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 */ 23 24 use core_user\output\myprofile\tree; 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 /** 29 * Add nodes to myprofile page. 30 * 31 * @param tree $tree Tree object 32 * @param stdClass $user User object 33 * @param bool $iscurrentuser 34 * @param stdClass $course Course object 35 * @return bool 36 * @throws coding_exception 37 * @throws dml_exception 38 * @throws moodle_exception 39 */ 40 function tool_dataprivacy_myprofile_navigation(tree $tree, $user, $iscurrentuser, $course) { 41 global $PAGE, $USER; 42 43 // Get the Privacy and policies category. 44 if (!array_key_exists('privacyandpolicies', $tree->__get('categories'))) { 45 // Create the category. 46 $categoryname = get_string('privacyandpolicies', 'admin'); 47 $category = new core_user\output\myprofile\category('privacyandpolicies', $categoryname, 'contact'); 48 $tree->add_category($category); 49 } else { 50 // Get the existing category. 51 $category = $tree->__get('categories')['privacyandpolicies']; 52 } 53 54 // Contact data protection officer link. 55 if (\tool_dataprivacy\api::can_contact_dpo() && $iscurrentuser) { 56 $renderer = $PAGE->get_renderer('tool_dataprivacy'); 57 $content = $renderer->render_contact_dpo_link(); 58 $node = new core_user\output\myprofile\node('privacyandpolicies', 'contactdpo', null, null, null, $content); 59 $category->add_node($node); 60 61 // Require our Javascript module to handle contact DPO interaction. 62 $PAGE->requires->js_call_amd('tool_dataprivacy/contactdpo', 'init'); 63 64 $url = new moodle_url('/admin/tool/dataprivacy/mydatarequests.php'); 65 $node = new core_user\output\myprofile\node('privacyandpolicies', 'datarequests', 66 get_string('datarequests', 'tool_dataprivacy'), null, $url); 67 $category->add_node($node); 68 69 // Check if the user has an ongoing data export request. 70 $hasexportrequest = \tool_dataprivacy\api::has_ongoing_request($user->id, \tool_dataprivacy\api::DATAREQUEST_TYPE_EXPORT); 71 // Show data export link only if the user doesn't have an ongoing data export request and has permission 72 // to download own data. 73 if (!$hasexportrequest && \tool_dataprivacy\api::can_create_data_download_request_for_self()) { 74 $exportparams = ['type' => \tool_dataprivacy\api::DATAREQUEST_TYPE_EXPORT]; 75 $exporturl = new moodle_url('/admin/tool/dataprivacy/createdatarequest.php', $exportparams); 76 $exportnode = new core_user\output\myprofile\node('privacyandpolicies', 'requestdataexport', 77 get_string('requesttypeexport', 'tool_dataprivacy'), null, $exporturl); 78 $category->add_node($exportnode); 79 } 80 81 // Check if the user has an ongoing data deletion request. 82 $hasdeleterequest = \tool_dataprivacy\api::has_ongoing_request($user->id, \tool_dataprivacy\api::DATAREQUEST_TYPE_DELETE); 83 // Show data deletion link only if the user doesn't have an ongoing data deletion request and has permission 84 // to create data deletion request. 85 if (!$hasdeleterequest && \tool_dataprivacy\api::can_create_data_deletion_request_for_self()) { 86 $deleteparams = ['type' => \tool_dataprivacy\api::DATAREQUEST_TYPE_DELETE]; 87 $deleteurl = new moodle_url('/admin/tool/dataprivacy/createdatarequest.php', $deleteparams); 88 $deletenode = new core_user\output\myprofile\node('privacyandpolicies', 'requestdatadeletion', 89 get_string('deletemyaccount', 'tool_dataprivacy'), null, $deleteurl); 90 $category->add_node($deletenode); 91 } 92 } 93 94 // A returned 0 means that the setting was set and disabled, false means that there is no value for the provided setting. 95 $showsummary = get_config('tool_dataprivacy', 'showdataretentionsummary'); 96 if ($showsummary === false) { 97 // This means that no value is stored in db. We use the default value in this case. 98 $showsummary = true; 99 } 100 101 if ($showsummary && $iscurrentuser) { 102 $summaryurl = new moodle_url('/admin/tool/dataprivacy/summary.php'); 103 $summarynode = new core_user\output\myprofile\node('privacyandpolicies', 'retentionsummary', 104 get_string('dataretentionsummary', 'tool_dataprivacy'), null, $summaryurl); 105 $category->add_node($summarynode); 106 } 107 108 // Add the Privacy category to the tree if it's not empty and it doesn't exist. 109 $nodes = $category->nodes; 110 if (!empty($nodes)) { 111 if (!array_key_exists('privacyandpolicies', $tree->__get('categories'))) { 112 $tree->add_category($category); 113 } 114 return true; 115 } 116 117 return false; 118 } 119 120 /** 121 * Callback to add footer elements. 122 * 123 * @return string HTML footer content 124 */ 125 function tool_dataprivacy_standard_footer_html() { 126 $output = ''; 127 128 // A returned 0 means that the setting was set and disabled, false means that there is no value for the provided setting. 129 $showsummary = get_config('tool_dataprivacy', 'showdataretentionsummary'); 130 if ($showsummary === false) { 131 // This means that no value is stored in db. We use the default value in this case. 132 $showsummary = true; 133 } 134 135 if ($showsummary) { 136 $url = new moodle_url('/admin/tool/dataprivacy/summary.php'); 137 $output = html_writer::link($url, get_string('dataretentionsummary', 'tool_dataprivacy')); 138 $output = html_writer::div($output, 'tool_dataprivacy'); 139 } 140 return $output; 141 } 142 143 /** 144 * Fragment to add a new purpose. 145 * 146 * @param array $args The fragment arguments. 147 * @return string The rendered mform fragment. 148 */ 149 function tool_dataprivacy_output_fragment_addpurpose_form($args) { 150 151 $formdata = []; 152 if (!empty($args['jsonformdata'])) { 153 $serialiseddata = json_decode($args['jsonformdata']); 154 parse_str($serialiseddata, $formdata); 155 } 156 157 $persistent = new \tool_dataprivacy\purpose(); 158 $mform = new \tool_dataprivacy\form\purpose(null, ['persistent' => $persistent], 159 'post', '', null, true, $formdata); 160 161 if (!empty($args['jsonformdata'])) { 162 // Show errors if data was received. 163 $mform->is_validated(); 164 } 165 166 return $mform->render(); 167 } 168 169 /** 170 * Fragment to add a new category. 171 * 172 * @param array $args The fragment arguments. 173 * @return string The rendered mform fragment. 174 */ 175 function tool_dataprivacy_output_fragment_addcategory_form($args) { 176 177 $formdata = []; 178 if (!empty($args['jsonformdata'])) { 179 $serialiseddata = json_decode($args['jsonformdata']); 180 parse_str($serialiseddata, $formdata); 181 } 182 183 $persistent = new \tool_dataprivacy\category(); 184 $mform = new \tool_dataprivacy\form\category(null, ['persistent' => $persistent], 185 'post', '', null, true, $formdata); 186 187 if (!empty($args['jsonformdata'])) { 188 // Show errors if data was received. 189 $mform->is_validated(); 190 } 191 192 return $mform->render(); 193 } 194 195 /** 196 * Fragment to edit a context purpose and category. 197 * 198 * @param array $args The fragment arguments. 199 * @return string The rendered mform fragment. 200 */ 201 function tool_dataprivacy_output_fragment_context_form($args) { 202 global $PAGE; 203 204 $contextid = $args[0]; 205 206 $context = \context_helper::instance_by_id($contextid); 207 $customdata = \tool_dataprivacy\form\context_instance::get_context_instance_customdata($context); 208 209 if (!empty($customdata['purposeretentionperiods'])) { 210 $PAGE->requires->js_call_amd('tool_dataprivacy/effective_retention_period', 'init', 211 [$customdata['purposeretentionperiods']]); 212 } 213 $mform = new \tool_dataprivacy\form\context_instance(null, $customdata); 214 return $mform->render(); 215 } 216 217 /** 218 * Fragment to edit a contextlevel purpose and category. 219 * 220 * @param array $args The fragment arguments. 221 * @return string The rendered mform fragment. 222 */ 223 function tool_dataprivacy_output_fragment_contextlevel_form($args) { 224 global $PAGE; 225 226 $contextlevel = $args[0]; 227 $customdata = \tool_dataprivacy\form\contextlevel::get_contextlevel_customdata($contextlevel); 228 229 if (!empty($customdata['purposeretentionperiods'])) { 230 $PAGE->requires->js_call_amd('tool_dataprivacy/effective_retention_period', 'init', 231 [$customdata['purposeretentionperiods']]); 232 } 233 234 $mform = new \tool_dataprivacy\form\contextlevel(null, $customdata); 235 return $mform->render(); 236 } 237 238 /** 239 * Serves any files associated with the data privacy settings. 240 * 241 * @param stdClass $course Course object 242 * @param stdClass $cm Course module object 243 * @param context $context Context 244 * @param string $filearea File area for data privacy 245 * @param array $args Arguments 246 * @param bool $forcedownload If we are forcing the download 247 * @param array $options More options 248 * @return bool Returns false if we don't find a file. 249 */ 250 function tool_dataprivacy_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) { 251 if ($context->contextlevel == CONTEXT_USER) { 252 // Make sure the user is logged in. 253 require_login(null, false); 254 255 // Get the data request ID. This should be the first element of the $args array. 256 $itemid = $args[0]; 257 // Fetch the data request object. An invalid ID will throw an exception. 258 $datarequest = new \tool_dataprivacy\data_request($itemid); 259 260 // Check if user is allowed to download it. 261 if (!\tool_dataprivacy\api::can_download_data_request_for_user($context->instanceid, $datarequest->get('requestedby'))) { 262 return false; 263 } 264 265 // Make the file unavailable if it has expired. 266 if (\tool_dataprivacy\data_request::is_expired($datarequest)) { 267 send_file_not_found(); 268 } 269 270 // All good. Serve the exported data. 271 $fs = get_file_storage(); 272 $relativepath = implode('/', $args); 273 $fullpath = "/$context->id/tool_dataprivacy/$filearea/$relativepath"; 274 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 275 return false; 276 } 277 send_stored_file($file, 0, 0, $forcedownload, $options); 278 } else { 279 send_file_not_found(); 280 } 281 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body