Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]
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->assertEqualsCanonicalizing($canview, $viewed, "Problem checking visible users for '{$createdusers[$USER->id]}'"); 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 public function test_get_enrolled_users_without_capability() { 847 $capability = 'moodle/course:viewparticipants'; 848 $data = $this->get_enrolled_users_setup($capability); 849 850 // Call without required capability. 851 $this->unassignUserCapability($capability, $data->context->id, $data->roleid); 852 $this->expectException(moodle_exception::class); 853 $categories = core_enrol_external::get_enrolled_users($data->course->id); 854 } 855 856 public function get_enrolled_users_with_capability_setup($capability) { 857 global $USER, $DB; 858 859 $this->resetAfterTest(true); 860 861 $return = new stdClass(); 862 863 // Create the course and fetch its context. 864 $return->course = self::getDataGenerator()->create_course(); 865 $context = context_course::instance($return->course->id); 866 867 // Create one teacher, and two students. 868 $return->teacher = self::getDataGenerator()->create_user(); 869 $return->student1 = self::getDataGenerator()->create_user(); 870 $return->student2 = self::getDataGenerator()->create_user(); 871 872 // Create a new student role based on the student archetype but with the capability prohibitted. 873 $fakestudentroleid = create_role('Fake student role', 'fakestudent', 'Fake student role', 'student'); 874 assign_capability($capability, CAP_PROHIBIT, $fakestudentroleid, $context->id); 875 876 // Enrol all of the users in the course. 877 // * 'teacher' is an editing teacher. 878 // * 'student1' is a standard student. 879 // * 'student2' is a student with the capability prohibitted. 880 $editingteacherroleid = $DB->get_field('role', 'id', array('shortname' => 'editingteacher')); 881 $studentroleid = $DB->get_field('role', 'id', array('shortname' => 'student')); 882 $this->getDataGenerator()->enrol_user($return->teacher->id, $return->course->id, $editingteacherroleid); 883 $this->getDataGenerator()->enrol_user($return->student1->id, $return->course->id, $studentroleid); 884 $this->getDataGenerator()->enrol_user($return->student2->id, $return->course->id, $fakestudentroleid); 885 886 // Log in as the teacher. 887 $this->setUser($return->teacher); 888 889 // Clear caches. 890 accesslib_clear_all_caches_for_unit_testing(); 891 892 return $return; 893 } 894 895 /** 896 * Test get_enrolled_users_with_capability without additional paramaters. 897 */ 898 public function test_get_enrolled_users_with_capability_without_parameters() { 899 $capability = 'moodle/course:viewparticipants'; 900 $data = $this->get_enrolled_users_with_capability_setup($capability); 901 902 $result = core_enrol_external::get_enrolled_users_with_capability( 903 array( 904 'coursecapabilities' => array( 905 'courseid' => $data->course->id, 906 'capabilities' => array( 907 $capability, 908 ), 909 ), 910 ), 911 array() 912 ); 913 914 // We need to execute the return values cleaning process to simulate the web service server. 915 $result = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_with_capability_returns(), $result); 916 917 // Check an array containing the expected user for the course capability is returned. 918 $expecteduserlist = $result[0]; 919 $this->assertEquals($data->course->id, $expecteduserlist['courseid']); 920 $this->assertEquals($capability, $expecteduserlist['capability']); 921 $this->assertEquals(2, count($expecteduserlist['users'])); 922 } 923 924 /** 925 * Test get_enrolled_users_with_capability 926 */ 927 public function test_get_enrolled_users_with_capability_with_parameters () { 928 $capability = 'moodle/course:viewparticipants'; 929 $data = $this->get_enrolled_users_with_capability_setup($capability); 930 931 $result = core_enrol_external::get_enrolled_users_with_capability( 932 array( 933 'coursecapabilities' => array( 934 'courseid' => $data->course->id, 935 'capabilities' => array( 936 $capability, 937 ), 938 ), 939 ), 940 array( 941 array('name' => 'limitfrom', 'value' => 1), 942 array('name' => 'limitnumber', 'value' => 1), 943 array('name' => 'userfields', 'value' => 'id') 944 ) 945 ); 946 947 // We need to execute the return values cleaning process to simulate the web service server. 948 $result = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_with_capability_returns(), $result); 949 950 // Check an array containing the expected user for the course capability is returned. 951 $expecteduserlist = $result[0]['users']; 952 $expecteduser = reset($expecteduserlist); 953 $this->assertEquals(1, count($expecteduserlist)); 954 $this->assertEquals($data->student1->id, $expecteduser['id']); 955 } 956 957 /** 958 * Test get_enrolled_users last course access. 959 */ 960 public function test_get_enrolled_users_with_capability_including_lastcourseaccess() { 961 global $DB; 962 $capability = 'moodle/course:viewparticipants'; 963 $data = $this->get_enrolled_users_with_capability_setup($capability); 964 965 $parameters = array( 966 'coursecapabilities' => array( 967 'courseid' => $data->course->id, 968 'capabilities' => array( 969 $capability, 970 ), 971 ), 972 ); 973 974 $result = core_enrol_external::get_enrolled_users_with_capability($parameters, array()); 975 // We need to execute the return values cleaning process to simulate the web service server. 976 $result = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_with_capability_returns(), $result); 977 978 // Check an array containing the expected user for the course capability is returned. 979 $expecteduserlist = $result[0]; 980 $this->assertEquals($data->course->id, $expecteduserlist['courseid']); 981 $this->assertEquals($capability, $expecteduserlist['capability']); 982 $this->assertEquals(2, count($expecteduserlist['users'])); 983 // We forced an access to the course via setUser. 984 $this->assertNotEquals(0, $expecteduserlist['users'][0]['lastcourseaccess']); 985 $this->assertEquals(0, $expecteduserlist['users'][1]['lastcourseaccess']); 986 987 // Force last access. 988 $timenow = time(); 989 $lastaccess = array( 990 'userid' => $expecteduserlist['users'][1]['id'], 991 'courseid' => $data->course->id, 992 'timeaccess' => $timenow 993 ); 994 $DB->insert_record('user_lastaccess', $lastaccess); 995 996 $result = core_enrol_external::get_enrolled_users_with_capability($parameters, array()); 997 // We need to execute the return values cleaning process to simulate the web service server. 998 $result = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_with_capability_returns(), $result); 999 1000 // Check the result set. 1001 $expecteduserlist = $result[0]; 1002 $this->assertEquals(2, count($expecteduserlist['users'])); 1003 $this->assertNotEquals(0, $expecteduserlist['users'][0]['lastcourseaccess']); 1004 $this->assertEquals($timenow, $expecteduserlist['users'][1]['lastcourseaccess']); 1005 } 1006 1007 /** 1008 * Test for core_enrol_external::edit_user_enrolment(). 1009 */ 1010 public function test_edit_user_enrolment() { 1011 global $DB; 1012 1013 $this->resetAfterTest(true); 1014 $datagen = $this->getDataGenerator(); 1015 1016 /** @var enrol_manual_plugin $manualplugin */ 1017 $manualplugin = enrol_get_plugin('manual'); 1018 $this->assertNotNull($manualplugin); 1019 1020 $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST); 1021 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST); 1022 $course = $datagen->create_course(); 1023 $user = $datagen->create_user(); 1024 $teacher = $datagen->create_user(); 1025 1026 $instanceid = null; 1027 $instances = enrol_get_instances($course->id, true); 1028 foreach ($instances as $inst) { 1029 if ($inst->enrol == 'manual') { 1030 $instanceid = (int)$inst->id; 1031 break; 1032 } 1033 } 1034 if (empty($instanceid)) { 1035 $instanceid = $manualplugin->add_default_instance($course); 1036 if (empty($instanceid)) { 1037 $instanceid = $manualplugin->add_instance($course); 1038 } 1039 } 1040 $this->assertNotNull($instanceid); 1041 1042 $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST); 1043 $manualplugin->enrol_user($instance, $user->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1044 $manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE); 1045 $ueid = (int)$DB->get_field( 1046 'user_enrolments', 1047 'id', 1048 ['enrolid' => $instance->id, 'userid' => $user->id], 1049 MUST_EXIST 1050 ); 1051 1052 // Login as teacher. 1053 $this->setUser($teacher); 1054 1055 $now = new DateTime(); 1056 $nowtime = $now->getTimestamp(); 1057 1058 // Invalid data. 1059 $data = core_enrol_external::edit_user_enrolment($course->id, $ueid, ENROL_USER_ACTIVE, $nowtime, $nowtime); 1060 $data = external_api::clean_returnvalue(core_enrol_external::edit_user_enrolment_returns(), $data); 1061 $this->assertFalse($data['result']); 1062 $this->assertNotEmpty($data['errors']); 1063 1064 // Valid data. 1065 $nextmonth = clone($now); 1066 $nextmonth->add(new DateInterval('P1M')); 1067 $nextmonthtime = $nextmonth->getTimestamp(); 1068 $data = core_enrol_external::edit_user_enrolment($course->id, $ueid, ENROL_USER_ACTIVE, $nowtime, $nextmonthtime); 1069 $data = external_api::clean_returnvalue(core_enrol_external::edit_user_enrolment_returns(), $data); 1070 $this->assertTrue($data['result']); 1071 $this->assertEmpty($data['errors']); 1072 1073 // Check updated user enrolment. 1074 $ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST); 1075 $this->assertEquals(ENROL_USER_ACTIVE, $ue->status); 1076 $this->assertEquals($nowtime, $ue->timestart); 1077 $this->assertEquals($nextmonthtime, $ue->timeend); 1078 1079 // Suspend user. 1080 $data = core_enrol_external::edit_user_enrolment($course->id, $ueid, ENROL_USER_SUSPENDED); 1081 $data = external_api::clean_returnvalue(core_enrol_external::edit_user_enrolment_returns(), $data); 1082 $this->assertTrue($data['result']); 1083 $this->assertEmpty($data['errors']); 1084 1085 // Check updated user enrolment. 1086 $ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST); 1087 $this->assertEquals(ENROL_USER_SUSPENDED, $ue->status); 1088 } 1089 1090 /** 1091 * dataProvider for test_submit_user_enrolment_form(). 1092 */ 1093 public function submit_user_enrolment_form_provider() { 1094 $now = new DateTime(); 1095 1096 $nextmonth = clone($now); 1097 $nextmonth->add(new DateInterval('P1M')); 1098 1099 return [ 1100 'Invalid data' => [ 1101 'customdata' => [ 1102 'status' => ENROL_USER_ACTIVE, 1103 'timestart' => [ 1104 'day' => $now->format('j'), 1105 'month' => $now->format('n'), 1106 'year' => $now->format('Y'), 1107 'hour' => $now->format('G'), 1108 'minute' => 0, 1109 'enabled' => 1, 1110 ], 1111 'timeend' => [ 1112 'day' => $now->format('j'), 1113 'month' => $now->format('n'), 1114 'year' => $now->format('Y'), 1115 'hour' => $now->format('G'), 1116 'minute' => 0, 1117 'enabled' => 1, 1118 ], 1119 ], 1120 'expectedresult' => false, 1121 'validationerror' => true, 1122 ], 1123 'Valid data' => [ 1124 'customdata' => [ 1125 'status' => ENROL_USER_ACTIVE, 1126 'timestart' => [ 1127 'day' => $now->format('j'), 1128 'month' => $now->format('n'), 1129 'year' => $now->format('Y'), 1130 'hour' => $now->format('G'), 1131 'minute' => 0, 1132 'enabled' => 1, 1133 ], 1134 'timeend' => [ 1135 'day' => $nextmonth->format('j'), 1136 'month' => $nextmonth->format('n'), 1137 'year' => $nextmonth->format('Y'), 1138 'hour' => $nextmonth->format('G'), 1139 'minute' => 0, 1140 'enabled' => 1, 1141 ], 1142 ], 1143 'expectedresult' => true, 1144 'validationerror' => false 1145 ], 1146 'Suspend user' => [ 1147 'customdata' => [ 1148 'status' => ENROL_USER_SUSPENDED, 1149 ], 1150 'expectedresult' => true, 1151 'validationerror' => false 1152 ], 1153 ]; 1154 } 1155 1156 /** 1157 * @param array $customdata The data we are providing to the webservice. 1158 * @param bool $expectedresult The result we are expecting to receive from the webservice. 1159 * @param bool $validationerror The validationerror we are expecting to receive from the webservice. 1160 * @dataProvider submit_user_enrolment_form_provider 1161 */ 1162 public function test_submit_user_enrolment_form($customdata, $expectedresult, $validationerror) { 1163 global $CFG, $DB; 1164 1165 $this->resetAfterTest(true); 1166 $datagen = $this->getDataGenerator(); 1167 1168 /** @var enrol_manual_plugin $manualplugin */ 1169 $manualplugin = enrol_get_plugin('manual'); 1170 1171 $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST); 1172 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST); 1173 $course = $datagen->create_course(); 1174 $user = $datagen->create_user(); 1175 $teacher = $datagen->create_user(); 1176 1177 $instanceid = null; 1178 $instances = enrol_get_instances($course->id, true); 1179 foreach ($instances as $inst) { 1180 if ($inst->enrol == 'manual') { 1181 $instanceid = (int)$inst->id; 1182 break; 1183 } 1184 } 1185 if (empty($instanceid)) { 1186 $instanceid = $manualplugin->add_default_instance($course); 1187 if (empty($instanceid)) { 1188 $instanceid = $manualplugin->add_instance($course); 1189 } 1190 } 1191 $this->assertNotNull($instanceid); 1192 1193 $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST); 1194 $manualplugin->enrol_user($instance, $user->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1195 $manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE); 1196 $ueid = (int) $DB->get_field( 1197 'user_enrolments', 1198 'id', 1199 ['enrolid' => $instance->id, 'userid' => $user->id], 1200 MUST_EXIST 1201 ); 1202 1203 // Login as teacher. 1204 $teacher->ignoresesskey = true; 1205 $this->setUser($teacher); 1206 1207 $formdata = [ 1208 'ue' => $ueid, 1209 'ifilter' => 0, 1210 'status' => null, 1211 'timestart' => null, 1212 'duration' => null, 1213 'timeend' => null, 1214 ]; 1215 1216 $formdata = array_merge($formdata, $customdata); 1217 1218 require_once("$CFG->dirroot/enrol/editenrolment_form.php"); 1219 $formdata = enrol_user_enrolment_form::mock_generate_submit_keys($formdata); 1220 1221 $querystring = http_build_query($formdata, '', '&'); 1222 1223 $result = external_api::clean_returnvalue( 1224 core_enrol_external::submit_user_enrolment_form_returns(), 1225 core_enrol_external::submit_user_enrolment_form($querystring) 1226 ); 1227 1228 $this->assertEqualsCanonicalizing( 1229 ['result' => $expectedresult, 'validationerror' => $validationerror], 1230 $result); 1231 1232 if ($result['result']) { 1233 $ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST); 1234 $this->assertEquals($formdata['status'], $ue->status); 1235 } 1236 } 1237 1238 /** 1239 * Test for core_enrol_external::unenrol_user_enrolment(). 1240 */ 1241 public function test_unenerol_user_enrolment() { 1242 global $DB; 1243 1244 $this->resetAfterTest(true); 1245 $datagen = $this->getDataGenerator(); 1246 1247 /** @var enrol_manual_plugin $manualplugin */ 1248 $manualplugin = enrol_get_plugin('manual'); 1249 $this->assertNotNull($manualplugin); 1250 1251 $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST); 1252 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST); 1253 $course = $datagen->create_course(); 1254 $user = $datagen->create_user(); 1255 $teacher = $datagen->create_user(); 1256 1257 $instanceid = null; 1258 $instances = enrol_get_instances($course->id, true); 1259 foreach ($instances as $inst) { 1260 if ($inst->enrol == 'manual') { 1261 $instanceid = (int)$inst->id; 1262 break; 1263 } 1264 } 1265 if (empty($instanceid)) { 1266 $instanceid = $manualplugin->add_default_instance($course); 1267 if (empty($instanceid)) { 1268 $instanceid = $manualplugin->add_instance($course); 1269 } 1270 } 1271 $this->assertNotNull($instanceid); 1272 1273 $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST); 1274 $manualplugin->enrol_user($instance, $user->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1275 $manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE); 1276 $ueid = (int)$DB->get_field( 1277 'user_enrolments', 1278 'id', 1279 ['enrolid' => $instance->id, 'userid' => $user->id], 1280 MUST_EXIST 1281 ); 1282 1283 // Login as teacher. 1284 $this->setUser($teacher); 1285 1286 // Invalid data by passing invalid ueid. 1287 $data = core_enrol_external::unenrol_user_enrolment(101010); 1288 $data = external_api::clean_returnvalue(core_enrol_external::unenrol_user_enrolment_returns(), $data); 1289 $this->assertFalse($data['result']); 1290 $this->assertNotEmpty($data['errors']); 1291 1292 // Valid data. 1293 $data = core_enrol_external::unenrol_user_enrolment($ueid); 1294 $data = external_api::clean_returnvalue(core_enrol_external::unenrol_user_enrolment_returns(), $data); 1295 $this->assertTrue($data['result']); 1296 $this->assertEmpty($data['errors']); 1297 1298 // Check unenrol user enrolment. 1299 $ue = $DB->count_records('user_enrolments', ['id' => $ueid]); 1300 $this->assertEquals(0, $ue); 1301 } 1302 1303 /** 1304 * Test for core_enrol_external::test_search_users(). 1305 */ 1306 public function test_search_users() { 1307 global $DB; 1308 1309 $this->resetAfterTest(true); 1310 $datagen = $this->getDataGenerator(); 1311 1312 /** @var enrol_manual_plugin $manualplugin */ 1313 $manualplugin = enrol_get_plugin('manual'); 1314 $this->assertNotNull($manualplugin); 1315 1316 $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST); 1317 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST); 1318 1319 $course1 = $datagen->create_course(); 1320 $course2 = $datagen->create_course(); 1321 1322 $user1 = $datagen->create_user(['firstname' => 'user 1']); 1323 $user2 = $datagen->create_user(['firstname' => 'user 2']); 1324 $user3 = $datagen->create_user(['firstname' => 'user 3']); 1325 $teacher = $datagen->create_user(['firstname' => 'user 4']); 1326 1327 $instanceid = null; 1328 $instances = enrol_get_instances($course1->id, true); 1329 foreach ($instances as $inst) { 1330 if ($inst->enrol == 'manual') { 1331 $instanceid = (int)$inst->id; 1332 break; 1333 } 1334 } 1335 if (empty($instanceid)) { 1336 $instanceid = $manualplugin->add_default_instance($course1); 1337 if (empty($instanceid)) { 1338 $instanceid = $manualplugin->add_instance($course1); 1339 } 1340 } 1341 $this->assertNotNull($instanceid); 1342 1343 $instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST); 1344 $manualplugin->enrol_user($instance, $user1->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1345 $manualplugin->enrol_user($instance, $user2->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1346 $manualplugin->enrol_user($instance, $user3->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE); 1347 $manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE); 1348 1349 $this->setUser($teacher); 1350 1351 // Search for users in a course with enrolled users. 1352 $result = core_enrol_external::search_users($course1->id, 'user', true, 0, 30); 1353 $this->assertCount(4, $result); 1354 1355 $this->expectException('moodle_exception'); 1356 // Search for users in a course without any enrolled users, shouldn't return anything. 1357 $result = core_enrol_external::search_users($course2->id, 'user', true, 0, 30); 1358 $this->assertCount(0, $result); 1359 1360 // Search for invalid first name. 1361 $result = core_enrol_external::search_users($course1->id, 'yada yada', true, 0, 30); 1362 $this->assertCount(0, $result); 1363 1364 // Test pagination, it should return only 3 users. 1365 $result = core_enrol_external::search_users($course1->id, 'user', true, 0, 3); 1366 $this->assertCount(3, $result); 1367 1368 // Test pagination, it should return only 3 users. 1369 $result = core_enrol_external::search_users($course1->id, 'user 1', true, 0, 1); 1370 $result = $result[0]; 1371 $this->assertEquals($user1->id, $result['id']); 1372 $this->assertEquals($user1->email, $result['email']); 1373 $this->assertEquals(fullname($user1), $result['fullname']); 1374 1375 $this->setUser($user1); 1376 1377 // Search for users in a course with enrolled users. 1378 $result = core_enrol_external::search_users($course1->id, 'user', true, 0, 30); 1379 $this->assertCount(4, $result); 1380 1381 $this->expectException('moodle_exception'); 1382 // Search for users in a course without any enrolled users, shouldn't return anything. 1383 $result = core_enrol_external::search_users($course2->id, 'user', true, 0, 30); 1384 $this->assertCount(0, $result); 1385 1386 // Search for invalid first name. 1387 $result = core_enrol_external::search_users($course1->id, 'yada yada', true, 0, 30); 1388 $this->assertCount(0, $result); 1389 } 1390 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body