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 $group->name
= \core_external\util
::format_string($group->name
, $context);
222 [$group->description
, $group->descriptionformat
] =
223 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
224 $context, 'group', 'description', $group->id
);
226 $groups[] = (array)$group;
233 * Returns description of method result value
235 * @return \core_external\external_description
238 public static function get_groups_returns() {
239 return new external_multiple_structure(
240 new external_single_structure(
242 'id' => new external_value(PARAM_INT
, 'group record id'),
243 'courseid' => new external_value(PARAM_INT
, 'id of course'),
244 'name' => new external_value(PARAM_TEXT
, 'group name'),
245 'description' => new external_value(PARAM_RAW
, 'group description text'),
246 'descriptionformat' => new external_format_value('description'),
247 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
248 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
249 'visibility' => new external_value(PARAM_INT
,
250 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. '
251 . '3 = Membership is hidden.'),
252 'participation' => new external_value(PARAM_BOOL
, 'participation mode'),
259 * Returns description of method parameters
261 * @return external_function_parameters
264 public static function get_course_groups_parameters() {
265 return new external_function_parameters(
267 'courseid' => new external_value(PARAM_INT
, 'id of course'),
273 * Get all groups in the specified course
275 * @param int $courseid id of course
276 * @return array of group objects (id, courseid, name, enrolmentkey)
279 public static function get_course_groups($courseid) {
280 $params = self
::validate_parameters(self
::get_course_groups_parameters(), array('courseid'=>$courseid));
282 // now security checks
283 $context = context_course
::instance($params['courseid'], IGNORE_MISSING
);
285 self
::validate_context($context);
286 } catch (Exception
$e) {
287 $exceptionparam = new stdClass();
288 $exceptionparam->message
= $e->getMessage();
289 $exceptionparam->courseid
= $params['courseid'];
290 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
292 require_capability('moodle/course:managegroups', $context);
294 $gs = groups_get_all_groups($params['courseid'], 0, 0,
295 'g.id, g.courseid, g.name, g.idnumber, g.description, g.descriptionformat, g.enrolmentkey, '
296 . 'g.visibility, g.participation');
299 foreach ($gs as $group) {
300 $group->name
= \core_external\util
::format_string($group->name
, $context);
301 [$group->description
, $group->descriptionformat
] =
302 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
303 $context, 'group', 'description', $group->id
);
304 $groups[] = (array)$group;
311 * Returns description of method result value
313 * @return \core_external\external_description
316 public static function get_course_groups_returns() {
317 return new external_multiple_structure(
318 new external_single_structure(
320 'id' => new external_value(PARAM_INT
, 'group record id'),
321 'courseid' => new external_value(PARAM_INT
, 'id of course'),
322 'name' => new external_value(PARAM_TEXT
, 'group name'),
323 'description' => new external_value(PARAM_RAW
, 'group description text'),
324 'descriptionformat' => new external_format_value('description'),
325 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
326 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
327 'visibility' => new external_value(PARAM_INT
,
328 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. '
329 . '3 = Membership is hidden.'),
330 'participation' => new external_value(PARAM_BOOL
, 'participation mode'),
337 * Returns description of method parameters
339 * @return external_function_parameters
342 public static function delete_groups_parameters() {
343 return new external_function_parameters(
345 'groupids' => new external_multiple_structure(new external_value(PARAM_INT
, 'Group ID')),
353 * @param array $groupids array of group ids
356 public static function delete_groups($groupids) {
358 require_once("$CFG->dirroot/group/lib.php");
360 $params = self
::validate_parameters(self
::delete_groups_parameters(), array('groupids'=>$groupids));
362 $transaction = $DB->start_delegated_transaction();
364 foreach ($params['groupids'] as $groupid) {
366 $groupid = validate_param($groupid, PARAM_INT
);
367 if (!$group = groups_get_group($groupid, '*', IGNORE_MISSING
)) {
368 // silently ignore attempts to delete nonexisting groups
372 // now security checks
373 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
375 self
::validate_context($context);
376 } catch (Exception
$e) {
377 $exceptionparam = new stdClass();
378 $exceptionparam->message
= $e->getMessage();
379 $exceptionparam->courseid
= $group->courseid
;
380 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
382 require_capability('moodle/course:managegroups', $context);
384 groups_delete_group($group);
387 $transaction->allow_commit();
391 * Returns description of method result value
396 public static function delete_groups_returns() {
402 * Returns description of method parameters
404 * @return external_function_parameters
407 public static function get_group_members_parameters() {
408 return new external_function_parameters(
410 'groupids' => new external_multiple_structure(new external_value(PARAM_INT
, 'Group ID')),
416 * Return all members for a group
418 * @param array $groupids array of group ids
419 * @return array with group id keys containing arrays of user ids
422 public static function get_group_members($groupids) {
425 $params = self
::validate_parameters(self
::get_group_members_parameters(), array('groupids'=>$groupids));
427 foreach ($params['groupids'] as $groupid) {
429 $group = groups_get_group($groupid, 'id, courseid, name, enrolmentkey', MUST_EXIST
);
430 // now security checks
431 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
433 self
::validate_context($context);
434 } catch (Exception
$e) {
435 $exceptionparam = new stdClass();
436 $exceptionparam->message
= $e->getMessage();
437 $exceptionparam->courseid
= $group->courseid
;
438 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
440 require_capability('moodle/course:managegroups', $context);
442 $groupmembers = groups_get_members($group->id
, 'u.id', 'lastname ASC, firstname ASC');
444 $members[] = array('groupid'=>$groupid, 'userids'=>array_keys($groupmembers));
451 * Returns description of method result value
453 * @return \core_external\external_description
456 public static function get_group_members_returns() {
457 return new external_multiple_structure(
458 new external_single_structure(
460 'groupid' => new external_value(PARAM_INT
, 'group record id'),
461 'userids' => new external_multiple_structure(new external_value(PARAM_INT
, 'user id')),
469 * Returns description of method parameters
471 * @return external_function_parameters
474 public static function add_group_members_parameters() {
475 return new external_function_parameters(
477 'members'=> new external_multiple_structure(
478 new external_single_structure(
480 'groupid' => new external_value(PARAM_INT
, 'group record id'),
481 'userid' => new external_value(PARAM_INT
, 'user id'),
492 * @param array $members of arrays with keys userid, groupid
495 public static function add_group_members($members) {
497 require_once("$CFG->dirroot/group/lib.php");
499 $params = self
::validate_parameters(self
::add_group_members_parameters(), array('members'=>$members));
501 $transaction = $DB->start_delegated_transaction();
502 foreach ($params['members'] as $member) {
504 $groupid = $member['groupid'];
505 $userid = $member['userid'];
507 $group = groups_get_group($groupid, '*', MUST_EXIST
);
508 $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0, 'mnethostid'=>$CFG->mnet_localhost_id
), '*', MUST_EXIST
);
510 // now security checks
511 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
513 self
::validate_context($context);
514 } catch (Exception
$e) {
515 $exceptionparam = new stdClass();
516 $exceptionparam->message
= $e->getMessage();
517 $exceptionparam->courseid
= $group->courseid
;
518 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
520 require_capability('moodle/course:managegroups', $context);
522 // now make sure user is enrolled in course - this is mandatory requirement,
523 // unfortunately this is slow
524 if (!is_enrolled($context, $userid)) {
525 throw new invalid_parameter_exception('Only enrolled users may be members of groups');
528 groups_add_member($group, $user);
531 $transaction->allow_commit();
535 * Returns description of method result value
540 public static function add_group_members_returns() {
546 * Returns description of method parameters
548 * @return external_function_parameters
551 public static function delete_group_members_parameters() {
552 return new external_function_parameters(
554 'members'=> new external_multiple_structure(
555 new external_single_structure(
557 'groupid' => new external_value(PARAM_INT
, 'group record id'),
558 'userid' => new external_value(PARAM_INT
, 'user id'),
567 * Delete group members
569 * @param array $members of arrays with keys userid, groupid
572 public static function delete_group_members($members) {
574 require_once("$CFG->dirroot/group/lib.php");
576 $params = self
::validate_parameters(self
::delete_group_members_parameters(), array('members'=>$members));
578 $transaction = $DB->start_delegated_transaction();
580 foreach ($params['members'] as $member) {
582 $groupid = $member['groupid'];
583 $userid = $member['userid'];
585 $group = groups_get_group($groupid, '*', MUST_EXIST
);
586 $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0, 'mnethostid'=>$CFG->mnet_localhost_id
), '*', MUST_EXIST
);
588 // now security checks
589 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
591 self
::validate_context($context);
592 } catch (Exception
$e) {
593 $exceptionparam = new stdClass();
594 $exceptionparam->message
= $e->getMessage();
595 $exceptionparam->courseid
= $group->courseid
;
596 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
598 require_capability('moodle/course:managegroups', $context);
600 if (!groups_remove_member_allowed($group, $user)) {
601 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context));
602 throw new moodle_exception('errorremovenotpermitted', 'group', '', $fullname);
604 groups_remove_member($group, $user);
607 $transaction->allow_commit();
611 * Returns description of method result value
616 public static function delete_group_members_returns() {
621 * Returns description of method parameters
623 * @return external_function_parameters
626 public static function create_groupings_parameters() {
627 return new external_function_parameters(
629 'groupings' => new external_multiple_structure(
630 new external_single_structure(
632 'courseid' => new external_value(PARAM_INT
, 'id of course'),
633 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
634 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
635 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
636 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
)
638 ), 'List of grouping object. A grouping has a courseid, a name and a description.'
647 * @param array $groupings array of grouping description arrays (with keys groupname and courseid)
648 * @return array of newly created groupings
651 public static function create_groupings($groupings) {
653 require_once("$CFG->dirroot/group/lib.php");
655 $params = self
::validate_parameters(self
::create_groupings_parameters(), array('groupings'=>$groupings));
657 $transaction = $DB->start_delegated_transaction();
659 $groupings = array();
661 foreach ($params['groupings'] as $grouping) {
662 $grouping = (object)$grouping;
664 if (trim($grouping->name
) == '') {
665 throw new invalid_parameter_exception('Invalid grouping name');
667 if ($DB->count_records('groupings', array('courseid'=>$grouping->courseid
, 'name'=>$grouping->name
))) {
668 throw new invalid_parameter_exception('Grouping with the same name already exists in the course');
671 // Now security checks .
672 $context = context_course
::instance($grouping->courseid
);
674 self
::validate_context($context);
675 } catch (Exception
$e) {
676 $exceptionparam = new stdClass();
677 $exceptionparam->message
= $e->getMessage();
678 $exceptionparam->courseid
= $grouping->courseid
;
679 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
681 require_capability('moodle/course:managegroups', $context);
683 $grouping->descriptionformat
= util
::validate_format($grouping->descriptionformat
);
685 // Finally create the grouping.
686 $grouping->id
= groups_create_grouping($grouping);
687 $groupings[] = (array)$grouping;
690 $transaction->allow_commit();
696 * Returns description of method result value
698 * @return \core_external\external_description
701 public static function create_groupings_returns() {
702 return new external_multiple_structure(
703 new external_single_structure(
705 'id' => new external_value(PARAM_INT
, 'grouping record id'),
706 'courseid' => new external_value(PARAM_INT
, 'id of course'),
707 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
708 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
709 'descriptionformat' => new external_format_value('description'),
710 'idnumber' => new external_value(PARAM_RAW
, 'id number')
712 ), 'List of grouping object. A grouping has an id, a courseid, a name and a description.'
717 * Returns description of method parameters
719 * @return external_function_parameters
722 public static function update_groupings_parameters() {
723 return new external_function_parameters(
725 'groupings' => new external_multiple_structure(
726 new external_single_structure(
728 'id' => new external_value(PARAM_INT
, 'id of grouping'),
729 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
730 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
731 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
732 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
)
734 ), 'List of grouping object. A grouping has a courseid, a name and a description.'
743 * @param array $groupings array of grouping description arrays (with keys groupname and courseid)
744 * @return array of newly updated groupings
747 public static function update_groupings($groupings) {
749 require_once("$CFG->dirroot/group/lib.php");
751 $params = self
::validate_parameters(self
::update_groupings_parameters(), array('groupings'=>$groupings));
753 $transaction = $DB->start_delegated_transaction();
755 foreach ($params['groupings'] as $grouping) {
756 $grouping = (object)$grouping;
758 if (trim($grouping->name
) == '') {
759 throw new invalid_parameter_exception('Invalid grouping name');
762 if (! $currentgrouping = $DB->get_record('groupings', array('id'=>$grouping->id
))) {
763 throw new invalid_parameter_exception("Grouping $grouping->id does not exist in the course");
766 // Check if the new modified grouping name already exists in the course.
767 if ($grouping->name
!= $currentgrouping->name
and
768 $DB->count_records('groupings', array('courseid'=>$currentgrouping->courseid
, 'name'=>$grouping->name
))) {
769 throw new invalid_parameter_exception('A different grouping with the same name already exists in the course');
772 $grouping->courseid
= $currentgrouping->courseid
;
774 // Now security checks.
775 $context = context_course
::instance($grouping->courseid
);
777 self
::validate_context($context);
778 } catch (Exception
$e) {
779 $exceptionparam = new stdClass();
780 $exceptionparam->message
= $e->getMessage();
781 $exceptionparam->courseid
= $grouping->courseid
;
782 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
784 require_capability('moodle/course:managegroups', $context);
786 // We must force allways FORMAT_HTML.
787 $grouping->descriptionformat
= util
::validate_format($grouping->descriptionformat
);
789 // Finally update the grouping.
790 groups_update_grouping($grouping);
793 $transaction->allow_commit();
799 * Returns description of method result value
801 * @return \core_external\external_description
804 public static function update_groupings_returns() {
809 * Returns description of method parameters
811 * @return external_function_parameters
814 public static function get_groupings_parameters() {
815 return new external_function_parameters(
817 'groupingids' => new external_multiple_structure(new external_value(PARAM_INT
, 'grouping ID')
818 , 'List of grouping id. A grouping id is an integer.'),
819 'returngroups' => new external_value(PARAM_BOOL
, 'return associated groups', VALUE_DEFAULT
, 0)
825 * Get groupings definition specified by ids
827 * @param array $groupingids arrays of grouping ids
828 * @param boolean $returngroups return the associated groups if true. The default is false.
829 * @return array of grouping objects (id, courseid, name)
832 public static function get_groupings($groupingids, $returngroups = false) {
834 require_once("$CFG->dirroot/group/lib.php");
835 require_once("$CFG->libdir/filelib.php");
837 $params = self
::validate_parameters(self
::get_groupings_parameters(),
838 array('groupingids' => $groupingids,
839 'returngroups' => $returngroups));
841 $groupings = array();
842 foreach ($params['groupingids'] as $groupingid) {
844 $grouping = groups_get_grouping($groupingid, '*', MUST_EXIST
);
846 // Now security checks.
847 $context = context_course
::instance($grouping->courseid
);
849 self
::validate_context($context);
850 } catch (Exception
$e) {
851 $exceptionparam = new stdClass();
852 $exceptionparam->message
= $e->getMessage();
853 $exceptionparam->courseid
= $grouping->courseid
;
854 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
856 require_capability('moodle/course:managegroups', $context);
858 list($grouping->description
, $grouping->descriptionformat
) =
859 \core_external\util
::format_text($grouping->description
, $grouping->descriptionformat
,
860 $context, 'grouping', 'description', $grouping->id
);
862 $groupingarray = (array)$grouping;
864 if ($params['returngroups']) {
865 $grouprecords = $DB->get_records_sql("SELECT * FROM {groups} g INNER JOIN {groupings_groups} gg ".
866 "ON g.id = gg.groupid WHERE gg.groupingid = ? ".
867 "ORDER BY groupid", array($groupingid));
870 foreach ($grouprecords as $grouprecord) {
871 list($grouprecord->description
, $grouprecord->descriptionformat
) =
872 \core_external\util
::format_text($grouprecord->description
, $grouprecord->descriptionformat
,
873 $context, 'group', 'description', $grouprecord->groupid
);
874 $groups[] = array('id' => $grouprecord->groupid
,
875 'name' => $grouprecord->name
,
876 'idnumber' => $grouprecord->idnumber
,
877 'description' => $grouprecord->description
,
878 'descriptionformat' => $grouprecord->descriptionformat
,
879 'enrolmentkey' => $grouprecord->enrolmentkey
,
880 'courseid' => $grouprecord->courseid
883 $groupingarray['groups'] = $groups;
886 $groupings[] = $groupingarray;
893 * Returns description of method result value
895 * @return \core_external\external_description
898 public static function get_groupings_returns() {
899 return new external_multiple_structure(
900 new external_single_structure(
902 'id' => new external_value(PARAM_INT
, 'grouping record id'),
903 'courseid' => new external_value(PARAM_INT
, 'id of course'),
904 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
905 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
906 'descriptionformat' => new external_format_value('description'),
907 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
908 'groups' => new external_multiple_structure(
909 new external_single_structure(
911 'id' => new external_value(PARAM_INT
, 'group record id'),
912 'courseid' => new external_value(PARAM_INT
, 'id of course'),
913 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
914 'description' => new external_value(PARAM_RAW
, 'group description text'),
915 'descriptionformat' => new external_format_value('description'),
916 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
917 'idnumber' => new external_value(PARAM_RAW
, 'id number')
920 'optional groups', VALUE_OPTIONAL
)
927 * Returns description of method parameters
929 * @return external_function_parameters
932 public static function get_course_groupings_parameters() {
933 return new external_function_parameters(
935 'courseid' => new external_value(PARAM_INT
, 'id of course'),
941 * Get all groupings in the specified course
943 * @param int $courseid id of course
944 * @return array of grouping objects (id, courseid, name, enrolmentkey)
947 public static function get_course_groupings($courseid) {
949 require_once("$CFG->dirroot/group/lib.php");
950 require_once("$CFG->libdir/filelib.php");
952 $params = self
::validate_parameters(self
::get_course_groupings_parameters(), array('courseid'=>$courseid));
954 // Now security checks.
955 $context = context_course
::instance($params['courseid']);
958 self
::validate_context($context);
959 } catch (Exception
$e) {
960 $exceptionparam = new stdClass();
961 $exceptionparam->message
= $e->getMessage();
962 $exceptionparam->courseid
= $params['courseid'];
963 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
965 require_capability('moodle/course:managegroups', $context);
967 $gs = groups_get_all_groupings($params['courseid']);
969 $groupings = array();
970 foreach ($gs as $grouping) {
971 list($grouping->description
, $grouping->descriptionformat
) =
972 \core_external\util
::format_text($grouping->description
, $grouping->descriptionformat
,
973 $context, 'grouping', 'description', $grouping->id
);
974 $groupings[] = (array)$grouping;
981 * Returns description of method result value
983 * @return \core_external\external_description
986 public static function get_course_groupings_returns() {
987 return new external_multiple_structure(
988 new external_single_structure(
990 'id' => new external_value(PARAM_INT
, 'grouping record id'),
991 'courseid' => new external_value(PARAM_INT
, 'id of course'),
992 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
993 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
994 'descriptionformat' => new external_format_value('description'),
995 'idnumber' => new external_value(PARAM_RAW
, 'id number')
1002 * Returns description of method parameters
1004 * @return external_function_parameters
1007 public static function delete_groupings_parameters() {
1008 return new external_function_parameters(
1010 'groupingids' => new external_multiple_structure(new external_value(PARAM_INT
, 'grouping ID')),
1018 * @param array $groupingids array of grouping ids
1022 public static function delete_groupings($groupingids) {
1024 require_once("$CFG->dirroot/group/lib.php");
1026 $params = self
::validate_parameters(self
::delete_groupings_parameters(), array('groupingids'=>$groupingids));
1028 $transaction = $DB->start_delegated_transaction();
1030 foreach ($params['groupingids'] as $groupingid) {
1032 if (!$grouping = groups_get_grouping($groupingid)) {
1033 // Silently ignore attempts to delete nonexisting groupings.
1037 // Now security checks.
1038 $context = context_course
::instance($grouping->courseid
);
1040 self
::validate_context($context);
1041 } catch (Exception
$e) {
1042 $exceptionparam = new stdClass();
1043 $exceptionparam->message
= $e->getMessage();
1044 $exceptionparam->courseid
= $grouping->courseid
;
1045 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
1047 require_capability('moodle/course:managegroups', $context);
1049 groups_delete_grouping($grouping);
1052 $transaction->allow_commit();
1056 * Returns description of method result value
1058 * @return \core_external\external_description
1061 public static function delete_groupings_returns() {
1066 * Returns description of method parameters
1068 * @return external_function_parameters
1071 public static function assign_grouping_parameters() {
1072 return new external_function_parameters(
1074 'assignments'=> new external_multiple_structure(
1075 new external_single_structure(
1077 'groupingid' => new external_value(PARAM_INT
, 'grouping record id'),
1078 'groupid' => new external_value(PARAM_INT
, 'group record id'),
1087 * Assign a group to a grouping
1089 * @param array $assignments of arrays with keys groupid, groupingid
1093 public static function assign_grouping($assignments) {
1095 require_once("$CFG->dirroot/group/lib.php");
1097 $params = self
::validate_parameters(self
::assign_grouping_parameters(), array('assignments'=>$assignments));
1099 $transaction = $DB->start_delegated_transaction();
1100 foreach ($params['assignments'] as $assignment) {
1102 $groupingid = $assignment['groupingid'];
1103 $groupid = $assignment['groupid'];
1105 $grouping = groups_get_grouping($groupingid, 'id, courseid', MUST_EXIST
);
1106 $group = groups_get_group($groupid, 'id, courseid', MUST_EXIST
);
1108 if ($DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) {
1109 // Continue silently if the group is yet assigned to the grouping.
1113 // Now security checks.
1114 $context = context_course
::instance($grouping->courseid
);
1116 self
::validate_context($context);
1117 } catch (Exception
$e) {
1118 $exceptionparam = new stdClass();
1119 $exceptionparam->message
= $e->getMessage();
1120 $exceptionparam->courseid
= $group->courseid
;
1121 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
1123 require_capability('moodle/course:managegroups', $context);
1125 groups_assign_grouping($groupingid, $groupid);
1128 $transaction->allow_commit();
1132 * Returns description of method result value
1137 public static function assign_grouping_returns() {
1142 * Returns description of method parameters
1144 * @return external_function_parameters
1147 public static function unassign_grouping_parameters() {
1148 return new external_function_parameters(
1150 'unassignments'=> new external_multiple_structure(
1151 new external_single_structure(
1153 'groupingid' => new external_value(PARAM_INT
, 'grouping record id'),
1154 'groupid' => new external_value(PARAM_INT
, 'group record id'),
1163 * Unassign a group from a grouping
1165 * @param array $unassignments of arrays with keys groupid, groupingid
1169 public static function unassign_grouping($unassignments) {
1171 require_once("$CFG->dirroot/group/lib.php");
1173 $params = self
::validate_parameters(self
::unassign_grouping_parameters(), array('unassignments'=>$unassignments));
1175 $transaction = $DB->start_delegated_transaction();
1176 foreach ($params['unassignments'] as $unassignment) {
1178 $groupingid = $unassignment['groupingid'];
1179 $groupid = $unassignment['groupid'];
1181 $grouping = groups_get_grouping($groupingid, 'id, courseid', MUST_EXIST
);
1182 $group = groups_get_group($groupid, 'id, courseid', MUST_EXIST
);
1184 if (!$DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) {
1185 // Continue silently if the group is not assigned to the grouping.
1189 // Now security checks.
1190 $context = context_course
::instance($grouping->courseid
);
1192 self
::validate_context($context);
1193 } catch (Exception
$e) {
1194 $exceptionparam = new stdClass();
1195 $exceptionparam->message
= $e->getMessage();
1196 $exceptionparam->courseid
= $group->courseid
;
1197 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
1199 require_capability('moodle/course:managegroups', $context);
1201 groups_unassign_grouping($groupingid, $groupid);
1204 $transaction->allow_commit();
1208 * Returns description of method result value
1213 public static function unassign_grouping_returns() {
1218 * Returns description of method parameters
1220 * @return external_function_parameters
1223 public static function get_course_user_groups_parameters() {
1224 return new external_function_parameters(
1226 'courseid' => new external_value(PARAM_INT
,
1227 'Id of course (empty or 0 for all the courses where the user is enrolled).', VALUE_DEFAULT
, 0),
1228 'userid' => new external_value(PARAM_INT
, 'Id of user (empty or 0 for current user).', VALUE_DEFAULT
, 0),
1229 'groupingid' => new external_value(PARAM_INT
, 'returns only groups in the specified grouping', VALUE_DEFAULT
, 0)
1235 * Get all groups in the specified course for the specified user.
1237 * @throws moodle_exception
1238 * @param int $courseid id of course.
1239 * @param int $userid id of user.
1240 * @param int $groupingid optional returns only groups in the specified grouping.
1241 * @return array of group objects (id, name, description, format) and possible warnings.
1244 public static function get_course_user_groups($courseid = 0, $userid = 0, $groupingid = 0) {
1247 // Warnings array, it can be empty at the end but is mandatory.
1248 $warnings = array();
1251 'courseid' => $courseid,
1252 'userid' => $userid,
1253 'groupingid' => $groupingid
1255 $params = self
::validate_parameters(self
::get_course_user_groups_parameters(), $params);
1257 $courseid = $params['courseid'];
1258 $userid = $params['userid'];
1259 $groupingid = $params['groupingid'];
1262 if (empty($userid)) {
1263 $userid = $USER->id
;
1265 $user = core_user
::get_user($userid, '*', MUST_EXIST
);
1266 core_user
::require_active_user($user);
1270 if (empty($courseid)) {
1271 $courses = enrol_get_users_courses($userid, true);
1272 $checkenrolments = false; // No need to check enrolments here since they are my courses.
1274 $courses = array($courseid => get_course($courseid));
1275 $checkenrolments = true;
1279 list($courses, $warnings) = util
::validate_courses(array_keys($courses), $courses, true);
1281 $usergroups = array();
1282 foreach ($courses as $course) {
1283 // Check if we have permissions for retrieve the information.
1284 if ($userid != $USER->id
&& !has_capability('moodle/course:managegroups', $course->context
)) {
1285 $warnings[] = array(
1287 'itemid' => $course->id
,
1288 'warningcode' => 'cannotmanagegroups',
1289 'message' => "User $USER->id cannot manage groups in course $course->id",
1294 // Check if the user being check is enrolled in the given course.
1295 if ($checkenrolments && !is_enrolled($course->context
, $userid)) {
1296 // We return a warning because the function does not fail for not enrolled users.
1297 $warnings[] = array(
1299 'itemid' => $course->id
,
1300 'warningcode' => 'notenrolled',
1301 'message' => "User $userid is not enrolled in course $course->id",
1305 $groups = groups_get_all_groups($course->id
, $userid, $groupingid,
1306 'g.id, g.name, g.description, g.descriptionformat, g.idnumber');
1308 foreach ($groups as $group) {
1309 $group->name
= \core_external\util
::format_string($group->name
, $course->context
);
1310 [$group->description
, $group->descriptionformat
] =
1311 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
1312 $course->context
, 'group', 'description', $group->id
);
1313 $group->courseid
= $course->id
;
1314 $usergroups[] = $group;
1319 'groups' => $usergroups,
1320 'warnings' => $warnings
1326 * Returns description of method result value.
1328 * @return \core_external\external_description A single structure containing groups and possible warnings.
1331 public static function get_course_user_groups_returns() {
1332 return new external_single_structure(
1334 'groups' => new external_multiple_structure(self
::group_description()),
1335 'warnings' => new external_warnings(),
1341 * Create group return value description.
1343 * @return external_single_structure The group description
1345 public static function group_description() {
1346 return new external_single_structure(
1348 'id' => new external_value(PARAM_INT
, 'group record id'),
1349 'name' => new external_value(PARAM_TEXT
, 'group name'),
1350 'description' => new external_value(PARAM_RAW
, 'group description text'),
1351 'descriptionformat' => new external_format_value('description'),
1352 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
1353 'courseid' => new external_value(PARAM_INT
, 'course id', VALUE_OPTIONAL
),
1359 * Returns description of method parameters
1361 * @return external_function_parameters
1364 public static function get_activity_allowed_groups_parameters() {
1365 return new external_function_parameters(
1367 'cmid' => new external_value(PARAM_INT
, 'course module id'),
1368 'userid' => new external_value(PARAM_INT
, 'id of user, empty for current user', VALUE_DEFAULT
, 0)
1374 * Gets a list of groups that the user is allowed to access within the specified activity.
1376 * @throws moodle_exception
1377 * @param int $cmid course module id
1378 * @param int $userid id of user.
1379 * @return array of group objects (id, name, description, format) and possible warnings.
1382 public static function get_activity_allowed_groups($cmid, $userid = 0) {
1385 // Warnings array, it can be empty at the end but is mandatory.
1386 $warnings = array();
1392 $params = self
::validate_parameters(self
::get_activity_allowed_groups_parameters(), $params);
1393 $cmid = $params['cmid'];
1394 $userid = $params['userid'];
1396 $cm = get_coursemodule_from_id(null, $cmid, 0, false, MUST_EXIST
);
1399 $context = context_module
::instance($cm->id
);
1400 $coursecontext = context_course
::instance($cm->course
);
1401 self
::validate_context($context);
1403 if (empty($userid)) {
1404 $userid = $USER->id
;
1407 $user = core_user
::get_user($userid, '*', MUST_EXIST
);
1408 core_user
::require_active_user($user);
1410 // Check if we have permissions for retrieve the information.
1411 if ($user->id
!= $USER->id
) {
1412 if (!has_capability('moodle/course:managegroups', $context)) {
1413 throw new moodle_exception('accessdenied', 'admin');
1416 // Validate if the user is enrolled in the course.
1417 $course = get_course($cm->course
);
1418 if (!can_access_course($course, $user, '', true)) {
1419 // We return a warning because the function does not fail for not enrolled users.
1421 $warning['item'] = 'course';
1422 $warning['itemid'] = $cm->course
;
1423 $warning['warningcode'] = '1';
1424 $warning['message'] = "User $user->id cannot access course $cm->course";
1425 $warnings[] = $warning;
1429 $usergroups = array();
1430 if (empty($warnings)) {
1431 $groups = groups_get_activity_allowed_groups($cm, $user->id
);
1433 foreach ($groups as $group) {
1434 $group->name
= \core_external\util
::format_string($group->name
, $coursecontext);
1435 [$group->description
, $group->descriptionformat
] =
1436 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
1437 $coursecontext, 'group', 'description', $group->id
);
1438 $group->courseid
= $cm->course
;
1439 $usergroups[] = $group;
1444 'groups' => $usergroups,
1445 'canaccessallgroups' => has_capability('moodle/site:accessallgroups', $context, $user),
1446 'warnings' => $warnings
1452 * Returns description of method result value.
1454 * @return \core_external\external_description A single structure containing groups and possible warnings.
1457 public static function get_activity_allowed_groups_returns() {
1458 return new external_single_structure(
1460 'groups' => new external_multiple_structure(self
::group_description()),
1461 'canaccessallgroups' => new external_value(PARAM_BOOL
,
1462 'Whether the user will be able to access all the activity groups.', VALUE_OPTIONAL
),
1463 'warnings' => new external_warnings(),
1469 * Returns description of method parameters
1471 * @return external_function_parameters
1474 public static function get_activity_groupmode_parameters() {
1475 return new external_function_parameters(
1477 'cmid' => new external_value(PARAM_INT
, 'course module id')
1483 * Returns effective groupmode used in a given activity.
1485 * @throws moodle_exception
1486 * @param int $cmid course module id.
1487 * @return array containing the group mode and possible warnings.
1489 * @throws moodle_exception
1491 public static function get_activity_groupmode($cmid) {
1494 // Warnings array, it can be empty at the end but is mandatory.
1495 $warnings = array();
1500 $params = self
::validate_parameters(self
::get_activity_groupmode_parameters(), $params);
1501 $cmid = $params['cmid'];
1503 $cm = get_coursemodule_from_id(null, $cmid, 0, false, MUST_EXIST
);
1506 $context = context_module
::instance($cm->id
);
1507 self
::validate_context($context);
1509 $groupmode = groups_get_activity_groupmode($cm);
1512 'groupmode' => $groupmode,
1513 'warnings' => $warnings
1519 * Returns description of method result value.
1521 * @return \core_external\external_description
1524 public static function get_activity_groupmode_returns() {
1525 return new external_single_structure(
1527 'groupmode' => new external_value(PARAM_INT
, 'group mode:
1528 0 for no groups, 1 for separate groups, 2 for visible groups'),
1529 'warnings' => new external_warnings(),
1535 * Returns description of method parameters
1537 * @return external_function_parameters
1540 public static function update_groups_parameters() {
1541 return new external_function_parameters(
1543 'groups' => new external_multiple_structure(
1544 new external_single_structure(
1546 'id' => new external_value(PARAM_INT
, 'ID of the group'),
1547 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
1548 'description' => new external_value(PARAM_RAW
, 'group description text', VALUE_OPTIONAL
),
1549 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
1550 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase', VALUE_OPTIONAL
),
1551 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
),
1552 'visibility' => new external_value(PARAM_TEXT
,
1553 'group visibility mode. 0 = Visible to all. 1 = Visible to members. '
1554 . '2 = See own membership. 3 = Membership is hidden.', VALUE_OPTIONAL
),
1555 'participation' => new external_value(PARAM_BOOL
,
1556 'activity participation enabled? Only for "all" and "members" visibility', VALUE_OPTIONAL
),
1558 ), 'List of group objects. A group is found by the id, then all other details provided will be updated.'
1567 * @param array $groups
1571 public static function update_groups($groups) {
1573 require_once("$CFG->dirroot/group/lib.php");
1575 $params = self
::validate_parameters(self
::update_groups_parameters(), array('groups' => $groups));
1577 $transaction = $DB->start_delegated_transaction();
1579 foreach ($params['groups'] as $group) {
1580 $group = (object) $group;
1582 if (trim($group->name
) == '') {
1583 throw new invalid_parameter_exception('Invalid group name');
1586 if (!$currentgroup = $DB->get_record('groups', array('id' => $group->id
))) {
1587 throw new invalid_parameter_exception("Group $group->id does not exist");
1590 // Check if the modified group name already exists in the course.
1591 if ($group->name
!= $currentgroup->name
and
1592 $DB->get_record('groups', array('courseid' => $currentgroup->courseid
, 'name' => $group->name
))) {
1593 throw new invalid_parameter_exception('A different group with the same name already exists in the course');
1596 if (isset($group->visibility
) ||
isset($group->participation
)) {
1597 $hasmembers = $DB->record_exists('groups_members', ['groupid' => $group->id
]);
1598 if (isset($group->visibility
)) {
1599 // Validate visibility.
1600 self
::validate_visibility($group->visibility
);
1601 if ($hasmembers && $group->visibility
!= $currentgroup->visibility
) {
1602 throw new invalid_parameter_exception(
1603 'The visibility of this group cannot be changed as it currently has members.');
1606 $group->visibility
= $currentgroup->visibility
;
1608 if (isset($group->participation
) && $hasmembers && $group->participation
!= $currentgroup->participation
) {
1609 throw new invalid_parameter_exception(
1610 'The participation mode of this group cannot be changed as it currently has members.');
1614 $group->courseid
= $currentgroup->courseid
;
1616 // Now security checks.
1617 $context = context_course
::instance($group->courseid
);
1619 self
::validate_context($context);
1620 } catch (Exception
$e) {
1621 $exceptionparam = new stdClass();
1622 $exceptionparam->message
= $e->getMessage();
1623 $exceptionparam->courseid
= $group->courseid
;
1624 throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
1626 require_capability('moodle/course:managegroups', $context);
1628 if (!empty($group->description
)) {
1629 $group->descriptionformat
= util
::validate_format($group->descriptionformat
);
1632 groups_update_group($group);
1635 $transaction->allow_commit();
1641 * Returns description of method result value
1646 public static function update_groups_returns() {