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