See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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 * Class containing the external API functions functions for the Data Privacy tool. 18 * 19 * @package tool_dataprivacy 20 * @copyright 2018 Jun Pataleta 21 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 */ 23 namespace tool_dataprivacy; 24 defined('MOODLE_INTERNAL') || die(); 25 26 require_once("$CFG->libdir/externallib.php"); 27 require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/dataprivacy/lib.php'); 28 29 use coding_exception; 30 use context_helper; 31 use context_system; 32 use context_user; 33 use core\invalid_persistent_exception; 34 use core\notification; 35 use core_user; 36 use dml_exception; 37 use external_api; 38 use external_description; 39 use external_function_parameters; 40 use external_multiple_structure; 41 use external_single_structure; 42 use external_value; 43 use external_warnings; 44 use invalid_parameter_exception; 45 use moodle_exception; 46 use required_capability_exception; 47 use restricted_context_exception; 48 use tool_dataprivacy\external\category_exporter; 49 use tool_dataprivacy\external\data_request_exporter; 50 use tool_dataprivacy\external\purpose_exporter; 51 use tool_dataprivacy\output\data_registry_page; 52 53 /** 54 * Class external. 55 * 56 * The external API for the Data Privacy tool. 57 * 58 * @copyright 2017 Jun Pataleta 59 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 60 */ 61 class external extends external_api { 62 63 /** 64 * Parameter description for cancel_data_request(). 65 * 66 * @since Moodle 3.5 67 * @return external_function_parameters 68 */ 69 public static function cancel_data_request_parameters() { 70 return new external_function_parameters([ 71 'requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED) 72 ]); 73 } 74 75 /** 76 * Cancel a data request. 77 * 78 * @since Moodle 3.5 79 * @param int $requestid The request ID. 80 * @return array 81 * @throws invalid_persistent_exception 82 * @throws coding_exception 83 * @throws invalid_parameter_exception 84 * @throws restricted_context_exception 85 */ 86 public static function cancel_data_request($requestid) { 87 global $USER; 88 89 $warnings = []; 90 $params = external_api::validate_parameters(self::cancel_data_request_parameters(), [ 91 'requestid' => $requestid 92 ]); 93 $requestid = $params['requestid']; 94 95 // Validate context and access to manage the registry. 96 $context = context_user::instance($USER->id); 97 self::validate_context($context); 98 99 // Ensure the request exists. 100 $select = 'id = :id AND (userid = :userid OR requestedby = :requestedby)'; 101 $params = ['id' => $requestid, 'userid' => $USER->id, 'requestedby' => $USER->id]; 102 $requests = data_request::get_records_select($select, $params); 103 $requestexists = count($requests) === 1; 104 105 $result = false; 106 if ($requestexists) { 107 $request = reset($requests); 108 $datasubject = $request->get('userid'); 109 110 if ($datasubject !== $USER->id) { 111 // The user is not the subject. Check that they can cancel this request. 112 if (!api::can_create_data_request_for_user($datasubject)) { 113 $forusercontext = \context_user::instance($datasubject); 114 throw new required_capability_exception($forusercontext, 115 'tool/dataprivacy:makedatarequestsforchildren', 'nopermissions', ''); 116 } 117 } 118 119 // TODO: Do we want a request to be non-cancellable past a certain point? E.g. When it's already approved/processing. 120 $result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_CANCELLED); 121 } else { 122 $warnings[] = [ 123 'item' => $requestid, 124 'warningcode' => 'errorrequestnotfound', 125 'message' => get_string('errorrequestnotfound', 'tool_dataprivacy') 126 ]; 127 } 128 129 return [ 130 'result' => $result, 131 'warnings' => $warnings 132 ]; 133 } 134 135 /** 136 * Parameter description for cancel_data_request(). 137 * 138 * @since Moodle 3.5 139 * @return external_description 140 */ 141 public static function cancel_data_request_returns() { 142 return new external_single_structure([ 143 'result' => new external_value(PARAM_BOOL, 'The processing result'), 144 'warnings' => new external_warnings() 145 ]); 146 } 147 148 /** 149 * Parameter description for contact_dpo(). 150 * 151 * @since Moodle 3.5 152 * @return external_function_parameters 153 */ 154 public static function contact_dpo_parameters() { 155 return new external_function_parameters([ 156 'message' => new external_value(PARAM_TEXT, 'The user\'s message to the Data Protection Officer(s)', VALUE_REQUIRED) 157 ]); 158 } 159 160 /** 161 * Make a general enquiry to a DPO. 162 * 163 * @since Moodle 3.5 164 * @param string $message The message to be sent to the DPO. 165 * @return array 166 * @throws coding_exception 167 * @throws invalid_parameter_exception 168 * @throws invalid_persistent_exception 169 * @throws restricted_context_exception 170 * @throws dml_exception 171 * @throws moodle_exception 172 */ 173 public static function contact_dpo($message) { 174 global $USER; 175 176 $warnings = []; 177 $params = external_api::validate_parameters(self::contact_dpo_parameters(), [ 178 'message' => $message 179 ]); 180 $message = $params['message']; 181 182 // Validate context. 183 $userid = $USER->id; 184 $context = context_user::instance($userid); 185 self::validate_context($context); 186 187 // Lodge the request. 188 $datarequest = new data_request(); 189 // The user the request is being made for. 190 $datarequest->set('userid', $userid); 191 // The user making the request. 192 $datarequest->set('requestedby', $userid); 193 // Set status. 194 $datarequest->set('status', api::DATAREQUEST_STATUS_PENDING); 195 // Set request type. 196 $datarequest->set('type', api::DATAREQUEST_TYPE_OTHERS); 197 // Set request comments. 198 $datarequest->set('comments', $message); 199 200 // Store subject access request. 201 $datarequest->create(); 202 203 // Get the list of the site Data Protection Officers. 204 $dpos = api::get_site_dpos(); 205 206 // Email the data request to the Data Protection Officer(s)/Admin(s). 207 $result = true; 208 foreach ($dpos as $dpo) { 209 $sendresult = api::notify_dpo($dpo, $datarequest); 210 if (!$sendresult) { 211 $result = false; 212 $warnings[] = [ 213 'item' => $dpo->id, 214 'warningcode' => 'errorsendingtodpo', 215 'message' => get_string('errorsendingmessagetodpo', 'tool_dataprivacy') 216 ]; 217 } 218 } 219 220 return [ 221 'result' => $result, 222 'warnings' => $warnings 223 ]; 224 } 225 226 /** 227 * Parameter description for contact_dpo(). 228 * 229 * @since Moodle 3.5 230 * @return external_description 231 */ 232 public static function contact_dpo_returns() { 233 return new external_single_structure([ 234 'result' => new external_value(PARAM_BOOL, 'The processing result'), 235 'warnings' => new external_warnings() 236 ]); 237 } 238 239 /** 240 * Parameter description for mark_complete(). 241 * 242 * @since Moodle 3.5.2 243 * @return external_function_parameters 244 */ 245 public static function mark_complete_parameters() { 246 return new external_function_parameters([ 247 'requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED) 248 ]); 249 } 250 251 /** 252 * Mark a user's general enquiry's status as complete. 253 * 254 * @since Moodle 3.5.2 255 * @param int $requestid The request ID of the general enquiry. 256 * @return array 257 * @throws coding_exception 258 * @throws invalid_parameter_exception 259 * @throws invalid_persistent_exception 260 * @throws restricted_context_exception 261 * @throws dml_exception 262 * @throws moodle_exception 263 */ 264 public static function mark_complete($requestid) { 265 global $USER; 266 267 $warnings = []; 268 $params = external_api::validate_parameters(self::mark_complete_parameters(), [ 269 'requestid' => $requestid, 270 ]); 271 $requestid = $params['requestid']; 272 273 // Validate context and access to manage the registry. 274 $context = context_system::instance(); 275 self::validate_context($context); 276 api::check_can_manage_data_registry(); 277 278 $message = get_string('markedcomplete', 'tool_dataprivacy'); 279 // Update the data request record. 280 if ($result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_COMPLETE, $USER->id, $message)) { 281 // Add notification in the session to be shown when the page is reloaded on the JS side. 282 notification::success(get_string('requestmarkedcomplete', 'tool_dataprivacy')); 283 } 284 285 return [ 286 'result' => $result, 287 'warnings' => $warnings 288 ]; 289 } 290 291 /** 292 * Parameter description for mark_complete(). 293 * 294 * @since Moodle 3.5.2 295 * @return external_description 296 */ 297 public static function mark_complete_returns() { 298 return new external_single_structure([ 299 'result' => new external_value(PARAM_BOOL, 'The processing result'), 300 'warnings' => new external_warnings() 301 ]); 302 } 303 304 /** 305 * Parameter description for get_data_request(). 306 * 307 * @since Moodle 3.5 308 * @return external_function_parameters 309 */ 310 public static function get_data_request_parameters() { 311 return new external_function_parameters([ 312 'requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED) 313 ]); 314 } 315 316 /** 317 * Fetch the details of a user's data request. 318 * 319 * @since Moodle 3.5 320 * @param int $requestid The request ID. 321 * @return array 322 * @throws coding_exception 323 * @throws dml_exception 324 * @throws invalid_parameter_exception 325 * @throws restricted_context_exception 326 * @throws moodle_exception 327 */ 328 public static function get_data_request($requestid) { 329 global $PAGE; 330 331 $warnings = []; 332 $params = external_api::validate_parameters(self::get_data_request_parameters(), [ 333 'requestid' => $requestid 334 ]); 335 $requestid = $params['requestid']; 336 337 // Validate context. 338 $context = context_system::instance(); 339 self::validate_context($context); 340 $requestpersistent = new data_request($requestid); 341 require_capability('tool/dataprivacy:managedatarequests', $context); 342 343 $exporter = new data_request_exporter($requestpersistent, ['context' => $context]); 344 $renderer = $PAGE->get_renderer('tool_dataprivacy'); 345 $result = $exporter->export($renderer); 346 347 return [ 348 'result' => $result, 349 'warnings' => $warnings 350 ]; 351 } 352 353 /** 354 * Parameter description for get_data_request(). 355 * 356 * @since Moodle 3.5 357 * @return external_description 358 */ 359 public static function get_data_request_returns() { 360 return new external_single_structure([ 361 'result' => data_request_exporter::get_read_structure(), 362 'warnings' => new external_warnings() 363 ]); 364 } 365 366 /** 367 * Parameter description for approve_data_request(). 368 * 369 * @since Moodle 3.5 370 * @return external_function_parameters 371 */ 372 public static function approve_data_request_parameters() { 373 return new external_function_parameters([ 374 'requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED) 375 ]); 376 } 377 378 /** 379 * Approve a data request. 380 * 381 * @since Moodle 3.5 382 * @param int $requestid The request ID. 383 * @return array 384 * @throws coding_exception 385 * @throws dml_exception 386 * @throws invalid_parameter_exception 387 * @throws restricted_context_exception 388 * @throws moodle_exception 389 */ 390 public static function approve_data_request($requestid) { 391 $warnings = []; 392 $params = external_api::validate_parameters(self::approve_data_request_parameters(), [ 393 'requestid' => $requestid 394 ]); 395 $requestid = $params['requestid']; 396 397 // Validate context. 398 $context = context_system::instance(); 399 self::validate_context($context); 400 require_capability('tool/dataprivacy:managedatarequests', $context); 401 402 // Ensure the request exists. 403 $requestexists = data_request::record_exists($requestid); 404 405 $result = false; 406 if ($requestexists) { 407 $result = api::approve_data_request($requestid); 408 409 // Add notification in the session to be shown when the page is reloaded on the JS side. 410 notification::success(get_string('requestapproved', 'tool_dataprivacy')); 411 } else { 412 $warnings[] = [ 413 'item' => $requestid, 414 'warningcode' => 'errorrequestnotfound', 415 'message' => get_string('errorrequestnotfound', 'tool_dataprivacy') 416 ]; 417 } 418 419 return [ 420 'result' => $result, 421 'warnings' => $warnings 422 ]; 423 } 424 425 /** 426 * Parameter description for approve_data_request(). 427 * 428 * @since Moodle 3.5 429 * @return external_description 430 */ 431 public static function approve_data_request_returns() { 432 return new external_single_structure([ 433 'result' => new external_value(PARAM_BOOL, 'The processing result'), 434 'warnings' => new external_warnings() 435 ]); 436 } 437 438 /** 439 * Parameter description for bulk_approve_data_requests(). 440 * 441 * @since Moodle 3.5 442 * @return external_function_parameters 443 */ 444 public static function bulk_approve_data_requests_parameters() { 445 return new external_function_parameters([ 446 'requestids' => new external_multiple_structure( 447 new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED) 448 ) 449 ]); 450 } 451 452 /** 453 * Bulk approve bulk data request. 454 * 455 * @since Moodle 3.5 456 * @param array $requestids Array consisting the request ID's. 457 * @return array 458 * @throws coding_exception 459 * @throws dml_exception 460 * @throws invalid_parameter_exception 461 * @throws restricted_context_exception 462 * @throws moodle_exception 463 */ 464 public static function bulk_approve_data_requests($requestids) { 465 $warnings = []; 466 $result = false; 467 $params = external_api::validate_parameters(self::bulk_approve_data_requests_parameters(), [ 468 'requestids' => $requestids 469 ]); 470 $requestids = $params['requestids']; 471 472 // Validate context. 473 $context = context_system::instance(); 474 self::validate_context($context); 475 require_capability('tool/dataprivacy:managedatarequests', $context); 476 477 foreach ($requestids as $requestid) { 478 // Ensure the request exists. 479 $requestexists = data_request::record_exists($requestid); 480 481 if ($requestexists) { 482 api::approve_data_request($requestid); 483 } else { 484 $warnings[] = [ 485 'item' => $requestid, 486 'warningcode' => 'errorrequestnotfound', 487 'message' => get_string('errorrequestnotfound', 'tool_dataprivacy') 488 ]; 489 } 490 } 491 492 if (empty($warnings)) { 493 $result = true; 494 // Add notification in the session to be shown when the page is reloaded on the JS side. 495 notification::success(get_string('requestsapproved', 'tool_dataprivacy')); 496 } 497 498 return [ 499 'result' => $result, 500 'warnings' => $warnings 501 ]; 502 } 503 504 /** 505 * Parameter description for bulk_approve_data_requests(). 506 * 507 * @since Moodle 3.5 508 * @return external_description 509 */ 510 public static function bulk_approve_data_requests_returns() { 511 return new external_single_structure([ 512 'result' => new external_value(PARAM_BOOL, 'The processing result'), 513 'warnings' => new external_warnings() 514 ]); 515 } 516 517 /** 518 * Parameter description for deny_data_request(). 519 * 520 * @since Moodle 3.5 521 * @return external_function_parameters 522 */ 523 public static function deny_data_request_parameters() { 524 return new external_function_parameters([ 525 'requestid' => new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED) 526 ]); 527 } 528 529 /** 530 * Deny a data request. 531 * 532 * @since Moodle 3.5 533 * @param int $requestid The request ID. 534 * @return array 535 * @throws coding_exception 536 * @throws dml_exception 537 * @throws invalid_parameter_exception 538 * @throws restricted_context_exception 539 * @throws moodle_exception 540 */ 541 public static function deny_data_request($requestid) { 542 $warnings = []; 543 $params = external_api::validate_parameters(self::deny_data_request_parameters(), [ 544 'requestid' => $requestid 545 ]); 546 $requestid = $params['requestid']; 547 548 // Validate context. 549 $context = context_system::instance(); 550 self::validate_context($context); 551 require_capability('tool/dataprivacy:managedatarequests', $context); 552 553 // Ensure the request exists. 554 $requestexists = data_request::record_exists($requestid); 555 556 $result = false; 557 if ($requestexists) { 558 $result = api::deny_data_request($requestid); 559 560 // Add notification in the session to be shown when the page is reloaded on the JS side. 561 notification::success(get_string('requestdenied', 'tool_dataprivacy')); 562 } else { 563 $warnings[] = [ 564 'item' => $requestid, 565 'warningcode' => 'errorrequestnotfound', 566 'message' => get_string('errorrequestnotfound', 'tool_dataprivacy') 567 ]; 568 } 569 570 return [ 571 'result' => $result, 572 'warnings' => $warnings 573 ]; 574 } 575 576 /** 577 * Parameter description for deny_data_request(). 578 * 579 * @since Moodle 3.5 580 * @return external_description 581 */ 582 public static function deny_data_request_returns() { 583 return new external_single_structure([ 584 'result' => new external_value(PARAM_BOOL, 'The processing result'), 585 'warnings' => new external_warnings() 586 ]); 587 } 588 589 /** 590 * Parameter description for bulk_deny_data_requests(). 591 * 592 * @since Moodle 3.5 593 * @return external_function_parameters 594 */ 595 public static function bulk_deny_data_requests_parameters() { 596 return new external_function_parameters([ 597 'requestids' => new external_multiple_structure( 598 new external_value(PARAM_INT, 'The request ID', VALUE_REQUIRED) 599 ) 600 ]); 601 } 602 603 /** 604 * Bulk deny data requests. 605 * 606 * @since Moodle 3.5 607 * @param array $requestids Array consisting of request ID's. 608 * @return array 609 * @throws coding_exception 610 * @throws dml_exception 611 * @throws invalid_parameter_exception 612 * @throws restricted_context_exception 613 * @throws moodle_exception 614 */ 615 public static function bulk_deny_data_requests($requestids) { 616 $warnings = []; 617 $result = false; 618 $params = external_api::validate_parameters(self::bulk_deny_data_requests_parameters(), [ 619 'requestids' => $requestids 620 ]); 621 $requestids = $params['requestids']; 622 623 // Validate context. 624 $context = context_system::instance(); 625 self::validate_context($context); 626 require_capability('tool/dataprivacy:managedatarequests', $context); 627 628 foreach ($requestids as $requestid) { 629 // Ensure the request exists. 630 $requestexists = data_request::record_exists($requestid); 631 632 if ($requestexists) { 633 api::deny_data_request($requestid); 634 } else { 635 $warnings[] = [ 636 'item' => $requestid, 637 'warningcode' => 'errorrequestnotfound', 638 'message' => get_string('errorrequestnotfound', 'tool_dataprivacy') 639 ]; 640 } 641 } 642 643 if (empty($warnings)) { 644 $result = true; 645 // Add notification in the session to be shown when the page is reloaded on the JS side. 646 notification::success(get_string('requestsdenied', 'tool_dataprivacy')); 647 } 648 649 return [ 650 'result' => $result, 651 'warnings' => $warnings 652 ]; 653 } 654 655 /** 656 * Parameter description for bulk_deny_data_requests(). 657 * 658 * @since Moodle 3.5 659 * @return external_description 660 */ 661 public static function bulk_deny_data_requests_returns() { 662 return new external_single_structure([ 663 'result' => new external_value(PARAM_BOOL, 'The processing result'), 664 'warnings' => new external_warnings() 665 ]); 666 } 667 668 /** 669 * Parameter description for get_data_request(). 670 * 671 * @since Moodle 3.5 672 * @return external_function_parameters 673 */ 674 public static function get_users_parameters() { 675 return new external_function_parameters([ 676 'query' => new external_value(PARAM_TEXT, 'The search query', VALUE_REQUIRED) 677 ]); 678 } 679 680 /** 681 * Fetch the details of a user's data request. 682 * 683 * @since Moodle 3.5 684 * @param string $query The search request. 685 * @return array 686 * @throws required_capability_exception 687 * @throws dml_exception 688 * @throws invalid_parameter_exception 689 * @throws restricted_context_exception 690 */ 691 public static function get_users($query) { 692 global $DB; 693 $params = external_api::validate_parameters(self::get_users_parameters(), [ 694 'query' => $query 695 ]); 696 $query = $params['query']; 697 698 // Validate context. 699 $context = context_system::instance(); 700 self::validate_context($context); 701 require_capability('tool/dataprivacy:managedatarequests', $context); 702 703 $allusernames = get_all_user_name_fields(true); 704 // Exclude admins and guest user. 705 $excludedusers = array_keys(get_admins()) + [guest_user()->id]; 706 $sort = 'lastname ASC, firstname ASC'; 707 $fields = 'id,' . $allusernames; 708 709 $extrafields = get_extra_user_fields($context); 710 if (!empty($extrafields)) { 711 $fields .= ',' . implode(',', $extrafields); 712 } 713 714 list($sql, $params) = users_search_sql($query, '', false, $extrafields, $excludedusers); 715 $users = $DB->get_records_select('user', $sql, $params, $sort, $fields, 0, 30); 716 $useroptions = []; 717 foreach ($users as $user) { 718 $useroption = (object)[ 719 'id' => $user->id, 720 'fullname' => fullname($user) 721 ]; 722 $useroption->extrafields = []; 723 foreach ($extrafields as $extrafield) { 724 // Sanitize the extra fields to prevent potential XSS exploit. 725 $useroption->extrafields[] = (object)[ 726 'name' => $extrafield, 727 'value' => s($user->$extrafield) 728 ]; 729 } 730 $useroptions[$user->id] = $useroption; 731 } 732 733 return $useroptions; 734 } 735 736 /** 737 * Parameter description for get_users(). 738 * 739 * @since Moodle 3.5 740 * @return external_description 741 * @throws coding_exception 742 */ 743 public static function get_users_returns() { 744 return new external_multiple_structure(new external_single_structure( 745 [ 746 'id' => new external_value(core_user::get_property_type('id'), 'ID of the user'), 747 'fullname' => new external_value(core_user::get_property_type('firstname'), 'The fullname of the user'), 748 'extrafields' => new external_multiple_structure( 749 new external_single_structure([ 750 'name' => new external_value(PARAM_TEXT, 'Name of the extrafield.'), 751 'value' => new external_value(PARAM_TEXT, 'Value of the extrafield.') 752 ] 753 ), 'List of extra fields', VALUE_OPTIONAL 754 ) 755 ] 756 )); 757 } 758 759 /** 760 * Parameter description for create_purpose_form(). 761 * 762 * @since Moodle 3.5 763 * @return external_function_parameters 764 */ 765 public static function create_purpose_form_parameters() { 766 return new external_function_parameters([ 767 'jsonformdata' => new external_value(PARAM_RAW, 'The data to create the purpose, encoded as a json array') 768 ]); 769 } 770 771 /** 772 * Creates a data purpose from form data. 773 * 774 * @since Moodle 3.5 775 * @param string $jsonformdata 776 * @return array 777 */ 778 public static function create_purpose_form($jsonformdata) { 779 global $PAGE; 780 781 $warnings = []; 782 783 $params = external_api::validate_parameters(self::create_purpose_form_parameters(), [ 784 'jsonformdata' => $jsonformdata 785 ]); 786 787 // Validate context and access to manage the registry. 788 self::validate_context(\context_system::instance()); 789 api::check_can_manage_data_registry(); 790 791 $serialiseddata = json_decode($params['jsonformdata']); 792 $data = array(); 793 parse_str($serialiseddata, $data); 794 795 $purpose = new \tool_dataprivacy\purpose(0); 796 $mform = new \tool_dataprivacy\form\purpose(null, ['persistent' => $purpose], 'post', '', null, true, $data); 797 798 $validationerrors = true; 799 if ($validateddata = $mform->get_data()) { 800 $purpose = api::create_purpose($validateddata); 801 $validationerrors = false; 802 } else if ($errors = $mform->is_validated()) { 803 throw new moodle_exception('generalerror'); 804 } 805 806 $exporter = new purpose_exporter($purpose, ['context' => \context_system::instance()]); 807 return [ 808 'purpose' => $exporter->export($PAGE->get_renderer('core')), 809 'validationerrors' => $validationerrors, 810 'warnings' => $warnings 811 ]; 812 } 813 814 /** 815 * Returns for create_purpose_form(). 816 * 817 * @since Moodle 3.5 818 * @return external_single_structure 819 */ 820 public static function create_purpose_form_returns() { 821 return new external_single_structure([ 822 'purpose' => purpose_exporter::get_read_structure(), 823 'validationerrors' => new external_value(PARAM_BOOL, 'Were there validation errors', VALUE_REQUIRED), 824 'warnings' => new external_warnings() 825 ]); 826 } 827 828 /** 829 * Parameter description for delete_purpose(). 830 * 831 * @since Moodle 3.5 832 * @return external_function_parameters 833 */ 834 public static function delete_purpose_parameters() { 835 return new external_function_parameters([ 836 'id' => new external_value(PARAM_INT, 'The purpose ID', VALUE_REQUIRED) 837 ]); 838 } 839 840 /** 841 * Deletes a data purpose. 842 * 843 * @since Moodle 3.5 844 * @param int $id The ID. 845 * @return array 846 * @throws invalid_persistent_exception 847 * @throws coding_exception 848 * @throws invalid_parameter_exception 849 */ 850 public static function delete_purpose($id) { 851 global $USER; 852 853 $params = external_api::validate_parameters(self::delete_purpose_parameters(), [ 854 'id' => $id 855 ]); 856 857 // Validate context and access to manage the registry. 858 self::validate_context(\context_system::instance()); 859 api::check_can_manage_data_registry(); 860 861 $result = api::delete_purpose($params['id']); 862 863 return [ 864 'result' => $result, 865 'warnings' => [] 866 ]; 867 } 868 869 /** 870 * Parameter description for delete_purpose(). 871 * 872 * @since Moodle 3.5 873 * @return external_single_structure 874 */ 875 public static function delete_purpose_returns() { 876 return new external_single_structure([ 877 'result' => new external_value(PARAM_BOOL, 'The processing result'), 878 'warnings' => new external_warnings() 879 ]); 880 } 881 882 /** 883 * Parameter description for create_category_form(). 884 * 885 * @since Moodle 3.5 886 * @return external_function_parameters 887 */ 888 public static function create_category_form_parameters() { 889 return new external_function_parameters([ 890 'jsonformdata' => new external_value(PARAM_RAW, 'The data to create the category, encoded as a json array') 891 ]); 892 } 893 894 /** 895 * Creates a data category from form data. 896 * 897 * @since Moodle 3.5 898 * @param string $jsonformdata 899 * @return array 900 */ 901 public static function create_category_form($jsonformdata) { 902 global $PAGE; 903 904 $warnings = []; 905 906 $params = external_api::validate_parameters(self::create_category_form_parameters(), [ 907 'jsonformdata' => $jsonformdata 908 ]); 909 910 // Validate context and access to manage the registry. 911 self::validate_context(\context_system::instance()); 912 api::check_can_manage_data_registry(); 913 914 $serialiseddata = json_decode($params['jsonformdata']); 915 $data = array(); 916 parse_str($serialiseddata, $data); 917 918 $category = new \tool_dataprivacy\category(0); 919 $mform = new \tool_dataprivacy\form\category(null, ['persistent' => $category], 'post', '', null, true, $data); 920 921 $validationerrors = true; 922 if ($validateddata = $mform->get_data()) { 923 $category = api::create_category($validateddata); 924 $validationerrors = false; 925 } else if ($errors = $mform->is_validated()) { 926 throw new moodle_exception('generalerror'); 927 } 928 929 $exporter = new category_exporter($category, ['context' => \context_system::instance()]); 930 return [ 931 'category' => $exporter->export($PAGE->get_renderer('core')), 932 'validationerrors' => $validationerrors, 933 'warnings' => $warnings 934 ]; 935 } 936 937 /** 938 * Returns for create_category_form(). 939 * 940 * @since Moodle 3.5 941 * @return external_single_structure 942 */ 943 public static function create_category_form_returns() { 944 return new external_single_structure([ 945 'category' => category_exporter::get_read_structure(), 946 'validationerrors' => new external_value(PARAM_BOOL, 'Were there validation errors', VALUE_REQUIRED), 947 'warnings' => new external_warnings() 948 ]); 949 } 950 951 /** 952 * Parameter description for delete_category(). 953 * 954 * @since Moodle 3.5 955 * @return external_function_parameters 956 */ 957 public static function delete_category_parameters() { 958 return new external_function_parameters([ 959 'id' => new external_value(PARAM_INT, 'The category ID', VALUE_REQUIRED) 960 ]); 961 } 962 963 /** 964 * Deletes a data category. 965 * 966 * @since Moodle 3.5 967 * @param int $id The ID. 968 * @return array 969 * @throws invalid_persistent_exception 970 * @throws coding_exception 971 * @throws invalid_parameter_exception 972 */ 973 public static function delete_category($id) { 974 global $USER; 975 976 $params = external_api::validate_parameters(self::delete_category_parameters(), [ 977 'id' => $id 978 ]); 979 980 // Validate context and access to manage the registry. 981 self::validate_context(\context_system::instance()); 982 api::check_can_manage_data_registry(); 983 984 $result = api::delete_category($params['id']); 985 986 return [ 987 'result' => $result, 988 'warnings' => [] 989 ]; 990 } 991 992 /** 993 * Parameter description for delete_category(). 994 * 995 * @since Moodle 3.5 996 * @return external_single_structure 997 */ 998 public static function delete_category_returns() { 999 return new external_single_structure([ 1000 'result' => new external_value(PARAM_BOOL, 'The processing result'), 1001 'warnings' => new external_warnings() 1002 ]); 1003 } 1004 1005 /** 1006 * Parameter description for set_contextlevel_form(). 1007 * 1008 * @since Moodle 3.5 1009 * @return external_function_parameters 1010 */ 1011 public static function set_contextlevel_form_parameters() { 1012 return new external_function_parameters([ 1013 'jsonformdata' => new external_value(PARAM_RAW, 'The context level data, encoded as a json array') 1014 ]); 1015 } 1016 1017 /** 1018 * Creates a data category from form data. 1019 * 1020 * @since Moodle 3.5 1021 * @param string $jsonformdata 1022 * @return array 1023 */ 1024 public static function set_contextlevel_form($jsonformdata) { 1025 global $PAGE; 1026 1027 $warnings = []; 1028 1029 $params = external_api::validate_parameters(self::set_contextlevel_form_parameters(), [ 1030 'jsonformdata' => $jsonformdata 1031 ]); 1032 1033 // Validate context and access to manage the registry. 1034 self::validate_context(\context_system::instance()); 1035 api::check_can_manage_data_registry(); 1036 1037 $serialiseddata = json_decode($params['jsonformdata']); 1038 $data = array(); 1039 parse_str($serialiseddata, $data); 1040 1041 $contextlevel = $data['contextlevel']; 1042 1043 $customdata = \tool_dataprivacy\form\contextlevel::get_contextlevel_customdata($contextlevel); 1044 $mform = new \tool_dataprivacy\form\contextlevel(null, $customdata, 'post', '', null, true, $data); 1045 if ($validateddata = $mform->get_data()) { 1046 $contextlevel = api::set_contextlevel($validateddata); 1047 } else if ($errors = $mform->is_validated()) { 1048 $warnings[] = json_encode($errors); 1049 } 1050 1051 if ($contextlevel) { 1052 $result = true; 1053 } else { 1054 $result = false; 1055 } 1056 return [ 1057 'result' => $result, 1058 'warnings' => $warnings 1059 ]; 1060 } 1061 1062 /** 1063 * Returns for set_contextlevel_form(). 1064 * 1065 * @since Moodle 3.5 1066 * @return external_single_structure 1067 */ 1068 public static function set_contextlevel_form_returns() { 1069 return new external_single_structure([ 1070 'result' => new external_value(PARAM_BOOL, 'Whether the data was properly set or not'), 1071 'warnings' => new external_warnings() 1072 ]); 1073 } 1074 1075 /** 1076 * Parameter description for set_context_form(). 1077 * 1078 * @since Moodle 3.5 1079 * @return external_function_parameters 1080 */ 1081 public static function set_context_form_parameters() { 1082 return new external_function_parameters([ 1083 'jsonformdata' => new external_value(PARAM_RAW, 'The context level data, encoded as a json array') 1084 ]); 1085 } 1086 1087 /** 1088 * Creates a data category from form data. 1089 * 1090 * @since Moodle 3.5 1091 * @param string $jsonformdata 1092 * @return array 1093 */ 1094 public static function set_context_form($jsonformdata) { 1095 global $PAGE; 1096 1097 $warnings = []; 1098 1099 $params = external_api::validate_parameters(self::set_context_form_parameters(), [ 1100 'jsonformdata' => $jsonformdata 1101 ]); 1102 1103 // Validate context and access to manage the registry. 1104 self::validate_context(\context_system::instance()); 1105 api::check_can_manage_data_registry(); 1106 1107 $serialiseddata = json_decode($params['jsonformdata']); 1108 $data = array(); 1109 parse_str($serialiseddata, $data); 1110 1111 $context = context_helper::instance_by_id($data['contextid']); 1112 $customdata = \tool_dataprivacy\form\context_instance::get_context_instance_customdata($context); 1113 $mform = new \tool_dataprivacy\form\context_instance(null, $customdata, 'post', '', null, true, $data); 1114 if ($validateddata = $mform->get_data()) { 1115 api::check_can_manage_data_registry($validateddata->contextid); 1116 $context = api::set_context_instance($validateddata); 1117 } else if ($errors = $mform->is_validated()) { 1118 $warnings[] = json_encode($errors); 1119 throw new moodle_exception('generalerror'); 1120 } 1121 1122 if ($context) { 1123 $result = true; 1124 } else { 1125 $result = false; 1126 } 1127 return [ 1128 'result' => $result, 1129 'warnings' => $warnings 1130 ]; 1131 } 1132 1133 /** 1134 * Returns for set_context_form(). 1135 * 1136 * @since Moodle 3.5 1137 * @return external_single_structure 1138 */ 1139 public static function set_context_form_returns() { 1140 return new external_single_structure([ 1141 'result' => new external_value(PARAM_BOOL, 'Whether the data was properly set or not'), 1142 'warnings' => new external_warnings() 1143 ]); 1144 } 1145 1146 /** 1147 * Parameter description for tree_extra_branches(). 1148 * 1149 * @since Moodle 3.5 1150 * @return external_function_parameters 1151 */ 1152 public static function tree_extra_branches_parameters() { 1153 return new external_function_parameters([ 1154 'contextid' => new external_value(PARAM_INT, 'The context id to expand'), 1155 'element' => new external_value(PARAM_ALPHA, 'The element we are interested on') 1156 ]); 1157 } 1158 1159 /** 1160 * Returns tree extra branches. 1161 * 1162 * @since Moodle 3.5 1163 * @param int $contextid 1164 * @param string $element 1165 * @return array 1166 */ 1167 public static function tree_extra_branches($contextid, $element) { 1168 1169 $params = external_api::validate_parameters(self::tree_extra_branches_parameters(), [ 1170 'contextid' => $contextid, 1171 'element' => $element, 1172 ]); 1173 1174 $context = context_helper::instance_by_id($params['contextid']); 1175 1176 self::validate_context($context); 1177 api::check_can_manage_data_registry($context->id); 1178 1179 switch ($params['element']) { 1180 case 'course': 1181 $branches = data_registry_page::get_courses_branch($context); 1182 break; 1183 case 'module': 1184 $branches = data_registry_page::get_modules_branch($context); 1185 break; 1186 case 'block': 1187 $branches = data_registry_page::get_blocks_branch($context); 1188 break; 1189 default: 1190 throw new \moodle_exception('Unsupported element provided.'); 1191 } 1192 1193 return [ 1194 'branches' => $branches, 1195 'warnings' => [], 1196 ]; 1197 } 1198 1199 /** 1200 * Returns for tree_extra_branches(). 1201 * 1202 * @since Moodle 3.5 1203 * @return external_single_structure 1204 */ 1205 public static function tree_extra_branches_returns() { 1206 return new external_single_structure([ 1207 'branches' => new external_multiple_structure(self::get_tree_node_structure(true)), 1208 'warnings' => new external_warnings() 1209 ]); 1210 } 1211 1212 /** 1213 * Parameters for confirm_contexts_for_deletion(). 1214 * 1215 * @since Moodle 3.5 1216 * @return external_function_parameters 1217 */ 1218 public static function confirm_contexts_for_deletion_parameters() { 1219 return new external_function_parameters([ 1220 'ids' => new external_multiple_structure( 1221 new external_value(PARAM_INT, 'Expired context record ID', VALUE_REQUIRED), 1222 'Array of expired context record IDs', VALUE_DEFAULT, [] 1223 ), 1224 ]); 1225 } 1226 1227 /** 1228 * Confirm a given array of expired context record IDs 1229 * 1230 * @since Moodle 3.5 1231 * @param int[] $ids Array of record IDs from the expired contexts table. 1232 * @return array 1233 * @throws coding_exception 1234 * @throws dml_exception 1235 * @throws invalid_parameter_exception 1236 * @throws restricted_context_exception 1237 */ 1238 public static function confirm_contexts_for_deletion($ids) { 1239 $warnings = []; 1240 $params = external_api::validate_parameters(self::confirm_contexts_for_deletion_parameters(), [ 1241 'ids' => $ids 1242 ]); 1243 $ids = $params['ids']; 1244 1245 // Validate context and access to manage the registry. 1246 self::validate_context(\context_system::instance()); 1247 api::check_can_manage_data_registry(); 1248 1249 $result = true; 1250 if (!empty($ids)) { 1251 $expiredcontextstoapprove = []; 1252 // Loop through the deletion of expired contexts and their children if necessary. 1253 foreach ($ids as $id) { 1254 $expiredcontext = new expired_context($id); 1255 $targetcontext = context_helper::instance_by_id($expiredcontext->get('contextid')); 1256 1257 if (!$targetcontext instanceof \context_user) { 1258 // Fetch this context's child contexts. Make sure that all of the child contexts are flagged for deletion. 1259 // User context children do not need to be considered. 1260 $childcontexts = $targetcontext->get_child_contexts(); 1261 foreach ($childcontexts as $child) { 1262 if ($expiredchildcontext = expired_context::get_record(['contextid' => $child->id])) { 1263 // Add this child context to the list for approval. 1264 $expiredcontextstoapprove[] = $expiredchildcontext; 1265 } else { 1266 // This context has not yet been flagged for deletion. 1267 $result = false; 1268 $message = get_string('errorcontexthasunexpiredchildren', 'tool_dataprivacy', 1269 $targetcontext->get_context_name(false)); 1270 $warnings[] = [ 1271 'item' => 'tool_dataprivacy_ctxexpired', 1272 'warningcode' => 'errorcontexthasunexpiredchildren', 1273 'message' => $message 1274 ]; 1275 // Exit the process. 1276 break 2; 1277 } 1278 } 1279 } 1280 1281 $expiredcontextstoapprove[] = $expiredcontext; 1282 } 1283 1284 // Proceed with the approval if everything's in order. 1285 if ($result) { 1286 // Mark expired contexts as approved for deletion. 1287 foreach ($expiredcontextstoapprove as $expired) { 1288 // Only mark expired contexts that are pending approval. 1289 if ($expired->get('status') == expired_context::STATUS_EXPIRED) { 1290 api::set_expired_context_status($expired, expired_context::STATUS_APPROVED); 1291 } 1292 } 1293 } 1294 1295 } else { 1296 // We don't have anything to process. 1297 $result = false; 1298 $warnings[] = [ 1299 'item' => 'tool_dataprivacy_ctxexpired', 1300 'warningcode' => 'errornoexpiredcontexts', 1301 'message' => get_string('errornoexpiredcontexts', 'tool_dataprivacy') 1302 ]; 1303 } 1304 1305 return [ 1306 'result' => $result, 1307 'warnings' => $warnings 1308 ]; 1309 } 1310 1311 /** 1312 * Returns for confirm_contexts_for_deletion(). 1313 * 1314 * @since Moodle 3.5 1315 * @return external_single_structure 1316 */ 1317 public static function confirm_contexts_for_deletion_returns() { 1318 return new external_single_structure([ 1319 'result' => new external_value(PARAM_BOOL, 'Whether the record was properly marked for deletion or not'), 1320 'warnings' => new external_warnings() 1321 ]); 1322 } 1323 1324 /** 1325 * Parameters for set_context_defaults(). 1326 * 1327 * @return external_function_parameters 1328 */ 1329 public static function set_context_defaults_parameters() { 1330 return new external_function_parameters([ 1331 'contextlevel' => new external_value(PARAM_INT, 'The context level', VALUE_REQUIRED), 1332 'category' => new external_value(PARAM_INT, 'The default category for the given context level', VALUE_REQUIRED), 1333 'purpose' => new external_value(PARAM_INT, 'The default purpose for the given context level', VALUE_REQUIRED), 1334 'activity' => new external_value(PARAM_PLUGIN, 'The plugin name of the activity', VALUE_DEFAULT, null), 1335 'override' => new external_value(PARAM_BOOL, 'Whether to override existing instances with the defaults', VALUE_DEFAULT, 1336 false), 1337 ]); 1338 } 1339 1340 /** 1341 * Updates the default category and purpose for a given context level (and optionally, a plugin). 1342 * 1343 * @param int $contextlevel The context level. 1344 * @param int $category The ID matching the category. 1345 * @param int $purpose The ID matching the purpose record. 1346 * @param int $activity The name of the activity that we're making a defaults configuration for. 1347 * @param bool $override Whether to override the purpose/categories of existing instances to these defaults. 1348 * @return array 1349 */ 1350 public static function set_context_defaults($contextlevel, $category, $purpose, $activity, $override) { 1351 $warnings = []; 1352 1353 $params = external_api::validate_parameters(self::set_context_defaults_parameters(), [ 1354 'contextlevel' => $contextlevel, 1355 'category' => $category, 1356 'purpose' => $purpose, 1357 'activity' => $activity, 1358 'override' => $override, 1359 ]); 1360 $contextlevel = $params['contextlevel']; 1361 $category = $params['category']; 1362 $purpose = $params['purpose']; 1363 $activity = $params['activity']; 1364 $override = $params['override']; 1365 1366 // Validate context. 1367 $context = context_system::instance(); 1368 self::validate_context($context); 1369 api::check_can_manage_data_registry(); 1370 1371 // Set the context defaults. 1372 $result = api::set_context_defaults($contextlevel, $category, $purpose, $activity, $override); 1373 1374 return [ 1375 'result' => $result, 1376 'warnings' => $warnings 1377 ]; 1378 } 1379 1380 /** 1381 * Returns for set_context_defaults(). 1382 * 1383 * @return external_single_structure 1384 */ 1385 public static function set_context_defaults_returns() { 1386 return new external_single_structure([ 1387 'result' => new external_value(PARAM_BOOL, 'Whether the context defaults were successfully set or not'), 1388 'warnings' => new external_warnings() 1389 ]); 1390 } 1391 1392 /** 1393 * Parameters for get_category_options(). 1394 * 1395 * @return external_function_parameters 1396 */ 1397 public static function get_category_options_parameters() { 1398 return new external_function_parameters([ 1399 'includeinherit' => new external_value(PARAM_BOOL, 'Include option "Inherit"', VALUE_DEFAULT, true), 1400 'includenotset' => new external_value(PARAM_BOOL, 'Include option "Not set"', VALUE_DEFAULT, false), 1401 ]); 1402 } 1403 1404 /** 1405 * Fetches a list of data category options containing category IDs as keys and the category name for the value. 1406 * 1407 * @param bool $includeinherit Whether to include the "Inherit" option. 1408 * @param bool $includenotset Whether to include the "Not set" option. 1409 * @return array 1410 */ 1411 public static function get_category_options($includeinherit, $includenotset) { 1412 $warnings = []; 1413 1414 $params = self::validate_parameters(self::get_category_options_parameters(), [ 1415 'includeinherit' => $includeinherit, 1416 'includenotset' => $includenotset 1417 ]); 1418 $includeinherit = $params['includeinherit']; 1419 $includenotset = $params['includenotset']; 1420 1421 $context = context_system::instance(); 1422 self::validate_context($context); 1423 api::check_can_manage_data_registry(); 1424 1425 $categories = api::get_categories(); 1426 $options = data_registry_page::category_options($categories, $includenotset, $includeinherit); 1427 $categoryoptions = []; 1428 foreach ($options as $id => $name) { 1429 $categoryoptions[] = [ 1430 'id' => $id, 1431 'name' => $name, 1432 ]; 1433 } 1434 1435 return [ 1436 'options' => $categoryoptions, 1437 'warnings' => $warnings 1438 ]; 1439 } 1440 1441 /** 1442 * Returns for get_category_options(). 1443 * 1444 * @return external_single_structure 1445 */ 1446 public static function get_category_options_returns() { 1447 $optiondefinition = new external_single_structure( 1448 [ 1449 'id' => new external_value(PARAM_INT, 'The category ID'), 1450 'name' => new external_value(PARAM_TEXT, 'The category name'), 1451 ] 1452 ); 1453 1454 return new external_single_structure([ 1455 'options' => new external_multiple_structure($optiondefinition), 1456 'warnings' => new external_warnings() 1457 ]); 1458 } 1459 1460 /** 1461 * Parameters for get_purpose_options(). 1462 * 1463 * @return external_function_parameters 1464 */ 1465 public static function get_purpose_options_parameters() { 1466 return new external_function_parameters([ 1467 'includeinherit' => new external_value(PARAM_BOOL, 'Include option "Inherit"', VALUE_DEFAULT, true), 1468 'includenotset' => new external_value(PARAM_BOOL, 'Include option "Not set"', VALUE_DEFAULT, false), 1469 ]); 1470 } 1471 1472 /** 1473 * Fetches a list of data storage purposes containing purpose IDs as keys and the purpose name for the value. 1474 * 1475 * @param bool $includeinherit Whether to include the "Inherit" option. 1476 * @param bool $includenotset Whether to include the "Not set" option. 1477 * @return array 1478 */ 1479 public static function get_purpose_options($includeinherit, $includenotset) { 1480 $warnings = []; 1481 1482 $params = self::validate_parameters(self::get_category_options_parameters(), [ 1483 'includeinherit' => $includeinherit, 1484 'includenotset' => $includenotset 1485 ]); 1486 $includeinherit = $params['includeinherit']; 1487 $includenotset = $params['includenotset']; 1488 1489 $context = context_system::instance(); 1490 self::validate_context($context); 1491 1492 $purposes = api::get_purposes(); 1493 $options = data_registry_page::purpose_options($purposes, $includenotset, $includeinherit); 1494 $purposeoptions = []; 1495 foreach ($options as $id => $name) { 1496 $purposeoptions[] = [ 1497 'id' => $id, 1498 'name' => $name, 1499 ]; 1500 } 1501 1502 return [ 1503 'options' => $purposeoptions, 1504 'warnings' => $warnings 1505 ]; 1506 } 1507 1508 /** 1509 * Returns for get_purpose_options(). 1510 * 1511 * @return external_single_structure 1512 */ 1513 public static function get_purpose_options_returns() { 1514 $optiondefinition = new external_single_structure( 1515 [ 1516 'id' => new external_value(PARAM_INT, 'The purpose ID'), 1517 'name' => new external_value(PARAM_TEXT, 'The purpose name'), 1518 ] 1519 ); 1520 1521 return new external_single_structure([ 1522 'options' => new external_multiple_structure($optiondefinition), 1523 'warnings' => new external_warnings() 1524 ]); 1525 } 1526 1527 /** 1528 * Parameters for get_activity_options(). 1529 * 1530 * @return external_function_parameters 1531 */ 1532 public static function get_activity_options_parameters() { 1533 return new external_function_parameters([ 1534 'nodefaults' => new external_value(PARAM_BOOL, 'Whether to fetch all activities or only those without defaults', 1535 VALUE_DEFAULT, false), 1536 ]); 1537 } 1538 1539 /** 1540 * Fetches a list of activity options for setting data registry defaults. 1541 * 1542 * @param boolean $nodefaults If false, it will fetch all of the activities. Otherwise, it will only fetch the activities 1543 * that don't have defaults yet (e.g. when adding a new activity module defaults). 1544 * @return array 1545 */ 1546 public static function get_activity_options($nodefaults) { 1547 $warnings = []; 1548 1549 $params = self::validate_parameters(self::get_activity_options_parameters(), [ 1550 'nodefaults' => $nodefaults, 1551 ]); 1552 $nodefaults = $params['nodefaults']; 1553 1554 $context = context_system::instance(); 1555 self::validate_context($context); 1556 1557 // Get activity module plugin info. 1558 $pluginmanager = \core_plugin_manager::instance(); 1559 $modplugins = $pluginmanager->get_enabled_plugins('mod'); 1560 $modoptions = []; 1561 1562 // Get the module-level defaults. data_registry::get_defaults falls back to this when there are no activity defaults. 1563 list($levelpurpose, $levelcategory) = data_registry::get_defaults(CONTEXT_MODULE); 1564 foreach ($modplugins as $name) { 1565 // Check if we have default purpose and category for this module if we want don't want to fetch everything. 1566 if ($nodefaults) { 1567 list($purpose, $category) = data_registry::get_defaults(CONTEXT_MODULE, $name); 1568 // Compare this with the module-level defaults. 1569 if ($purpose !== $levelpurpose || $category !== $levelcategory) { 1570 // If the defaults for this activity has been already set, there's no need to add this in the list of options. 1571 continue; 1572 } 1573 } 1574 1575 $displayname = $pluginmanager->plugin_name('mod_' . $name); 1576 $modoptions[] = (object)[ 1577 'name' => $name, 1578 'displayname' => $displayname 1579 ]; 1580 } 1581 1582 return [ 1583 'options' => $modoptions, 1584 'warnings' => $warnings 1585 ]; 1586 } 1587 1588 /** 1589 * Returns for get_category_options(). 1590 * 1591 * @return external_single_structure 1592 */ 1593 public static function get_activity_options_returns() { 1594 $optionsdefinition = new external_single_structure( 1595 [ 1596 'name' => new external_value(PARAM_TEXT, 'The plugin name of the activity'), 1597 'displayname' => new external_value(PARAM_TEXT, 'The display name of the activity'), 1598 ] 1599 ); 1600 1601 return new external_single_structure([ 1602 'options' => new external_multiple_structure($optionsdefinition), 1603 'warnings' => new external_warnings() 1604 ]); 1605 } 1606 1607 /** 1608 * Gets the structure of a tree node (link + child branches). 1609 * 1610 * @since Moodle 3.5 1611 * @param bool $allowchildbranches 1612 * @return array 1613 */ 1614 private static function get_tree_node_structure($allowchildbranches = true) { 1615 $fields = [ 1616 'text' => new external_value(PARAM_RAW, 'The node text', VALUE_REQUIRED), 1617 'expandcontextid' => new external_value(PARAM_INT, 'The contextid this node expands', VALUE_REQUIRED), 1618 'expandelement' => new external_value(PARAM_ALPHA, 'What element is this node expanded to', VALUE_REQUIRED), 1619 'contextid' => new external_value(PARAM_INT, 'The node contextid', VALUE_REQUIRED), 1620 'contextlevel' => new external_value(PARAM_INT, 'The node contextlevel', VALUE_REQUIRED), 1621 'expanded' => new external_value(PARAM_INT, 'Is it expanded', VALUE_REQUIRED), 1622 ]; 1623 1624 if ($allowchildbranches) { 1625 // Passing false as we will not have more than 1 sub-level. 1626 $fields['branches'] = new external_multiple_structure( 1627 self::get_tree_node_structure(false), 1628 'Children node structure', 1629 VALUE_OPTIONAL 1630 ); 1631 } else { 1632 // We will only have 1 sub-level and we don't want an infinite get_tree_node_structure, this is a hacky 1633 // way to prevent this infinite loop when calling get_tree_node_structure recursively. 1634 $fields['branches'] = new external_multiple_structure( 1635 new external_value( 1636 PARAM_TEXT, 1637 'Nothing really, it will always be an empty array', 1638 VALUE_OPTIONAL 1639 ) 1640 ); 1641 } 1642 1643 return new external_single_structure($fields, 'Node structure', VALUE_OPTIONAL); 1644 } 1645 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body