See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401]
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 registry renderable. 19 * 20 * @package tool_dataprivacy 21 * @copyright 2018 David Monllao 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 namespace tool_dataprivacy\output; 25 defined('MOODLE_INTERNAL') || die(); 26 27 use renderable; 28 use renderer_base; 29 use stdClass; 30 use templatable; 31 use tool_dataprivacy\data_registry; 32 33 require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/dataprivacy/lib.php'); 34 require_once($CFG->libdir . '/blocklib.php'); 35 36 /** 37 * Class containing the data registry renderable 38 * 39 * @copyright 2018 David Monllao 40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 */ 42 class data_registry_page implements renderable, templatable { 43 44 /** 45 * @var int 46 */ 47 private $defaultcontextlevel; 48 49 /** 50 * @var int 51 */ 52 private $defaultcontextid; 53 54 /** 55 * Constructor. 56 * 57 * @param int $defaultcontextlevel 58 * @param int $defaultcontextid 59 * @return null 60 */ 61 public function __construct($defaultcontextlevel = false, $defaultcontextid = false) { 62 $this->defaultcontextlevel = $defaultcontextlevel; 63 $this->defaultcontextid = $defaultcontextid; 64 } 65 66 /** 67 * Export this data so it can be used as the context for a mustache template. 68 * 69 * @param renderer_base $output 70 * @return stdClass 71 */ 72 public function export_for_template(renderer_base $output) { 73 global $PAGE; 74 75 $params = [\context_system::instance()->id, $this->defaultcontextlevel, $this->defaultcontextid]; 76 $PAGE->requires->js_call_amd('tool_dataprivacy/data_registry', 'init', $params); 77 78 $data = new stdClass(); 79 $defaultsbutton = new \action_link( 80 new \moodle_url('/admin/tool/dataprivacy/defaults.php'), 81 get_string('setdefaults', 'tool_dataprivacy'), 82 null, 83 ['class' => 'btn btn-primary'] 84 ); 85 $data->defaultsbutton = $defaultsbutton->export_for_template($output); 86 87 $actionmenu = new \action_menu(); 88 $actionmenu->set_menu_trigger(get_string('edit'), 'btn btn-primary'); 89 $actionmenu->set_owner_selector('dataregistry-actions'); 90 91 $url = new \moodle_url('/admin/tool/dataprivacy/categories.php'); 92 $categories = new \action_menu_link_secondary($url, null, get_string('categories', 'tool_dataprivacy')); 93 $actionmenu->add($categories); 94 95 $url = new \moodle_url('/admin/tool/dataprivacy/purposes.php'); 96 $purposes = new \action_menu_link_secondary($url, null, get_string('purposes', 'tool_dataprivacy')); 97 $actionmenu->add($purposes); 98 99 $data->actions = $actionmenu->export_for_template($output); 100 101 if (!data_registry::defaults_set()) { 102 $data->info = (object)[ 103 'message' => get_string('dataregistryinfo', 'tool_dataprivacy'), 104 'announce' => 1 105 ]; 106 $data->nosystemdefaults = (object)[ 107 'message' => get_string('nosystemdefaults', 'tool_dataprivacy'), 108 'announce' => 1 109 ]; 110 } 111 112 $data->tree = $this->get_default_tree_structure(); 113 114 return $data; 115 } 116 117 /** 118 * Returns the tree default structure. 119 * 120 * @return array 121 */ 122 private function get_default_tree_structure() { 123 124 $frontpage = \context_course::instance(SITEID); 125 126 $categorybranches = $this->get_all_category_branches(); 127 128 $elements = [ 129 'text' => get_string('contextlevelname' . CONTEXT_SYSTEM, 'tool_dataprivacy'), 130 'contextlevel' => CONTEXT_SYSTEM, 131 'branches' => [ 132 [ 133 'text' => get_string('user'), 134 'contextlevel' => CONTEXT_USER, 135 ], [ 136 'text' => get_string('categories'), 137 'branches' => $categorybranches, 138 'expandelement' => 'category', 139 ], [ 140 'text' => get_string('frontpagecourse', 'tool_dataprivacy'), 141 'contextid' => $frontpage->id, 142 'branches' => [ 143 [ 144 'text' => get_string('activitiesandresources', 'tool_dataprivacy'), 145 'expandcontextid' => $frontpage->id, 146 'expandelement' => 'module', 147 'expanded' => 0, 148 ], [ 149 'text' => get_string('blocks'), 150 'expandcontextid' => $frontpage->id, 151 'expandelement' => 'block', 152 'expanded' => 0, 153 ], 154 ] 155 ] 156 ] 157 ]; 158 159 // Returned as an array to follow a common array format. 160 return [self::complete($elements, $this->defaultcontextlevel, $this->defaultcontextid)]; 161 } 162 163 /** 164 * Returns the hierarchy of system course categories. 165 * 166 * @return array 167 */ 168 private function get_all_category_branches() { 169 170 $categories = data_registry::get_site_categories(); 171 172 $categoriesbranch = []; 173 while (count($categories) > 0) { 174 foreach ($categories as $key => $category) { 175 176 $context = \context_coursecat::instance($category->id); 177 $newnode = [ 178 'text' => shorten_text(format_string($category->name, true, ['context' => $context])), 179 'categoryid' => $category->id, 180 'contextid' => $context->id, 181 ]; 182 if ($category->coursecount > 0) { 183 $newnode['branches'] = [ 184 [ 185 'text' => get_string('courses'), 186 'expandcontextid' => $context->id, 187 'expandelement' => 'course', 188 'expanded' => 0, 189 ] 190 ]; 191 } 192 193 $added = false; 194 if ($category->parent == 0) { 195 // New categories root-level node. 196 $categoriesbranch[] = $newnode; 197 $added = true; 198 199 } else { 200 // Add the new node under the appropriate parent. 201 if ($this->add_to_parent_category_branch($category, $newnode, $categoriesbranch)) { 202 $added = true; 203 } 204 } 205 206 if ($added) { 207 unset($categories[$key]); 208 } 209 } 210 } 211 212 return $categoriesbranch; 213 } 214 215 /** 216 * Gets the courses branch for the provided category. 217 * 218 * @param \context $catcontext 219 * @return array 220 */ 221 public static function get_courses_branch(\context $catcontext) { 222 223 if ($catcontext->contextlevel !== CONTEXT_COURSECAT) { 224 throw new \coding_exception('A course category context should be provided'); 225 } 226 227 $coursecat = \core_course_category::get($catcontext->instanceid); 228 $courses = $coursecat->get_courses(); 229 230 $branches = []; 231 232 foreach ($courses as $course) { 233 234 $coursecontext = \context_course::instance($course->id); 235 236 $coursenode = [ 237 'text' => shorten_text(format_string($course->shortname, true, ['context' => $coursecontext])), 238 'contextid' => $coursecontext->id, 239 'branches' => [ 240 [ 241 'text' => get_string('activitiesandresources', 'tool_dataprivacy'), 242 'expandcontextid' => $coursecontext->id, 243 'expandelement' => 'module', 244 'expanded' => 0, 245 ], [ 246 'text' => get_string('blocks'), 247 'expandcontextid' => $coursecontext->id, 248 'expandelement' => 'block', 249 'expanded' => 0, 250 ], 251 ] 252 ]; 253 $branches[] = self::complete($coursenode); 254 } 255 256 return $branches; 257 } 258 259 /** 260 * Gets the modules branch for the provided course. 261 * 262 * @param \context $coursecontext 263 * @return array 264 */ 265 public static function get_modules_branch(\context $coursecontext) { 266 267 if ($coursecontext->contextlevel !== CONTEXT_COURSE) { 268 throw new \coding_exception('A course context should be provided'); 269 } 270 271 $branches = []; 272 273 // Using the current user. 274 $modinfo = get_fast_modinfo($coursecontext->instanceid); 275 foreach ($modinfo->get_instances() as $moduletype => $instances) { 276 foreach ($instances as $cm) { 277 278 if (!$cm->uservisible) { 279 continue; 280 } 281 282 $a = (object)[ 283 'instancename' => shorten_text($cm->get_formatted_name()), 284 'modulename' => get_string('pluginname', 'mod_' . $moduletype), 285 ]; 286 287 $text = get_string('moduleinstancename', 'tool_dataprivacy', $a); 288 $branches[] = self::complete([ 289 'text' => $text, 290 'contextid' => $cm->context->id, 291 ]); 292 } 293 } 294 295 return $branches; 296 } 297 298 /** 299 * Gets the blocks branch for the provided course. 300 * 301 * @param \context $coursecontext 302 * @return null 303 */ 304 public static function get_blocks_branch(\context $coursecontext) { 305 global $DB; 306 307 if ($coursecontext->contextlevel !== CONTEXT_COURSE) { 308 throw new \coding_exception('A course context should be provided'); 309 } 310 311 $branches = []; 312 313 $children = $coursecontext->get_child_contexts(); 314 foreach ($children as $childcontext) { 315 316 if ($childcontext->contextlevel !== CONTEXT_BLOCK) { 317 continue; 318 } 319 320 $blockinstance = block_instance_by_id($childcontext->instanceid); 321 $displayname = shorten_text(format_string($blockinstance->get_title(), true, ['context' => $childcontext])); 322 $branches[] = self::complete([ 323 'text' => $displayname, 324 'contextid' => $childcontext->id, 325 ]); 326 327 } 328 329 return $branches; 330 } 331 332 /** 333 * Adds the provided category to the categories branch. 334 * 335 * @param stdClass $category 336 * @param array $newnode 337 * @param array $categoriesbranch 338 * @return bool 339 */ 340 private function add_to_parent_category_branch($category, $newnode, &$categoriesbranch) { 341 342 foreach ($categoriesbranch as $key => $branch) { 343 if (!empty($branch['categoryid']) && $branch['categoryid'] == $category->parent) { 344 // It may be empty (if it does not contain courses and this is the first child cat). 345 if (!isset($categoriesbranch[$key]['branches'])) { 346 $categoriesbranch[$key]['branches'] = []; 347 } 348 $categoriesbranch[$key]['branches'][] = $newnode; 349 return true; 350 } 351 if (!empty($branch['branches'])) { 352 $parent = $this->add_to_parent_category_branch($category, $newnode, $categoriesbranch[$key]['branches']); 353 if ($parent) { 354 return true; 355 } 356 } 357 } 358 359 return false; 360 } 361 362 /** 363 * Completes tree nodes with default values. 364 * 365 * @param array $node 366 * @param int|false $currentcontextlevel 367 * @param int|false $currentcontextid 368 * @return array 369 */ 370 private static function complete($node, $currentcontextlevel = false, $currentcontextid = false) { 371 if (!isset($node['active'])) { 372 if ($currentcontextlevel && !empty($node['contextlevel']) && 373 $currentcontextlevel == $node['contextlevel'] && 374 empty($currentcontextid)) { 375 // This is the active context level, we also checked that there 376 // is no default contextid set. 377 $node['active'] = true; 378 } else if ($currentcontextid && !empty($node['contextid']) && 379 $currentcontextid == $node['contextid']) { 380 $node['active'] = true; 381 } else { 382 $node['active'] = null; 383 } 384 } 385 386 if (!isset($node['branches'])) { 387 $node['branches'] = []; 388 } else { 389 foreach ($node['branches'] as $key => $childnode) { 390 $node['branches'][$key] = self::complete($childnode, $currentcontextlevel, $currentcontextid); 391 } 392 } 393 394 if (!isset($node['expandelement'])) { 395 $node['expandelement'] = null; 396 } 397 398 if (!isset($node['expandcontextid'])) { 399 $node['expandcontextid'] = null; 400 } 401 402 if (!isset($node['contextid'])) { 403 $node['contextid'] = null; 404 } 405 406 if (!isset($node['contextlevel'])) { 407 $node['contextlevel'] = null; 408 } 409 410 if (!isset($node['expanded'])) { 411 if (!empty($node['branches'])) { 412 $node['expanded'] = 1; 413 } else { 414 $node['expanded'] = 0; 415 } 416 } 417 return $node; 418 } 419 420 /** 421 * From a list of purpose persistents to a list of id => name purposes. 422 * 423 * @param \tool_dataprivacy\purpose[] $purposes 424 * @param bool $includenotset 425 * @param bool $includeinherit 426 * @return string[] 427 */ 428 public static function purpose_options($purposes, $includenotset = true, $includeinherit = true) { 429 $options = self::base_options($includenotset, $includeinherit); 430 foreach ($purposes as $purpose) { 431 $options[$purpose->get('id')] = $purpose->get('name'); 432 } 433 434 return $options; 435 } 436 437 /** 438 * From a list of category persistents to a list of id => name categories. 439 * 440 * @param \tool_dataprivacy\category[] $categories 441 * @param bool $includenotset 442 * @param bool $includeinherit 443 * @return string[] 444 */ 445 public static function category_options($categories, $includenotset = true, $includeinherit = true) { 446 $options = self::base_options($includenotset, $includeinherit); 447 foreach ($categories as $category) { 448 $options[$category->get('id')] = $category->get('name'); 449 } 450 451 return $options; 452 } 453 454 /** 455 * Base not set and inherit options. 456 * 457 * @param bool $includenotset 458 * @param bool $includeinherit 459 * @return array 460 */ 461 private static function base_options($includenotset = true, $includeinherit = true) { 462 463 $options = []; 464 465 if ($includenotset) { 466 $options[\tool_dataprivacy\context_instance::NOTSET] = get_string('notset', 'tool_dataprivacy'); 467 } 468 469 if ($includeinherit) { 470 $options[\tool_dataprivacy\context_instance::INHERIT] = get_string('inherit', 'tool_dataprivacy'); 471 } 472 473 return $options; 474 } 475 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body