Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Full functional accesslib test. 19 * 20 * @package core 21 * @category phpunit 22 * @copyright 2011 Petr Skoda {@link http://skodak.org} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 /** 29 * Functional test for accesslib.php 30 * 31 * Note: execution may take many minutes especially on slower servers. 32 */ 33 class accesslib_test extends advanced_testcase { 34 /** 35 * Verify comparison of context instances in phpunit asserts. 36 */ 37 public function test_context_comparisons() { 38 $frontpagecontext1 = context_course::instance(SITEID); 39 context_helper::reset_caches(); 40 $frontpagecontext2 = context_course::instance(SITEID); 41 $this->assertEquals($frontpagecontext1, $frontpagecontext2); 42 43 $user1 = context_user::instance(1); 44 $user2 = context_user::instance(2); 45 $this->assertNotEquals($user1, $user2); 46 } 47 48 /** 49 * Test resetting works. 50 * 51 * @covers ::accesslib_clear_all_caches_for_unit_testing 52 */ 53 public function test_accesslib_clear_all_caches() { 54 global $ACCESSLIB_PRIVATE; 55 56 $this->resetAfterTest(); 57 58 $this->setAdminUser(); 59 load_all_capabilities(); 60 61 $this->assertNotEmpty($ACCESSLIB_PRIVATE->accessdatabyuser); 62 accesslib_clear_all_caches_for_unit_testing(); 63 $this->assertEmpty($ACCESSLIB_PRIVATE->dirtycontexts); 64 $this->assertEmpty($ACCESSLIB_PRIVATE->accessdatabyuser); 65 } 66 67 /** 68 * Check modifying capability record is not exposed to other code. 69 */ 70 public function test_capabilities_mutation() { 71 $oldcap = get_capability_info('moodle/site:config'); 72 $cap = get_capability_info('moodle/site:config'); 73 unset($cap->name); 74 $newcap = get_capability_info('moodle/site:config'); 75 76 $this->assertFalse(isset($cap->name)); 77 $this->assertTrue(isset($newcap->name)); 78 $this->assertTrue(isset($oldcap->name)); 79 } 80 81 /** 82 * Test getting of role access 83 * 84 * @covers ::get_role_access 85 */ 86 public function test_get_role_access() { 87 global $DB; 88 89 $roles = $DB->get_records('role'); 90 foreach ($roles as $role) { 91 $access = get_role_access($role->id); 92 93 $this->assertTrue(is_array($access)); 94 $this->assertTrue(is_array($access['ra'])); 95 $this->assertFalse(isset($access['rdef'])); 96 $this->assertFalse(isset($access['rdef_count'])); 97 $this->assertFalse(isset($access['loaded'])); 98 $this->assertTrue(isset($access['time'])); 99 $this->assertTrue(is_array($access['rsw'])); 100 } 101 102 // Note: the data is validated in the functional permission evaluation test at the end of this testcase. 103 } 104 105 /** 106 * Test getting of guest role. 107 * 108 * @covers ::get_guest_role 109 */ 110 public function test_get_guest_role() { 111 global $CFG; 112 113 $guest = get_guest_role(); 114 $this->assertEquals('guest', $guest->archetype); 115 $this->assertEquals('guest', $guest->shortname); 116 117 $this->assertEquals($CFG->guestroleid, $guest->id); 118 } 119 120 /** 121 * Test if user is admin. 122 * 123 * @covers ::is_siteadmin 124 */ 125 public function test_is_siteadmin() { 126 global $DB, $CFG; 127 128 $this->resetAfterTest(); 129 130 $users = $DB->get_records('user'); 131 132 foreach ($users as $user) { 133 $this->setUser(0); 134 if ($user->username === 'admin') { 135 $this->assertTrue(is_siteadmin($user)); 136 $this->assertTrue(is_siteadmin($user->id)); 137 $this->setUser($user); 138 $this->assertTrue(is_siteadmin()); 139 $this->assertTrue(is_siteadmin(null)); 140 } else { 141 $this->assertFalse(is_siteadmin($user)); 142 $this->assertFalse(is_siteadmin($user->id)); 143 $this->setUser($user); 144 $this->assertFalse(is_siteadmin()); 145 $this->assertFalse(is_siteadmin(null)); 146 } 147 } 148 149 // Change the site admin list and check that it still works with 150 // multiple admins. We do this with userids only (not real user 151 // accounts) because it makes the test simpler. 152 $before = $CFG->siteadmins; 153 set_config('siteadmins', '666,667,668'); 154 $this->assertTrue(is_siteadmin(666)); 155 $this->assertTrue(is_siteadmin(667)); 156 $this->assertTrue(is_siteadmin(668)); 157 $this->assertFalse(is_siteadmin(669)); 158 set_config('siteadmins', '13'); 159 $this->assertTrue(is_siteadmin(13)); 160 $this->assertFalse(is_siteadmin(666)); 161 set_config('siteadmins', $before); 162 } 163 164 /** 165 * Test if user is enrolled in a course 166 * 167 * @covers ::is_enrolled 168 */ 169 public function test_is_enrolled() { 170 global $DB; 171 172 $this->resetAfterTest(); 173 174 // Generate data. 175 $user = $this->getDataGenerator()->create_user(); 176 $course = $this->getDataGenerator()->create_course(); 177 $coursecontext = context_course::instance($course->id); 178 $role = $DB->get_record('role', array('shortname'=>'student')); 179 180 // There should be a manual enrolment as part of the default install. 181 $plugin = enrol_get_plugin('manual'); 182 $instance = $DB->get_record('enrol', array( 183 'courseid' => $course->id, 184 'enrol' => 'manual', 185 )); 186 $this->assertNotSame(false, $instance); 187 188 // Enrol the user in the course. 189 $plugin->enrol_user($instance, $user->id, $role->id); 190 191 // We'll test with the mod/assign:submit capability. 192 $capability= 'mod/assign:submit'; 193 $this->assertTrue($DB->record_exists('capabilities', array('name' => $capability))); 194 195 // Switch to our user. 196 $this->setUser($user); 197 198 // Ensure that the user has the capability first. 199 $this->assertTrue(has_capability($capability, $coursecontext, $user->id)); 200 201 // We first test whether the user is enrolled on the course as this 202 // seeds the cache, then we test for the capability. 203 $this->assertTrue(is_enrolled($coursecontext, $user, '', true)); 204 $this->assertTrue(is_enrolled($coursecontext, $user, $capability)); 205 206 // Prevent the capability for this user role. 207 assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext); 208 $this->assertFalse(has_capability($capability, $coursecontext, $user->id)); 209 210 // Again, we seed the cache first by checking initial enrolment, 211 // and then we test the actual capability. 212 $this->assertTrue(is_enrolled($coursecontext, $user, '', true)); 213 $this->assertFalse(is_enrolled($coursecontext, $user, $capability)); 214 } 215 216 /** 217 * Test logged in test. 218 * 219 * @covers ::isloggedin 220 */ 221 public function test_isloggedin() { 222 global $USER; 223 224 $this->resetAfterTest(); 225 226 $USER->id = 0; 227 $this->assertFalse(isloggedin()); 228 $USER->id = 1; 229 $this->assertTrue(isloggedin()); 230 } 231 232 /** 233 * Test guest user test. 234 * 235 * @covers ::isguestuser 236 */ 237 public function test_isguestuser() { 238 global $DB; 239 240 $this->resetAfterTest(); 241 242 $guest = $DB->get_record('user', array('username'=>'guest')); 243 $this->setUser(0); 244 $this->assertFalse(isguestuser()); 245 $this->setAdminUser(); 246 $this->assertFalse(isguestuser()); 247 $this->assertTrue(isguestuser($guest)); 248 $this->assertTrue(isguestuser($guest->id)); 249 $this->setUser($guest); 250 $this->assertTrue(isguestuser()); 251 252 $users = $DB->get_records('user'); 253 foreach ($users as $user) { 254 if ($user->username === 'guest') { 255 continue; 256 } 257 $this->assertFalse(isguestuser($user)); 258 } 259 } 260 261 /** 262 * Test capability riskiness. 263 * 264 * @covers ::is_safe_capability 265 */ 266 public function test_is_safe_capability() { 267 global $DB; 268 // Note: there is not much to test, just make sure no notices are throw for the most dangerous cap. 269 $capability = $DB->get_record('capabilities', array('name'=>'moodle/site:config'), '*', MUST_EXIST); 270 $this->assertFalse(is_safe_capability($capability)); 271 } 272 273 /** 274 * Test context fetching. 275 * 276 * @covers ::get_context_info_array 277 */ 278 public function test_get_context_info_array() { 279 $this->resetAfterTest(); 280 281 $syscontext = context_system::instance(); 282 $user = $this->getDataGenerator()->create_user(); 283 $usercontext = context_user::instance($user->id); 284 $course = $this->getDataGenerator()->create_course(); 285 $catcontext = context_coursecat::instance($course->category); 286 $coursecontext = context_course::instance($course->id); 287 $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id)); 288 $modcontext = context_module::instance($page->cmid); 289 $cm = get_coursemodule_from_instance('page', $page->id); 290 $block1 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$coursecontext->id)); 291 $block1context = context_block::instance($block1->id); 292 $block2 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$modcontext->id)); 293 $block2context = context_block::instance($block2->id); 294 295 $result = get_context_info_array($syscontext->id); 296 $this->assertCount(3, $result); 297 $this->assertEquals($syscontext, $result[0]); 298 $this->assertNull($result[1]); 299 $this->assertNull($result[2]); 300 301 $result = get_context_info_array($usercontext->id); 302 $this->assertCount(3, $result); 303 $this->assertEquals($usercontext, $result[0]); 304 $this->assertNull($result[1]); 305 $this->assertNull($result[2]); 306 307 $result = get_context_info_array($catcontext->id); 308 $this->assertCount(3, $result); 309 $this->assertEquals($catcontext, $result[0]); 310 $this->assertNull($result[1]); 311 $this->assertNull($result[2]); 312 313 $result = get_context_info_array($coursecontext->id); 314 $this->assertCount(3, $result); 315 $this->assertEquals($coursecontext, $result[0]); 316 $this->assertEquals($course->id, $result[1]->id); 317 $this->assertSame($course->shortname, $result[1]->shortname); 318 $this->assertNull($result[2]); 319 320 $result = get_context_info_array($block1context->id); 321 $this->assertCount(3, $result); 322 $this->assertEquals($block1context, $result[0]); 323 $this->assertEquals($course->id, $result[1]->id); 324 $this->assertEquals($course->shortname, $result[1]->shortname); 325 $this->assertNull($result[2]); 326 327 $result = get_context_info_array($modcontext->id); 328 $this->assertCount(3, $result); 329 $this->assertEquals($modcontext, $result[0]); 330 $this->assertEquals($course->id, $result[1]->id); 331 $this->assertSame($course->shortname, $result[1]->shortname); 332 $this->assertEquals($cm->id, $result[2]->id); 333 334 $result = get_context_info_array($block2context->id); 335 $this->assertCount(3, $result); 336 $this->assertEquals($block2context, $result[0]); 337 $this->assertEquals($course->id, $result[1]->id); 338 $this->assertSame($course->shortname, $result[1]->shortname); 339 $this->assertEquals($cm->id, $result[2]->id); 340 } 341 342 /** 343 * Test looking for course contacts. 344 * 345 * @covers ::has_coursecontact_role 346 */ 347 public function test_has_coursecontact_role() { 348 global $DB, $CFG; 349 350 $this->resetAfterTest(); 351 352 $users = $DB->get_records('user'); 353 354 // Nobody is expected to have any course level roles. 355 $this->assertNotEmpty($CFG->coursecontact); 356 foreach ($users as $user) { 357 $this->assertFalse(has_coursecontact_role($user->id)); 358 } 359 360 $user = $this->getDataGenerator()->create_user(); 361 $course = $this->getDataGenerator()->create_course(); 362 $contactroles = preg_split('/,/', $CFG->coursecontact); 363 $roleid = reset($contactroles); 364 role_assign($roleid, $user->id, context_course::instance($course->id)); 365 $this->assertTrue(has_coursecontact_role($user->id)); 366 } 367 368 /** 369 * Test creation of roles. 370 * 371 * @covers ::create_role 372 */ 373 public function test_create_role() { 374 global $DB; 375 376 $this->resetAfterTest(); 377 378 // Create role and get event. 379 $sink = $this->redirectEvents(); 380 $id = create_role('New student role', 'student2', 'New student description', 'student'); 381 $events = $sink->get_events(); 382 $sink->close(); 383 $event = array_pop($events); 384 $role = $DB->get_record('role', ['id' => $id]); 385 386 $this->assertNotEmpty($role); 387 $this->assertSame('New student role', $role->name); 388 $this->assertSame('student2', $role->shortname); 389 $this->assertSame('New student description', $role->description); 390 $this->assertSame('student', $role->archetype); 391 392 // Test triggered event. 393 $this->assertInstanceOf('\core\event\role_created', $event); 394 $this->assertSame('role', $event->target); 395 $this->assertSame('role', $event->objecttable); 396 $this->assertSame((int)$role->id, $event->objectid); 397 $this->assertEquals(context_system::instance(), $event->get_context()); 398 $this->assertSame($role->shortname, $event->other['shortname']); 399 $this->assertSame($role->archetype, $event->other['archetype']); 400 } 401 402 /** 403 * Test adding of capabilities to roles. 404 * 405 * @covers ::assign_capability 406 */ 407 public function test_assign_capability() { 408 global $DB, $USER; 409 410 $this->resetAfterTest(); 411 412 $user = $this->getDataGenerator()->create_user(); 413 $syscontext = context_system::instance(); 414 $frontcontext = context_course::instance(SITEID); 415 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 416 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to student by default. 417 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'))); 418 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'))); 419 420 $this->setUser($user); 421 $result = assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $frontcontext->id); 422 $this->assertTrue($result); 423 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')); 424 $this->assertNotEmpty($permission); 425 $this->assertEquals(CAP_ALLOW, $permission->permission); 426 $this->assertEquals($user->id, $permission->modifierid); 427 428 $this->setUser(0); 429 $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, false); 430 $this->assertTrue($result); 431 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')); 432 $this->assertNotEmpty($permission); 433 $this->assertEquals(CAP_ALLOW, $permission->permission); 434 $this->assertEquals($user->id, $permission->modifierid); 435 436 $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, true); 437 $this->assertTrue($result); 438 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')); 439 $this->assertNotEmpty($permission); 440 $this->assertEquals(CAP_PROHIBIT, $permission->permission); 441 $this->assertEquals(0, $permission->modifierid); 442 443 $result = assign_capability('moodle/backup:backupcourse', CAP_INHERIT, $student->id, $frontcontext->id); 444 $this->assertTrue($result); 445 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')); 446 $this->assertEmpty($permission); 447 448 // Test event triggered. 449 $sink = $this->redirectEvents(); 450 $capability = 'moodle/backup:backupcourse'; 451 assign_capability($capability, CAP_ALLOW, $student->id, $syscontext); 452 $events = $sink->get_events(); 453 $sink->close(); 454 $this->assertCount(1, $events); 455 $event = $events[0]; 456 $this->assertInstanceOf('\core\event\capability_assigned', $event); 457 $this->assertSame('role_capabilities', $event->objecttable); 458 $this->assertEquals($student->id, $event->objectid); 459 $this->assertEquals($syscontext->id, $event->contextid); 460 $other = ['capability' => $capability, 'oldpermission' => CAP_INHERIT, 'permission' => CAP_ALLOW]; 461 $this->assertEquals($other, $event->other); 462 $description = "The user id '$USER->id' assigned the '$capability' capability for " . 463 "role '$student->id' with 'Allow' permission"; 464 $this->assertEquals($description, $event->get_description()); 465 466 // Test if the event has different description when updating the capability permission. 467 $sink = $this->redirectEvents(); 468 assign_capability($capability, CAP_PROHIBIT, $student->id, $syscontext, true); 469 $events = $sink->get_events(); 470 $sink->close(); 471 $event = $events[0]; 472 $description = "The user id '$USER->id' changed the '$capability' capability permission for " . 473 "role '$student->id' from 'Allow' to 'Prohibit'"; 474 $this->assertEquals($description, $event->get_description()); 475 } 476 477 /** 478 * Test removing of capabilities from roles. 479 * 480 * @covers ::unassign_capability 481 */ 482 public function test_unassign_capability() { 483 global $DB, $USER; 484 485 $this->resetAfterTest(); 486 487 $syscontext = context_system::instance(); 488 $frontcontext = context_course::instance(SITEID); 489 $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST); 490 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to manager by default. 491 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id); 492 493 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 494 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 495 496 $result = unassign_capability('moodle/backup:backupcourse', $manager->id, $syscontext->id); 497 $this->assertTrue($result); 498 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 499 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 500 unassign_capability('moodle/backup:backupcourse', $manager->id, $frontcontext); 501 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 502 503 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id); 504 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id); 505 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 506 507 $result = unassign_capability('moodle/backup:backupcourse', $manager->id); 508 $this->assertTrue($result); 509 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 510 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 511 512 // Test event triggered. 513 $sink = $this->redirectEvents(); 514 $capability = 'moodle/backup:backupcourse'; 515 unassign_capability($capability, CAP_ALLOW, $manager->id); 516 $events = $sink->get_events(); 517 $sink->close(); 518 $this->assertCount(1, $events); 519 $event = $events[0]; 520 $this->assertInstanceOf('\core\event\capability_unassigned', $event); 521 $this->assertSame('role_capabilities', $event->objecttable); 522 $this->assertEquals($manager->id, $event->objectid); 523 $this->assertEquals($syscontext->id, $event->contextid); 524 $this->assertEquals($capability, $event->other['capability']); 525 $description = "The user id id '$USER->id' has unassigned the '$capability' capability for role '$manager->id'"; 526 $this->assertEquals($description, $event->get_description()); 527 } 528 529 /** 530 * Test role assigning. 531 * 532 * @covers ::role_assign 533 */ 534 public function test_role_assign() { 535 global $DB, $USER; 536 537 $this->resetAfterTest(); 538 539 $user = $this->getDataGenerator()->create_user(); 540 $course = $this->getDataGenerator()->create_course(); 541 $role = $DB->get_record('role', array('shortname'=>'student')); 542 543 $this->setUser(0); 544 $context = context_system::instance(); 545 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 546 role_assign($role->id, $user->id, $context->id); 547 $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)); 548 $this->assertNotEmpty($ras); 549 $this->assertSame('', $ras->component); 550 $this->assertSame('0', $ras->itemid); 551 $this->assertEquals($USER->id, $ras->modifierid); 552 553 $this->setAdminUser(); 554 $context = context_course::instance($course->id); 555 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 556 role_assign($role->id, $user->id, $context->id, 'enrol_self', 1, 666); 557 $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)); 558 $this->assertNotEmpty($ras); 559 $this->assertSame('enrol_self', $ras->component); 560 $this->assertSame('1', $ras->itemid); 561 $this->assertEquals($USER->id, $ras->modifierid); 562 $this->assertEquals(666, $ras->timemodified); 563 564 // Test event triggered. 565 566 $user2 = $this->getDataGenerator()->create_user(); 567 $sink = $this->redirectEvents(); 568 $raid = role_assign($role->id, $user2->id, $context->id); 569 $events = $sink->get_events(); 570 $sink->close(); 571 $this->assertCount(1, $events); 572 $event = $events[0]; 573 $this->assertInstanceOf('\core\event\role_assigned', $event); 574 $this->assertSame('role', $event->target); 575 $this->assertSame('role', $event->objecttable); 576 $this->assertEquals($role->id, $event->objectid); 577 $this->assertEquals($context->id, $event->contextid); 578 $this->assertEquals($user2->id, $event->relateduserid); 579 $this->assertCount(3, $event->other); 580 $this->assertEquals($raid, $event->other['id']); 581 $this->assertSame('', $event->other['component']); 582 $this->assertEquals(0, $event->other['itemid']); 583 $this->assertInstanceOf('moodle_url', $event->get_url()); 584 } 585 586 /** 587 * Test role unassigning. 588 * 589 * @covers ::role_unassign 590 */ 591 public function test_role_unassign() { 592 global $DB, $USER; 593 594 $this->resetAfterTest(); 595 596 $user = $this->getDataGenerator()->create_user(); 597 $course = $this->getDataGenerator()->create_course(); 598 $role = $DB->get_record('role', array('shortname'=>'student')); 599 600 $context = context_course::instance($course->id); 601 role_assign($role->id, $user->id, $context->id); 602 $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 603 role_unassign($role->id, $user->id, $context->id); 604 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 605 606 role_assign($role->id, $user->id, $context->id, 'enrol_self', 1); 607 $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 608 role_unassign($role->id, $user->id, $context->id, 'enrol_self', 1); 609 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 610 611 // Test event triggered. 612 613 role_assign($role->id, $user->id, $context->id); 614 $sink = $this->redirectEvents(); 615 role_unassign($role->id, $user->id, $context->id); 616 $events = $sink->get_events(); 617 $sink->close(); 618 $this->assertCount(1, $events); 619 $event = $events[0]; 620 $this->assertInstanceOf('\core\event\role_unassigned', $event); 621 $this->assertSame('role', $event->target); 622 $this->assertSame('role', $event->objecttable); 623 $this->assertEquals($role->id, $event->objectid); 624 $this->assertEquals($context->id, $event->contextid); 625 $this->assertEquals($user->id, $event->relateduserid); 626 $this->assertCount(3, $event->other); 627 $this->assertSame('', $event->other['component']); 628 $this->assertEquals(0, $event->other['itemid']); 629 $this->assertInstanceOf('moodle_url', $event->get_url()); 630 } 631 632 /** 633 * Test role unassigning. 634 * 635 * @covers ::role_unassign_all 636 */ 637 public function test_role_unassign_all() { 638 global $DB; 639 640 $this->resetAfterTest(); 641 642 $user = $this->getDataGenerator()->create_user(); 643 $course = $this->getDataGenerator()->create_course(); 644 $role = $DB->get_record('role', array('shortname'=>'student')); 645 $role2 = $DB->get_record('role', array('shortname'=>'teacher')); 646 $syscontext = context_system::instance(); 647 $coursecontext = context_course::instance($course->id); 648 $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id)); 649 $modcontext = context_module::instance($page->cmid); 650 651 role_assign($role->id, $user->id, $syscontext->id); 652 role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1); 653 $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id))); 654 role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role->id)); 655 $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id))); 656 657 role_assign($role->id, $user->id, $syscontext->id); 658 role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1); 659 role_assign($role->id, $user->id, $modcontext->id); 660 $this->assertEquals(3, $DB->count_records('role_assignments', array('userid'=>$user->id))); 661 role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), false); 662 $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id))); 663 role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), true); 664 $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id))); 665 role_unassign_all(array('userid'=>$user->id)); 666 $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id))); 667 668 role_assign($role->id, $user->id, $syscontext->id); 669 role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1); 670 role_assign($role->id, $user->id, $coursecontext->id); 671 role_assign($role->id, $user->id, $modcontext->id); 672 $this->assertEquals(4, $DB->count_records('role_assignments', array('userid'=>$user->id))); 673 role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id, 'component'=>'enrol_self'), true, true); 674 $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id))); 675 676 // Test events triggered. 677 678 role_assign($role2->id, $user->id, $coursecontext->id); 679 role_assign($role2->id, $user->id, $modcontext->id); 680 $sink = $this->redirectEvents(); 681 role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role2->id)); 682 $events = $sink->get_events(); 683 $sink->close(); 684 $this->assertCount(2, $events); 685 $this->assertInstanceOf('\core\event\role_unassigned', $events[0]); 686 $this->assertInstanceOf('\core\event\role_unassigned', $events[1]); 687 } 688 689 /** 690 * Test role queries. 691 * 692 * @covers ::get_roles_with_capability 693 */ 694 public function test_get_roles_with_capability() { 695 global $DB; 696 697 $this->resetAfterTest(); 698 699 $syscontext = context_system::instance(); 700 $frontcontext = context_course::instance(SITEID); 701 $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST); 702 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST); 703 704 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok. 705 $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse')); 706 707 $roles = get_roles_with_capability('moodle/backup:backupcourse'); 708 $this->assertEquals(array(), $roles); 709 710 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id); 711 assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $manager->id, $frontcontext->id); 712 assign_capability('moodle/backup:backupcourse', CAP_PREVENT, $teacher->id, $frontcontext->id); 713 714 $roles = get_roles_with_capability('moodle/backup:backupcourse'); 715 $this->assertEqualsCanonicalizing(array($teacher->id, $manager->id), array_keys($roles), true); 716 717 $roles = get_roles_with_capability('moodle/backup:backupcourse', CAP_ALLOW); 718 $this->assertEqualsCanonicalizing(array($manager->id), array_keys($roles), true); 719 720 $roles = get_roles_with_capability('moodle/backup:backupcourse', null, $syscontext); 721 $this->assertEqualsCanonicalizing(array($manager->id), array_keys($roles), true); 722 } 723 724 /** 725 * Test deleting of roles. 726 * 727 * @covers ::delete_role 728 */ 729 public function test_delete_role() { 730 global $DB; 731 732 $this->resetAfterTest(); 733 734 $role = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST); 735 $user = $this->getDataGenerator()->create_user(); 736 role_assign($role->id, $user->id, context_system::instance()); 737 $course = $this->getDataGenerator()->create_course(); 738 $rolename = (object)array('roleid'=>$role->id, 'name'=>'Man', 'contextid'=>context_course::instance($course->id)->id); 739 $DB->insert_record('role_names', $rolename); 740 741 $this->assertTrue($DB->record_exists('role_assignments', array('roleid'=>$role->id))); 742 $this->assertTrue($DB->record_exists('role_capabilities', array('roleid'=>$role->id))); 743 $this->assertTrue($DB->record_exists('role_names', array('roleid'=>$role->id))); 744 $this->assertTrue($DB->record_exists('role_context_levels', array('roleid'=>$role->id))); 745 $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$role->id))); 746 $this->assertTrue($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id))); 747 $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$role->id))); 748 $this->assertTrue($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id))); 749 750 // Delete role and get event. 751 $sink = $this->redirectEvents(); 752 $result = delete_role($role->id); 753 $events = $sink->get_events(); 754 $sink->close(); 755 $event = array_pop($events); 756 757 $this->assertTrue($result); 758 $this->assertFalse($DB->record_exists('role', array('id'=>$role->id))); 759 $this->assertFalse($DB->record_exists('role_assignments', array('roleid'=>$role->id))); 760 $this->assertFalse($DB->record_exists('role_capabilities', array('roleid'=>$role->id))); 761 $this->assertFalse($DB->record_exists('role_names', array('roleid'=>$role->id))); 762 $this->assertFalse($DB->record_exists('role_context_levels', array('roleid'=>$role->id))); 763 $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$role->id))); 764 $this->assertFalse($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id))); 765 $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$role->id))); 766 $this->assertFalse($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id))); 767 768 // Test triggered event. 769 $this->assertInstanceOf('\core\event\role_deleted', $event); 770 $this->assertSame('role', $event->target); 771 $this->assertSame('role', $event->objecttable); 772 $this->assertSame($role->id, $event->objectid); 773 $this->assertEquals(context_system::instance(), $event->get_context()); 774 $this->assertSame($role->shortname, $event->other['shortname']); 775 $this->assertSame($role->description, $event->other['description']); 776 $this->assertSame($role->archetype, $event->other['archetype']); 777 } 778 779 /** 780 * Test fetching of all roles. 781 * 782 * @covers ::get_all_roles 783 */ 784 public function test_get_all_roles() { 785 global $DB; 786 787 $this->resetAfterTest(); 788 789 $allroles = get_all_roles(); 790 $this->assertIsArray($allroles); 791 $initialrolescount = count($allroles); 792 $this->assertTrue($initialrolescount >= 8); // There are 8 roles is standard install. 793 $rolenames = array_column($allroles, 'shortname'); 794 foreach (get_role_archetypes() as $archetype) { 795 $this->assertContains($archetype, $rolenames); 796 } 797 798 $role = reset($allroles); 799 $role = (array)$role; 800 801 $this->assertEqualsCanonicalizing(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype'), 802 array_keys($role)); 803 804 foreach ($allroles as $roleid => $role) { 805 $this->assertEquals($role->id, $roleid); 806 } 807 808 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST); 809 $course = $this->getDataGenerator()->create_course(); 810 $coursecontext = context_course::instance($course->id); 811 $otherid = create_role('Other role', 'other', 'Some other role', ''); 812 $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 813 $DB->insert_record('role_names', $teacherename); 814 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id); 815 $DB->insert_record('role_names', $otherrename); 816 $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name'); 817 818 $allroles = get_all_roles($coursecontext); 819 $this->assertIsArray($allroles); 820 $this->assertCount($initialrolescount + 1, $allroles); 821 $role = reset($allroles); 822 $role = (array)$role; 823 824 $this->assertEqualsCanonicalizing(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype', 'coursealias'), array_keys($role)); 825 826 foreach ($allroles as $roleid => $role) { 827 $this->assertEquals($role->id, $roleid); 828 if (isset($renames[$roleid])) { 829 $this->assertSame($renames[$roleid], $role->coursealias); 830 } else { 831 $this->assertNull($role->coursealias); 832 } 833 } 834 } 835 836 /** 837 * Test getting of all archetypes. 838 * 839 * @covers ::get_role_archetypes 840 */ 841 public function test_get_role_archetypes() { 842 $archetypes = get_role_archetypes(); 843 $this->assertCount(8, $archetypes); // There are 8 archetypes in standard install. 844 foreach ($archetypes as $k => $v) { 845 $this->assertSame($k, $v); 846 } 847 } 848 849 /** 850 * Test getting of roles with given archetype. 851 * 852 * @covers ::get_archetype_roles 853 */ 854 public function test_get_archetype_roles() { 855 $this->resetAfterTest(); 856 857 // New install should have at least 1 role for each archetype. 858 $archetypes = get_role_archetypes(); 859 foreach ($archetypes as $archetype) { 860 $roles = get_archetype_roles($archetype); 861 $this->assertGreaterThanOrEqual(1, count($roles)); 862 $role = reset($roles); 863 $this->assertSame($archetype, $role->archetype); 864 } 865 866 create_role('New student role', 'student2', 'New student description', 'student'); 867 $roles = get_archetype_roles('student'); 868 $this->assertGreaterThanOrEqual(2, count($roles)); 869 } 870 871 /** 872 * Test aliased role names. 873 * 874 * @covers ::role_get_name 875 */ 876 public function test_role_get_name() { 877 global $DB; 878 879 $this->resetAfterTest(); 880 881 $allroles = $DB->get_records('role'); 882 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST); 883 $course = $this->getDataGenerator()->create_course(); 884 $coursecontext = context_course::instance($course->id); 885 $otherid = create_role('Other role', 'other', 'Some other role', ''); 886 $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 887 $DB->insert_record('role_names', $teacherename); 888 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id); 889 $DB->insert_record('role_names', $otherrename); 890 $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name'); 891 892 foreach ($allroles as $role) { 893 if (in_array($role->shortname, get_role_archetypes())) { 894 // Standard roles do not have a set name. 895 $this->assertSame('', $role->name); 896 } 897 // Get localised name from lang pack. 898 $name = role_get_name($role, null, ROLENAME_ORIGINAL); 899 $this->assertNotEmpty($name); 900 $this->assertNotEquals($role->shortname, $name); 901 902 if (isset($renames[$role->id])) { 903 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext)); 904 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS)); 905 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW)); 906 $this->assertSame("{$renames[$role->id]} ($name)", role_get_name($role, $coursecontext, ROLENAME_BOTH)); 907 } else { 908 $this->assertSame($name, role_get_name($role, $coursecontext)); 909 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ALIAS)); 910 $this->assertNull(role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW)); 911 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_BOTH)); 912 } 913 $this->assertSame($name, role_get_name($role)); 914 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ORIGINAL)); 915 $this->assertSame($name, role_get_name($role, null, ROLENAME_ORIGINAL)); 916 $this->assertSame($role->shortname, role_get_name($role, $coursecontext, ROLENAME_SHORT)); 917 $this->assertSame($role->shortname, role_get_name($role, null, ROLENAME_SHORT)); 918 $this->assertSame("$name ($role->shortname)", role_get_name($role, $coursecontext, ROLENAME_ORIGINALANDSHORT)); 919 $this->assertSame("$name ($role->shortname)", role_get_name($role, null, ROLENAME_ORIGINALANDSHORT)); 920 $this->assertNull(role_get_name($role, null, ROLENAME_ALIAS_RAW)); 921 } 922 } 923 924 /** 925 * Test tweaking of role name arrays. 926 * 927 * @covers ::role_fix_names 928 */ 929 public function test_role_fix_names() { 930 global $DB; 931 932 $this->resetAfterTest(); 933 934 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST); 935 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 936 $otherid = create_role('Other role', 'other', 'Some other role', ''); 937 $anotherid = create_role('Another role', 'another', 'Yet another other role', ''); 938 $allroles = $DB->get_records('role'); 939 940 $syscontext = context_system::instance(); 941 $frontcontext = context_course::instance(SITEID); 942 $course = $this->getDataGenerator()->create_course(); 943 $coursecontext = context_course::instance($course->id); 944 $category = $DB->get_record('course_categories', array('id'=>$course->category), '*', MUST_EXIST); 945 $categorycontext = context_coursecat::instance($category->id); 946 947 $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 948 $DB->insert_record('role_names', $teacherename); 949 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id); 950 $DB->insert_record('role_names', $otherrename); 951 $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name'); 952 953 // Make sure all localname contain proper values for each ROLENAME_ constant, 954 // note role_get_name() on frontpage is used to get the original name for future compatibility. 955 $roles = $allroles; 956 unset($roles[$student->id]); // Remove one role to make sure no role is added or removed. 957 $rolenames = array(); 958 foreach ($roles as $role) { 959 $rolenames[$role->id] = $role->name; 960 } 961 962 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT); 963 foreach ($alltypes as $type) { 964 $fixed = role_fix_names($roles, $coursecontext, $type); 965 $this->assertCount(count($roles), $fixed); 966 foreach ($fixed as $roleid => $rolename) { 967 $this->assertInstanceOf('stdClass', $rolename); 968 $role = $allroles[$roleid]; 969 $name = role_get_name($role, $coursecontext, $type); 970 $this->assertSame($name, $rolename->localname); 971 } 972 $fixed = role_fix_names($rolenames, $coursecontext, $type); 973 $this->assertCount(count($rolenames), $fixed); 974 foreach ($fixed as $roleid => $rolename) { 975 $role = $allroles[$roleid]; 976 $name = role_get_name($role, $coursecontext, $type); 977 $this->assertSame($name, $rolename); 978 } 979 } 980 } 981 982 /** 983 * Test role default allows. 984 * 985 * @covers ::get_default_role_archetype_allows 986 */ 987 public function test_get_default_role_archetype_allows() { 988 $archetypes = get_role_archetypes(); 989 foreach ($archetypes as $archetype) { 990 991 $result = get_default_role_archetype_allows('assign', $archetype); 992 $this->assertIsArray($result); 993 994 $result = get_default_role_archetype_allows('override', $archetype); 995 $this->assertIsArray($result); 996 997 $result = get_default_role_archetype_allows('switch', $archetype); 998 $this->assertIsArray($result); 999 1000 $result = get_default_role_archetype_allows('view', $archetype); 1001 $this->assertIsArray($result); 1002 } 1003 1004 $result = get_default_role_archetype_allows('assign', ''); 1005 $this->assertSame(array(), $result); 1006 1007 $result = get_default_role_archetype_allows('override', ''); 1008 $this->assertSame(array(), $result); 1009 1010 $result = get_default_role_archetype_allows('switch', ''); 1011 $this->assertSame(array(), $result); 1012 1013 $result = get_default_role_archetype_allows('view', ''); 1014 $this->assertSame(array(), $result); 1015 1016 $result = get_default_role_archetype_allows('assign', 'wrongarchetype'); 1017 $this->assertSame(array(), $result); 1018 $this->assertDebuggingCalled(); 1019 1020 $result = get_default_role_archetype_allows('override', 'wrongarchetype'); 1021 $this->assertSame(array(), $result); 1022 $this->assertDebuggingCalled(); 1023 1024 $result = get_default_role_archetype_allows('switch', 'wrongarchetype'); 1025 $this->assertSame(array(), $result); 1026 $this->assertDebuggingCalled(); 1027 1028 $result = get_default_role_archetype_allows('view', 'wrongarchetype'); 1029 $this->assertSame(array(), $result); 1030 $this->assertDebuggingCalled(); 1031 } 1032 1033 /** 1034 * Test allowing of role assignments. 1035 * 1036 * @covers ::core_role_set_assign_allowed 1037 */ 1038 public function test_core_role_set_assign_allowed() { 1039 global $DB, $CFG; 1040 1041 $this->resetAfterTest(); 1042 1043 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1044 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1045 1046 $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id))); 1047 core_role_set_assign_allowed($otherid, $student->id); 1048 $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id))); 1049 1050 // Test event trigger. 1051 $allowroleassignevent = \core\event\role_allow_assign_updated::create([ 1052 'context' => context_system::instance(), 1053 'objectid' => $otherid, 1054 'other' => ['targetroleid' => $student->id] 1055 ]); 1056 $sink = $this->redirectEvents(); 1057 $allowroleassignevent->trigger(); 1058 $events = $sink->get_events(); 1059 $sink->close(); 1060 $event = array_pop($events); 1061 $this->assertInstanceOf('\core\event\role_allow_assign_updated', $event); 1062 } 1063 1064 /** 1065 * Test allowing of role overrides. 1066 * 1067 * @covers ::core_role_set_override_allowed 1068 */ 1069 public function test_core_role_set_override_allowed() { 1070 global $DB, $CFG; 1071 1072 $this->resetAfterTest(); 1073 1074 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1075 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1076 1077 $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id))); 1078 core_role_set_override_allowed($otherid, $student->id); 1079 $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id))); 1080 1081 // Test event trigger. 1082 $allowroleassignevent = \core\event\role_allow_override_updated::create([ 1083 'context' => context_system::instance(), 1084 'objectid' => $otherid, 1085 'other' => ['targetroleid' => $student->id] 1086 ]); 1087 $sink = $this->redirectEvents(); 1088 $allowroleassignevent->trigger(); 1089 $events = $sink->get_events(); 1090 $sink->close(); 1091 $event = array_pop($events); 1092 $this->assertInstanceOf('\core\event\role_allow_override_updated', $event); 1093 } 1094 1095 /** 1096 * Test allowing of role switching. 1097 * 1098 * @covers ::core_role_set_switch_allowed 1099 */ 1100 public function test_core_role_set_switch_allowed() { 1101 global $DB, $CFG; 1102 1103 $this->resetAfterTest(); 1104 1105 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1106 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1107 1108 $this->assertFalse($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id))); 1109 core_role_set_switch_allowed($otherid, $student->id); 1110 $this->assertTrue($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id))); 1111 1112 // Test event trigger. 1113 $allowroleassignevent = \core\event\role_allow_switch_updated::create([ 1114 'context' => context_system::instance(), 1115 'objectid' => $otherid, 1116 'other' => ['targetroleid' => $student->id] 1117 ]); 1118 $sink = $this->redirectEvents(); 1119 $allowroleassignevent->trigger(); 1120 $events = $sink->get_events(); 1121 $sink->close(); 1122 $event = array_pop($events); 1123 $this->assertInstanceOf('\core\event\role_allow_switch_updated', $event); 1124 } 1125 1126 /** 1127 * Test allowing of role switching. 1128 * 1129 * @covers ::core_role_set_view_allowed 1130 */ 1131 public function test_core_role_set_view_allowed() { 1132 global $DB, $CFG; 1133 1134 $this->resetAfterTest(); 1135 1136 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1137 $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 1138 1139 $this->assertFalse($DB->record_exists('role_allow_view', array('roleid' => $otherid, 'allowview' => $student->id))); 1140 core_role_set_view_allowed($otherid, $student->id); 1141 $this->assertTrue($DB->record_exists('role_allow_view', array('roleid' => $otherid, 'allowview' => $student->id))); 1142 1143 // Test event trigger. 1144 $allowroleassignevent = \core\event\role_allow_view_updated::create([ 1145 'context' => context_system::instance(), 1146 'objectid' => $otherid, 1147 'other' => ['targetroleid' => $student->id] 1148 ]); 1149 $sink = $this->redirectEvents(); 1150 $allowroleassignevent->trigger(); 1151 $events = $sink->get_events(); 1152 $sink->close(); 1153 $event = array_pop($events); 1154 $this->assertInstanceOf('\core\event\role_allow_view_updated', $event); 1155 } 1156 1157 /** 1158 * Test returning of assignable roles in context. 1159 * 1160 * @covers ::get_assignable_roles 1161 */ 1162 public function test_get_assignable_roles() { 1163 global $DB; 1164 1165 $this->resetAfterTest(); 1166 1167 $course = $this->getDataGenerator()->create_course(); 1168 $coursecontext = context_course::instance($course->id); 1169 1170 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1171 $teacher = $this->getDataGenerator()->create_user(); 1172 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1173 $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1174 $DB->insert_record('role_names', $teacherename); 1175 1176 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1177 $student = $this->getDataGenerator()->create_user(); 1178 role_assign($studentrole->id, $student->id, $coursecontext); 1179 1180 $contexts = $DB->get_records('context'); 1181 $users = $DB->get_records('user'); 1182 $allroles = $DB->get_records('role'); 1183 1184 // Evaluate all results for all users in all contexts. 1185 foreach ($users as $user) { 1186 $this->setUser($user); 1187 foreach ($contexts as $contextid => $unused) { 1188 $context = context_helper::instance_by_id($contextid); 1189 $roles = get_assignable_roles($context, ROLENAME_SHORT); 1190 foreach ($allroles as $roleid => $role) { 1191 if (isset($roles[$roleid])) { 1192 if (is_siteadmin()) { 1193 $this->assertTrue($DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid))); 1194 } else { 1195 $this->assertTrue(user_can_assign($context, $roleid), "u:$user->id r:$roleid"); 1196 } 1197 $this->assertEquals($role->shortname, $roles[$roleid]); 1198 } else { 1199 $allowed = $DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid)); 1200 if (is_siteadmin()) { 1201 $this->assertFalse($allowed); 1202 } else { 1203 $this->assertFalse($allowed and user_can_assign($context, $roleid), "u:$user->id, r:{$allroles[$roleid]->name}, c:$context->contextlevel"); 1204 } 1205 } 1206 } 1207 } 1208 } 1209 1210 // Not-logged-in user. 1211 $this->setUser(0); 1212 foreach ($contexts as $contextid => $unused) { 1213 $context = context_helper::instance_by_id($contextid); 1214 $roles = get_assignable_roles($context, ROLENAME_SHORT); 1215 $this->assertSame(array(), $roles); 1216 } 1217 1218 // Test current user. 1219 $this->setUser(0); 1220 $admin = $DB->get_record('user', array('username'=>'admin'), '*', MUST_EXIST); 1221 $roles1 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin); 1222 $roles2 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin->id); 1223 $this->setAdminUser(); 1224 $roles3 = get_assignable_roles($coursecontext, ROLENAME_SHORT); 1225 $this->assertSame($roles1, $roles3); 1226 $this->assertSame($roles2, $roles3); 1227 1228 // Test parameter defaults. 1229 $this->setAdminUser(); 1230 $roles1 = get_assignable_roles($coursecontext); 1231 $roles2 = get_assignable_roles($coursecontext, ROLENAME_ALIAS, false, $admin); 1232 $this->assertEquals($roles2, $roles1); 1233 1234 // Verify returned names - let's allow all roles everywhere to simplify this a bit. 1235 $alllevels = context_helper::get_all_levels(); 1236 $alllevels = array_keys($alllevels); 1237 foreach ($allroles as $roleid => $role) { 1238 set_role_contextlevels($roleid, $alllevels); 1239 } 1240 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT); 1241 foreach ($alltypes as $type) { 1242 $rolenames = role_fix_names($allroles, $coursecontext, $type); 1243 $roles = get_assignable_roles($coursecontext, $type, false, $admin); 1244 foreach ($roles as $roleid => $rolename) { 1245 $this->assertSame($rolenames[$roleid]->localname, $rolename); 1246 } 1247 } 1248 1249 // Verify counts. 1250 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT); 1251 foreach ($alltypes as $type) { 1252 $roles = get_assignable_roles($coursecontext, $type, false, $admin); 1253 list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($coursecontext, $type, true, $admin); 1254 $this->assertEquals($roles, $rolenames); 1255 foreach ($rolenames as $roleid => $name) { 1256 if ($roleid == $teacherrole->id or $roleid == $studentrole->id) { 1257 $this->assertEquals(1, $rolecounts[$roleid]); 1258 } else { 1259 $this->assertEquals(0, $rolecounts[$roleid]); 1260 } 1261 $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]); 1262 } 1263 } 1264 } 1265 1266 /** 1267 * Test user count of assignable roles in context where users are assigned the role via different components. 1268 * 1269 * @covers ::get_assignable_roles 1270 */ 1271 public function test_get_assignable_roles_distinct_usercount() { 1272 global $DB; 1273 1274 $this->resetAfterTest(true); 1275 1276 $this->setAdminUser(); 1277 1278 $course = $this->getDataGenerator()->create_course(); 1279 $context = \context_course::instance($course->id); 1280 1281 $user1 = $this->getDataGenerator()->create_user(); 1282 $user2 = $this->getDataGenerator()->create_user(); 1283 1284 $studentrole = $DB->get_record('role', ['shortname' => 'student']); 1285 1286 // Assign each user the student role in course. 1287 role_assign($studentrole->id, $user1->id, $context->id); 1288 role_assign($studentrole->id, $user2->id, $context->id); 1289 1290 list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_SHORT, true); 1291 $this->assertEquals(2, $rolecounts[$studentrole->id]); 1292 1293 // Assign first user the student role in course again (this time via 'enrol_self' component). 1294 role_assign($studentrole->id, $user1->id, $context->id, 'enrol_self', 1); 1295 1296 // There are still only two distinct users. 1297 list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_SHORT, true); 1298 $this->assertEquals(2, $rolecounts[$studentrole->id]); 1299 } 1300 1301 /** 1302 * Test getting of all switchable roles. 1303 * 1304 * @covers ::get_switchable_roles 1305 */ 1306 public function test_get_switchable_roles() { 1307 global $DB; 1308 1309 $this->resetAfterTest(); 1310 1311 $course = $this->getDataGenerator()->create_course(); 1312 $coursecontext = context_course::instance($course->id); 1313 1314 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1315 $teacher = $this->getDataGenerator()->create_user(); 1316 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1317 $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1318 $DB->insert_record('role_names', $teacherename); 1319 1320 $contexts = $DB->get_records('context'); 1321 $users = $DB->get_records('user'); 1322 $allroles = $DB->get_records('role'); 1323 1324 // Evaluate all results for all users in all contexts. 1325 foreach ($users as $user) { 1326 $this->setUser($user); 1327 foreach ($contexts as $contextid => $unused) { 1328 $context = context_helper::instance_by_id($contextid); 1329 $roles = get_switchable_roles($context); 1330 foreach ($allroles as $roleid => $role) { 1331 if (is_siteadmin()) { 1332 $this->assertTrue(isset($roles[$roleid])); 1333 } else { 1334 $parents = $context->get_parent_context_ids(true); 1335 $pcontexts = implode(',' , $parents); 1336 $allowed = $DB->record_exists_sql( 1337 "SELECT r.id 1338 FROM {role} r 1339 JOIN {role_allow_switch} ras ON ras.allowswitch = r.id 1340 JOIN {role_assignments} ra ON ra.roleid = ras.roleid 1341 WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid 1342 ", 1343 array('userid'=>$user->id, 'roleid'=>$roleid) 1344 ); 1345 if (isset($roles[$roleid])) { 1346 $this->assertTrue($allowed); 1347 } else { 1348 $this->assertFalse($allowed); 1349 } 1350 } 1351 1352 if (isset($roles[$roleid])) { 1353 $coursecontext = $context->get_course_context(false); 1354 $this->assertSame(role_get_name($role, $coursecontext), $roles[$roleid]); 1355 } 1356 } 1357 } 1358 } 1359 } 1360 1361 /** 1362 * Test getting of all overridable roles. 1363 * 1364 * @covers ::get_overridable_roles 1365 */ 1366 public function test_get_overridable_roles() { 1367 global $DB; 1368 1369 $this->resetAfterTest(); 1370 1371 $course = $this->getDataGenerator()->create_course(); 1372 $coursecontext = context_course::instance($course->id); 1373 1374 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1375 $teacher = $this->getDataGenerator()->create_user(); 1376 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1377 $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1378 $DB->insert_record('role_names', $teacherename); 1379 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok. 1380 assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id); 1381 1382 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1383 $student = $this->getDataGenerator()->create_user(); 1384 role_assign($studentrole->id, $student->id, $coursecontext); 1385 1386 $contexts = $DB->get_records('context'); 1387 $users = $DB->get_records('user'); 1388 $allroles = $DB->get_records('role'); 1389 1390 // Evaluate all results for all users in all contexts. 1391 foreach ($users as $user) { 1392 $this->setUser($user); 1393 foreach ($contexts as $contextid => $unused) { 1394 $context = context_helper::instance_by_id($contextid); 1395 $roles = get_overridable_roles($context, ROLENAME_SHORT); 1396 foreach ($allroles as $roleid => $role) { 1397 $hascap = has_any_capability(array('moodle/role:safeoverride', 'moodle/role:override'), $context); 1398 if (is_siteadmin()) { 1399 $this->assertTrue(isset($roles[$roleid])); 1400 } else { 1401 $parents = $context->get_parent_context_ids(true); 1402 $pcontexts = implode(',' , $parents); 1403 $allowed = $DB->record_exists_sql( 1404 "SELECT r.id 1405 FROM {role} r 1406 JOIN {role_allow_override} rao ON r.id = rao.allowoverride 1407 JOIN {role_assignments} ra ON rao.roleid = ra.roleid 1408 WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid 1409 ", 1410 array('userid'=>$user->id, 'roleid'=>$roleid) 1411 ); 1412 if (isset($roles[$roleid])) { 1413 $this->assertTrue($hascap); 1414 $this->assertTrue($allowed); 1415 } else { 1416 $this->assertFalse($hascap and $allowed); 1417 } 1418 } 1419 1420 if (isset($roles[$roleid])) { 1421 $this->assertEquals($role->shortname, $roles[$roleid]); 1422 } 1423 } 1424 } 1425 } 1426 1427 // Test parameter defaults. 1428 $this->setAdminUser(); 1429 $roles1 = get_overridable_roles($coursecontext); 1430 $roles2 = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false); 1431 $this->assertEquals($roles2, $roles1); 1432 1433 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT); 1434 foreach ($alltypes as $type) { 1435 $rolenames = role_fix_names($allroles, $coursecontext, $type); 1436 $roles = get_overridable_roles($coursecontext, $type, false); 1437 foreach ($roles as $roleid => $rolename) { 1438 $this->assertSame($rolenames[$roleid]->localname, $rolename); 1439 } 1440 } 1441 1442 // Verify counts. 1443 $roles = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false); 1444 list($rolenames, $rolecounts, $nameswithcounts) = get_overridable_roles($coursecontext, ROLENAME_ALIAS, true); 1445 $this->assertEquals($roles, $rolenames); 1446 foreach ($rolenames as $roleid => $name) { 1447 if ($roleid == $teacherrole->id) { 1448 $this->assertEquals(1, $rolecounts[$roleid]); 1449 } else { 1450 $this->assertEquals(0, $rolecounts[$roleid]); 1451 } 1452 $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]); 1453 } 1454 } 1455 1456 /** 1457 * Test getting of all overridable roles. 1458 * 1459 * @covers ::get_viewable_roles 1460 */ 1461 public function test_get_viewable_roles_course() { 1462 global $DB; 1463 1464 $this->resetAfterTest(); 1465 1466 $course = $this->getDataGenerator()->create_course(); 1467 $coursecontext = context_course::instance($course->id); 1468 1469 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 1470 $teacher = $this->getDataGenerator()->create_user(); 1471 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1472 1473 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 1474 $studentrolerename = (object) array('roleid' => $studentrole->id, 'name' => 'Učitel', 'contextid' => $coursecontext->id); 1475 $DB->insert_record('role_names', $studentrolerename); 1476 1477 // By default teacher can see student. 1478 $this->setUser($teacher); 1479 $viewableroles = get_viewable_roles($coursecontext); 1480 $this->assertContains($studentrolerename->name, array_values($viewableroles)); 1481 // Remove view permission. 1482 $DB->delete_records('role_allow_view', array('roleid' => $teacherrole->id, 'allowview' => $studentrole->id)); 1483 $viewableroles = get_viewable_roles($coursecontext); 1484 // Teacher can no longer see student role. 1485 $this->assertNotContains($studentrolerename->name, array_values($viewableroles)); 1486 // Allow again teacher to view student. 1487 core_role_set_view_allowed($teacherrole->id, $studentrole->id); 1488 // Teacher can now see student role. 1489 $viewableroles = get_viewable_roles($coursecontext); 1490 $this->assertContains($studentrolerename->name, array_values($viewableroles)); 1491 } 1492 1493 /** 1494 * Test getting of all overridable roles. 1495 * 1496 * @covers ::get_viewable_roles 1497 */ 1498 public function test_get_viewable_roles_system() { 1499 global $DB; 1500 1501 $this->resetAfterTest(); 1502 1503 $context = context_system::instance(); 1504 1505 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 1506 $teacher = $this->getDataGenerator()->create_user(); 1507 role_assign($teacherrole->id, $teacher->id, $context); 1508 1509 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 1510 $studentrolename = role_get_name($studentrole, $context); 1511 1512 // By default teacher can see student. 1513 $this->setUser($teacher); 1514 $viewableroles = get_viewable_roles($context); 1515 $this->assertContains($studentrolename, array_values($viewableroles)); 1516 // Remove view permission. 1517 $DB->delete_records('role_allow_view', array('roleid' => $teacherrole->id, 'allowview' => $studentrole->id)); 1518 $viewableroles = get_viewable_roles($context); 1519 // Teacher can no longer see student role. 1520 $this->assertNotContains($studentrolename, array_values($viewableroles)); 1521 // Allow again teacher to view student. 1522 core_role_set_view_allowed($teacherrole->id, $studentrole->id); 1523 // Teacher can now see student role. 1524 $viewableroles = get_viewable_roles($context); 1525 $this->assertContains($studentrolename, array_values($viewableroles)); 1526 } 1527 1528 /** 1529 * Test we have context level defaults. 1530 * 1531 * @covers ::get_default_contextlevels 1532 */ 1533 public function test_get_default_contextlevels() { 1534 $archetypes = get_role_archetypes(); 1535 $alllevels = context_helper::get_all_levels(); 1536 foreach ($archetypes as $archetype) { 1537 $defaults = get_default_contextlevels($archetype); 1538 $this->assertIsArray($defaults); 1539 foreach ($defaults as $level) { 1540 $this->assertTrue(isset($alllevels[$level])); 1541 } 1542 } 1543 } 1544 1545 /** 1546 * Test role context level setup. 1547 * 1548 * @covers ::set_role_contextlevels 1549 */ 1550 public function test_set_role_contextlevels() { 1551 global $DB; 1552 1553 $this->resetAfterTest(); 1554 1555 $roleid = create_role('New student role', 'student2', 'New student description', 'student'); 1556 1557 $this->assertFalse($DB->record_exists('role_context_levels', array('roleid' => $roleid))); 1558 1559 set_role_contextlevels($roleid, array(CONTEXT_COURSE, CONTEXT_MODULE)); 1560 $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel'); 1561 $this->assertCount(2, $levels); 1562 $this->assertTrue(isset($levels[CONTEXT_COURSE])); 1563 $this->assertTrue(isset($levels[CONTEXT_MODULE])); 1564 1565 set_role_contextlevels($roleid, array(CONTEXT_COURSE)); 1566 $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel'); 1567 $this->assertCount(1, $levels); 1568 $this->assertTrue(isset($levels[CONTEXT_COURSE])); 1569 } 1570 1571 /** 1572 * Test getting of role context levels 1573 * 1574 * @covers ::get_roles_for_contextlevels 1575 */ 1576 public function test_get_roles_for_contextlevels() { 1577 global $DB; 1578 1579 $allroles = get_all_roles(); 1580 foreach (context_helper::get_all_levels() as $level => $unused) { 1581 $roles = get_roles_for_contextlevels($level); 1582 foreach ($allroles as $roleid => $unused) { 1583 $exists = $DB->record_exists('role_context_levels', array('contextlevel'=>$level, 'roleid'=>$roleid)); 1584 if (in_array($roleid, $roles)) { 1585 $this->assertTrue($exists); 1586 } else { 1587 $this->assertFalse($exists); 1588 } 1589 } 1590 } 1591 } 1592 1593 /** 1594 * Test default enrol roles. 1595 * 1596 * @covers ::get_default_enrol_roles 1597 */ 1598 public function test_get_default_enrol_roles() { 1599 $this->resetAfterTest(); 1600 1601 $course = $this->getDataGenerator()->create_course(); 1602 $coursecontext = context_course::instance($course->id); 1603 1604 $id2 = create_role('New student role', 'student2', 'New student description', 'student'); 1605 set_role_contextlevels($id2, array(CONTEXT_COURSE)); 1606 1607 $allroles = get_all_roles(); 1608 $expected = array($id2=>$allroles[$id2]); 1609 1610 foreach (get_roles_for_contextlevels(CONTEXT_COURSE) as $roleid) { 1611 $expected[$roleid] = $roleid; 1612 } 1613 1614 $roles = get_default_enrol_roles($coursecontext); 1615 foreach ($allroles as $role) { 1616 $this->assertEquals(isset($expected[$role->id]), isset($roles[$role->id])); 1617 if (isset($roles[$role->id])) { 1618 $this->assertSame(role_get_name($role, $coursecontext), $roles[$role->id]); 1619 } 1620 } 1621 } 1622 1623 /** 1624 * Test getting of role users. 1625 * 1626 * @covers ::get_role_users 1627 */ 1628 public function test_get_role_users() { 1629 global $DB; 1630 1631 $this->resetAfterTest(); 1632 1633 $systemcontext = context_system::instance(); 1634 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1635 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1636 $noeditteacherrole = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST); 1637 $course = $this->getDataGenerator()->create_course(); 1638 $coursecontext = context_course::instance($course->id); 1639 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1640 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1641 $DB->insert_record('role_names', $teacherrename); 1642 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id); 1643 $DB->insert_record('role_names', $otherrename); 1644 1645 $user1 = $this->getDataGenerator()->create_user(array('firstname'=>'John', 'lastname'=>'Smith')); 1646 role_assign($teacherrole->id, $user1->id, $coursecontext->id); 1647 $user2 = $this->getDataGenerator()->create_user(array('firstname'=>'Jan', 'lastname'=>'Kovar')); 1648 role_assign($teacherrole->id, $user2->id, $systemcontext->id); 1649 $user3 = $this->getDataGenerator()->create_user(); 1650 $this->getDataGenerator()->enrol_user($user3->id, $course->id, $teacherrole->id); 1651 $user4 = $this->getDataGenerator()->create_user(); 1652 $this->getDataGenerator()->enrol_user($user4->id, $course->id, $studentrole->id); 1653 $this->getDataGenerator()->enrol_user($user4->id, $course->id, $noeditteacherrole->id); 1654 1655 $group = $this->getDataGenerator()->create_group(array('courseid'=>$course->id)); 1656 groups_add_member($group, $user3); 1657 1658 $users = get_role_users($teacherrole->id, $coursecontext); 1659 $this->assertCount(2, $users); 1660 $this->assertArrayHasKey($user1->id, $users); 1661 $this->assertEquals($users[$user1->id]->id, $user1->id); 1662 $this->assertEquals($users[$user1->id]->roleid, $teacherrole->id); 1663 $this->assertEquals($users[$user1->id]->rolename, $teacherrole->name); 1664 $this->assertEquals($users[$user1->id]->roleshortname, $teacherrole->shortname); 1665 $this->assertEquals($users[$user1->id]->rolecoursealias, $teacherrename->name); 1666 $this->assertArrayHasKey($user3->id, $users); 1667 $this->assertEquals($users[$user3->id]->id, $user3->id); 1668 $this->assertEquals($users[$user3->id]->roleid, $teacherrole->id); 1669 $this->assertEquals($users[$user3->id]->rolename, $teacherrole->name); 1670 $this->assertEquals($users[$user3->id]->roleshortname, $teacherrole->shortname); 1671 $this->assertEquals($users[$user3->id]->rolecoursealias, $teacherrename->name); 1672 1673 $users = get_role_users($teacherrole->id, $coursecontext, true); 1674 $this->assertCount(3, $users); 1675 1676 $users = get_role_users($teacherrole->id, $coursecontext, true, '', null, null, '', 2, 1); 1677 $this->assertCount(1, $users); 1678 1679 $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber'); 1680 $this->assertCount(2, $users); 1681 $this->assertArrayHasKey($user1->id, $users); 1682 $this->assertArrayHasKey($user3->id, $users); 1683 1684 $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email'); 1685 $this->assertDebuggingCalled('get_role_users() adding u.lastname, u.firstname to the query result because they were required by $sort but missing in $fields'); 1686 $this->assertCount(2, $users); 1687 $this->assertArrayHasKey($user1->id, $users); 1688 $this->assertObjectHasAttribute('lastname', $users[$user1->id]); 1689 $this->assertObjectHasAttribute('firstname', $users[$user1->id]); 1690 $this->assertArrayHasKey($user3->id, $users); 1691 $this->assertObjectHasAttribute('lastname', $users[$user3->id]); 1692 $this->assertObjectHasAttribute('firstname', $users[$user3->id]); 1693 1694 $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id AS id_alias'); 1695 $this->assertDebuggingCalled('get_role_users() adding u.lastname, u.firstname to the query result because they were required by $sort but missing in $fields'); 1696 $this->assertCount(2, $users); 1697 $this->assertArrayHasKey($user1->id, $users); 1698 $this->assertObjectHasAttribute('id_alias', $users[$user1->id]); 1699 $this->assertObjectHasAttribute('lastname', $users[$user1->id]); 1700 $this->assertObjectHasAttribute('firstname', $users[$user1->id]); 1701 $this->assertArrayHasKey($user3->id, $users); 1702 $this->assertObjectHasAttribute('id_alias', $users[$user3->id]); 1703 $this->assertObjectHasAttribute('lastname', $users[$user3->id]); 1704 $this->assertObjectHasAttribute('firstname', $users[$user3->id]); 1705 1706 $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber', null, $group->id); 1707 $this->assertCount(1, $users); 1708 $this->assertArrayHasKey($user3->id, $users); 1709 1710 $users = get_role_users($teacherrole->id, $coursecontext, true, 'u.id, u.email, u.idnumber, u.firstname', 'u.idnumber', null, '', '', '', 'u.firstname = :xfirstname', array('xfirstname'=>'John')); 1711 $this->assertCount(1, $users); 1712 $this->assertArrayHasKey($user1->id, $users); 1713 1714 $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false, 'ra.id', 'ra.id'); 1715 $this->assertDebuggingNotCalled(); 1716 $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false, 'ra.userid', 'ra.userid'); 1717 $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' . 1718 'role assignments id (ra.id) as unique field, you can use $fields param for it.'); 1719 $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false); 1720 $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' . 1721 'role assignments id (ra.id) as unique field, you can use $fields param for it.'); 1722 $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, 1723 false, 'u.id, u.firstname', 'u.id, u.firstname'); 1724 $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' . 1725 'role assignments id (ra.id) as unique field, you can use $fields param for it.'); 1726 } 1727 1728 /** 1729 * Test used role query. 1730 * 1731 * @covers ::get_roles_used_in_context 1732 */ 1733 public function test_get_roles_used_in_context() { 1734 global $DB; 1735 1736 $this->resetAfterTest(); 1737 1738 $systemcontext = context_system::instance(); 1739 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1740 $course = $this->getDataGenerator()->create_course(); 1741 $coursecontext = context_course::instance($course->id); 1742 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1743 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1744 $DB->insert_record('role_names', $teacherrename); 1745 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id); 1746 $DB->insert_record('role_names', $otherrename); 1747 1748 $user1 = $this->getDataGenerator()->create_user(); 1749 role_assign($teacherrole->id, $user1->id, $coursecontext->id); 1750 1751 $roles = get_roles_used_in_context($coursecontext); 1752 $this->assertCount(1, $roles); 1753 $role = reset($roles); 1754 $roleid = key($roles); 1755 $this->assertEquals($roleid, $role->id); 1756 $this->assertEquals($teacherrole->id, $role->id); 1757 $this->assertSame($teacherrole->name, $role->name); 1758 $this->assertSame($teacherrole->shortname, $role->shortname); 1759 $this->assertEquals($teacherrole->sortorder, $role->sortorder); 1760 $this->assertSame($teacherrename->name, $role->coursealias); 1761 1762 $user2 = $this->getDataGenerator()->create_user(); 1763 role_assign($teacherrole->id, $user2->id, $systemcontext->id); 1764 role_assign($otherid, $user2->id, $systemcontext->id); 1765 1766 $roles = get_roles_used_in_context($systemcontext); 1767 $this->assertCount(2, $roles); 1768 } 1769 1770 /** 1771 * Test roles used in course. 1772 * 1773 * @covers ::get_user_roles_in_course 1774 */ 1775 public function test_get_user_roles_in_course() { 1776 global $DB, $CFG; 1777 1778 $this->resetAfterTest(); 1779 1780 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1781 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1782 $managerrole = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST); 1783 $course = $this->getDataGenerator()->create_course(); 1784 $coursecontext = context_course::instance($course->id); 1785 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1786 $DB->insert_record('role_names', $teacherrename); 1787 1788 $roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs. 1789 $this->assertTrue(in_array($teacherrole->id, $roleids)); 1790 $this->assertTrue(in_array($studentrole->id, $roleids)); 1791 $this->assertFalse(in_array($managerrole->id, $roleids)); 1792 1793 $user1 = $this->getDataGenerator()->create_user(); 1794 role_assign($teacherrole->id, $user1->id, $coursecontext->id); 1795 role_assign($studentrole->id, $user1->id, $coursecontext->id); 1796 $user2 = $this->getDataGenerator()->create_user(); 1797 role_assign($studentrole->id, $user2->id, $coursecontext->id); 1798 $user3 = $this->getDataGenerator()->create_user(); 1799 $user4 = $this->getDataGenerator()->create_user(); 1800 role_assign($managerrole->id, $user4->id, $coursecontext->id); 1801 1802 $this->setAdminUser(); 1803 1804 $roles = get_user_roles_in_course($user1->id, $course->id); 1805 $this->assertEquals([ 1806 role_get_name($teacherrole, $coursecontext), 1807 role_get_name($studentrole, $coursecontext), 1808 ], array_map('strip_tags', explode(', ', $roles))); 1809 1810 $roles = get_user_roles_in_course($user2->id, $course->id); 1811 $this->assertEquals([ 1812 role_get_name($studentrole, $coursecontext), 1813 ], array_map('strip_tags', explode(', ', $roles))); 1814 1815 $roles = get_user_roles_in_course($user3->id, $course->id); 1816 $this->assertEmpty($roles); 1817 1818 // Managers should be able to see a link to their own role type, given they can assign it in the context. 1819 $this->setUser($user4); 1820 $roles = get_user_roles_in_course($user4->id, $course->id); 1821 $this->assertEquals([ 1822 role_get_name($managerrole, $coursecontext), 1823 ], array_map('strip_tags', explode(', ', $roles))); 1824 1825 // Managers should see 2 roles if viewing a user who has been enrolled as a student and a teacher in the course. 1826 $roles = get_user_roles_in_course($user1->id, $course->id); 1827 $this->assertEquals([ 1828 role_get_name($teacherrole, $coursecontext), 1829 role_get_name($studentrole, $coursecontext), 1830 ], array_map('strip_tags', explode(', ', $roles))); 1831 1832 // Students should not see the manager role if viewing a manager's profile. 1833 $this->setUser($user2); 1834 $roles = get_user_roles_in_course($user4->id, $course->id); 1835 $this->assertEmpty($roles); // Should see 0 roles on the manager's profile. 1836 } 1837 1838 /** 1839 * Test get_user_roles and get_users_roles 1840 * 1841 * @covers ::get_user_roles 1842 */ 1843 public function test_get_user_roles() { 1844 global $DB, $CFG; 1845 1846 $this->resetAfterTest(); 1847 1848 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1849 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1850 $course = $this->getDataGenerator()->create_course(); 1851 $coursecontext = context_course::instance($course->id); 1852 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1853 $DB->insert_record('role_names', $teacherrename); 1854 1855 $roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs. 1856 1857 $user1 = $this->getDataGenerator()->create_user(); 1858 role_assign($teacherrole->id, $user1->id, $coursecontext->id); 1859 role_assign($studentrole->id, $user1->id, $coursecontext->id); 1860 $user2 = $this->getDataGenerator()->create_user(); 1861 role_assign($studentrole->id, $user2->id, $coursecontext->id); 1862 $user3 = $this->getDataGenerator()->create_user(); 1863 1864 $u1roles = get_user_roles($coursecontext, $user1->id); 1865 1866 $u2roles = get_user_roles($coursecontext, $user2->id); 1867 1868 $allroles = get_users_roles($coursecontext, [], false); 1869 $specificuserroles = get_users_roles($coursecontext, [$user1->id, $user2->id]); 1870 $this->assertEquals($u1roles, $allroles[$user1->id]); 1871 $this->assertEquals($u1roles, $specificuserroles[$user1->id]); 1872 $this->assertEquals($u2roles, $allroles[$user2->id]); 1873 $this->assertEquals($u2roles, $specificuserroles[$user2->id]); 1874 } 1875 1876 /** 1877 * Test has_capability(), has_any_capability() and has_all_capabilities(). 1878 * 1879 * @covers ::has_capability 1880 * @covers ::has_any_capability 1881 * @covers ::has_all_capabilities 1882 */ 1883 public function test_has_capability_and_friends() { 1884 global $DB; 1885 1886 $this->resetAfterTest(); 1887 1888 $course = $this->getDataGenerator()->create_course(); 1889 $coursecontext = context_course::instance($course->id); 1890 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1891 $teacher = $this->getDataGenerator()->create_user(); 1892 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1893 $admin = $DB->get_record('user', array('username'=>'admin')); 1894 1895 // Note: Here are used default capabilities, the full test is in permission evaluation bellow, 1896 // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user. 1897 1898 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupsection'))); 1899 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); 1900 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/site:approvecourse'))); 1901 1902 $sca = array('moodle/backup:backupsection', 'moodle/backup:backupcourse', 'moodle/site:approvecourse'); 1903 $sc = array('moodle/backup:backupsection', 'moodle/backup:backupcourse'); 1904 1905 $this->setUser(0); 1906 $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext)); 1907 $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext)); 1908 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext)); 1909 $this->assertFalse(has_any_capability($sca, $coursecontext)); 1910 $this->assertFalse(has_all_capabilities($sca, $coursecontext)); 1911 1912 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $teacher)); 1913 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $teacher)); 1914 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $teacher)); 1915 $this->assertTrue(has_any_capability($sca, $coursecontext, $teacher)); 1916 $this->assertTrue(has_all_capabilities($sc, $coursecontext, $teacher)); 1917 $this->assertFalse(has_all_capabilities($sca, $coursecontext, $teacher)); 1918 1919 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $admin)); 1920 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $admin)); 1921 $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext, $admin)); 1922 $this->assertTrue(has_any_capability($sca, $coursecontext, $admin)); 1923 $this->assertTrue(has_all_capabilities($sc, $coursecontext, $admin)); 1924 $this->assertTrue(has_all_capabilities($sca, $coursecontext, $admin)); 1925 1926 $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, $admin, false)); 1927 $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, $admin, false)); 1928 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $admin, false)); 1929 $this->assertFalse(has_any_capability($sca, $coursecontext, $admin, false)); 1930 $this->assertFalse(has_all_capabilities($sc, $coursecontext, $admin, false)); 1931 $this->assertFalse(has_all_capabilities($sca, $coursecontext, $admin, false)); 1932 1933 $this->setUser($teacher); 1934 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext)); 1935 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext)); 1936 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext)); 1937 $this->assertTrue(has_any_capability($sca, $coursecontext)); 1938 $this->assertTrue(has_all_capabilities($sc, $coursecontext)); 1939 $this->assertFalse(has_all_capabilities($sca, $coursecontext)); 1940 1941 $this->setAdminUser(); 1942 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext)); 1943 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext)); 1944 $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext)); 1945 $this->assertTrue(has_any_capability($sca, $coursecontext)); 1946 $this->assertTrue(has_all_capabilities($sc, $coursecontext)); 1947 $this->assertTrue(has_all_capabilities($sca, $coursecontext)); 1948 1949 $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, 0)); 1950 $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, 0)); 1951 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, 0)); 1952 $this->assertFalse(has_any_capability($sca, $coursecontext, 0)); 1953 $this->assertFalse(has_all_capabilities($sca, $coursecontext, 0)); 1954 } 1955 1956 /** 1957 * Utility method to fake a plugin 1958 * 1959 * @param string $pluginname plugin name 1960 * @return void 1961 */ 1962 protected function setup_fake_plugin($pluginname) { 1963 global $CFG; 1964 // Here we have to hack the component loader so we can insert our fake plugin and test that 1965 // the access.php works. 1966 $mockedcomponent = new ReflectionClass(core_component::class); 1967 $mockedplugins = $mockedcomponent->getProperty('plugins'); 1968 $mockedplugins->setAccessible(true); 1969 $plugins = $mockedplugins->getValue(); 1970 $plugins['fake'] = [$pluginname => "{$CFG->dirroot}/lib/tests/fixtures/fakeplugins/$pluginname"]; 1971 $mockedplugins->setValue(null, $plugins); 1972 update_capabilities('fake_access'); 1973 $this->resetDebugging(); // We have debugging messages here that we need to get rid of. 1974 // End of the component loader mock. 1975 } 1976 1977 /** 1978 * Test get_deprecated_capability_info() 1979 * 1980 * @covers ::get_deprecated_capability_info 1981 */ 1982 public function test_get_deprecated_capability_info() { 1983 $this->resetAfterTest(); 1984 $course = $this->getDataGenerator()->create_course(); 1985 $coursecontext = context_course::instance($course->id); 1986 $user = $this->getDataGenerator()->create_and_enrol($course); 1987 $this->setup_fake_plugin('access'); 1988 1989 // For now we have deprecated fake/access:fakecapability. 1990 $capinfo = get_deprecated_capability_info('fake/access:fakecapability'); 1991 $this->assertNotEmpty($capinfo); 1992 $this->assertEquals("The capability 'fake/access:fakecapability' is" 1993 . " deprecated.This capability should not be used anymore.", $capinfo['fullmessage']); 1994 } 1995 1996 /** 1997 * Test get_deprecated_capability_info() through has_capability 1998 * 1999 * @covers ::get_deprecated_capability_info 2000 */ 2001 public function test_get_deprecated_capability_info_through_has_capability() { 2002 $this->resetAfterTest(); 2003 $course = $this->getDataGenerator()->create_course(); 2004 $coursecontext = context_course::instance($course->id); 2005 $user = $this->getDataGenerator()->create_and_enrol($course); 2006 $this->setup_fake_plugin('access'); 2007 2008 // For now we have deprecated fake/access:fakecapability. 2009 $hascap = has_capability('fake/access:fakecapability', $coursecontext, $user); 2010 $this->assertTrue($hascap); 2011 $this->assertDebuggingCalled("The capability 'fake/access:fakecapability' is deprecated." 2012 . "This capability should not be used anymore."); 2013 } 2014 2015 /** 2016 * Test get_deprecated_capability_info() through get_user_capability_contexts() 2017 * 2018 * @covers ::get_deprecated_capability_info 2019 */ 2020 public function test_get_deprecated_capability_info_through_get_user_capability_contexts() { 2021 $this->resetAfterTest(); 2022 $category = $this->getDataGenerator()->create_category(); 2023 $course = $this->getDataGenerator()->create_course(['categoryid' => $category->id]); 2024 $user = $this->getDataGenerator()->create_and_enrol($course); 2025 $this->setup_fake_plugin('access'); 2026 2027 // For now we have deprecated fake/access:fakecapability. 2028 list($categories, $courses) = get_user_capability_contexts('fake/access:fakecapability', false, $user->id); 2029 $this->assertNotEmpty($courses); 2030 $this->assertDebuggingCalled("The capability 'fake/access:fakecapability' is deprecated." 2031 . "This capability should not be used anymore."); 2032 } 2033 2034 /** 2035 * Test get_deprecated_capability_info with a capability that does not exist 2036 * 2037 * @param string $capability the capability name 2038 * @param array $debugmessages the debug messsages we expect 2039 * @param bool $expectedexisting does the capability exist 2040 * @covers ::get_deprecated_capability_info 2041 * @dataProvider deprecated_capabilities_use_cases 2042 */ 2043 public function test_get_deprecated_capability_specific_cases(string $capability, array $debugmessages, 2044 bool $expectedexisting) { 2045 $this->resetAfterTest(); 2046 $course = $this->getDataGenerator()->create_course(); 2047 $coursecontext = context_course::instance($course->id); 2048 $user = $this->getDataGenerator()->create_and_enrol($course); 2049 $this->setup_fake_plugin('access'); 2050 2051 // For now we have deprecated fake/access:fakecapability. 2052 $this->resetDebugging(); 2053 $hascap = has_capability($capability, $coursecontext, $user); 2054 $this->assertEquals($expectedexisting, $hascap); 2055 $this->assertDebuggingCalledCount(count($debugmessages), $debugmessages); 2056 } 2057 2058 /** 2059 * Specific use case for deprecated capabilities 2060 * 2061 * @return array 2062 */ 2063 public function deprecated_capabilities_use_cases() { 2064 return [ 2065 'capability missing' => [ 2066 'fake/access:missingcapability', 2067 [ 2068 "Capability \"fake/access:missingcapability\" was not found! This has to be fixed in code." 2069 ], 2070 false 2071 ], 2072 'replacement no info' => [ 2073 'fake/access:replacementnoinfo', 2074 [ 2075 "The capability 'fake/access:replacementnoinfo' is deprecated.", 2076 ], 2077 true 2078 ], 2079 'replacement missing' => [ 2080 'fake/access:replacementmissing', 2081 [ 2082 "The capability 'fake/access:replacementmissing' is deprecated.This capability should not be used anymore.", 2083 ], 2084 true 2085 ], 2086 'replacement with non existing cap' => [ 2087 'fake/access:replacementwithwrongcapability', 2088 [ 2089 "Capability 'fake/access:replacementwithwrongcapability' was supposed to be replaced with" 2090 . " 'fake/access:nonexistingcapabilty', which does not exist !", 2091 "The capability 'fake/access:replacementwithwrongcapability' is deprecated." 2092 . "This capability should not be used anymore.It will be replaced by 'fake/access:nonexistingcapabilty'." 2093 ], 2094 true 2095 ], 2096 'replacement with existing' => [ 2097 'fake/access:replacementwithexisting', // Existing capability buf for a different role. 2098 [ 2099 "The capability 'fake/access:replacementwithexisting' is deprecated.This capability should not be used anymore." 2100 . "It will be replaced by 'fake/access:existingcapability'.", 2101 ], 2102 false // As the capability is applied to managers, we should not have this capability for this simple user. 2103 ], 2104 ]; 2105 } 2106 2107 /** 2108 * Test that assigning a fake cap does not return. 2109 * 2110 * @covers ::get_users_by_capability 2111 * @covers ::get_with_capability_join 2112 * @covers ::get_with_capability_sql 2113 * @covers ::has_capability 2114 */ 2115 public function test_fake_capability() { 2116 global $DB; 2117 2118 $this->resetAfterTest(); 2119 2120 $course = $this->getDataGenerator()->create_course(); 2121 $coursecontext = context_course::instance($course->id); 2122 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 2123 $teacher = $this->getDataGenerator()->create_user(); 2124 2125 $fakecapname = 'moodle/fake:capability'; 2126 2127 role_assign($teacherrole->id, $teacher->id, $coursecontext); 2128 $admin = $DB->get_record('user', array('username' => 'admin')); 2129 2130 // Test a capability which does not exist. 2131 // Note: Do not use assign_capability because it will not allow fake caps. 2132 $DB->insert_record('role_capabilities', (object) [ 2133 'contextid' => $coursecontext->id, 2134 'roleid' => $teacherrole->id, 2135 'capability' => $fakecapname, 2136 'permission' => CAP_ALLOW, 2137 'timemodified' => time(), 2138 'modifierid' => 0, 2139 ]); 2140 2141 // Check `has_capability`. 2142 $this->assertFalse(has_capability($fakecapname, $coursecontext, $teacher)); 2143 $this->assertDebuggingCalled("Capability \"{$fakecapname}\" was not found! This has to be fixed in code."); 2144 $this->assertFalse(has_capability($fakecapname, $coursecontext, $admin)); 2145 $this->assertDebuggingCalled("Capability \"{$fakecapname}\" was not found! This has to be fixed in code."); 2146 2147 // Check `get_with_capability_sql` (with uses `get_with_capability_join`). 2148 list($sql, $params) = get_with_capability_sql($coursecontext, $fakecapname); 2149 $users = $DB->get_records_sql($sql, $params); 2150 2151 $this->assertFalse(array_key_exists($teacher->id, $users)); 2152 $this->assertFalse(array_key_exists($admin->id, $users)); 2153 2154 // Check `get_users_by_capability`. 2155 $users = get_users_by_capability($coursecontext, $fakecapname); 2156 2157 $this->assertFalse(array_key_exists($teacher->id, $users)); 2158 $this->assertFalse(array_key_exists($admin->id, $users)); 2159 } 2160 2161 /** 2162 * Test that assigning a fake cap does not return. 2163 * 2164 * @covers ::assign_capability 2165 */ 2166 public function test_fake_capability_assign() { 2167 global $DB; 2168 2169 $this->resetAfterTest(); 2170 2171 $course = $this->getDataGenerator()->create_course(); 2172 $coursecontext = context_course::instance($course->id); 2173 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 2174 $teacher = $this->getDataGenerator()->create_user(); 2175 2176 $capability = 'moodle/fake:capability'; 2177 2178 role_assign($teacherrole->id, $teacher->id, $coursecontext); 2179 $admin = $DB->get_record('user', array('username' => 'admin')); 2180 2181 $this->expectException('coding_exception'); 2182 $this->expectExceptionMessage("Capability '{$capability}' was not found! This has to be fixed in code."); 2183 assign_capability($capability, CAP_ALLOW, $teacherrole->id, $coursecontext); 2184 } 2185 2186 /** 2187 * Test that assigning a fake cap does not return. 2188 * 2189 * @covers ::unassign_capability 2190 */ 2191 public function test_fake_capability_unassign() { 2192 global $DB; 2193 2194 $this->resetAfterTest(); 2195 2196 $course = $this->getDataGenerator()->create_course(); 2197 $coursecontext = context_course::instance($course->id); 2198 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 2199 $teacher = $this->getDataGenerator()->create_user(); 2200 2201 $capability = 'moodle/fake:capability'; 2202 2203 role_assign($teacherrole->id, $teacher->id, $coursecontext); 2204 $admin = $DB->get_record('user', array('username' => 'admin')); 2205 2206 $this->expectException('coding_exception'); 2207 $this->expectExceptionMessage("Capability '{$capability}' was not found! This has to be fixed in code."); 2208 unassign_capability($capability, CAP_ALLOW, $teacherrole->id, $coursecontext); 2209 } 2210 2211 /** 2212 * Test that the caching in get_role_definitions() and get_role_definitions_uncached() 2213 * works as intended. 2214 * 2215 * @covers ::get_role_definitions 2216 * @covers ::role_change_permission 2217 */ 2218 public function test_role_definition_caching() { 2219 global $DB; 2220 2221 $this->resetAfterTest(); 2222 2223 // Get some role ids. 2224 $authenticatedrole = $DB->get_record('role', array('shortname' => 'user'), '*', MUST_EXIST); 2225 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 2226 $emptyroleid = create_role('No capabilities', 'empty', 'A role with no capabilties'); 2227 $course = $this->getDataGenerator()->create_course(); 2228 $coursecontext = context_course::instance($course->id); 2229 2230 // Instantiate the cache instance, since that does DB queries (get_config) 2231 // and we don't care about those. 2232 cache::make('core', 'roledefs'); 2233 2234 // One database query is not necessarily one database read, it seems. Find out how many. 2235 $startdbreads = $DB->perf_get_reads(); 2236 $rs = $DB->get_recordset('user'); 2237 $rs->close(); 2238 $readsperquery = $DB->perf_get_reads() - $startdbreads; 2239 2240 // Now load some role definitions, and check when it queries the database. 2241 2242 // Load the capabilities for two roles. Should be one query. 2243 $startdbreads = $DB->perf_get_reads(); 2244 get_role_definitions([$authenticatedrole->id, $studentrole->id]); 2245 $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2246 2247 // Load the capabilities for same two roles. Should not query the DB. 2248 $startdbreads = $DB->perf_get_reads(); 2249 get_role_definitions([$authenticatedrole->id, $studentrole->id]); 2250 $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2251 2252 // Include a third role. Should do one DB query. 2253 $startdbreads = $DB->perf_get_reads(); 2254 get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]); 2255 $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2256 2257 // Repeat call. No DB queries. 2258 $startdbreads = $DB->perf_get_reads(); 2259 get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]); 2260 $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2261 2262 // Alter a role. 2263 role_change_permission($studentrole->id, $coursecontext, 'moodle/course:tag', CAP_ALLOW); 2264 2265 // Should now know to do one query. 2266 $startdbreads = $DB->perf_get_reads(); 2267 get_role_definitions([$authenticatedrole->id, $studentrole->id]); 2268 $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2269 2270 // Now clear the in-memory cache, and verify that it does not query the DB. 2271 // Cannot use accesslib_clear_all_caches_for_unit_testing since that also 2272 // clears the MUC cache. 2273 global $ACCESSLIB_PRIVATE; 2274 $ACCESSLIB_PRIVATE->cacheroledefs = array(); 2275 2276 // Get all roles. Should not need the DB. 2277 $startdbreads = $DB->perf_get_reads(); 2278 get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]); 2279 $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2280 } 2281 2282 /** 2283 * Tests get_user_capability_course() which checks a capability across all courses. 2284 * 2285 * @covers ::get_user_capability_course 2286 */ 2287 public function test_get_user_capability_course() { 2288 global $CFG, $USER; 2289 2290 $this->resetAfterTest(); 2291 2292 $generator = $this->getDataGenerator(); 2293 $cap = 'moodle/course:view'; 2294 2295 // The structure being created here is this: 2296 // 2297 // All tests work with the single capability 'moodle/course:view'. 2298 // 2299 // ROLE DEF/OVERRIDE ROLE ASSIGNS 2300 // Role: Allow Prohib Empty Def user u1 u2 u3 u4 u5 u6 u7 u8 2301 // System ALLOW PROHIBIT A E A+E 2302 // cat1 ALLOW 2303 // C1 (ALLOW) P 2304 // C2 ALLOW E P 2305 // cat2 PREVENT 2306 // C3 ALLOW E 2307 // C4 2308 // Misc. A 2309 // C5 PREVENT A 2310 // C6 PROHIBIT 2311 // 2312 // Front-page and guest role stuff from the end of this test not included in the diagram. 2313 2314 // Create a role which allows course:view and one that prohibits it, and one neither. 2315 $allowroleid = $generator->create_role(); 2316 $prohibitroleid = $generator->create_role(); 2317 $emptyroleid = $generator->create_role(); 2318 $systemcontext = context_system::instance(); 2319 assign_capability($cap, CAP_ALLOW, $allowroleid, $systemcontext->id); 2320 assign_capability($cap, CAP_PROHIBIT, $prohibitroleid, $systemcontext->id); 2321 2322 // Create two categories (nested). 2323 $cat1 = $generator->create_category(); 2324 $cat2 = $generator->create_category(['parent' => $cat1->id]); 2325 2326 // Create six courses - two in cat1, two in cat2, and two in default category. 2327 // Shortnames are used for a sorting test. Otherwise they are not significant. 2328 $c1 = $generator->create_course(['category' => $cat1->id, 'shortname' => 'Z']); 2329 $c2 = $generator->create_course(['category' => $cat1->id, 'shortname' => 'Y']); 2330 $c3 = $generator->create_course(['category' => $cat2->id, 'shortname' => 'X']); 2331 $c4 = $generator->create_course(['category' => $cat2->id]); 2332 $c5 = $generator->create_course(); 2333 $c6 = $generator->create_course(); 2334 2335 // Category overrides: in cat 1, empty role is allowed; in cat 2, empty role is prevented. 2336 assign_capability($cap, CAP_ALLOW, $emptyroleid, 2337 context_coursecat::instance($cat1->id)->id); 2338 assign_capability($cap, CAP_PREVENT, $emptyroleid, 2339 context_coursecat::instance($cat2->id)->id); 2340 2341 // Course overrides: in C5, allow role is prevented; in C6, empty role is prohibited; in 2342 // C3, empty role is allowed. 2343 assign_capability($cap, CAP_PREVENT, $allowroleid, 2344 context_course::instance($c5->id)->id); 2345 assign_capability($cap, CAP_PROHIBIT, $emptyroleid, 2346 context_course::instance($c6->id)->id); 2347 assign_capability($cap, CAP_ALLOW, $emptyroleid, 2348 context_course::instance($c3->id)->id); 2349 assign_capability($cap, CAP_ALLOW, $prohibitroleid, 2350 context_course::instance($c2->id)->id); 2351 2352 // User 1 has no roles except default user role. 2353 $u1 = $generator->create_user(); 2354 2355 // It returns false (annoyingly) if there are no courses. 2356 $this->assertFalse(get_user_capability_course($cap, $u1->id, true, '', 'id')); 2357 2358 // Final override: in C1, default user role is allowed. 2359 assign_capability($cap, CAP_ALLOW, $CFG->defaultuserroleid, 2360 context_course::instance($c1->id)->id); 2361 2362 // Should now get C1 only. 2363 $courses = get_user_capability_course($cap, $u1->id, true, '', 'id'); 2364 $this->assert_course_ids([$c1->id], $courses); 2365 2366 // User 2 has allow role (system wide). 2367 $u2 = $generator->create_user(); 2368 role_assign($allowroleid, $u2->id, $systemcontext->id); 2369 2370 // Should get everything except C5. 2371 $courses = get_user_capability_course($cap, $u2->id, true, '', 'id'); 2372 $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id, $c6->id], $courses); 2373 2374 // User 3 has empty role (system wide). 2375 $u3 = $generator->create_user(); 2376 role_assign($emptyroleid, $u3->id, $systemcontext->id); 2377 2378 // Should get cat 1 courses but not cat2, except C3. 2379 $courses = get_user_capability_course($cap, $u3->id, true, '', 'id'); 2380 $this->assert_course_ids([$c1->id, $c2->id, $c3->id], $courses); 2381 2382 // User 4 has allow and empty role (system wide). 2383 $u4 = $generator->create_user(); 2384 role_assign($allowroleid, $u4->id, $systemcontext->id); 2385 role_assign($emptyroleid, $u4->id, $systemcontext->id); 2386 2387 // Should get everything except C5 and C6. 2388 $courses = get_user_capability_course($cap, $u4->id, true, '', 'id'); 2389 $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id], $courses); 2390 2391 // User 5 has allow role in default category only. 2392 $u5 = $generator->create_user(); 2393 role_assign($allowroleid, $u5->id, context_coursecat::instance($c5->category)->id); 2394 2395 // Should get C1 and the default category courses but not C5. 2396 $courses = get_user_capability_course($cap, $u5->id, true, '', 'id'); 2397 $this->assert_course_ids([$c1->id, $c6->id], $courses); 2398 2399 // User 6 has a bunch of course roles: prohibit role in C1, empty role in C3, allow role in 2400 // C6. 2401 $u6 = $generator->create_user(); 2402 role_assign($prohibitroleid, $u6->id, context_course::instance($c1->id)->id); 2403 role_assign($emptyroleid, $u6->id, context_course::instance($c3->id)->id); 2404 role_assign($allowroleid, $u6->id, context_course::instance($c5->id)->id); 2405 2406 // Should get C3 only because the allow role is prevented in C5. 2407 $courses = get_user_capability_course($cap, $u6->id, true, '', 'id'); 2408 $this->assert_course_ids([$c3->id], $courses); 2409 2410 // User 7 has empty role in C2. 2411 $u7 = $generator->create_user(); 2412 role_assign($emptyroleid, $u7->id, context_course::instance($c2->id)->id); 2413 2414 // Should get C1 by the default user role override, and C2 by the cat1 level override. 2415 $courses = get_user_capability_course($cap, $u7->id, true, '', 'id'); 2416 $this->assert_course_ids([$c1->id, $c2->id], $courses); 2417 2418 // User 8 has prohibit role as system context, to verify that prohibits can't be overridden. 2419 $u8 = $generator->create_user(); 2420 role_assign($prohibitroleid, $u8->id, context_course::instance($c2->id)->id); 2421 2422 // Should get C1 by the default user role override, no other courses because the prohibit cannot be overridden. 2423 $courses = get_user_capability_course($cap, $u8->id, true, '', 'id'); 2424 $this->assert_course_ids([$c1->id], $courses); 2425 2426 // Admin user gets everything.... 2427 $courses = get_user_capability_course($cap, get_admin()->id, true, '', 'id'); 2428 $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id, $c5->id, $c6->id], 2429 $courses); 2430 2431 // Unless you turn off doanything, when it only has the things a user with no role does. 2432 $courses = get_user_capability_course($cap, get_admin()->id, false, '', 'id'); 2433 $this->assert_course_ids([$c1->id], $courses); 2434 2435 // Using u3 as an example, test the limit feature. 2436 $courses = get_user_capability_course($cap, $u3->id, true, '', 'id', 2); 2437 $this->assert_course_ids([$c1->id, $c2->id], $courses); 2438 2439 // Check sorting. 2440 $courses = get_user_capability_course($cap, $u3->id, true, '', 'shortname'); 2441 $this->assert_course_ids([$c3->id, $c2->id, $c1->id], $courses); 2442 2443 // Check returned fields - default. 2444 $courses = get_user_capability_course($cap, $u3->id, true, '', 'id'); 2445 $this->assertEquals((object)['id' => $c1->id], $courses[0]); 2446 2447 // Add a selection of fields, including the context ones with special handling. 2448 $courses = get_user_capability_course($cap, $u3->id, true, 'shortname, ctxlevel, ctxdepth, ctxinstance', 'id'); 2449 $this->assertEquals((object)['id' => $c1->id, 'shortname' => 'Z', 'ctxlevel' => 50, 2450 'ctxdepth' => 3, 'ctxinstance' => $c1->id], $courses[0]); 2451 2452 // Test front page role - user 1 has no roles, but if we change the front page role 2453 // definition so that it has our capability, then they should see the front page course. 2454 // as well as C1. 2455 assign_capability($cap, CAP_ALLOW, $CFG->defaultfrontpageroleid, $systemcontext->id); 2456 $courses = get_user_capability_course($cap, $u1->id, true, '', 'id'); 2457 $this->assert_course_ids([SITEID, $c1->id], $courses); 2458 2459 // Check that temporary guest access (in this case, given on course 2 for user 1) 2460 // also is included, if it has this capability. 2461 assign_capability($cap, CAP_ALLOW, $CFG->guestroleid, $systemcontext->id); 2462 $this->setUser($u1); 2463 load_temp_course_role(context_course::instance($c2->id), $CFG->guestroleid); 2464 $courses = get_user_capability_course($cap, $USER->id, true, '', 'id'); 2465 $this->assert_course_ids([SITEID, $c1->id, $c2->id], $courses); 2466 } 2467 2468 /** 2469 * Tests get_user_capability_contexts() which checks a capability across all courses and categories. 2470 * Testing for categories only because courses results are covered by test_get_user_capability_course. 2471 * 2472 * @covers ::get_user_capability_contexts 2473 */ 2474 public function test_get_user_capability_contexts() { 2475 $this->resetAfterTest(); 2476 2477 $generator = $this->getDataGenerator(); 2478 $cap = 'moodle/contentbank:access'; 2479 $defaultcategoryid = 1; 2480 2481 // The structure being created here is this: 2482 // 2483 // All tests work with the single capability 'moodle/contentbank:access'. 2484 // ROLE DEF/OVERRIDE . 2485 // Role: Allow Prohibit Empty . 2486 // System ALLOW PROHIBIT . 2487 // cat1 PREVENT ALLOW ALLOW . 2488 // cat3 ALLOW PROHIBIT . 2489 // cat2 PROHIBIT PROHIBIT PROHIBIT . 2490 2491 // Create a role which allows contentbank:access and one that prohibits it, and one neither. 2492 $allowroleid = $generator->create_role(); 2493 $prohibitroleid = $generator->create_role(); 2494 $emptyroleid = $generator->create_role(); 2495 $systemcontext = context_system::instance(); 2496 assign_capability($cap, CAP_ALLOW, $allowroleid, $systemcontext->id); 2497 assign_capability($cap, CAP_PROHIBIT, $prohibitroleid, $systemcontext->id); 2498 2499 // Create three categories (two of them nested). 2500 $cat1 = $generator->create_category(['name' => 'Aardvarks']); 2501 $cat2 = $generator->create_category(['name' => 'Badgers']); 2502 $cat3 = $generator->create_category(['parent' => $cat1->id, 'name' => 'Cheetahs']); 2503 2504 // Category overrides: in cat 1, empty role is allowed; in cat 2, empty role is prevented. 2505 assign_capability($cap, CAP_ALLOW, $emptyroleid, 2506 context_coursecat::instance($cat1->id)->id); 2507 assign_capability($cap, CAP_PREVENT, $emptyroleid, 2508 context_coursecat::instance($cat2->id)->id); 2509 2510 // Course category overrides: in cat1, allow role is prevented and prohibit role is allowed; 2511 // in Cat2, allow role is prohibited. 2512 assign_capability($cap, CAP_PREVENT, $allowroleid, 2513 context_coursecat::instance($cat1->id)->id); 2514 assign_capability($cap, CAP_ALLOW, $prohibitroleid, 2515 context_coursecat::instance($cat1->id)->id); 2516 assign_capability($cap, CAP_PROHIBIT, $allowroleid, 2517 context_coursecat::instance($cat2->id)->id); 2518 2519 // User 1 has no roles except default user role. 2520 $u1 = $generator->create_user(); 2521 2522 // It returns false (annoyingly) if there are no course categories. 2523 list($categories, $courses) = get_user_capability_contexts($cap, true, $u1->id); 2524 $this->assertFalse($categories); 2525 2526 // User 2 has allow role (system wide). 2527 $u2 = $generator->create_user(); 2528 role_assign($allowroleid, $u2->id, $systemcontext->id); 2529 2530 // Should get $defaultcategory only. cat2 is prohibited; cat1 is prevented, so cat3 is not allowed. 2531 list($categories, $courses) = get_user_capability_contexts($cap, true, $u2->id); 2532 // Using same assert_course_ids helper even when we are checking course category ids. 2533 $this->assert_course_ids([$defaultcategoryid], $categories); 2534 2535 // User 3 has empty role (system wide). 2536 $u3 = $generator->create_user(); 2537 role_assign($emptyroleid, $u3->id, $systemcontext->id); 2538 2539 // Should get cat1 and cat3. cat2 is prohibited; no access to system level. Sorted by category name. 2540 list($categories, $courses) = get_user_capability_contexts($cap, true, $u3->id, true, '', '', '', 'name'); 2541 $this->assert_course_ids([$cat1->id, $cat3->id], $categories); 2542 2543 // User 4 has prohibit role (system wide). 2544 $u4 = $generator->create_user(); 2545 role_assign($prohibitroleid, $u4->id, $systemcontext->id); 2546 2547 // Should not get any, because all of them are prohibited at system level. 2548 // Even if we try to allow an specific category. 2549 list($categories, $courses) = get_user_capability_contexts($cap, true, $u4->id); 2550 $this->assertFalse($categories); 2551 } 2552 2553 /** 2554 * Extracts an array of course ids to make the above test script shorter. 2555 * 2556 * @param int[] $expected Array of expected course ids 2557 * @param stdClass[] $courses Array of course objects 2558 */ 2559 protected function assert_course_ids(array $expected, array $courses) { 2560 $courseids = array_map(function($c) { 2561 return $c->id; 2562 }, $courses); 2563 $this->assertEquals($expected, $courseids); 2564 } 2565 2566 /** 2567 * Test if course creator future capability lookup works. 2568 * 2569 * @covers ::guess_if_creator_will_have_course_capability 2570 * @covers ::has_capability 2571 */ 2572 public function test_guess_if_creator_will_have_course_capability() { 2573 global $DB, $CFG, $USER; 2574 2575 $this->resetAfterTest(); 2576 2577 $category = $this->getDataGenerator()->create_category(); 2578 $course = $this->getDataGenerator()->create_course(array('category'=>$category->id)); 2579 2580 $syscontext = context_system::instance(); 2581 $categorycontext = context_coursecat::instance($category->id); 2582 $coursecontext = context_course::instance($course->id); 2583 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 2584 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 2585 $creatorrole = $DB->get_record('role', array('shortname'=>'coursecreator'), '*', MUST_EXIST); 2586 $managerrole = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST); 2587 2588 $this->assertEquals($teacherrole->id, $CFG->creatornewroleid); 2589 2590 $creator = $this->getDataGenerator()->create_user(); 2591 $manager = $this->getDataGenerator()->create_user(); 2592 role_assign($managerrole->id, $manager->id, $categorycontext); 2593 2594 $this->assertFalse(has_capability('moodle/course:view', $categorycontext, $creator)); 2595 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator)); 2596 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator)); 2597 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator)); 2598 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator)); 2599 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator)); 2600 2601 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager)); 2602 $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext, $manager)); 2603 $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext, $manager)); 2604 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager->id)); 2605 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager->id)); 2606 2607 $this->assertEquals(0, $USER->id); 2608 $this->assertFalse(has_capability('moodle/course:view', $categorycontext)); 2609 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext)); 2610 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext)); 2611 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext)); 2612 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext)); 2613 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext)); 2614 2615 $this->setUser($manager); 2616 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext)); 2617 $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext)); 2618 $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext)); 2619 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext)); 2620 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext)); 2621 2622 $this->setAdminUser(); 2623 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext)); 2624 $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext)); 2625 $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext)); 2626 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext)); 2627 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext)); 2628 $this->setUser(0); 2629 2630 role_assign($creatorrole->id, $creator->id, $categorycontext); 2631 2632 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator)); 2633 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator)); 2634 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator)); 2635 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator)); 2636 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator)); 2637 2638 $this->setUser($creator); 2639 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, null)); 2640 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, null)); 2641 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, null)); 2642 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, null)); 2643 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, null)); 2644 $this->setUser(0); 2645 2646 set_config('creatornewroleid', $studentrole->id); 2647 2648 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator)); 2649 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator)); 2650 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator)); 2651 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator)); 2652 2653 set_config('creatornewroleid', $teacherrole->id); 2654 2655 role_change_permission($managerrole->id, $categorycontext, 'moodle/course:visibility', CAP_PREVENT); 2656 role_assign($creatorrole->id, $manager->id, $categorycontext); 2657 2658 $this->assertTrue(has_capability('moodle/course:view', $categorycontext, $manager)); 2659 $this->assertTrue(has_capability('moodle/course:view', $coursecontext, $manager)); 2660 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager)); 2661 $this->assertTrue(has_capability('moodle/role:assign', $coursecontext, $manager)); 2662 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager)); 2663 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager)); 2664 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager)); 2665 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager)); 2666 2667 role_change_permission($managerrole->id, $categorycontext, 'moodle/course:view', CAP_PREVENT); 2668 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager)); 2669 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager)); 2670 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager)); 2671 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager)); 2672 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager)); 2673 2674 $this->getDataGenerator()->enrol_user($manager->id, $course->id, 0); 2675 2676 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager)); 2677 $this->assertTrue(has_capability('moodle/role:assign', $coursecontext, $manager)); 2678 $this->assertTrue(is_enrolled($coursecontext, $manager)); 2679 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager)); 2680 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager)); 2681 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager)); 2682 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager)); 2683 2684 // Test problems. 2685 2686 try { 2687 guess_if_creator_will_have_course_capability('moodle/course:visibility', $syscontext, $creator); 2688 $this->fail('Exception expected when non course/category context passed to guess_if_creator_will_have_course_capability()'); 2689 } catch (moodle_exception $e) { 2690 $this->assertInstanceOf('coding_exception', $e); 2691 } 2692 } 2693 2694 /** 2695 * Test require_capability() exceptions. 2696 * 2697 * @covers ::require_capability 2698 */ 2699 public function test_require_capability() { 2700 $this->resetAfterTest(); 2701 2702 $syscontext = context_system::instance(); 2703 2704 $this->setUser(0); 2705 $this->assertFalse(has_capability('moodle/site:config', $syscontext)); 2706 try { 2707 require_capability('moodle/site:config', $syscontext); 2708 $this->fail('Exception expected from require_capability()'); 2709 } catch (moodle_exception $e) { 2710 $this->assertInstanceOf('required_capability_exception', $e); 2711 } 2712 $this->setAdminUser(); 2713 $this->assertFalse(has_capability('moodle/site:config', $syscontext, 0)); 2714 try { 2715 require_capability('moodle/site:config', $syscontext, 0); 2716 $this->fail('Exception expected from require_capability()'); 2717 } catch (moodle_exception $e) { 2718 $this->assertInstanceOf('required_capability_exception', $e); 2719 } 2720 $this->assertFalse(has_capability('moodle/site:config', $syscontext, null, false)); 2721 try { 2722 require_capability('moodle/site:config', $syscontext, null, false); 2723 $this->fail('Exception expected from require_capability()'); 2724 } catch (moodle_exception $e) { 2725 $this->assertInstanceOf('required_capability_exception', $e); 2726 } 2727 } 2728 2729 /** 2730 * Test that enrolled users SQL does not return any values for users in 2731 * other courses. 2732 * 2733 * 2734 * @covers ::get_enrolled_users 2735 * @covers ::get_enrolled_sql 2736 * @covers ::get_enrolled_with_capabilities_join 2737 * @covers ::get_enrolled_join 2738 * @covers ::get_with_capability_join 2739 * @covers ::groups_get_members_join 2740 * @covers ::get_suspended_userids 2741 */ 2742 public function test_get_enrolled_sql_different_course() { 2743 global $DB; 2744 2745 $this->resetAfterTest(); 2746 2747 $course = $this->getDataGenerator()->create_course(); 2748 $context = context_course::instance($course->id); 2749 $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 2750 $user = $this->getDataGenerator()->create_user(); 2751 2752 // This user should not appear anywhere, we're not interested in that context. 2753 $course2 = $this->getDataGenerator()->create_course(); 2754 $this->getDataGenerator()->enrol_user($user->id, $course2->id, $student->id); 2755 2756 $enrolled = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, false); 2757 $active = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, true); 2758 $suspended = get_suspended_userids($context); 2759 2760 $this->assertFalse(isset($enrolled[$user->id])); 2761 $this->assertFalse(isset($active[$user->id])); 2762 $this->assertFalse(isset($suspended[$user->id])); 2763 $this->assertCount(0, $enrolled); 2764 $this->assertCount(0, $active); 2765 $this->assertCount(0, $suspended); 2766 } 2767 2768 /** 2769 * Test that enrolled users SQL does not return any values for role 2770 * assignments without an enrolment. 2771 * 2772 * 2773 * @covers ::get_enrolled_users 2774 * @covers ::get_enrolled_sql 2775 * @covers ::get_enrolled_with_capabilities_join 2776 * @covers ::get_enrolled_join 2777 * @covers ::get_with_capability_join 2778 * @covers ::groups_get_members_join 2779 * @covers ::get_suspended_userids 2780 */ 2781 public function test_get_enrolled_sql_role_only() { 2782 global $DB; 2783 2784 $this->resetAfterTest(); 2785 2786 $course = $this->getDataGenerator()->create_course(); 2787 $context = context_course::instance($course->id); 2788 $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 2789 $user = $this->getDataGenerator()->create_user(); 2790 2791 // Role assignment is not the same as course enrollment. 2792 role_assign($student->id, $user->id, $context->id); 2793 2794 $enrolled = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, false); 2795 $active = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, true); 2796 $suspended = get_suspended_userids($context); 2797 2798 $this->assertFalse(isset($enrolled[$user->id])); 2799 $this->assertFalse(isset($active[$user->id])); 2800 $this->assertFalse(isset($suspended[$user->id])); 2801 $this->assertCount(0, $enrolled); 2802 $this->assertCount(0, $active); 2803 $this->assertCount(0, $suspended); 2804 } 2805 2806 /** 2807 * Test that multiple enrolments for the same user are counted correctly. 2808 * 2809 * @covers ::get_enrolled_users 2810 * @covers ::get_enrolled_sql 2811 * @covers ::get_enrolled_with_capabilities_join 2812 * @covers ::get_enrolled_join 2813 * @covers ::get_with_capability_join 2814 * @covers ::groups_get_members_join 2815 * @covers ::get_suspended_userids 2816 */ 2817 public function test_get_enrolled_sql_multiple_enrolments() { 2818 global $DB; 2819 2820 $this->resetAfterTest(); 2821 2822 $course = $this->getDataGenerator()->create_course(); 2823 $context = context_course::instance($course->id); 2824 $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 2825 $user = $this->getDataGenerator()->create_user(); 2826 2827 // Add a suspended enrol. 2828 $selfinstance = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'self')); 2829 $selfplugin = enrol_get_plugin('self'); 2830 $selfplugin->update_status($selfinstance, ENROL_INSTANCE_ENABLED); 2831 $this->getDataGenerator()->enrol_user($user->id, $course->id, $student->id, 'self', 0, 0, ENROL_USER_SUSPENDED); 2832 2833 // Should be enrolled, but not active - user is suspended. 2834 $enrolled = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, false); 2835 $active = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, true); 2836 $suspended = get_suspended_userids($context); 2837 2838 $this->assertTrue(isset($enrolled[$user->id])); 2839 $this->assertFalse(isset($active[$user->id])); 2840 $this->assertTrue(isset($suspended[$user->id])); 2841 $this->assertCount(1, $enrolled); 2842 $this->assertCount(0, $active); 2843 $this->assertCount(1, $suspended); 2844 2845 // Add an active enrol for the user. Any active enrol makes them enrolled. 2846 $this->getDataGenerator()->enrol_user($user->id, $course->id, $student->id); 2847 2848 // User should be active now. 2849 $enrolled = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, false); 2850 $active = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, true); 2851 $suspended = get_suspended_userids($context); 2852 2853 $this->assertTrue(isset($enrolled[$user->id])); 2854 $this->assertTrue(isset($active[$user->id])); 2855 $this->assertFalse(isset($suspended[$user->id])); 2856 $this->assertCount(1, $enrolled); 2857 $this->assertCount(1, $active); 2858 $this->assertCount(0, $suspended); 2859 2860 } 2861 2862 /** 2863 * Test that enrolled users returns only users in those groups that are 2864 * specified. 2865 * 2866 * @covers ::get_enrolled_users 2867 * @covers ::get_enrolled_sql 2868 * @covers ::get_enrolled_with_capabilities_join 2869 * @covers ::get_enrolled_join 2870 * @covers ::get_with_capability_join 2871 * @covers ::groups_get_members_join 2872 * @covers ::get_suspended_userids 2873 */ 2874 public function test_get_enrolled_sql_userswithgroups() { 2875 $this->resetAfterTest(); 2876 2877 $systemcontext = context_system::instance(); 2878 $course = $this->getDataGenerator()->create_course(); 2879 $coursecontext = context_course::instance($course->id); 2880 $user1 = $this->getDataGenerator()->create_user(); 2881 $user2 = $this->getDataGenerator()->create_user(); 2882 2883 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 2884 $this->getDataGenerator()->enrol_user($user2->id, $course->id); 2885 2886 $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 2887 groups_add_member($group1, $user1); 2888 $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 2889 groups_add_member($group2, $user2); 2890 2891 // Get user from group 1. 2892 $group1users = get_enrolled_users($coursecontext, '', $group1->id); 2893 $this->assertCount(1, $group1users); 2894 $this->assertArrayHasKey($user1->id, $group1users); 2895 $this->assertEquals(1, count_enrolled_users($coursecontext, '', $group1->id)); 2896 2897 // Get user from group 2. 2898 $group2users = get_enrolled_users($coursecontext, '', $group2->id); 2899 $this->assertCount(1, $group2users); 2900 $this->assertArrayHasKey($user2->id, $group2users); 2901 $this->assertEquals(1, count_enrolled_users($coursecontext, '', $group2->id)); 2902 2903 // Get users from multiple groups. 2904 $groupusers = get_enrolled_users($coursecontext, '', [$group1->id, $group2->id]); 2905 $this->assertCount(2, $groupusers); 2906 $this->assertArrayHasKey($user1->id, $groupusers); 2907 $this->assertArrayHasKey($user2->id, $groupusers); 2908 $this->assertEquals(2, count_enrolled_users($coursecontext, '', [$group1->id, $group2->id])); 2909 } 2910 2911 /** 2912 * Test that enrolled users SQL does not return any values for users 2913 * without a group when $context is not a valid course context. 2914 * 2915 * @covers ::get_enrolled_users 2916 * @covers ::get_enrolled_sql 2917 * @covers ::get_enrolled_with_capabilities_join 2918 * @covers ::get_enrolled_join 2919 * @covers ::get_with_capability_join 2920 * @covers ::groups_get_members_join 2921 * @covers ::get_suspended_userids 2922 */ 2923 public function test_get_enrolled_sql_userswithoutgroup() { 2924 global $DB; 2925 2926 $this->resetAfterTest(); 2927 2928 $systemcontext = context_system::instance(); 2929 $course = $this->getDataGenerator()->create_course(); 2930 $coursecontext = context_course::instance($course->id); 2931 $user1 = $this->getDataGenerator()->create_user(); 2932 $user2 = $this->getDataGenerator()->create_user(); 2933 2934 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 2935 $this->getDataGenerator()->enrol_user($user2->id, $course->id); 2936 2937 $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 2938 groups_add_member($group, $user1); 2939 2940 $enrolled = get_enrolled_users($coursecontext); 2941 $this->assertCount(2, $enrolled); 2942 2943 // Get users without any group on the course context. 2944 $enrolledwithoutgroup = get_enrolled_users($coursecontext, '', USERSWITHOUTGROUP); 2945 $this->assertCount(1, $enrolledwithoutgroup); 2946 $this->assertFalse(isset($enrolledwithoutgroup[$user1->id])); 2947 2948 // Get users without any group on the system context (it should throw an exception). 2949 $this->expectException('coding_exception'); 2950 get_enrolled_users($systemcontext, '', USERSWITHOUTGROUP); 2951 } 2952 2953 /** 2954 * Test that enrolled users returns only users in those groups that are 2955 * specified, and they are allowed to see members of. 2956 * 2957 * @covers ::get_enrolled_users 2958 * @covers ::get_enrolled_sql 2959 * @covers ::get_enrolled_with_capabilities_join 2960 * @covers ::get_enrolled_join 2961 * @covers ::get_with_capability_join 2962 * @covers ::groups_get_members_join 2963 * @covers ::get_suspended_userids 2964 */ 2965 public function test_get_enrolled_sql_userswithhiddengroups() { 2966 $this->resetAfterTest(); 2967 2968 $course = $this->getDataGenerator()->create_course(); 2969 $coursecontext = context_course::instance($course->id); 2970 $user1 = $this->getDataGenerator()->create_user(); 2971 $user2 = $this->getDataGenerator()->create_user(); 2972 $user3 = $this->getDataGenerator()->create_user(); 2973 $user4 = $this->getDataGenerator()->create_user(); 2974 $user5 = $this->getDataGenerator()->create_user(); 2975 $user6 = $this->getDataGenerator()->create_user(); 2976 2977 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 2978 $this->getDataGenerator()->enrol_user($user2->id, $course->id); 2979 $this->getDataGenerator()->enrol_user($user3->id, $course->id); 2980 $this->getDataGenerator()->enrol_user($user4->id, $course->id); 2981 $this->getDataGenerator()->enrol_user($user5->id, $course->id); 2982 $this->getDataGenerator()->enrol_user($user6->id, $course->id); 2983 2984 $group1 = $this->getDataGenerator()->create_group([ 2985 'courseid' => $course->id, 2986 'visibility' => GROUPS_VISIBILITY_ALL, 2987 ]); 2988 groups_add_member($group1, $user1); 2989 $group2 = $this->getDataGenerator()->create_group([ 2990 'courseid' => $course->id, 2991 'visibility' => GROUPS_VISIBILITY_MEMBERS, 2992 ]); 2993 groups_add_member($group2, $user2); 2994 groups_add_member($group2, $user5); 2995 $group3 = $this->getDataGenerator()->create_group([ 2996 'courseid' => $course->id, 2997 'visibility' => GROUPS_VISIBILITY_OWN, 2998 ]); 2999 groups_add_member($group3, $user3); 3000 groups_add_member($group3, $user6); 3001 $group4 = $this->getDataGenerator()->create_group([ 3002 'courseid' => $course->id, 3003 'visibility' => GROUPS_VISIBILITY_NONE, 3004 ]); 3005 groups_add_member($group4, $user4); 3006 3007 $groupids = [$group1->id, $group2->id, $group3->id, $group4->id]; 3008 // User 1 can only see members of Group 1. 3009 $this->setUser($user1); 3010 $user1groupusers = get_enrolled_users($coursecontext, '', $groupids); 3011 $this->assertCount(1, $user1groupusers); 3012 $this->assertArrayHasKey($user1->id, $user1groupusers); 3013 $this->assertEquals(1, count_enrolled_users($coursecontext, '', $groupids)); 3014 // User 2 can see all members of Group 1 and Group 2. 3015 $this->setUser($user2); 3016 $user2groupusers = get_enrolled_users($coursecontext, '', $groupids); 3017 $this->assertCount(3, $user2groupusers); 3018 $this->assertArrayHasKey($user1->id, $user2groupusers); 3019 $this->assertArrayHasKey($user2->id, $user2groupusers); 3020 $this->assertArrayHasKey($user5->id, $user2groupusers); 3021 $this->assertEquals(3, count_enrolled_users($coursecontext, '', $groupids)); 3022 // User 3 can see members of Group 1, and themselves in Group 3 but not other members. 3023 $this->setUser($user3); 3024 $user3groupusers = get_enrolled_users($coursecontext, '', $groupids); 3025 $this->assertCount(2, $user3groupusers); 3026 $this->assertArrayHasKey($user1->id, $user3groupusers); 3027 $this->assertArrayHasKey($user3->id, $user3groupusers); 3028 $this->assertEquals(2, count_enrolled_users($coursecontext, '', $groupids)); 3029 // User 4 can only see members of Group 1. 3030 $this->setUser($user4); 3031 $user4groupusers = get_enrolled_users($coursecontext, '', $groupids); 3032 $this->assertCount(1, $user4groupusers); 3033 $this->assertArrayHasKey($user1->id, $user4groupusers); 3034 $this->assertEquals(1, count_enrolled_users($coursecontext, '', $groupids)); 3035 } 3036 3037 public function get_enrolled_sql_provider() { 3038 return array( 3039 array( 3040 // Two users who are enrolled. 3041 'users' => array( 3042 array( 3043 'enrolled' => true, 3044 'active' => true, 3045 ), 3046 array( 3047 'enrolled' => true, 3048 'active' => true, 3049 ), 3050 ), 3051 'counts' => array( 3052 'enrolled' => 2, 3053 'active' => 2, 3054 'suspended' => 0, 3055 ), 3056 ), 3057 array( 3058 // A user who is suspended. 3059 'users' => array( 3060 array( 3061 'status' => ENROL_USER_SUSPENDED, 3062 'enrolled' => true, 3063 'suspended' => true, 3064 ), 3065 ), 3066 'counts' => array( 3067 'enrolled' => 1, 3068 'active' => 0, 3069 'suspended' => 1, 3070 ), 3071 ), 3072 array( 3073 // One of each. 3074 'users' => array( 3075 array( 3076 'enrolled' => true, 3077 'active' => true, 3078 ), 3079 array( 3080 'status' => ENROL_USER_SUSPENDED, 3081 'enrolled' => true, 3082 'suspended' => true, 3083 ), 3084 ), 3085 'counts' => array( 3086 'enrolled' => 2, 3087 'active' => 1, 3088 'suspended' => 1, 3089 ), 3090 ), 3091 array( 3092 // One user who is not yet enrolled. 3093 'users' => array( 3094 array( 3095 'timestart' => DAYSECS, 3096 'enrolled' => true, 3097 'active' => false, 3098 'suspended' => true, 3099 ), 3100 ), 3101 'counts' => array( 3102 'enrolled' => 1, 3103 'active' => 0, 3104 'suspended' => 1, 3105 ), 3106 ), 3107 array( 3108 // One user who is no longer enrolled 3109 'users' => array( 3110 array( 3111 'timeend' => -DAYSECS, 3112 'enrolled' => true, 3113 'active' => false, 3114 'suspended' => true, 3115 ), 3116 ), 3117 'counts' => array( 3118 'enrolled' => 1, 3119 'active' => 0, 3120 'suspended' => 1, 3121 ), 3122 ), 3123 array( 3124 // One user who is not yet enrolled, and one who is no longer enrolled. 3125 'users' => array( 3126 array( 3127 'timeend' => -DAYSECS, 3128 'enrolled' => true, 3129 'active' => false, 3130 'suspended' => true, 3131 ), 3132 array( 3133 'timestart' => DAYSECS, 3134 'enrolled' => true, 3135 'active' => false, 3136 'suspended' => true, 3137 ), 3138 ), 3139 'counts' => array( 3140 'enrolled' => 2, 3141 'active' => 0, 3142 'suspended' => 2, 3143 ), 3144 ), 3145 ); 3146 } 3147 3148 /** 3149 * @dataProvider get_enrolled_sql_provider 3150 * @covers ::get_enrolled_users 3151 * @covers ::get_suspended_userids 3152 */ 3153 public function test_get_enrolled_sql_course($users, $counts) { 3154 global $DB; 3155 3156 $this->resetAfterTest(); 3157 3158 $course = $this->getDataGenerator()->create_course(); 3159 $context = context_course::instance($course->id); 3160 $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 3161 $createdusers = array(); 3162 3163 foreach ($users as &$userdata) { 3164 $user = $this->getDataGenerator()->create_user(); 3165 $userdata['id'] = $user->id; 3166 3167 $timestart = 0; 3168 $timeend = 0; 3169 $status = null; 3170 if (isset($userdata['timestart'])) { 3171 $timestart = time() + $userdata['timestart']; 3172 } 3173 if (isset($userdata['timeend'])) { 3174 $timeend = time() + $userdata['timeend']; 3175 } 3176 if (isset($userdata['status'])) { 3177 $status = $userdata['status']; 3178 } 3179 3180 // Enrol the user in the course. 3181 $this->getDataGenerator()->enrol_user($user->id, $course->id, $student->id, 'manual', $timestart, $timeend, $status); 3182 } 3183 3184 // After all users have been enroled, check expectations. 3185 $enrolled = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, false); 3186 $active = get_enrolled_users($context, '', 0, 'u.id', null, 0, 0, true); 3187 $suspended = get_suspended_userids($context); 3188 3189 foreach ($users as $userdata) { 3190 if (isset($userdata['enrolled']) && $userdata['enrolled']) { 3191 $this->assertTrue(isset($enrolled[$userdata['id']])); 3192 } else { 3193 $this->assertFalse(isset($enrolled[$userdata['id']])); 3194 } 3195 3196 if (isset($userdata['active']) && $userdata['active']) { 3197 $this->assertTrue(isset($active[$userdata['id']])); 3198 } else { 3199 $this->assertFalse(isset($active[$userdata['id']])); 3200 } 3201 3202 if (isset($userdata['suspended']) && $userdata['suspended']) { 3203 $this->assertTrue(isset($suspended[$userdata['id']])); 3204 } else { 3205 $this->assertFalse(isset($suspended[$userdata['id']])); 3206 } 3207 } 3208 3209 $this->assertCount($counts['enrolled'], $enrolled); 3210 $this->assertCount($counts['active'], $active); 3211 $this->assertCount($counts['suspended'], $suspended); 3212 } 3213 3214 /** 3215 * A small functional test of permission evaluations. 3216 */ 3217 public function test_permission_evaluation() { 3218 global $USER, $SITE, $CFG, $DB, $ACCESSLIB_PRIVATE; 3219 3220 $this->resetAfterTest(); 3221 3222 $generator = $this->getDataGenerator(); 3223 3224 // Fill the site with some real data. 3225 $testcategories = array(); 3226 $testcourses = array(); 3227 $testpages = array(); 3228 $testblocks = array(); 3229 $allroles = $DB->get_records_menu('role', array(), 'id', 'shortname, id'); 3230 3231 $systemcontext = context_system::instance(); 3232 $frontpagecontext = context_course::instance(SITEID); 3233 3234 // Add block to system context. 3235 $bi = $generator->create_block('online_users'); 3236 context_block::instance($bi->id); 3237 $testblocks[] = $bi->id; 3238 3239 // Some users. 3240 $testusers = array(); 3241 for ($i=0; $i<20; $i++) { 3242 $user = $generator->create_user(); 3243 $testusers[$i] = $user->id; 3244 $usercontext = context_user::instance($user->id); 3245 3246 // Add block to user profile. 3247 $bi = $generator->create_block('online_users', array('parentcontextid'=>$usercontext->id)); 3248 $testblocks[] = $bi->id; 3249 } 3250 3251 // Add block to frontpage. 3252 $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagecontext->id)); 3253 $frontpageblockcontext = context_block::instance($bi->id); 3254 $testblocks[] = $bi->id; 3255 3256 // Add a resource to frontpage. 3257 $page = $generator->create_module('page', array('course'=>$SITE->id)); 3258 $testpages[] = $page->cmid; 3259 $frontpagepagecontext = context_module::instance($page->cmid); 3260 3261 // Add block to frontpage resource. 3262 $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagepagecontext->id)); 3263 $frontpagepageblockcontext = context_block::instance($bi->id); 3264 $testblocks[] = $bi->id; 3265 3266 // Some nested course categories with courses. 3267 $manualenrol = enrol_get_plugin('manual'); 3268 $parentcat = 0; 3269 for ($i=0; $i<5; $i++) { 3270 $cat = $generator->create_category(array('parent'=>$parentcat)); 3271 $testcategories[] = $cat->id; 3272 $catcontext = context_coursecat::instance($cat->id); 3273 $parentcat = $cat->id; 3274 3275 if ($i >= 4) { 3276 continue; 3277 } 3278 3279 // Add resource to each category. 3280 $bi = $generator->create_block('online_users', array('parentcontextid'=>$catcontext->id)); 3281 context_block::instance($bi->id); 3282 3283 // Add a few courses to each category. 3284 for ($j=0; $j<6; $j++) { 3285 $course = $generator->create_course(array('category'=>$cat->id)); 3286 $testcourses[] = $course->id; 3287 $coursecontext = context_course::instance($course->id); 3288 3289 if ($j >= 5) { 3290 continue; 3291 } 3292 // Add manual enrol instance. 3293 $manualenrol->add_default_instance($DB->get_record('course', array('id'=>$course->id))); 3294 3295 // Add block to each course. 3296 $bi = $generator->create_block('online_users', array('parentcontextid'=>$coursecontext->id)); 3297 $testblocks[] = $bi->id; 3298 3299 // Add a resource to each course. 3300 $page = $generator->create_module('page', array('course'=>$course->id)); 3301 $testpages[] = $page->cmid; 3302 $modcontext = context_module::instance($page->cmid); 3303 3304 // Add block to each module. 3305 $bi = $generator->create_block('online_users', array('parentcontextid'=>$modcontext->id)); 3306 $testblocks[] = $bi->id; 3307 } 3308 } 3309 3310 // Make sure all contexts were created properly. 3311 $count = 1; // System. 3312 $count += $DB->count_records('user', array('deleted'=>0)); 3313 $count += $DB->count_records('course_categories'); 3314 $count += $DB->count_records('course'); 3315 $count += $DB->count_records('course_modules'); 3316 $count += $DB->count_records('block_instances'); 3317 $this->assertEquals($count, $DB->count_records('context')); 3318 $this->assertEquals(0, $DB->count_records('context', array('depth'=>0))); 3319 $this->assertEquals(0, $DB->count_records('context', array('path'=>null))); 3320 3321 3322 // Test context_helper::get_level_name() method. 3323 3324 $levels = context_helper::get_all_levels(); 3325 foreach ($levels as $level => $classname) { 3326 $name = context_helper::get_level_name($level); 3327 $this->assertNotEmpty($name); 3328 } 3329 3330 3331 // Test context::instance_by_id(), context_xxx::instance() methods. 3332 3333 $context = context::instance_by_id($frontpagecontext->id); 3334 $this->assertSame(CONTEXT_COURSE, $context->contextlevel); 3335 $this->assertFalse(context::instance_by_id(-1, IGNORE_MISSING)); 3336 try { 3337 context::instance_by_id(-1); 3338 $this->fail('exception expected'); 3339 } catch (moodle_exception $e) { 3340 $this->assertTrue(true); 3341 } 3342 $this->assertInstanceOf('context_system', context_system::instance()); 3343 $this->assertInstanceOf('context_coursecat', context_coursecat::instance($testcategories[0])); 3344 $this->assertInstanceOf('context_course', context_course::instance($testcourses[0])); 3345 $this->assertInstanceOf('context_module', context_module::instance($testpages[0])); 3346 $this->assertInstanceOf('context_block', context_block::instance($testblocks[0])); 3347 3348 $this->assertFalse(context_coursecat::instance(-1, IGNORE_MISSING)); 3349 $this->assertFalse(context_course::instance(-1, IGNORE_MISSING)); 3350 $this->assertFalse(context_module::instance(-1, IGNORE_MISSING)); 3351 $this->assertFalse(context_block::instance(-1, IGNORE_MISSING)); 3352 try { 3353 context_coursecat::instance(-1); 3354 $this->fail('exception expected'); 3355 } catch (moodle_exception $e) { 3356 $this->assertTrue(true); 3357 } 3358 try { 3359 context_course::instance(-1); 3360 $this->fail('exception expected'); 3361 } catch (moodle_exception $e) { 3362 $this->assertTrue(true); 3363 } 3364 try { 3365 context_module::instance(-1); 3366 $this->fail('exception expected'); 3367 } catch (moodle_exception $e) { 3368 $this->assertTrue(true); 3369 } 3370 try { 3371 context_block::instance(-1); 3372 $this->fail('exception expected'); 3373 } catch (moodle_exception $e) { 3374 $this->assertTrue(true); 3375 } 3376 3377 3378 // Test $context->get_url(), $context->get_context_name(), $context->get_capabilities() methods. 3379 3380 $testcontexts = array(); 3381 $testcontexts[CONTEXT_SYSTEM] = context_system::instance(); 3382 $testcontexts[CONTEXT_COURSECAT] = context_coursecat::instance($testcategories[0]); 3383 $testcontexts[CONTEXT_COURSE] = context_course::instance($testcourses[0]); 3384 $testcontexts[CONTEXT_MODULE] = context_module::instance($testpages[0]); 3385 $testcontexts[CONTEXT_BLOCK] = context_block::instance($testblocks[0]); 3386 3387 foreach ($testcontexts as $context) { 3388 $name = $context->get_context_name(true, true); 3389 $this->assertNotEmpty($name); 3390 3391 $this->assertInstanceOf('moodle_url', $context->get_url()); 3392 3393 $caps = $context->get_capabilities(); 3394 $this->assertTrue(is_array($caps)); 3395 foreach ($caps as $cap) { 3396 $cap = (array)$cap; 3397 $this->assertSame(array_keys($cap), array('id', 'name', 'captype', 'contextlevel', 'component', 'riskbitmask')); 3398 } 3399 } 3400 unset($testcontexts); 3401 3402 // Test $context->get_course_context() method. 3403 3404 $this->assertFalse($systemcontext->get_course_context(false)); 3405 try { 3406 $systemcontext->get_course_context(); 3407 $this->fail('exception expected'); 3408 } catch (moodle_exception $e) { 3409 $this->assertInstanceOf('coding_exception', $e); 3410 } 3411 $context = context_coursecat::instance($testcategories[0]); 3412 $this->assertFalse($context->get_course_context(false)); 3413 try { 3414 $context->get_course_context(); 3415 $this->fail('exception expected'); 3416 } catch (moodle_exception $e) { 3417 $this->assertInstanceOf('coding_exception', $e); 3418 } 3419 $this->assertEquals($frontpagecontext, $frontpagecontext->get_course_context(true)); 3420 $this->assertEquals($frontpagecontext, $frontpagepagecontext->get_course_context(true)); 3421 $this->assertEquals($frontpagecontext, $frontpagepageblockcontext->get_course_context(true)); 3422 3423 3424 // Test $context->get_parent_context(), $context->get_parent_contexts(), $context->get_parent_context_ids() methods. 3425 3426 $userid = reset($testusers); 3427 $usercontext = context_user::instance($userid); 3428 $this->assertEquals($systemcontext, $usercontext->get_parent_context()); 3429 $this->assertEquals(array($systemcontext->id=>$systemcontext), $usercontext->get_parent_contexts()); 3430 $this->assertEquals(array($usercontext->id=>$usercontext, $systemcontext->id=>$systemcontext), $usercontext->get_parent_contexts(true)); 3431 3432 $this->assertEquals(array(), $systemcontext->get_parent_contexts()); 3433 $this->assertEquals(array($systemcontext->id=>$systemcontext), $systemcontext->get_parent_contexts(true)); 3434 $this->assertEquals(array(), $systemcontext->get_parent_context_ids()); 3435 $this->assertEquals(array($systemcontext->id), $systemcontext->get_parent_context_ids(true)); 3436 $this->assertEquals(array(), $systemcontext->get_parent_context_paths()); 3437 $this->assertEquals(array($systemcontext->id => $systemcontext->path), $systemcontext->get_parent_context_paths(true)); 3438 3439 $this->assertEquals($systemcontext, $frontpagecontext->get_parent_context()); 3440 $this->assertEquals(array($systemcontext->id=>$systemcontext), $frontpagecontext->get_parent_contexts()); 3441 $this->assertEquals(array($frontpagecontext->id=>$frontpagecontext, $systemcontext->id=>$systemcontext), $frontpagecontext->get_parent_contexts(true)); 3442 $this->assertEquals(array($systemcontext->id), $frontpagecontext->get_parent_context_ids()); 3443 $this->assertEquals(array($frontpagecontext->id, $systemcontext->id), $frontpagecontext->get_parent_context_ids(true)); 3444 $this->assertEquals(array($systemcontext->id => $systemcontext->path), $frontpagecontext->get_parent_context_paths()); 3445 $expected = array($systemcontext->id => $systemcontext->path, $frontpagecontext->id => $frontpagecontext->path); 3446 $this->assertEquals($expected, $frontpagecontext->get_parent_context_paths(true)); 3447 3448 $this->assertFalse($systemcontext->get_parent_context()); 3449 $frontpagecontext = context_course::instance($SITE->id); 3450 $parent = $systemcontext; 3451 foreach ($testcategories as $catid) { 3452 $catcontext = context_coursecat::instance($catid); 3453 $this->assertEquals($parent, $catcontext->get_parent_context()); 3454 $parent = $catcontext; 3455 } 3456 $this->assertEquals($frontpagecontext, $frontpagepagecontext->get_parent_context()); 3457 $this->assertEquals($frontpagecontext, $frontpageblockcontext->get_parent_context()); 3458 $this->assertEquals($frontpagepagecontext, $frontpagepageblockcontext->get_parent_context()); 3459 3460 3461 // Test $context->get_child_contexts() method. 3462 3463 $children = $systemcontext->get_child_contexts(); 3464 $this->resetDebugging(); 3465 $this->assertEquals(count($children)+1, $DB->count_records('context')); 3466 3467 $context = context_coursecat::instance($testcategories[3]); 3468 $children = $context->get_child_contexts(); 3469 $countcats = 0; 3470 $countcourses = 0; 3471 $countblocks = 0; 3472 foreach ($children as $child) { 3473 if ($child->contextlevel == CONTEXT_COURSECAT) { 3474 $countcats++; 3475 } 3476 if ($child->contextlevel == CONTEXT_COURSE) { 3477 $countcourses++; 3478 } 3479 if ($child->contextlevel == CONTEXT_BLOCK) { 3480 $countblocks++; 3481 } 3482 } 3483 $this->assertCount(8, $children); 3484 $this->assertEquals(1, $countcats); 3485 $this->assertEquals(6, $countcourses); 3486 $this->assertEquals(1, $countblocks); 3487 3488 $context = context_course::instance($testcourses[2]); 3489 $children = $context->get_child_contexts(); 3490 3491 $context = context_module::instance($testpages[3]); 3492 $children = $context->get_child_contexts(); 3493 $this->assertCount(1, $children); 3494 3495 $context = context_block::instance($testblocks[1]); 3496 $children = $context->get_child_contexts(); 3497 $this->assertCount(0, $children); 3498 3499 unset($children); 3500 unset($countcats); 3501 unset($countcourses); 3502 unset($countblocks); 3503 3504 3505 // Test context_helper::reset_caches() method. 3506 3507 context_helper::reset_caches(); 3508 $this->assertEquals(0, context_inspection::test_context_cache_size()); 3509 context_course::instance($SITE->id); 3510 $this->assertEquals(1, context_inspection::test_context_cache_size()); 3511 3512 3513 // Test context preloading. 3514 3515 context_helper::reset_caches(); 3516 $sql = "SELECT ".context_helper::get_preload_record_columns_sql('c')." 3517 FROM {context} c 3518 WHERE c.contextlevel <> ".CONTEXT_SYSTEM; 3519 $records = $DB->get_records_sql($sql); 3520 $firstrecord = reset($records); 3521 $columns = context_helper::get_preload_record_columns('c'); 3522 $firstrecord = (array)$firstrecord; 3523 $this->assertSame(array_keys($firstrecord), array_values($columns)); 3524 context_helper::reset_caches(); 3525 foreach ($records as $record) { 3526 context_helper::preload_from_record($record); 3527 $this->assertEquals(new stdClass(), $record); 3528 } 3529 $this->assertEquals(count($records), context_inspection::test_context_cache_size()); 3530 unset($records); 3531 unset($columns); 3532 3533 context_helper::reset_caches(); 3534 context_helper::preload_course($SITE->id); 3535 $numfrontpagemodules = $DB->count_records('course_modules', array('course' => $SITE->id)); 3536 $this->assertEquals(3 + $numfrontpagemodules, context_inspection::test_context_cache_size()); // Depends on number of default blocks. 3537 3538 // Test assign_capability(), unassign_capability() functions. 3539 3540 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); 3541 $this->assertFalse($rc); 3542 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext->id); 3543 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); 3544 $this->assertEquals(CAP_ALLOW, $rc->permission); 3545 assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext->id); 3546 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); 3547 $this->assertEquals(CAP_ALLOW, $rc->permission); 3548 assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext, true); 3549 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); 3550 $this->assertEquals(CAP_PREVENT, $rc->permission); 3551 3552 assign_capability('moodle/site:accessallgroups', CAP_INHERIT, $allroles['teacher'], $frontpagecontext); 3553 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); 3554 $this->assertFalse($rc); 3555 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext); 3556 unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext, true); 3557 $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); 3558 $this->assertFalse($rc); 3559 unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext->id, true); 3560 unset($rc); 3561 3562 accesslib_clear_all_caches_for_unit_testing(); // Must be done after assign_capability(). 3563 3564 3565 // Test role_assign(), role_unassign(), role_unassign_all() functions. 3566 3567 $context = context_course::instance($testcourses[1]); 3568 $this->assertEquals(0, $DB->count_records('role_assignments', array('contextid'=>$context->id))); 3569 role_assign($allroles['teacher'], $testusers[1], $context->id); 3570 role_assign($allroles['teacher'], $testusers[2], $context->id); 3571 role_assign($allroles['manager'], $testusers[1], $context->id); 3572 $this->assertEquals(3, $DB->count_records('role_assignments', array('contextid'=>$context->id))); 3573 role_unassign($allroles['teacher'], $testusers[1], $context->id); 3574 $this->assertEquals(2, $DB->count_records('role_assignments', array('contextid'=>$context->id))); 3575 role_unassign_all(array('contextid'=>$context->id)); 3576 $this->assertEquals(0, $DB->count_records('role_assignments', array('contextid'=>$context->id))); 3577 unset($context); 3578 3579 accesslib_clear_all_caches_for_unit_testing(); // Just in case. 3580 3581 3582 // Test has_capability(), get_users_by_capability(), role_switch(), reload_all_capabilities() and friends functions. 3583 3584 $adminid = get_admin()->id; 3585 $guestid = $CFG->siteguest; 3586 3587 // Enrol some users into some courses. 3588 $course1 = $DB->get_record('course', array('id'=>$testcourses[22]), '*', MUST_EXIST); 3589 $course2 = $DB->get_record('course', array('id'=>$testcourses[7]), '*', MUST_EXIST); 3590 $cms = $DB->get_records('course_modules', array('course'=>$course1->id), 'id'); 3591 $cm1 = reset($cms); 3592 $blocks = $DB->get_records('block_instances', array('parentcontextid'=>context_module::instance($cm1->id)->id), 'id'); 3593 $block1 = reset($blocks); 3594 $instance1 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course1->id)); 3595 $instance2 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course2->id)); 3596 for ($i=0; $i<9; $i++) { 3597 $manualenrol->enrol_user($instance1, $testusers[$i], $allroles['student']); 3598 } 3599 $manualenrol->enrol_user($instance1, $testusers[8], $allroles['teacher']); 3600 $manualenrol->enrol_user($instance1, $testusers[9], $allroles['editingteacher']); 3601 3602 for ($i=10; $i<15; $i++) { 3603 $manualenrol->enrol_user($instance2, $testusers[$i], $allroles['student']); 3604 } 3605 $manualenrol->enrol_user($instance2, $testusers[15], $allroles['editingteacher']); 3606 3607 // Add tons of role assignments - the more the better. 3608 role_assign($allroles['coursecreator'], $testusers[11], context_coursecat::instance($testcategories[2])); 3609 role_assign($allroles['manager'], $testusers[12], context_coursecat::instance($testcategories[1])); 3610 role_assign($allroles['student'], $testusers[9], context_module::instance($cm1->id)); 3611 role_assign($allroles['teacher'], $testusers[8], context_module::instance($cm1->id)); 3612 role_assign($allroles['guest'], $testusers[13], context_course::instance($course1->id)); 3613 role_assign($allroles['teacher'], $testusers[7], context_block::instance($block1->id)); 3614 role_assign($allroles['manager'], $testusers[9], context_block::instance($block1->id)); 3615 role_assign($allroles['editingteacher'], $testusers[9], context_course::instance($course1->id)); 3616 3617 role_assign($allroles['teacher'], $adminid, context_course::instance($course1->id)); 3618 role_assign($allroles['editingteacher'], $adminid, context_block::instance($block1->id)); 3619 3620 // Add tons of overrides - the more the better. 3621 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpageblockcontext, true); 3622 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpageblockcontext, true); 3623 assign_capability('moodle/block:view', CAP_PROHIBIT, $allroles['guest'], $frontpageblockcontext, true); 3624 assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['user'], $frontpageblockcontext, true); 3625 assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['student'], $frontpageblockcontext, true); 3626 3627 assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $CFG->defaultuserroleid, $frontpagepagecontext, true); 3628 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagepagecontext, true); 3629 assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $frontpagepagecontext, true); 3630 assign_capability('mod/page:view', CAP_ALLOW, $allroles['user'], $frontpagepagecontext, true); 3631 assign_capability('mod/page:view', CAP_ALLOW, $allroles['student'], $frontpagepagecontext, true); 3632 3633 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpagecontext, true); 3634 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext, true); 3635 assign_capability('mod/page:view', CAP_ALLOW, $allroles['guest'], $frontpagecontext, true); 3636 assign_capability('mod/page:view', CAP_PROHIBIT, $allroles['user'], $frontpagecontext, true); 3637 3638 assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $systemcontext, true); 3639 3640 // Prepare for prohibit test. 3641 role_assign($allroles['editingteacher'], $testusers[19], context_system::instance()); 3642 role_assign($allroles['teacher'], $testusers[19], context_course::instance($testcourses[17])); 3643 role_assign($allroles['editingteacher'], $testusers[19], context_course::instance($testcourses[17])); 3644 assign_capability('moodle/course:update', CAP_PROHIBIT, $allroles['teacher'], context_course::instance($testcourses[17]), true); 3645 3646 accesslib_clear_all_caches_for_unit_testing(); /// Must be done after assign_capability(). 3647 3648 // Extra tests for guests and not-logged-in users because they can not be verified by cross checking 3649 // with get_users_by_capability() where they are ignored. 3650 $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, $guestid)); 3651 $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, $guestid)); 3652 $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, $guestid)); 3653 $this->assertFalse(has_capability('mod/page:view', $systemcontext, $guestid)); 3654 3655 $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, 0)); 3656 $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, 0)); 3657 $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, 0)); 3658 $this->assertFalse(has_capability('mod/page:view', $systemcontext, 0)); 3659 3660 $this->assertFalse(has_capability('moodle/course:create', $systemcontext, $testusers[11])); 3661 $this->assertTrue(has_capability('moodle/course:create', context_coursecat::instance($testcategories[2]), $testusers[11])); 3662 $this->assertFalse(has_capability('moodle/course:create', context_course::instance($testcourses[1]), $testusers[11])); 3663 $this->assertTrue(has_capability('moodle/course:create', context_course::instance($testcourses[19]), $testusers[11])); 3664 3665 $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[1]), $testusers[9])); 3666 $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[19]), $testusers[9])); 3667 $this->assertFalse(has_capability('moodle/course:update', $systemcontext, $testusers[9])); 3668 3669 // Test prohibits. 3670 $this->assertTrue(has_capability('moodle/course:update', context_system::instance(), $testusers[19])); 3671 $ids = get_users_by_capability(context_system::instance(), 'moodle/course:update', 'u.id'); 3672 $this->assertArrayHasKey($testusers[19], $ids); 3673 $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[17]), $testusers[19])); 3674 $ids = get_users_by_capability(context_course::instance($testcourses[17]), 'moodle/course:update', 'u.id'); 3675 $this->assertArrayNotHasKey($testusers[19], $ids); 3676 3677 // Test the list of enrolled users. 3678 $coursecontext = context_course::instance($course1->id); 3679 $enrolled = get_enrolled_users($coursecontext); 3680 $this->assertCount(10, $enrolled); 3681 for ($i=0; $i<10; $i++) { 3682 $this->assertTrue(isset($enrolled[$testusers[$i]])); 3683 } 3684 $enrolled = get_enrolled_users($coursecontext, 'moodle/course:update'); 3685 $this->assertCount(1, $enrolled); 3686 $this->assertTrue(isset($enrolled[$testusers[9]])); 3687 unset($enrolled); 3688 3689 // Role switching. 3690 $userid = $testusers[9]; 3691 $USER = $DB->get_record('user', array('id'=>$userid)); 3692 load_all_capabilities(); 3693 $coursecontext = context_course::instance($course1->id); 3694 $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); 3695 $this->assertFalse(is_role_switched($course1->id)); 3696 role_switch($allroles['student'], $coursecontext); 3697 $this->assertTrue(is_role_switched($course1->id)); 3698 $this->assertEquals($allroles['student'], $USER->access['rsw'][$coursecontext->path]); 3699 $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); 3700 reload_all_capabilities(); 3701 $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); 3702 role_switch(0, $coursecontext); 3703 $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); 3704 $userid = $adminid; 3705 $USER = $DB->get_record('user', array('id'=>$userid)); 3706 load_all_capabilities(); 3707 $coursecontext = context_course::instance($course1->id); 3708 $blockcontext = context_block::instance($block1->id); 3709 $this->assertTrue(has_capability('moodle/course:update', $blockcontext)); 3710 role_switch($allroles['student'], $coursecontext); 3711 $this->assertEquals($allroles['student'], $USER->access['rsw'][$coursecontext->path]); 3712 $this->assertFalse(has_capability('moodle/course:update', $blockcontext)); 3713 reload_all_capabilities(); 3714 $this->assertFalse(has_capability('moodle/course:update', $blockcontext)); 3715 load_all_capabilities(); 3716 $this->assertTrue(has_capability('moodle/course:update', $blockcontext)); 3717 3718 // Temp course role for enrol. 3719 $DB->delete_records('cache_flags', array()); // This prevents problem with dirty contexts immediately resetting the temp role - this is a known problem... 3720 $userid = $testusers[5]; 3721 $roleid = $allroles['editingteacher']; 3722 $USER = $DB->get_record('user', array('id'=>$userid)); 3723 load_all_capabilities(); 3724 $coursecontext = context_course::instance($course1->id); 3725 $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); 3726 $this->assertFalse(isset($USER->access['ra'][$coursecontext->path][$roleid])); 3727 load_temp_course_role($coursecontext, $roleid); 3728 $this->assertEquals($USER->access['ra'][$coursecontext->path][$roleid], $roleid); 3729 $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); 3730 remove_temp_course_roles($coursecontext); 3731 $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid)); 3732 load_temp_course_role($coursecontext, $roleid); 3733 reload_all_capabilities(); 3734 $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid)); 3735 $USER = new stdClass(); 3736 $USER->id = 0; 3737 3738 // Now cross check has_capability() with get_users_by_capability(), each using different code paths, 3739 // they have to be kept in sync, usually only one of them breaks, so we know when something is wrong, 3740 // at the same time validate extra restrictions (guest read only no risks, admin exception, non existent and deleted users). 3741 $contexts = $DB->get_records('context', array(), 'id'); 3742 $contexts = array_values($contexts); 3743 $capabilities = $DB->get_records('capabilities', array(), 'id'); 3744 $capabilities = array_values($capabilities); 3745 $roles = array($allroles['guest'], $allroles['user'], $allroles['teacher'], $allroles['editingteacher'], $allroles['coursecreator'], $allroles['manager']); 3746 $userids = array_values($testusers); 3747 $userids[] = get_admin()->id; 3748 3749 if (!PHPUNIT_LONGTEST) { 3750 $contexts = array_slice($contexts, 0, 10); 3751 $capabilities = array_slice($capabilities, 0, 5); 3752 $userids = array_slice($userids, 0, 5); 3753 } 3754 3755 foreach ($userids as $userid) { // No guest or deleted. 3756 // Each user gets 0-10 random roles. 3757 $rcount = rand(0, 10); 3758 for ($j=0; $j<$rcount; $j++) { 3759 $roleid = $roles[rand(0, count($roles)-1)]; 3760 $contextid = $contexts[rand(0, count($contexts)-1)]->id; 3761 role_assign($roleid, $userid, $contextid); 3762 } 3763 } 3764 3765 $permissions = array(CAP_ALLOW, CAP_PREVENT, CAP_INHERIT, CAP_PREVENT); 3766 $maxoverrides = count($contexts)*10; 3767 for ($j=0; $j<$maxoverrides; $j++) { 3768 $roleid = $roles[rand(0, count($roles)-1)]; 3769 $contextid = $contexts[rand(0, count($contexts)-1)]->id; 3770 $permission = $permissions[rand(0, count($permissions)-1)]; 3771 $capname = $capabilities[rand(0, count($capabilities)-1)]->name; 3772 assign_capability($capname, $permission, $roleid, $contextid, true); 3773 } 3774 unset($permissions); 3775 unset($roles); 3776 3777 accesslib_clear_all_caches_for_unit_testing(); // must be done after assign_capability(). 3778 3779 // Test time - let's set up some real user, just in case the logic for USER affects the others... 3780 $USER = $DB->get_record('user', array('id'=>$testusers[3])); 3781 load_all_capabilities(); 3782 3783 $userids[] = $CFG->siteguest; 3784 $userids[] = 0; // Not-logged-in user. 3785 $userids[] = -1; // Non-existent user. 3786 3787 foreach ($contexts as $crecord) { 3788 $context = context::instance_by_id($crecord->id); 3789 if ($coursecontext = $context->get_course_context(false)) { 3790 $enrolled = get_enrolled_users($context); 3791 } else { 3792 $enrolled = array(); 3793 } 3794 foreach ($capabilities as $cap) { 3795 $allowed = get_users_by_capability($context, $cap->name, 'u.id, u.username'); 3796 if ($enrolled) { 3797 $enrolledwithcap = get_enrolled_users($context, $cap->name); 3798 } else { 3799 $enrolledwithcap = array(); 3800 } 3801 foreach ($userids as $userid) { 3802 if ($userid == 0 or isguestuser($userid)) { 3803 if ($userid == 0) { 3804 $CFG->forcelogin = true; 3805 $this->assertFalse(has_capability($cap->name, $context, $userid)); 3806 unset($CFG->forcelogin); 3807 } 3808 if (($cap->captype === 'write') or ($cap->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))) { 3809 $this->assertFalse(has_capability($cap->name, $context, $userid)); 3810 } 3811 $this->assertFalse(isset($allowed[$userid])); 3812 } else { 3813 if (is_siteadmin($userid)) { 3814 $this->assertTrue(has_capability($cap->name, $context, $userid, true)); 3815 } 3816 $hascap = has_capability($cap->name, $context, $userid, false); 3817 $this->assertSame($hascap, isset($allowed[$userid]), "Capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." "); 3818 if (isset($enrolled[$userid])) { 3819 $this->assertSame(isset($allowed[$userid]), isset($enrolledwithcap[$userid]), "Enrolment with capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." "); 3820 } 3821 } 3822 } 3823 } 3824 } 3825 // Back to nobody. 3826 $USER = new stdClass(); 3827 $USER->id = 0; 3828 unset($contexts); 3829 unset($userids); 3830 unset($capabilities); 3831 3832 // Now let's do all the remaining tests that break our carefully prepared fake site. 3833 3834 3835 // Test $context->mark_dirty() method. 3836 3837 $DB->delete_records('cache_flags', array()); 3838 accesslib_clear_all_caches(false); 3839 $systemcontext->mark_dirty(); 3840 $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); 3841 $this->assertTrue(isset($dirty[$systemcontext->path])); 3842 $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$systemcontext->path])); 3843 3844 3845 // Test $context->reload_if_dirty() method. 3846 3847 $DB->delete_records('cache_flags', array()); 3848 accesslib_clear_all_caches(false); 3849 load_all_capabilities(); 3850 $context = context_course::instance($testcourses[2]); 3851 $page = $DB->get_record('page', array('course'=>$testcourses[2])); 3852 $pagecm = get_coursemodule_from_instance('page', $page->id); 3853 $pagecontext = context_module::instance($pagecm->id); 3854 3855 $context->mark_dirty(); 3856 $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path])); 3857 $USER->access['test'] = true; 3858 $context->reload_if_dirty(); 3859 $this->assertFalse(isset($USER->access['test'])); 3860 3861 $context->mark_dirty(); 3862 $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path])); 3863 $USER->access['test'] = true; 3864 $pagecontext->reload_if_dirty(); 3865 $this->assertFalse(isset($USER->access['test'])); 3866 3867 3868 // Test context_helper::build_all_paths() method. 3869 3870 $oldcontexts = $DB->get_records('context', array(), 'id'); 3871 $DB->set_field_select('context', 'path', null, "contextlevel <> ".CONTEXT_SYSTEM); 3872 $DB->set_field_select('context', 'depth', 0, "contextlevel <> ".CONTEXT_SYSTEM); 3873 context_helper::build_all_paths(); 3874 $newcontexts = $DB->get_records('context', array(), 'id'); 3875 $this->assertEquals($oldcontexts, $newcontexts); 3876 unset($oldcontexts); 3877 unset($newcontexts); 3878 3879 3880 // Test $context->reset_paths() method. 3881 3882 $context = context_course::instance($testcourses[2]); 3883 $children = $context->get_child_contexts(); 3884 $context->reset_paths(false); 3885 $this->assertNull($DB->get_field('context', 'path', array('id'=>$context->id))); 3886 $this->assertEquals(0, $DB->get_field('context', 'depth', array('id'=>$context->id))); 3887 foreach ($children as $child) { 3888 $this->assertNull($DB->get_field('context', 'path', array('id'=>$child->id))); 3889 $this->assertEquals(0, $DB->get_field('context', 'depth', array('id'=>$child->id))); 3890 } 3891 $this->assertEquals(count($children)+1, $DB->count_records('context', array('depth'=>0))); 3892 $this->assertEquals(count($children)+1, $DB->count_records('context', array('path'=>null))); 3893 3894 $context = context_course::instance($testcourses[2]); 3895 $context->reset_paths(true); 3896 $context = context_course::instance($testcourses[2]); 3897 $this->assertSame($context->path, $DB->get_field('context', 'path', array('id'=>$context->id))); 3898 $this->assertSame($context->depth, $DB->get_field('context', 'depth', array('id'=>$context->id))); 3899 $this->assertEquals(0, $DB->count_records('context', array('depth'=>0))); 3900 $this->assertEquals(0, $DB->count_records('context', array('path'=>null))); 3901 3902 3903 // Test $context->update_moved() method. 3904 3905 accesslib_clear_all_caches(false); 3906 $DB->delete_records('cache_flags', array()); 3907 $course = $DB->get_record('course', array('id'=>$testcourses[0])); 3908 $context = context_course::instance($course->id); 3909 $oldpath = $context->path; 3910 $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}"); 3911 $categorycontext = context_coursecat::instance($miscid); 3912 $course->category = $miscid; 3913 $DB->update_record('course', $course); 3914 $context->update_moved($categorycontext); 3915 3916 $context = context_course::instance($course->id); 3917 $this->assertEquals($categorycontext, $context->get_parent_context()); 3918 $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); 3919 $this->assertFalse(isset($dirty[$oldpath])); 3920 $this->assertTrue(isset($dirty[$context->path])); 3921 3922 3923 // Test $context->delete_content() method. 3924 3925 context_helper::reset_caches(); 3926 $context = context_module::instance($testpages[3]); 3927 $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); 3928 $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); 3929 $context->delete_content(); 3930 $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); 3931 $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); 3932 3933 3934 // Test $context->delete() method. 3935 3936 context_helper::reset_caches(); 3937 $context = context_module::instance($testpages[4]); 3938 $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); 3939 $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); 3940 $bi = $DB->get_record('block_instances', array('parentcontextid'=>$context->id)); 3941 $bicontext = context_block::instance($bi->id); 3942 $DB->delete_records('cache_flags', array()); 3943 $context->delete(); // Should delete also linked blocks. 3944 $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); 3945 $this->assertFalse(isset($dirty[$context->path])); 3946 $this->assertFalse($DB->record_exists('context', array('id'=>$context->id))); 3947 $this->assertFalse($DB->record_exists('context', array('id'=>$bicontext->id))); 3948 $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_MODULE, 'instanceid'=>$testpages[4]))); 3949 $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK, 'instanceid'=>$bi->id))); 3950 $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); 3951 context_module::instance($testpages[4]); 3952 3953 3954 // Test context_helper::delete_instance() method. 3955 3956 context_helper::reset_caches(); 3957 $lastcourse = array_pop($testcourses); 3958 $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse))); 3959 $coursecontext = context_course::instance($lastcourse); 3960 $this->assertEquals(1, context_inspection::test_context_cache_size()); 3961 $this->assertNotEquals(CONTEXT_COURSE, $coursecontext->instanceid); 3962 $DB->delete_records('cache_flags', array()); 3963 context_helper::delete_instance(CONTEXT_COURSE, $lastcourse); 3964 $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); 3965 $this->assertFalse(isset($dirty[$coursecontext->path])); 3966 $this->assertEquals(0, context_inspection::test_context_cache_size()); 3967 $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse))); 3968 context_course::instance($lastcourse); 3969 3970 3971 // Test context_helper::create_instances() method. 3972 3973 $prevcount = $DB->count_records('context'); 3974 $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); 3975 context_helper::create_instances(null, true); 3976 $this->assertSame($DB->count_records('context'), $prevcount); 3977 $this->assertEquals(0, $DB->count_records('context', array('depth'=>0))); 3978 $this->assertEquals(0, $DB->count_records('context', array('path'=>null))); 3979 3980 $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); 3981 $DB->delete_records('block_instances', array()); 3982 $prevcount = $DB->count_records('context'); 3983 $DB->delete_records_select('context', 'contextlevel <> '.CONTEXT_SYSTEM); 3984 context_helper::create_instances(null, true); 3985 $this->assertSame($prevcount, $DB->count_records('context')); 3986 $this->assertEquals(0, $DB->count_records('context', array('depth'=>0))); 3987 $this->assertEquals(0, $DB->count_records('context', array('path'=>null))); 3988 3989 // Test context_helper::cleanup_instances() method. 3990 3991 $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}"); 3992 $DB->delete_records('course', array('id'=>$lastcourse)); 3993 $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}"); 3994 $DB->delete_records('course_categories', array('id'=>$lastcategory)); 3995 $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0"); 3996 $DB->delete_records('user', array('id'=>$lastuser)); 3997 $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id)); 3998 $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid)); 3999 context_helper::cleanup_instances(); 4000 $count = 1; // System. 4001 $count += $DB->count_records('user', array('deleted'=>0)); 4002 $count += $DB->count_records('course_categories'); 4003 $count += $DB->count_records('course'); 4004 $count += $DB->count_records('course_modules'); 4005 $count += $DB->count_records('block_instances'); 4006 $this->assertEquals($count, $DB->count_records('context')); 4007 4008 4009 // Test context cache size restrictions. 4010 4011 $testusers= array(); 4012 for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) { 4013 $user = $generator->create_user(); 4014 $testusers[$i] = $user->id; 4015 } 4016 context_helper::create_instances(null, true); 4017 context_helper::reset_caches(); 4018 for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) { 4019 context_user::instance($testusers[$i]); 4020 if ($i == CONTEXT_CACHE_MAX_SIZE - 1) { 4021 $this->assertEquals(CONTEXT_CACHE_MAX_SIZE, context_inspection::test_context_cache_size()); 4022 } else if ($i == CONTEXT_CACHE_MAX_SIZE) { 4023 // Once the limit is reached roughly 1/3 of records should be removed from cache. 4024 $this->assertEquals((int)ceil(CONTEXT_CACHE_MAX_SIZE * (2/3) + 101), context_inspection::test_context_cache_size()); 4025 } 4026 } 4027 // We keep the first 100 cached. 4028 $prevsize = context_inspection::test_context_cache_size(); 4029 for ($i=0; $i<100; $i++) { 4030 context_user::instance($testusers[$i]); 4031 $this->assertEquals($prevsize, context_inspection::test_context_cache_size()); 4032 } 4033 context_user::instance($testusers[102]); 4034 $this->assertEquals($prevsize+1, context_inspection::test_context_cache_size()); 4035 unset($testusers); 4036 4037 4038 4039 // Test basic test of legacy functions. 4040 // Note: watch out, the fake site might be pretty borked already. 4041 4042 $this->assertEquals(get_system_context(), context_system::instance()); 4043 $this->assertDebuggingCalled('get_system_context() is deprecated, please use context_system::instance() instead.', DEBUG_DEVELOPER); 4044 4045 foreach ($DB->get_records('context') as $contextid => $record) { 4046 $context = context::instance_by_id($contextid); 4047 $this->assertEquals($context, get_context_instance($record->contextlevel, $record->instanceid)); 4048 $this->assertDebuggingCalled('get_context_instance() is deprecated, please use context_xxxx::instance() instead.', DEBUG_DEVELOPER); 4049 } 4050 4051 // Make sure a debugging is thrown. 4052 get_context_instance($record->contextlevel, $record->instanceid); 4053 $this->assertDebuggingCalled('get_context_instance() is deprecated, please use context_xxxx::instance() instead.', DEBUG_DEVELOPER); 4054 get_system_context(); 4055 $this->assertDebuggingCalled('get_system_context() is deprecated, please use context_system::instance() instead.', DEBUG_DEVELOPER); 4056 } 4057 4058 /** 4059 * Helper that verifies a list of capabilities, as returned by 4060 * $context->get_capabilities() contains certain capabilities. 4061 * 4062 * @param array $expected a list of capability names 4063 * @param array $actual a list of capability info from $context->get_capabilities(). 4064 */ 4065 protected function assert_capability_list_contains($expected, $actual) { 4066 $actualnames = []; 4067 foreach ($actual as $cap) { 4068 $actualnames[] = $cap->name; 4069 } 4070 // Verify each expected element exists. 4071 foreach ($expected as $key => $value) { 4072 $this->assertContains($value, $actualnames); 4073 } 4074 } 4075 4076 /** 4077 * Test that context_system::get_capabilities returns capabilities relevant to all modules. 4078 * 4079 * @covers \context_system::get_capabilities 4080 */ 4081 public function test_context_module_caps_returned_by_get_capabilities_in_sys_context() { 4082 $actual = context_system::instance()->get_capabilities(); 4083 4084 // Just test a few representative capabilities. 4085 $expectedcapabilities = ['moodle/site:accessallgroups', 'moodle/site:viewfullnames', 4086 'repository/upload:view', 'atto/recordrtc:recordaudio']; 4087 4088 $this->assert_capability_list_contains($expectedcapabilities, $actual); 4089 } 4090 4091 /** 4092 * Test that context_coursecat::get_capabilities returns capabilities relevant to all modules. 4093 * 4094 * @covers \context_coursecat::get_capabilities 4095 */ 4096 public function test_context_module_caps_returned_by_get_capabilities_in_course_cat_context() { 4097 $this->resetAfterTest(true); 4098 $generator = $this->getDataGenerator(); 4099 $cat = $generator->create_category(); 4100 4101 $actual = context_coursecat::instance($cat->id)->get_capabilities(); 4102 4103 // Just test a few representative capabilities. 4104 $expectedcapabilities = ['moodle/site:accessallgroups', 'moodle/site:viewfullnames', 4105 'repository/upload:view', 'atto/recordrtc:recordaudio']; 4106 4107 $this->assert_capability_list_contains($expectedcapabilities, $actual); 4108 } 4109 4110 /** 4111 * Test that context_course::get_capabilities returns capabilities relevant to all modules. 4112 * 4113 * @covers \context_course::get_capabilities 4114 */ 4115 public function test_context_module_caps_returned_by_get_capabilities_in_course_context() { 4116 $this->resetAfterTest(true); 4117 $generator = $this->getDataGenerator(); 4118 $cat = $generator->create_category(); 4119 $course = $generator->create_course(['category' => $cat->id]); 4120 4121 $actual = context_course::instance($course->id)->get_capabilities(); 4122 4123 // Just test a few representative capabilities. 4124 $expectedcapabilities = ['moodle/site:accessallgroups', 'moodle/site:viewfullnames', 4125 'repository/upload:view', 'atto/recordrtc:recordaudio']; 4126 4127 $this->assert_capability_list_contains($expectedcapabilities, $actual); 4128 } 4129 4130 /** 4131 * Test that context_module::get_capabilities returns capabilities relevant to all modules. 4132 * 4133 * @covers \context_module::get_capabilities 4134 */ 4135 public function test_context_module_caps_returned_by_get_capabilities_mod_context() { 4136 $this->resetAfterTest(true); 4137 $generator = $this->getDataGenerator(); 4138 $cat = $generator->create_category(); 4139 $course = $generator->create_course(['category' => $cat->id]); 4140 $page = $generator->create_module('page', ['course' => $course->id]); 4141 4142 $actual = context_module::instance($page->cmid)->get_capabilities(); 4143 4144 // Just test a few representative capabilities. 4145 $expectedcapabilities = ['moodle/site:accessallgroups', 'moodle/site:viewfullnames', 4146 'repository/upload:view', 'atto/recordrtc:recordaudio']; 4147 4148 $this->assert_capability_list_contains($expectedcapabilities, $actual); 4149 } 4150 4151 /** 4152 * Test that {@see context_block::get_capabilities} returns capabilities relevant to blocks 4153 * 4154 * @covers \context_block::get_capabilities 4155 */ 4156 public function test_context_block_caps_returned_by_get_capabilities_block_context(): void { 4157 $this->resetAfterTest(); 4158 4159 $course = $this->getDataGenerator()->create_course(); 4160 $block = $this->getDataGenerator()->create_block('online_users', [ 4161 'parentcontextid' => context_course::instance($course->id)->id, 4162 ]); 4163 4164 $capabilities = context_block::instance($block->id)->get_capabilities(); 4165 4166 // Just test a few representative capabilities. 4167 $expected = ['block/online_users:addinstance', 'moodle/block:edit', 'moodle/block:view']; 4168 $this->assert_capability_list_contains($expected, $capabilities); 4169 4170 // Now test with different sorting. 4171 $capabilitiesbyname = context_block::instance($block->id)->get_capabilities('riskbitmask'); 4172 4173 $capabilitynames = array_column($capabilities, 'name'); 4174 $capabilitynamesordered = array_column($capabilitiesbyname, 'name'); 4175 4176 // Each array should contain the same data, ordered differently. 4177 $this->assertEqualsCanonicalizing($capabilitynames, $capabilitynamesordered); 4178 $this->assertNotSame($capabilitynames, $capabilitynamesordered); 4179 } 4180 4181 /** 4182 * Test that {@see context_user::get_capabilities} returns capabilities relevant to users 4183 * 4184 * @covers \context_user::get_capabilities 4185 */ 4186 public function test_context_user_caps_returned_by_get_capabilities_user_context(): void { 4187 $this->resetAfterTest(); 4188 4189 $user = $this->getDataGenerator()->create_user(); 4190 $capabilities = context_user::instance($user->id)->get_capabilities(); 4191 4192 // Just test a few representative capabilities. 4193 $expected = ['moodle/user:editmessageprofile', 'moodle/user:editprofile', 'moodle/user:viewalldetails']; 4194 $this->assert_capability_list_contains($expected, $capabilities); 4195 4196 // Now test with different sorting. 4197 $capabilitiesbyname = context_user::instance($user->id)->get_capabilities('name'); 4198 4199 $capabilitynames = array_column($capabilities, 'name'); 4200 $capabilitynamesordered = array_column($capabilitiesbyname, 'name'); 4201 4202 // Each array should contain the same data, ordered differently. 4203 $this->assertEqualsCanonicalizing($capabilitynames, $capabilitynamesordered); 4204 $this->assertNotSame($capabilitynames, $capabilitynamesordered); 4205 } 4206 4207 /** 4208 * Test updating of role capabilities during upgrade 4209 * 4210 * @covers ::update_capabilities 4211 * @covers ::update_capabilities 4212 */ 4213 public function test_update_capabilities() { 4214 global $DB, $SITE; 4215 4216 $this->resetAfterTest(true); 4217 4218 $froncontext = context_course::instance($SITE->id); 4219 $student = $DB->get_record('role', array('shortname'=>'student')); 4220 $teacher = $DB->get_record('role', array('shortname'=>'teacher')); 4221 4222 $existingcaps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask'); 4223 4224 $this->assertFalse(isset($existingcaps['moodle/site:restore'])); // Moved to new 'moodle/restore:restorecourse'. 4225 $this->assertTrue(isset($existingcaps['moodle/restore:restorecourse'])); // New cap from 'moodle/site:restore'. 4226 $this->assertTrue(isset($existingcaps['moodle/site:sendmessage'])); // New capability. 4227 $this->assertTrue(isset($existingcaps['moodle/backup:backupcourse'])); 4228 $this->assertTrue(isset($existingcaps['moodle/backup:backupsection'])); // Cloned from 'moodle/backup:backupcourse'. 4229 $this->assertTrue(isset($existingcaps['moodle/site:approvecourse'])); // Updated bitmask. 4230 $this->assertTrue(isset($existingcaps['moodle/course:manageactivities'])); 4231 $this->assertTrue(isset($existingcaps['mod/page:addinstance'])); // Cloned from core 'moodle/course:manageactivities'. 4232 4233 // Fake state before upgrade. 4234 $DB->set_field('capabilities', 'name', 'moodle/site:restore', array('name'=>'moodle/restore:restorecourse')); 4235 $DB->set_field('role_capabilities', 'capability', 'moodle/site:restore', array('capability'=>'moodle/restore:restorecourse')); 4236 assign_capability('moodle/site:restore', CAP_PROHIBIT, $teacher->id, $froncontext->id, true); 4237 $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/site:restore', 'roleid'=>$teacher->id), 'contextid, permission', 'contextid, permission')); 4238 4239 $DB->delete_records('role_capabilities', array('capability'=>'moodle/site:sendmessage')); 4240 $DB->delete_records('capabilities', array('name'=>'moodle/site:sendmessage')); 4241 4242 $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupsection')); 4243 $DB->delete_records('capabilities', array('name'=>'moodle/backup:backupsection')); 4244 assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $froncontext->id, true); 4245 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $teacher->id, $froncontext->id, true); 4246 4247 $DB->set_field('capabilities', 'riskbitmask', 0, array('name'=>'moodle/site:approvecourse')); 4248 4249 $DB->delete_records('role_capabilities', array('capability'=>'mod/page:addinstance')); 4250 $DB->delete_records('capabilities', array('name'=>'mod/page:addinstance')); 4251 assign_capability('moodle/course:manageactivities', CAP_PROHIBIT, $student->id, $froncontext->id, true); 4252 assign_capability('moodle/course:manageactivities', CAP_ALLOW, $teacher->id, $froncontext->id, true); 4253 4254 // Execute core. 4255 update_capabilities('moodle'); 4256 4257 // Only core should be upgraded. 4258 $caps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask'); 4259 4260 $this->assertFalse(isset($existingcaps['moodle/site:restore'])); 4261 $this->assertTrue(isset($caps['moodle/restore:restorecourse'])); 4262 $this->assertEquals($existingcaps['moodle/restore:restorecourse'], $caps['moodle/restore:restorecourse']); 4263 $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/restore:restorecourse', 'roleid'=>$teacher->id), 'contextid, permission', 'contextid, permission')); 4264 $this->assertEquals($perms1, $perms2); 4265 4266 $this->assertTrue(isset($caps['moodle/site:sendmessage'])); 4267 $this->assertEquals($existingcaps['moodle/site:sendmessage'], $caps['moodle/site:sendmessage']); 4268 4269 $this->assertTrue(isset($caps['moodle/backup:backupsection'])); 4270 $this->assertEquals($existingcaps['moodle/backup:backupsection'], $caps['moodle/backup:backupsection']); 4271 $roles = $DB->get_records_sql('SELECT DISTINCT roleid AS id FROM {role_capabilities} WHERE capability=? OR capability=?', array('moodle/backup:backupcourse', 'moodle/backup:backupsection')); 4272 foreach ($roles as $role) { 4273 $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission')); 4274 $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/backup:backupsection', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission')); 4275 $this->assertEquals($perms1, $perms2); 4276 } 4277 4278 $this->assertTrue(isset($caps['moodle/site:approvecourse'])); 4279 $this->assertEquals($existingcaps['moodle/site:approvecourse'], $caps['moodle/site:approvecourse']); 4280 4281 $this->assertFalse(isset($caps['mod/page:addinstance'])); 4282 4283 // Execute plugin. 4284 update_capabilities('mod_page'); 4285 $caps = $DB->get_records('capabilities', array(), 'id', 'name, captype, contextlevel, component, riskbitmask'); 4286 $this->assertTrue(isset($caps['mod/page:addinstance'])); 4287 $roles = $DB->get_records_sql('SELECT DISTINCT roleid AS id FROM {role_capabilities} WHERE capability=? OR capability=?', array('moodle/course:manageactivities', 'mod/page:addinstance')); 4288 foreach ($roles as $role) { 4289 $perms1 = array_values($DB->get_records('role_capabilities', array('capability'=>'moodle/course:manageactivities', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission')); 4290 $perms2 = array_values($DB->get_records('role_capabilities', array('capability'=>'mod/page:addinstance', 'roleid'=>$role->id), 'contextid, permission', 'contextid, permission')); 4291 } 4292 $this->assertEquals($perms1, $perms2); 4293 } 4294 4295 /** 4296 * Checks install performance in update_capabilities. 4297 * 4298 * @covers ::update_capabilities() 4299 */ 4300 public function test_update_capabilities_install_performance(): void { 4301 global $DB; 4302 4303 $this->resetAfterTest(); 4304 4305 // Get rid of all the capabilities for forum. 4306 $testmodule = 'forum'; 4307 $DB->delete_records_select('capabilities', 'name LIKE ?', ['mod/' . $testmodule . ':%']); 4308 4309 $beforeq = $DB->perf_get_queries(); 4310 update_capabilities('mod_' . $testmodule); 4311 $afterq = $DB->perf_get_queries(); 4312 4313 // In my testing there are currently 237 queries; there were 373 before a performance 4314 // fix. This test confirms performance doesn't degrade to near the previous level. 4315 $this->assertLessThan(300, $afterq - $beforeq); 4316 } 4317 4318 /** 4319 * Checks install performance in update_capabilities when a new capability is cloned. 4320 * 4321 * This only has impact if there are a significant number of overrides of the existing 4322 * capability. 4323 * 4324 * @covers ::update_capabilities() 4325 */ 4326 public function test_update_capabilities_clone_performance(): void { 4327 global $DB; 4328 4329 $this->resetAfterTest(); 4330 4331 // Create a bunch of activities in a course. In each one, override so manager doesn't have 4332 // moodle/course:manageactivities. 4333 $generator = $this->getDataGenerator(); 4334 $course = $generator->create_course(); 4335 $roleid = $DB->get_field('role', 'id', ['shortname' => 'manager']); 4336 for ($i = 0; $i < 100; $i++) { 4337 $page = $generator->create_module('page', ['course' => $course->id]); 4338 $contextid = context_module::instance($page->cmid)->id; 4339 assign_capability('moodle/course:manageactivities', CAP_PREVENT, $roleid, $contextid); 4340 } 4341 4342 // Get rid of one of the capabilities for forum, which clones moodle/course:manageactivities. 4343 $DB->delete_records('capabilities', ['name' => 'mod/forum:addinstance']); 4344 4345 // Clear the context cache to simulate a realistic situation where we don't already have 4346 // all those contexts in the cache. 4347 accesslib_clear_all_caches_for_unit_testing(); 4348 4349 $beforeq = $DB->perf_get_queries(); 4350 update_capabilities('mod_forum'); 4351 $afterq = $DB->perf_get_queries(); 4352 4353 // In my testing there are currently 214 queries after performance was improved for cloning, 4354 // compared to 414 before. This test confirms performance doesn't degrade to near the 4355 // previous level. 4356 $this->assertLessThan(300, $afterq - $beforeq); 4357 } 4358 4359 /** 4360 * Tests update_capabilities when a capability is cloned, but there are existing settings 4361 * for that capability. 4362 * 4363 * Under normal circumstances this shouldn't happen as it is only used for new capabilities, 4364 * but it's possible there could be incorrect data in database.) 4365 * 4366 * @covers ::update_capabilities() 4367 */ 4368 public function test_update_capabilities_clone_existing(): void { 4369 global $DB; 4370 4371 $this->resetAfterTest(); 4372 4373 // Create activities in a course. In each one, override so manager doesn't have 4374 // moodle/course:manageactivities. In one of them, also override mod/forum:addinstance 4375 // to something different. 4376 $generator = $this->getDataGenerator(); 4377 $course = $generator->create_course(); 4378 $roleid = $DB->get_field('role', 'id', ['shortname' => 'manager']); 4379 $page1 = $generator->create_module('page', ['course' => $course->id]); 4380 $context1 = context_module::instance($page1->cmid); 4381 assign_capability('moodle/course:manageactivities', CAP_PREVENT, $roleid, $context1->id); 4382 $page2 = $generator->create_module('page', ['course' => $course->id]); 4383 $context2 = context_module::instance($page2->cmid); 4384 assign_capability('moodle/course:manageactivities', CAP_PREVENT, $roleid, $context2->id); 4385 assign_capability('mod/forum:addinstance', CAP_PROHIBIT, $roleid, $context2->id); 4386 4387 // Get rid of one of the capabilities for forum, which clones moodle/course:manageactivities. 4388 $DB->delete_records('capabilities', ['name' => 'mod/forum:addinstance']); 4389 4390 // Reinstall the capability. 4391 update_capabilities('mod_forum'); 4392 4393 // Check the results: we should duplicate the manageactivities setting (PREVENT). 4394 $rec1 = $DB->get_record('role_capabilities', ['roleid' => $roleid, 4395 'contextid' => $context1->id, 'capability' => 'mod/forum:addinstance']); 4396 $this->assertEquals(CAP_PREVENT, $rec1->permission); 4397 // The second page, we should overwrite the previous existing permission setting. 4398 $rec2 = $DB->get_record('role_capabilities', ['roleid' => $roleid, 4399 'contextid' => $context2->id, 'capability' => 'mod/forum:addinstance']); 4400 $this->assertEquals(CAP_PREVENT, $rec2->permission); 4401 } 4402 4403 /** 4404 * Tests reset_role_capabilities function. 4405 * 4406 * @covers ::reset_role_capabilities 4407 */ 4408 public function test_reset_role_capabilities() { 4409 global $DB; 4410 $this->resetAfterTest(true); 4411 $generator = $this->getDataGenerator(); 4412 4413 // Create test course and user, enrol one in the other. 4414 $course = $generator->create_course(); 4415 $user = $generator->create_user(); 4416 $roleid = $DB->get_field('role', 'id', array('shortname' => 'student'), MUST_EXIST); 4417 $generator->enrol_user($user->id, $course->id, $roleid); 4418 4419 // Change student role so it DOES have 'mod/forum:addinstance'. 4420 $systemcontext = context_system::instance(); 4421 assign_capability('mod/forum:addinstance', CAP_ALLOW, $roleid, $systemcontext->id); 4422 4423 // Override course so it does NOT allow students 'mod/forum:viewdiscussion'. 4424 $coursecontext = context_course::instance($course->id); 4425 assign_capability('mod/forum:viewdiscussion', CAP_PREVENT, $roleid, $coursecontext->id); 4426 4427 // Check expected capabilities so far. 4428 $this->assertTrue(has_capability('mod/forum:addinstance', $coursecontext, $user)); 4429 $this->assertFalse(has_capability('mod/forum:viewdiscussion', $coursecontext, $user)); 4430 4431 // Oops, allowing student to add forums was a mistake, let's reset the role. 4432 reset_role_capabilities($roleid); 4433 4434 // Check new expected capabilities - role capabilities should have been reset, 4435 // while the override at course level should remain. 4436 $this->assertFalse(has_capability('mod/forum:addinstance', $coursecontext, $user)); 4437 $this->assertFalse(has_capability('mod/forum:viewdiscussion', $coursecontext, $user)); 4438 } 4439 4440 /** 4441 * Tests count_role_users function. 4442 * 4443 * @covers ::count_role_users 4444 */ 4445 public function test_count_role_users() { 4446 global $DB; 4447 $this->resetAfterTest(true); 4448 $generator = self::getDataGenerator(); 4449 // Create a course in a category, and some users. 4450 $category = $generator->create_category(); 4451 $course = $generator->create_course(array('category' => $category->id)); 4452 $user1 = $generator->create_user(); 4453 $user2 = $generator->create_user(); 4454 $user3 = $generator->create_user(); 4455 $user4 = $generator->create_user(); 4456 $user5 = $generator->create_user(); 4457 $roleid1 = $DB->get_field('role', 'id', array('shortname' => 'manager'), MUST_EXIST); 4458 $roleid2 = $DB->get_field('role', 'id', array('shortname' => 'coursecreator'), MUST_EXIST); 4459 // Enrol two users as managers onto the course, and 1 onto the category. 4460 $generator->enrol_user($user1->id, $course->id, $roleid1); 4461 $generator->enrol_user($user2->id, $course->id, $roleid1); 4462 $generator->role_assign($roleid1, $user3->id, context_coursecat::instance($category->id)); 4463 // Enrol 1 user as a coursecreator onto the course, and another onto the category. 4464 // This is to ensure we do not count users with roles that are not specified. 4465 $generator->enrol_user($user4->id, $course->id, $roleid2); 4466 $generator->role_assign($roleid2, $user5->id, context_coursecat::instance($category->id)); 4467 // Check that the correct users are found on the course. 4468 $this->assertEquals(2, count_role_users($roleid1, context_course::instance($course->id), false)); 4469 $this->assertEquals(3, count_role_users($roleid1, context_course::instance($course->id), true)); 4470 // Check for the category. 4471 $this->assertEquals(1, count_role_users($roleid1, context_coursecat::instance($category->id), false)); 4472 $this->assertEquals(1, count_role_users($roleid1, context_coursecat::instance($category->id), true)); 4473 // Have a user with the same role at both the category and course level. 4474 $generator->role_assign($roleid1, $user1->id, context_coursecat::instance($category->id)); 4475 // The course level checks should remain the same. 4476 $this->assertEquals(2, count_role_users($roleid1, context_course::instance($course->id), false)); 4477 $this->assertEquals(3, count_role_users($roleid1, context_course::instance($course->id), true)); 4478 } 4479 4480 /** 4481 * Test fetching users by capability. 4482 * 4483 * @covers ::get_users_by_capability 4484 */ 4485 public function test_get_users_by_capability() { 4486 global $DB; 4487 4488 $this->resetAfterTest(); 4489 4490 $course = $this->getDataGenerator()->create_course(); 4491 $coursecontext = context_course::instance($course->id); 4492 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 4493 $teacher = $this->getDataGenerator()->create_user(); 4494 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 4495 $student = $this->getDataGenerator()->create_user(); 4496 $guest = $DB->get_record('user', array('username' => 'guest')); 4497 4498 role_assign($teacherrole->id, $teacher->id, $coursecontext); 4499 role_assign($studentrole->id, $student->id, $coursecontext); 4500 $admin = $DB->get_record('user', array('username' => 'admin')); 4501 4502 // Note: Here are used default capabilities, the full test is in permission evaluation below, 4503 // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user. 4504 $this->assertTrue($DB->record_exists('capabilities', array('name' => 'moodle/backup:backupcourse'))); 4505 $this->assertTrue($DB->record_exists('capabilities', array('name' => 'moodle/site:approvecourse'))); 4506 4507 $users = get_users_by_capability($coursecontext, 'moodle/backup:backupcourse'); 4508 4509 $this->assertTrue(array_key_exists($teacher->id, $users)); 4510 $this->assertFalse(array_key_exists($admin->id, $users)); 4511 $this->assertFalse(array_key_exists($student->id, $users)); 4512 $this->assertFalse(array_key_exists($guest->id, $users)); 4513 4514 $users = get_users_by_capability($coursecontext, 'moodle/site:approvecourse'); 4515 4516 $this->assertFalse(array_key_exists($teacher->id, $users)); 4517 $this->assertFalse(array_key_exists($admin->id, $users)); 4518 $this->assertFalse(array_key_exists($student->id, $users)); 4519 $this->assertFalse(array_key_exists($guest->id, $users)); 4520 4521 // Test role override. 4522 assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacherrole->id, $coursecontext, true); 4523 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $studentrole->id, $coursecontext, true); 4524 4525 $users = get_users_by_capability($coursecontext, 'moodle/backup:backupcourse'); 4526 4527 $this->assertFalse(array_key_exists($teacher->id, $users)); 4528 $this->assertFalse(array_key_exists($admin->id, $users)); 4529 $this->assertTrue(array_key_exists($student->id, $users)); 4530 $this->assertFalse(array_key_exists($guest->id, $users)); 4531 } 4532 4533 4534 /** 4535 * @covers ::get_with_capability_sql 4536 */ 4537 public function test_get_with_capability_sql() { 4538 global $DB; 4539 4540 $this->resetAfterTest(); 4541 4542 $course = $this->getDataGenerator()->create_course(); 4543 $coursecontext = context_course::instance($course->id); 4544 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 4545 $teacher = $this->getDataGenerator()->create_user(); 4546 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 4547 $student = $this->getDataGenerator()->create_user(); 4548 $guest = $DB->get_record('user', array('username' => 'guest')); 4549 4550 role_assign($teacherrole->id, $teacher->id, $coursecontext); 4551 role_assign($studentrole->id, $student->id, $coursecontext); 4552 $admin = $DB->get_record('user', array('username' => 'admin')); 4553 4554 // Note: Here are used default capabilities, the full test is in permission evaluation below, 4555 // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user. 4556 $this->assertTrue($DB->record_exists('capabilities', array('name' => 'moodle/backup:backupcourse'))); 4557 $this->assertTrue($DB->record_exists('capabilities', array('name' => 'moodle/site:approvecourse'))); 4558 4559 list($sql, $params) = get_with_capability_sql($coursecontext, 'moodle/backup:backupcourse'); 4560 $users = $DB->get_records_sql($sql, $params); 4561 4562 $this->assertTrue(array_key_exists($teacher->id, $users)); 4563 $this->assertFalse(array_key_exists($admin->id, $users)); 4564 $this->assertFalse(array_key_exists($student->id, $users)); 4565 $this->assertFalse(array_key_exists($guest->id, $users)); 4566 4567 list($sql, $params) = get_with_capability_sql($coursecontext, 'moodle/site:approvecourse'); 4568 $users = $DB->get_records_sql($sql, $params); 4569 4570 $this->assertFalse(array_key_exists($teacher->id, $users)); 4571 $this->assertFalse(array_key_exists($admin->id, $users)); 4572 $this->assertFalse(array_key_exists($student->id, $users)); 4573 $this->assertFalse(array_key_exists($guest->id, $users)); 4574 4575 // Test role override. 4576 assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacherrole->id, $coursecontext, true); 4577 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $studentrole->id, $coursecontext, true); 4578 4579 list($sql, $params) = get_with_capability_sql($coursecontext, 'moodle/backup:backupcourse'); 4580 $users = $DB->get_records_sql($sql, $params); 4581 4582 $this->assertFalse(array_key_exists($teacher->id, $users)); 4583 $this->assertFalse(array_key_exists($admin->id, $users)); 4584 $this->assertTrue(array_key_exists($student->id, $users)); 4585 $this->assertFalse(array_key_exists($guest->id, $users)); 4586 } 4587 4588 4589 /** 4590 * Get the test cases for {@link test_get_with_capability_join_when_overrides_present()}. 4591 * 4592 * The particular capabilties used here do not really matter. What is important is 4593 * that they are capabilities which the Student roles has by default, but the 4594 * authenticated suser role does not. 4595 * 4596 * @return array 4597 */ 4598 public function get_get_with_capability_join_override_cases() { 4599 return [ 4600 'no overrides' => [true, []], 4601 'one override' => [true, ['moodle/course:viewscales']], 4602 'both overrides' => [false, ['moodle/course:viewscales', 'moodle/question:flag']], 4603 ]; 4604 } 4605 4606 /** 4607 * Test get_with_capability_join. 4608 * 4609 * @dataProvider get_get_with_capability_join_override_cases 4610 * @covers ::get_with_capability_join 4611 * 4612 * @param bool $studentshouldbereturned whether, with this combination of capabilities, the student should be in the results. 4613 * @param array $capabilitiestoprevent capabilities to override to prevent in the course context. 4614 */ 4615 public function test_get_with_capability_join_when_overrides_present( 4616 bool $studentshouldbereturned, array $capabilitiestoprevent) { 4617 global $DB; 4618 $this->resetAfterTest(); 4619 $generator = $this->getDataGenerator(); 4620 4621 // Create a course. 4622 $category = $generator->create_category(); 4623 $course = $generator->create_course(['category' => $category->id]); 4624 4625 // Create a user. 4626 $student = $generator->create_user(); 4627 $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST); 4628 $generator->enrol_user($student->id, $course->id, $studentrole->id); 4629 4630 // This test assumes that by default the student roles has the two 4631 // capabilities. Check this now in case the role definitions are every changed. 4632 $coursecontext = context_course::instance($course->id); 4633 $this->assertTrue(has_capability('moodle/course:viewscales', $coursecontext, $student)); 4634 $this->assertTrue(has_capability('moodle/question:flag', $coursecontext, $student)); 4635 4636 // We test cases where there are a varying number of prevent overrides. 4637 foreach ($capabilitiestoprevent as $capability) { 4638 role_change_permission($studentrole->id, $coursecontext, $capability, CAP_PREVENT); 4639 } 4640 4641 // So now, assemble our query using the method under test, and verify that it returns the student. 4642 $sqljoin = get_with_capability_join($coursecontext, 4643 ['moodle/course:viewscales', 'moodle/question:flag'], 'u.id'); 4644 4645 $users = $DB->get_records_sql("SELECT u.* 4646 FROM {user} u 4647 {$sqljoin->joins} 4648 WHERE {$sqljoin->wheres}", $sqljoin->params); 4649 if ($studentshouldbereturned) { 4650 $this->assertEquals([$student->id], array_keys($users)); 4651 } else { 4652 $this->assertEmpty($users); 4653 } 4654 } 4655 4656 /** 4657 * Test the get_profile_roles() function. 4658 * 4659 * @covers ::get_profile_roles 4660 */ 4661 public function test_get_profile_roles() { 4662 global $DB; 4663 $this->resetAfterTest(); 4664 4665 $course = $this->getDataGenerator()->create_course(); 4666 $coursecontext = context_course::instance($course->id); 4667 4668 // Assign a student role. 4669 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 4670 $user1 = $this->getDataGenerator()->create_user(); 4671 role_assign($studentrole->id, $user1->id, $coursecontext); 4672 4673 // Assign an editing teacher role. 4674 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 4675 $user2 = $this->getDataGenerator()->create_user(); 4676 role_assign($teacherrole->id, $user2->id, $coursecontext); 4677 4678 // Create a custom role that can be assigned at course level, but don't assign it yet. 4679 create_role('Custom role', 'customrole', 'Custom course role'); 4680 $customrole = $DB->get_record('role', array('shortname' => 'customrole'), '*', MUST_EXIST); 4681 set_role_contextlevels($customrole->id, [CONTEXT_COURSE]); 4682 core_role_set_assign_allowed($teacherrole->id, $customrole->id); // Allow teacher to assign the role in the course. 4683 4684 // Set the site policy 'profileroles' to show student, teacher and non-editing teacher roles (i.e. not the custom role). 4685 $neteacherrole = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST); 4686 set_config('profileroles', "{$studentrole->id}, {$teacherrole->id}, {$neteacherrole->id}"); 4687 4688 // A student in the course (given they can't assign roles) should see those roles which are: 4689 // - listed in the 'profileroles' site policy AND 4690 // - are assigned in the course context (or parent contexts). 4691 // In this case, the non-editing teacher role is not assigned and should not be returned. 4692 $expected = [ 4693 $teacherrole->id => (object) [ 4694 'id' => $teacherrole->id, 4695 'name' => '', 4696 'shortname' => $teacherrole->shortname, 4697 'sortorder' => $teacherrole->sortorder, 4698 'coursealias' => null 4699 ], 4700 $studentrole->id => (object) [ 4701 'id' => $studentrole->id, 4702 'name' => '', 4703 'shortname' => $studentrole->shortname, 4704 'sortorder' => $studentrole->sortorder, 4705 'coursealias' => null 4706 ] 4707 ]; 4708 $this->setUser($user1); 4709 $this->assertEquals($expected, get_profile_roles($coursecontext)); 4710 4711 // An editing teacher should also see only 2 roles at this stage as only 2 roles are assigned: 'teacher' and 'student'. 4712 $this->setUser($user2); 4713 $this->assertEquals($expected, get_profile_roles($coursecontext)); 4714 4715 // Assign a custom role in the course. 4716 $user3 = $this->getDataGenerator()->create_user(); 4717 role_assign($customrole->id, $user3->id, $coursecontext); 4718 4719 // Confirm that the teacher can see the custom role now that it's assigned. 4720 $expectedteacher = [ 4721 $teacherrole->id => (object) [ 4722 'id' => $teacherrole->id, 4723 'name' => '', 4724 'shortname' => $teacherrole->shortname, 4725 'sortorder' => $teacherrole->sortorder, 4726 'coursealias' => null 4727 ], 4728 $studentrole->id => (object) [ 4729 'id' => $studentrole->id, 4730 'name' => '', 4731 'shortname' => $studentrole->shortname, 4732 'sortorder' => $studentrole->sortorder, 4733 'coursealias' => null 4734 ], 4735 $customrole->id => (object) [ 4736 'id' => $customrole->id, 4737 'name' => 'Custom role', 4738 'shortname' => $customrole->shortname, 4739 'sortorder' => $customrole->sortorder, 4740 'coursealias' => null 4741 ] 4742 ]; 4743 $this->setUser($user2); 4744 $this->assertEquals($expectedteacher, get_profile_roles($coursecontext)); 4745 4746 // And that the student can't, because the role isn't included in the 'profileroles' site policy. 4747 $expectedstudent = [ 4748 $teacherrole->id => (object) [ 4749 'id' => $teacherrole->id, 4750 'name' => '', 4751 'shortname' => $teacherrole->shortname, 4752 'sortorder' => $teacherrole->sortorder, 4753 'coursealias' => null 4754 ], 4755 $studentrole->id => (object) [ 4756 'id' => $studentrole->id, 4757 'name' => '', 4758 'shortname' => $studentrole->shortname, 4759 'sortorder' => $studentrole->sortorder, 4760 'coursealias' => null 4761 ] 4762 ]; 4763 $this->setUser($user1); 4764 $this->assertEquals($expectedstudent, get_profile_roles($coursecontext)); 4765 4766 // If we have no roles listed in the site policy, the teacher should be able to see the assigned roles. 4767 $expectedteacher = [ 4768 $studentrole->id => (object) [ 4769 'id' => $studentrole->id, 4770 'name' => '', 4771 'shortname' => $studentrole->shortname, 4772 'sortorder' => $studentrole->sortorder, 4773 'coursealias' => null 4774 ], 4775 $customrole->id => (object) [ 4776 'id' => $customrole->id, 4777 'name' => 'Custom role', 4778 'shortname' => $customrole->shortname, 4779 'sortorder' => $customrole->sortorder, 4780 'coursealias' => null 4781 ], 4782 $teacherrole->id => (object) [ 4783 'id' => $teacherrole->id, 4784 'name' => '', 4785 'shortname' => $teacherrole->shortname, 4786 'sortorder' => $teacherrole->sortorder, 4787 'coursealias' => null 4788 ], 4789 ]; 4790 set_config('profileroles', ""); 4791 $this->setUser($user2); 4792 $this->assertEquals($expectedteacher, get_profile_roles($coursecontext)); 4793 } 4794 4795 /** 4796 * Data provider for is_parent_of context checks. 4797 * 4798 * @return array 4799 */ 4800 public function is_parent_of_provider(): array { 4801 $provideboth = function(string $desc, string $contextpath, string $testpath, bool $expected): array { 4802 return [ 4803 "includeself: true; {$desc}" => [ 4804 $contextpath, 4805 $testpath, 4806 true, 4807 $expected, 4808 ], 4809 "includeself: false; {$desc}" => [ 4810 $contextpath, 4811 $testpath, 4812 false, 4813 $expected, 4814 ], 4815 ]; 4816 }; 4817 4818 return array_merge( 4819 [ 4820 'includeself: true, testing self' => [ 4821 '/1/4/17/291/1001/17105', 4822 '/1/4/17/291/1001/17105', 4823 true, 4824 true, 4825 ], 4826 'includeself: false, testing self' => [ 4827 '/1/4/17/291/1001/17105', 4828 '/1/4/17/291/1001/17105', 4829 false, 4830 false, 4831 ], 4832 ], 4833 $provideboth( 4834 'testing parent', 4835 '/1/4/17/291/1001/17105', 4836 '/1/4/17/291/1001', 4837 false 4838 ), 4839 $provideboth( 4840 'testing child', 4841 '/1/4/17/291/1001', 4842 '/1/4/17/291/1001/17105', 4843 true 4844 ), 4845 $provideboth( 4846 'testing grandchild', 4847 '/1', 4848 '/1/4/17/291/1001/17105', 4849 true 4850 ) 4851 ); 4852 } 4853 4854 /** 4855 * Ensure that the is_parent_of() function works as anticipated. 4856 * 4857 * @dataProvider is_parent_of_provider 4858 * @covers \context::is_parent_of 4859 * @covers \context_block::is_parent_of 4860 * @covers \context_course::is_parent_of 4861 * @covers \context_coursecat::is_parent_of 4862 * @covers \context_module::is_parent_of 4863 * @covers \context_system::is_parent_of 4864 * @covers \context_user::is_parent_of 4865 * @param string $contextpath The path of the context being compared with 4866 * @param string $testpath The path of the context being compared 4867 * @param bool $testself Whether to check the current context 4868 * @param bool $expected The expected result 4869 */ 4870 public function test_is_parent_of(string $contextpath, string $testpath, bool $testself, bool $expected): void { 4871 $context = $this->getMockBuilder(\context::class) 4872 ->disableOriginalConstructor() 4873 ->onlyMethods([ 4874 'get_url', 4875 'get_capabilities', 4876 ]) 4877 ->getMock(); 4878 4879 $rcp = new ReflectionProperty($context, '_path'); 4880 $rcp->setAccessible(true); 4881 $rcp->setValue($context, $contextpath); 4882 4883 $comparisoncontext = $this->getMockBuilder(\context::class) 4884 ->disableOriginalConstructor() 4885 ->onlyMethods([ 4886 'get_url', 4887 'get_capabilities', 4888 ]) 4889 ->getMock(); 4890 4891 $rcp = new ReflectionProperty($comparisoncontext, '_path'); 4892 $rcp->setAccessible(true); 4893 $rcp->setValue($comparisoncontext, $testpath); 4894 4895 $this->assertEquals($expected, $context->is_parent_of($comparisoncontext, $testself)); 4896 } 4897 4898 /** 4899 * Data provider for is_child_of context checks. 4900 * 4901 * @return array 4902 */ 4903 public function is_child_of_provider(): array { 4904 $provideboth = function(string $desc, string $contextpath, string $testpath, bool $expected): array { 4905 return [ 4906 "includeself: true; {$desc}" => [ 4907 $contextpath, 4908 $testpath, 4909 true, 4910 $expected, 4911 ], 4912 "includeself: false; {$desc}" => [ 4913 $contextpath, 4914 $testpath, 4915 false, 4916 $expected, 4917 ], 4918 ]; 4919 }; 4920 4921 return array_merge( 4922 [ 4923 'includeself: true, testing self' => [ 4924 '/1/4/17/291/1001/17105', 4925 '/1/4/17/291/1001/17105', 4926 true, 4927 true, 4928 ], 4929 'includeself: false, testing self' => [ 4930 '/1/4/17/291/1001/17105', 4931 '/1/4/17/291/1001/17105', 4932 false, 4933 false, 4934 ], 4935 ], 4936 $provideboth( 4937 'testing child', 4938 '/1/4/17/291/1001/17105', 4939 '/1/4/17/291/1001', 4940 true 4941 ), 4942 $provideboth( 4943 'testing parent', 4944 '/1/4/17/291/1001', 4945 '/1/4/17/291/1001/17105', 4946 false 4947 ), 4948 $provideboth( 4949 'testing grandchild', 4950 '/1/4/17/291/1001/17105', 4951 '/1', 4952 true 4953 ), 4954 $provideboth( 4955 'testing grandparent', 4956 '/1', 4957 '/1/4/17/291/1001/17105', 4958 false 4959 ) 4960 ); 4961 } 4962 4963 /** 4964 * Ensure that the is_child_of() function works as anticipated. 4965 * 4966 * @dataProvider is_child_of_provider 4967 * @covers \context::is_child_of 4968 * @covers \context_block::is_child_of 4969 * @covers \context_course::is_child_of 4970 * @covers \context_coursecat::is_child_of 4971 * @covers \context_module::is_child_of 4972 * @covers \context_system::is_child_of 4973 * @covers \context_user::is_child_of 4974 * @param string $contextpath The path of the context being compared with 4975 * @param string $testpath The path of the context being compared 4976 * @param bool $testself Whether to check the current context 4977 * @param bool $expected The expected result 4978 */ 4979 public function test_is_child_of(string $contextpath, string $testpath, bool $testself, bool $expected): void { 4980 $context = $this->getMockBuilder(\context::class) 4981 ->disableOriginalConstructor() 4982 ->onlyMethods([ 4983 'get_url', 4984 'get_capabilities', 4985 ]) 4986 ->getMock(); 4987 4988 $rcp = new ReflectionProperty($context, '_path'); 4989 $rcp->setAccessible(true); 4990 $rcp->setValue($context, $contextpath); 4991 4992 $comparisoncontext = $this->getMockBuilder(\context::class) 4993 ->disableOriginalConstructor() 4994 ->onlyMethods([ 4995 'get_url', 4996 'get_capabilities', 4997 ]) 4998 ->getMock(); 4999 5000 $rcp = new ReflectionProperty($comparisoncontext, '_path'); 5001 $rcp->setAccessible(true); 5002 $rcp->setValue($comparisoncontext, $testpath); 5003 5004 $this->assertEquals($expected, $context->is_child_of($comparisoncontext, $testself)); 5005 } 5006 5007 /** 5008 * Ensure that the get_parent_contexts() function limits the number of queries it performs. 5009 * 5010 * @covers ::get_parent_contexts 5011 */ 5012 public function test_get_parent_contexts_preload() { 5013 global $DB; 5014 5015 $this->resetAfterTest(); 5016 5017 /* 5018 * Given the following data structure: 5019 * System 5020 * - Category 5021 * --- Category 5022 * ----- Category 5023 * ------- Category 5024 * --------- Course 5025 * ----------- Activity (Forum) 5026 */ 5027 5028 $contexts = []; 5029 5030 $cat1 = $this->getDataGenerator()->create_category(); 5031 $cat2 = $this->getDataGenerator()->create_category(['parent' => $cat1->id]); 5032 $cat3 = $this->getDataGenerator()->create_category(['parent' => $cat2->id]); 5033 $cat4 = $this->getDataGenerator()->create_category(['parent' => $cat3->id]); 5034 $course = $this->getDataGenerator()->create_course(['category' => $cat4->id]); 5035 $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]); 5036 5037 $modcontext = context_module::instance($forum->cmid); 5038 5039 context_helper::reset_caches(); 5040 5041 // There should only be a single DB query. 5042 $predbqueries = $DB->perf_get_reads(); 5043 5044 $parents = $modcontext->get_parent_contexts(); 5045 // Note: For some databases There is one read, plus one FETCH, plus one CLOSE. 5046 // These all show as reads, when there has actually only been a single query. 5047 $this->assertLessThanOrEqual(3, $DB->perf_get_reads() - $predbqueries); 5048 } 5049 5050 /** 5051 * Ensure that get_with_capability_sql and get_with_capability_join respect context locking. 5052 * 5053 * @covers ::get_with_capability_join 5054 * @covers ::get_with_capability_sql 5055 */ 5056 public function test_get_with_capability_sql_locked() { 5057 global $DB; 5058 5059 $this->resetAfterTest(); 5060 5061 $generator = $this->getDataGenerator(); 5062 5063 $cat1 = $generator->create_category(); 5064 $cat2 = $generator->create_category(); 5065 $cat1course1 = $generator->create_course(['category' => $cat1->id]); 5066 $cat1course1forum = $generator->create_module('forum', ['course' => $cat1course1]); 5067 5068 $contexts = (object) [ 5069 'system' => \context_system::instance(), 5070 'cat1' => \context_coursecat::instance($cat1->id), 5071 'cat2' => \context_coursecat::instance($cat2->id), 5072 'cat1course1' => \context_course::instance($cat1course1->id), 5073 'cat1course1forum' => \context_module::instance($cat1course1forum->cmid), 5074 ]; 5075 5076 // Test with the 'mod/forum:startdiscussion' capability. 5077 $caput = 'mod/forum:startdiscussion'; 5078 5079 // Create a test user. 5080 $uut = $generator->create_and_enrol($cat1course1, 'teacher'); 5081 5082 // Initially the user will be returned by get_users_by_capability. 5083 list($sql, $params) = get_with_capability_sql($contexts->cat1course1forum, $caput); 5084 $users = $DB->get_records_sql($sql, $params); 5085 $this->assertArrayHasKey($uut->id, $users); 5086 5087 // Freezing the forum will remove the user. 5088 set_config('contextlocking', 1); 5089 $contexts->cat1course1forum->set_locked(true); 5090 list($sql, $params) = get_with_capability_sql($contexts->cat1course1forum, $caput); 5091 $users = $DB->get_records_sql($sql, $params); 5092 $this->assertArrayNotHasKey($uut->id, $users); 5093 5094 // But not if context locking is disabled. 5095 set_config('contextlocking', 0); 5096 list($sql, $params) = get_with_capability_sql($contexts->cat1course1forum, $caput); 5097 $users = $DB->get_records_sql($sql, $params); 5098 $this->assertArrayHasKey($uut->id, $users); 5099 5100 $contexts->cat1course1forum->set_locked(false); 5101 5102 // Freezing the course will have the same effect. 5103 set_config('contextlocking', 1); 5104 $contexts->cat1course1->set_locked(true); 5105 list($sql, $params) = get_with_capability_sql($contexts->cat1course1forum, $caput); 5106 $users = $DB->get_records_sql($sql, $params); 5107 $this->assertArrayNotHasKey($uut->id, $users); 5108 5109 // But not if context locking is disabled. 5110 set_config('contextlocking', 0); 5111 list($sql, $params) = get_with_capability_sql($contexts->cat1course1forum, $caput); 5112 $users = $DB->get_records_sql($sql, $params); 5113 $this->assertArrayHasKey($uut->id, $users); 5114 5115 $contexts->cat1course1->set_locked(false); 5116 5117 // Freezing the category will have the same effect. 5118 set_config('contextlocking', 1); 5119 $contexts->cat1->set_locked(true); 5120 list($sql, $params) = get_with_capability_sql($contexts->cat1course1forum, $caput); 5121 $users = $DB->get_records_sql($sql, $params); 5122 $this->assertArrayNotHasKey($uut->id, $users); 5123 5124 // But not if context locking is disabled. 5125 set_config('contextlocking', 0); 5126 list($sql, $params) = get_with_capability_sql($contexts->cat1course1forum, $caput); 5127 $users = $DB->get_records_sql($sql, $params); 5128 $this->assertArrayHasKey($uut->id, $users); 5129 5130 $contexts->cat1->set_locked(false); 5131 5132 // Freezing an unrelated category will have no effect. 5133 set_config('contextlocking', 1); 5134 $contexts->cat2->set_locked(true); 5135 list($sql, $params) = get_with_capability_sql($contexts->cat1course1forum, $caput); 5136 $users = $DB->get_records_sql($sql, $params); 5137 $this->assertArrayHasKey($uut->id, $users); 5138 } 5139 5140 /** 5141 * Ensure that get_users_by_capability respects context freezing. 5142 * 5143 * @covers ::get_users_by_capability 5144 */ 5145 public function test_get_users_by_capability_locked() { 5146 $this->resetAfterTest(); 5147 5148 $generator = $this->getDataGenerator(); 5149 5150 $cat1 = $generator->create_category(); 5151 $cat2 = $generator->create_category(); 5152 $cat1course1 = $generator->create_course(['category' => $cat1->id]); 5153 $cat1course1forum = $generator->create_module('forum', ['course' => $cat1course1]); 5154 5155 $contexts = (object) [ 5156 'system' => \context_system::instance(), 5157 'cat1' => \context_coursecat::instance($cat1->id), 5158 'cat2' => \context_coursecat::instance($cat2->id), 5159 'cat1course1' => \context_course::instance($cat1course1->id), 5160 'cat1course1forum' => \context_module::instance($cat1course1forum->cmid), 5161 ]; 5162 5163 // Test with the 'mod/forum:startdiscussion' capability. 5164 $caput = 'mod/forum:startdiscussion'; 5165 5166 // Create a test user. 5167 $uut = $generator->create_and_enrol($cat1course1, 'teacher'); 5168 5169 // Initially the user will be returned by get_users_by_capability. 5170 $users = get_users_by_capability($contexts->cat1course1forum, $caput); 5171 $this->assertArrayHasKey($uut->id, $users); 5172 5173 // Freezing the forum will remove the user. 5174 set_config('contextlocking', 1); 5175 $contexts->cat1course1forum->set_locked(true); 5176 $users = get_users_by_capability($contexts->cat1course1forum, $caput); 5177 $this->assertArrayNotHasKey($uut->id, $users); 5178 5179 // But not if context locking is disabled. 5180 set_config('contextlocking', 0); 5181 $users = get_users_by_capability($contexts->cat1course1forum, $caput); 5182 $this->assertArrayHasKey($uut->id, $users); 5183 5184 $contexts->cat1course1forum->set_locked(false); 5185 5186 // Freezing the course will have the same effect. 5187 set_config('contextlocking', 1); 5188 $contexts->cat1course1->set_locked(true); 5189 $users = get_users_by_capability($contexts->cat1course1forum, $caput); 5190 $this->assertArrayNotHasKey($uut->id, $users); 5191 5192 // But not if context locking is disabled. 5193 set_config('contextlocking', 0); 5194 $users = get_users_by_capability($contexts->cat1course1forum, $caput); 5195 $this->assertArrayHasKey($uut->id, $users); 5196 5197 $contexts->cat1course1->set_locked(false); 5198 5199 // Freezing the category will have the same effect. 5200 set_config('contextlocking', 1); 5201 $contexts->cat1->set_locked(true); 5202 $users = get_users_by_capability($contexts->cat1course1forum, $caput); 5203 $this->assertArrayNotHasKey($uut->id, $users); 5204 5205 // But not if context locking is disabled. 5206 set_config('contextlocking', 0); 5207 $users = get_users_by_capability($contexts->cat1course1forum, $caput); 5208 $this->assertArrayHasKey($uut->id, $users); 5209 5210 $contexts->cat1->set_locked(false); 5211 5212 // Freezing an unrelated category will have no effect. 5213 set_config('contextlocking', 1); 5214 $contexts->cat2->set_locked(true); 5215 $users = get_users_by_capability($contexts->cat1course1forum, $caput); 5216 $this->assertArrayHasKey($uut->id, $users); 5217 } 5218 5219 /** 5220 * Test require_all_capabilities. 5221 * 5222 * @covers ::require_all_capabilities 5223 */ 5224 public function test_require_all_capabilities() { 5225 global $DB; 5226 5227 $this->resetAfterTest(); 5228 5229 $course = $this->getDataGenerator()->create_course(); 5230 $coursecontext = context_course::instance($course->id); 5231 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 5232 $teacher = $this->getDataGenerator()->create_user(); 5233 role_assign($teacherrole->id, $teacher->id, $coursecontext); 5234 5235 // Note: Here are used default capabilities, the full test is in permission evaluation bellow, 5236 // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user. 5237 $this->assertTrue($DB->record_exists('capabilities', array('name' => 'moodle/backup:backupsection'))); 5238 $this->assertTrue($DB->record_exists('capabilities', array('name' => 'moodle/backup:backupcourse'))); 5239 5240 $sca = array('moodle/backup:backupsection', 'moodle/backup:backupcourse'); 5241 5242 $this->setUser($teacher); 5243 require_all_capabilities($sca, $coursecontext); 5244 require_all_capabilities($sca, $coursecontext, $teacher); 5245 5246 // Guest users should not have any of these perms. 5247 $this->setUser(0); 5248 $this->expectException(\required_capability_exception::class); 5249 require_all_capabilities($sca, $coursecontext); 5250 } 5251 5252 /** 5253 * Test get_navigation_filter_context. 5254 * 5255 * @covers ::get_navigation_filter_context 5256 */ 5257 public function test_get_navigation_filter_context() { 5258 $this->resetAfterTest(); 5259 $course = $this->getDataGenerator()->create_course(); 5260 set_config('filternavigationwithsystemcontext', 0); 5261 // First test passed values are returned if disabled. 5262 $this->assertNull(context_helper::get_navigation_filter_context(null)); 5263 $coursecontext = context_course::instance($course->id); 5264 $filtercontext = context_helper::get_navigation_filter_context($coursecontext); 5265 $this->assertEquals($coursecontext->id, $filtercontext->id); 5266 5267 // Now test that any input returns system context if enabled. 5268 set_config('filternavigationwithsystemcontext', 1); 5269 $filtercontext = context_helper::get_navigation_filter_context(null); 5270 $this->assertInstanceOf('\context_system', $filtercontext); 5271 $filtercontext = context_helper::get_navigation_filter_context($coursecontext); 5272 $this->assertInstanceOf('\context_system', $filtercontext); 5273 } 5274 } 5275 5276 /** 5277 * Context caching fixture 5278 */ 5279 abstract class context_inspection extends \core\context_helper { 5280 public static function test_context_cache_size() { 5281 return self::$cache_count; 5282 } 5283 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body