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