Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 401 and 402] [Versions 401 and 403]

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