ab0f6990dccf15db9e9e808cfdb6079036060141
[moodle.git] / enrol / externallib.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * External course participation api.
20  *
21  * This api is mostly read only, the actual enrol and unenrol
22  * support is in each enrol plugin.
23  *
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
28  */
30 defined('MOODLE_INTERNAL') || die();
32 require_once("$CFG->libdir/externallib.php");
34 /**
35  * Enrol external functions
36  *
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
42  */
43 class core_enrol_external extends external_api {
45     /**
46      * Returns description of method parameters
47      *
48      * @return external_function_parameters
49      * @since Moodle 2.4
50      */
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')),
60                         )
61                     )
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')
68                         )
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())
75             )
76         );
77     }
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.
82      *
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
86      */
87     public static function get_enrolled_users_with_capability($coursecapabilities, $options) {
88         global $CFG, $DB;
89         require_once($CFG->dirroot . "/user/lib.php");
91         if (empty($coursecapabilities)) {
92             throw new invalid_parameter_exception('Parameter can not be empty');
93         }
94         $params = self::validate_parameters(self::get_enrolled_users_with_capability_parameters(),
95             array ('coursecapabilities' => $coursecapabilities,  'options'=>$options));
96         $result = array();
97         $userlist = array();
98         $groupid        = 0;
99         $onlyactive     = false;
100         $userfields     = array();
101         $limitfrom = 0;
102         $limitnumber = 0;
103         foreach ($params['options'] as $option) {
104             switch ($option['name']) {
105                 case 'groupid':
106                     $groupid = (int)$option['value'];
107                     break;
108                 case 'onlyactive':
109                     $onlyactive = !empty($option['value']);
110                     break;
111                 case 'userfields':
112                     $thefields = explode(',', $option['value']);
113                     foreach ($thefields as $f) {
114                         $userfields[] = clean_param($f, PARAM_ALPHANUMEXT);
115                     }
116                     break;
117                 case 'limitfrom' :
118                     $limitfrom = clean_param($option['value'], PARAM_INT);
119                     break;
120                 case 'limitnumber' :
121                     $limitnumber = clean_param($option['value'], PARAM_INT);
122                     break;
123             }
124         }
126         foreach ($params['coursecapabilities'] as $coursecapability) {
127             $courseid = $coursecapability['courseid'];
128             $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
129             $coursecontext = context_course::instance($courseid);
130             if (!$coursecontext) {
131                 throw new moodle_exception('cannotfindcourse', 'error', '', null,
132                         'The course id ' . $courseid . ' doesn\'t exist.');
133             }
134             if ($courseid == SITEID) {
135                 $context = context_system::instance();
136             } else {
137                 $context = $coursecontext;
138             }
139             try {
140                 self::validate_context($context);
141             } catch (Exception $e) {
142                 $exceptionparam = new stdClass();
143                 $exceptionparam->message = $e->getMessage();
144                 $exceptionparam->courseid = $params['courseid'];
145                 throw new moodle_exception(get_string('errorcoursecontextnotvalid' , 'webservice', $exceptionparam));
146             }
148             if ($courseid == SITEID) {
149                 require_capability('moodle/site:viewparticipants', $context);
150             } else {
151                 require_capability('moodle/course:viewparticipants', $context);
152             }
153             // The accessallgroups capability is needed to use this option.
154             if (!empty($groupid) && groups_is_member($groupid)) {
155                 require_capability('moodle/site:accessallgroups', $coursecontext);
156             }
157             // The course:enrolereview capability is needed to use this option.
158             if ($onlyactive) {
159                 require_capability('moodle/course:enrolreview', $coursecontext);
160             }
162             // To see the permissions of others role:review capability is required.
163             require_capability('moodle/role:review', $coursecontext);
164             foreach ($coursecapability['capabilities'] as $capability) {
165                 $courseusers['courseid'] = $courseid;
166                 $courseusers['capability'] = $capability;
168                 list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $capability, $groupid, $onlyactive);
170                 $sql = "SELECT u.* FROM {user} u WHERE u.id IN ($enrolledsql) ORDER BY u.id ASC";
172                 $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber);
173                 $users = array();
174                 foreach ($enrolledusers as $courseuser) {
175                     if ($userdetails = user_get_user_details($courseuser, $course, $userfields)) {
176                         $users[] = $userdetails;
177                     }
178                 }
179                 $enrolledusers->close();
180                 $courseusers['users'] = $users;
181                 $result[] = $courseusers;
182             }
183         }
184         return $result;
185     }
187     /**
188      * Returns description of method result value
189      *
190      * @return external_multiple_structure
191      * @since Moodle 2.4
192      */
193     public static function get_enrolled_users_with_capability_returns() {
194         return  new external_multiple_structure( new external_single_structure (
195                 array (
196                     'courseid' => new external_value(PARAM_INT, 'Course ID number in the Moodle course table'),
197                     'capability' => new external_value(PARAM_CAPABILITY, 'Capability name'),
198                     'users' => new external_multiple_structure(
199                         new external_single_structure(
200                 array(
201                     'id'    => new external_value(PARAM_INT, 'ID of the user'),
202                     'username'    => new external_value(PARAM_RAW, 'Username', VALUE_OPTIONAL),
203                     'firstname'   => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
204                     'lastname'    => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
205                     'fullname'    => new external_value(PARAM_NOTAGS, 'The fullname of the user'),
206                     'email'       => new external_value(PARAM_TEXT, 'Email address', VALUE_OPTIONAL),
207                     'address'     => new external_value(PARAM_MULTILANG, 'Postal address', VALUE_OPTIONAL),
208                     'phone1'      => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL),
209                     'phone2'      => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL),
210                     'icq'         => new external_value(PARAM_NOTAGS, 'icq number', VALUE_OPTIONAL),
211                     'skype'       => new external_value(PARAM_NOTAGS, 'skype id', VALUE_OPTIONAL),
212                     'yahoo'       => new external_value(PARAM_NOTAGS, 'yahoo id', VALUE_OPTIONAL),
213                     'aim'         => new external_value(PARAM_NOTAGS, 'aim id', VALUE_OPTIONAL),
214                     'msn'         => new external_value(PARAM_NOTAGS, 'msn number', VALUE_OPTIONAL),
215                     'department'  => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
216                     'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
217                     'interests'   => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
218                     'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
219                     'lastaccess'  => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
220                     'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
221                     'descriptionformat' => new external_value(PARAM_INT, 'User profile description format', VALUE_OPTIONAL),
222                     'city'        => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
223                     'url'         => new external_value(PARAM_URL, 'URL of the user', VALUE_OPTIONAL),
224                     'country'     => new external_value(PARAM_ALPHA, 'Country code of the user, such as AU or CZ', VALUE_OPTIONAL),
225                     'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small', VALUE_OPTIONAL),
226                     'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big', VALUE_OPTIONAL),
227                     'customfields' => new external_multiple_structure(
228                         new external_single_structure(
229                             array(
230                                 'type'  => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field'),
231                                 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
232                                 'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
233                                 'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field'),
234                             )
235                         ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
236                     'groups' => new external_multiple_structure(
237                         new external_single_structure(
238                             array(
239                                 'id'  => new external_value(PARAM_INT, 'group id'),
240                                 'name' => new external_value(PARAM_RAW, 'group name'),
241                                 'description' => new external_value(PARAM_RAW, 'group description'),
242                             )
243                         ), 'user groups', VALUE_OPTIONAL),
244                     'roles' => new external_multiple_structure(
245                         new external_single_structure(
246                             array(
247                                 'roleid'       => new external_value(PARAM_INT, 'role id'),
248                                 'name'         => new external_value(PARAM_RAW, 'role name'),
249                                 'shortname'    => new external_value(PARAM_ALPHANUMEXT, 'role shortname'),
250                                 'sortorder'    => new external_value(PARAM_INT, 'role sortorder')
251                             )
252                         ), 'user roles', VALUE_OPTIONAL),
253                     'preferences' => new external_multiple_structure(
254                         new external_single_structure(
255                             array(
256                                 'name'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the preferences'),
257                                 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
258                             )
259                     ), 'User preferences', VALUE_OPTIONAL),
260                     'enrolledcourses' => new external_multiple_structure(
261                         new external_single_structure(
262                             array(
263                                 'id'  => new external_value(PARAM_INT, 'Id of the course'),
264                                 'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'),
265                                 'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
266                             )
267                     ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
268                 )
269                         ), 'List of users that are enrolled in the course and have the specified capability'),
270                     )
271                 )
272             );
273     }
275     /**
276      * Returns description of method parameters
277      *
278      * @return external_function_parameters
279      */
280     public static function get_users_courses_parameters() {
281         return new external_function_parameters(
282             array(
283                 'userid' => new external_value(PARAM_INT, 'user id'),
284             )
285         );
286     }
288     /**
289      * Get list of courses user is enrolled in (only active enrolments are returned).
290      * Please note the current user must be able to access the course, otherwise the course is not included.
291      *
292      * @param int $userid
293      * @return array of courses
294      */
295     public static function get_users_courses($userid) {
296         global $USER, $DB;
298         // Do basic automatic PARAM checks on incoming data, using params description
299         // If any problems are found then exceptions are thrown with helpful error messages
300         $params = self::validate_parameters(self::get_users_courses_parameters(), array('userid'=>$userid));
302         $courses = enrol_get_users_courses($params['userid'], true, 'id, shortname, fullname, idnumber, visible,
303                    summary, summaryformat, format, showgrades, lang, enablecompletion, category, startdate, enddate');
304         $result = array();
306         foreach ($courses as $course) {
307             $context = context_course::instance($course->id, IGNORE_MISSING);
308             try {
309                 self::validate_context($context);
310             } catch (Exception $e) {
311                 // current user can not access this course, sorry we can not disclose who is enrolled in this course!
312                 continue;
313             }
315             if ($userid != $USER->id and !has_capability('moodle/course:viewparticipants', $context)) {
316                 // we need capability to view participants
317                 continue;
318             }
320             list($enrolledsqlselect, $enrolledparams) = get_enrolled_sql($context);
321             $enrolledsql = "SELECT COUNT('x') FROM ($enrolledsqlselect) enrolleduserids";
322             $enrolledusercount = $DB->count_records_sql($enrolledsql, $enrolledparams);
324             list($course->summary, $course->summaryformat) =
325                 external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', null);
326             $course->fullname = external_format_string($course->fullname, $context->id);
327             $course->shortname = external_format_string($course->shortname, $context->id);
329             $progress = null;
330             if ($course->enablecompletion) {
331                 $progress = \core_completion\progress::get_course_progress_percentage($course);
332             }
334             $result[] = array(
335                 'id' => $course->id,
336                 'shortname' => $course->shortname,
337                 'fullname' => $course->fullname,
338                 'idnumber' => $course->idnumber,
339                 'visible' => $course->visible,
340                 'enrolledusercount' => $enrolledusercount,
341                 'summary' => $course->summary,
342                 'summaryformat' => $course->summaryformat,
343                 'format' => $course->format,
344                 'showgrades' => $course->showgrades,
345                 'lang' => $course->lang,
346                 'enablecompletion' => $course->enablecompletion,
347                 'category' => $course->category,
348                 'progress' => $progress,
349                 'startdate' => $course->startdate,
350                 'enddate' => $course->enddate,
351             );
352         }
354         return $result;
355     }
357     /**
358      * Returns description of method result value
359      *
360      * @return external_description
361      */
362     public static function get_users_courses_returns() {
363         return new external_multiple_structure(
364             new external_single_structure(
365                 array(
366                     'id'        => new external_value(PARAM_INT, 'id of course'),
367                     'shortname' => new external_value(PARAM_RAW, 'short name of course'),
368                     'fullname'  => new external_value(PARAM_RAW, 'long name of course'),
369                     'enrolledusercount' => new external_value(PARAM_INT, 'Number of enrolled users in this course'),
370                     'idnumber'  => new external_value(PARAM_RAW, 'id number of course'),
371                     'visible'   => new external_value(PARAM_INT, '1 means visible, 0 means hidden course'),
372                     'summary'   => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL),
373                     'summaryformat' => new external_format_value('summary', VALUE_OPTIONAL),
374                     'format'    => new external_value(PARAM_PLUGIN, 'course format: weeks, topics, social, site', VALUE_OPTIONAL),
375                     'showgrades' => new external_value(PARAM_BOOL, 'true if grades are shown, otherwise false', VALUE_OPTIONAL),
376                     'lang'      => new external_value(PARAM_LANG, 'forced course language', VALUE_OPTIONAL),
377                     'enablecompletion' => new external_value(PARAM_BOOL, 'true if completion is enabled, otherwise false',
378                                                                 VALUE_OPTIONAL),
379                     'category' => new external_value(PARAM_INT, 'course category id', VALUE_OPTIONAL),
380                     'progress' => new external_value(PARAM_FLOAT, 'Progress percentage', VALUE_OPTIONAL),
381                     'startdate' => new external_value(PARAM_INT, 'Timestamp when the course start', VALUE_OPTIONAL),
382                     'enddate' => new external_value(PARAM_INT, 'Timestamp when the course end', VALUE_OPTIONAL),
383                 )
384             )
385         );
386     }
388     /**
389      * Returns description of method parameters value
390      *
391      * @return external_description
392      */
393     public static function get_potential_users_parameters() {
394         return new external_function_parameters(
395             array(
396                 'courseid' => new external_value(PARAM_INT, 'course id'),
397                 'enrolid' => new external_value(PARAM_INT, 'enrolment id'),
398                 'search' => new external_value(PARAM_RAW, 'query'),
399                 'searchanywhere' => new external_value(PARAM_BOOL, 'find a match anywhere, or only at the beginning'),
400                 'page' => new external_value(PARAM_INT, 'Page number'),
401                 'perpage' => new external_value(PARAM_INT, 'Number per page'),
402             )
403         );
404     }
406     /**
407      * Get potential users.
408      *
409      * @param int $courseid Course id
410      * @param int $enrolid Enrolment id
411      * @param string $search The query
412      * @param boolean $searchanywhere Match anywhere in the string
413      * @param int $page Page number
414      * @param int $perpage Max per page
415      * @return array An array of users
416      */
417     public static function get_potential_users($courseid, $enrolid, $search, $searchanywhere, $page, $perpage) {
418         global $PAGE, $DB, $CFG;
420         require_once($CFG->dirroot.'/enrol/locallib.php');
421         require_once($CFG->dirroot.'/user/lib.php');
423         $params = self::validate_parameters(
424             self::get_potential_users_parameters(),
425             array(
426                 'courseid' => $courseid,
427                 'enrolid' => $enrolid,
428                 'search' => $search,
429                 'searchanywhere' => $searchanywhere,
430                 'page' => $page,
431                 'perpage' => $perpage
432             )
433         );
434         $context = context_course::instance($params['courseid']);
435         try {
436             self::validate_context($context);
437         } catch (Exception $e) {
438             $exceptionparam = new stdClass();
439             $exceptionparam->message = $e->getMessage();
440             $exceptionparam->courseid = $params['courseid'];
441             throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
442         }
443         require_capability('moodle/course:enrolreview', $context);
445         $course = $DB->get_record('course', array('id' => $params['courseid']));
446         $manager = new course_enrolment_manager($PAGE, $course);
448         $users = $manager->get_potential_users($params['enrolid'],
449                                                $params['search'],
450                                                $params['searchanywhere'],
451                                                $params['page'],
452                                                $params['perpage']);
454         $results = array();
455         foreach ($users['users'] as $id => $user) {
456             // Note: We pass the course here to validate that the current user can at least view user details in this course.
457             // The user we are looking at is not in this course yet though - but we only fetch the minimal set of
458             // user records, and the user has been validated to have course:enrolreview in this course. Otherwise
459             // there is no way to find users who aren't in the course in order to enrol them.
460             if ($userdetails = user_get_user_details($user, $course)) {
461                 $results[] = $userdetails;
462             }
463         }
464         return $results;
465     }
467     /**
468      * Returns description of method result value
469      *
470      * @return external_description
471      */
472     public static function get_potential_users_returns() {
473         global $CFG;
474         require_once($CFG->dirroot . '/user/externallib.php');
475         return new external_multiple_structure(core_user_external::user_description());
476     }
478     /**
479      * Returns description of method parameters
480      *
481      * @return external_function_parameters
482      */
483     public static function get_enrolled_users_parameters() {
484         return new external_function_parameters(
485             array(
486                 'courseid' => new external_value(PARAM_INT, 'course id'),
487                 'options'  => new external_multiple_structure(
488                     new external_single_structure(
489                         array(
490                             'name'  => new external_value(PARAM_ALPHANUMEXT, 'option name'),
491                             'value' => new external_value(PARAM_RAW, 'option value')
492                         )
493                     ), 'Option names:
494                             * withcapability (string) return only users with this capability. This option requires \'moodle/role:review\' on the course context.
495                             * groupid (integer) return only users in this group id. If the course has groups enabled and this param
496                                                 isn\'t defined, returns all the viewable users.
497                                                 This option requires \'moodle/site:accessallgroups\' on the course context if the
498                                                 user doesn\'t belong to the group.
499                             * onlyactive (integer) return only users with active enrolments and matching time restrictions. This option requires \'moodle/course:enrolreview\' on the course context.
500                             * userfields (\'string, string, ...\') return only the values of these user fields.
501                             * limitfrom (integer) sql limit from.
502                             * limitnumber (integer) maximum number of returned users.
503                             * sortby (string) sort by id, firstname or lastname. For ordering like the site does, use siteorder.
504                             * sortdirection (string) ASC or DESC',
505                             VALUE_DEFAULT, array()),
506             )
507         );
508     }
510     /**
511      * Get course participants details
512      *
513      * @param int $courseid  course id
514      * @param array $options options {
515      *                                'name' => option name
516      *                                'value' => option value
517      *                               }
518      * @return array An array of users
519      */
520     public static function get_enrolled_users($courseid, $options = array()) {
521         global $CFG, $USER, $DB;
522         require_once($CFG->dirroot . "/user/lib.php");
524         $params = self::validate_parameters(
525             self::get_enrolled_users_parameters(),
526             array(
527                 'courseid'=>$courseid,
528                 'options'=>$options
529             )
530         );
531         $withcapability = '';
532         $groupid        = 0;
533         $onlyactive     = false;
534         $userfields     = array();
535         $limitfrom = 0;
536         $limitnumber = 0;
537         $sortby = 'us.id';
538         $sortparams = array();
539         $sortdirection = 'ASC';
540         foreach ($options as $option) {
541             switch ($option['name']) {
542             case 'withcapability':
543                 $withcapability = $option['value'];
544                 break;
545             case 'groupid':
546                 $groupid = (int)$option['value'];
547                 break;
548             case 'onlyactive':
549                 $onlyactive = !empty($option['value']);
550                 break;
551             case 'userfields':
552                 $thefields = explode(',', $option['value']);
553                 foreach ($thefields as $f) {
554                     $userfields[] = clean_param($f, PARAM_ALPHANUMEXT);
555                 }
556                 break;
557             case 'limitfrom' :
558                 $limitfrom = clean_param($option['value'], PARAM_INT);
559                 break;
560             case 'limitnumber' :
561                 $limitnumber = clean_param($option['value'], PARAM_INT);
562                 break;
563             case 'sortby':
564                 $sortallowedvalues = array('id', 'firstname', 'lastname', 'siteorder');
565                 if (!in_array($option['value'], $sortallowedvalues)) {
566                     throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $option['value'] . '),' .
567                         'allowed values are: ' . implode(',', $sortallowedvalues));
568                 }
569                 if ($option['value'] == 'siteorder') {
570                     list($sortby, $sortparams) = users_order_by_sql('us');
571                 } else {
572                     $sortby = 'us.' . $option['value'];
573                 }
574                 break;
575             case 'sortdirection':
576                 $sortdirection = strtoupper($option['value']);
577                 $directionallowedvalues = array('ASC', 'DESC');
578                 if (!in_array($sortdirection, $directionallowedvalues)) {
579                     throw new invalid_parameter_exception('Invalid value for sortdirection parameter
580                         (value: ' . $sortdirection . '),' . 'allowed values are: ' . implode(',', $directionallowedvalues));
581                 }
582                 break;
583             }
584         }
586         $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
587         $coursecontext = context_course::instance($courseid, IGNORE_MISSING);
588         if ($courseid == SITEID) {
589             $context = context_system::instance();
590         } else {
591             $context = $coursecontext;
592         }
593         try {
594             self::validate_context($context);
595         } catch (Exception $e) {
596             $exceptionparam = new stdClass();
597             $exceptionparam->message = $e->getMessage();
598             $exceptionparam->courseid = $params['courseid'];
599             throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
600         }
602         if ($courseid == SITEID) {
603             require_capability('moodle/site:viewparticipants', $context);
604         } else {
605             require_capability('moodle/course:viewparticipants', $context);
606         }
607         // to overwrite this parameter, you need role:review capability
608         if ($withcapability) {
609             require_capability('moodle/role:review', $coursecontext);
610         }
611         // need accessallgroups capability if you want to overwrite this option
612         if (!empty($groupid) && !groups_is_member($groupid)) {
613             require_capability('moodle/site:accessallgroups', $coursecontext);
614         }
615         // to overwrite this option, you need course:enrolereview permission
616         if ($onlyactive) {
617             require_capability('moodle/course:enrolreview', $coursecontext);
618         }
620         list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive);
621         $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
622         $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel)";
623         $enrolledparams['contextlevel'] = CONTEXT_USER;
625         $groupjoin = '';
626         if (empty($groupid) && groups_get_course_groupmode($course) == SEPARATEGROUPS &&
627                 !has_capability('moodle/site:accessallgroups', $coursecontext)) {
628             // Filter by groups the user can view.
629             $usergroups = groups_get_user_groups($course->id);
630             if (!empty($usergroups['0'])) {
631                 list($groupsql, $groupparams) = $DB->get_in_or_equal($usergroups['0'], SQL_PARAMS_NAMED);
632                 $groupjoin = "JOIN {groups_members} gm ON (u.id = gm.userid AND gm.groupid $groupsql)";
633                 $enrolledparams = array_merge($enrolledparams, $groupparams);
634             } else {
635                 // User doesn't belong to any group, so he can't see any user. Return an empty array.
636                 return array();
637             }
638         }
639         $sql = "SELECT us.*
640                   FROM {user} us
641                   JOIN (
642                       SELECT DISTINCT u.id $ctxselect
643                         FROM {user} u $ctxjoin $groupjoin
644                        WHERE u.id IN ($enrolledsql)
645                   ) q ON q.id = us.id
646                 ORDER BY $sortby $sortdirection";
647         $enrolledparams = array_merge($enrolledparams, $sortparams);
648         $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber);
649         $users = array();
650         foreach ($enrolledusers as $user) {
651             context_helper::preload_from_record($user);
652             if ($userdetails = user_get_user_details($user, $course, $userfields)) {
653                 $users[] = $userdetails;
654             }
655         }
656         $enrolledusers->close();
658         return $users;
659     }
661     /**
662      * Returns description of method result value
663      *
664      * @return external_description
665      */
666     public static function get_enrolled_users_returns() {
667         return new external_multiple_structure(
668             new external_single_structure(
669                 array(
670                     'id'    => new external_value(PARAM_INT, 'ID of the user'),
671                     'username'    => new external_value(PARAM_RAW, 'Username policy is defined in Moodle security config', VALUE_OPTIONAL),
672                     'firstname'   => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
673                     'lastname'    => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
674                     'fullname'    => new external_value(PARAM_NOTAGS, 'The fullname of the user'),
675                     'email'       => new external_value(PARAM_TEXT, 'An email address - allow email as root@localhost', VALUE_OPTIONAL),
676                     'address'     => new external_value(PARAM_TEXT, 'Postal address', VALUE_OPTIONAL),
677                     'phone1'      => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL),
678                     'phone2'      => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL),
679                     'icq'         => new external_value(PARAM_NOTAGS, 'icq number', VALUE_OPTIONAL),
680                     'skype'       => new external_value(PARAM_NOTAGS, 'skype id', VALUE_OPTIONAL),
681                     'yahoo'       => new external_value(PARAM_NOTAGS, 'yahoo id', VALUE_OPTIONAL),
682                     'aim'         => new external_value(PARAM_NOTAGS, 'aim id', VALUE_OPTIONAL),
683                     'msn'         => new external_value(PARAM_NOTAGS, 'msn number', VALUE_OPTIONAL),
684                     'department'  => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
685                     'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
686                     'idnumber'    => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
687                     'interests'   => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
688                     'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
689                     'lastaccess'  => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
690                     'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
691                     'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL),
692                     'city'        => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
693                     'url'         => new external_value(PARAM_URL, 'URL of the user', VALUE_OPTIONAL),
694                     'country'     => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
695                     'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small version', VALUE_OPTIONAL),
696                     'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big version', VALUE_OPTIONAL),
697                     'customfields' => new external_multiple_structure(
698                         new external_single_structure(
699                             array(
700                                 'type'  => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field - text field, checkbox...'),
701                                 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
702                                 'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
703                                 'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field - to be able to build the field class in the code'),
704                             )
705                         ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
706                     'groups' => new external_multiple_structure(
707                         new external_single_structure(
708                             array(
709                                 'id'  => new external_value(PARAM_INT, 'group id'),
710                                 'name' => new external_value(PARAM_RAW, 'group name'),
711                                 'description' => new external_value(PARAM_RAW, 'group description'),
712                                 'descriptionformat' => new external_format_value('description'),
713                             )
714                         ), 'user groups', VALUE_OPTIONAL),
715                     'roles' => new external_multiple_structure(
716                         new external_single_structure(
717                             array(
718                                 'roleid'       => new external_value(PARAM_INT, 'role id'),
719                                 'name'         => new external_value(PARAM_RAW, 'role name'),
720                                 'shortname'    => new external_value(PARAM_ALPHANUMEXT, 'role shortname'),
721                                 'sortorder'    => new external_value(PARAM_INT, 'role sortorder')
722                             )
723                         ), 'user roles', VALUE_OPTIONAL),
724                     'preferences' => new external_multiple_structure(
725                         new external_single_structure(
726                             array(
727                                 'name'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the preferences'),
728                                 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
729                             )
730                     ), 'User preferences', VALUE_OPTIONAL),
731                     'enrolledcourses' => new external_multiple_structure(
732                         new external_single_structure(
733                             array(
734                                 'id'  => new external_value(PARAM_INT, 'Id of the course'),
735                                 'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'),
736                                 'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
737                             )
738                     ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
739                 )
740             )
741         );
742     }
744     /**
745      * Returns description of get_course_enrolment_methods() parameters
746      *
747      * @return external_function_parameters
748      */
749     public static function get_course_enrolment_methods_parameters() {
750         return new external_function_parameters(
751             array(
752                 'courseid' => new external_value(PARAM_INT, 'Course id')
753             )
754         );
755     }
757     /**
758      * Get list of active course enrolment methods for current user.
759      *
760      * @param int $courseid
761      * @return array of course enrolment methods
762      * @throws moodle_exception
763      */
764     public static function get_course_enrolment_methods($courseid) {
765         global $DB;
767         $params = self::validate_parameters(self::get_course_enrolment_methods_parameters(), array('courseid' => $courseid));
768         self::validate_context(context_system::instance());
770         $course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST);
771         $context = context_course::instance($course->id);
772         if (!$course->visible and !has_capability('moodle/course:viewhiddencourses', $context)) {
773             throw new moodle_exception('coursehidden');
774         }
776         $result = array();
777         $enrolinstances = enrol_get_instances($params['courseid'], true);
778         foreach ($enrolinstances as $enrolinstance) {
779             if ($enrolplugin = enrol_get_plugin($enrolinstance->enrol)) {
780                 if ($instanceinfo = $enrolplugin->get_enrol_info($enrolinstance)) {
781                     $result[] = (array) $instanceinfo;
782                 }
783             }
784         }
785         return $result;
786     }
788     /**
789      * Returns description of get_course_enrolment_methods() result value
790      *
791      * @return external_description
792      */
793     public static function get_course_enrolment_methods_returns() {
794         return new external_multiple_structure(
795             new external_single_structure(
796                 array(
797                     'id' => new external_value(PARAM_INT, 'id of course enrolment instance'),
798                     'courseid' => new external_value(PARAM_INT, 'id of course'),
799                     'type' => new external_value(PARAM_PLUGIN, 'type of enrolment plugin'),
800                     'name' => new external_value(PARAM_RAW, 'name of enrolment plugin'),
801                     'status' => new external_value(PARAM_RAW, 'status of enrolment plugin'),
802                     'wsfunction' => new external_value(PARAM_ALPHANUMEXT, 'webservice function to get more information', VALUE_OPTIONAL),
803                 )
804             )
805         );
806     }
809 /**
810  * Role external functions
811  *
812  * @package    core_role
813  * @category   external
814  * @copyright  2011 Jerome Mouneyrac
815  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
816  * @since Moodle 2.2
817  */
818 class core_role_external extends external_api {
820     /**
821      * Returns description of method parameters
822      *
823      * @return external_function_parameters
824      */
825     public static function assign_roles_parameters() {
826         return new external_function_parameters(
827             array(
828                 'assignments' => new external_multiple_structure(
829                     new external_single_structure(
830                         array(
831                             'roleid'    => new external_value(PARAM_INT, 'Role to assign to the user'),
832                             'userid'    => new external_value(PARAM_INT, 'The user that is going to be assigned'),
833                             'contextid' => new external_value(PARAM_INT, 'The context to assign the user role in', VALUE_OPTIONAL),
834                             'contextlevel' => new external_value(PARAM_ALPHA, 'The context level to assign the user role in
835                                     (block, course, coursecat, system, user, module)', VALUE_OPTIONAL),
836                             'instanceid' => new external_value(PARAM_INT, 'The Instance id of item where the role needs to be assigned', VALUE_OPTIONAL),
837                         )
838                     )
839                 )
840             )
841         );
842     }
844     /**
845      * Manual role assignments to users
846      *
847      * @param array $assignments An array of manual role assignment
848      */
849     public static function assign_roles($assignments) {
850         global $DB;
852         // Do basic automatic PARAM checks on incoming data, using params description
853         // If any problems are found then exceptions are thrown with helpful error messages
854         $params = self::validate_parameters(self::assign_roles_parameters(), array('assignments'=>$assignments));
856         $transaction = $DB->start_delegated_transaction();
858         foreach ($params['assignments'] as $assignment) {
859             // Ensure correct context level with a instance id or contextid is passed.
860             $context = self::get_context_from_params($assignment);
862             // Ensure the current user is allowed to run this function in the enrolment context.
863             self::validate_context($context);
864             require_capability('moodle/role:assign', $context);
866             // throw an exception if user is not able to assign the role in this context
867             $roles = get_assignable_roles($context, ROLENAME_SHORT);
869             if (!array_key_exists($assignment['roleid'], $roles)) {
870                 throw new invalid_parameter_exception('Can not assign roleid='.$assignment['roleid'].' in contextid='.$assignment['contextid']);
871             }
873             role_assign($assignment['roleid'], $assignment['userid'], $context->id);
874         }
876         $transaction->allow_commit();
877     }
879     /**
880      * Returns description of method result value
881      *
882      * @return null
883      */
884     public static function assign_roles_returns() {
885         return null;
886     }
889     /**
890      * Returns description of method parameters
891      *
892      * @return external_function_parameters
893      */
894     public static function unassign_roles_parameters() {
895         return new external_function_parameters(
896             array(
897                 'unassignments' => new external_multiple_structure(
898                     new external_single_structure(
899                         array(
900                             'roleid'    => new external_value(PARAM_INT, 'Role to assign to the user'),
901                             'userid'    => new external_value(PARAM_INT, 'The user that is going to be assigned'),
902                             'contextid' => new external_value(PARAM_INT, 'The context to unassign the user role from', VALUE_OPTIONAL),
903                             'contextlevel' => new external_value(PARAM_ALPHA, 'The context level to unassign the user role in
904 +                                    (block, course, coursecat, system, user, module)', VALUE_OPTIONAL),
905                             'instanceid' => new external_value(PARAM_INT, 'The Instance id of item where the role needs to be unassigned', VALUE_OPTIONAL),
906                         )
907                     )
908                 )
909             )
910         );
911     }
913      /**
914      * Unassign roles from users
915      *
916      * @param array $unassignments An array of unassignment
917      */
918     public static function unassign_roles($unassignments) {
919          global $DB;
921         // Do basic automatic PARAM checks on incoming data, using params description
922         // If any problems are found then exceptions are thrown with helpful error messages
923         $params = self::validate_parameters(self::unassign_roles_parameters(), array('unassignments'=>$unassignments));
925         $transaction = $DB->start_delegated_transaction();
927         foreach ($params['unassignments'] as $unassignment) {
928             // Ensure the current user is allowed to run this function in the unassignment context
929             $context = self::get_context_from_params($unassignment);
930             self::validate_context($context);
931             require_capability('moodle/role:assign', $context);
933             // throw an exception if user is not able to unassign the role in this context
934             $roles = get_assignable_roles($context, ROLENAME_SHORT);
935             if (!array_key_exists($unassignment['roleid'], $roles)) {
936                 throw new invalid_parameter_exception('Can not unassign roleid='.$unassignment['roleid'].' in contextid='.$unassignment['contextid']);
937             }
939             role_unassign($unassignment['roleid'], $unassignment['userid'], $context->id);
940         }
942         $transaction->allow_commit();
943     }
945    /**
946      * Returns description of method result value
947      *
948      * @return null
949      */
950     public static function unassign_roles_returns() {
951         return null;
952     }