| 1 | efrain | 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 |  * Fragment to add a new purpose.
 | 
        
           |  |  | 121 |  *
 | 
        
           |  |  | 122 |  * @param array $args The fragment arguments.
 | 
        
           |  |  | 123 |  * @return string The rendered mform fragment.
 | 
        
           |  |  | 124 |  */
 | 
        
           |  |  | 125 | function tool_dataprivacy_output_fragment_addpurpose_form($args) {
 | 
        
           |  |  | 126 |   | 
        
           |  |  | 127 |     $formdata = [];
 | 
        
           |  |  | 128 |     if (!empty($args['jsonformdata'])) {
 | 
        
           |  |  | 129 |         $serialiseddata = json_decode($args['jsonformdata']);
 | 
        
           |  |  | 130 |         parse_str($serialiseddata, $formdata);
 | 
        
           |  |  | 131 |     }
 | 
        
           |  |  | 132 |   | 
        
           |  |  | 133 |     $persistent = new \tool_dataprivacy\purpose();
 | 
        
           |  |  | 134 |     $mform = new \tool_dataprivacy\form\purpose(null, ['persistent' => $persistent],
 | 
        
           |  |  | 135 |         'post', '', null, true, $formdata);
 | 
        
           |  |  | 136 |   | 
        
           |  |  | 137 |     if (!empty($args['jsonformdata'])) {
 | 
        
           |  |  | 138 |         // Show errors if data was received.
 | 
        
           |  |  | 139 |         $mform->is_validated();
 | 
        
           |  |  | 140 |     }
 | 
        
           |  |  | 141 |   | 
        
           |  |  | 142 |     return $mform->render();
 | 
        
           |  |  | 143 | }
 | 
        
           |  |  | 144 |   | 
        
           |  |  | 145 | /**
 | 
        
           |  |  | 146 |  * Fragment to add a new category.
 | 
        
           |  |  | 147 |  *
 | 
        
           |  |  | 148 |  * @param array $args The fragment arguments.
 | 
        
           |  |  | 149 |  * @return string The rendered mform fragment.
 | 
        
           |  |  | 150 |  */
 | 
        
           |  |  | 151 | function tool_dataprivacy_output_fragment_addcategory_form($args) {
 | 
        
           |  |  | 152 |   | 
        
           |  |  | 153 |     $formdata = [];
 | 
        
           |  |  | 154 |     if (!empty($args['jsonformdata'])) {
 | 
        
           |  |  | 155 |         $serialiseddata = json_decode($args['jsonformdata']);
 | 
        
           |  |  | 156 |         parse_str($serialiseddata, $formdata);
 | 
        
           |  |  | 157 |     }
 | 
        
           |  |  | 158 |   | 
        
           |  |  | 159 |     $persistent = new \tool_dataprivacy\category();
 | 
        
           |  |  | 160 |     $mform = new \tool_dataprivacy\form\category(null, ['persistent' => $persistent],
 | 
        
           |  |  | 161 |         'post', '', null, true, $formdata);
 | 
        
           |  |  | 162 |   | 
        
           |  |  | 163 |     if (!empty($args['jsonformdata'])) {
 | 
        
           |  |  | 164 |         // Show errors if data was received.
 | 
        
           |  |  | 165 |         $mform->is_validated();
 | 
        
           |  |  | 166 |     }
 | 
        
           |  |  | 167 |   | 
        
           |  |  | 168 |     return $mform->render();
 | 
        
           |  |  | 169 | }
 | 
        
           |  |  | 170 |   | 
        
           |  |  | 171 | /**
 | 
        
           |  |  | 172 |  * Fragment to edit a context purpose and category.
 | 
        
           |  |  | 173 |  *
 | 
        
           |  |  | 174 |  * @param array $args The fragment arguments.
 | 
        
           |  |  | 175 |  * @return string The rendered mform fragment.
 | 
        
           |  |  | 176 |  */
 | 
        
           |  |  | 177 | function tool_dataprivacy_output_fragment_context_form($args) {
 | 
        
           |  |  | 178 |     global $PAGE;
 | 
        
           |  |  | 179 |   | 
        
           |  |  | 180 |     $contextid = $args[0];
 | 
        
           |  |  | 181 |   | 
        
           |  |  | 182 |     $context = \context_helper::instance_by_id($contextid);
 | 
        
           |  |  | 183 |     $customdata = \tool_dataprivacy\form\context_instance::get_context_instance_customdata($context);
 | 
        
           |  |  | 184 |   | 
        
           |  |  | 185 |     if (!empty($customdata['purposeretentionperiods'])) {
 | 
        
           |  |  | 186 |         $PAGE->requires->js_call_amd('tool_dataprivacy/effective_retention_period', 'init',
 | 
        
           |  |  | 187 |             [$customdata['purposeretentionperiods']]);
 | 
        
           |  |  | 188 |     }
 | 
        
           |  |  | 189 |     $mform = new \tool_dataprivacy\form\context_instance(null, $customdata);
 | 
        
           |  |  | 190 |     return $mform->render();
 | 
        
           |  |  | 191 | }
 | 
        
           |  |  | 192 |   | 
        
           |  |  | 193 | /**
 | 
        
           |  |  | 194 |  * Fragment to edit a contextlevel purpose and category.
 | 
        
           |  |  | 195 |  *
 | 
        
           |  |  | 196 |  * @param array $args The fragment arguments.
 | 
        
           |  |  | 197 |  * @return string The rendered mform fragment.
 | 
        
           |  |  | 198 |  */
 | 
        
           |  |  | 199 | function tool_dataprivacy_output_fragment_contextlevel_form($args) {
 | 
        
           |  |  | 200 |     global $PAGE;
 | 
        
           |  |  | 201 |   | 
        
           |  |  | 202 |     $contextlevel = $args[0];
 | 
        
           |  |  | 203 |     $customdata = \tool_dataprivacy\form\contextlevel::get_contextlevel_customdata($contextlevel);
 | 
        
           |  |  | 204 |   | 
        
           |  |  | 205 |     if (!empty($customdata['purposeretentionperiods'])) {
 | 
        
           |  |  | 206 |         $PAGE->requires->js_call_amd('tool_dataprivacy/effective_retention_period', 'init',
 | 
        
           |  |  | 207 |             [$customdata['purposeretentionperiods']]);
 | 
        
           |  |  | 208 |     }
 | 
        
           |  |  | 209 |   | 
        
           |  |  | 210 |     $mform = new \tool_dataprivacy\form\contextlevel(null, $customdata);
 | 
        
           |  |  | 211 |     return $mform->render();
 | 
        
           |  |  | 212 | }
 | 
        
           |  |  | 213 |   | 
        
           |  |  | 214 | /**
 | 
        
           |  |  | 215 |  * Serves any files associated with the data privacy settings.
 | 
        
           |  |  | 216 |  *
 | 
        
           |  |  | 217 |  * @param stdClass $course Course object
 | 
        
           |  |  | 218 |  * @param stdClass $cm Course module object
 | 
        
           |  |  | 219 |  * @param context $context Context
 | 
        
           |  |  | 220 |  * @param string $filearea File area for data privacy
 | 
        
           |  |  | 221 |  * @param array $args Arguments
 | 
        
           |  |  | 222 |  * @param bool $forcedownload If we are forcing the download
 | 
        
           |  |  | 223 |  * @param array $options More options
 | 
        
           |  |  | 224 |  * @return bool Returns false if we don't find a file.
 | 
        
           |  |  | 225 |  */
 | 
        
           |  |  | 226 | function tool_dataprivacy_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) {
 | 
        
           |  |  | 227 |     if ($context->contextlevel == CONTEXT_USER) {
 | 
        
           |  |  | 228 |         // Make sure the user is logged in.
 | 
        
           |  |  | 229 |         require_login(null, false);
 | 
        
           |  |  | 230 |   | 
        
           |  |  | 231 |         // Get the data request ID. This should be the first element of the $args array.
 | 
        
           |  |  | 232 |         $itemid = $args[0];
 | 
        
           |  |  | 233 |         // Fetch the data request object. An invalid ID will throw an exception.
 | 
        
           |  |  | 234 |         $datarequest = new \tool_dataprivacy\data_request($itemid);
 | 
        
           |  |  | 235 |   | 
        
           |  |  | 236 |         // Check if user is allowed to download it.
 | 
        
           |  |  | 237 |         if (!\tool_dataprivacy\api::can_download_data_request_for_user($context->instanceid, $datarequest->get('requestedby'))) {
 | 
        
           |  |  | 238 |             return false;
 | 
        
           |  |  | 239 |         }
 | 
        
           |  |  | 240 |   | 
        
           |  |  | 241 |         // Make the file unavailable if it has expired.
 | 
        
           |  |  | 242 |         if (\tool_dataprivacy\data_request::is_expired($datarequest)) {
 | 
        
           |  |  | 243 |             send_file_not_found();
 | 
        
           |  |  | 244 |         }
 | 
        
           |  |  | 245 |   | 
        
           |  |  | 246 |         // All good. Serve the exported data.
 | 
        
           |  |  | 247 |         $fs = get_file_storage();
 | 
        
           |  |  | 248 |         $relativepath = implode('/', $args);
 | 
        
           |  |  | 249 |         $fullpath = "/$context->id/tool_dataprivacy/$filearea/$relativepath";
 | 
        
           |  |  | 250 |         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
 | 
        
           |  |  | 251 |             return false;
 | 
        
           |  |  | 252 |         }
 | 
        
           |  |  | 253 |         send_stored_file($file, 0, 0, $forcedownload, $options);
 | 
        
           |  |  | 254 |     } else {
 | 
        
           |  |  | 255 |         send_file_not_found();
 | 
        
           |  |  | 256 |     }
 | 
        
           |  |  | 257 | }
 | 
        
           |  |  | 258 |   | 
        
           |  |  | 259 | /**
 | 
        
           |  |  | 260 |  * Fragment to add a select course.
 | 
        
           |  |  | 261 |  *
 | 
        
           |  |  | 262 |  * @param array $args The fragment arguments.
 | 
        
           |  |  | 263 |  * @return string The rendered mform fragment.
 | 
        
           |  |  | 264 |  */
 | 
        
           |  |  | 265 | function tool_dataprivacy_output_fragment_selectcourses_form(array $args): string {
 | 
        
           |  |  | 266 |     $args = (object)$args;
 | 
        
           |  |  | 267 |   | 
        
           |  |  | 268 |     $context = context_system::instance();
 | 
        
           |  |  | 269 |     require_capability('tool/dataprivacy:managedatarequests', $context);
 | 
        
           |  |  | 270 |   | 
        
           |  |  | 271 |     if (!empty($args->jsonformdata)) {
 | 
        
           |  |  | 272 |         $serialiseddata = json_decode($args->jsonformdata);
 | 
        
           |  |  | 273 |     }
 | 
        
           |  |  | 274 |   | 
        
           |  |  | 275 |     $mform = new exportfilter_form(null, ['requestid' => $serialiseddata->requestid]);
 | 
        
           |  |  | 276 |   | 
        
           |  |  | 277 |     return $mform->render();
 | 
        
           |  |  | 278 | }
 |