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