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