See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [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 defined('MOODLE_INTERNAL') || die(); 18 19 global $CFG; 20 21 require_once($CFG->dirroot . '/webservice/tests/helpers.php'); 22 require_once($CFG->dirroot . '/enrol/externallib.php'); 23 24 /** 25 * Enrol external PHPunit tests 26 * 27 * @package core_enrol 28 * @category external 29 * @copyright 2012 Jerome Mouneyrac 30 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 31 * @since Moodle 2.4 32 */ 33 class core_enrol_externallib_testcase extends externallib_advanced_testcase { 34 35 /** 36 * dataProvider for test_get_enrolled_users_visibility(). 37 */ 38 public function get_enrolled_users_visibility_provider() { 39 return array( 40 'Course without groups, default behavior (not filtering by cap, group, active)' => 41 array( 42 'settings' => array( 43 'coursegroupmode' => NOGROUPS, 44 'withcapability' => null, 45 'groupid' => null, 46 'onlyactive' => false, 47 'allowedcaps' => array(), 48 ), 49 'results' => array( // Everybody can view everybody. 50 'user0' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 51 'user1' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 52 'user2' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 53 'user31' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 54 'userall' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 55 ), 56 ), 57 58 'Course with visible groups, default behavior (not filtering by cap, group, active)' => 59 array( 60 'settings' => array( 61 'coursegroupmode' => VISIBLEGROUPS, 62 'withcapability' => null, 63 'groupid' => null, 64 'onlyactive' => false, 65 'allowedcaps' => array(), 66 ), 67 'results' => array( // Everybody can view everybody. 68 'user0' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 69 'user1' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 70 'user2' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 71 'user31' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 72 'userall' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 73 ), 74 ), 75 76 'Course with separate groups, default behavior (not filtering by cap, group, active)' => 77 array( 78 'settings' => array( 79 'coursegroupmode' => SEPARATEGROUPS, 80 'withcapability' => null, 81 'groupid' => null, 82 'onlyactive' => false, 83 'allowedcaps' => array(), 84 ), 85 'results' => array( // Only users from own groups are visible. 86 'user0' => array('canview' => array()), // Poor guy, cannot see anybody, himself included. 87 'user1' => array('canview' => array('user1', 'userall')), 88 'user2' => array('canview' => array('user2', 'user2su', 'userall')), 89 'user31' => array('canview' => array('user31', 'user32', 'userall')), 90 'userall' => array('canview' => array('user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 91 ), 92 ), 93 94 'Course with separate groups, default behavior (not filtering but having moodle/site:accessallgroups)' => 95 array( 96 'settings' => array( 97 'coursegroupmode' => VISIBLEGROUPS, 98 'withcapability' => null, 99 'groupid' => null, 100 'onlyactive' => false, 101 'allowedcaps' => array('moodle/site:accessallgroups'), 102 ), 103 'results' => array( // Everybody can view everybody. 104 'user0' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 105 'user1' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 106 'user2' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 107 'user31' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 108 'userall' => array('canview' => array('user0', 'user1', 'user2', 'user2su', 'user31', 'user32', 'userall')), 109 ), 110 ), 111 112 'Course with separate groups, filtering onlyactive (missing moodle/course:enrolreview)' => 113 array( 114 'settings' => array( 115 'coursegroupmode' => SEPARATEGROUPS, 116 'withcapability' => null, 117 'groupid' => null, 118 'onlyactive' => true, 119 'allowedcaps' => array(), 120 ), 121 'results' => array( // returns exception, cannot view anybody without the cap. 122 'user2' => array('exception' => array( 123 'type' => 'required_capability_exception', 124 'message' => 'Review course enrolments')), 125 'userall' => array('exception' => array( 126 'type' => 'required_capability_exception', 127 'message' => 'Review course enrolments')), 128 ), 129 ), 130 131 'Course with separate groups, filtering onlyactive (having moodle/course:enrolreview)' => 132 array( 133 'settings' => array( 134 'coursegroupmode' => SEPARATEGROUPS, 135 'withcapability' => null, 136 'groupid' => null, 137 'onlyactive' => true, 138 'allowedcaps' => array('moodle/course:enrolreview'), 139 ), 140 'results' => array( // Suspended are not returned. 141 'user2' => array('canview' => array('user2', 'userall')), 142 'user31' => array('canview' => array('user31', 'user32', 'userall')), 143 'userall' => array('canview' => array('user1', 'user2', 'user31', 'user32', 'userall')), 144 ), 145 ), 146 147 'Course with separate groups, filtering by groupid (not having moodle/site:accessallgroups)' => 148 array( 149 'settings' => array( 150 'coursegroupmode' => SEPARATEGROUPS, 151 'withcapability' => null, 152 'groupid' => 'group2', 153 'onlyactive' => false, 154 'allowedcaps' => array(), 155 ), 156 'results' => array( // Only group 2 members and only for members. Exception for non-members. 157 'user0' => array('exception' => array( 158 'type' => 'required_capability_exception', 159 'message' => 'Access all groups')), 160 'user1' => array('exception' => array( 161 'type' => 'required_capability_exception', 162 'message' => 'Access all groups')), 163 'user2' => array('canview' => array('user2', 'user2su', 'userall')), 164 'userall' => array('canview' => array('user2', 'user2su', 'userall')), 165 ), 166 ), 167 168 'Course with separate groups, filtering by groupid (having moodle/site:accessallgroups)' => 169 array( 170 'settings' => array( 171 'coursegroupmode' => SEPARATEGROUPS, 172 'withcapability' => null, 173 'groupid' => 'group2', 174 'onlyactive' => false, 175 'allowedcaps' => array('moodle/site:accessallgroups'), 176 ), 177 'results' => array( // All users with 'moodle/site:accessallgroups' can view group 2 178 'user0' => array('canview' => array('user2', 'user2su', 'userall')), 179 'user1' => array('canview' => array('user2', 'user2su', 'userall')), 180 'user2' => array('canview' => array('user2', 'user2su', 'userall')), 181 'userall' => array('canview' => array('user2', 'user2su', 'userall')), 182 ), 183 ), 184 185 'Course with separate groups, filtering by withcapability (not having moodle/role:review)' => 186 array( 187 'settings' => array( 188 'coursegroupmode' => SEPARATEGROUPS, 189 'withcapability' => 'moodle/course:bulkmessaging', 190 'groupid' => null, 191 'onlyactive' => false, 192 'allowedcaps' => array(), 193 ), 194 'results' => array( // No user has 'moodle/role:review' so exception. 195 'user0' => array('exception' => array( 196 'type' => 'required_capability_exception', 197 'message' => 'Review permissions for others')), 198 'user1' => array('exception' => array( 199 'type' => 'required_capability_exception', 200 'message' => 'Review permissions for others')), 201 'user2' => array('exception' => array( 202 'type' => 'required_capability_exception', 203 'message' => 'Review permissions for others')), 204 'userall' => array('exception' => array( 205 'type' => 'required_capability_exception', 206 'message' => 'Review permissions for others')), 207 ), 208 ), 209 210 'Course with separate groups, filtering by withcapability (having moodle/role:review)' => 211 array( 212 'settings' => array( 213 'coursegroupmode' => SEPARATEGROUPS, 214 'withcapability' => 'moodle/course:bulkmessaging', 215 'groupid' => null, 216 'onlyactive' => false, 217 'allowedcaps' => array('moodle/role:review'), 218 ), 219 'results' => array( // No user has withcapability, but all have 'moodle/role:review'. Empties. 220 'user0' => array('canview' => array()), 221 'user1' => array('canview' => array()), 222 'user2' => array('canview' => array()), 223 'userall' => array('canview' => array()), 224 ), 225 ), 226 227 'Course with separate groups, filtering by withcapability (having moodle/role:review)' => 228 array( 229 'settings' => array( 230 'coursegroupmode' => SEPARATEGROUPS, 231 'withcapability' => 'moodle/course:bulkmessaging', 232 'groupid' => null, 233 'onlyactive' => false, 234 'allowedcaps' => array('moodle/role:review', 'moodle/course:bulkmessaging'), 235 ), 236 'results' => array( // Users (previous) have withcapability, and all have 'moodle/role:review'. 237 'user0' => array('canview' => array()), 238 'user1' => array('canview' => array('user1')), 239 'user2' => array('canview' => array('user2')), 240 'userall' => array('canview' => array('user1', 'user2', 'userall')), 241 ), 242 ), 243 ); 244 } 245 246 /** 247 * Verify get_enrolled_users() returned users are the expected in every situation. 248 * 249 * @dataProvider get_enrolled_users_visibility_provider 250 */ 251 public function test_get_enrolled_users_visibility($settings, $results) { 252 253 global $USER; 254 255 $this->resetAfterTest(); 256 257 // Create the course and the users. 258 $course = $this->getDataGenerator()->create_course(array('groupmode' => $settings['coursegroupmode'])); 259 $coursecontext = context_course::instance($course->id); 260 $user0 = $this->getDataGenerator()->create_user(array('username' => 'user0')); // A user without group. 261 $user1 = $this->getDataGenerator()->create_user(array('username' => 'user1')); // User for group 1. 262 $user2 = $this->getDataGenerator()->create_user(array('username' => 'user2')); // Two users for group 2. 263 $user2su = $this->getDataGenerator()->create_user(array('username' => 'user2su')); // (one suspended). 264 $user31 = $this->getDataGenerator()->create_user(array('username' => 'user31')); // Two users for group 3. 265 $user32 = $this->getDataGenerator()->create_user(array('username' => 'user32')); // (both enabled). 266 $userall = $this->getDataGenerator()->create_user(array('username' => 'userall')); // A user in all groups. 267 268 // Create utility array of created users, to produce better assertion messages. 269 $createdusers = array(); 270 foreach (array($user0, $user1, $user2, $user2su, $user31, $user32, $userall) as $createduser) { 271 $createdusers[$createduser->id] = $createduser->username; 272 } 273 274 // Enrol the users in the course. 275 $this->getDataGenerator()->enrol_user($user0->id, $course->id); 276 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 277 $this->getDataGenerator()->enrol_user($user2->id, $course->id); 278 $this->getDataGenerator()->enrol_user($user2su->id, $course->id, null, 'manual', 0, 0, ENROL_USER_SUSPENDED); 279 $this->getDataGenerator()->enrol_user($user31->id, $course->id); 280 $this->getDataGenerator()->enrol_user($user32->id, $course->id); 281 $this->getDataGenerator()->enrol_user($userall->id, $course->id); 282 283 // Create 3 groups. 284 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 285 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 286 $group3 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 287 288 // Add the users to the groups. 289 $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id)); 290 $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user2->id)); 291 $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user2su->id)); 292 $this->getDataGenerator()->create_group_member(array('groupid' => $group3->id, 'userid' => $user31->id)); 293 $this->getDataGenerator()->create_group_member(array('groupid' => $group3->id, 'userid' => $user32->id)); 294 $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $userall->id)); 295 $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $userall->id)); 296 $this->getDataGenerator()->create_group_member(array('groupid' => $group3->id, 'userid' => $userall->id)); 297 298 // Create a role to add the allowedcaps. Users will have this role assigned. 299 $roleid = $this->getDataGenerator()->create_role(); 300 // Allow the specified capabilities. 301 if (!empty($settings['allowedcaps'])) { 302 foreach ($settings['allowedcaps'] as $capability) { 303 assign_capability($capability, CAP_ALLOW, $roleid, $coursecontext); 304 } 305 } 306 307 // For each of the users, configure everything, perform the call, and assert results. 308 foreach ($results as $user => $expectations) { 309 // Convert canview expectations into a nice array of ids for easier handling. 310 $canview = array(); 311 $exception = null; 312 // Analyse the expectations. 313 if (isset($expectations['canview'])) { 314 foreach ($expectations['canview'] as $canviewuser) { 315 $canview[] = $createdusers[${$canviewuser}->id]; 316 } 317 } else if (isset($expectations['exception'])) { 318 $exception = $expectations['exception']; 319 $this->expectException($exception['type']); 320 $this->expectExceptionMessage($exception['message']); 321 } else { 322 // Failed, only canview and exception are supported. 323 $this->markTestIncomplete('Incomplete, only canview and exception are supported'); 324 } 325 // Switch to the user and assign the role. 326 $this->setUser(${$user}); 327 role_assign($roleid, $USER->id, $coursecontext); 328 329 // Convert groupid to proper id. 330 $groupid = 0; 331 if (isset($settings['groupid'])) { 332 $groupid = ${$settings['groupid']}->id; 333 } 334 335 // Call to the function. 336 $options = array( 337 array('name' => 'withcapability', 'value' => $settings['withcapability']), 338 array('name' => 'groupid', 'value' => $groupid), 339 array('name' => 'onlyactive', 'value' => $settings['onlyactive']), 340 array('name' => 'userfields', 'value' => 'id') 341 ); 342 $enrolledusers = core_enrol_external::get_enrolled_users($course->id, $options); 343 344 // We need to execute the return values cleaning process to simulate the web service server. 345 $enrolledusers = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_returns(), $enrolledusers); 346 347 // We are only interested in ids to check visibility. 348 $viewed = array(); 349 // Verify the user canview the expected users. 350 foreach ($enrolledusers as $enrolleduser) { 351 $viewed[] = $createdusers[$enrolleduser['id']]; 352 } 353 // Verify viewed matches canview expectation (using canonicalize to ignore ordering). 354 $this->assertEquals($canview, $viewed, "Problem checking visible users for '{$createdusers[$USER->id]}'", 0, 1, true); 355 } 356 } 357 358 /** 359 * Test get_users_courses 360 */ 361 public function test_get_users_courses() { 362 global $CFG, $DB; 363 require_once($CFG->dirroot . '/completion/criteria/completion_criteria_self.php'); 364 365 $this->resetAfterTest(true); 366 $CFG->enablecompletion = 1; 367 368 $timenow = time(); 369 $coursedata1 = array( 370 'fullname' => '<b>Course 1</b>', // Adding tags here to check that external_format_string works. 371 'shortname' => '<b>Course 1</b>', // Adding tags here to check that external_format_string works. 372 'summary' => 'Lightwork Course 1 description', 373 'summaryformat' => FORMAT_MOODLE, 374 'lang' => 'en', 375 'enablecompletion' => true, 376 'showgrades' => true, 377 'startdate' => $timenow, 378 'enddate' => $timenow + WEEKSECS, 379 'marker' => 1 380 ); 381 382 $coursedata2 = array( 383 'lang' => 'kk', // Check invalid language pack. 384 ); 385 386 $course1 = self::getDataGenerator()->create_course($coursedata1); 387 $course2 = self::getDataGenerator()->create_course($coursedata2); 388 $courses = array($course1, $course2); 389 $contexts = array ($course1->id => context_course::instance($course1->id), 390 $course2->id => context_course::instance($course2->id)); 391 392 $student = $this->getDataGenerator()->create_user(); 393 $otherstudent = $this->getDataGenerator()->create_user(); 394 $studentroleid = $DB->get_field('role', 'id', array('shortname' => 'student')); 395 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentroleid); 396 $this->getDataGenerator()->enrol_user($otherstudent->id, $course1->id, $studentroleid); 397 $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentroleid); 398 399 // Force last access. 400 $timenow = time(); 401 $lastaccess = array( 402 'userid' => $student->id, 403 'courseid' => $course1->id, 404 'timeaccess' => $timenow 405 ); 406 $DB->insert_record('user_lastaccess', $lastaccess); 407 408 // Force completion, setting at least one criteria. 409 require_once($CFG->dirroot.'/completion/criteria/completion_criteria_self.php'); 410 $criteriadata = new stdClass(); 411 $criteriadata->id = $course1->id; 412 // Self completion. 413 $criteriadata->criteria_self = 1; 414 415 $criterion = new completion_criteria_self(); 416 $criterion->update_config($criteriadata); 417 418 $ccompletion = new completion_completion(array('course' => $course1->id, 'userid' => $student->id)); 419 $ccompletion->mark_complete(); 420 421 // Set course hidden and favourited. 422 set_user_preference('block_myoverview_hidden_course_' . $course1->id, 1, $student); 423 $ufservice = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($student->id)); 424 $ufservice->create_favourite('core_course', 'courses', $course1->id, \context_system::instance()); 425 426 $this->setUser($student); 427 // Call the external function. 428 $enrolledincourses = core_enrol_external::get_users_courses($student->id, true); 429 430 // We need to execute the return values cleaning process to simulate the web service server. 431 $enrolledincourses = external_api::clean_returnvalue(core_enrol_external::get_users_courses_returns(), $enrolledincourses); 432 433 // Check we retrieve the good total number of enrolled users. 434 $this->assertEquals(2, count($enrolledincourses)); 435 436 // We need to format summary and summaryformat before to compare them with those values returned by the webservice. 437 list($course1->summary, $course1->summaryformat) = 438 external_format_text($course1->summary, $course1->summaryformat, $contexts[$course1->id]->id, 'course', 'summary', 0); 439 440 // Check there are no differences between $course1 properties and course values returned by the webservice 441 // only for those fields listed in the $coursedata1 array. 442 $course1->fullname = external_format_string($course1->fullname, $contexts[$course1->id]->id); 443 $course1->shortname = external_format_string($course1->shortname, $contexts[$course1->id]->id); 444 foreach ($enrolledincourses as $courseenrol) { 445 if ($courseenrol['id'] == $course1->id) { 446 foreach ($coursedata1 as $fieldname => $value) { 447 $this->assertEquals($courseenrol[$fieldname], $course1->$fieldname); 448 } 449 // Text extra fields. 450 $this->assertEquals($course1->fullname, $courseenrol['displayname']); 451 $this->assertEquals([], $courseenrol['overviewfiles']); 452 $this->assertEquals($timenow, $courseenrol['lastaccess']); 453 $this->assertEquals(100.0, $courseenrol['progress']); 454 $this->assertEquals(true, $courseenrol['completed']); 455 $this->assertTrue($courseenrol['completionhascriteria']); 456 $this->assertTrue($courseenrol['completionusertracked']); 457 $this->assertTrue($courseenrol['hidden']); 458 $this->assertTrue($courseenrol['isfavourite']); 459 $this->assertEquals(2, $courseenrol['enrolledusercount']); 460 } else { 461 // Check language pack. Should be empty since an incorrect one was used when creating the course. 462 $this->assertEmpty($courseenrol['lang']); 463 $this->assertEquals($course2->fullname, $courseenrol['displayname']); 464 $this->assertEquals([], $courseenrol['overviewfiles']); 465 $this->assertEquals(0, $courseenrol['lastaccess']); 466 $this->assertEquals(0, $courseenrol['progress']); 467 $this->assertEquals(false, $courseenrol['completed']); 468 $this->assertFalse($courseenrol['completionhascriteria']); 469 $this->assertFalse($courseenrol['completionusertracked']); 470 $this->assertFalse($courseenrol['hidden']); 471 $this->assertFalse($courseenrol['isfavourite']); 472 $this->assertEquals(1, $courseenrol['enrolledusercount']); 473 } 474 } 475 476 // Check that returnusercount works correctly. 477 $enrolledincourses = core_enrol_external::get_users_courses($student->id, false); 478 $enrolledincourses = external_api::clean_returnvalue(core_enrol_external::get_users_courses_returns(), $enrolledincourses); 479 foreach ($enrolledincourses as $courseenrol) { 480 $this->assertFalse(isset($courseenrol['enrolledusercount'])); 481 } 482 483 // Now check that admin users can see all the info. 484 $this->setAdminUser(); 485 486 $enrolledincourses = core_enrol_external::get_users_courses($student->id, true); 487 $enrolledincourses = external_api::clean_returnvalue(core_enrol_external::get_users_courses_returns(), $enrolledincourses); 488 $this->assertEquals(2, count($enrolledincourses)); 489 foreach ($enrolledincourses as $courseenrol) { 490 if ($courseenrol['id'] == $course1->id) { 491 $this->assertEquals($timenow, $courseenrol['lastaccess']); 492 $this->assertEquals(100.0, $courseenrol['progress']); 493 $this->assertTrue($courseenrol['completionhascriteria']); 494 $this->assertTrue($courseenrol['completionusertracked']); 495 $this->assertFalse($courseenrol['isfavourite']); // This always false. 496 $this->assertFalse($courseenrol['hidden']); // This always false. 497 } else { 498 $this->assertEquals(0, $courseenrol['progress']); 499 $this->assertFalse($courseenrol['completionhascriteria']); 500 $this->assertFalse($courseenrol['completionusertracked']); 501 $this->assertFalse($courseenrol['isfavourite']); // This always false. 502 $this->assertFalse($courseenrol['hidden']); // This always false. 503 } 504 } 505 506 // Check other users can't see private info. 507 $this->setUser($otherstudent); 508 509 $enrolledincourses = core_enrol_external::get_users_courses($student->id, true); 510 $enrolledincourses = external_api::clean_returnvalue(core_enrol_external::get_users_courses_returns(), $enrolledincourses); 511 $this->assertEquals(1, count($enrolledincourses)); 512 513 $this->assertEquals($timenow, $enrolledincourses[0]['lastaccess']); // I can see this, not hidden. 514 $this->assertEquals(null, $enrolledincourses[0]['progress']); // I can't see this, private. 515 516 // Change some global profile visibility fields. 517 $CFG->hiddenuserfields = 'lastaccess'; 518 $enrolledincourses = core_enrol_external::get_users_courses($student->id, true); 519 $enrolledincourses = external_api::clean_returnvalue(core_enrol_external::get_users_courses_returns(), $enrolledincourses); 520 521 $this->assertEquals(0, $enrolledincourses[0]['lastaccess']); // I can't see this, hidden by global setting. 522 } 523 524 /** 525 * Test that get_users_courses respects the capability to view participants when viewing courses of other user 526 */ 527 public function test_get_users_courses_can_view_participants(): void { 528 global $DB; 529 530 $this->resetAfterTest(); 531 532 $course = $this->getDataGenerator()->create_course(); 533 $context = context_course::instance($course->id); 534 535 $user1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 536 $user2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 537 538 $this->setUser($user1); 539 540 $courses = core_enrol_external::clean_returnvalue( 541 core_enrol_external::get_users_courses_returns(), 542 core_enrol_external::get_users_courses($user2->id, false) 543 ); 544 545 $this->assertCount(1, $courses); 546 $this->assertEquals($course->id, reset($courses)['id']); 547 548 // Prohibit the capability for viewing course participants. 549 $studentrole = $DB->get_field('role', 'id', ['shortname' => 'student']); 550 assign_capability('moodle/course:viewparticipants', CAP_PROHIBIT, $studentrole, $context->id); 551 552 $courses = core_enrol_external::clean_returnvalue( 553 core_enrol_external::get_users_courses_returns(), 554 core_enrol_external::get_users_courses($user2->id, false) 555 ); 556 $this->assertEmpty($courses); 557 } 558 559 /* 560 * Test that get_users_courses respects the capability to view a users profile when viewing courses of other user 561 */ 562 public function test_get_users_courses_can_view_profile(): void { 563 $this->resetAfterTest(); 564 565 $course = $this->getDataGenerator()->create_course([ 566 'groupmode' => VISIBLEGROUPS, 567 ]); 568 569 $user1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 570 $user2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 571 572 // Create separate groups for each of our students. 573 $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 574 groups_add_member($group1, $user1); 575 $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 576 groups_add_member($group2, $user2); 577 578 $this->setUser($user1); 579 580 $courses = core_enrol_external::clean_returnvalue( 581 core_enrol_external::get_users_courses_returns(), 582 core_enrol_external::get_users_courses($user2->id, false) 583 ); 584 585 $this->assertCount(1, $courses); 586 $this->assertEquals($course->id, reset($courses)['id']); 587 588 // Change to separate groups mode, so students can't view information about each other in different groups. 589 $course->groupmode = SEPARATEGROUPS; 590 update_course($course); 591 592 $courses = core_enrol_external::clean_returnvalue( 593 core_enrol_external::get_users_courses_returns(), 594 core_enrol_external::get_users_courses($user2->id, false) 595 ); 596 $this->assertEmpty($courses); 597 } 598 599 /** 600 * Test get_users_courses with mathjax in the name. 601 */ 602 public function test_get_users_courses_with_mathjax() { 603 global $DB; 604 605 $this->resetAfterTest(true); 606 607 // Enable MathJax filter in content and headings. 608 $this->configure_filters([ 609 ['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true], 610 ]); 611 612 // Create a course with MathJax in the name and summary. 613 $coursedata = [ 614 'fullname' => 'Course 1 $$(a+b)=2$$', 615 'shortname' => 'Course 1 $$(a+b)=2$$', 616 'summary' => 'Lightwork Course 1 description $$(a+b)=2$$', 617 'summaryformat' => FORMAT_HTML, 618 ]; 619 620 $course = self::getDataGenerator()->create_course($coursedata); 621 $context = context_course::instance($course->id); 622 623 // Enrol a student in the course. 624 $student = $this->getDataGenerator()->create_user(); 625 $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student']); 626 $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentroleid); 627 628 $this->setUser($student); 629 630 // Call the external function. 631 $enrolledincourses = core_enrol_external::get_users_courses($student->id, true); 632 633 // We need to execute the return values cleaning process to simulate the web service server. 634 $enrolledincourses = external_api::clean_returnvalue(core_enrol_external::get_users_courses_returns(), $enrolledincourses); 635 636 // Check that the amount of courses is the right one. 637 $this->assertCount(1, $enrolledincourses); 638 639 // Filter the values to compare them with the returned ones. 640 $course->fullname = external_format_string($course->fullname, $context->id); 641 $course->shortname = external_format_string($course->shortname, $context->id); 642 list($course->summary, $course->summaryformat) = 643 external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', 0); 644 645 // Compare the values. 646 $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $enrolledincourses[0]['fullname']); 647 $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $enrolledincourses[0]['shortname']); 648 $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $enrolledincourses[0]['summary']); 649 $this->assertEquals($course->fullname, $enrolledincourses[0]['fullname']); 650 $this->assertEquals($course->shortname, $enrolledincourses[0]['shortname']); 651 $this->assertEquals($course->summary, $enrolledincourses[0]['summary']); 652 } 653 654 /** 655 * Test get_course_enrolment_methods 656 */ 657 public function test_get_course_enrolment_methods() { 658 global $DB; 659 660 $this->resetAfterTest(true); 661 662 // Get enrolment plugins. 663 $selfplugin = enrol_get_plugin('self'); 664 $this->assertNotEmpty($selfplugin); 665 $manualplugin = enrol_get_plugin('manual'); 666 $this->assertNotEmpty($manualplugin); 667 668 $studentrole = $DB->get_record('role', array('shortname'=>'student')); 669 $this->assertNotEmpty($studentrole); 670 671 $course1 = self::getDataGenerator()->create_course(); 672 $coursedata = new stdClass(); 673 $coursedata->visible = 0; 674 $course2 = self::getDataGenerator()->create_course($coursedata); 675 676 // Add enrolment methods for course. 677 $instanceid1 = $selfplugin->add_instance($course1, array('status' => ENROL_INSTANCE_ENABLED, 678 'name' => 'Test instance 1', 679 'customint6' => 1, 680 'roleid' => $studentrole->id)); 681 $instanceid2 = $selfplugin->add_instance($course1, array('status' => ENROL_INSTANCE_DISABLED, 682 'name' => 'Test instance 2', 683 'roleid' => $studentrole->id)); 684 685 $instanceid3 = $manualplugin->add_instance($course1, array('status' => ENROL_INSTANCE_ENABLED, 686 'name' => 'Test instance 3')); 687 688 $enrolmentmethods = $DB->get_records('enrol', array('courseid' => $course1->id, 'status' => ENROL_INSTANCE_ENABLED)); 689 $this->assertCount(2, $enrolmentmethods); 690 691 $this->setAdminUser(); 692 693 // Check if information is returned. 694 $enrolmentmethods = core_enrol_external::get_course_enrolment_methods($course1->id); 695 $enrolmentmethods = external_api::clean_returnvalue(core_enrol_external::get_course_enrolment_methods_returns(), 696 $enrolmentmethods); 697 // Enrolment information is currently returned by self enrolment plugin, so count == 1. 698 // This should be changed as we implement get_enrol_info() for other enrolment plugins. 699 $this->assertCount(1, $enrolmentmethods); 700 701 $enrolmentmethod = $enrolmentmethods[0]; 702 $this->assertEquals($course1->id, $enrolmentmethod['courseid']); 703 $this->assertEquals('self', $enrolmentmethod['type']); 704 $this->assertTrue($enrolmentmethod['status']); 705 $this->assertFalse(isset($enrolmentmethod['wsfunction'])); 706 707 $instanceid4 = $selfplugin->add_instance($course2, array('status' => ENROL_INSTANCE_ENABLED, 708 'name' => 'Test instance 4', 709 'roleid' => $studentrole->id, 710 'customint6' => 1, 711 'password' => 'test')); 712 $enrolmentmethods = core_enrol_external::get_course_enrolment_methods($course2->id); 713 $enrolmentmethods = external_api::clean_returnvalue(core_enrol_external::get_course_enrolment_methods_returns(), 714 $enrolmentmethods); 715 $this->assertCount(1, $enrolmentmethods); 716 717 $enrolmentmethod = $enrolmentmethods[0]; 718 $this->assertEquals($course2->id, $enrolmentmethod['courseid']); 719 $this->assertEquals('self', $enrolmentmethod['type']); 720 $this->assertTrue($enrolmentmethod['status']); 721 $this->assertEquals('enrol_self_get_instance_info', $enrolmentmethod['wsfunction']); 722 723 // Try to retrieve information using a normal user for a hidden course. 724 $user = self::getDataGenerator()->create_user(); 725 $this->setUser($user); 726 try { 727 core_enrol_external::get_course_enrolment_methods($course2->id); 728 } catch (moodle_exception $e) { 729 $this->assertEquals('coursehidden', $e->errorcode); 730 } 731 } 732 733 public function get_enrolled_users_setup($capability) { 734 global $USER; 735 736 $this->resetAfterTest(true); 737 738 $return = new stdClass(); 739 740 $return->course = self::getDataGenerator()->create_course(); 741 $return->user1 = self::getDataGenerator()->create_user(); 742 $return->user2 = self::getDataGenerator()->create_user(); 743 $return->user3 = self::getDataGenerator()->create_user(); 744 $this->setUser($return->user3); 745 746 // Set the required capabilities by the external function. 747 $return->context = context_course::instance($return->course->id); 748 $return->roleid = $this->assignUserCapability($capability, $return->context->id); 749 $this->assignUserCapability('moodle/user:viewdetails', $return->context->id, $return->roleid); 750 751 // Enrol the users in the course. 752 $this->getDataGenerator()->enrol_user($return->user1->id, $return->course->id, $return->roleid, 'manual'); 753 $this->getDataGenerator()->enrol_user($return->user2->id, $return->course->id, $return->roleid, 'manual'); 754 $this->getDataGenerator()->enrol_user($return->user3->id, $return->course->id, $return->roleid, 'manual'); 755 756 return $return; 757 } 758 759 /** 760 * Test get_enrolled_users from core_enrol_external without additional 761 * parameters. 762 */ 763 public function test_get_enrolled_users_without_parameters() { 764 $capability = 'moodle/course:viewparticipants'; 765 $data = $this->get_enrolled_users_setup($capability); 766 767 // Call the external function. 768 $enrolledusers = core_enrol_external::get_enrolled_users($data->course->id); 769 770 // We need to execute the return values cleaning process to simulate the web service server. 771 $enrolledusers = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_returns(), $enrolledusers); 772 773 // Check the result set. 774 $this->assertEquals(3, count($enrolledusers)); 775 $this->assertArrayHasKey('email', $enrolledusers[0]); 776 } 777 778 /** 779 * Test get_enrolled_users from core_enrol_external with some parameters set. 780 */ 781 public function test_get_enrolled_users_with_parameters() { 782 $capability = 'moodle/course:viewparticipants'; 783 $data = $this->get_enrolled_users_setup($capability); 784 785 // Call the function with some parameters set. 786 $enrolledusers = core_enrol_external::get_enrolled_users($data->course->id, array( 787 array('name' => 'limitfrom', 'value' => 2), 788 array('name' => 'limitnumber', 'value' => 1), 789 array('name' => 'userfields', 'value' => 'id') 790 )); 791 792 // We need to execute the return values cleaning process to simulate the web service server. 793 $enrolledusers = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_returns(), $enrolledusers); 794 795 // Check the result set, we should only get the 3rd result, which is $user3. 796 $this->assertCount(1, $enrolledusers); 797 $this->assertEquals($data->user3->id, $enrolledusers[0]['id']); 798 $this->assertArrayHasKey('id', $enrolledusers[0]); 799 $this->assertArrayNotHasKey('email', $enrolledusers[0]); 800 } 801 802 803 /** 804 * Test get_enrolled_users last course access. 805 */ 806 public function test_get_enrolled_users_including_lastcourseaccess() { 807 global $DB; 808 $capability = 'moodle/course:viewparticipants'; 809 $data = $this->get_enrolled_users_setup($capability); 810 811 // Call the external function. 812 $enrolledusers = core_enrol_external::get_enrolled_users($data->course->id); 813 // We need to execute the return values cleaning process to simulate the web service server. 814 $enrolledusers = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_returns(), $enrolledusers); 815 816 // Check the result set. 817 $this->assertEquals(3, count($enrolledusers)); 818 $this->assertArrayHasKey('email', $enrolledusers[0]); 819 $this->assertEquals(0, $enrolledusers[0]['lastcourseaccess']); 820 $this->assertEquals(0, $enrolledusers[1]['lastcourseaccess']); 821 $this->assertNotEquals(0, $enrolledusers[2]['lastcourseaccess']); // We forced an access to the course via setUser. 822 823 // Force last access. 824 $timenow = time(); 825 $lastaccess = array( 826 'userid' => $enrolledusers[0]['id'], 827 'courseid' => $data->course->id, 828 'timeaccess' => $timenow 829 ); 830 $DB->insert_record('user_lastaccess', $lastaccess); 831 832 $enrolledusers = core_enrol_external::get_enrolled_users($data->course->id); 833 $enrolledusers = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_returns(), $enrolledusers); 834 835 // Check the result set. 836 $this->assertEquals(3, count($enrolledusers)); 837 $this->assertEquals($timenow, $enrolledusers[0]['lastcourseaccess']); 838 $this->assertEquals(0, $enrolledusers[1]['lastcourseaccess']); 839 $this->assertNotEquals(0, $enrolledusers[2]['lastcourseaccess']); 840 } 841 842 /** 843 * Test get_enrolled_users from core_enrol_external with capability to 844 * viewparticipants removed. 845 * 846 * @expectedException moodle_exception 847 */ 848 public function test_get_enrolled_users_without_capability() { 849 $capability = 'moodle/course:viewparticipants'; 850 $data = $this->get_enrolled_users_setup($capability); 851 852 // Call without required capability. 853 $this->unassignUserCapability($capability, $data->context->id, $data->roleid); 854 $categories = core_enrol_external::get_enrolled_users($data->course->id); 855 } 856 857 public function get_enrolled_users_with_capability_setup($capability) { 858 global $USER, $DB; 859 860 $this->resetAfterTest(true); 861 862 $return = new stdClass(); 863 864 // Create the course and fetch its context. 865 $return->course = self::getDataGenerator()->create_course(); 866 $context = context_course::instance($return->course->id); 867 868 // Create one teacher, and two students. 869 $return->teacher = self::getDataGenerator()->create_user(); 870 $return->student1 = self::getDataGenerator()->create_user(); 871 $return->student2 = self::getDataGenerator()->create_user(); 872 873 // Create a new student role based on the student archetype but with the capability prohibitted. 874 $fakestudentroleid = create_role('Fake student role', 'fakestudent', 'Fake student role', 'student'); 875 assign_capability($capability, CAP_PROHIBIT, $fakestudentroleid, $context->id); 876 877 // Enrol all of the users in the course. 878 // * 'teacher' is an editing teacher. 879 // * 'student1' is a standard student. 880 // * 'student2' is a student with the capability prohibitted. 881 $editingteacherroleid = $DB->get_field('role', 'id', array('shortname' => 'editingteacher')); 882 $studentroleid = $DB->get_field('role', 'id', array('shortname' => 'student')); 883 $this->getDataGenerator()->enrol_user($return->teacher->id, $return->course->id, $editingteacherroleid); 884 $this->getDataGenerator()->enrol_user($return->student1->id, $return->course->id, $studentroleid); 885 $this->getDataGenerator()->enrol_user($return->student2->id, $return->course->id, $fakestudentroleid); 886 887 // Log in as the teacher. 888 $this->setUser($return->teacher); 889 890 // Clear caches. 891 accesslib_clear_all_caches_for_unit_testing(); 892 893 return $return; 894 } 895 896 /** 897 * Test get_enrolled_users_with_capability without additional paramaters. 898 */ 899 public function test_get_enrolled_users_with_capability_without_parameters() { 900 $capability = 'moodle/course:viewparticipants'; 901 $data = $this->get_enrolled_users_with_capability_setup($capability); 902 903 $result = core_enrol_external::get_enrolled_users_with_capability( 904 array( 905 'coursecapabilities' => array( 906 'courseid' => $data->course->id, 907 'capabilities' => array( 908 $capability, 909 ), 910 ), 911 ), 912 array() 913 ); 914 915 // We need to execute the return values cleaning process to simulate the web service server. 916 $result = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_with_capability_returns(), $result); 917 918 // Check an array containing the expected user for the course capability is returned. 919 $expecteduserlist = $result[0]; 920 $this->assertEquals($data->course->id, $expecteduserlist['courseid']); 921 $this->assertEquals($capability, $expecteduserlist['capability']); 922 $this->assertEquals(2, count($expecteduserlist['users'])); 923 } 924 925 /** 926 * Test get_enrolled_users_with_capability 927 */ 928 public function test_get_enrolled_users_with_capability_with_parameters () { 929 $capability = 'moodle/course:viewparticipants'; 930 $data = $this->get_enrolled_users_with_capability_setup($capability); 931 932 $result = core_enrol_external::get_enrolled_users_with_capability( 933 array( 934 'coursecapabilities' => array( 935 'courseid' => $data->course->id, 936 'capabilities' => array( 937 $capability, 938 ), 939 ), 940 ), 941 array( 942 array('name' => 'limitfrom', 'value' => 1), 943 array('name' => 'limitnumber', 'value' => 1), 944 array('name' => 'userfields', 'value' => 'id') 945 ) 946 ); 947 948 // We need to execute the return values cleaning process to simulate the web service server. 949 $result = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_with_capability_returns(), $result); 950 951 // Check an array containing the expected user for the course capability is returned. 952 $expecteduserlist = $result[0]['users']; 953 $expecteduser = reset($expecteduserlist); 954 $this->assertEquals(1, count($expecteduserlist)); 955 $this->assertEquals($data->student1->id, $expecteduser['id']); 956 } 957 958 /** 959 * Test get_enrolled_users last course access. 960 */ 961 public function test_get_enrolled_users_with_capability_including_lastcourseaccess() { 962 global $DB; 963 $capability = 'moodle/course:viewparticipants'; 964 $data = $this->get_enrolled_users_with_capability_setup($capability); 965 966 $parameters = array( 967 'coursecapabilities' => array( 968 'courseid' => $data->course->id, 969 'capabilities' => array( 970 $capability, 971 ), 972 ), 973 ); 974 975 $result = core_enrol_external::get_enrolled_users_with_capability($parameters, array()); 976 // We need to execute the return values cleaning process to simulate the web service server. 977 $result = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_with_capability_returns(), $result); 978 979 // Check an array containing the expected user for the course capability is returned. 980 $expecteduserlist = $result[0]; 981 $this->assertEquals($data->course->id, $expecteduserlist['courseid']); 982 $this->assertEquals($capability, $expecteduserlist['capability']); 983 $this->assertEquals(2, count($expecteduserlist['users'])); 984 // We forced an access to the course via setUser. 985 $this->assertNotEquals(0, $expecteduserlist['users'][0]['lastcourseaccess']); 986 $this->assertEquals(0, $expecteduserlist['users'][1]['lastcourseaccess']); 987 988 // Force last access. 989 $timenow = time(); 990 $lastaccess = array( 991 'userid' => $expecteduserlist['users'][1]['id'], 992 'courseid' => $data->course->id, 993 'timeaccess' => $timenow 994 ); 995 $DB->insert_record('user_lastaccess', $lastaccess); 996 997 $result = core_enrol_external::get_enrolled_users_with_capability($parameters, array()); 998 // We need to execute the return values cleaning process to simulate the web service server. 999 $result = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_with_capability_returns(), $result); 1000 1001 // Check the result set. 1002 $expecteduserlist = $result[0]; 1003 $this->assertEquals(2, count($expecteduserlist['users'])); 1004 $this->assertNotEquals(0, $expecteduserlist['users'][0]['lastcourseaccess']); 1005 $this->assertEquals($timenow, $expecteduserlist['users'][1]['lastcourseaccess']); 1006 } 1007 1008 /** 1009 * Test for core_enrol_external::edit_user_enrolment(). 1010 */ 1011 public function test_edit_user_enrolment() { 1012 global $DB; 1013 1014 $this->resetAfterTest(true); 1015 $datagen = $this->getDataGenerator(); 1016 1017 /** @var enrol_manual_plugin $manualplugin */ 1018 $manualplugin = enrol_get_plugin('manual'); 1019 $this->assertNotNull($manualplugin); 1020 1021 $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST); 1022 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST); 1023 $course = $datagen->create_course(); 1024 $user = $datagen->create_user(); 1025 $teacher = $datagen->create_user(); 1026 1027 $instanceid = null; 1028 $instances = enrol_get_instances($course->id, true); 1029 foreach ($instances as $inst) { 1030 if ($inst->enrol == 'manual') { 1031 $instanceid = (int)$inst->id; 1032 break; 1033 } 1034 } 1035 if (empty($instanceid)) { 1036 $instanceid = $manualplugin->add_default_instance($course); 1037 if (empty($instanceid)) { 1038 $instanceid = $manualplugin->add_instance($course); 1039 } 1040 } 1041 $this->assertNotNull($instanceid); 1042 1043 $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST); 1044 $manualplugin->enrol_user($instance, $user->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1045 $manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE); 1046 $ueid = (int)$DB->get_field( 1047 'user_enrolments', 1048 'id', 1049 ['enrolid' => $instance->id, 'userid' => $user->id], 1050 MUST_EXIST 1051 ); 1052 1053 // Login as teacher. 1054 $this->setUser($teacher); 1055 1056 $now = new DateTime(); 1057 $nowtime = $now->getTimestamp(); 1058 1059 // Invalid data. 1060 $data = core_enrol_external::edit_user_enrolment($course->id, $ueid, ENROL_USER_ACTIVE, $nowtime, $nowtime); 1061 $data = external_api::clean_returnvalue(core_enrol_external::edit_user_enrolment_returns(), $data); 1062 $this->assertFalse($data['result']); 1063 $this->assertNotEmpty($data['errors']); 1064 1065 // Valid data. 1066 $nextmonth = clone($now); 1067 $nextmonth->add(new DateInterval('P1M')); 1068 $nextmonthtime = $nextmonth->getTimestamp(); 1069 $data = core_enrol_external::edit_user_enrolment($course->id, $ueid, ENROL_USER_ACTIVE, $nowtime, $nextmonthtime); 1070 $data = external_api::clean_returnvalue(core_enrol_external::edit_user_enrolment_returns(), $data); 1071 $this->assertTrue($data['result']); 1072 $this->assertEmpty($data['errors']); 1073 1074 // Check updated user enrolment. 1075 $ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST); 1076 $this->assertEquals(ENROL_USER_ACTIVE, $ue->status); 1077 $this->assertEquals($nowtime, $ue->timestart); 1078 $this->assertEquals($nextmonthtime, $ue->timeend); 1079 1080 // Suspend user. 1081 $data = core_enrol_external::edit_user_enrolment($course->id, $ueid, ENROL_USER_SUSPENDED); 1082 $data = external_api::clean_returnvalue(core_enrol_external::edit_user_enrolment_returns(), $data); 1083 $this->assertTrue($data['result']); 1084 $this->assertEmpty($data['errors']); 1085 1086 // Check updated user enrolment. 1087 $ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST); 1088 $this->assertEquals(ENROL_USER_SUSPENDED, $ue->status); 1089 } 1090 1091 /** 1092 * dataProvider for test_submit_user_enrolment_form(). 1093 */ 1094 public function submit_user_enrolment_form_provider() { 1095 $now = new DateTime(); 1096 1097 $nextmonth = clone($now); 1098 $nextmonth->add(new DateInterval('P1M')); 1099 1100 return [ 1101 'Invalid data' => [ 1102 'customdata' => [ 1103 'status' => ENROL_USER_ACTIVE, 1104 'timestart' => [ 1105 'day' => $now->format('j'), 1106 'month' => $now->format('n'), 1107 'year' => $now->format('Y'), 1108 'hour' => $now->format('G'), 1109 'minute' => 0, 1110 'enabled' => 1, 1111 ], 1112 'timeend' => [ 1113 'day' => $now->format('j'), 1114 'month' => $now->format('n'), 1115 'year' => $now->format('Y'), 1116 'hour' => $now->format('G'), 1117 'minute' => 0, 1118 'enabled' => 1, 1119 ], 1120 ], 1121 'expectedresult' => false, 1122 'validationerror' => true, 1123 ], 1124 'Valid data' => [ 1125 'customdata' => [ 1126 'status' => ENROL_USER_ACTIVE, 1127 'timestart' => [ 1128 'day' => $now->format('j'), 1129 'month' => $now->format('n'), 1130 'year' => $now->format('Y'), 1131 'hour' => $now->format('G'), 1132 'minute' => 0, 1133 'enabled' => 1, 1134 ], 1135 'timeend' => [ 1136 'day' => $nextmonth->format('j'), 1137 'month' => $nextmonth->format('n'), 1138 'year' => $nextmonth->format('Y'), 1139 'hour' => $nextmonth->format('G'), 1140 'minute' => 0, 1141 'enabled' => 1, 1142 ], 1143 ], 1144 'expectedresult' => true, 1145 'validationerror' => false 1146 ], 1147 'Suspend user' => [ 1148 'customdata' => [ 1149 'status' => ENROL_USER_SUSPENDED, 1150 ], 1151 'expectedresult' => true, 1152 'validationerror' => false 1153 ], 1154 ]; 1155 } 1156 1157 /** 1158 * @param array $customdata The data we are providing to the webservice. 1159 * @param bool $expectedresult The result we are expecting to receive from the webservice. 1160 * @param bool $validationerror The validationerror we are expecting to receive from the webservice. 1161 * @dataProvider submit_user_enrolment_form_provider 1162 */ 1163 public function test_submit_user_enrolment_form($customdata, $expectedresult, $validationerror) { 1164 global $CFG, $DB; 1165 1166 $this->resetAfterTest(true); 1167 $datagen = $this->getDataGenerator(); 1168 1169 /** @var enrol_manual_plugin $manualplugin */ 1170 $manualplugin = enrol_get_plugin('manual'); 1171 1172 $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST); 1173 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST); 1174 $course = $datagen->create_course(); 1175 $user = $datagen->create_user(); 1176 $teacher = $datagen->create_user(); 1177 1178 $instanceid = null; 1179 $instances = enrol_get_instances($course->id, true); 1180 foreach ($instances as $inst) { 1181 if ($inst->enrol == 'manual') { 1182 $instanceid = (int)$inst->id; 1183 break; 1184 } 1185 } 1186 if (empty($instanceid)) { 1187 $instanceid = $manualplugin->add_default_instance($course); 1188 if (empty($instanceid)) { 1189 $instanceid = $manualplugin->add_instance($course); 1190 } 1191 } 1192 $this->assertNotNull($instanceid); 1193 1194 $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST); 1195 $manualplugin->enrol_user($instance, $user->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1196 $manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE); 1197 $ueid = (int) $DB->get_field( 1198 'user_enrolments', 1199 'id', 1200 ['enrolid' => $instance->id, 'userid' => $user->id], 1201 MUST_EXIST 1202 ); 1203 1204 // Login as teacher. 1205 $teacher->ignoresesskey = true; 1206 $this->setUser($teacher); 1207 1208 $formdata = [ 1209 'ue' => $ueid, 1210 'ifilter' => 0, 1211 'status' => null, 1212 'timestart' => null, 1213 'duration' => null, 1214 'timeend' => null, 1215 ]; 1216 1217 $formdata = array_merge($formdata, $customdata); 1218 1219 require_once("$CFG->dirroot/enrol/editenrolment_form.php"); 1220 $formdata = enrol_user_enrolment_form::mock_generate_submit_keys($formdata); 1221 1222 $querystring = http_build_query($formdata, '', '&'); 1223 1224 $result = external_api::clean_returnvalue( 1225 core_enrol_external::submit_user_enrolment_form_returns(), 1226 core_enrol_external::submit_user_enrolment_form($querystring) 1227 ); 1228 1229 $this->assertEquals( 1230 ['result' => $expectedresult, 'validationerror' => $validationerror], 1231 $result, 1232 '', 0.0, 10, true); 1233 1234 if ($result['result']) { 1235 $ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST); 1236 $this->assertEquals($formdata['status'], $ue->status); 1237 } 1238 } 1239 1240 /** 1241 * Test for core_enrol_external::unenrol_user_enrolment(). 1242 */ 1243 public function test_unenerol_user_enrolment() { 1244 global $DB; 1245 1246 $this->resetAfterTest(true); 1247 $datagen = $this->getDataGenerator(); 1248 1249 /** @var enrol_manual_plugin $manualplugin */ 1250 $manualplugin = enrol_get_plugin('manual'); 1251 $this->assertNotNull($manualplugin); 1252 1253 $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST); 1254 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST); 1255 $course = $datagen->create_course(); 1256 $user = $datagen->create_user(); 1257 $teacher = $datagen->create_user(); 1258 1259 $instanceid = null; 1260 $instances = enrol_get_instances($course->id, true); 1261 foreach ($instances as $inst) { 1262 if ($inst->enrol == 'manual') { 1263 $instanceid = (int)$inst->id; 1264 break; 1265 } 1266 } 1267 if (empty($instanceid)) { 1268 $instanceid = $manualplugin->add_default_instance($course); 1269 if (empty($instanceid)) { 1270 $instanceid = $manualplugin->add_instance($course); 1271 } 1272 } 1273 $this->assertNotNull($instanceid); 1274 1275 $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST); 1276 $manualplugin->enrol_user($instance, $user->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1277 $manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE); 1278 $ueid = (int)$DB->get_field( 1279 'user_enrolments', 1280 'id', 1281 ['enrolid' => $instance->id, 'userid' => $user->id], 1282 MUST_EXIST 1283 ); 1284 1285 // Login as teacher. 1286 $this->setUser($teacher); 1287 1288 // Invalid data by passing invalid ueid. 1289 $data = core_enrol_external::unenrol_user_enrolment(101010); 1290 $data = external_api::clean_returnvalue(core_enrol_external::unenrol_user_enrolment_returns(), $data); 1291 $this->assertFalse($data['result']); 1292 $this->assertNotEmpty($data['errors']); 1293 1294 // Valid data. 1295 $data = core_enrol_external::unenrol_user_enrolment($ueid); 1296 $data = external_api::clean_returnvalue(core_enrol_external::unenrol_user_enrolment_returns(), $data); 1297 $this->assertTrue($data['result']); 1298 $this->assertEmpty($data['errors']); 1299 1300 // Check unenrol user enrolment. 1301 $ue = $DB->count_records('user_enrolments', ['id' => $ueid]); 1302 $this->assertEquals(0, $ue); 1303 } 1304 1305 /** 1306 * Test for core_enrol_external::test_search_users(). 1307 */ 1308 public function test_search_users() { 1309 global $DB; 1310 1311 $this->resetAfterTest(true); 1312 $datagen = $this->getDataGenerator(); 1313 1314 /** @var enrol_manual_plugin $manualplugin */ 1315 $manualplugin = enrol_get_plugin('manual'); 1316 $this->assertNotNull($manualplugin); 1317 1318 $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST); 1319 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST); 1320 1321 $course1 = $datagen->create_course(); 1322 $course2 = $datagen->create_course(); 1323 1324 $user1 = $datagen->create_user(['firstname' => 'user 1']); 1325 $user2 = $datagen->create_user(['firstname' => 'user 2']); 1326 $user3 = $datagen->create_user(['firstname' => 'user 3']); 1327 $teacher = $datagen->create_user(['firstname' => 'user 4']); 1328 1329 $instanceid = null; 1330 $instances = enrol_get_instances($course1->id, true); 1331 foreach ($instances as $inst) { 1332 if ($inst->enrol == 'manual') { 1333 $instanceid = (int)$inst->id; 1334 break; 1335 } 1336 } 1337 if (empty($instanceid)) { 1338 $instanceid = $manualplugin->add_default_instance($course1); 1339 if (empty($instanceid)) { 1340 $instanceid = $manualplugin->add_instance($course1); 1341 } 1342 } 1343 $this->assertNotNull($instanceid); 1344 1345 $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST); 1346 $manualplugin->enrol_user($instance, $user1->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1347 $manualplugin->enrol_user($instance, $user2->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1348 $manualplugin->enrol_user($instance, $user3->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1349 $manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE); 1350 1351 $this->setUser($teacher); 1352 1353 // Search for users in a course with enrolled users. 1354 $result = core_enrol_external::search_users($course1->id, 'user', true, 0, 30); 1355 $this->assertCount(4, $result); 1356 1357 $this->expectException('moodle_exception'); 1358 // Search for users in a course without any enrolled users, shouldn't return anything. 1359 $result = core_enrol_external::search_users($course2->id, 'user', true, 0, 30); 1360 $this->assertCount(0, $result); 1361 1362 // Search for invalid first name. 1363 $result = core_enrol_external::search_users($course1->id, 'yada yada', true, 0, 30); 1364 $this->assertCount(0, $result); 1365 1366 // Test pagination, it should return only 3 users. 1367 $result = core_enrol_external::search_users($course1->id, 'user', true, 0, 3); 1368 $this->assertCount(3, $result); 1369 1370 // Test pagination, it should return only 3 users. 1371 $result = core_enrol_external::search_users($course1->id, 'user 1', true, 0, 1); 1372 $result = $result[0]; 1373 $this->assertEquals($user1->id, $result['id']); 1374 $this->assertEquals($user1->email, $result['email']); 1375 $this->assertEquals(fullname($user1), $result['fullname']); 1376 1377 $this->setUser($user1); 1378 1379 // Search for users in a course with enrolled users. 1380 $result = core_enrol_external::search_users($course1->id, 'user', true, 0, 30); 1381 $this->assertCount(4, $result); 1382 1383 $this->expectException('moodle_exception'); 1384 // Search for users in a course without any enrolled users, shouldn't return anything. 1385 $result = core_enrol_external::search_users($course2->id, 'user', true, 0, 30); 1386 $this->assertCount(0, $result); 1387 1388 // Search for invalid first name. 1389 $result = core_enrol_external::search_users($course1->id, 'yada yada', true, 0, 30); 1390 $this->assertCount(0, $result); 1391 } 1392 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body