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