Merge branch 'install_35_STABLE' of https://git.in.moodle.com/amosbot/moodle-install...
[moodle.git] / enrol / externallib.php
blob7c1b131ea3690d380e655e655b04846744344ff1
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/>.
18 /**
19 * External course participation api.
21 * This api is mostly read only, the actual enrol and unenrol
22 * support is in each enrol plugin.
24 * @package core_enrol
25 * @category external
26 * @copyright 2010 Jerome Mouneyrac
27 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30 defined('MOODLE_INTERNAL') || die();
32 require_once("$CFG->libdir/externallib.php");
34 /**
35 * Enrol external functions
37 * @package core_enrol
38 * @category external
39 * @copyright 2011 Jerome Mouneyrac
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 * @since Moodle 2.2
43 class core_enrol_external extends external_api {
45 /**
46 * Returns description of method parameters
48 * @return external_function_parameters
49 * @since Moodle 2.4
51 public static function get_enrolled_users_with_capability_parameters() {
52 return new external_function_parameters(
53 array (
54 'coursecapabilities' => new external_multiple_structure(
55 new external_single_structure(
56 array (
57 'courseid' => new external_value(PARAM_INT, 'Course ID number in the Moodle course table'),
58 'capabilities' => new external_multiple_structure(
59 new external_value(PARAM_CAPABILITY, 'Capability name, such as mod/forum:viewdiscussion')),
62 , 'course id and associated capability name'),
63 'options' => new external_multiple_structure(
64 new external_single_structure(
65 array(
66 'name' => new external_value(PARAM_ALPHANUMEXT, 'option name'),
67 'value' => new external_value(PARAM_RAW, 'option value')
69 ), 'Option names:
70 * groupid (integer) return only users in this group id. Requires \'moodle/site:accessallgroups\' .
71 * onlyactive (integer) only users with active enrolments. Requires \'moodle/course:enrolreview\' .
72 * userfields (\'string, string, ...\') return only the values of these user fields.
73 * limitfrom (integer) sql limit from.
74 * limitnumber (integer) max number of users per course and capability.', VALUE_DEFAULT, array())
79 /**
80 * Return users that have the capabilities for each course specified. For each course and capability specified,
81 * a list of the users that are enrolled in the course and have that capability are returned.
83 * @param array $coursecapabilities array of course ids and associated capability names {courseid, {capabilities}}
84 * @return array An array of arrays describing users for each associated courseid and capability
85 * @since Moodle 2.4
87 public static function get_enrolled_users_with_capability($coursecapabilities, $options) {
88 global $CFG, $DB;
90 require_once($CFG->dirroot . '/course/lib.php');
91 require_once($CFG->dirroot . "/user/lib.php");
93 if (empty($coursecapabilities)) {
94 throw new invalid_parameter_exception('Parameter can not be empty');
96 $params = self::validate_parameters(self::get_enrolled_users_with_capability_parameters(),
97 array ('coursecapabilities' => $coursecapabilities, 'options'=>$options));
98 $result = array();
99 $userlist = array();
100 $groupid = 0;
101 $onlyactive = false;
102 $userfields = array();
103 $limitfrom = 0;
104 $limitnumber = 0;
105 foreach ($params['options'] as $option) {
106 switch ($option['name']) {
107 case 'groupid':
108 $groupid = (int)$option['value'];
109 break;
110 case 'onlyactive':
111 $onlyactive = !empty($option['value']);
112 break;
113 case 'userfields':
114 $thefields = explode(',', $option['value']);
115 foreach ($thefields as $f) {
116 $userfields[] = clean_param($f, PARAM_ALPHANUMEXT);
118 break;
119 case 'limitfrom' :
120 $limitfrom = clean_param($option['value'], PARAM_INT);
121 break;
122 case 'limitnumber' :
123 $limitnumber = clean_param($option['value'], PARAM_INT);
124 break;
128 foreach ($params['coursecapabilities'] as $coursecapability) {
129 $courseid = $coursecapability['courseid'];
130 $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
131 $coursecontext = context_course::instance($courseid);
132 if (!$coursecontext) {
133 throw new moodle_exception('cannotfindcourse', 'error', '', null,
134 'The course id ' . $courseid . ' doesn\'t exist.');
136 if ($courseid == SITEID) {
137 $context = context_system::instance();
138 } else {
139 $context = $coursecontext;
141 try {
142 self::validate_context($context);
143 } catch (Exception $e) {
144 $exceptionparam = new stdClass();
145 $exceptionparam->message = $e->getMessage();
146 $exceptionparam->courseid = $params['courseid'];
147 throw new moodle_exception(get_string('errorcoursecontextnotvalid' , 'webservice', $exceptionparam));
150 course_require_view_participants($context);
152 // The accessallgroups capability is needed to use this option.
153 if (!empty($groupid) && groups_is_member($groupid)) {
154 require_capability('moodle/site:accessallgroups', $coursecontext);
156 // The course:enrolereview capability is needed to use this option.
157 if ($onlyactive) {
158 require_capability('moodle/course:enrolreview', $coursecontext);
161 // To see the permissions of others role:review capability is required.
162 require_capability('moodle/role:review', $coursecontext);
163 foreach ($coursecapability['capabilities'] as $capability) {
164 $courseusers['courseid'] = $courseid;
165 $courseusers['capability'] = $capability;
167 list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $capability, $groupid, $onlyactive);
169 $sql = "SELECT u.* FROM {user} u WHERE u.id IN ($enrolledsql) ORDER BY u.id ASC";
171 $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber);
172 $users = array();
173 foreach ($enrolledusers as $courseuser) {
174 if ($userdetails = user_get_user_details($courseuser, $course, $userfields)) {
175 $users[] = $userdetails;
178 $enrolledusers->close();
179 $courseusers['users'] = $users;
180 $result[] = $courseusers;
183 return $result;
187 * Returns description of method result value
189 * @return external_multiple_structure
190 * @since Moodle 2.4
192 public static function get_enrolled_users_with_capability_returns() {
193 return new external_multiple_structure( new external_single_structure (
194 array (
195 'courseid' => new external_value(PARAM_INT, 'Course ID number in the Moodle course table'),
196 'capability' => new external_value(PARAM_CAPABILITY, 'Capability name'),
197 'users' => new external_multiple_structure(
198 new external_single_structure(
199 array(
200 'id' => new external_value(PARAM_INT, 'ID of the user'),
201 'username' => new external_value(PARAM_RAW, 'Username', VALUE_OPTIONAL),
202 'firstname' => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
203 'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
204 'fullname' => new external_value(PARAM_NOTAGS, 'The fullname of the user'),
205 'email' => new external_value(PARAM_TEXT, 'Email address', VALUE_OPTIONAL),
206 'address' => new external_value(PARAM_MULTILANG, 'Postal address', VALUE_OPTIONAL),
207 'phone1' => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL),
208 'phone2' => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL),
209 'icq' => new external_value(PARAM_NOTAGS, 'icq number', VALUE_OPTIONAL),
210 'skype' => new external_value(PARAM_NOTAGS, 'skype id', VALUE_OPTIONAL),
211 'yahoo' => new external_value(PARAM_NOTAGS, 'yahoo id', VALUE_OPTIONAL),
212 'aim' => new external_value(PARAM_NOTAGS, 'aim id', VALUE_OPTIONAL),
213 'msn' => new external_value(PARAM_NOTAGS, 'msn number', VALUE_OPTIONAL),
214 'department' => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
215 'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
216 'interests' => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
217 'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
218 'lastaccess' => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
219 'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
220 'descriptionformat' => new external_value(PARAM_INT, 'User profile description format', VALUE_OPTIONAL),
221 'city' => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
222 'url' => new external_value(PARAM_URL, 'URL of the user', VALUE_OPTIONAL),
223 'country' => new external_value(PARAM_ALPHA, 'Country code of the user, such as AU or CZ', VALUE_OPTIONAL),
224 'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small', VALUE_OPTIONAL),
225 'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big', VALUE_OPTIONAL),
226 'customfields' => new external_multiple_structure(
227 new external_single_structure(
228 array(
229 'type' => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field'),
230 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
231 'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
232 'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field'),
234 ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
235 'groups' => new external_multiple_structure(
236 new external_single_structure(
237 array(
238 'id' => new external_value(PARAM_INT, 'group id'),
239 'name' => new external_value(PARAM_RAW, 'group name'),
240 'description' => new external_value(PARAM_RAW, 'group description'),
242 ), 'user groups', VALUE_OPTIONAL),
243 'roles' => new external_multiple_structure(
244 new external_single_structure(
245 array(
246 'roleid' => new external_value(PARAM_INT, 'role id'),
247 'name' => new external_value(PARAM_RAW, 'role name'),
248 'shortname' => new external_value(PARAM_ALPHANUMEXT, 'role shortname'),
249 'sortorder' => new external_value(PARAM_INT, 'role sortorder')
251 ), 'user roles', VALUE_OPTIONAL),
252 'preferences' => new external_multiple_structure(
253 new external_single_structure(
254 array(
255 'name' => new external_value(PARAM_RAW, 'The name of the preferences'),
256 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
258 ), 'User preferences', VALUE_OPTIONAL),
259 'enrolledcourses' => new external_multiple_structure(
260 new external_single_structure(
261 array(
262 'id' => new external_value(PARAM_INT, 'Id of the course'),
263 'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'),
264 'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
266 ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
268 ), 'List of users that are enrolled in the course and have the specified capability'),
275 * Returns description of method parameters
277 * @return external_function_parameters
279 public static function get_users_courses_parameters() {
280 return new external_function_parameters(
281 array(
282 'userid' => new external_value(PARAM_INT, 'user id'),
288 * Get list of courses user is enrolled in (only active enrolments are returned).
289 * Please note the current user must be able to access the course, otherwise the course is not included.
291 * @param int $userid
292 * @return array of courses
294 public static function get_users_courses($userid) {
295 global $CFG, $USER, $DB;
297 require_once($CFG->dirroot . '/course/lib.php');
299 // Do basic automatic PARAM checks on incoming data, using params description
300 // If any problems are found then exceptions are thrown with helpful error messages
301 $params = self::validate_parameters(self::get_users_courses_parameters(), array('userid'=>$userid));
302 $userid = $params['userid'];
303 $sameuser = $USER->id == $userid;
305 $courses = enrol_get_users_courses($params['userid'], true, 'id, shortname, fullname, idnumber, visible,
306 summary, summaryformat, format, showgrades, lang, enablecompletion, category, startdate, enddate');
307 $result = array();
309 foreach ($courses as $course) {
310 $context = context_course::instance($course->id, IGNORE_MISSING);
311 try {
312 self::validate_context($context);
313 } catch (Exception $e) {
314 // current user can not access this course, sorry we can not disclose who is enrolled in this course!
315 continue;
318 if (!$sameuser and !course_can_view_participants($context)) {
319 // we need capability to view participants
320 continue;
323 list($enrolledsqlselect, $enrolledparams) = get_enrolled_sql($context);
324 $enrolledsql = "SELECT COUNT('x') FROM ($enrolledsqlselect) enrolleduserids";
325 $enrolledusercount = $DB->count_records_sql($enrolledsql, $enrolledparams);
327 list($course->summary, $course->summaryformat) =
328 external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', null);
329 $course->fullname = external_format_string($course->fullname, $context->id);
330 $course->shortname = external_format_string($course->shortname, $context->id);
332 $progress = null;
333 // Return only private information if the user should be able to see it.
334 if ($course->enablecompletion &&
335 ($sameuser || completion_can_view_data($userid, $course))) {
337 $progress = \core_completion\progress::get_course_progress_percentage($course, $userid);
340 $result[] = array(
341 'id' => $course->id,
342 'shortname' => $course->shortname,
343 'fullname' => $course->fullname,
344 'idnumber' => $course->idnumber,
345 'visible' => $course->visible,
346 'enrolledusercount' => $enrolledusercount,
347 'summary' => $course->summary,
348 'summaryformat' => $course->summaryformat,
349 'format' => $course->format,
350 'showgrades' => $course->showgrades,
351 'lang' => clean_param($course->lang, PARAM_LANG),
352 'enablecompletion' => $course->enablecompletion,
353 'category' => $course->category,
354 'progress' => $progress,
355 'startdate' => $course->startdate,
356 'enddate' => $course->enddate,
360 return $result;
364 * Returns description of method result value
366 * @return external_description
368 public static function get_users_courses_returns() {
369 return new external_multiple_structure(
370 new external_single_structure(
371 array(
372 'id' => new external_value(PARAM_INT, 'id of course'),
373 'shortname' => new external_value(PARAM_RAW, 'short name of course'),
374 'fullname' => new external_value(PARAM_RAW, 'long name of course'),
375 'enrolledusercount' => new external_value(PARAM_INT, 'Number of enrolled users in this course'),
376 'idnumber' => new external_value(PARAM_RAW, 'id number of course'),
377 'visible' => new external_value(PARAM_INT, '1 means visible, 0 means hidden course'),
378 'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL),
379 'summaryformat' => new external_format_value('summary', VALUE_OPTIONAL),
380 'format' => new external_value(PARAM_PLUGIN, 'course format: weeks, topics, social, site', VALUE_OPTIONAL),
381 'showgrades' => new external_value(PARAM_BOOL, 'true if grades are shown, otherwise false', VALUE_OPTIONAL),
382 'lang' => new external_value(PARAM_LANG, 'forced course language', VALUE_OPTIONAL),
383 'enablecompletion' => new external_value(PARAM_BOOL, 'true if completion is enabled, otherwise false',
384 VALUE_OPTIONAL),
385 'category' => new external_value(PARAM_INT, 'course category id', VALUE_OPTIONAL),
386 'progress' => new external_value(PARAM_FLOAT, 'Progress percentage', VALUE_OPTIONAL),
387 'startdate' => new external_value(PARAM_INT, 'Timestamp when the course start', VALUE_OPTIONAL),
388 'enddate' => new external_value(PARAM_INT, 'Timestamp when the course end', VALUE_OPTIONAL),
395 * Returns description of method parameters value
397 * @return external_description
399 public static function get_potential_users_parameters() {
400 return new external_function_parameters(
401 array(
402 'courseid' => new external_value(PARAM_INT, 'course id'),
403 'enrolid' => new external_value(PARAM_INT, 'enrolment id'),
404 'search' => new external_value(PARAM_RAW, 'query'),
405 'searchanywhere' => new external_value(PARAM_BOOL, 'find a match anywhere, or only at the beginning'),
406 'page' => new external_value(PARAM_INT, 'Page number'),
407 'perpage' => new external_value(PARAM_INT, 'Number per page'),
413 * Get potential users.
415 * @param int $courseid Course id
416 * @param int $enrolid Enrolment id
417 * @param string $search The query
418 * @param boolean $searchanywhere Match anywhere in the string
419 * @param int $page Page number
420 * @param int $perpage Max per page
421 * @return array An array of users
423 public static function get_potential_users($courseid, $enrolid, $search, $searchanywhere, $page, $perpage) {
424 global $PAGE, $DB, $CFG;
426 require_once($CFG->dirroot.'/enrol/locallib.php');
427 require_once($CFG->dirroot.'/user/lib.php');
429 $params = self::validate_parameters(
430 self::get_potential_users_parameters(),
431 array(
432 'courseid' => $courseid,
433 'enrolid' => $enrolid,
434 'search' => $search,
435 'searchanywhere' => $searchanywhere,
436 'page' => $page,
437 'perpage' => $perpage
440 $context = context_course::instance($params['courseid']);
441 try {
442 self::validate_context($context);
443 } catch (Exception $e) {
444 $exceptionparam = new stdClass();
445 $exceptionparam->message = $e->getMessage();
446 $exceptionparam->courseid = $params['courseid'];
447 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
449 require_capability('moodle/course:enrolreview', $context);
451 $course = $DB->get_record('course', array('id' => $params['courseid']));
452 $manager = new course_enrolment_manager($PAGE, $course);
454 $users = $manager->get_potential_users($params['enrolid'],
455 $params['search'],
456 $params['searchanywhere'],
457 $params['page'],
458 $params['perpage']);
460 $results = array();
461 // Add also extra user fields.
462 $requiredfields = array_merge(
463 ['id', 'fullname', 'profileimageurl', 'profileimageurlsmall'],
464 get_extra_user_fields($context)
466 foreach ($users['users'] as $id => $user) {
467 // Note: We pass the course here to validate that the current user can at least view user details in this course.
468 // The user we are looking at is not in this course yet though - but we only fetch the minimal set of
469 // user records, and the user has been validated to have course:enrolreview in this course. Otherwise
470 // there is no way to find users who aren't in the course in order to enrol them.
471 if ($userdetails = user_get_user_details($user, $course, $requiredfields)) {
472 $results[] = $userdetails;
475 return $results;
479 * Returns description of method result value
481 * @return external_description
483 public static function get_potential_users_returns() {
484 global $CFG;
485 require_once($CFG->dirroot . '/user/externallib.php');
486 return new external_multiple_structure(core_user_external::user_description());
490 * Returns description of method parameters
492 * @return external_function_parameters
494 public static function get_enrolled_users_parameters() {
495 return new external_function_parameters(
496 array(
497 'courseid' => new external_value(PARAM_INT, 'course id'),
498 'options' => new external_multiple_structure(
499 new external_single_structure(
500 array(
501 'name' => new external_value(PARAM_ALPHANUMEXT, 'option name'),
502 'value' => new external_value(PARAM_RAW, 'option value')
504 ), 'Option names:
505 * withcapability (string) return only users with this capability. This option requires \'moodle/role:review\' on the course context.
506 * groupid (integer) return only users in this group id. If the course has groups enabled and this param
507 isn\'t defined, returns all the viewable users.
508 This option requires \'moodle/site:accessallgroups\' on the course context if the
509 user doesn\'t belong to the group.
510 * onlyactive (integer) return only users with active enrolments and matching time restrictions. This option requires \'moodle/course:enrolreview\' on the course context.
511 * userfields (\'string, string, ...\') return only the values of these user fields.
512 * limitfrom (integer) sql limit from.
513 * limitnumber (integer) maximum number of returned users.
514 * sortby (string) sort by id, firstname or lastname. For ordering like the site does, use siteorder.
515 * sortdirection (string) ASC or DESC',
516 VALUE_DEFAULT, array()),
522 * Get course participants details
524 * @param int $courseid course id
525 * @param array $options options {
526 * 'name' => option name
527 * 'value' => option value
529 * @return array An array of users
531 public static function get_enrolled_users($courseid, $options = array()) {
532 global $CFG, $USER, $DB;
534 require_once($CFG->dirroot . '/course/lib.php');
535 require_once($CFG->dirroot . "/user/lib.php");
537 $params = self::validate_parameters(
538 self::get_enrolled_users_parameters(),
539 array(
540 'courseid'=>$courseid,
541 'options'=>$options
544 $withcapability = '';
545 $groupid = 0;
546 $onlyactive = false;
547 $userfields = array();
548 $limitfrom = 0;
549 $limitnumber = 0;
550 $sortby = 'us.id';
551 $sortparams = array();
552 $sortdirection = 'ASC';
553 foreach ($options as $option) {
554 switch ($option['name']) {
555 case 'withcapability':
556 $withcapability = $option['value'];
557 break;
558 case 'groupid':
559 $groupid = (int)$option['value'];
560 break;
561 case 'onlyactive':
562 $onlyactive = !empty($option['value']);
563 break;
564 case 'userfields':
565 $thefields = explode(',', $option['value']);
566 foreach ($thefields as $f) {
567 $userfields[] = clean_param($f, PARAM_ALPHANUMEXT);
569 break;
570 case 'limitfrom' :
571 $limitfrom = clean_param($option['value'], PARAM_INT);
572 break;
573 case 'limitnumber' :
574 $limitnumber = clean_param($option['value'], PARAM_INT);
575 break;
576 case 'sortby':
577 $sortallowedvalues = array('id', 'firstname', 'lastname', 'siteorder');
578 if (!in_array($option['value'], $sortallowedvalues)) {
579 throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $option['value'] . '),' .
580 'allowed values are: ' . implode(',', $sortallowedvalues));
582 if ($option['value'] == 'siteorder') {
583 list($sortby, $sortparams) = users_order_by_sql('us');
584 } else {
585 $sortby = 'us.' . $option['value'];
587 break;
588 case 'sortdirection':
589 $sortdirection = strtoupper($option['value']);
590 $directionallowedvalues = array('ASC', 'DESC');
591 if (!in_array($sortdirection, $directionallowedvalues)) {
592 throw new invalid_parameter_exception('Invalid value for sortdirection parameter
593 (value: ' . $sortdirection . '),' . 'allowed values are: ' . implode(',', $directionallowedvalues));
595 break;
599 $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
600 $coursecontext = context_course::instance($courseid, IGNORE_MISSING);
601 if ($courseid == SITEID) {
602 $context = context_system::instance();
603 } else {
604 $context = $coursecontext;
606 try {
607 self::validate_context($context);
608 } catch (Exception $e) {
609 $exceptionparam = new stdClass();
610 $exceptionparam->message = $e->getMessage();
611 $exceptionparam->courseid = $params['courseid'];
612 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
615 course_require_view_participants($context);
617 // to overwrite this parameter, you need role:review capability
618 if ($withcapability) {
619 require_capability('moodle/role:review', $coursecontext);
621 // need accessallgroups capability if you want to overwrite this option
622 if (!empty($groupid) && !groups_is_member($groupid)) {
623 require_capability('moodle/site:accessallgroups', $coursecontext);
625 // to overwrite this option, you need course:enrolereview permission
626 if ($onlyactive) {
627 require_capability('moodle/course:enrolreview', $coursecontext);
630 list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive);
631 $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
632 $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel)";
633 $enrolledparams['contextlevel'] = CONTEXT_USER;
635 $groupjoin = '';
636 if (empty($groupid) && groups_get_course_groupmode($course) == SEPARATEGROUPS &&
637 !has_capability('moodle/site:accessallgroups', $coursecontext)) {
638 // Filter by groups the user can view.
639 $usergroups = groups_get_user_groups($course->id);
640 if (!empty($usergroups['0'])) {
641 list($groupsql, $groupparams) = $DB->get_in_or_equal($usergroups['0'], SQL_PARAMS_NAMED);
642 $groupjoin = "JOIN {groups_members} gm ON (u.id = gm.userid AND gm.groupid $groupsql)";
643 $enrolledparams = array_merge($enrolledparams, $groupparams);
644 } else {
645 // User doesn't belong to any group, so he can't see any user. Return an empty array.
646 return array();
649 $sql = "SELECT us.*
650 FROM {user} us
651 JOIN (
652 SELECT DISTINCT u.id $ctxselect
653 FROM {user} u $ctxjoin $groupjoin
654 WHERE u.id IN ($enrolledsql)
655 ) q ON q.id = us.id
656 ORDER BY $sortby $sortdirection";
657 $enrolledparams = array_merge($enrolledparams, $sortparams);
658 $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber);
659 $users = array();
660 foreach ($enrolledusers as $user) {
661 context_helper::preload_from_record($user);
662 if ($userdetails = user_get_user_details($user, $course, $userfields)) {
663 $users[] = $userdetails;
666 $enrolledusers->close();
668 return $users;
672 * Returns description of method result value
674 * @return external_description
676 public static function get_enrolled_users_returns() {
677 return new external_multiple_structure(
678 new external_single_structure(
679 array(
680 'id' => new external_value(PARAM_INT, 'ID of the user'),
681 'username' => new external_value(PARAM_RAW, 'Username policy is defined in Moodle security config', VALUE_OPTIONAL),
682 'firstname' => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
683 'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
684 'fullname' => new external_value(PARAM_NOTAGS, 'The fullname of the user'),
685 'email' => new external_value(PARAM_TEXT, 'An email address - allow email as root@localhost', VALUE_OPTIONAL),
686 'address' => new external_value(PARAM_TEXT, 'Postal address', VALUE_OPTIONAL),
687 'phone1' => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL),
688 'phone2' => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL),
689 'icq' => new external_value(PARAM_NOTAGS, 'icq number', VALUE_OPTIONAL),
690 'skype' => new external_value(PARAM_NOTAGS, 'skype id', VALUE_OPTIONAL),
691 'yahoo' => new external_value(PARAM_NOTAGS, 'yahoo id', VALUE_OPTIONAL),
692 'aim' => new external_value(PARAM_NOTAGS, 'aim id', VALUE_OPTIONAL),
693 'msn' => new external_value(PARAM_NOTAGS, 'msn number', VALUE_OPTIONAL),
694 'department' => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
695 'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
696 'idnumber' => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
697 'interests' => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
698 'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
699 'lastaccess' => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
700 'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
701 'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL),
702 'city' => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
703 'url' => new external_value(PARAM_URL, 'URL of the user', VALUE_OPTIONAL),
704 'country' => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
705 'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small version', VALUE_OPTIONAL),
706 'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big version', VALUE_OPTIONAL),
707 'customfields' => new external_multiple_structure(
708 new external_single_structure(
709 array(
710 'type' => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field - text field, checkbox...'),
711 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
712 'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
713 'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field - to be able to build the field class in the code'),
715 ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
716 'groups' => new external_multiple_structure(
717 new external_single_structure(
718 array(
719 'id' => new external_value(PARAM_INT, 'group id'),
720 'name' => new external_value(PARAM_RAW, 'group name'),
721 'description' => new external_value(PARAM_RAW, 'group description'),
722 'descriptionformat' => new external_format_value('description'),
724 ), 'user groups', VALUE_OPTIONAL),
725 'roles' => new external_multiple_structure(
726 new external_single_structure(
727 array(
728 'roleid' => new external_value(PARAM_INT, 'role id'),
729 'name' => new external_value(PARAM_RAW, 'role name'),
730 'shortname' => new external_value(PARAM_ALPHANUMEXT, 'role shortname'),
731 'sortorder' => new external_value(PARAM_INT, 'role sortorder')
733 ), 'user roles', VALUE_OPTIONAL),
734 'preferences' => new external_multiple_structure(
735 new external_single_structure(
736 array(
737 'name' => new external_value(PARAM_RAW, 'The name of the preferences'),
738 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
740 ), 'User preferences', VALUE_OPTIONAL),
741 'enrolledcourses' => new external_multiple_structure(
742 new external_single_structure(
743 array(
744 'id' => new external_value(PARAM_INT, 'Id of the course'),
745 'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'),
746 'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
748 ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
755 * Returns description of get_course_enrolment_methods() parameters
757 * @return external_function_parameters
759 public static function get_course_enrolment_methods_parameters() {
760 return new external_function_parameters(
761 array(
762 'courseid' => new external_value(PARAM_INT, 'Course id')
768 * Get list of active course enrolment methods for current user.
770 * @param int $courseid
771 * @return array of course enrolment methods
772 * @throws moodle_exception
774 public static function get_course_enrolment_methods($courseid) {
775 global $DB;
777 $params = self::validate_parameters(self::get_course_enrolment_methods_parameters(), array('courseid' => $courseid));
778 self::validate_context(context_system::instance());
780 $course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST);
781 $context = context_course::instance($course->id);
782 if (!$course->visible and !has_capability('moodle/course:viewhiddencourses', $context)) {
783 throw new moodle_exception('coursehidden');
786 $result = array();
787 $enrolinstances = enrol_get_instances($params['courseid'], true);
788 foreach ($enrolinstances as $enrolinstance) {
789 if ($enrolplugin = enrol_get_plugin($enrolinstance->enrol)) {
790 if ($instanceinfo = $enrolplugin->get_enrol_info($enrolinstance)) {
791 $result[] = (array) $instanceinfo;
795 return $result;
799 * Returns description of get_course_enrolment_methods() result value
801 * @return external_description
803 public static function get_course_enrolment_methods_returns() {
804 return new external_multiple_structure(
805 new external_single_structure(
806 array(
807 'id' => new external_value(PARAM_INT, 'id of course enrolment instance'),
808 'courseid' => new external_value(PARAM_INT, 'id of course'),
809 'type' => new external_value(PARAM_PLUGIN, 'type of enrolment plugin'),
810 'name' => new external_value(PARAM_RAW, 'name of enrolment plugin'),
811 'status' => new external_value(PARAM_RAW, 'status of enrolment plugin'),
812 'wsfunction' => new external_value(PARAM_ALPHANUMEXT, 'webservice function to get more information', VALUE_OPTIONAL),
819 * Returns description of edit_user_enrolment() parameters
821 * @return external_function_parameters
823 public static function edit_user_enrolment_parameters() {
824 return new external_function_parameters(
825 array(
826 'courseid' => new external_value(PARAM_INT, 'User enrolment ID'),
827 'ueid' => new external_value(PARAM_INT, 'User enrolment ID'),
828 'status' => new external_value(PARAM_INT, 'Enrolment status'),
829 'timestart' => new external_value(PARAM_INT, 'Enrolment start timestamp', VALUE_DEFAULT, 0),
830 'timeend' => new external_value(PARAM_INT, 'Enrolment end timestamp', VALUE_DEFAULT, 0),
836 * External function that updates a given user enrolment.
838 * @param int $courseid The course ID.
839 * @param int $ueid The user enrolment ID.
840 * @param int $status The enrolment status.
841 * @param int $timestart Enrolment start timestamp.
842 * @param int $timeend Enrolment end timestamp.
843 * @return array An array consisting of the processing result, errors and form output, if available.
845 public static function edit_user_enrolment($courseid, $ueid, $status, $timestart = 0, $timeend = 0) {
846 global $CFG, $DB, $PAGE;
848 $params = self::validate_parameters(self::edit_user_enrolment_parameters(), [
849 'courseid' => $courseid,
850 'ueid' => $ueid,
851 'status' => $status,
852 'timestart' => $timestart,
853 'timeend' => $timeend,
856 $course = get_course($courseid);
857 $context = context_course::instance($course->id);
858 self::validate_context($context);
860 $userenrolment = $DB->get_record('user_enrolments', ['id' => $params['ueid']], '*', MUST_EXIST);
861 $userenroldata = [
862 'status' => $params['status'],
863 'timestart' => $params['timestart'],
864 'timeend' => $params['timeend'],
867 $result = false;
868 $errors = [];
870 // Validate data against the edit user enrolment form.
871 $instance = $DB->get_record('enrol', ['id' => $userenrolment->enrolid], '*', MUST_EXIST);
872 $plugin = enrol_get_plugin($instance->enrol);
873 require_once("$CFG->dirroot/enrol/editenrolment_form.php");
874 $customformdata = [
875 'ue' => $userenrolment,
876 'modal' => true,
877 'enrolinstancename' => $plugin->get_instance_name($instance)
879 $mform = new \enrol_user_enrolment_form(null, $customformdata, 'post', '', null, true, $userenroldata);
880 $mform->set_data($userenroldata);
881 $validationerrors = $mform->validation($userenroldata, null);
882 if (empty($validationerrors)) {
883 require_once($CFG->dirroot . '/enrol/locallib.php');
884 $manager = new course_enrolment_manager($PAGE, $course);
885 $result = $manager->edit_enrolment($userenrolment, (object)$userenroldata);
886 } else {
887 foreach ($validationerrors as $key => $errormessage) {
888 $errors[] = (object)[
889 'key' => $key,
890 'message' => $errormessage
895 return [
896 'result' => $result,
897 'errors' => $errors,
902 * Returns description of edit_user_enrolment() result value
904 * @return external_description
906 public static function edit_user_enrolment_returns() {
907 return new external_single_structure(
908 array(
909 'result' => new external_value(PARAM_BOOL, 'True if the user\'s enrolment was successfully updated'),
910 'errors' => new external_multiple_structure(
911 new external_single_structure(
912 array(
913 'key' => new external_value(PARAM_TEXT, 'The data that failed the validation'),
914 'message' => new external_value(PARAM_TEXT, 'The error message'),
916 ), 'List of validation errors'
923 * Returns description of unenrol_user_enrolment() parameters
925 * @return external_function_parameters
927 public static function unenrol_user_enrolment_parameters() {
928 return new external_function_parameters(
929 array(
930 'ueid' => new external_value(PARAM_INT, 'User enrolment ID')
936 * External function that unenrols a given user enrolment.
938 * @param int $ueid The user enrolment ID.
939 * @return array An array consisting of the processing result, errors.
941 public static function unenrol_user_enrolment($ueid) {
942 global $CFG, $DB, $PAGE;
944 $params = self::validate_parameters(self::unenrol_user_enrolment_parameters(), [
945 'ueid' => $ueid
948 $result = false;
949 $errors = [];
951 $userenrolment = $DB->get_record('user_enrolments', ['id' => $params['ueid']], '*');
952 if ($userenrolment) {
953 $userid = $userenrolment->userid;
954 $enrolid = $userenrolment->enrolid;
955 $enrol = $DB->get_record('enrol', ['id' => $enrolid], '*', MUST_EXIST);
956 $courseid = $enrol->courseid;
957 $course = get_course($courseid);
958 $context = context_course::instance($course->id);
959 self::validate_context($context);
960 } else {
961 $validationerrors['invalidrequest'] = get_string('invalidrequest', 'enrol');
964 // If the userenrolment exists, unenrol the user.
965 if (!isset($validationerrors)) {
966 require_once($CFG->dirroot . '/enrol/locallib.php');
967 $manager = new course_enrolment_manager($PAGE, $course);
968 $result = $manager->unenrol_user($userenrolment);
969 } else {
970 foreach ($validationerrors as $key => $errormessage) {
971 $errors[] = (object)[
972 'key' => $key,
973 'message' => $errormessage
978 return [
979 'result' => $result,
980 'errors' => $errors,
985 * Returns description of unenrol_user_enrolment() result value
987 * @return external_description
989 public static function unenrol_user_enrolment_returns() {
990 return new external_single_structure(
991 array(
992 'result' => new external_value(PARAM_BOOL, 'True if the user\'s enrolment was successfully updated'),
993 'errors' => new external_multiple_structure(
994 new external_single_structure(
995 array(
996 'key' => new external_value(PARAM_TEXT, 'The data that failed the validation'),
997 'message' => new external_value(PARAM_TEXT, 'The error message'),
999 ), 'List of validation errors'
1007 * Role external functions
1009 * @package core_role
1010 * @category external
1011 * @copyright 2011 Jerome Mouneyrac
1012 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1013 * @since Moodle 2.2
1015 class core_role_external extends external_api {
1018 * Returns description of method parameters
1020 * @return external_function_parameters
1022 public static function assign_roles_parameters() {
1023 return new external_function_parameters(
1024 array(
1025 'assignments' => new external_multiple_structure(
1026 new external_single_structure(
1027 array(
1028 'roleid' => new external_value(PARAM_INT, 'Role to assign to the user'),
1029 'userid' => new external_value(PARAM_INT, 'The user that is going to be assigned'),
1030 'contextid' => new external_value(PARAM_INT, 'The context to assign the user role in', VALUE_OPTIONAL),
1031 'contextlevel' => new external_value(PARAM_ALPHA, 'The context level to assign the user role in
1032 (block, course, coursecat, system, user, module)', VALUE_OPTIONAL),
1033 'instanceid' => new external_value(PARAM_INT, 'The Instance id of item where the role needs to be assigned', VALUE_OPTIONAL),
1042 * Manual role assignments to users
1044 * @param array $assignments An array of manual role assignment
1046 public static function assign_roles($assignments) {
1047 global $DB;
1049 // Do basic automatic PARAM checks on incoming data, using params description
1050 // If any problems are found then exceptions are thrown with helpful error messages
1051 $params = self::validate_parameters(self::assign_roles_parameters(), array('assignments'=>$assignments));
1053 $transaction = $DB->start_delegated_transaction();
1055 foreach ($params['assignments'] as $assignment) {
1056 // Ensure correct context level with a instance id or contextid is passed.
1057 $context = self::get_context_from_params($assignment);
1059 // Ensure the current user is allowed to run this function in the enrolment context.
1060 self::validate_context($context);
1061 require_capability('moodle/role:assign', $context);
1063 // throw an exception if user is not able to assign the role in this context
1064 $roles = get_assignable_roles($context, ROLENAME_SHORT);
1066 if (!array_key_exists($assignment['roleid'], $roles)) {
1067 throw new invalid_parameter_exception('Can not assign roleid='.$assignment['roleid'].' in contextid='.$assignment['contextid']);
1070 role_assign($assignment['roleid'], $assignment['userid'], $context->id);
1073 $transaction->allow_commit();
1077 * Returns description of method result value
1079 * @return null
1081 public static function assign_roles_returns() {
1082 return null;
1087 * Returns description of method parameters
1089 * @return external_function_parameters
1091 public static function unassign_roles_parameters() {
1092 return new external_function_parameters(
1093 array(
1094 'unassignments' => new external_multiple_structure(
1095 new external_single_structure(
1096 array(
1097 'roleid' => new external_value(PARAM_INT, 'Role to assign to the user'),
1098 'userid' => new external_value(PARAM_INT, 'The user that is going to be assigned'),
1099 'contextid' => new external_value(PARAM_INT, 'The context to unassign the user role from', VALUE_OPTIONAL),
1100 'contextlevel' => new external_value(PARAM_ALPHA, 'The context level to unassign the user role in
1101 + (block, course, coursecat, system, user, module)', VALUE_OPTIONAL),
1102 'instanceid' => new external_value(PARAM_INT, 'The Instance id of item where the role needs to be unassigned', VALUE_OPTIONAL),
1111 * Unassign roles from users
1113 * @param array $unassignments An array of unassignment
1115 public static function unassign_roles($unassignments) {
1116 global $DB;
1118 // Do basic automatic PARAM checks on incoming data, using params description
1119 // If any problems are found then exceptions are thrown with helpful error messages
1120 $params = self::validate_parameters(self::unassign_roles_parameters(), array('unassignments'=>$unassignments));
1122 $transaction = $DB->start_delegated_transaction();
1124 foreach ($params['unassignments'] as $unassignment) {
1125 // Ensure the current user is allowed to run this function in the unassignment context
1126 $context = self::get_context_from_params($unassignment);
1127 self::validate_context($context);
1128 require_capability('moodle/role:assign', $context);
1130 // throw an exception if user is not able to unassign the role in this context
1131 $roles = get_assignable_roles($context, ROLENAME_SHORT);
1132 if (!array_key_exists($unassignment['roleid'], $roles)) {
1133 throw new invalid_parameter_exception('Can not unassign roleid='.$unassignment['roleid'].' in contextid='.$unassignment['contextid']);
1136 role_unassign($unassignment['roleid'], $unassignment['userid'], $context->id);
1139 $transaction->allow_commit();
1143 * Returns description of method result value
1145 * @return null
1147 public static function unassign_roles_returns() {
1148 return null;