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