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