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