2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
17 use core_external\external_api
;
18 use core_external\external_format_value
;
19 use core_external\external_function_parameters
;
20 use core_external\external_multiple_structure
;
21 use core_external\external_single_structure
;
22 use core_external\external_value
;
23 use core_external\external_warnings
;
24 use core_external\util
;
25 use core_group\visibility
;
28 * Group external functions
32 * @copyright 2011 Jerome Mouneyrac
33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 class core_group_external
extends external_api
{
40 * Validate visibility.
42 * @param int $visibility Visibility string, must one of the visibility class constants.
43 * @throws invalid_parameter_exception if visibility is not an allowed value.
45 protected static function validate_visibility(int $visibility): void
{
47 GROUPS_VISIBILITY_ALL
,
48 GROUPS_VISIBILITY_MEMBERS
,
49 GROUPS_VISIBILITY_OWN
,
50 GROUPS_VISIBILITY_NONE
,
52 if (!array_key_exists($visibility, $allowed)) {
53 throw new invalid_parameter_exception('Invalid group visibility provided. Must be one of '
54 . join(',', $allowed));
59 * Returns description of method parameters
61 * @return external_function_parameters
64 public static function create_groups_parameters() {
65 return new external_function_parameters(
67 'groups' => new external_multiple_structure(
68 new external_single_structure(
70 'courseid' => new external_value(PARAM_INT
, 'id of course'),
71 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
72 'description' => new external_value(PARAM_RAW
, 'group description text'),
73 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
74 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase', VALUE_OPTIONAL
),
75 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
),
76 'visibility' => new external_value(PARAM_INT
,
77 'group visibility mode. 0 = Visible to all. 1 = Visible to members. '
78 . '2 = See own membership. 3 = Membership is hidden. default: 0',
80 'participation' => new external_value(PARAM_BOOL
,
81 'activity participation enabled? Only for "all" and "members" visibility. Default true.',
84 ), 'List of group object. A group has a courseid, a name, a description and an enrolment key.'
93 * @param array $groups array of group description arrays (with keys groupname and courseid)
94 * @return array of newly created groups
97 public static function create_groups($groups) {
99 require_once("$CFG->dirroot/group/lib.php");
101 $params = self
::validate_parameters(self
::create_groups_parameters(), array('groups'=>$groups));
103 $transaction = $DB->start_delegated_transaction();
107 foreach ($params['groups'] as $group) {
108 $group = (object)$group;
110 if (trim($group->name
) == '') {
111 throw new invalid_parameter_exception('Invalid group name');
113 if ($DB->get_record('groups', array('courseid'=>$group->courseid
, 'name'=>$group->name
))) {
114 throw new invalid_parameter_exception('Group with the same name already exists in the course');
117 // now security checks
118 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
120 self
::validate_context($context);
121 } catch (Exception
$e) {
122 $exceptionparam = new stdClass();
123 $exceptionparam->message
= $e->getMessage();
124 $exceptionparam->courseid
= $group->courseid
;
125 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
127 require_capability('moodle/course:managegroups', $context);
130 $group->descriptionformat
= util
::validate_format($group->descriptionformat
);
132 // Validate visibility.
133 self
::validate_visibility($group->visibility
);
135 // finally create the group
136 $group->id
= groups_create_group($group, false);
137 if (!isset($group->enrolmentkey
)) {
138 $group->enrolmentkey
= '';
140 if (!isset($group->idnumber
)) {
141 $group->idnumber
= '';
144 $groups[] = (array)$group;
147 $transaction->allow_commit();
153 * Returns description of method result value
155 * @return \core_external\external_description
158 public static function create_groups_returns() {
159 return new external_multiple_structure(
160 new external_single_structure(
162 'id' => new external_value(PARAM_INT
, 'group record id'),
163 'courseid' => new external_value(PARAM_INT
, 'id of course'),
164 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
165 'description' => new external_value(PARAM_RAW
, 'group description text'),
166 'descriptionformat' => new external_format_value('description'),
167 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
168 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
169 'visibility' => new external_value(PARAM_INT
,
170 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. '
171 . '3 = Membership is hidden.'),
172 'participation' => new external_value(PARAM_BOOL
, 'participation mode'),
174 ), 'List of group object. A group has an id, a courseid, a name, a description and an enrolment key.'
179 * Returns description of method parameters
181 * @return external_function_parameters
184 public static function get_groups_parameters() {
185 return new external_function_parameters(
187 'groupids' => new external_multiple_structure(new external_value(PARAM_INT
, 'Group ID')
188 ,'List of group id. A group id is an integer.'),
194 * Get groups definition specified by ids
196 * @param array $groupids arrays of group ids
197 * @return array of group objects (id, courseid, name, enrolmentkey)
200 public static function get_groups($groupids) {
201 $params = self
::validate_parameters(self
::get_groups_parameters(), array('groupids'=>$groupids));
204 foreach ($params['groupids'] as $groupid) {
206 $group = groups_get_group($groupid, 'id, courseid, name, idnumber, description, descriptionformat, enrolmentkey, '
207 . 'visibility, participation', MUST_EXIST
);
209 // now security checks
210 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
212 self
::validate_context($context);
213 } catch (Exception
$e) {
214 $exceptionparam = new stdClass();
215 $exceptionparam->message
= $e->getMessage();
216 $exceptionparam->courseid
= $group->courseid
;
217 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
219 require_capability('moodle/course:managegroups', $context);
221 list($group->description
, $group->descriptionformat
) =
222 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
223 $context, 'group', 'description', $group->id
);
225 $groups[] = (array)$group;
232 * Returns description of method result value
234 * @return \core_external\external_description
237 public static function get_groups_returns() {
238 return new external_multiple_structure(
239 new external_single_structure(
241 'id' => new external_value(PARAM_INT
, 'group record id'),
242 'courseid' => new external_value(PARAM_INT
, 'id of course'),
243 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
244 'description' => new external_value(PARAM_RAW
, 'group description text'),
245 'descriptionformat' => new external_format_value('description'),
246 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
247 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
248 'visibility' => new external_value(PARAM_INT
,
249 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. '
250 . '3 = Membership is hidden.'),
251 'participation' => new external_value(PARAM_BOOL
, 'participation mode'),
258 * Returns description of method parameters
260 * @return external_function_parameters
263 public static function get_course_groups_parameters() {
264 return new external_function_parameters(
266 'courseid' => new external_value(PARAM_INT
, 'id of course'),
272 * Get all groups in the specified course
274 * @param int $courseid id of course
275 * @return array of group objects (id, courseid, name, enrolmentkey)
278 public static function get_course_groups($courseid) {
279 $params = self
::validate_parameters(self
::get_course_groups_parameters(), array('courseid'=>$courseid));
281 // now security checks
282 $context = context_course
::instance($params['courseid'], IGNORE_MISSING
);
284 self
::validate_context($context);
285 } catch (Exception
$e) {
286 $exceptionparam = new stdClass();
287 $exceptionparam->message
= $e->getMessage();
288 $exceptionparam->courseid
= $params['courseid'];
289 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
291 require_capability('moodle/course:managegroups', $context);
293 $gs = groups_get_all_groups($params['courseid'], 0, 0,
294 'g.id, g.courseid, g.name, g.idnumber, g.description, g.descriptionformat, g.enrolmentkey, '
295 . 'g.visibility, g.participation');
298 foreach ($gs as $group) {
299 list($group->description
, $group->descriptionformat
) =
300 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
301 $context, 'group', 'description', $group->id
);
302 $groups[] = (array)$group;
309 * Returns description of method result value
311 * @return \core_external\external_description
314 public static function get_course_groups_returns() {
315 return new external_multiple_structure(
316 new external_single_structure(
318 'id' => new external_value(PARAM_INT
, 'group record id'),
319 'courseid' => new external_value(PARAM_INT
, 'id of course'),
320 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
321 'description' => new external_value(PARAM_RAW
, 'group description text'),
322 'descriptionformat' => new external_format_value('description'),
323 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
324 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
325 'visibility' => new external_value(PARAM_INT
,
326 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. '
327 . '3 = Membership is hidden.'),
328 'participation' => new external_value(PARAM_BOOL
, 'participation mode'),
335 * Returns description of method parameters
337 * @return external_function_parameters
340 public static function delete_groups_parameters() {
341 return new external_function_parameters(
343 'groupids' => new external_multiple_structure(new external_value(PARAM_INT
, 'Group ID')),
351 * @param array $groupids array of group ids
354 public static function delete_groups($groupids) {
356 require_once("$CFG->dirroot/group/lib.php");
358 $params = self
::validate_parameters(self
::delete_groups_parameters(), array('groupids'=>$groupids));
360 $transaction = $DB->start_delegated_transaction();
362 foreach ($params['groupids'] as $groupid) {
364 $groupid = validate_param($groupid, PARAM_INT
);
365 if (!$group = groups_get_group($groupid, '*', IGNORE_MISSING
)) {
366 // silently ignore attempts to delete nonexisting groups
370 // now security checks
371 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
373 self
::validate_context($context);
374 } catch (Exception
$e) {
375 $exceptionparam = new stdClass();
376 $exceptionparam->message
= $e->getMessage();
377 $exceptionparam->courseid
= $group->courseid
;
378 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
380 require_capability('moodle/course:managegroups', $context);
382 groups_delete_group($group);
385 $transaction->allow_commit();
389 * Returns description of method result value
394 public static function delete_groups_returns() {
400 * Returns description of method parameters
402 * @return external_function_parameters
405 public static function get_group_members_parameters() {
406 return new external_function_parameters(
408 'groupids' => new external_multiple_structure(new external_value(PARAM_INT
, 'Group ID')),
414 * Return all members for a group
416 * @param array $groupids array of group ids
417 * @return array with group id keys containing arrays of user ids
420 public static function get_group_members($groupids) {
423 $params = self
::validate_parameters(self
::get_group_members_parameters(), array('groupids'=>$groupids));
425 foreach ($params['groupids'] as $groupid) {
427 $group = groups_get_group($groupid, 'id, courseid, name, enrolmentkey', MUST_EXIST
);
428 // now security checks
429 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
431 self
::validate_context($context);
432 } catch (Exception
$e) {
433 $exceptionparam = new stdClass();
434 $exceptionparam->message
= $e->getMessage();
435 $exceptionparam->courseid
= $group->courseid
;
436 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
438 require_capability('moodle/course:managegroups', $context);
440 $groupmembers = groups_get_members($group->id
, 'u.id', 'lastname ASC, firstname ASC');
442 $members[] = array('groupid'=>$groupid, 'userids'=>array_keys($groupmembers));
449 * Returns description of method result value
451 * @return \core_external\external_description
454 public static function get_group_members_returns() {
455 return new external_multiple_structure(
456 new external_single_structure(
458 'groupid' => new external_value(PARAM_INT
, 'group record id'),
459 'userids' => new external_multiple_structure(new external_value(PARAM_INT
, 'user id')),
467 * Returns description of method parameters
469 * @return external_function_parameters
472 public static function add_group_members_parameters() {
473 return new external_function_parameters(
475 'members'=> new external_multiple_structure(
476 new external_single_structure(
478 'groupid' => new external_value(PARAM_INT
, 'group record id'),
479 'userid' => new external_value(PARAM_INT
, 'user id'),
490 * @param array $members of arrays with keys userid, groupid
493 public static function add_group_members($members) {
495 require_once("$CFG->dirroot/group/lib.php");
497 $params = self
::validate_parameters(self
::add_group_members_parameters(), array('members'=>$members));
499 $transaction = $DB->start_delegated_transaction();
500 foreach ($params['members'] as $member) {
502 $groupid = $member['groupid'];
503 $userid = $member['userid'];
505 $group = groups_get_group($groupid, '*', MUST_EXIST
);
506 $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0, 'mnethostid'=>$CFG->mnet_localhost_id
), '*', MUST_EXIST
);
508 // now security checks
509 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
511 self
::validate_context($context);
512 } catch (Exception
$e) {
513 $exceptionparam = new stdClass();
514 $exceptionparam->message
= $e->getMessage();
515 $exceptionparam->courseid
= $group->courseid
;
516 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
518 require_capability('moodle/course:managegroups', $context);
520 // now make sure user is enrolled in course - this is mandatory requirement,
521 // unfortunately this is slow
522 if (!is_enrolled($context, $userid)) {
523 throw new invalid_parameter_exception('Only enrolled users may be members of groups');
526 groups_add_member($group, $user);
529 $transaction->allow_commit();
533 * Returns description of method result value
538 public static function add_group_members_returns() {
544 * Returns description of method parameters
546 * @return external_function_parameters
549 public static function delete_group_members_parameters() {
550 return new external_function_parameters(
552 'members'=> new external_multiple_structure(
553 new external_single_structure(
555 'groupid' => new external_value(PARAM_INT
, 'group record id'),
556 'userid' => new external_value(PARAM_INT
, 'user id'),
565 * Delete group members
567 * @param array $members of arrays with keys userid, groupid
570 public static function delete_group_members($members) {
572 require_once("$CFG->dirroot/group/lib.php");
574 $params = self
::validate_parameters(self
::delete_group_members_parameters(), array('members'=>$members));
576 $transaction = $DB->start_delegated_transaction();
578 foreach ($params['members'] as $member) {
580 $groupid = $member['groupid'];
581 $userid = $member['userid'];
583 $group = groups_get_group($groupid, '*', MUST_EXIST
);
584 $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0, 'mnethostid'=>$CFG->mnet_localhost_id
), '*', MUST_EXIST
);
586 // now security checks
587 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
589 self
::validate_context($context);
590 } catch (Exception
$e) {
591 $exceptionparam = new stdClass();
592 $exceptionparam->message
= $e->getMessage();
593 $exceptionparam->courseid
= $group->courseid
;
594 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
596 require_capability('moodle/course:managegroups', $context);
598 if (!groups_remove_member_allowed($group, $user)) {
599 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context));
600 throw new moodle_exception('errorremovenotpermitted', 'group', '', $fullname);
602 groups_remove_member($group, $user);
605 $transaction->allow_commit();
609 * Returns description of method result value
614 public static function delete_group_members_returns() {
619 * Returns description of method parameters
621 * @return external_function_parameters
624 public static function create_groupings_parameters() {
625 return new external_function_parameters(
627 'groupings' => new external_multiple_structure(
628 new external_single_structure(
630 'courseid' => new external_value(PARAM_INT
, 'id of course'),
631 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
632 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
633 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
634 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
)
636 ), 'List of grouping object. A grouping has a courseid, a name and a description.'
645 * @param array $groupings array of grouping description arrays (with keys groupname and courseid)
646 * @return array of newly created groupings
649 public static function create_groupings($groupings) {
651 require_once("$CFG->dirroot/group/lib.php");
653 $params = self
::validate_parameters(self
::create_groupings_parameters(), array('groupings'=>$groupings));
655 $transaction = $DB->start_delegated_transaction();
657 $groupings = array();
659 foreach ($params['groupings'] as $grouping) {
660 $grouping = (object)$grouping;
662 if (trim($grouping->name
) == '') {
663 throw new invalid_parameter_exception('Invalid grouping name');
665 if ($DB->count_records('groupings', array('courseid'=>$grouping->courseid
, 'name'=>$grouping->name
))) {
666 throw new invalid_parameter_exception('Grouping with the same name already exists in the course');
669 // Now security checks .
670 $context = context_course
::instance($grouping->courseid
);
672 self
::validate_context($context);
673 } catch (Exception
$e) {
674 $exceptionparam = new stdClass();
675 $exceptionparam->message
= $e->getMessage();
676 $exceptionparam->courseid
= $grouping->courseid
;
677 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
679 require_capability('moodle/course:managegroups', $context);
681 $grouping->descriptionformat
= util
::validate_format($grouping->descriptionformat
);
683 // Finally create the grouping.
684 $grouping->id
= groups_create_grouping($grouping);
685 $groupings[] = (array)$grouping;
688 $transaction->allow_commit();
694 * Returns description of method result value
696 * @return \core_external\external_description
699 public static function create_groupings_returns() {
700 return new external_multiple_structure(
701 new external_single_structure(
703 'id' => new external_value(PARAM_INT
, 'grouping record id'),
704 'courseid' => new external_value(PARAM_INT
, 'id of course'),
705 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
706 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
707 'descriptionformat' => new external_format_value('description'),
708 'idnumber' => new external_value(PARAM_RAW
, 'id number')
710 ), 'List of grouping object. A grouping has an id, a courseid, a name and a description.'
715 * Returns description of method parameters
717 * @return external_function_parameters
720 public static function update_groupings_parameters() {
721 return new external_function_parameters(
723 'groupings' => new external_multiple_structure(
724 new external_single_structure(
726 'id' => new external_value(PARAM_INT
, 'id of grouping'),
727 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
728 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
729 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
730 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
)
732 ), 'List of grouping object. A grouping has a courseid, a name and a description.'
741 * @param array $groupings array of grouping description arrays (with keys groupname and courseid)
742 * @return array of newly updated groupings
745 public static function update_groupings($groupings) {
747 require_once("$CFG->dirroot/group/lib.php");
749 $params = self
::validate_parameters(self
::update_groupings_parameters(), array('groupings'=>$groupings));
751 $transaction = $DB->start_delegated_transaction();
753 foreach ($params['groupings'] as $grouping) {
754 $grouping = (object)$grouping;
756 if (trim($grouping->name
) == '') {
757 throw new invalid_parameter_exception('Invalid grouping name');
760 if (! $currentgrouping = $DB->get_record('groupings', array('id'=>$grouping->id
))) {
761 throw new invalid_parameter_exception("Grouping $grouping->id does not exist in the course");
764 // Check if the new modified grouping name already exists in the course.
765 if ($grouping->name
!= $currentgrouping->name
and
766 $DB->count_records('groupings', array('courseid'=>$currentgrouping->courseid
, 'name'=>$grouping->name
))) {
767 throw new invalid_parameter_exception('A different grouping with the same name already exists in the course');
770 $grouping->courseid
= $currentgrouping->courseid
;
772 // Now security checks.
773 $context = context_course
::instance($grouping->courseid
);
775 self
::validate_context($context);
776 } catch (Exception
$e) {
777 $exceptionparam = new stdClass();
778 $exceptionparam->message
= $e->getMessage();
779 $exceptionparam->courseid
= $grouping->courseid
;
780 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
782 require_capability('moodle/course:managegroups', $context);
784 // We must force allways FORMAT_HTML.
785 $grouping->descriptionformat
= util
::validate_format($grouping->descriptionformat
);
787 // Finally update the grouping.
788 groups_update_grouping($grouping);
791 $transaction->allow_commit();
797 * Returns description of method result value
799 * @return \core_external\external_description
802 public static function update_groupings_returns() {
807 * Returns description of method parameters
809 * @return external_function_parameters
812 public static function get_groupings_parameters() {
813 return new external_function_parameters(
815 'groupingids' => new external_multiple_structure(new external_value(PARAM_INT
, 'grouping ID')
816 , 'List of grouping id. A grouping id is an integer.'),
817 'returngroups' => new external_value(PARAM_BOOL
, 'return associated groups', VALUE_DEFAULT
, 0)
823 * Get groupings definition specified by ids
825 * @param array $groupingids arrays of grouping ids
826 * @param boolean $returngroups return the associated groups if true. The default is false.
827 * @return array of grouping objects (id, courseid, name)
830 public static function get_groupings($groupingids, $returngroups = false) {
832 require_once("$CFG->dirroot/group/lib.php");
833 require_once("$CFG->libdir/filelib.php");
835 $params = self
::validate_parameters(self
::get_groupings_parameters(),
836 array('groupingids' => $groupingids,
837 'returngroups' => $returngroups));
839 $groupings = array();
840 foreach ($params['groupingids'] as $groupingid) {
842 $grouping = groups_get_grouping($groupingid, '*', MUST_EXIST
);
844 // Now security checks.
845 $context = context_course
::instance($grouping->courseid
);
847 self
::validate_context($context);
848 } catch (Exception
$e) {
849 $exceptionparam = new stdClass();
850 $exceptionparam->message
= $e->getMessage();
851 $exceptionparam->courseid
= $grouping->courseid
;
852 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
854 require_capability('moodle/course:managegroups', $context);
856 list($grouping->description
, $grouping->descriptionformat
) =
857 \core_external\util
::format_text($grouping->description
, $grouping->descriptionformat
,
858 $context, 'grouping', 'description', $grouping->id
);
860 $groupingarray = (array)$grouping;
862 if ($params['returngroups']) {
863 $grouprecords = $DB->get_records_sql("SELECT * FROM {groups} g INNER JOIN {groupings_groups} gg ".
864 "ON g.id = gg.groupid WHERE gg.groupingid = ? ".
865 "ORDER BY groupid", array($groupingid));
868 foreach ($grouprecords as $grouprecord) {
869 list($grouprecord->description
, $grouprecord->descriptionformat
) =
870 \core_external\util
::format_text($grouprecord->description
, $grouprecord->descriptionformat
,
871 $context, 'group', 'description', $grouprecord->groupid
);
872 $groups[] = array('id' => $grouprecord->groupid
,
873 'name' => $grouprecord->name
,
874 'idnumber' => $grouprecord->idnumber
,
875 'description' => $grouprecord->description
,
876 'descriptionformat' => $grouprecord->descriptionformat
,
877 'enrolmentkey' => $grouprecord->enrolmentkey
,
878 'courseid' => $grouprecord->courseid
881 $groupingarray['groups'] = $groups;
884 $groupings[] = $groupingarray;
891 * Returns description of method result value
893 * @return \core_external\external_description
896 public static function get_groupings_returns() {
897 return new external_multiple_structure(
898 new external_single_structure(
900 'id' => new external_value(PARAM_INT
, 'grouping record id'),
901 'courseid' => new external_value(PARAM_INT
, 'id of course'),
902 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
903 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
904 'descriptionformat' => new external_format_value('description'),
905 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
906 'groups' => new external_multiple_structure(
907 new external_single_structure(
909 'id' => new external_value(PARAM_INT
, 'group record id'),
910 'courseid' => new external_value(PARAM_INT
, 'id of course'),
911 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
912 'description' => new external_value(PARAM_RAW
, 'group description text'),
913 'descriptionformat' => new external_format_value('description'),
914 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
915 'idnumber' => new external_value(PARAM_RAW
, 'id number')
918 'optional groups', VALUE_OPTIONAL
)
925 * Returns description of method parameters
927 * @return external_function_parameters
930 public static function get_course_groupings_parameters() {
931 return new external_function_parameters(
933 'courseid' => new external_value(PARAM_INT
, 'id of course'),
939 * Get all groupings in the specified course
941 * @param int $courseid id of course
942 * @return array of grouping objects (id, courseid, name, enrolmentkey)
945 public static function get_course_groupings($courseid) {
947 require_once("$CFG->dirroot/group/lib.php");
948 require_once("$CFG->libdir/filelib.php");
950 $params = self
::validate_parameters(self
::get_course_groupings_parameters(), array('courseid'=>$courseid));
952 // Now security checks.
953 $context = context_course
::instance($params['courseid']);
956 self
::validate_context($context);
957 } catch (Exception
$e) {
958 $exceptionparam = new stdClass();
959 $exceptionparam->message
= $e->getMessage();
960 $exceptionparam->courseid
= $params['courseid'];
961 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
963 require_capability('moodle/course:managegroups', $context);
965 $gs = groups_get_all_groupings($params['courseid']);
967 $groupings = array();
968 foreach ($gs as $grouping) {
969 list($grouping->description
, $grouping->descriptionformat
) =
970 \core_external\util
::format_text($grouping->description
, $grouping->descriptionformat
,
971 $context, 'grouping', 'description', $grouping->id
);
972 $groupings[] = (array)$grouping;
979 * Returns description of method result value
981 * @return \core_external\external_description
984 public static function get_course_groupings_returns() {
985 return new external_multiple_structure(
986 new external_single_structure(
988 'id' => new external_value(PARAM_INT
, 'grouping record id'),
989 'courseid' => new external_value(PARAM_INT
, 'id of course'),
990 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
991 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
992 'descriptionformat' => new external_format_value('description'),
993 'idnumber' => new external_value(PARAM_RAW
, 'id number')
1000 * Returns description of method parameters
1002 * @return external_function_parameters
1005 public static function delete_groupings_parameters() {
1006 return new external_function_parameters(
1008 'groupingids' => new external_multiple_structure(new external_value(PARAM_INT
, 'grouping ID')),
1016 * @param array $groupingids array of grouping ids
1020 public static function delete_groupings($groupingids) {
1022 require_once("$CFG->dirroot/group/lib.php");
1024 $params = self
::validate_parameters(self
::delete_groupings_parameters(), array('groupingids'=>$groupingids));
1026 $transaction = $DB->start_delegated_transaction();
1028 foreach ($params['groupingids'] as $groupingid) {
1030 if (!$grouping = groups_get_grouping($groupingid)) {
1031 // Silently ignore attempts to delete nonexisting groupings.
1035 // Now security checks.
1036 $context = context_course
::instance($grouping->courseid
);
1038 self
::validate_context($context);
1039 } catch (Exception
$e) {
1040 $exceptionparam = new stdClass();
1041 $exceptionparam->message
= $e->getMessage();
1042 $exceptionparam->courseid
= $grouping->courseid
;
1043 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
1045 require_capability('moodle/course:managegroups', $context);
1047 groups_delete_grouping($grouping);
1050 $transaction->allow_commit();
1054 * Returns description of method result value
1056 * @return \core_external\external_description
1059 public static function delete_groupings_returns() {
1064 * Returns description of method parameters
1066 * @return external_function_parameters
1069 public static function assign_grouping_parameters() {
1070 return new external_function_parameters(
1072 'assignments'=> new external_multiple_structure(
1073 new external_single_structure(
1075 'groupingid' => new external_value(PARAM_INT
, 'grouping record id'),
1076 'groupid' => new external_value(PARAM_INT
, 'group record id'),
1085 * Assign a group to a grouping
1087 * @param array $assignments of arrays with keys groupid, groupingid
1091 public static function assign_grouping($assignments) {
1093 require_once("$CFG->dirroot/group/lib.php");
1095 $params = self
::validate_parameters(self
::assign_grouping_parameters(), array('assignments'=>$assignments));
1097 $transaction = $DB->start_delegated_transaction();
1098 foreach ($params['assignments'] as $assignment) {
1100 $groupingid = $assignment['groupingid'];
1101 $groupid = $assignment['groupid'];
1103 $grouping = groups_get_grouping($groupingid, 'id, courseid', MUST_EXIST
);
1104 $group = groups_get_group($groupid, 'id, courseid', MUST_EXIST
);
1106 if ($DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) {
1107 // Continue silently if the group is yet assigned to the grouping.
1111 // Now security checks.
1112 $context = context_course
::instance($grouping->courseid
);
1114 self
::validate_context($context);
1115 } catch (Exception
$e) {
1116 $exceptionparam = new stdClass();
1117 $exceptionparam->message
= $e->getMessage();
1118 $exceptionparam->courseid
= $group->courseid
;
1119 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
1121 require_capability('moodle/course:managegroups', $context);
1123 groups_assign_grouping($groupingid, $groupid);
1126 $transaction->allow_commit();
1130 * Returns description of method result value
1135 public static function assign_grouping_returns() {
1140 * Returns description of method parameters
1142 * @return external_function_parameters
1145 public static function unassign_grouping_parameters() {
1146 return new external_function_parameters(
1148 'unassignments'=> new external_multiple_structure(
1149 new external_single_structure(
1151 'groupingid' => new external_value(PARAM_INT
, 'grouping record id'),
1152 'groupid' => new external_value(PARAM_INT
, 'group record id'),
1161 * Unassign a group from a grouping
1163 * @param array $unassignments of arrays with keys groupid, groupingid
1167 public static function unassign_grouping($unassignments) {
1169 require_once("$CFG->dirroot/group/lib.php");
1171 $params = self
::validate_parameters(self
::unassign_grouping_parameters(), array('unassignments'=>$unassignments));
1173 $transaction = $DB->start_delegated_transaction();
1174 foreach ($params['unassignments'] as $unassignment) {
1176 $groupingid = $unassignment['groupingid'];
1177 $groupid = $unassignment['groupid'];
1179 $grouping = groups_get_grouping($groupingid, 'id, courseid', MUST_EXIST
);
1180 $group = groups_get_group($groupid, 'id, courseid', MUST_EXIST
);
1182 if (!$DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) {
1183 // Continue silently if the group is not assigned to the grouping.
1187 // Now security checks.
1188 $context = context_course
::instance($grouping->courseid
);
1190 self
::validate_context($context);
1191 } catch (Exception
$e) {
1192 $exceptionparam = new stdClass();
1193 $exceptionparam->message
= $e->getMessage();
1194 $exceptionparam->courseid
= $group->courseid
;
1195 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
1197 require_capability('moodle/course:managegroups', $context);
1199 groups_unassign_grouping($groupingid, $groupid);
1202 $transaction->allow_commit();
1206 * Returns description of method result value
1211 public static function unassign_grouping_returns() {
1216 * Returns description of method parameters
1218 * @return external_function_parameters
1221 public static function get_course_user_groups_parameters() {
1222 return new external_function_parameters(
1224 'courseid' => new external_value(PARAM_INT
,
1225 'Id of course (empty or 0 for all the courses where the user is enrolled).', VALUE_DEFAULT
, 0),
1226 'userid' => new external_value(PARAM_INT
, 'Id of user (empty or 0 for current user).', VALUE_DEFAULT
, 0),
1227 'groupingid' => new external_value(PARAM_INT
, 'returns only groups in the specified grouping', VALUE_DEFAULT
, 0)
1233 * Get all groups in the specified course for the specified user.
1235 * @throws moodle_exception
1236 * @param int $courseid id of course.
1237 * @param int $userid id of user.
1238 * @param int $groupingid optional returns only groups in the specified grouping.
1239 * @return array of group objects (id, name, description, format) and possible warnings.
1242 public static function get_course_user_groups($courseid = 0, $userid = 0, $groupingid = 0) {
1245 // Warnings array, it can be empty at the end but is mandatory.
1246 $warnings = array();
1249 'courseid' => $courseid,
1250 'userid' => $userid,
1251 'groupingid' => $groupingid
1253 $params = self
::validate_parameters(self
::get_course_user_groups_parameters(), $params);
1255 $courseid = $params['courseid'];
1256 $userid = $params['userid'];
1257 $groupingid = $params['groupingid'];
1260 if (empty($userid)) {
1261 $userid = $USER->id
;
1263 $user = core_user
::get_user($userid, '*', MUST_EXIST
);
1264 core_user
::require_active_user($user);
1268 if (empty($courseid)) {
1269 $courses = enrol_get_users_courses($userid, true);
1270 $checkenrolments = false; // No need to check enrolments here since they are my courses.
1272 $courses = array($courseid => get_course($courseid));
1273 $checkenrolments = true;
1277 list($courses, $warnings) = util
::validate_courses(array_keys($courses), $courses, true);
1279 $usergroups = array();
1280 foreach ($courses as $course) {
1281 // Check if we have permissions for retrieve the information.
1282 if ($userid != $USER->id
&& !has_capability('moodle/course:managegroups', $course->context
)) {
1283 $warnings[] = array(
1285 'itemid' => $course->id
,
1286 'warningcode' => 'cannotmanagegroups',
1287 'message' => "User $USER->id cannot manage groups in course $course->id",
1292 // Check if the user being check is enrolled in the given course.
1293 if ($checkenrolments && !is_enrolled($course->context
, $userid)) {
1294 // We return a warning because the function does not fail for not enrolled users.
1295 $warnings[] = array(
1297 'itemid' => $course->id
,
1298 'warningcode' => 'notenrolled',
1299 'message' => "User $userid is not enrolled in course $course->id",
1303 $groups = groups_get_all_groups($course->id
, $userid, $groupingid,
1304 'g.id, g.name, g.description, g.descriptionformat, g.idnumber');
1306 foreach ($groups as $group) {
1307 list($group->description
, $group->descriptionformat
) =
1308 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
1309 $course->context
, 'group', 'description', $group->id
);
1310 $group->courseid
= $course->id
;
1311 $usergroups[] = $group;
1316 'groups' => $usergroups,
1317 'warnings' => $warnings
1323 * Returns description of method result value.
1325 * @return \core_external\external_description A single structure containing groups and possible warnings.
1328 public static function get_course_user_groups_returns() {
1329 return new external_single_structure(
1331 'groups' => new external_multiple_structure(self
::group_description()),
1332 'warnings' => new external_warnings(),
1338 * Create group return value description.
1340 * @return external_single_structure The group description
1342 public static function group_description() {
1343 return new external_single_structure(
1345 'id' => new external_value(PARAM_INT
, 'group record id'),
1346 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
1347 'description' => new external_value(PARAM_RAW
, 'group description text'),
1348 'descriptionformat' => new external_format_value('description'),
1349 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
1350 'courseid' => new external_value(PARAM_INT
, 'course id', VALUE_OPTIONAL
),
1356 * Returns description of method parameters
1358 * @return external_function_parameters
1361 public static function get_activity_allowed_groups_parameters() {
1362 return new external_function_parameters(
1364 'cmid' => new external_value(PARAM_INT
, 'course module id'),
1365 'userid' => new external_value(PARAM_INT
, 'id of user, empty for current user', VALUE_DEFAULT
, 0)
1371 * Gets a list of groups that the user is allowed to access within the specified activity.
1373 * @throws moodle_exception
1374 * @param int $cmid course module id
1375 * @param int $userid id of user.
1376 * @return array of group objects (id, name, description, format) and possible warnings.
1379 public static function get_activity_allowed_groups($cmid, $userid = 0) {
1382 // Warnings array, it can be empty at the end but is mandatory.
1383 $warnings = array();
1389 $params = self
::validate_parameters(self
::get_activity_allowed_groups_parameters(), $params);
1390 $cmid = $params['cmid'];
1391 $userid = $params['userid'];
1393 $cm = get_coursemodule_from_id(null, $cmid, 0, false, MUST_EXIST
);
1396 $context = context_module
::instance($cm->id
);
1397 $coursecontext = context_course
::instance($cm->course
);
1398 self
::validate_context($context);
1400 if (empty($userid)) {
1401 $userid = $USER->id
;
1404 $user = core_user
::get_user($userid, '*', MUST_EXIST
);
1405 core_user
::require_active_user($user);
1407 // Check if we have permissions for retrieve the information.
1408 if ($user->id
!= $USER->id
) {
1409 if (!has_capability('moodle/course:managegroups', $context)) {
1410 throw new moodle_exception('accessdenied', 'admin');
1413 // Validate if the user is enrolled in the course.
1414 $course = get_course($cm->course
);
1415 if (!can_access_course($course, $user, '', true)) {
1416 // We return a warning because the function does not fail for not enrolled users.
1418 $warning['item'] = 'course';
1419 $warning['itemid'] = $cm->course
;
1420 $warning['warningcode'] = '1';
1421 $warning['message'] = "User $user->id cannot access course $cm->course";
1422 $warnings[] = $warning;
1426 $usergroups = array();
1427 if (empty($warnings)) {
1428 $groups = groups_get_activity_allowed_groups($cm, $user->id
);
1430 foreach ($groups as $group) {
1431 list($group->description
, $group->descriptionformat
) =
1432 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
1433 $coursecontext, 'group', 'description', $group->id
);
1434 $group->courseid
= $cm->course
;
1435 $usergroups[] = $group;
1440 'groups' => $usergroups,
1441 'canaccessallgroups' => has_capability('moodle/site:accessallgroups', $context, $user),
1442 'warnings' => $warnings
1448 * Returns description of method result value.
1450 * @return \core_external\external_description A single structure containing groups and possible warnings.
1453 public static function get_activity_allowed_groups_returns() {
1454 return new external_single_structure(
1456 'groups' => new external_multiple_structure(self
::group_description()),
1457 'canaccessallgroups' => new external_value(PARAM_BOOL
,
1458 'Whether the user will be able to access all the activity groups.', VALUE_OPTIONAL
),
1459 'warnings' => new external_warnings(),
1465 * Returns description of method parameters
1467 * @return external_function_parameters
1470 public static function get_activity_groupmode_parameters() {
1471 return new external_function_parameters(
1473 'cmid' => new external_value(PARAM_INT
, 'course module id')
1479 * Returns effective groupmode used in a given activity.
1481 * @throws moodle_exception
1482 * @param int $cmid course module id.
1483 * @return array containing the group mode and possible warnings.
1485 * @throws moodle_exception
1487 public static function get_activity_groupmode($cmid) {
1490 // Warnings array, it can be empty at the end but is mandatory.
1491 $warnings = array();
1496 $params = self
::validate_parameters(self
::get_activity_groupmode_parameters(), $params);
1497 $cmid = $params['cmid'];
1499 $cm = get_coursemodule_from_id(null, $cmid, 0, false, MUST_EXIST
);
1502 $context = context_module
::instance($cm->id
);
1503 self
::validate_context($context);
1505 $groupmode = groups_get_activity_groupmode($cm);
1508 'groupmode' => $groupmode,
1509 'warnings' => $warnings
1515 * Returns description of method result value.
1517 * @return \core_external\external_description
1520 public static function get_activity_groupmode_returns() {
1521 return new external_single_structure(
1523 'groupmode' => new external_value(PARAM_INT
, 'group mode:
1524 0 for no groups, 1 for separate groups, 2 for visible groups'),
1525 'warnings' => new external_warnings(),
1531 * Returns description of method parameters
1533 * @return external_function_parameters
1536 public static function update_groups_parameters() {
1537 return new external_function_parameters(
1539 'groups' => new external_multiple_structure(
1540 new external_single_structure(
1542 'id' => new external_value(PARAM_INT
, 'ID of the group'),
1543 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
1544 'description' => new external_value(PARAM_RAW
, 'group description text', VALUE_OPTIONAL
),
1545 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
1546 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase', VALUE_OPTIONAL
),
1547 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
),
1548 'visibility' => new external_value(PARAM_TEXT
,
1549 'group visibility mode. 0 = Visible to all. 1 = Visible to members. '
1550 . '2 = See own membership. 3 = Membership is hidden.', VALUE_OPTIONAL
),
1551 'participation' => new external_value(PARAM_BOOL
,
1552 'activity participation enabled? Only for "all" and "members" visibility', VALUE_OPTIONAL
),
1554 ), 'List of group objects. A group is found by the id, then all other details provided will be updated.'
1563 * @param array $groups
1567 public static function update_groups($groups) {
1569 require_once("$CFG->dirroot/group/lib.php");
1571 $params = self
::validate_parameters(self
::update_groups_parameters(), array('groups' => $groups));
1573 $transaction = $DB->start_delegated_transaction();
1575 foreach ($params['groups'] as $group) {
1576 $group = (object) $group;
1578 if (trim($group->name
) == '') {
1579 throw new invalid_parameter_exception('Invalid group name');
1582 if (!$currentgroup = $DB->get_record('groups', array('id' => $group->id
))) {
1583 throw new invalid_parameter_exception("Group $group->id does not exist");
1586 // Check if the modified group name already exists in the course.
1587 if ($group->name
!= $currentgroup->name
and
1588 $DB->get_record('groups', array('courseid' => $currentgroup->courseid
, 'name' => $group->name
))) {
1589 throw new invalid_parameter_exception('A different group with the same name already exists in the course');
1592 if (isset($group->visibility
) ||
isset($group->participation
)) {
1593 $hasmembers = $DB->record_exists('groups_members', ['groupid' => $group->id
]);
1594 if (isset($group->visibility
)) {
1595 // Validate visibility.
1596 self
::validate_visibility($group->visibility
);
1597 if ($hasmembers && $group->visibility
!= $currentgroup->visibility
) {
1598 throw new invalid_parameter_exception(
1599 'The visibility of this group cannot be changed as it currently has members.');
1602 $group->visibility
= $currentgroup->visibility
;
1604 if (isset($group->participation
) && $hasmembers && $group->participation
!= $currentgroup->participation
) {
1605 throw new invalid_parameter_exception(
1606 'The participation mode of this group cannot be changed as it currently has members.');
1610 $group->courseid
= $currentgroup->courseid
;
1612 // Now security checks.
1613 $context = context_course
::instance($group->courseid
);
1615 self
::validate_context($context);
1616 } catch (Exception
$e) {
1617 $exceptionparam = new stdClass();
1618 $exceptionparam->message
= $e->getMessage();
1619 $exceptionparam->courseid
= $group->courseid
;
1620 throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
1622 require_capability('moodle/course:managegroups', $context);
1624 if (!empty($group->description
)) {
1625 $group->descriptionformat
= util
::validate_format($group->descriptionformat
);
1628 groups_update_group($group);
1631 $transaction->allow_commit();
1637 * Returns description of method result value
1642 public static function update_groups_returns() {