Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

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