Merge branch 'MDL-81457-main' of https://github.com/andrewnicols/moodle
[moodle.git] / enrol / externallib.php
blob4ee08386251453a13fbb557188c5360a2f935b94
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
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 /**
18 * Course participations External functions.
20 * @package core_enrol
21 * @category external
22 * @copyright 2010 Jerome Mouneyrac
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 use core_external\external_api;
27 use core_external\external_files;
28 use core_external\external_format_value;
29 use core_external\external_function_parameters;
30 use core_external\external_multiple_structure;
31 use core_external\external_single_structure;
32 use core_external\external_value;
34 /**
35 * Enrol external functions
37 * This api is mostly read only, the actual enrol and unenrol
38 * support is in each enrol plugin.
40 * @package core_enrol
41 * @category external
42 * @copyright 2010 Jerome Mouneyrac
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44 * @since Moodle 2.2
46 class core_enrol_external extends external_api {
48 /**
49 * Returns description of method parameters
51 * @return external_function_parameters
52 * @since Moodle 2.4
54 public static function get_enrolled_users_with_capability_parameters() {
55 return new external_function_parameters(
56 array (
57 'coursecapabilities' => new external_multiple_structure(
58 new external_single_structure(
59 array (
60 'courseid' => new external_value(PARAM_INT, 'Course ID number in the Moodle course table'),
61 'capabilities' => new external_multiple_structure(
62 new external_value(PARAM_CAPABILITY, 'Capability name, such as mod/forum:viewdiscussion')),
65 , 'course id and associated capability name'),
66 'options' => new external_multiple_structure(
67 new external_single_structure(
68 array(
69 'name' => new external_value(PARAM_ALPHANUMEXT, 'option name'),
70 'value' => new external_value(PARAM_RAW, 'option value')
72 ), 'Option names:
73 * groupid (integer) return only users in this group id. Requires \'moodle/site:accessallgroups\' .
74 * onlyactive (integer) only users with active enrolments. Requires \'moodle/course:enrolreview\' .
75 * userfields (\'string, string, ...\') return only the values of these user fields.
76 * limitfrom (integer) sql limit from.
77 * limitnumber (integer) max number of users per course and capability.', VALUE_DEFAULT, array())
82 /**
83 * Return users that have the capabilities for each course specified. For each course and capability specified,
84 * a list of the users that are enrolled in the course and have that capability are returned.
86 * @param array $coursecapabilities array of course ids and associated capability names {courseid, {capabilities}}
87 * @return array An array of arrays describing users for each associated courseid and capability
88 * @since Moodle 2.4
90 public static function get_enrolled_users_with_capability($coursecapabilities, $options) {
91 global $CFG, $DB;
93 require_once($CFG->dirroot . '/course/lib.php');
94 require_once($CFG->dirroot . "/user/lib.php");
96 if (empty($coursecapabilities)) {
97 throw new invalid_parameter_exception('Parameter can not be empty');
99 $params = self::validate_parameters(self::get_enrolled_users_with_capability_parameters(),
100 array ('coursecapabilities' => $coursecapabilities, 'options'=>$options));
101 $result = array();
102 $userlist = array();
103 $groupid = 0;
104 $onlyactive = false;
105 $userfields = array();
106 $limitfrom = 0;
107 $limitnumber = 0;
108 foreach ($params['options'] as $option) {
109 switch ($option['name']) {
110 case 'groupid':
111 $groupid = (int)$option['value'];
112 break;
113 case 'onlyactive':
114 $onlyactive = !empty($option['value']);
115 break;
116 case 'userfields':
117 $thefields = explode(',', $option['value']);
118 foreach ($thefields as $f) {
119 $userfields[] = clean_param($f, PARAM_ALPHANUMEXT);
121 break;
122 case 'limitfrom' :
123 $limitfrom = clean_param($option['value'], PARAM_INT);
124 break;
125 case 'limitnumber' :
126 $limitnumber = clean_param($option['value'], PARAM_INT);
127 break;
131 foreach ($params['coursecapabilities'] as $coursecapability) {
132 $courseid = $coursecapability['courseid'];
133 $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
134 $coursecontext = context_course::instance($courseid);
135 if (!$coursecontext) {
136 throw new moodle_exception('cannotfindcourse', 'error', '', null,
137 'The course id ' . $courseid . ' doesn\'t exist.');
139 if ($courseid == SITEID) {
140 $context = context_system::instance();
141 } else {
142 $context = $coursecontext;
144 try {
145 self::validate_context($context);
146 } catch (Exception $e) {
147 $exceptionparam = new stdClass();
148 $exceptionparam->message = $e->getMessage();
149 $exceptionparam->courseid = $params['courseid'];
150 throw new moodle_exception(get_string('errorcoursecontextnotvalid' , 'webservice', $exceptionparam));
153 course_require_view_participants($context);
155 // The accessallgroups capability is needed to use this option.
156 if (!empty($groupid) && groups_is_member($groupid)) {
157 require_capability('moodle/site:accessallgroups', $coursecontext);
159 // The course:enrolereview capability is needed to use this option.
160 if ($onlyactive) {
161 require_capability('moodle/course:enrolreview', $coursecontext);
164 // To see the permissions of others role:review capability is required.
165 require_capability('moodle/role:review', $coursecontext);
166 foreach ($coursecapability['capabilities'] as $capability) {
167 $courseusers['courseid'] = $courseid;
168 $courseusers['capability'] = $capability;
170 list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $capability, $groupid, $onlyactive);
171 $enrolledparams['courseid'] = $courseid;
173 $sql = "SELECT u.*, COALESCE(ul.timeaccess, 0) AS lastcourseaccess
174 FROM {user} u
175 LEFT JOIN {user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = :courseid)
176 WHERE u.id IN ($enrolledsql)
177 ORDER BY u.id ASC";
179 $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber);
180 $users = array();
181 foreach ($enrolledusers as $courseuser) {
182 if ($userdetails = user_get_user_details($courseuser, $course, $userfields)) {
183 $users[] = $userdetails;
186 $enrolledusers->close();
187 $courseusers['users'] = $users;
188 $result[] = $courseusers;
191 return $result;
195 * Returns description of method result value
197 * @return external_multiple_structure
198 * @since Moodle 2.4
200 public static function get_enrolled_users_with_capability_returns() {
201 return new external_multiple_structure( new external_single_structure (
202 array (
203 'courseid' => new external_value(PARAM_INT, 'Course ID number in the Moodle course table'),
204 'capability' => new external_value(PARAM_CAPABILITY, 'Capability name'),
205 'users' => new external_multiple_structure(
206 new external_single_structure(
207 array(
208 'id' => new external_value(PARAM_INT, 'ID of the user'),
209 'username' => new external_value(PARAM_RAW, 'Username', VALUE_OPTIONAL),
210 'firstname' => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
211 'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
212 'fullname' => new external_value(PARAM_NOTAGS, 'The fullname of the user'),
213 'email' => new external_value(PARAM_TEXT, 'Email address', VALUE_OPTIONAL),
214 'address' => new external_value(PARAM_TEXT, 'Postal address', VALUE_OPTIONAL),
215 'phone1' => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL),
216 'phone2' => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL),
217 'department' => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
218 'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
219 'interests' => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
220 'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
221 'lastaccess' => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
222 'lastcourseaccess' => new external_value(PARAM_INT, 'last access to the course (0 if never)', VALUE_OPTIONAL),
223 'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
224 'descriptionformat' => new external_value(PARAM_INT, 'User profile description format', VALUE_OPTIONAL),
225 'city' => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
226 'country' => new external_value(PARAM_ALPHA, 'Country code of the user, such as AU or CZ', VALUE_OPTIONAL),
227 'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small', VALUE_OPTIONAL),
228 'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big', VALUE_OPTIONAL),
229 'customfields' => new external_multiple_structure(
230 new external_single_structure(
231 array(
232 'type' => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field'),
233 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
234 'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
235 'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field'),
237 ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
238 'groups' => new external_multiple_structure(
239 new external_single_structure(
240 array(
241 'id' => new external_value(PARAM_INT, 'group id'),
242 'name' => new external_value(PARAM_RAW, 'group name'),
243 'description' => new external_value(PARAM_RAW, 'group description'),
245 ), 'user groups', VALUE_OPTIONAL),
246 'roles' => new external_multiple_structure(
247 new external_single_structure(
248 array(
249 'roleid' => new external_value(PARAM_INT, 'role id'),
250 'name' => new external_value(PARAM_RAW, 'role name'),
251 'shortname' => new external_value(PARAM_ALPHANUMEXT, 'role shortname'),
252 'sortorder' => new external_value(PARAM_INT, 'role sortorder')
254 ), 'user roles', VALUE_OPTIONAL),
255 'preferences' => new external_multiple_structure(
256 new external_single_structure(
257 array(
258 'name' => new external_value(PARAM_RAW, 'The name of the preferences'),
259 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
261 ), 'User preferences', VALUE_OPTIONAL),
262 'enrolledcourses' => new external_multiple_structure(
263 new external_single_structure(
264 array(
265 'id' => new external_value(PARAM_INT, 'Id of the course'),
266 'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'),
267 'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
269 ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
271 ), 'List of users that are enrolled in the course and have the specified capability'),
278 * Returns description of method parameters
280 * @return external_function_parameters
282 public static function get_users_courses_parameters() {
283 return new external_function_parameters(
284 array(
285 'userid' => new external_value(PARAM_INT, 'user id'),
286 'returnusercount' => new external_value(PARAM_BOOL,
287 'Include count of enrolled users for each course? This can add several seconds to the response time'
288 . ' if a user is on several large courses, so set this to false if the value will not be used to'
289 . ' improve performance.',
290 VALUE_DEFAULT, true),
296 * Get list of courses user is enrolled in (only active enrolments are returned).
297 * Please note the current user must be able to access the course, otherwise the course is not included.
299 * @param int $userid
300 * @param bool $returnusercount
301 * @return array of courses
303 public static function get_users_courses($userid, $returnusercount = true) {
304 global $CFG, $USER, $DB, $OUTPUT;
306 require_once($CFG->dirroot . '/course/lib.php');
307 require_once($CFG->dirroot . '/user/lib.php');
308 require_once($CFG->libdir . '/completionlib.php');
310 // Do basic automatic PARAM checks on incoming data, using params description
311 // If any problems are found then exceptions are thrown with helpful error messages
312 $params = self::validate_parameters(self::get_users_courses_parameters(),
313 ['userid' => $userid, 'returnusercount' => $returnusercount]);
314 $userid = $params['userid'];
315 $returnusercount = $params['returnusercount'];
317 $courses = enrol_get_users_courses($userid, true, '*');
318 $result = array();
320 // Get user data including last access to courses.
321 $user = get_complete_user_data('id', $userid);
322 $sameuser = $USER->id == $userid;
324 // Retrieve favourited courses (starred).
325 $favouritecourseids = array();
326 if ($sameuser) {
327 $ufservice = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($userid));
328 $favourites = $ufservice->find_favourites_by_type('core_course', 'courses');
330 if ($favourites) {
331 $favouritecourseids = array_flip(array_map(
332 function($favourite) {
333 return $favourite->itemid;
334 }, $favourites));
338 foreach ($courses as $course) {
339 $context = context_course::instance($course->id, IGNORE_MISSING);
340 try {
341 self::validate_context($context);
342 } catch (Exception $e) {
343 // current user can not access this course, sorry we can not disclose who is enrolled in this course!
344 continue;
347 // If viewing details of another user, then we must be able to view participants as well as profile of that user.
348 if (!$sameuser && (!course_can_view_participants($context) || !user_can_view_profile($user, $course))) {
349 continue;
352 if ($returnusercount) {
353 list($enrolledsqlselect, $enrolledparams) = get_enrolled_sql($context);
354 $enrolledsql = "SELECT COUNT('x') FROM ($enrolledsqlselect) enrolleduserids";
355 $enrolledusercount = $DB->count_records_sql($enrolledsql, $enrolledparams);
358 $displayname = \core_external\util::format_string(get_course_display_name_for_list($course), $context);
359 list($course->summary, $course->summaryformat) =
360 \core_external\util::format_text($course->summary, $course->summaryformat, $context, 'course', 'summary', null);
361 $course->fullname = \core_external\util::format_string($course->fullname, $context);
362 $course->shortname = \core_external\util::format_string($course->shortname, $context);
364 $progress = null;
365 $completed = null;
366 $completionhascriteria = false;
367 $completionusertracked = false;
369 // Return only private information if the user should be able to see it.
370 if ($sameuser || completion_can_view_data($userid, $course)) {
371 if ($course->enablecompletion) {
372 $completion = new completion_info($course);
373 $completed = $completion->is_course_complete($userid);
374 $completionhascriteria = $completion->has_criteria();
375 $completionusertracked = $completion->is_tracked_user($userid);
376 $progress = \core_completion\progress::get_course_progress_percentage($course, $userid);
380 $lastaccess = null;
381 // Check if last access is a hidden field.
382 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
383 $canviewlastaccess = $sameuser || !isset($hiddenfields['lastaccess']);
384 if (!$canviewlastaccess) {
385 $canviewlastaccess = has_capability('moodle/course:viewhiddenuserfields', $context);
388 if ($canviewlastaccess && isset($user->lastcourseaccess[$course->id])) {
389 $lastaccess = $user->lastcourseaccess[$course->id];
392 $hidden = false;
393 if ($sameuser) {
394 $hidden = boolval(get_user_preferences('block_myoverview_hidden_course_' . $course->id, 0));
397 // Retrieve course overview used files.
398 $courselist = new core_course_list_element($course);
399 $overviewfiles = array();
400 foreach ($courselist->get_course_overviewfiles() as $file) {
401 $fileurl = moodle_url::make_webservice_pluginfile_url($file->get_contextid(), $file->get_component(),
402 $file->get_filearea(), null, $file->get_filepath(),
403 $file->get_filename())->out(false);
404 $overviewfiles[] = array(
405 'filename' => $file->get_filename(),
406 'fileurl' => $fileurl,
407 'filesize' => $file->get_filesize(),
408 'filepath' => $file->get_filepath(),
409 'mimetype' => $file->get_mimetype(),
410 'timemodified' => $file->get_timemodified(),
414 $courseimage = \core_course\external\course_summary_exporter::get_course_image($course);
415 if (!$courseimage) {
416 $courseimage = $OUTPUT->get_generated_url_for_course($context);
419 $courseresult = [
420 'id' => $course->id,
421 'shortname' => $course->shortname,
422 'fullname' => $course->fullname,
423 'displayname' => $displayname,
424 'idnumber' => $course->idnumber,
425 'visible' => $course->visible,
426 'summary' => $course->summary,
427 'summaryformat' => $course->summaryformat,
428 'format' => $course->format,
429 'courseimage' => $courseimage,
430 'showgrades' => $course->showgrades,
431 'lang' => clean_param($course->lang, PARAM_LANG),
432 'enablecompletion' => $course->enablecompletion,
433 'completionhascriteria' => $completionhascriteria,
434 'completionusertracked' => $completionusertracked,
435 'category' => $course->category,
436 'progress' => $progress,
437 'completed' => $completed,
438 'startdate' => $course->startdate,
439 'enddate' => $course->enddate,
440 'marker' => $course->marker,
441 'lastaccess' => $lastaccess,
442 'isfavourite' => isset($favouritecourseids[$course->id]),
443 'hidden' => $hidden,
444 'overviewfiles' => $overviewfiles,
445 'showactivitydates' => $course->showactivitydates,
446 'showcompletionconditions' => $course->showcompletionconditions,
447 'timemodified' => $course->timemodified,
449 if ($returnusercount) {
450 $courseresult['enrolledusercount'] = $enrolledusercount;
452 $result[] = $courseresult;
455 return $result;
459 * Returns description of method result value
461 * @return \core_external\external_description
463 public static function get_users_courses_returns() {
464 return new external_multiple_structure(
465 new external_single_structure(
466 array(
467 'id' => new external_value(PARAM_INT, 'id of course'),
468 'shortname' => new external_value(PARAM_RAW, 'short name of course'),
469 'fullname' => new external_value(PARAM_RAW, 'long name of course'),
470 'displayname' => new external_value(PARAM_RAW, 'course display name for lists.', VALUE_OPTIONAL),
471 'enrolledusercount' => new external_value(PARAM_INT, 'Number of enrolled users in this course',
472 VALUE_OPTIONAL),
473 'idnumber' => new external_value(PARAM_RAW, 'id number of course'),
474 'visible' => new external_value(PARAM_INT, '1 means visible, 0 means not yet visible course'),
475 'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL),
476 'summaryformat' => new external_format_value('summary', VALUE_OPTIONAL),
477 'format' => new external_value(PARAM_PLUGIN, 'course format: weeks, topics, social, site', VALUE_OPTIONAL),
478 'courseimage' => new external_value(PARAM_URL, 'The course image URL', VALUE_OPTIONAL),
479 'showgrades' => new external_value(PARAM_BOOL, 'true if grades are shown, otherwise false', VALUE_OPTIONAL),
480 'lang' => new external_value(PARAM_LANG, 'forced course language', VALUE_OPTIONAL),
481 'enablecompletion' => new external_value(PARAM_BOOL, 'true if completion is enabled, otherwise false',
482 VALUE_OPTIONAL),
483 'completionhascriteria' => new external_value(PARAM_BOOL, 'If completion criteria is set.', VALUE_OPTIONAL),
484 'completionusertracked' => new external_value(PARAM_BOOL, 'If the user is completion tracked.', VALUE_OPTIONAL),
485 'category' => new external_value(PARAM_INT, 'course category id', VALUE_OPTIONAL),
486 'progress' => new external_value(PARAM_FLOAT, 'Progress percentage', VALUE_OPTIONAL),
487 'completed' => new external_value(PARAM_BOOL, 'Whether the course is completed.', VALUE_OPTIONAL),
488 'startdate' => new external_value(PARAM_INT, 'Timestamp when the course start', VALUE_OPTIONAL),
489 'enddate' => new external_value(PARAM_INT, 'Timestamp when the course end', VALUE_OPTIONAL),
490 'marker' => new external_value(PARAM_INT, 'Course section marker.', VALUE_OPTIONAL),
491 'lastaccess' => new external_value(PARAM_INT, 'Last access to the course (timestamp).', VALUE_OPTIONAL),
492 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this course a favourite.', VALUE_OPTIONAL),
493 'hidden' => new external_value(PARAM_BOOL, 'If the user hide the course from the dashboard.', VALUE_OPTIONAL),
494 'overviewfiles' => new external_files('Overview files attached to this course.', VALUE_OPTIONAL),
495 'showactivitydates' => new external_value(PARAM_BOOL, 'Whether the activity dates are shown or not'),
496 'showcompletionconditions' => new external_value(PARAM_BOOL, 'Whether the activity completion conditions are shown or not'),
497 'timemodified' => new external_value(PARAM_INT, 'Last time course settings were updated (timestamp).',
498 VALUE_OPTIONAL),
505 * Returns description of method parameters value
507 * @return \core_external\external_description
509 public static function get_potential_users_parameters() {
510 return new external_function_parameters(
511 array(
512 'courseid' => new external_value(PARAM_INT, 'course id'),
513 'enrolid' => new external_value(PARAM_INT, 'enrolment id'),
514 'search' => new external_value(PARAM_RAW, 'query'),
515 'searchanywhere' => new external_value(PARAM_BOOL, 'find a match anywhere, or only at the beginning'),
516 'page' => new external_value(PARAM_INT, 'Page number'),
517 'perpage' => new external_value(PARAM_INT, 'Number per page'),
523 * Get potential users.
525 * @param int $courseid Course id
526 * @param int $enrolid Enrolment id
527 * @param string $search The query
528 * @param boolean $searchanywhere Match anywhere in the string
529 * @param int $page Page number
530 * @param int $perpage Max per page
531 * @return array An array of users
533 public static function get_potential_users($courseid, $enrolid, $search, $searchanywhere, $page, $perpage) {
534 global $PAGE, $DB, $CFG;
536 require_once($CFG->dirroot.'/enrol/locallib.php');
537 require_once($CFG->dirroot.'/user/lib.php');
539 $params = self::validate_parameters(
540 self::get_potential_users_parameters(),
541 array(
542 'courseid' => $courseid,
543 'enrolid' => $enrolid,
544 'search' => $search,
545 'searchanywhere' => $searchanywhere,
546 'page' => $page,
547 'perpage' => $perpage
550 $context = context_course::instance($params['courseid']);
551 try {
552 self::validate_context($context);
553 } catch (Exception $e) {
554 $exceptionparam = new stdClass();
555 $exceptionparam->message = $e->getMessage();
556 $exceptionparam->courseid = $params['courseid'];
557 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
559 require_capability('moodle/course:enrolreview', $context);
561 $course = $DB->get_record('course', array('id' => $params['courseid']));
562 $manager = new course_enrolment_manager($PAGE, $course);
564 $users = $manager->get_potential_users($params['enrolid'],
565 $params['search'],
566 $params['searchanywhere'],
567 $params['page'],
568 $params['perpage']);
570 $results = array();
571 // Add also extra user fields.
572 $identityfields = \core_user\fields::get_identity_fields($context, true);
573 $customprofilefields = [];
574 foreach ($identityfields as $key => $value) {
575 if ($fieldname = \core_user\fields::match_custom_field($value)) {
576 unset($identityfields[$key]);
577 $customprofilefields[$fieldname] = true;
580 if ($customprofilefields) {
581 $identityfields[] = 'customfields';
583 $requiredfields = array_merge(
584 ['id', 'fullname', 'profileimageurl', 'profileimageurlsmall'],
585 $identityfields
587 foreach ($users['users'] as $id => $user) {
588 // Note: We pass the course here to validate that the current user can at least view user details in this course.
589 // The user we are looking at is not in this course yet though - but we only fetch the minimal set of
590 // user records, and the user has been validated to have course:enrolreview in this course. Otherwise
591 // there is no way to find users who aren't in the course in order to enrol them.
592 if ($userdetails = user_get_user_details($user, $course, $requiredfields)) {
593 // For custom fields, only return the ones we actually need.
594 if ($customprofilefields && array_key_exists('customfields', $userdetails)) {
595 foreach ($userdetails['customfields'] as $key => $data) {
596 if (!array_key_exists($data['shortname'], $customprofilefields)) {
597 unset($userdetails['customfields'][$key]);
600 $userdetails['customfields'] = array_values($userdetails['customfields']);
602 $results[] = $userdetails;
605 return $results;
609 * Returns description of method result value
611 * @return \core_external\external_description
613 public static function get_potential_users_returns() {
614 global $CFG;
615 require_once($CFG->dirroot . '/user/externallib.php');
616 return new external_multiple_structure(core_user_external::user_description());
620 * Returns description of method parameters
622 * @return external_function_parameters
624 public static function search_users_parameters(): external_function_parameters {
625 return new external_function_parameters(
627 'courseid' => new external_value(PARAM_INT, 'course id'),
628 'search' => new external_value(PARAM_RAW, 'query'),
629 'searchanywhere' => new external_value(PARAM_BOOL, 'find a match anywhere, or only at the beginning'),
630 'page' => new external_value(PARAM_INT, 'Page number'),
631 'perpage' => new external_value(PARAM_INT, 'Number per page'),
632 'contextid' => new external_value(PARAM_INT, 'Context ID', VALUE_DEFAULT, null),
638 * Search course participants.
640 * @param int $courseid Course id
641 * @param string $search The query
642 * @param bool $searchanywhere Match anywhere in the string
643 * @param int $page Page number
644 * @param int $perpage Max per page
645 * @param ?int $contextid Context ID we are in - we might use search on activity level and its group mode can be different from course group mode.
646 * @return array An array of users
647 * @throws moodle_exception
649 public static function search_users(int $courseid, string $search, bool $searchanywhere, int $page, int $perpage, ?int $contextid = null): array {
650 global $PAGE, $CFG;
652 require_once($CFG->dirroot.'/enrol/locallib.php');
653 require_once($CFG->dirroot.'/user/lib.php');
655 $params = self::validate_parameters(
656 self::search_users_parameters(),
658 'courseid' => $courseid,
659 'search' => $search,
660 'searchanywhere' => $searchanywhere,
661 'page' => $page,
662 'perpage' => $perpage,
663 'contextid' => $contextid,
666 if (isset($contextid)) {
667 $context = context::instance_by_id($params['contextid']);
668 } else {
669 $context = context_course::instance($params['courseid']);
671 try {
672 self::validate_context($context);
673 } catch (Exception $e) {
674 $exceptionparam = new stdClass();
675 $exceptionparam->message = $e->getMessage();
676 $exceptionparam->courseid = $params['courseid'];
677 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
679 course_require_view_participants($context);
681 $course = get_course($params['courseid']);
682 $manager = new course_enrolment_manager($PAGE, $course);
684 $users = $manager->search_users(
685 $params['search'],
686 $params['searchanywhere'],
687 $params['page'],
688 $params['perpage'],
689 false,
690 $params['contextid']
693 $results = [];
694 // Add also extra user fields.
695 $requiredfields = array_merge(
696 ['id', 'fullname', 'profileimageurl', 'profileimageurlsmall'],
697 // TODO Does not support custom user profile fields (MDL-70456).
698 \core_user\fields::get_identity_fields($context, false)
700 foreach ($users['users'] as $user) {
701 if ($userdetails = user_get_user_details($user, $course, $requiredfields)) {
702 $results[] = $userdetails;
705 return $results;
709 * Returns description of method result value
711 * @return external_multiple_structure
713 public static function search_users_returns(): external_multiple_structure {
714 global $CFG;
715 require_once($CFG->dirroot . '/user/externallib.php');
716 return new external_multiple_structure(core_user_external::user_description());
720 * Returns description of method parameters
722 * @return external_function_parameters
724 public static function get_enrolled_users_parameters() {
725 return new external_function_parameters(
727 'courseid' => new external_value(PARAM_INT, 'course id'),
728 'options' => new external_multiple_structure(
729 new external_single_structure(
731 'name' => new external_value(PARAM_ALPHANUMEXT, 'option name'),
732 'value' => new external_value(PARAM_RAW, 'option value')
734 ), 'Option names:
735 * withcapability (string) return only users with this capability. This option requires \'moodle/role:review\' on the course context.
736 * groupid (integer) return only users in this group id. If the course has groups enabled and this param
737 isn\'t defined, returns all the viewable users.
738 This option requires \'moodle/site:accessallgroups\' on the course context if the
739 user doesn\'t belong to the group.
740 * onlyactive (integer) return only users with active enrolments and matching time restrictions.
741 This option requires \'moodle/course:enrolreview\' on the course context.
742 Please note that this option can\'t
743 be used together with onlysuspended (only one can be active).
744 * onlysuspended (integer) return only suspended users. This option requires
745 \'moodle/course:enrolreview\' on the course context. Please note that this option can\'t
746 be used together with onlyactive (only one can be active).
747 * userfields (\'string, string, ...\') return only the values of these user fields.
748 * limitfrom (integer) sql limit from.
749 * limitnumber (integer) maximum number of returned users.
750 * sortby (string) sort by id, firstname or lastname. For ordering like the site does, use siteorder.
751 * sortdirection (string) ASC or DESC',
752 VALUE_DEFAULT, []),
758 * Get course participants details
760 * @param int $courseid course id
761 * @param array $options options {
762 * 'name' => option name
763 * 'value' => option value
765 * @return array An array of users
767 public static function get_enrolled_users($courseid, $options = []) {
768 global $CFG, $USER, $DB;
770 require_once($CFG->dirroot . '/course/lib.php');
771 require_once($CFG->dirroot . "/user/lib.php");
773 $params = self::validate_parameters(
774 self::get_enrolled_users_parameters(),
776 'courseid'=>$courseid,
777 'options'=>$options
780 $withcapability = '';
781 $groupid = 0;
782 $onlyactive = false;
783 $onlysuspended = false;
784 $userfields = [];
785 $limitfrom = 0;
786 $limitnumber = 0;
787 $sortby = 'us.id';
788 $sortparams = [];
789 $sortdirection = 'ASC';
790 foreach ($options as $option) {
791 switch ($option['name']) {
792 case 'withcapability':
793 $withcapability = $option['value'];
794 break;
795 case 'groupid':
796 $groupid = (int)$option['value'];
797 break;
798 case 'onlyactive':
799 $onlyactive = !empty($option['value']);
800 break;
801 case 'onlysuspended':
802 $onlysuspended = !empty($option['value']);
803 break;
804 case 'userfields':
805 $thefields = explode(',', $option['value']);
806 foreach ($thefields as $f) {
807 $userfields[] = clean_param($f, PARAM_ALPHANUMEXT);
809 break;
810 case 'limitfrom' :
811 $limitfrom = clean_param($option['value'], PARAM_INT);
812 break;
813 case 'limitnumber' :
814 $limitnumber = clean_param($option['value'], PARAM_INT);
815 break;
816 case 'sortby':
817 $sortallowedvalues = ['id', 'firstname', 'lastname', 'siteorder'];
818 if (!in_array($option['value'], $sortallowedvalues)) {
819 throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' .
820 $option['value'] . '), allowed values are: ' . implode(',', $sortallowedvalues));
822 if ($option['value'] == 'siteorder') {
823 list($sortby, $sortparams) = users_order_by_sql('us');
824 } else {
825 $sortby = 'us.' . $option['value'];
827 break;
828 case 'sortdirection':
829 $sortdirection = strtoupper($option['value']);
830 $directionallowedvalues = ['ASC', 'DESC'];
831 if (!in_array($sortdirection, $directionallowedvalues)) {
832 throw new invalid_parameter_exception('Invalid value for sortdirection parameter
833 (value: ' . $sortdirection . '),' . 'allowed values are: ' . implode(',', $directionallowedvalues));
835 break;
839 $course = $DB->get_record('course', ['id' => $courseid], '*', MUST_EXIST);
840 $coursecontext = context_course::instance($courseid, IGNORE_MISSING);
841 if ($courseid == SITEID) {
842 $context = context_system::instance();
843 } else {
844 $context = $coursecontext;
846 try {
847 self::validate_context($context);
848 } catch (Exception $e) {
849 $exceptionparam = new stdClass();
850 $exceptionparam->message = $e->getMessage();
851 $exceptionparam->courseid = $params['courseid'];
852 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
855 course_require_view_participants($context);
857 // to overwrite this parameter, you need role:review capability
858 if ($withcapability) {
859 require_capability('moodle/role:review', $coursecontext);
861 // need accessallgroups capability if you want to overwrite this option
862 if (!empty($groupid) && !groups_is_member($groupid)) {
863 require_capability('moodle/site:accessallgroups', $coursecontext);
865 // to overwrite this option, you need course:enrolereview permission
866 if ($onlyactive || $onlysuspended) {
867 require_capability('moodle/course:enrolreview', $coursecontext);
870 list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive,
871 $onlysuspended);
872 $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
873 $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel)";
874 $enrolledparams['contextlevel'] = CONTEXT_USER;
876 $groupjoin = '';
877 if (empty($groupid) && groups_get_course_groupmode($course) == SEPARATEGROUPS &&
878 !has_capability('moodle/site:accessallgroups', $coursecontext)) {
879 // Filter by groups the user can view.
880 $usergroups = groups_get_user_groups($course->id);
881 if (!empty($usergroups['0'])) {
882 list($groupsql, $groupparams) = $DB->get_in_or_equal($usergroups['0'], SQL_PARAMS_NAMED);
883 $groupjoin = "JOIN {groups_members} gm ON (u.id = gm.userid AND gm.groupid $groupsql)";
884 $enrolledparams = array_merge($enrolledparams, $groupparams);
885 } else {
886 // User doesn't belong to any group, so he can't see any user. Return an empty array.
887 return [];
890 $sql = "SELECT us.*, COALESCE(ul.timeaccess, 0) AS lastcourseaccess
891 FROM {user} us
892 JOIN (
893 SELECT DISTINCT u.id $ctxselect
894 FROM {user} u $ctxjoin $groupjoin
895 WHERE u.id IN ($enrolledsql)
896 ) q ON q.id = us.id
897 LEFT JOIN {user_lastaccess} ul ON (ul.userid = us.id AND ul.courseid = :courseid)
898 ORDER BY $sortby $sortdirection";
899 $enrolledparams = array_merge($enrolledparams, $sortparams);
900 $enrolledparams['courseid'] = $courseid;
902 $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber);
903 $users = [];
904 foreach ($enrolledusers as $user) {
905 context_helper::preload_from_record($user);
906 if ($userdetails = user_get_user_details($user, $course, $userfields)) {
907 $users[] = $userdetails;
910 $enrolledusers->close();
912 return $users;
916 * Returns description of method result value
918 * @return \core_external\external_description
920 public static function get_enrolled_users_returns() {
921 return new external_multiple_structure(
922 new external_single_structure(
924 'id' => new external_value(PARAM_INT, 'ID of the user'),
925 'username' => new external_value(PARAM_RAW, 'Username policy is defined in Moodle security config', VALUE_OPTIONAL),
926 'firstname' => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
927 'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
928 'fullname' => new external_value(PARAM_NOTAGS, 'The fullname of the user'),
929 'email' => new external_value(PARAM_TEXT, 'An email address - allow email as root@localhost', VALUE_OPTIONAL),
930 'address' => new external_value(PARAM_TEXT, 'Postal address', VALUE_OPTIONAL),
931 'phone1' => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL),
932 'phone2' => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL),
933 'department' => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
934 'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
935 'idnumber' => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
936 'interests' => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
937 'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
938 'lastaccess' => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
939 'lastcourseaccess' => new external_value(PARAM_INT, 'last access to the course (0 if never)', VALUE_OPTIONAL),
940 'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
941 'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL),
942 'city' => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
943 'country' => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
944 'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small version', VALUE_OPTIONAL),
945 'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big version', VALUE_OPTIONAL),
946 'customfields' => new external_multiple_structure(
947 new external_single_structure(
949 'type' => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field - text field, checkbox...'),
950 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
951 'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
952 'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field - to be able to build the field class in the code'),
954 ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
955 'groups' => new external_multiple_structure(
956 new external_single_structure(
958 'id' => new external_value(PARAM_INT, 'group id'),
959 'name' => new external_value(PARAM_RAW, 'group name'),
960 'description' => new external_value(PARAM_RAW, 'group description'),
961 'descriptionformat' => new external_format_value('description'),
963 ), 'user groups', VALUE_OPTIONAL),
964 'roles' => new external_multiple_structure(
965 new external_single_structure(
967 'roleid' => new external_value(PARAM_INT, 'role id'),
968 'name' => new external_value(PARAM_RAW, 'role name'),
969 'shortname' => new external_value(PARAM_ALPHANUMEXT, 'role shortname'),
970 'sortorder' => new external_value(PARAM_INT, 'role sortorder')
972 ), 'user roles', VALUE_OPTIONAL),
973 'preferences' => new external_multiple_structure(
974 new external_single_structure(
976 'name' => new external_value(PARAM_RAW, 'The name of the preferences'),
977 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
979 ), 'User preferences', VALUE_OPTIONAL),
980 'enrolledcourses' => new external_multiple_structure(
981 new external_single_structure(
983 'id' => new external_value(PARAM_INT, 'Id of the course'),
984 'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'),
985 'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
987 ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
994 * Returns description of get_course_enrolment_methods() parameters
996 * @return external_function_parameters
998 public static function get_course_enrolment_methods_parameters() {
999 return new external_function_parameters(
1000 array(
1001 'courseid' => new external_value(PARAM_INT, 'Course id')
1007 * Get list of active course enrolment methods for current user.
1009 * @param int $courseid
1010 * @return array of course enrolment methods
1011 * @throws moodle_exception
1013 public static function get_course_enrolment_methods($courseid) {
1014 global $DB;
1016 $params = self::validate_parameters(self::get_course_enrolment_methods_parameters(), array('courseid' => $courseid));
1017 self::validate_context(context_system::instance());
1019 $course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST);
1020 if (!core_course_category::can_view_course_info($course) && !can_access_course($course)) {
1021 throw new moodle_exception('coursehidden');
1024 $result = array();
1025 $enrolinstances = enrol_get_instances($params['courseid'], true);
1026 foreach ($enrolinstances as $enrolinstance) {
1027 if ($enrolplugin = enrol_get_plugin($enrolinstance->enrol)) {
1028 if ($instanceinfo = $enrolplugin->get_enrol_info($enrolinstance)) {
1029 $result[] = (array) $instanceinfo;
1033 return $result;
1037 * Returns description of get_course_enrolment_methods() result value
1039 * @return \core_external\external_description
1041 public static function get_course_enrolment_methods_returns() {
1042 return new external_multiple_structure(
1043 new external_single_structure(
1044 array(
1045 'id' => new external_value(PARAM_INT, 'id of course enrolment instance'),
1046 'courseid' => new external_value(PARAM_INT, 'id of course'),
1047 'type' => new external_value(PARAM_PLUGIN, 'type of enrolment plugin'),
1048 'name' => new external_value(PARAM_RAW, 'name of enrolment plugin'),
1049 'status' => new external_value(PARAM_RAW, 'status of enrolment plugin'),
1050 'wsfunction' => new external_value(PARAM_ALPHANUMEXT, 'webservice function to get more information', VALUE_OPTIONAL),
1057 * Returns description of submit_user_enrolment_form parameters.
1059 * @return external_function_parameters
1061 public static function submit_user_enrolment_form_parameters() {
1062 return new external_function_parameters([
1063 'formdata' => new external_value(PARAM_RAW, 'The data from the event form'),
1068 * External function that handles the user enrolment form submission.
1070 * @param string $formdata The user enrolment form data in s URI encoded param string
1071 * @return array An array consisting of the processing result and error flag, if available
1073 public static function submit_user_enrolment_form($formdata) {
1074 global $CFG, $DB, $PAGE;
1076 // Parameter validation.
1077 $params = self::validate_parameters(self::submit_user_enrolment_form_parameters(), ['formdata' => $formdata]);
1079 $data = [];
1080 parse_str($params['formdata'], $data);
1082 $userenrolment = $DB->get_record('user_enrolments', ['id' => $data['ue']], '*', MUST_EXIST);
1083 $instance = $DB->get_record('enrol', ['id' => $userenrolment->enrolid], '*', MUST_EXIST);
1084 $plugin = enrol_get_plugin($instance->enrol);
1085 $course = get_course($instance->courseid);
1086 $context = context_course::instance($course->id);
1087 self::validate_context($context);
1089 require_once("$CFG->dirroot/enrol/editenrolment_form.php");
1090 $customformdata = [
1091 'ue' => $userenrolment,
1092 'modal' => true,
1093 'enrolinstancename' => $plugin->get_instance_name($instance)
1095 $mform = new enrol_user_enrolment_form(null, $customformdata, 'post', '', null, true, $data);
1097 if ($validateddata = $mform->get_data()) {
1098 if (!empty($validateddata->duration) && $validateddata->timeend == 0) {
1099 $validateddata->timeend = $validateddata->timestart + $validateddata->duration;
1101 require_once($CFG->dirroot . '/enrol/locallib.php');
1102 $manager = new course_enrolment_manager($PAGE, $course);
1103 $result = $manager->edit_enrolment($userenrolment, $validateddata);
1105 return ['result' => $result];
1106 } else {
1107 return ['result' => false, 'validationerror' => true];
1112 * Returns description of submit_user_enrolment_form() result value
1114 * @return \core_external\external_description
1116 public static function submit_user_enrolment_form_returns() {
1117 return new external_single_structure([
1118 'result' => new external_value(PARAM_BOOL, 'True if the user\'s enrolment was successfully updated'),
1119 'validationerror' => new external_value(PARAM_BOOL, 'Indicates invalid form data', VALUE_DEFAULT, false),
1124 * Returns description of unenrol_user_enrolment() parameters
1126 * @return external_function_parameters
1128 public static function unenrol_user_enrolment_parameters() {
1129 return new external_function_parameters(
1130 array(
1131 'ueid' => new external_value(PARAM_INT, 'User enrolment ID')
1137 * External function that unenrols a given user enrolment.
1139 * @param int $ueid The user enrolment ID.
1140 * @return array An array consisting of the processing result, errors.
1142 public static function unenrol_user_enrolment($ueid) {
1143 global $CFG, $DB, $PAGE;
1145 $params = self::validate_parameters(self::unenrol_user_enrolment_parameters(), [
1146 'ueid' => $ueid
1149 $result = false;
1150 $errors = [];
1152 $userenrolment = $DB->get_record('user_enrolments', ['id' => $params['ueid']], '*');
1153 if ($userenrolment) {
1154 $userid = $userenrolment->userid;
1155 $enrolid = $userenrolment->enrolid;
1156 $enrol = $DB->get_record('enrol', ['id' => $enrolid], '*', MUST_EXIST);
1157 $courseid = $enrol->courseid;
1158 $course = get_course($courseid);
1159 $context = context_course::instance($course->id);
1160 self::validate_context($context);
1161 } else {
1162 $validationerrors['invalidrequest'] = get_string('invalidrequest', 'enrol');
1165 // If the userenrolment exists, unenrol the user.
1166 if (!isset($validationerrors)) {
1167 require_once($CFG->dirroot . '/enrol/locallib.php');
1168 $manager = new course_enrolment_manager($PAGE, $course);
1169 $result = $manager->unenrol_user($userenrolment);
1170 } else {
1171 foreach ($validationerrors as $key => $errormessage) {
1172 $errors[] = (object)[
1173 'key' => $key,
1174 'message' => $errormessage
1179 return [
1180 'result' => $result,
1181 'errors' => $errors,
1186 * Returns description of unenrol_user_enrolment() result value
1188 * @return \core_external\external_description
1190 public static function unenrol_user_enrolment_returns() {
1191 return new external_single_structure(
1192 array(
1193 'result' => new external_value(PARAM_BOOL, 'True if the user\'s enrolment was successfully updated'),
1194 'errors' => new external_multiple_structure(
1195 new external_single_structure(
1196 array(
1197 'key' => new external_value(PARAM_TEXT, 'The data that failed the validation'),
1198 'message' => new external_value(PARAM_TEXT, 'The error message'),
1200 ), 'List of validation errors'
1208 * Role external functions
1210 * @package core_role
1211 * @category external
1212 * @copyright 2011 Jerome Mouneyrac
1213 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1214 * @since Moodle 2.2
1216 class core_role_external extends external_api {
1219 * Returns description of method parameters
1221 * @return external_function_parameters
1223 public static function assign_roles_parameters() {
1224 return new external_function_parameters(
1225 array(
1226 'assignments' => new external_multiple_structure(
1227 new external_single_structure(
1228 array(
1229 'roleid' => new external_value(PARAM_INT, 'Role to assign to the user'),
1230 'userid' => new external_value(PARAM_INT, 'The user that is going to be assigned'),
1231 'contextid' => new external_value(PARAM_INT, 'The context to assign the user role in', VALUE_OPTIONAL),
1232 'contextlevel' => new external_value(PARAM_ALPHA, 'The context level to assign the user role in
1233 (block, course, coursecat, system, user, module)', VALUE_OPTIONAL),
1234 'instanceid' => new external_value(PARAM_INT, 'The Instance id of item where the role needs to be assigned', VALUE_OPTIONAL),
1243 * Manual role assignments to users
1245 * @param array $assignments An array of manual role assignment
1247 public static function assign_roles($assignments) {
1248 global $DB;
1250 // Do basic automatic PARAM checks on incoming data, using params description
1251 // If any problems are found then exceptions are thrown with helpful error messages
1252 $params = self::validate_parameters(self::assign_roles_parameters(), array('assignments'=>$assignments));
1254 $transaction = $DB->start_delegated_transaction();
1256 foreach ($params['assignments'] as $assignment) {
1257 // Ensure correct context level with a instance id or contextid is passed.
1258 $context = self::get_context_from_params($assignment);
1260 // Ensure the current user is allowed to run this function in the enrolment context.
1261 self::validate_context($context);
1262 require_capability('moodle/role:assign', $context);
1264 // throw an exception if user is not able to assign the role in this context
1265 $roles = get_assignable_roles($context, ROLENAME_SHORT);
1267 if (!array_key_exists($assignment['roleid'], $roles)) {
1268 throw new invalid_parameter_exception('Can not assign roleid='.$assignment['roleid'].' in contextid='.$assignment['contextid']);
1271 role_assign($assignment['roleid'], $assignment['userid'], $context->id);
1274 $transaction->allow_commit();
1278 * Returns description of method result value
1280 * @return null
1282 public static function assign_roles_returns() {
1283 return null;
1288 * Returns description of method parameters
1290 * @return external_function_parameters
1292 public static function unassign_roles_parameters() {
1293 return new external_function_parameters(
1294 array(
1295 'unassignments' => new external_multiple_structure(
1296 new external_single_structure(
1297 array(
1298 'roleid' => new external_value(PARAM_INT, 'Role to assign to the user'),
1299 'userid' => new external_value(PARAM_INT, 'The user that is going to be assigned'),
1300 'contextid' => new external_value(PARAM_INT, 'The context to unassign the user role from', VALUE_OPTIONAL),
1301 'contextlevel' => new external_value(PARAM_ALPHA, 'The context level to unassign the user role in
1302 + (block, course, coursecat, system, user, module)', VALUE_OPTIONAL),
1303 'instanceid' => new external_value(PARAM_INT, 'The Instance id of item where the role needs to be unassigned', VALUE_OPTIONAL),
1312 * Unassign roles from users
1314 * @param array $unassignments An array of unassignment
1316 public static function unassign_roles($unassignments) {
1317 global $DB;
1319 // Do basic automatic PARAM checks on incoming data, using params description
1320 // If any problems are found then exceptions are thrown with helpful error messages
1321 $params = self::validate_parameters(self::unassign_roles_parameters(), array('unassignments'=>$unassignments));
1323 $transaction = $DB->start_delegated_transaction();
1325 foreach ($params['unassignments'] as $unassignment) {
1326 // Ensure the current user is allowed to run this function in the unassignment context
1327 $context = self::get_context_from_params($unassignment);
1328 self::validate_context($context);
1329 require_capability('moodle/role:assign', $context);
1331 // throw an exception if user is not able to unassign the role in this context
1332 $roles = get_assignable_roles($context, ROLENAME_SHORT);
1333 if (!array_key_exists($unassignment['roleid'], $roles)) {
1334 throw new invalid_parameter_exception('Can not unassign roleid='.$unassignment['roleid'].' in contextid='.$unassignment['contextid']);
1337 role_unassign($unassignment['roleid'], $unassignment['userid'], $context->id);
1340 $transaction->allow_commit();
1344 * Returns description of method result value
1346 * @return null
1348 public static function unassign_roles_returns() {
1349 return null;