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 use core_external\external_api; 18 use core_external\external_format_value; 19 use core_external\external_function_parameters; 20 use core_external\external_multiple_structure; 21 use core_external\external_single_structure; 22 use core_external\external_value; 23 use core_external\external_warnings; 24 use core_external\util; 25 use core_group\visibility; 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 require_once($CFG->dirroot . '/group/lib.php'); 30 31 /** 32 * Group external functions 33 * 34 * @package core_group 35 * @category external 36 * @copyright 2011 Jerome Mouneyrac 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 * @since Moodle 2.2 39 */ 40 class core_group_external extends external_api { 41 42 43 /** 44 * Validate visibility. 45 * 46 * @param int $visibility Visibility string, must one of the visibility class constants. 47 * @throws invalid_parameter_exception if visibility is not an allowed value. 48 */ 49 protected static function validate_visibility(int $visibility): void { 50 $allowed = [ 51 GROUPS_VISIBILITY_ALL, 52 GROUPS_VISIBILITY_MEMBERS, 53 GROUPS_VISIBILITY_OWN, 54 GROUPS_VISIBILITY_NONE, 55 ]; 56 if (!array_key_exists($visibility, $allowed)) { 57 throw new invalid_parameter_exception('Invalid group visibility provided. Must be one of ' 58 . join(',', $allowed)); 59 } 60 } 61 62 /** 63 * Returns description of method parameters 64 * 65 * @return external_function_parameters 66 * @since Moodle 2.2 67 */ 68 public static function create_groups_parameters() { 69 return new external_function_parameters( 70 array( 71 'groups' => new external_multiple_structure( 72 new external_single_structure( 73 array( 74 'courseid' => new external_value(PARAM_INT, 'id of course'), 75 'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'), 76 'description' => new external_value(PARAM_RAW, 'group description text'), 77 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT), 78 'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase', VALUE_OPTIONAL), 79 'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL), 80 'visibility' => new external_value(PARAM_INT, 81 'group visibility mode. 0 = Visible to all. 1 = Visible to members. ' 82 . '2 = See own membership. 3 = Membership is hidden. default: 0', 83 VALUE_DEFAULT, 0), 84 'participation' => new external_value(PARAM_BOOL, 85 'activity participation enabled? Only for "all" and "members" visibility. Default true.', 86 VALUE_DEFAULT, true), 87 'customfields' => self::build_custom_fields_parameters_structure(), 88 ) 89 ), 'List of group object. A group has a courseid, a name, a description and an enrolment key.' 90 ) 91 ) 92 ); 93 } 94 95 /** 96 * Create groups 97 * 98 * @param array $groups array of group description arrays (with keys groupname and courseid) 99 * @return array of newly created groups 100 * @since Moodle 2.2 101 */ 102 public static function create_groups($groups) { 103 global $CFG, $DB; 104 require_once("$CFG->dirroot/group/lib.php"); 105 106 $params = self::validate_parameters(self::create_groups_parameters(), array('groups'=>$groups)); 107 108 $transaction = $DB->start_delegated_transaction(); 109 110 $groups = array(); 111 112 foreach ($params['groups'] as $group) { 113 $group = (object)$group; 114 115 if (trim($group->name) == '') { 116 throw new invalid_parameter_exception('Invalid group name'); 117 } 118 if ($DB->get_record('groups', array('courseid'=>$group->courseid, 'name'=>$group->name))) { 119 throw new invalid_parameter_exception('Group with the same name already exists in the course'); 120 } 121 122 // now security checks 123 $context = context_course::instance($group->courseid, IGNORE_MISSING); 124 try { 125 self::validate_context($context); 126 } catch (Exception $e) { 127 $exceptionparam = new stdClass(); 128 $exceptionparam->message = $e->getMessage(); 129 $exceptionparam->courseid = $group->courseid; 130 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 131 } 132 require_capability('moodle/course:managegroups', $context); 133 134 // Validate format. 135 $group->descriptionformat = util::validate_format($group->descriptionformat); 136 137 // Validate visibility. 138 self::validate_visibility($group->visibility); 139 140 // Custom fields. 141 if (!empty($group->customfields)) { 142 foreach ($group->customfields as $field) { 143 $fieldname = self::build_custom_field_name($field['shortname']); 144 $group->{$fieldname} = $field['value']; 145 } 146 } 147 148 // finally create the group 149 $group->id = groups_create_group($group, false); 150 if (!isset($group->enrolmentkey)) { 151 $group->enrolmentkey = ''; 152 } 153 if (!isset($group->idnumber)) { 154 $group->idnumber = ''; 155 } 156 157 $groups[] = (array)$group; 158 } 159 160 $transaction->allow_commit(); 161 162 return $groups; 163 } 164 165 /** 166 * Returns description of method result value 167 * 168 * @return \core_external\external_description 169 * @since Moodle 2.2 170 */ 171 public static function create_groups_returns() { 172 return new external_multiple_structure( 173 new external_single_structure( 174 array( 175 'id' => new external_value(PARAM_INT, 'group record id'), 176 'courseid' => new external_value(PARAM_INT, 'id of course'), 177 'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'), 178 'description' => new external_value(PARAM_RAW, 'group description text'), 179 'descriptionformat' => new external_format_value('description'), 180 'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase'), 181 'idnumber' => new external_value(PARAM_RAW, 'id number'), 182 'visibility' => new external_value(PARAM_INT, 183 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. ' 184 . '3 = Membership is hidden.'), 185 'participation' => new external_value(PARAM_BOOL, 'participation mode'), 186 'customfields' => self::build_custom_fields_parameters_structure(), 187 ) 188 ), 'List of group object. A group has an id, a courseid, a name, a description and an enrolment key.' 189 ); 190 } 191 192 /** 193 * Returns description of method parameters 194 * 195 * @return external_function_parameters 196 * @since Moodle 2.2 197 */ 198 public static function get_groups_parameters() { 199 return new external_function_parameters( 200 array( 201 'groupids' => new external_multiple_structure(new external_value(PARAM_INT, 'Group ID') 202 ,'List of group id. A group id is an integer.'), 203 ) 204 ); 205 } 206 207 /** 208 * Get groups definition specified by ids 209 * 210 * @param array $groupids arrays of group ids 211 * @return array of group objects (id, courseid, name, enrolmentkey) 212 * @since Moodle 2.2 213 */ 214 public static function get_groups($groupids) { 215 $params = self::validate_parameters(self::get_groups_parameters(), array('groupids'=>$groupids)); 216 217 $groups = array(); 218 $customfieldsdata = get_group_custom_fields_data($groupids); 219 foreach ($params['groupids'] as $groupid) { 220 // validate params 221 $group = groups_get_group($groupid, 'id, courseid, name, idnumber, description, descriptionformat, enrolmentkey, ' 222 . 'visibility, participation', MUST_EXIST); 223 224 // now security checks 225 $context = context_course::instance($group->courseid, IGNORE_MISSING); 226 try { 227 self::validate_context($context); 228 } catch (Exception $e) { 229 $exceptionparam = new stdClass(); 230 $exceptionparam->message = $e->getMessage(); 231 $exceptionparam->courseid = $group->courseid; 232 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 233 } 234 require_capability('moodle/course:managegroups', $context); 235 236 $group->name = \core_external\util::format_string($group->name, $context); 237 [$group->description, $group->descriptionformat] = 238 \core_external\util::format_text($group->description, $group->descriptionformat, 239 $context, 'group', 'description', $group->id); 240 241 $group->customfields = $customfieldsdata[$group->id] ?? []; 242 $groups[] = (array)$group; 243 } 244 245 return $groups; 246 } 247 248 /** 249 * Returns description of method result value 250 * 251 * @return \core_external\external_description 252 * @since Moodle 2.2 253 */ 254 public static function get_groups_returns() { 255 return new external_multiple_structure( 256 new external_single_structure( 257 array( 258 'id' => new external_value(PARAM_INT, 'group record id'), 259 'courseid' => new external_value(PARAM_INT, 'id of course'), 260 'name' => new external_value(PARAM_TEXT, 'group name'), 261 'description' => new external_value(PARAM_RAW, 'group description text'), 262 'descriptionformat' => new external_format_value('description'), 263 'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase'), 264 'idnumber' => new external_value(PARAM_RAW, 'id number'), 265 'visibility' => new external_value(PARAM_INT, 266 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. ' 267 . '3 = Membership is hidden.'), 268 'participation' => new external_value(PARAM_BOOL, 'participation mode'), 269 'customfields' => self::build_custom_fields_returns_structure(), 270 ) 271 ) 272 ); 273 } 274 275 /** 276 * Returns description of method parameters 277 * 278 * @return external_function_parameters 279 * @since Moodle 2.2 280 */ 281 public static function get_course_groups_parameters() { 282 return new external_function_parameters( 283 array( 284 'courseid' => new external_value(PARAM_INT, 'id of course'), 285 ) 286 ); 287 } 288 289 /** 290 * Get all groups in the specified course 291 * 292 * @param int $courseid id of course 293 * @return array of group objects (id, courseid, name, enrolmentkey) 294 * @since Moodle 2.2 295 */ 296 public static function get_course_groups($courseid) { 297 $params = self::validate_parameters(self::get_course_groups_parameters(), array('courseid'=>$courseid)); 298 299 // now security checks 300 $context = context_course::instance($params['courseid'], IGNORE_MISSING); 301 try { 302 self::validate_context($context); 303 } catch (Exception $e) { 304 $exceptionparam = new stdClass(); 305 $exceptionparam->message = $e->getMessage(); 306 $exceptionparam->courseid = $params['courseid']; 307 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 308 } 309 require_capability('moodle/course:managegroups', $context); 310 311 $gs = groups_get_all_groups($params['courseid'], 0, 0, 312 'g.id, g.courseid, g.name, g.idnumber, g.description, g.descriptionformat, g.enrolmentkey, ' 313 . 'g.visibility, g.participation'); 314 315 $groups = array(); 316 foreach ($gs as $group) { 317 $group->name = \core_external\util::format_string($group->name, $context); 318 [$group->description, $group->descriptionformat] = 319 \core_external\util::format_text($group->description, $group->descriptionformat, 320 $context, 'group', 'description', $group->id); 321 $groups[] = (array)$group; 322 } 323 324 return $groups; 325 } 326 327 /** 328 * Returns description of method result value 329 * 330 * @return \core_external\external_description 331 * @since Moodle 2.2 332 */ 333 public static function get_course_groups_returns() { 334 return new external_multiple_structure( 335 new external_single_structure( 336 array( 337 'id' => new external_value(PARAM_INT, 'group record id'), 338 'courseid' => new external_value(PARAM_INT, 'id of course'), 339 'name' => new external_value(PARAM_TEXT, 'group name'), 340 'description' => new external_value(PARAM_RAW, 'group description text'), 341 'descriptionformat' => new external_format_value('description'), 342 'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase'), 343 'idnumber' => new external_value(PARAM_RAW, 'id number'), 344 'visibility' => new external_value(PARAM_INT, 345 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. ' 346 . '3 = Membership is hidden.'), 347 'participation' => new external_value(PARAM_BOOL, 'participation mode'), 348 ) 349 ) 350 ); 351 } 352 353 /** 354 * Returns description of method parameters 355 * 356 * @return external_function_parameters 357 * @since Moodle 2.2 358 */ 359 public static function delete_groups_parameters() { 360 return new external_function_parameters( 361 array( 362 'groupids' => new external_multiple_structure(new external_value(PARAM_INT, 'Group ID')), 363 ) 364 ); 365 } 366 367 /** 368 * Delete groups 369 * 370 * @param array $groupids array of group ids 371 * @since Moodle 2.2 372 */ 373 public static function delete_groups($groupids) { 374 global $CFG, $DB; 375 require_once("$CFG->dirroot/group/lib.php"); 376 377 $params = self::validate_parameters(self::delete_groups_parameters(), array('groupids'=>$groupids)); 378 379 $transaction = $DB->start_delegated_transaction(); 380 381 foreach ($params['groupids'] as $groupid) { 382 // validate params 383 $groupid = validate_param($groupid, PARAM_INT); 384 if (!$group = groups_get_group($groupid, '*', IGNORE_MISSING)) { 385 // silently ignore attempts to delete nonexisting groups 386 continue; 387 } 388 389 // now security checks 390 $context = context_course::instance($group->courseid, IGNORE_MISSING); 391 try { 392 self::validate_context($context); 393 } catch (Exception $e) { 394 $exceptionparam = new stdClass(); 395 $exceptionparam->message = $e->getMessage(); 396 $exceptionparam->courseid = $group->courseid; 397 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 398 } 399 require_capability('moodle/course:managegroups', $context); 400 401 groups_delete_group($group); 402 } 403 404 $transaction->allow_commit(); 405 } 406 407 /** 408 * Returns description of method result value 409 * 410 * @return null 411 * @since Moodle 2.2 412 */ 413 public static function delete_groups_returns() { 414 return null; 415 } 416 417 418 /** 419 * Returns description of method parameters 420 * 421 * @return external_function_parameters 422 * @since Moodle 2.2 423 */ 424 public static function get_group_members_parameters() { 425 return new external_function_parameters( 426 array( 427 'groupids' => new external_multiple_structure(new external_value(PARAM_INT, 'Group ID')), 428 ) 429 ); 430 } 431 432 /** 433 * Return all members for a group 434 * 435 * @param array $groupids array of group ids 436 * @return array with group id keys containing arrays of user ids 437 * @since Moodle 2.2 438 */ 439 public static function get_group_members($groupids) { 440 $members = array(); 441 442 $params = self::validate_parameters(self::get_group_members_parameters(), array('groupids'=>$groupids)); 443 444 foreach ($params['groupids'] as $groupid) { 445 // validate params 446 $group = groups_get_group($groupid, 'id, courseid, name, enrolmentkey', MUST_EXIST); 447 // now security checks 448 $context = context_course::instance($group->courseid, IGNORE_MISSING); 449 try { 450 self::validate_context($context); 451 } catch (Exception $e) { 452 $exceptionparam = new stdClass(); 453 $exceptionparam->message = $e->getMessage(); 454 $exceptionparam->courseid = $group->courseid; 455 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 456 } 457 require_capability('moodle/course:managegroups', $context); 458 459 $groupmembers = groups_get_members($group->id, 'u.id', 'lastname ASC, firstname ASC'); 460 461 $members[] = array('groupid'=>$groupid, 'userids'=>array_keys($groupmembers)); 462 } 463 464 return $members; 465 } 466 467 /** 468 * Returns description of method result value 469 * 470 * @return \core_external\external_description 471 * @since Moodle 2.2 472 */ 473 public static function get_group_members_returns() { 474 return new external_multiple_structure( 475 new external_single_structure( 476 array( 477 'groupid' => new external_value(PARAM_INT, 'group record id'), 478 'userids' => new external_multiple_structure(new external_value(PARAM_INT, 'user id')), 479 ) 480 ) 481 ); 482 } 483 484 485 /** 486 * Returns description of method parameters 487 * 488 * @return external_function_parameters 489 * @since Moodle 2.2 490 */ 491 public static function add_group_members_parameters() { 492 return new external_function_parameters( 493 array( 494 'members'=> new external_multiple_structure( 495 new external_single_structure( 496 array( 497 'groupid' => new external_value(PARAM_INT, 'group record id'), 498 'userid' => new external_value(PARAM_INT, 'user id'), 499 ) 500 ) 501 ) 502 ) 503 ); 504 } 505 506 /** 507 * Add group members 508 * 509 * @param array $members of arrays with keys userid, groupid 510 * @since Moodle 2.2 511 */ 512 public static function add_group_members($members) { 513 global $CFG, $DB; 514 require_once("$CFG->dirroot/group/lib.php"); 515 516 $params = self::validate_parameters(self::add_group_members_parameters(), array('members'=>$members)); 517 518 $transaction = $DB->start_delegated_transaction(); 519 foreach ($params['members'] as $member) { 520 // validate params 521 $groupid = $member['groupid']; 522 $userid = $member['userid']; 523 524 $group = groups_get_group($groupid, '*', MUST_EXIST); 525 $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0, 'mnethostid'=>$CFG->mnet_localhost_id), '*', MUST_EXIST); 526 527 // now security checks 528 $context = context_course::instance($group->courseid, IGNORE_MISSING); 529 try { 530 self::validate_context($context); 531 } catch (Exception $e) { 532 $exceptionparam = new stdClass(); 533 $exceptionparam->message = $e->getMessage(); 534 $exceptionparam->courseid = $group->courseid; 535 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 536 } 537 require_capability('moodle/course:managegroups', $context); 538 539 // now make sure user is enrolled in course - this is mandatory requirement, 540 // unfortunately this is slow 541 if (!is_enrolled($context, $userid)) { 542 throw new invalid_parameter_exception('Only enrolled users may be members of groups'); 543 } 544 545 groups_add_member($group, $user); 546 } 547 548 $transaction->allow_commit(); 549 } 550 551 /** 552 * Returns description of method result value 553 * 554 * @return null 555 * @since Moodle 2.2 556 */ 557 public static function add_group_members_returns() { 558 return null; 559 } 560 561 562 /** 563 * Returns description of method parameters 564 * 565 * @return external_function_parameters 566 * @since Moodle 2.2 567 */ 568 public static function delete_group_members_parameters() { 569 return new external_function_parameters( 570 array( 571 'members'=> new external_multiple_structure( 572 new external_single_structure( 573 array( 574 'groupid' => new external_value(PARAM_INT, 'group record id'), 575 'userid' => new external_value(PARAM_INT, 'user id'), 576 ) 577 ) 578 ) 579 ) 580 ); 581 } 582 583 /** 584 * Delete group members 585 * 586 * @param array $members of arrays with keys userid, groupid 587 * @since Moodle 2.2 588 */ 589 public static function delete_group_members($members) { 590 global $CFG, $DB; 591 require_once("$CFG->dirroot/group/lib.php"); 592 593 $params = self::validate_parameters(self::delete_group_members_parameters(), array('members'=>$members)); 594 595 $transaction = $DB->start_delegated_transaction(); 596 597 foreach ($params['members'] as $member) { 598 // validate params 599 $groupid = $member['groupid']; 600 $userid = $member['userid']; 601 602 $group = groups_get_group($groupid, '*', MUST_EXIST); 603 $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0, 'mnethostid'=>$CFG->mnet_localhost_id), '*', MUST_EXIST); 604 605 // now security checks 606 $context = context_course::instance($group->courseid, IGNORE_MISSING); 607 try { 608 self::validate_context($context); 609 } catch (Exception $e) { 610 $exceptionparam = new stdClass(); 611 $exceptionparam->message = $e->getMessage(); 612 $exceptionparam->courseid = $group->courseid; 613 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 614 } 615 require_capability('moodle/course:managegroups', $context); 616 617 if (!groups_remove_member_allowed($group, $user)) { 618 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context)); 619 throw new moodle_exception('errorremovenotpermitted', 'group', '', $fullname); 620 } 621 groups_remove_member($group, $user); 622 } 623 624 $transaction->allow_commit(); 625 } 626 627 /** 628 * Returns description of method result value 629 * 630 * @return null 631 * @since Moodle 2.2 632 */ 633 public static function delete_group_members_returns() { 634 return null; 635 } 636 637 /** 638 * Returns description of method parameters 639 * 640 * @return external_function_parameters 641 * @since Moodle 2.3 642 */ 643 public static function create_groupings_parameters() { 644 return new external_function_parameters( 645 array( 646 'groupings' => new external_multiple_structure( 647 new external_single_structure( 648 array( 649 'courseid' => new external_value(PARAM_INT, 'id of course'), 650 'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'), 651 'description' => new external_value(PARAM_RAW, 'grouping description text'), 652 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT), 653 'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL), 654 'customfields' => self::build_custom_fields_parameters_structure(), 655 ) 656 ), 'List of grouping object. A grouping has a courseid, a name and a description.' 657 ) 658 ) 659 ); 660 } 661 662 /** 663 * Create groupings 664 * 665 * @param array $groupings array of grouping description arrays (with keys groupname and courseid) 666 * @return array of newly created groupings 667 * @since Moodle 2.3 668 */ 669 public static function create_groupings($groupings) { 670 global $CFG, $DB; 671 require_once("$CFG->dirroot/group/lib.php"); 672 673 $params = self::validate_parameters(self::create_groupings_parameters(), array('groupings'=>$groupings)); 674 675 $transaction = $DB->start_delegated_transaction(); 676 677 $groupings = array(); 678 679 foreach ($params['groupings'] as $grouping) { 680 $grouping = (object)$grouping; 681 682 if (trim($grouping->name) == '') { 683 throw new invalid_parameter_exception('Invalid grouping name'); 684 } 685 if ($DB->count_records('groupings', array('courseid'=>$grouping->courseid, 'name'=>$grouping->name))) { 686 throw new invalid_parameter_exception('Grouping with the same name already exists in the course'); 687 } 688 689 // Now security checks . 690 $context = context_course::instance($grouping->courseid); 691 try { 692 self::validate_context($context); 693 } catch (Exception $e) { 694 $exceptionparam = new stdClass(); 695 $exceptionparam->message = $e->getMessage(); 696 $exceptionparam->courseid = $grouping->courseid; 697 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 698 } 699 require_capability('moodle/course:managegroups', $context); 700 701 $grouping->descriptionformat = util::validate_format($grouping->descriptionformat); 702 703 // Custom fields. 704 if (!empty($grouping->customfields)) { 705 foreach ($grouping->customfields as $field) { 706 $fieldname = self::build_custom_field_name($field['shortname']); 707 $grouping->{$fieldname} = $field['value']; 708 } 709 } 710 711 // Finally create the grouping. 712 $grouping->id = groups_create_grouping($grouping); 713 $groupings[] = (array)$grouping; 714 } 715 716 $transaction->allow_commit(); 717 718 return $groupings; 719 } 720 721 /** 722 * Returns description of method result value 723 * 724 * @return \core_external\external_description 725 * @since Moodle 2.3 726 */ 727 public static function create_groupings_returns() { 728 return new external_multiple_structure( 729 new external_single_structure( 730 array( 731 'id' => new external_value(PARAM_INT, 'grouping record id'), 732 'courseid' => new external_value(PARAM_INT, 'id of course'), 733 'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'), 734 'description' => new external_value(PARAM_RAW, 'grouping description text'), 735 'descriptionformat' => new external_format_value('description'), 736 'idnumber' => new external_value(PARAM_RAW, 'id number'), 737 'customfields' => self::build_custom_fields_parameters_structure(), 738 ) 739 ), 'List of grouping object. A grouping has an id, a courseid, a name and a description.' 740 ); 741 } 742 743 /** 744 * Returns description of method parameters 745 * 746 * @return external_function_parameters 747 * @since Moodle 2.3 748 */ 749 public static function update_groupings_parameters() { 750 return new external_function_parameters( 751 array( 752 'groupings' => new external_multiple_structure( 753 new external_single_structure( 754 array( 755 'id' => new external_value(PARAM_INT, 'id of grouping'), 756 'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'), 757 'description' => new external_value(PARAM_RAW, 'grouping description text'), 758 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT), 759 'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL), 760 'customfields' => self::build_custom_fields_parameters_structure(), 761 ) 762 ), 'List of grouping object. A grouping has a courseid, a name and a description.' 763 ) 764 ) 765 ); 766 } 767 768 /** 769 * Update groupings 770 * 771 * @param array $groupings array of grouping description arrays (with keys groupname and courseid) 772 * @return array of newly updated groupings 773 * @since Moodle 2.3 774 */ 775 public static function update_groupings($groupings) { 776 global $CFG, $DB; 777 require_once("$CFG->dirroot/group/lib.php"); 778 779 $params = self::validate_parameters(self::update_groupings_parameters(), array('groupings'=>$groupings)); 780 781 $transaction = $DB->start_delegated_transaction(); 782 783 foreach ($params['groupings'] as $grouping) { 784 $grouping = (object)$grouping; 785 786 if (trim($grouping->name) == '') { 787 throw new invalid_parameter_exception('Invalid grouping name'); 788 } 789 790 if (! $currentgrouping = $DB->get_record('groupings', array('id'=>$grouping->id))) { 791 throw new invalid_parameter_exception("Grouping $grouping->id does not exist in the course"); 792 } 793 794 // Check if the new modified grouping name already exists in the course. 795 if ($grouping->name != $currentgrouping->name and 796 $DB->count_records('groupings', array('courseid'=>$currentgrouping->courseid, 'name'=>$grouping->name))) { 797 throw new invalid_parameter_exception('A different grouping with the same name already exists in the course'); 798 } 799 800 $grouping->courseid = $currentgrouping->courseid; 801 802 // Now security checks. 803 $context = context_course::instance($grouping->courseid); 804 try { 805 self::validate_context($context); 806 } catch (Exception $e) { 807 $exceptionparam = new stdClass(); 808 $exceptionparam->message = $e->getMessage(); 809 $exceptionparam->courseid = $grouping->courseid; 810 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 811 } 812 require_capability('moodle/course:managegroups', $context); 813 814 // We must force allways FORMAT_HTML. 815 $grouping->descriptionformat = util::validate_format($grouping->descriptionformat); 816 817 // Custom fields. 818 if (!empty($grouping->customfields)) { 819 foreach ($grouping->customfields as $field) { 820 $fieldname = self::build_custom_field_name($field['shortname']); 821 $grouping->{$fieldname} = $field['value']; 822 } 823 } 824 825 // Finally update the grouping. 826 groups_update_grouping($grouping); 827 } 828 829 $transaction->allow_commit(); 830 831 return null; 832 } 833 834 /** 835 * Returns description of method result value 836 * 837 * @return \core_external\external_description 838 * @since Moodle 2.3 839 */ 840 public static function update_groupings_returns() { 841 return null; 842 } 843 844 /** 845 * Returns description of method parameters 846 * 847 * @return external_function_parameters 848 * @since Moodle 2.3 849 */ 850 public static function get_groupings_parameters() { 851 return new external_function_parameters( 852 array( 853 'groupingids' => new external_multiple_structure(new external_value(PARAM_INT, 'grouping ID') 854 , 'List of grouping id. A grouping id is an integer.'), 855 'returngroups' => new external_value(PARAM_BOOL, 'return associated groups', VALUE_DEFAULT, 0) 856 ) 857 ); 858 } 859 860 /** 861 * Get groupings definition specified by ids 862 * 863 * @param array $groupingids arrays of grouping ids 864 * @param boolean $returngroups return the associated groups if true. The default is false. 865 * @return array of grouping objects (id, courseid, name) 866 * @since Moodle 2.3 867 */ 868 public static function get_groupings($groupingids, $returngroups = false) { 869 global $CFG, $DB; 870 require_once("$CFG->dirroot/group/lib.php"); 871 require_once("$CFG->libdir/filelib.php"); 872 873 $params = self::validate_parameters(self::get_groupings_parameters(), 874 array('groupingids' => $groupingids, 875 'returngroups' => $returngroups)); 876 877 $groupings = array(); 878 $groupingcustomfieldsdata = get_grouping_custom_fields_data($groupingids); 879 foreach ($params['groupingids'] as $groupingid) { 880 // Validate params. 881 $grouping = groups_get_grouping($groupingid, '*', MUST_EXIST); 882 883 // Now security checks. 884 $context = context_course::instance($grouping->courseid); 885 try { 886 self::validate_context($context); 887 } catch (Exception $e) { 888 $exceptionparam = new stdClass(); 889 $exceptionparam->message = $e->getMessage(); 890 $exceptionparam->courseid = $grouping->courseid; 891 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 892 } 893 require_capability('moodle/course:managegroups', $context); 894 895 list($grouping->description, $grouping->descriptionformat) = 896 \core_external\util::format_text($grouping->description, $grouping->descriptionformat, 897 $context, 'grouping', 'description', $grouping->id); 898 899 $grouping->customfields = $groupingcustomfieldsdata[$grouping->id] ?? []; 900 $groupingarray = (array)$grouping; 901 902 if ($params['returngroups']) { 903 $grouprecords = $DB->get_records_sql("SELECT * FROM {groups} g INNER JOIN {groupings_groups} gg ". 904 "ON g.id = gg.groupid WHERE gg.groupingid = ? ". 905 "ORDER BY groupid", array($groupingid)); 906 if ($grouprecords) { 907 $groups = array(); 908 $groupids = []; 909 foreach ($grouprecords as $grouprecord) { 910 list($grouprecord->description, $grouprecord->descriptionformat) = 911 \core_external\util::format_text($grouprecord->description, $grouprecord->descriptionformat, 912 $context, 'group', 'description', $grouprecord->groupid); 913 $groups[] = array('id' => $grouprecord->groupid, 914 'name' => $grouprecord->name, 915 'idnumber' => $grouprecord->idnumber, 916 'description' => $grouprecord->description, 917 'descriptionformat' => $grouprecord->descriptionformat, 918 'enrolmentkey' => $grouprecord->enrolmentkey, 919 'courseid' => $grouprecord->courseid 920 ); 921 $groupids[] = $grouprecord->groupid; 922 } 923 $groupcustomfieldsdata = get_group_custom_fields_data($groupids); 924 foreach ($groups as $i => $group) { 925 $groups[$i]['customfields'] = $groupcustomfieldsdata[$group['id']] ?? []; 926 } 927 $groupingarray['groups'] = $groups; 928 } 929 } 930 $groupings[] = $groupingarray; 931 } 932 933 return $groupings; 934 } 935 936 /** 937 * Returns description of method result value 938 * 939 * @return \core_external\external_description 940 * @since Moodle 2.3 941 */ 942 public static function get_groupings_returns() { 943 return new external_multiple_structure( 944 new external_single_structure( 945 array( 946 'id' => new external_value(PARAM_INT, 'grouping record id'), 947 'courseid' => new external_value(PARAM_INT, 'id of course'), 948 'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'), 949 'description' => new external_value(PARAM_RAW, 'grouping description text'), 950 'descriptionformat' => new external_format_value('description'), 951 'idnumber' => new external_value(PARAM_RAW, 'id number'), 952 'customfields' => self::build_custom_fields_returns_structure(), 953 'groups' => new external_multiple_structure( 954 new external_single_structure( 955 array( 956 'id' => new external_value(PARAM_INT, 'group record id'), 957 'courseid' => new external_value(PARAM_INT, 'id of course'), 958 'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'), 959 'description' => new external_value(PARAM_RAW, 'group description text'), 960 'descriptionformat' => new external_format_value('description'), 961 'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase'), 962 'idnumber' => new external_value(PARAM_RAW, 'id number'), 963 'customfields' => self::build_custom_fields_returns_structure(), 964 ) 965 ), 966 'optional groups', VALUE_OPTIONAL) 967 ) 968 ) 969 ); 970 } 971 972 /** 973 * Returns description of method parameters 974 * 975 * @return external_function_parameters 976 * @since Moodle 2.3 977 */ 978 public static function get_course_groupings_parameters() { 979 return new external_function_parameters( 980 array( 981 'courseid' => new external_value(PARAM_INT, 'id of course'), 982 ) 983 ); 984 } 985 986 /** 987 * Get all groupings in the specified course 988 * 989 * @param int $courseid id of course 990 * @return array of grouping objects (id, courseid, name, enrolmentkey) 991 * @since Moodle 2.3 992 */ 993 public static function get_course_groupings($courseid) { 994 global $CFG; 995 require_once("$CFG->dirroot/group/lib.php"); 996 require_once("$CFG->libdir/filelib.php"); 997 998 $params = self::validate_parameters(self::get_course_groupings_parameters(), array('courseid'=>$courseid)); 999 1000 // Now security checks. 1001 $context = context_course::instance($params['courseid']); 1002 1003 try { 1004 self::validate_context($context); 1005 } catch (Exception $e) { 1006 $exceptionparam = new stdClass(); 1007 $exceptionparam->message = $e->getMessage(); 1008 $exceptionparam->courseid = $params['courseid']; 1009 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 1010 } 1011 require_capability('moodle/course:managegroups', $context); 1012 1013 $gs = groups_get_all_groupings($params['courseid']); 1014 1015 $groupings = array(); 1016 foreach ($gs as $grouping) { 1017 list($grouping->description, $grouping->descriptionformat) = 1018 \core_external\util::format_text($grouping->description, $grouping->descriptionformat, 1019 $context, 'grouping', 'description', $grouping->id); 1020 $groupings[] = (array)$grouping; 1021 } 1022 1023 return $groupings; 1024 } 1025 1026 /** 1027 * Returns description of method result value 1028 * 1029 * @return \core_external\external_description 1030 * @since Moodle 2.3 1031 */ 1032 public static function get_course_groupings_returns() { 1033 return new external_multiple_structure( 1034 new external_single_structure( 1035 array( 1036 'id' => new external_value(PARAM_INT, 'grouping record id'), 1037 'courseid' => new external_value(PARAM_INT, 'id of course'), 1038 'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'), 1039 'description' => new external_value(PARAM_RAW, 'grouping description text'), 1040 'descriptionformat' => new external_format_value('description'), 1041 'idnumber' => new external_value(PARAM_RAW, 'id number') 1042 ) 1043 ) 1044 ); 1045 } 1046 1047 /** 1048 * Returns description of method parameters 1049 * 1050 * @return external_function_parameters 1051 * @since Moodle 2.3 1052 */ 1053 public static function delete_groupings_parameters() { 1054 return new external_function_parameters( 1055 array( 1056 'groupingids' => new external_multiple_structure(new external_value(PARAM_INT, 'grouping ID')), 1057 ) 1058 ); 1059 } 1060 1061 /** 1062 * Delete groupings 1063 * 1064 * @param array $groupingids array of grouping ids 1065 * @return void 1066 * @since Moodle 2.3 1067 */ 1068 public static function delete_groupings($groupingids) { 1069 global $CFG, $DB; 1070 require_once("$CFG->dirroot/group/lib.php"); 1071 1072 $params = self::validate_parameters(self::delete_groupings_parameters(), array('groupingids'=>$groupingids)); 1073 1074 $transaction = $DB->start_delegated_transaction(); 1075 1076 foreach ($params['groupingids'] as $groupingid) { 1077 1078 if (!$grouping = groups_get_grouping($groupingid)) { 1079 // Silently ignore attempts to delete nonexisting groupings. 1080 continue; 1081 } 1082 1083 // Now security checks. 1084 $context = context_course::instance($grouping->courseid); 1085 try { 1086 self::validate_context($context); 1087 } catch (Exception $e) { 1088 $exceptionparam = new stdClass(); 1089 $exceptionparam->message = $e->getMessage(); 1090 $exceptionparam->courseid = $grouping->courseid; 1091 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 1092 } 1093 require_capability('moodle/course:managegroups', $context); 1094 1095 groups_delete_grouping($grouping); 1096 } 1097 1098 $transaction->allow_commit(); 1099 } 1100 1101 /** 1102 * Returns description of method result value 1103 * 1104 * @return \core_external\external_description 1105 * @since Moodle 2.3 1106 */ 1107 public static function delete_groupings_returns() { 1108 return null; 1109 } 1110 1111 /** 1112 * Returns description of method parameters 1113 * 1114 * @return external_function_parameters 1115 * @since Moodle 2.3 1116 */ 1117 public static function assign_grouping_parameters() { 1118 return new external_function_parameters( 1119 array( 1120 'assignments'=> new external_multiple_structure( 1121 new external_single_structure( 1122 array( 1123 'groupingid' => new external_value(PARAM_INT, 'grouping record id'), 1124 'groupid' => new external_value(PARAM_INT, 'group record id'), 1125 ) 1126 ) 1127 ) 1128 ) 1129 ); 1130 } 1131 1132 /** 1133 * Assign a group to a grouping 1134 * 1135 * @param array $assignments of arrays with keys groupid, groupingid 1136 * @return void 1137 * @since Moodle 2.3 1138 */ 1139 public static function assign_grouping($assignments) { 1140 global $CFG, $DB; 1141 require_once("$CFG->dirroot/group/lib.php"); 1142 1143 $params = self::validate_parameters(self::assign_grouping_parameters(), array('assignments'=>$assignments)); 1144 1145 $transaction = $DB->start_delegated_transaction(); 1146 foreach ($params['assignments'] as $assignment) { 1147 // Validate params. 1148 $groupingid = $assignment['groupingid']; 1149 $groupid = $assignment['groupid']; 1150 1151 $grouping = groups_get_grouping($groupingid, 'id, courseid', MUST_EXIST); 1152 $group = groups_get_group($groupid, 'id, courseid', MUST_EXIST); 1153 1154 if ($DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) { 1155 // Continue silently if the group is yet assigned to the grouping. 1156 continue; 1157 } 1158 1159 // Now security checks. 1160 $context = context_course::instance($grouping->courseid); 1161 try { 1162 self::validate_context($context); 1163 } catch (Exception $e) { 1164 $exceptionparam = new stdClass(); 1165 $exceptionparam->message = $e->getMessage(); 1166 $exceptionparam->courseid = $group->courseid; 1167 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 1168 } 1169 require_capability('moodle/course:managegroups', $context); 1170 1171 groups_assign_grouping($groupingid, $groupid); 1172 } 1173 1174 $transaction->allow_commit(); 1175 } 1176 1177 /** 1178 * Returns description of method result value 1179 * 1180 * @return null 1181 * @since Moodle 2.3 1182 */ 1183 public static function assign_grouping_returns() { 1184 return null; 1185 } 1186 1187 /** 1188 * Returns description of method parameters 1189 * 1190 * @return external_function_parameters 1191 * @since Moodle 2.3 1192 */ 1193 public static function unassign_grouping_parameters() { 1194 return new external_function_parameters( 1195 array( 1196 'unassignments'=> new external_multiple_structure( 1197 new external_single_structure( 1198 array( 1199 'groupingid' => new external_value(PARAM_INT, 'grouping record id'), 1200 'groupid' => new external_value(PARAM_INT, 'group record id'), 1201 ) 1202 ) 1203 ) 1204 ) 1205 ); 1206 } 1207 1208 /** 1209 * Unassign a group from a grouping 1210 * 1211 * @param array $unassignments of arrays with keys groupid, groupingid 1212 * @return void 1213 * @since Moodle 2.3 1214 */ 1215 public static function unassign_grouping($unassignments) { 1216 global $CFG, $DB; 1217 require_once("$CFG->dirroot/group/lib.php"); 1218 1219 $params = self::validate_parameters(self::unassign_grouping_parameters(), array('unassignments'=>$unassignments)); 1220 1221 $transaction = $DB->start_delegated_transaction(); 1222 foreach ($params['unassignments'] as $unassignment) { 1223 // Validate params. 1224 $groupingid = $unassignment['groupingid']; 1225 $groupid = $unassignment['groupid']; 1226 1227 $grouping = groups_get_grouping($groupingid, 'id, courseid', MUST_EXIST); 1228 $group = groups_get_group($groupid, 'id, courseid', MUST_EXIST); 1229 1230 if (!$DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) { 1231 // Continue silently if the group is not assigned to the grouping. 1232 continue; 1233 } 1234 1235 // Now security checks. 1236 $context = context_course::instance($grouping->courseid); 1237 try { 1238 self::validate_context($context); 1239 } catch (Exception $e) { 1240 $exceptionparam = new stdClass(); 1241 $exceptionparam->message = $e->getMessage(); 1242 $exceptionparam->courseid = $group->courseid; 1243 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 1244 } 1245 require_capability('moodle/course:managegroups', $context); 1246 1247 groups_unassign_grouping($groupingid, $groupid); 1248 } 1249 1250 $transaction->allow_commit(); 1251 } 1252 1253 /** 1254 * Returns description of method result value 1255 * 1256 * @return null 1257 * @since Moodle 2.3 1258 */ 1259 public static function unassign_grouping_returns() { 1260 return null; 1261 } 1262 1263 /** 1264 * Returns description of method parameters 1265 * 1266 * @return external_function_parameters 1267 * @since Moodle 2.9 1268 */ 1269 public static function get_course_user_groups_parameters() { 1270 return new external_function_parameters( 1271 array( 1272 'courseid' => new external_value(PARAM_INT, 1273 'Id of course (empty or 0 for all the courses where the user is enrolled).', VALUE_DEFAULT, 0), 1274 'userid' => new external_value(PARAM_INT, 'Id of user (empty or 0 for current user).', VALUE_DEFAULT, 0), 1275 'groupingid' => new external_value(PARAM_INT, 'returns only groups in the specified grouping', VALUE_DEFAULT, 0) 1276 ) 1277 ); 1278 } 1279 1280 /** 1281 * Get all groups in the specified course for the specified user. 1282 * 1283 * @throws moodle_exception 1284 * @param int $courseid id of course. 1285 * @param int $userid id of user. 1286 * @param int $groupingid optional returns only groups in the specified grouping. 1287 * @return array of group objects (id, name, description, format) and possible warnings. 1288 * @since Moodle 2.9 1289 */ 1290 public static function get_course_user_groups($courseid = 0, $userid = 0, $groupingid = 0) { 1291 global $USER; 1292 1293 // Warnings array, it can be empty at the end but is mandatory. 1294 $warnings = array(); 1295 1296 $params = array( 1297 'courseid' => $courseid, 1298 'userid' => $userid, 1299 'groupingid' => $groupingid 1300 ); 1301 $params = self::validate_parameters(self::get_course_user_groups_parameters(), $params); 1302 1303 $courseid = $params['courseid']; 1304 $userid = $params['userid']; 1305 $groupingid = $params['groupingid']; 1306 1307 // Validate user. 1308 if (empty($userid)) { 1309 $userid = $USER->id; 1310 } else { 1311 $user = core_user::get_user($userid, '*', MUST_EXIST); 1312 core_user::require_active_user($user); 1313 } 1314 1315 // Get courses. 1316 if (empty($courseid)) { 1317 $courses = enrol_get_users_courses($userid, true); 1318 $checkenrolments = false; // No need to check enrolments here since they are my courses. 1319 } else { 1320 $courses = array($courseid => get_course($courseid)); 1321 $checkenrolments = true; 1322 } 1323 1324 // Security checks. 1325 list($courses, $warnings) = util::validate_courses(array_keys($courses), $courses, true); 1326 1327 $usergroups = array(); 1328 foreach ($courses as $course) { 1329 // Check if we have permissions for retrieve the information. 1330 if ($userid != $USER->id && !has_capability('moodle/course:managegroups', $course->context)) { 1331 $warnings[] = array( 1332 'item' => 'course', 1333 'itemid' => $course->id, 1334 'warningcode' => 'cannotmanagegroups', 1335 'message' => "User $USER->id cannot manage groups in course $course->id", 1336 ); 1337 continue; 1338 } 1339 1340 // Check if the user being check is enrolled in the given course. 1341 if ($checkenrolments && !is_enrolled($course->context, $userid)) { 1342 // We return a warning because the function does not fail for not enrolled users. 1343 $warnings[] = array( 1344 'item' => 'course', 1345 'itemid' => $course->id, 1346 'warningcode' => 'notenrolled', 1347 'message' => "User $userid is not enrolled in course $course->id", 1348 ); 1349 } 1350 1351 $groups = groups_get_all_groups($course->id, $userid, $groupingid, 1352 'g.id, g.name, g.description, g.descriptionformat, g.idnumber'); 1353 1354 foreach ($groups as $group) { 1355 $group->name = \core_external\util::format_string($group->name, $course->context); 1356 [$group->description, $group->descriptionformat] = 1357 \core_external\util::format_text($group->description, $group->descriptionformat, 1358 $course->context, 'group', 'description', $group->id); 1359 $group->courseid = $course->id; 1360 $usergroups[] = $group; 1361 } 1362 } 1363 1364 $results = array( 1365 'groups' => $usergroups, 1366 'warnings' => $warnings 1367 ); 1368 return $results; 1369 } 1370 1371 /** 1372 * Returns description of method result value. 1373 * 1374 * @return \core_external\external_description A single structure containing groups and possible warnings. 1375 * @since Moodle 2.9 1376 */ 1377 public static function get_course_user_groups_returns() { 1378 return new external_single_structure( 1379 array( 1380 'groups' => new external_multiple_structure(self::group_description()), 1381 'warnings' => new external_warnings(), 1382 ) 1383 ); 1384 } 1385 1386 /** 1387 * Create group return value description. 1388 * 1389 * @return external_single_structure The group description 1390 */ 1391 public static function group_description() { 1392 return new external_single_structure( 1393 array( 1394 'id' => new external_value(PARAM_INT, 'group record id'), 1395 'name' => new external_value(PARAM_TEXT, 'group name'), 1396 'description' => new external_value(PARAM_RAW, 'group description text'), 1397 'descriptionformat' => new external_format_value('description'), 1398 'idnumber' => new external_value(PARAM_RAW, 'id number'), 1399 'courseid' => new external_value(PARAM_INT, 'course id', VALUE_OPTIONAL), 1400 ) 1401 ); 1402 } 1403 1404 /** 1405 * Returns description of method parameters 1406 * 1407 * @return external_function_parameters 1408 * @since Moodle 3.0 1409 */ 1410 public static function get_activity_allowed_groups_parameters() { 1411 return new external_function_parameters( 1412 array( 1413 'cmid' => new external_value(PARAM_INT, 'course module id'), 1414 'userid' => new external_value(PARAM_INT, 'id of user, empty for current user', VALUE_DEFAULT, 0) 1415 ) 1416 ); 1417 } 1418 1419 /** 1420 * Gets a list of groups that the user is allowed to access within the specified activity. 1421 * 1422 * @throws moodle_exception 1423 * @param int $cmid course module id 1424 * @param int $userid id of user. 1425 * @return array of group objects (id, name, description, format) and possible warnings. 1426 * @since Moodle 3.0 1427 */ 1428 public static function get_activity_allowed_groups($cmid, $userid = 0) { 1429 global $USER; 1430 1431 // Warnings array, it can be empty at the end but is mandatory. 1432 $warnings = array(); 1433 1434 $params = array( 1435 'cmid' => $cmid, 1436 'userid' => $userid 1437 ); 1438 $params = self::validate_parameters(self::get_activity_allowed_groups_parameters(), $params); 1439 $cmid = $params['cmid']; 1440 $userid = $params['userid']; 1441 1442 $cm = get_coursemodule_from_id(null, $cmid, 0, false, MUST_EXIST); 1443 1444 // Security checks. 1445 $context = context_module::instance($cm->id); 1446 $coursecontext = context_course::instance($cm->course); 1447 self::validate_context($context); 1448 1449 if (empty($userid)) { 1450 $userid = $USER->id; 1451 } 1452 1453 $user = core_user::get_user($userid, '*', MUST_EXIST); 1454 core_user::require_active_user($user); 1455 1456 // Check if we have permissions for retrieve the information. 1457 if ($user->id != $USER->id) { 1458 if (!has_capability('moodle/course:managegroups', $context)) { 1459 throw new moodle_exception('accessdenied', 'admin'); 1460 } 1461 1462 // Validate if the user is enrolled in the course. 1463 $course = get_course($cm->course); 1464 if (!can_access_course($course, $user, '', true)) { 1465 // We return a warning because the function does not fail for not enrolled users. 1466 $warning = array(); 1467 $warning['item'] = 'course'; 1468 $warning['itemid'] = $cm->course; 1469 $warning['warningcode'] = '1'; 1470 $warning['message'] = "User $user->id cannot access course $cm->course"; 1471 $warnings[] = $warning; 1472 } 1473 } 1474 1475 $usergroups = array(); 1476 if (empty($warnings)) { 1477 $groups = groups_get_activity_allowed_groups($cm, $user->id); 1478 1479 foreach ($groups as $group) { 1480 $group->name = \core_external\util::format_string($group->name, $coursecontext); 1481 [$group->description, $group->descriptionformat] = 1482 \core_external\util::format_text($group->description, $group->descriptionformat, 1483 $coursecontext, 'group', 'description', $group->id); 1484 $group->courseid = $cm->course; 1485 $usergroups[] = $group; 1486 } 1487 } 1488 1489 $results = array( 1490 'groups' => $usergroups, 1491 'canaccessallgroups' => has_capability('moodle/site:accessallgroups', $context, $user), 1492 'warnings' => $warnings 1493 ); 1494 return $results; 1495 } 1496 1497 /** 1498 * Returns description of method result value. 1499 * 1500 * @return \core_external\external_description A single structure containing groups and possible warnings. 1501 * @since Moodle 3.0 1502 */ 1503 public static function get_activity_allowed_groups_returns() { 1504 return new external_single_structure( 1505 array( 1506 'groups' => new external_multiple_structure(self::group_description()), 1507 'canaccessallgroups' => new external_value(PARAM_BOOL, 1508 'Whether the user will be able to access all the activity groups.', VALUE_OPTIONAL), 1509 'warnings' => new external_warnings(), 1510 ) 1511 ); 1512 } 1513 1514 /** 1515 * Returns description of method parameters 1516 * 1517 * @return external_function_parameters 1518 * @since Moodle 3.0 1519 */ 1520 public static function get_activity_groupmode_parameters() { 1521 return new external_function_parameters( 1522 array( 1523 'cmid' => new external_value(PARAM_INT, 'course module id') 1524 ) 1525 ); 1526 } 1527 1528 /** 1529 * Returns effective groupmode used in a given activity. 1530 * 1531 * @throws moodle_exception 1532 * @param int $cmid course module id. 1533 * @return array containing the group mode and possible warnings. 1534 * @since Moodle 3.0 1535 * @throws moodle_exception 1536 */ 1537 public static function get_activity_groupmode($cmid) { 1538 global $USER; 1539 1540 // Warnings array, it can be empty at the end but is mandatory. 1541 $warnings = array(); 1542 1543 $params = array( 1544 'cmid' => $cmid 1545 ); 1546 $params = self::validate_parameters(self::get_activity_groupmode_parameters(), $params); 1547 $cmid = $params['cmid']; 1548 1549 $cm = get_coursemodule_from_id(null, $cmid, 0, false, MUST_EXIST); 1550 1551 // Security checks. 1552 $context = context_module::instance($cm->id); 1553 self::validate_context($context); 1554 1555 $groupmode = groups_get_activity_groupmode($cm); 1556 1557 $results = array( 1558 'groupmode' => $groupmode, 1559 'warnings' => $warnings 1560 ); 1561 return $results; 1562 } 1563 1564 /** 1565 * Returns description of method result value. 1566 * 1567 * @return \core_external\external_description 1568 * @since Moodle 3.0 1569 */ 1570 public static function get_activity_groupmode_returns() { 1571 return new external_single_structure( 1572 array( 1573 'groupmode' => new external_value(PARAM_INT, 'group mode: 1574 0 for no groups, 1 for separate groups, 2 for visible groups'), 1575 'warnings' => new external_warnings(), 1576 ) 1577 ); 1578 } 1579 1580 /** 1581 * Returns description of method parameters 1582 * 1583 * @return external_function_parameters 1584 * @since Moodle 3.6 1585 */ 1586 public static function update_groups_parameters() { 1587 return new external_function_parameters( 1588 array( 1589 'groups' => new external_multiple_structure( 1590 new external_single_structure( 1591 array( 1592 'id' => new external_value(PARAM_INT, 'ID of the group'), 1593 'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'), 1594 'description' => new external_value(PARAM_RAW, 'group description text', VALUE_OPTIONAL), 1595 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT), 1596 'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase', VALUE_OPTIONAL), 1597 'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL), 1598 'visibility' => new external_value(PARAM_TEXT, 1599 'group visibility mode. 0 = Visible to all. 1 = Visible to members. ' 1600 . '2 = See own membership. 3 = Membership is hidden.', VALUE_OPTIONAL), 1601 'participation' => new external_value(PARAM_BOOL, 1602 'activity participation enabled? Only for "all" and "members" visibility', VALUE_OPTIONAL), 1603 'customfields' => self::build_custom_fields_parameters_structure(), 1604 ) 1605 ), 'List of group objects. A group is found by the id, then all other details provided will be updated.' 1606 ) 1607 ) 1608 ); 1609 } 1610 1611 /** 1612 * Update groups 1613 * 1614 * @param array $groups 1615 * @return null 1616 * @since Moodle 3.6 1617 */ 1618 public static function update_groups($groups) { 1619 global $CFG, $DB; 1620 require_once("$CFG->dirroot/group/lib.php"); 1621 1622 $params = self::validate_parameters(self::update_groups_parameters(), array('groups' => $groups)); 1623 1624 $transaction = $DB->start_delegated_transaction(); 1625 1626 foreach ($params['groups'] as $group) { 1627 $group = (object) $group; 1628 1629 if (trim($group->name) == '') { 1630 throw new invalid_parameter_exception('Invalid group name'); 1631 } 1632 1633 if (!$currentgroup = $DB->get_record('groups', array('id' => $group->id))) { 1634 throw new invalid_parameter_exception("Group $group->id does not exist"); 1635 } 1636 1637 // Check if the modified group name already exists in the course. 1638 if ($group->name != $currentgroup->name and 1639 $DB->get_record('groups', array('courseid' => $currentgroup->courseid, 'name' => $group->name))) { 1640 throw new invalid_parameter_exception('A different group with the same name already exists in the course'); 1641 } 1642 1643 if (isset($group->visibility) || isset($group->participation)) { 1644 $hasmembers = $DB->record_exists('groups_members', ['groupid' => $group->id]); 1645 if (isset($group->visibility)) { 1646 // Validate visibility. 1647 self::validate_visibility($group->visibility); 1648 if ($hasmembers && $group->visibility != $currentgroup->visibility) { 1649 throw new invalid_parameter_exception( 1650 'The visibility of this group cannot be changed as it currently has members.'); 1651 } 1652 } else { 1653 $group->visibility = $currentgroup->visibility; 1654 } 1655 if (isset($group->participation) && $hasmembers && $group->participation != $currentgroup->participation) { 1656 throw new invalid_parameter_exception( 1657 'The participation mode of this group cannot be changed as it currently has members.'); 1658 } 1659 } 1660 1661 $group->courseid = $currentgroup->courseid; 1662 1663 // Now security checks. 1664 $context = context_course::instance($group->courseid); 1665 try { 1666 self::validate_context($context); 1667 } catch (Exception $e) { 1668 $exceptionparam = new stdClass(); 1669 $exceptionparam->message = $e->getMessage(); 1670 $exceptionparam->courseid = $group->courseid; 1671 throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam); 1672 } 1673 require_capability('moodle/course:managegroups', $context); 1674 1675 if (!empty($group->description)) { 1676 $group->descriptionformat = util::validate_format($group->descriptionformat); 1677 } 1678 1679 // Custom fields. 1680 if (!empty($group->customfields)) { 1681 foreach ($group->customfields as $field) { 1682 $fieldname = self::build_custom_field_name($field['shortname']); 1683 $group->{$fieldname} = $field['value']; 1684 } 1685 } 1686 1687 groups_update_group($group); 1688 } 1689 1690 $transaction->allow_commit(); 1691 1692 return null; 1693 } 1694 1695 /** 1696 * Returns description of method result value 1697 * 1698 * @return null 1699 * @since Moodle 3.6 1700 */ 1701 public static function update_groups_returns() { 1702 return null; 1703 } 1704 1705 /** 1706 * Builds a structure for custom fields parameters. 1707 * 1708 * @return \core_external\external_multiple_structure 1709 */ 1710 protected static function build_custom_fields_parameters_structure(): external_multiple_structure { 1711 return new external_multiple_structure( 1712 new external_single_structure([ 1713 'shortname' => new external_value(PARAM_ALPHANUMEXT, 'The shortname of the custom field'), 1714 'value' => new external_value(PARAM_RAW, 'The value of the custom field'), 1715 ]), 'Custom fields', VALUE_OPTIONAL 1716 ); 1717 } 1718 1719 /** 1720 * Builds a structure for custom fields returns. 1721 * 1722 * @return \core_external\external_multiple_structure 1723 */ 1724 protected static function build_custom_fields_returns_structure(): external_multiple_structure { 1725 return new external_multiple_structure( 1726 new external_single_structure([ 1727 'name' => new external_value(PARAM_RAW, 'The name of the custom field'), 1728 'shortname' => new external_value(PARAM_RAW, 1729 'The shortname of the custom field - to be able to build the field class in the code'), 1730 'type' => new external_value(PARAM_ALPHANUMEXT, 1731 'The type of the custom field - text field, checkbox...'), 1732 'valueraw' => new external_value(PARAM_RAW, 'The raw value of the custom field'), 1733 'value' => new external_value(PARAM_RAW, 'The value of the custom field'), 1734 ]), 'Custom fields', VALUE_OPTIONAL 1735 ); 1736 } 1737 1738 /** 1739 * Builds a suitable name of a custom field for a custom field handler based on provided shortname. 1740 * 1741 * @param string $shortname shortname to use. 1742 * @return string 1743 */ 1744 protected static function build_custom_field_name(string $shortname): string { 1745 return 'customfield_' . $shortname; 1746 } 1747 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body