See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 401 and 402] [Versions 401 and 403]
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/>. 16 17 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 */ 29 30 defined('MOODLE_INTERNAL') || die(); 31 32 require_once("$CFG->libdir/externallib.php"); 33 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 { 44 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 } 78 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 90 require_once($CFG->dirroot . '/course/lib.php'); 91 require_once($CFG->dirroot . "/user/lib.php"); 92 93 if (empty($coursecapabilities)) { 94 throw new invalid_parameter_exception('Parameter can not be empty'); 95 } 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); 117 } 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; 125 } 126 } 127 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.'); 135 } 136 if ($courseid == SITEID) { 137 $context = context_system::instance(); 138 } else { 139 $context = $coursecontext; 140 } 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)); 148 } 149 150 course_require_view_participants($context); 151 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); 155 } 156 // The course:enrolereview capability is needed to use this option. 157 if ($onlyactive) { 158 require_capability('moodle/course:enrolreview', $coursecontext); 159 } 160 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; 166 167 list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $capability, $groupid, $onlyactive); 168 $enrolledparams['courseid'] = $courseid; 169 170 $sql = "SELECT u.*, COALESCE(ul.timeaccess, 0) AS lastcourseaccess 171 FROM {user} u 172 LEFT JOIN {user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = :courseid) 173 WHERE u.id IN ($enrolledsql) 174 ORDER BY u.id ASC"; 175 176 $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber); 177 $users = array(); 178 foreach ($enrolledusers as $courseuser) { 179 if ($userdetails = user_get_user_details($courseuser, $course, $userfields)) { 180 $users[] = $userdetails; 181 } 182 } 183 $enrolledusers->close(); 184 $courseusers['users'] = $users; 185 $result[] = $courseusers; 186 } 187 } 188 return $result; 189 } 190 191 /** 192 * Returns description of method result value 193 * 194 * @return external_multiple_structure 195 * @since Moodle 2.4 196 */ 197 public static function get_enrolled_users_with_capability_returns() { 198 return new external_multiple_structure( new external_single_structure ( 199 array ( 200 'courseid' => new external_value(PARAM_INT, 'Course ID number in the Moodle course table'), 201 'capability' => new external_value(PARAM_CAPABILITY, 'Capability name'), 202 'users' => new external_multiple_structure( 203 new external_single_structure( 204 array( 205 'id' => new external_value(PARAM_INT, 'ID of the user'), 206 'username' => new external_value(PARAM_RAW, 'Username', VALUE_OPTIONAL), 207 'firstname' => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL), 208 'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL), 209 'fullname' => new external_value(PARAM_NOTAGS, 'The fullname of the user'), 210 'email' => new external_value(PARAM_TEXT, 'Email address', VALUE_OPTIONAL), 211 'address' => new external_value(PARAM_MULTILANG, 'Postal address', VALUE_OPTIONAL), 212 'phone1' => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL), 213 'phone2' => new external_value(PARAM_NOTAGS, 'Phone 2', 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 'lastcourseaccess' => new external_value(PARAM_INT, 'last access to the course (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 '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'), 233 ) 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'), 241 ) 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') 250 ) 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'), 257 ) 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') 265 ) 266 ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL) 267 ) 268 ), 'List of users that are enrolled in the course and have the specified capability'), 269 ) 270 ) 271 ); 272 } 273 274 /** 275 * Returns description of method parameters 276 * 277 * @return external_function_parameters 278 */ 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'), 283 'returnusercount' => new external_value(PARAM_BOOL, 284 'Include count of enrolled users for each course? This can add several seconds to the response time' 285 . ' if a user is on several large courses, so set this to false if the value will not be used to' 286 . ' improve performance.', 287 VALUE_DEFAULT, true), 288 ) 289 ); 290 } 291 292 /** 293 * Get list of courses user is enrolled in (only active enrolments are returned). 294 * Please note the current user must be able to access the course, otherwise the course is not included. 295 * 296 * @param int $userid 297 * @param bool $returnusercount 298 * @return array of courses 299 */ 300 public static function get_users_courses($userid, $returnusercount = true) { 301 global $CFG, $USER, $DB; 302 303 require_once($CFG->dirroot . '/course/lib.php'); 304 require_once($CFG->dirroot . '/user/lib.php'); 305 require_once($CFG->libdir . '/completionlib.php'); 306 307 // Do basic automatic PARAM checks on incoming data, using params description 308 // If any problems are found then exceptions are thrown with helpful error messages 309 $params = self::validate_parameters(self::get_users_courses_parameters(), 310 ['userid' => $userid, 'returnusercount' => $returnusercount]); 311 $userid = $params['userid']; 312 $returnusercount = $params['returnusercount']; 313 314 $courses = enrol_get_users_courses($userid, true, '*'); 315 $result = array(); 316 317 // Get user data including last access to courses. 318 $user = get_complete_user_data('id', $userid); 319 $sameuser = $USER->id == $userid; 320 321 // Retrieve favourited courses (starred). 322 $favouritecourseids = array(); 323 if ($sameuser) { 324 $ufservice = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($userid)); 325 $favourites = $ufservice->find_favourites_by_type('core_course', 'courses'); 326 327 if ($favourites) { 328 $favouritecourseids = array_flip(array_map( 329 function($favourite) { 330 return $favourite->itemid; 331 }, $favourites)); 332 } 333 } 334 335 foreach ($courses as $course) { 336 $context = context_course::instance($course->id, IGNORE_MISSING); 337 try { 338 self::validate_context($context); 339 } catch (Exception $e) { 340 // current user can not access this course, sorry we can not disclose who is enrolled in this course! 341 continue; 342 } 343 344 // If viewing details of another user, then we must be able to view participants as well as profile of that user. 345 if (!$sameuser && (!course_can_view_participants($context) || !user_can_view_profile($user, $course))) { 346 continue; 347 } 348 349 if ($returnusercount) { 350 list($enrolledsqlselect, $enrolledparams) = get_enrolled_sql($context); 351 $enrolledsql = "SELECT COUNT('x') FROM ($enrolledsqlselect) enrolleduserids"; 352 $enrolledusercount = $DB->count_records_sql($enrolledsql, $enrolledparams); 353 } 354 355 $displayname = external_format_string(get_course_display_name_for_list($course), $context->id); 356 list($course->summary, $course->summaryformat) = 357 external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', null); 358 $course->fullname = external_format_string($course->fullname, $context->id); 359 $course->shortname = external_format_string($course->shortname, $context->id); 360 361 $progress = null; 362 $completed = null; 363 $completionhascriteria = false; 364 $completionusertracked = false; 365 366 // Return only private information if the user should be able to see it. 367 if ($sameuser || completion_can_view_data($userid, $course)) { 368 if ($course->enablecompletion) { 369 $completion = new completion_info($course); 370 $completed = $completion->is_course_complete($userid); 371 $completionhascriteria = $completion->has_criteria(); 372 $completionusertracked = $completion->is_tracked_user($userid); 373 $progress = \core_completion\progress::get_course_progress_percentage($course, $userid); 374 } 375 } 376 377 $lastaccess = null; 378 // Check if last access is a hidden field. 379 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields)); 380 $canviewlastaccess = $sameuser || !isset($hiddenfields['lastaccess']); 381 if (!$canviewlastaccess) { 382 $canviewlastaccess = has_capability('moodle/course:viewhiddenuserfields', $context); 383 } 384 385 if ($canviewlastaccess && isset($user->lastcourseaccess[$course->id])) { 386 $lastaccess = $user->lastcourseaccess[$course->id]; 387 } 388 389 $hidden = false; 390 if ($sameuser) { 391 $hidden = boolval(get_user_preferences('block_myoverview_hidden_course_' . $course->id, 0)); 392 } 393 394 // Retrieve course overview used files. 395 $courselist = new core_course_list_element($course); 396 $overviewfiles = array(); 397 foreach ($courselist->get_course_overviewfiles() as $file) { 398 $fileurl = moodle_url::make_webservice_pluginfile_url($file->get_contextid(), $file->get_component(), 399 $file->get_filearea(), null, $file->get_filepath(), 400 $file->get_filename())->out(false); 401 $overviewfiles[] = array( 402 'filename' => $file->get_filename(), 403 'fileurl' => $fileurl, 404 'filesize' => $file->get_filesize(), 405 'filepath' => $file->get_filepath(), 406 'mimetype' => $file->get_mimetype(), 407 'timemodified' => $file->get_timemodified(), 408 ); 409 } 410 411 $courseresult = [ 412 'id' => $course->id, 413 'shortname' => $course->shortname, 414 'fullname' => $course->fullname, 415 'displayname' => $displayname, 416 'idnumber' => $course->idnumber, 417 'visible' => $course->visible, 418 'summary' => $course->summary, 419 'summaryformat' => $course->summaryformat, 420 'format' => $course->format, 421 'showgrades' => $course->showgrades, 422 'lang' => clean_param($course->lang, PARAM_LANG), 423 'enablecompletion' => $course->enablecompletion, 424 'completionhascriteria' => $completionhascriteria, 425 'completionusertracked' => $completionusertracked, 426 'category' => $course->category, 427 'progress' => $progress, 428 'completed' => $completed, 429 'startdate' => $course->startdate, 430 'enddate' => $course->enddate, 431 'marker' => $course->marker, 432 'lastaccess' => $lastaccess, 433 'isfavourite' => isset($favouritecourseids[$course->id]), 434 'hidden' => $hidden, 435 'overviewfiles' => $overviewfiles, 436 'showactivitydates' => $course->showactivitydates, 437 'showcompletionconditions' => $course->showcompletionconditions, 438 'timemodified' => $course->timemodified, 439 ]; 440 if ($returnusercount) { 441 $courseresult['enrolledusercount'] = $enrolledusercount; 442 } 443 $result[] = $courseresult; 444 } 445 446 return $result; 447 } 448 449 /** 450 * Returns description of method result value 451 * 452 * @return external_description 453 */ 454 public static function get_users_courses_returns() { 455 return new external_multiple_structure( 456 new external_single_structure( 457 array( 458 'id' => new external_value(PARAM_INT, 'id of course'), 459 'shortname' => new external_value(PARAM_RAW, 'short name of course'), 460 'fullname' => new external_value(PARAM_RAW, 'long name of course'), 461 'displayname' => new external_value(PARAM_RAW, 'course display name for lists.', VALUE_OPTIONAL), 462 'enrolledusercount' => new external_value(PARAM_INT, 'Number of enrolled users in this course', 463 VALUE_OPTIONAL), 464 'idnumber' => new external_value(PARAM_RAW, 'id number of course'), 465 'visible' => new external_value(PARAM_INT, '1 means visible, 0 means not yet visible course'), 466 'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL), 467 'summaryformat' => new external_format_value('summary', VALUE_OPTIONAL), 468 'format' => new external_value(PARAM_PLUGIN, 'course format: weeks, topics, social, site', VALUE_OPTIONAL), 469 'showgrades' => new external_value(PARAM_BOOL, 'true if grades are shown, otherwise false', VALUE_OPTIONAL), 470 'lang' => new external_value(PARAM_LANG, 'forced course language', VALUE_OPTIONAL), 471 'enablecompletion' => new external_value(PARAM_BOOL, 'true if completion is enabled, otherwise false', 472 VALUE_OPTIONAL), 473 'completionhascriteria' => new external_value(PARAM_BOOL, 'If completion criteria is set.', VALUE_OPTIONAL), 474 'completionusertracked' => new external_value(PARAM_BOOL, 'If the user is completion tracked.', VALUE_OPTIONAL), 475 'category' => new external_value(PARAM_INT, 'course category id', VALUE_OPTIONAL), 476 'progress' => new external_value(PARAM_FLOAT, 'Progress percentage', VALUE_OPTIONAL), 477 'completed' => new external_value(PARAM_BOOL, 'Whether the course is completed.', VALUE_OPTIONAL), 478 'startdate' => new external_value(PARAM_INT, 'Timestamp when the course start', VALUE_OPTIONAL), 479 'enddate' => new external_value(PARAM_INT, 'Timestamp when the course end', VALUE_OPTIONAL), 480 'marker' => new external_value(PARAM_INT, 'Course section marker.', VALUE_OPTIONAL), 481 'lastaccess' => new external_value(PARAM_INT, 'Last access to the course (timestamp).', VALUE_OPTIONAL), 482 'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this course a favourite.', VALUE_OPTIONAL), 483 'hidden' => new external_value(PARAM_BOOL, 'If the user hide the course from the dashboard.', VALUE_OPTIONAL), 484 'overviewfiles' => new external_files('Overview files attached to this course.', VALUE_OPTIONAL), 485 'showactivitydates' => new external_value(PARAM_BOOL, 'Whether the activity dates are shown or not'), 486 'showcompletionconditions' => new external_value(PARAM_BOOL, 'Whether the activity completion conditions are shown or not'), 487 'timemodified' => new external_value(PARAM_INT, 'Last time course settings were updated (timestamp).', 488 VALUE_OPTIONAL), 489 ) 490 ) 491 ); 492 } 493 494 /** 495 * Returns description of method parameters value 496 * 497 * @return external_description 498 */ 499 public static function get_potential_users_parameters() { 500 return new external_function_parameters( 501 array( 502 'courseid' => new external_value(PARAM_INT, 'course id'), 503 'enrolid' => new external_value(PARAM_INT, 'enrolment id'), 504 'search' => new external_value(PARAM_RAW, 'query'), 505 'searchanywhere' => new external_value(PARAM_BOOL, 'find a match anywhere, or only at the beginning'), 506 'page' => new external_value(PARAM_INT, 'Page number'), 507 'perpage' => new external_value(PARAM_INT, 'Number per page'), 508 ) 509 ); 510 } 511 512 /** 513 * Get potential users. 514 * 515 * @param int $courseid Course id 516 * @param int $enrolid Enrolment id 517 * @param string $search The query 518 * @param boolean $searchanywhere Match anywhere in the string 519 * @param int $page Page number 520 * @param int $perpage Max per page 521 * @return array An array of users 522 */ 523 public static function get_potential_users($courseid, $enrolid, $search, $searchanywhere, $page, $perpage) { 524 global $PAGE, $DB, $CFG; 525 526 require_once($CFG->dirroot.'/enrol/locallib.php'); 527 require_once($CFG->dirroot.'/user/lib.php'); 528 529 $params = self::validate_parameters( 530 self::get_potential_users_parameters(), 531 array( 532 'courseid' => $courseid, 533 'enrolid' => $enrolid, 534 'search' => $search, 535 'searchanywhere' => $searchanywhere, 536 'page' => $page, 537 'perpage' => $perpage 538 ) 539 ); 540 $context = context_course::instance($params['courseid']); 541 try { 542 self::validate_context($context); 543 } catch (Exception $e) { 544 $exceptionparam = new stdClass(); 545 $exceptionparam->message = $e->getMessage(); 546 $exceptionparam->courseid = $params['courseid']; 547 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 548 } 549 require_capability('moodle/course:enrolreview', $context); 550 551 $course = $DB->get_record('course', array('id' => $params['courseid'])); 552 $manager = new course_enrolment_manager($PAGE, $course); 553 554 $users = $manager->get_potential_users($params['enrolid'], 555 $params['search'], 556 $params['searchanywhere'], 557 $params['page'], 558 $params['perpage']); 559 560 $results = array(); 561 // Add also extra user fields. 562 $identityfields = \core_user\fields::get_identity_fields($context, true); 563 $customprofilefields = []; 564 foreach ($identityfields as $key => $value) { 565 if ($fieldname = \core_user\fields::match_custom_field($value)) { 566 unset($identityfields[$key]); 567 $customprofilefields[$fieldname] = true; 568 } 569 } 570 if ($customprofilefields) { 571 $identityfields[] = 'customfields'; 572 } 573 $requiredfields = array_merge( 574 ['id', 'fullname', 'profileimageurl', 'profileimageurlsmall'], 575 $identityfields 576 ); 577 foreach ($users['users'] as $id => $user) { 578 // Note: We pass the course here to validate that the current user can at least view user details in this course. 579 // The user we are looking at is not in this course yet though - but we only fetch the minimal set of 580 // user records, and the user has been validated to have course:enrolreview in this course. Otherwise 581 // there is no way to find users who aren't in the course in order to enrol them. 582 if ($userdetails = user_get_user_details($user, $course, $requiredfields)) { 583 // For custom fields, only return the ones we actually need. 584 if ($customprofilefields && array_key_exists('customfields', $userdetails)) { 585 foreach ($userdetails['customfields'] as $key => $data) { 586 if (!array_key_exists($data['shortname'], $customprofilefields)) { 587 unset($userdetails['customfields'][$key]); 588 } 589 } 590 $userdetails['customfields'] = array_values($userdetails['customfields']); 591 } 592 $results[] = $userdetails; 593 } 594 } 595 return $results; 596 } 597 598 /** 599 * Returns description of method result value 600 * 601 * @return external_description 602 */ 603 public static function get_potential_users_returns() { 604 global $CFG; 605 require_once($CFG->dirroot . '/user/externallib.php'); 606 return new external_multiple_structure(core_user_external::user_description()); 607 } 608 609 /** 610 * Returns description of method parameters 611 * 612 * @return external_function_parameters 613 */ 614 public static function search_users_parameters(): external_function_parameters { 615 return new external_function_parameters( 616 [ 617 'courseid' => new external_value(PARAM_INT, 'course id'), 618 'search' => new external_value(PARAM_RAW, 'query'), 619 'searchanywhere' => new external_value(PARAM_BOOL, 'find a match anywhere, or only at the beginning'), 620 'page' => new external_value(PARAM_INT, 'Page number'), 621 'perpage' => new external_value(PARAM_INT, 'Number per page'), 622 ] 623 ); 624 } 625 626 /** 627 * Search course participants. 628 * 629 * @param int $courseid Course id 630 * @param string $search The query 631 * @param bool $searchanywhere Match anywhere in the string 632 * @param int $page Page number 633 * @param int $perpage Max per page 634 * @return array An array of users 635 * @throws moodle_exception 636 */ 637 public static function search_users(int $courseid, string $search, bool $searchanywhere, int $page, int $perpage): array { 638 global $PAGE, $DB, $CFG; 639 640 require_once($CFG->dirroot.'/enrol/locallib.php'); 641 require_once($CFG->dirroot.'/user/lib.php'); 642 643 $params = self::validate_parameters( 644 self::search_users_parameters(), 645 [ 646 'courseid' => $courseid, 647 'search' => $search, 648 'searchanywhere' => $searchanywhere, 649 'page' => $page, 650 'perpage' => $perpage 651 ] 652 ); 653 $context = context_course::instance($params['courseid']); 654 try { 655 self::validate_context($context); 656 } catch (Exception $e) { 657 $exceptionparam = new stdClass(); 658 $exceptionparam->message = $e->getMessage(); 659 $exceptionparam->courseid = $params['courseid']; 660 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 661 } 662 course_require_view_participants($context); 663 664 $course = get_course($params['courseid']); 665 $manager = new course_enrolment_manager($PAGE, $course); 666 667 $users = $manager->search_users($params['search'], 668 $params['searchanywhere'], 669 $params['page'], 670 $params['perpage']); 671 672 $results = []; 673 // Add also extra user fields. 674 $requiredfields = array_merge( 675 ['id', 'fullname', 'profileimageurl', 'profileimageurlsmall'], 676 // TODO Does not support custom user profile fields (MDL-70456). 677 \core_user\fields::get_identity_fields($context, false) 678 ); 679 foreach ($users['users'] as $user) { 680 if ($userdetails = user_get_user_details($user, $course, $requiredfields)) { 681 $results[] = $userdetails; 682 } 683 } 684 return $results; 685 } 686 687 /** 688 * Returns description of method result value 689 * 690 * @return external_multiple_structure 691 */ 692 public static function search_users_returns(): external_multiple_structure { 693 global $CFG; 694 require_once($CFG->dirroot . '/user/externallib.php'); 695 return new external_multiple_structure(core_user_external::user_description()); 696 } 697 698 /** 699 * Returns description of method parameters 700 * 701 * @return external_function_parameters 702 */ 703 public static function get_enrolled_users_parameters() { 704 return new external_function_parameters( 705 [ 706 'courseid' => new external_value(PARAM_INT, 'course id'), 707 'options' => new external_multiple_structure( 708 new external_single_structure( 709 [ 710 'name' => new external_value(PARAM_ALPHANUMEXT, 'option name'), 711 'value' => new external_value(PARAM_RAW, 'option value') 712 ] 713 ), 'Option names: 714 * withcapability (string) return only users with this capability. This option requires \'moodle/role:review\' on the course context. 715 * groupid (integer) return only users in this group id. If the course has groups enabled and this param 716 isn\'t defined, returns all the viewable users. 717 This option requires \'moodle/site:accessallgroups\' on the course context if the 718 user doesn\'t belong to the group. 719 * onlyactive (integer) return only users with active enrolments and matching time restrictions. 720 This option requires \'moodle/course:enrolreview\' on the course context. 721 Please note that this option can\'t 722 be used together with onlysuspended (only one can be active). 723 * onlysuspended (integer) return only suspended users. This option requires 724 \'moodle/course:enrolreview\' on the course context. Please note that this option can\'t 725 be used together with onlyactive (only one can be active). 726 * userfields (\'string, string, ...\') return only the values of these user fields. 727 * limitfrom (integer) sql limit from. 728 * limitnumber (integer) maximum number of returned users. 729 * sortby (string) sort by id, firstname or lastname. For ordering like the site does, use siteorder. 730 * sortdirection (string) ASC or DESC', 731 VALUE_DEFAULT, []), 732 ] 733 ); 734 } 735 736 /** 737 * Get course participants details 738 * 739 * @param int $courseid course id 740 * @param array $options options { 741 * 'name' => option name 742 * 'value' => option value 743 * } 744 * @return array An array of users 745 */ 746 public static function get_enrolled_users($courseid, $options = []) { 747 global $CFG, $USER, $DB; 748 749 require_once($CFG->dirroot . '/course/lib.php'); 750 require_once($CFG->dirroot . "/user/lib.php"); 751 752 $params = self::validate_parameters( 753 self::get_enrolled_users_parameters(), 754 [ 755 'courseid'=>$courseid, 756 'options'=>$options 757 ] 758 ); 759 $withcapability = ''; 760 $groupid = 0; 761 $onlyactive = false; 762 $onlysuspended = false; 763 $userfields = []; 764 $limitfrom = 0; 765 $limitnumber = 0; 766 $sortby = 'us.id'; 767 $sortparams = []; 768 $sortdirection = 'ASC'; 769 foreach ($options as $option) { 770 switch ($option['name']) { 771 case 'withcapability': 772 $withcapability = $option['value']; 773 break; 774 case 'groupid': 775 $groupid = (int)$option['value']; 776 break; 777 case 'onlyactive': 778 $onlyactive = !empty($option['value']); 779 break; 780 case 'onlysuspended': 781 $onlysuspended = !empty($option['value']); 782 break; 783 case 'userfields': 784 $thefields = explode(',', $option['value']); 785 foreach ($thefields as $f) { 786 $userfields[] = clean_param($f, PARAM_ALPHANUMEXT); 787 } 788 break; 789 case 'limitfrom' : 790 $limitfrom = clean_param($option['value'], PARAM_INT); 791 break; 792 case 'limitnumber' : 793 $limitnumber = clean_param($option['value'], PARAM_INT); 794 break; 795 case 'sortby': 796 $sortallowedvalues = ['id', 'firstname', 'lastname', 'siteorder']; 797 if (!in_array($option['value'], $sortallowedvalues)) { 798 throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . 799 $option['value'] . '), allowed values are: ' . implode(',', $sortallowedvalues)); 800 } 801 if ($option['value'] == 'siteorder') { 802 list($sortby, $sortparams) = users_order_by_sql('us'); 803 } else { 804 $sortby = 'us.' . $option['value']; 805 } 806 break; 807 case 'sortdirection': 808 $sortdirection = strtoupper($option['value']); 809 $directionallowedvalues = ['ASC', 'DESC']; 810 if (!in_array($sortdirection, $directionallowedvalues)) { 811 throw new invalid_parameter_exception('Invalid value for sortdirection parameter 812 (value: ' . $sortdirection . '),' . 'allowed values are: ' . implode(',', $directionallowedvalues)); 813 } 814 break; 815 } 816 } 817 818 $course = $DB->get_record('course', ['id' => $courseid], '*', MUST_EXIST); 819 $coursecontext = context_course::instance($courseid, IGNORE_MISSING); 820 if ($courseid == SITEID) { 821 $context = context_system::instance(); 822 } else { 823 $context = $coursecontext; 824 } 825 try { 826 self::validate_context($context); 827 } catch (Exception $e) { 828 $exceptionparam = new stdClass(); 829 $exceptionparam->message = $e->getMessage(); 830 $exceptionparam->courseid = $params['courseid']; 831 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); 832 } 833 834 course_require_view_participants($context); 835 836 // to overwrite this parameter, you need role:review capability 837 if ($withcapability) { 838 require_capability('moodle/role:review', $coursecontext); 839 } 840 // need accessallgroups capability if you want to overwrite this option 841 if (!empty($groupid) && !groups_is_member($groupid)) { 842 require_capability('moodle/site:accessallgroups', $coursecontext); 843 } 844 // to overwrite this option, you need course:enrolereview permission 845 if ($onlyactive || $onlysuspended) { 846 require_capability('moodle/course:enrolreview', $coursecontext); 847 } 848 849 list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive, 850 $onlysuspended); 851 $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); 852 $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel)"; 853 $enrolledparams['contextlevel'] = CONTEXT_USER; 854 855 $groupjoin = ''; 856 if (empty($groupid) && groups_get_course_groupmode($course) == SEPARATEGROUPS && 857 !has_capability('moodle/site:accessallgroups', $coursecontext)) { 858 // Filter by groups the user can view. 859 $usergroups = groups_get_user_groups($course->id); 860 if (!empty($usergroups['0'])) { 861 list($groupsql, $groupparams) = $DB->get_in_or_equal($usergroups['0'], SQL_PARAMS_NAMED); 862 $groupjoin = "JOIN {groups_members} gm ON (u.id = gm.userid AND gm.groupid $groupsql)"; 863 $enrolledparams = array_merge($enrolledparams, $groupparams); 864 } else { 865 // User doesn't belong to any group, so he can't see any user. Return an empty array. 866 return []; 867 } 868 } 869 $sql = "SELECT us.*, COALESCE(ul.timeaccess, 0) AS lastcourseaccess 870 FROM {user} us 871 JOIN ( 872 SELECT DISTINCT u.id $ctxselect 873 FROM {user} u $ctxjoin $groupjoin 874 WHERE u.id IN ($enrolledsql) 875 ) q ON q.id = us.id 876 LEFT JOIN {user_lastaccess} ul ON (ul.userid = us.id AND ul.courseid = :courseid) 877 ORDER BY $sortby $sortdirection"; 878 $enrolledparams = array_merge($enrolledparams, $sortparams); 879 $enrolledparams['courseid'] = $courseid; 880 881 $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber); 882 $users = []; 883 foreach ($enrolledusers as $user) { 884 context_helper::preload_from_record($user); 885 if ($userdetails = user_get_user_details($user, $course, $userfields)) { 886 $users[] = $userdetails; 887 } 888 } 889 $enrolledusers->close(); 890 891 return $users; 892 } 893 894 /** 895 * Returns description of method result value 896 * 897 * @return external_description 898 */ 899 public static function get_enrolled_users_returns() { 900 return new external_multiple_structure( 901 new external_single_structure( 902 [ 903 'id' => new external_value(PARAM_INT, 'ID of the user'), 904 'username' => new external_value(PARAM_RAW, 'Username policy is defined in Moodle security config', VALUE_OPTIONAL), 905 'firstname' => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL), 906 'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL), 907 'fullname' => new external_value(PARAM_NOTAGS, 'The fullname of the user'), 908 'email' => new external_value(PARAM_TEXT, 'An email address - allow email as root@localhost', VALUE_OPTIONAL), 909 'address' => new external_value(PARAM_TEXT, 'Postal address', VALUE_OPTIONAL), 910 'phone1' => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL), 911 'phone2' => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL), 912 'department' => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL), 913 'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL), 914 'idnumber' => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL), 915 'interests' => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL), 916 'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL), 917 'lastaccess' => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL), 918 'lastcourseaccess' => new external_value(PARAM_INT, 'last access to the course (0 if never)', VALUE_OPTIONAL), 919 'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL), 920 'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL), 921 'city' => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL), 922 'country' => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL), 923 'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small version', VALUE_OPTIONAL), 924 'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big version', VALUE_OPTIONAL), 925 'customfields' => new external_multiple_structure( 926 new external_single_structure( 927 [ 928 'type' => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field - text field, checkbox...'), 929 'value' => new external_value(PARAM_RAW, 'The value of the custom field'), 930 'name' => new external_value(PARAM_RAW, 'The name of the custom field'), 931 'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field - to be able to build the field class in the code'), 932 ] 933 ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL), 934 'groups' => new external_multiple_structure( 935 new external_single_structure( 936 [ 937 'id' => new external_value(PARAM_INT, 'group id'), 938 'name' => new external_value(PARAM_RAW, 'group name'), 939 'description' => new external_value(PARAM_RAW, 'group description'), 940 'descriptionformat' => new external_format_value('description'), 941 ] 942 ), 'user groups', VALUE_OPTIONAL), 943 'roles' => new external_multiple_structure( 944 new external_single_structure( 945 [ 946 'roleid' => new external_value(PARAM_INT, 'role id'), 947 'name' => new external_value(PARAM_RAW, 'role name'), 948 'shortname' => new external_value(PARAM_ALPHANUMEXT, 'role shortname'), 949 'sortorder' => new external_value(PARAM_INT, 'role sortorder') 950 ] 951 ), 'user roles', VALUE_OPTIONAL), 952 'preferences' => new external_multiple_structure( 953 new external_single_structure( 954 [ 955 'name' => new external_value(PARAM_RAW, 'The name of the preferences'), 956 'value' => new external_value(PARAM_RAW, 'The value of the custom field'), 957 ] 958 ), 'User preferences', VALUE_OPTIONAL), 959 'enrolledcourses' => new external_multiple_structure( 960 new external_single_structure( 961 [ 962 'id' => new external_value(PARAM_INT, 'Id of the course'), 963 'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'), 964 'shortname' => new external_value(PARAM_RAW, 'Shortname of the course') 965 ] 966 ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL) 967 ] 968 ) 969 ); 970 } 971 972 /** 973 * Returns description of get_course_enrolment_methods() parameters 974 * 975 * @return external_function_parameters 976 */ 977 public static function get_course_enrolment_methods_parameters() { 978 return new external_function_parameters( 979 array( 980 'courseid' => new external_value(PARAM_INT, 'Course id') 981 ) 982 ); 983 } 984 985 /** 986 * Get list of active course enrolment methods for current user. 987 * 988 * @param int $courseid 989 * @return array of course enrolment methods 990 * @throws moodle_exception 991 */ 992 public static function get_course_enrolment_methods($courseid) { 993 global $DB; 994 995 $params = self::validate_parameters(self::get_course_enrolment_methods_parameters(), array('courseid' => $courseid)); 996 self::validate_context(context_system::instance()); 997 998 $course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST); 999 if (!core_course_category::can_view_course_info($course) && !can_access_course($course)) { 1000 throw new moodle_exception('coursehidden'); 1001 } 1002 1003 $result = array(); 1004 $enrolinstances = enrol_get_instances($params['courseid'], true); 1005 foreach ($enrolinstances as $enrolinstance) { 1006 if ($enrolplugin = enrol_get_plugin($enrolinstance->enrol)) { 1007 if ($instanceinfo = $enrolplugin->get_enrol_info($enrolinstance)) { 1008 $result[] = (array) $instanceinfo; 1009 } 1010 } 1011 } 1012 return $result; 1013 } 1014 1015 /** 1016 * Returns description of get_course_enrolment_methods() result value 1017 * 1018 * @return external_description 1019 */ 1020 public static function get_course_enrolment_methods_returns() { 1021 return new external_multiple_structure( 1022 new external_single_structure( 1023 array( 1024 'id' => new external_value(PARAM_INT, 'id of course enrolment instance'), 1025 'courseid' => new external_value(PARAM_INT, 'id of course'), 1026 'type' => new external_value(PARAM_PLUGIN, 'type of enrolment plugin'), 1027 'name' => new external_value(PARAM_RAW, 'name of enrolment plugin'), 1028 'status' => new external_value(PARAM_RAW, 'status of enrolment plugin'), 1029 'wsfunction' => new external_value(PARAM_ALPHANUMEXT, 'webservice function to get more information', VALUE_OPTIONAL), 1030 ) 1031 ) 1032 ); 1033 } 1034 1035 /** 1036 * Returns description of submit_user_enrolment_form parameters. 1037 * 1038 * @return external_function_parameters. 1039 */ 1040 public static function submit_user_enrolment_form_parameters() { 1041 return new external_function_parameters([ 1042 'formdata' => new external_value(PARAM_RAW, 'The data from the event form'), 1043 ]); 1044 } 1045 1046 /** 1047 * External function that handles the user enrolment form submission. 1048 * 1049 * @param string $formdata The user enrolment form data in s URI encoded param string 1050 * @return array An array consisting of the processing result and error flag, if available 1051 */ 1052 public static function submit_user_enrolment_form($formdata) { 1053 global $CFG, $DB, $PAGE; 1054 1055 // Parameter validation. 1056 $params = self::validate_parameters(self::submit_user_enrolment_form_parameters(), ['formdata' => $formdata]); 1057 1058 $data = []; 1059 parse_str($params['formdata'], $data); 1060 1061 $userenrolment = $DB->get_record('user_enrolments', ['id' => $data['ue']], '*', MUST_EXIST); 1062 $instance = $DB->get_record('enrol', ['id' => $userenrolment->enrolid], '*', MUST_EXIST); 1063 $plugin = enrol_get_plugin($instance->enrol); 1064 $course = get_course($instance->courseid); 1065 $context = context_course::instance($course->id); 1066 self::validate_context($context); 1067 1068 require_once("$CFG->dirroot/enrol/editenrolment_form.php"); 1069 $customformdata = [ 1070 'ue' => $userenrolment, 1071 'modal' => true, 1072 'enrolinstancename' => $plugin->get_instance_name($instance) 1073 ]; 1074 $mform = new enrol_user_enrolment_form(null, $customformdata, 'post', '', null, true, $data); 1075 1076 if ($validateddata = $mform->get_data()) { 1077 if (!empty($validateddata->duration) && $validateddata->timeend == 0) { 1078 $validateddata->timeend = $validateddata->timestart + $validateddata->duration; 1079 } 1080 require_once($CFG->dirroot . '/enrol/locallib.php'); 1081 $manager = new course_enrolment_manager($PAGE, $course); 1082 $result = $manager->edit_enrolment($userenrolment, $validateddata); 1083 1084 return ['result' => $result]; 1085 } else { 1086 return ['result' => false, 'validationerror' => true]; 1087 } 1088 } 1089 1090 /** 1091 * Returns description of submit_user_enrolment_form() result value 1092 * 1093 * @return external_description 1094 */ 1095 public static function submit_user_enrolment_form_returns() { 1096 return new external_single_structure([ 1097 'result' => new external_value(PARAM_BOOL, 'True if the user\'s enrolment was successfully updated'), 1098 'validationerror' => new external_value(PARAM_BOOL, 'Indicates invalid form data', VALUE_DEFAULT, false), 1099 ]); 1100 } 1101 1102 /** 1103 * Returns description of unenrol_user_enrolment() parameters 1104 * 1105 * @return external_function_parameters 1106 */ 1107 public static function unenrol_user_enrolment_parameters() { 1108 return new external_function_parameters( 1109 array( 1110 'ueid' => new external_value(PARAM_INT, 'User enrolment ID') 1111 ) 1112 ); 1113 } 1114 1115 /** 1116 * External function that unenrols a given user enrolment. 1117 * 1118 * @param int $ueid The user enrolment ID. 1119 * @return array An array consisting of the processing result, errors. 1120 */ 1121 public static function unenrol_user_enrolment($ueid) { 1122 global $CFG, $DB, $PAGE; 1123 1124 $params = self::validate_parameters(self::unenrol_user_enrolment_parameters(), [ 1125 'ueid' => $ueid 1126 ]); 1127 1128 $result = false; 1129 $errors = []; 1130 1131 $userenrolment = $DB->get_record('user_enrolments', ['id' => $params['ueid']], '*'); 1132 if ($userenrolment) { 1133 $userid = $userenrolment->userid; 1134 $enrolid = $userenrolment->enrolid; 1135 $enrol = $DB->get_record('enrol', ['id' => $enrolid], '*', MUST_EXIST); 1136 $courseid = $enrol->courseid; 1137 $course = get_course($courseid); 1138 $context = context_course::instance($course->id); 1139 self::validate_context($context); 1140 } else { 1141 $validationerrors['invalidrequest'] = get_string('invalidrequest', 'enrol'); 1142 } 1143 1144 // If the userenrolment exists, unenrol the user. 1145 if (!isset($validationerrors)) { 1146 require_once($CFG->dirroot . '/enrol/locallib.php'); 1147 $manager = new course_enrolment_manager($PAGE, $course); 1148 $result = $manager->unenrol_user($userenrolment); 1149 } else { 1150 foreach ($validationerrors as $key => $errormessage) { 1151 $errors[] = (object)[ 1152 'key' => $key, 1153 'message' => $errormessage 1154 ]; 1155 } 1156 } 1157 1158 return [ 1159 'result' => $result, 1160 'errors' => $errors, 1161 ]; 1162 } 1163 1164 /** 1165 * Returns description of unenrol_user_enrolment() result value 1166 * 1167 * @return external_description 1168 */ 1169 public static function unenrol_user_enrolment_returns() { 1170 return new external_single_structure( 1171 array( 1172 'result' => new external_value(PARAM_BOOL, 'True if the user\'s enrolment was successfully updated'), 1173 'errors' => new external_multiple_structure( 1174 new external_single_structure( 1175 array( 1176 'key' => new external_value(PARAM_TEXT, 'The data that failed the validation'), 1177 'message' => new external_value(PARAM_TEXT, 'The error message'), 1178 ) 1179 ), 'List of validation errors' 1180 ), 1181 ) 1182 ); 1183 } 1184 } 1185 1186 /** 1187 * Role external functions 1188 * 1189 * @package core_role 1190 * @category external 1191 * @copyright 2011 Jerome Mouneyrac 1192 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1193 * @since Moodle 2.2 1194 */ 1195 class core_role_external extends external_api { 1196 1197 /** 1198 * Returns description of method parameters 1199 * 1200 * @return external_function_parameters 1201 */ 1202 public static function assign_roles_parameters() { 1203 return new external_function_parameters( 1204 array( 1205 'assignments' => new external_multiple_structure( 1206 new external_single_structure( 1207 array( 1208 'roleid' => new external_value(PARAM_INT, 'Role to assign to the user'), 1209 'userid' => new external_value(PARAM_INT, 'The user that is going to be assigned'), 1210 'contextid' => new external_value(PARAM_INT, 'The context to assign the user role in', VALUE_OPTIONAL), 1211 'contextlevel' => new external_value(PARAM_ALPHA, 'The context level to assign the user role in 1212 (block, course, coursecat, system, user, module)', VALUE_OPTIONAL), 1213 'instanceid' => new external_value(PARAM_INT, 'The Instance id of item where the role needs to be assigned', VALUE_OPTIONAL), 1214 ) 1215 ) 1216 ) 1217 ) 1218 ); 1219 } 1220 1221 /** 1222 * Manual role assignments to users 1223 * 1224 * @param array $assignments An array of manual role assignment 1225 */ 1226 public static function assign_roles($assignments) { 1227 global $DB; 1228 1229 // Do basic automatic PARAM checks on incoming data, using params description 1230 // If any problems are found then exceptions are thrown with helpful error messages 1231 $params = self::validate_parameters(self::assign_roles_parameters(), array('assignments'=>$assignments)); 1232 1233 $transaction = $DB->start_delegated_transaction(); 1234 1235 foreach ($params['assignments'] as $assignment) { 1236 // Ensure correct context level with a instance id or contextid is passed. 1237 $context = self::get_context_from_params($assignment); 1238 1239 // Ensure the current user is allowed to run this function in the enrolment context. 1240 self::validate_context($context); 1241 require_capability('moodle/role:assign', $context); 1242 1243 // throw an exception if user is not able to assign the role in this context 1244 $roles = get_assignable_roles($context, ROLENAME_SHORT); 1245 1246 if (!array_key_exists($assignment['roleid'], $roles)) { 1247 throw new invalid_parameter_exception('Can not assign roleid='.$assignment['roleid'].' in contextid='.$assignment['contextid']); 1248 } 1249 1250 role_assign($assignment['roleid'], $assignment['userid'], $context->id); 1251 } 1252 1253 $transaction->allow_commit(); 1254 } 1255 1256 /** 1257 * Returns description of method result value 1258 * 1259 * @return null 1260 */ 1261 public static function assign_roles_returns() { 1262 return null; 1263 } 1264 1265 1266 /** 1267 * Returns description of method parameters 1268 * 1269 * @return external_function_parameters 1270 */ 1271 public static function unassign_roles_parameters() { 1272 return new external_function_parameters( 1273 array( 1274 'unassignments' => new external_multiple_structure( 1275 new external_single_structure( 1276 array( 1277 'roleid' => new external_value(PARAM_INT, 'Role to assign to the user'), 1278 'userid' => new external_value(PARAM_INT, 'The user that is going to be assigned'), 1279 'contextid' => new external_value(PARAM_INT, 'The context to unassign the user role from', VALUE_OPTIONAL), 1280 'contextlevel' => new external_value(PARAM_ALPHA, 'The context level to unassign the user role in 1281 + (block, course, coursecat, system, user, module)', VALUE_OPTIONAL), 1282 'instanceid' => new external_value(PARAM_INT, 'The Instance id of item where the role needs to be unassigned', VALUE_OPTIONAL), 1283 ) 1284 ) 1285 ) 1286 ) 1287 ); 1288 } 1289 1290 /** 1291 * Unassign roles from users 1292 * 1293 * @param array $unassignments An array of unassignment 1294 */ 1295 public static function unassign_roles($unassignments) { 1296 global $DB; 1297 1298 // Do basic automatic PARAM checks on incoming data, using params description 1299 // If any problems are found then exceptions are thrown with helpful error messages 1300 $params = self::validate_parameters(self::unassign_roles_parameters(), array('unassignments'=>$unassignments)); 1301 1302 $transaction = $DB->start_delegated_transaction(); 1303 1304 foreach ($params['unassignments'] as $unassignment) { 1305 // Ensure the current user is allowed to run this function in the unassignment context 1306 $context = self::get_context_from_params($unassignment); 1307 self::validate_context($context); 1308 require_capability('moodle/role:assign', $context); 1309 1310 // throw an exception if user is not able to unassign the role in this context 1311 $roles = get_assignable_roles($context, ROLENAME_SHORT); 1312 if (!array_key_exists($unassignment['roleid'], $roles)) { 1313 throw new invalid_parameter_exception('Can not unassign roleid='.$unassignment['roleid'].' in contextid='.$unassignment['contextid']); 1314 } 1315 1316 role_unassign($unassignment['roleid'], $unassignment['userid'], $context->id); 1317 } 1318 1319 $transaction->allow_commit(); 1320 } 1321 1322 /** 1323 * Returns description of method result value 1324 * 1325 * @return null 1326 */ 1327 public static function unassign_roles_returns() { 1328 return null; 1329 } 1330 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body