Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 38 and 311] [Versions 39 and 311]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Full functional accesslib test. 19 * 20 * @package core 21 * @category phpunit 22 * @copyright 2011 Petr Skoda {@link http://skodak.org} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 29 /** 30 * Functional test for accesslib.php 31 * 32 * Note: execution may take many minutes especially on slower servers. 33 */ 34 class core_accesslib_testcase extends advanced_testcase { 35 /** 36 * Verify comparison of context instances in phpunit asserts. 37 */ 38 public function test_context_comparisons() { 39 $frontpagecontext1 = context_course::instance(SITEID); 40 context_helper::reset_caches(); 41 $frontpagecontext2 = context_course::instance(SITEID); 42 $this->assertEquals($frontpagecontext1, $frontpagecontext2); 43 44 $user1 = context_user::instance(1); 45 $user2 = context_user::instance(2); 46 $this->assertNotEquals($user1, $user2); 47 } 48 49 /** 50 * Test resetting works. 51 */ 52 public function test_accesslib_clear_all_caches() { 53 global $ACCESSLIB_PRIVATE; 54 55 $this->resetAfterTest(); 56 57 $this->setAdminUser(); 58 load_all_capabilities(); 59 60 $this->assertNotEmpty($ACCESSLIB_PRIVATE->accessdatabyuser); 61 accesslib_clear_all_caches_for_unit_testing(); 62 $this->assertEmpty($ACCESSLIB_PRIVATE->dirtycontexts); 63 $this->assertEmpty($ACCESSLIB_PRIVATE->accessdatabyuser); 64 } 65 66 /** 67 * Check modifying capability record is not exposed to other code. 68 */ 69 public function test_capabilities_mutation() { 70 $oldcap = get_capability_info('moodle/site:config'); 71 $cap = get_capability_info('moodle/site:config'); 72 unset($cap->name); 73 $newcap = get_capability_info('moodle/site:config'); 74 75 $this->assertFalse(isset($cap->name)); 76 $this->assertTrue(isset($newcap->name)); 77 $this->assertTrue(isset($oldcap->name)); 78 } 79 80 /** 81 * Test getting of role access 82 */ 83 public function test_get_role_access() { 84 global $DB; 85 86 $roles = $DB->get_records('role'); 87 foreach ($roles as $role) { 88 $access = get_role_access($role->id); 89 90 $this->assertTrue(is_array($access)); 91 $this->assertTrue(is_array($access['ra'])); 92 $this->assertFalse(isset($access['rdef'])); 93 $this->assertFalse(isset($access['rdef_count'])); 94 $this->assertFalse(isset($access['loaded'])); 95 $this->assertTrue(isset($access['time'])); 96 $this->assertTrue(is_array($access['rsw'])); 97 } 98 99 // Note: the data is validated in the functional permission evaluation test at the end of this testcase. 100 } 101 102 /** 103 * Test getting of guest role. 104 */ 105 public function test_get_guest_role() { 106 global $CFG; 107 108 $guest = get_guest_role(); 109 $this->assertEquals('guest', $guest->archetype); 110 $this->assertEquals('guest', $guest->shortname); 111 112 $this->assertEquals($CFG->guestroleid, $guest->id); 113 } 114 115 /** 116 * Test if user is admin. 117 */ 118 public function test_is_siteadmin() { 119 global $DB, $CFG; 120 121 $this->resetAfterTest(); 122 123 $users = $DB->get_records('user'); 124 125 foreach ($users as $user) { 126 $this->setUser(0); 127 if ($user->username === 'admin') { 128 $this->assertTrue(is_siteadmin($user)); 129 $this->assertTrue(is_siteadmin($user->id)); 130 $this->setUser($user); 131 $this->assertTrue(is_siteadmin()); 132 $this->assertTrue(is_siteadmin(null)); 133 } else { 134 $this->assertFalse(is_siteadmin($user)); 135 $this->assertFalse(is_siteadmin($user->id)); 136 $this->setUser($user); 137 $this->assertFalse(is_siteadmin()); 138 $this->assertFalse(is_siteadmin(null)); 139 } 140 } 141 142 // Change the site admin list and check that it still works with 143 // multiple admins. We do this with userids only (not real user 144 // accounts) because it makes the test simpler. 145 $before = $CFG->siteadmins; 146 set_config('siteadmins', '666,667,668'); 147 $this->assertTrue(is_siteadmin(666)); 148 $this->assertTrue(is_siteadmin(667)); 149 $this->assertTrue(is_siteadmin(668)); 150 $this->assertFalse(is_siteadmin(669)); 151 set_config('siteadmins', '13'); 152 $this->assertTrue(is_siteadmin(13)); 153 $this->assertFalse(is_siteadmin(666)); 154 set_config('siteadmins', $before); 155 } 156 157 /** 158 * Test if user is enrolled in a course 159 */ 160 public function test_is_enrolled() { 161 global $DB; 162 163 $this->resetAfterTest(); 164 165 // Generate data. 166 $user = $this->getDataGenerator()->create_user(); 167 $course = $this->getDataGenerator()->create_course(); 168 $coursecontext = context_course::instance($course->id); 169 $role = $DB->get_record('role', array('shortname'=>'student')); 170 171 // There should be a manual enrolment as part of the default install. 172 $plugin = enrol_get_plugin('manual'); 173 $instance = $DB->get_record('enrol', array( 174 'courseid' => $course->id, 175 'enrol' => 'manual', 176 )); 177 $this->assertNotSame(false, $instance); 178 179 // Enrol the user in the course. 180 $plugin->enrol_user($instance, $user->id, $role->id); 181 182 // We'll test with the mod/assign:submit capability. 183 $capability= 'mod/assign:submit'; 184 $this->assertTrue($DB->record_exists('capabilities', array('name' => $capability))); 185 186 // Switch to our user. 187 $this->setUser($user); 188 189 // Ensure that the user has the capability first. 190 $this->assertTrue(has_capability($capability, $coursecontext, $user->id)); 191 192 // We first test whether the user is enrolled on the course as this 193 // seeds the cache, then we test for the capability. 194 $this->assertTrue(is_enrolled($coursecontext, $user, '', true)); 195 $this->assertTrue(is_enrolled($coursecontext, $user, $capability)); 196 197 // Prevent the capability for this user role. 198 assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext); 199 $this->assertFalse(has_capability($capability, $coursecontext, $user->id)); 200 201 // Again, we seed the cache first by checking initial enrolment, 202 // and then we test the actual capability. 203 $this->assertTrue(is_enrolled($coursecontext, $user, '', true)); 204 $this->assertFalse(is_enrolled($coursecontext, $user, $capability)); 205 } 206 207 /** 208 * Test logged in test. 209 */ 210 public function test_isloggedin() { 211 global $USER; 212 213 $this->resetAfterTest(); 214 215 $USER->id = 0; 216 $this->assertFalse(isloggedin()); 217 $USER->id = 1; 218 $this->assertTrue(isloggedin()); 219 } 220 221 /** 222 * Test guest user test. 223 */ 224 public function test_isguestuser() { 225 global $DB; 226 227 $this->resetAfterTest(); 228 229 $guest = $DB->get_record('user', array('username'=>'guest')); 230 $this->setUser(0); 231 $this->assertFalse(isguestuser()); 232 $this->setAdminUser(); 233 $this->assertFalse(isguestuser()); 234 $this->assertTrue(isguestuser($guest)); 235 $this->assertTrue(isguestuser($guest->id)); 236 $this->setUser($guest); 237 $this->assertTrue(isguestuser()); 238 239 $users = $DB->get_records('user'); 240 foreach ($users as $user) { 241 if ($user->username === 'guest') { 242 continue; 243 } 244 $this->assertFalse(isguestuser($user)); 245 } 246 } 247 248 /** 249 * Test capability riskiness. 250 */ 251 public function test_is_safe_capability() { 252 global $DB; 253 // Note: there is not much to test, just make sure no notices are throw for the most dangerous cap. 254 $capability = $DB->get_record('capabilities', array('name'=>'moodle/site:config'), '*', MUST_EXIST); 255 $this->assertFalse(is_safe_capability($capability)); 256 } 257 258 /** 259 * Test context fetching. 260 */ 261 public function test_get_context_info_array() { 262 $this->resetAfterTest(); 263 264 $syscontext = context_system::instance(); 265 $user = $this->getDataGenerator()->create_user(); 266 $usercontext = context_user::instance($user->id); 267 $course = $this->getDataGenerator()->create_course(); 268 $catcontext = context_coursecat::instance($course->category); 269 $coursecontext = context_course::instance($course->id); 270 $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id)); 271 $modcontext = context_module::instance($page->cmid); 272 $cm = get_coursemodule_from_instance('page', $page->id); 273 $block1 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$coursecontext->id)); 274 $block1context = context_block::instance($block1->id); 275 $block2 = $this->getDataGenerator()->create_block('online_users', array('parentcontextid'=>$modcontext->id)); 276 $block2context = context_block::instance($block2->id); 277 278 $result = get_context_info_array($syscontext->id); 279 $this->assertCount(3, $result); 280 $this->assertEquals($syscontext, $result[0]); 281 $this->assertNull($result[1]); 282 $this->assertNull($result[2]); 283 284 $result = get_context_info_array($usercontext->id); 285 $this->assertCount(3, $result); 286 $this->assertEquals($usercontext, $result[0]); 287 $this->assertNull($result[1]); 288 $this->assertNull($result[2]); 289 290 $result = get_context_info_array($catcontext->id); 291 $this->assertCount(3, $result); 292 $this->assertEquals($catcontext, $result[0]); 293 $this->assertNull($result[1]); 294 $this->assertNull($result[2]); 295 296 $result = get_context_info_array($coursecontext->id); 297 $this->assertCount(3, $result); 298 $this->assertEquals($coursecontext, $result[0]); 299 $this->assertEquals($course->id, $result[1]->id); 300 $this->assertSame($course->shortname, $result[1]->shortname); 301 $this->assertNull($result[2]); 302 303 $result = get_context_info_array($block1context->id); 304 $this->assertCount(3, $result); 305 $this->assertEquals($block1context, $result[0]); 306 $this->assertEquals($course->id, $result[1]->id); 307 $this->assertEquals($course->shortname, $result[1]->shortname); 308 $this->assertNull($result[2]); 309 310 $result = get_context_info_array($modcontext->id); 311 $this->assertCount(3, $result); 312 $this->assertEquals($modcontext, $result[0]); 313 $this->assertEquals($course->id, $result[1]->id); 314 $this->assertSame($course->shortname, $result[1]->shortname); 315 $this->assertEquals($cm->id, $result[2]->id); 316 317 $result = get_context_info_array($block2context->id); 318 $this->assertCount(3, $result); 319 $this->assertEquals($block2context, $result[0]); 320 $this->assertEquals($course->id, $result[1]->id); 321 $this->assertSame($course->shortname, $result[1]->shortname); 322 $this->assertEquals($cm->id, $result[2]->id); 323 } 324 325 /** 326 * Test looking for course contacts. 327 */ 328 public function test_has_coursecontact_role() { 329 global $DB, $CFG; 330 331 $this->resetAfterTest(); 332 333 $users = $DB->get_records('user'); 334 335 // Nobody is expected to have any course level roles. 336 $this->assertNotEmpty($CFG->coursecontact); 337 foreach ($users as $user) { 338 $this->assertFalse(has_coursecontact_role($user->id)); 339 } 340 341 $user = $this->getDataGenerator()->create_user(); 342 $course = $this->getDataGenerator()->create_course(); 343 $contactroles = preg_split('/,/', $CFG->coursecontact); 344 $roleid = reset($contactroles); 345 role_assign($roleid, $user->id, context_course::instance($course->id)); 346 $this->assertTrue(has_coursecontact_role($user->id)); 347 } 348 349 /** 350 * Test creation of roles. 351 */ 352 public function test_create_role() { 353 global $DB; 354 355 $this->resetAfterTest(); 356 357 $id = create_role('New student role', 'student2', 'New student description', 'student'); 358 $role = $DB->get_record('role', array('id'=>$id)); 359 360 $this->assertNotEmpty($role); 361 $this->assertSame('New student role', $role->name); 362 $this->assertSame('student2', $role->shortname); 363 $this->assertSame('New student description', $role->description); 364 $this->assertSame('student', $role->archetype); 365 } 366 367 /** 368 * Test adding of capabilities to roles. 369 */ 370 public function test_assign_capability() { 371 global $DB, $USER; 372 373 $this->resetAfterTest(); 374 375 $user = $this->getDataGenerator()->create_user(); 376 $syscontext = context_system::instance(); 377 $frontcontext = context_course::instance(SITEID); 378 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 379 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to student by default. 380 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'))); 381 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'))); 382 383 $this->setUser($user); 384 $result = assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $frontcontext->id); 385 $this->assertTrue($result); 386 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')); 387 $this->assertNotEmpty($permission); 388 $this->assertEquals(CAP_ALLOW, $permission->permission); 389 $this->assertEquals($user->id, $permission->modifierid); 390 391 $this->setUser(0); 392 $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, false); 393 $this->assertTrue($result); 394 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')); 395 $this->assertNotEmpty($permission); 396 $this->assertEquals(CAP_ALLOW, $permission->permission); 397 $this->assertEquals($user->id, $permission->modifierid); 398 399 $result = assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $student->id, $frontcontext->id, true); 400 $this->assertTrue($result); 401 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')); 402 $this->assertNotEmpty($permission); 403 $this->assertEquals(CAP_PROHIBIT, $permission->permission); 404 $this->assertEquals(0, $permission->modifierid); 405 406 $result = assign_capability('moodle/backup:backupcourse', CAP_INHERIT, $student->id, $frontcontext->id); 407 $this->assertTrue($result); 408 $permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse')); 409 $this->assertEmpty($permission); 410 411 // Test event triggered. 412 $sink = $this->redirectEvents(); 413 $capability = 'moodle/backup:backupcourse'; 414 assign_capability($capability, CAP_ALLOW, $student->id, $syscontext); 415 $events = $sink->get_events(); 416 $sink->close(); 417 $this->assertCount(1, $events); 418 $event = $events[0]; 419 $this->assertInstanceOf('\core\event\capability_assigned', $event); 420 $this->assertSame('role_capabilities', $event->objecttable); 421 $this->assertEquals($student->id, $event->objectid); 422 $this->assertEquals($syscontext->id, $event->contextid); 423 $other = ['capability' => $capability, 'oldpermission' => CAP_INHERIT, 'permission' => CAP_ALLOW]; 424 $this->assertEquals($other, $event->other); 425 $description = "The user id '$USER->id' assigned the '$capability' capability for " . 426 "role '$student->id' with 'Allow' permission"; 427 $this->assertEquals($description, $event->get_description()); 428 429 // Test if the event has different description when updating the capability permission. 430 $sink = $this->redirectEvents(); 431 assign_capability($capability, CAP_PROHIBIT, $student->id, $syscontext, true); 432 $events = $sink->get_events(); 433 $sink->close(); 434 $event = $events[0]; 435 $description = "The user id '$USER->id' changed the '$capability' capability permission for " . 436 "role '$student->id' from 'Allow' to 'Prohibit'"; 437 $this->assertEquals($description, $event->get_description()); 438 } 439 440 /** 441 * Test removing of capabilities from roles. 442 */ 443 public function test_unassign_capability() { 444 global $DB, $USER; 445 446 $this->resetAfterTest(); 447 448 $syscontext = context_system::instance(); 449 $frontcontext = context_course::instance(SITEID); 450 $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST); 451 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability assigned to manager by default. 452 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id); 453 454 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 455 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 456 457 $result = unassign_capability('moodle/backup:backupcourse', $manager->id, $syscontext->id); 458 $this->assertTrue($result); 459 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 460 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 461 unassign_capability('moodle/backup:backupcourse', $manager->id, $frontcontext); 462 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 463 464 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id); 465 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $frontcontext->id); 466 $this->assertTrue($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 467 468 $result = unassign_capability('moodle/backup:backupcourse', $manager->id); 469 $this->assertTrue($result); 470 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 471 $this->assertFalse($DB->record_exists('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$manager->id, 'capability'=>'moodle/backup:backupcourse'))); 472 473 // Test event triggered. 474 $sink = $this->redirectEvents(); 475 $capability = 'moodle/backup:backupcourse'; 476 unassign_capability($capability, CAP_ALLOW, $manager->id); 477 $events = $sink->get_events(); 478 $sink->close(); 479 $this->assertCount(1, $events); 480 $event = $events[0]; 481 $this->assertInstanceOf('\core\event\capability_unassigned', $event); 482 $this->assertSame('role_capabilities', $event->objecttable); 483 $this->assertEquals($manager->id, $event->objectid); 484 $this->assertEquals($syscontext->id, $event->contextid); 485 $this->assertEquals($capability, $event->other['capability']); 486 $description = "The user id id '$USER->id' has unassigned the '$capability' capability for role '$manager->id'"; 487 $this->assertEquals($description, $event->get_description()); 488 } 489 490 /** 491 * Test role assigning. 492 */ 493 public function test_role_assign() { 494 global $DB, $USER; 495 496 $this->resetAfterTest(); 497 498 $user = $this->getDataGenerator()->create_user(); 499 $course = $this->getDataGenerator()->create_course(); 500 $role = $DB->get_record('role', array('shortname'=>'student')); 501 502 $this->setUser(0); 503 $context = context_system::instance(); 504 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 505 role_assign($role->id, $user->id, $context->id); 506 $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)); 507 $this->assertNotEmpty($ras); 508 $this->assertSame('', $ras->component); 509 $this->assertSame('0', $ras->itemid); 510 $this->assertEquals($USER->id, $ras->modifierid); 511 512 $this->setAdminUser(); 513 $context = context_course::instance($course->id); 514 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 515 role_assign($role->id, $user->id, $context->id, 'enrol_self', 1, 666); 516 $ras = $DB->get_record('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id)); 517 $this->assertNotEmpty($ras); 518 $this->assertSame('enrol_self', $ras->component); 519 $this->assertSame('1', $ras->itemid); 520 $this->assertEquals($USER->id, $ras->modifierid); 521 $this->assertEquals(666, $ras->timemodified); 522 523 // Test event triggered. 524 525 $user2 = $this->getDataGenerator()->create_user(); 526 $sink = $this->redirectEvents(); 527 $raid = role_assign($role->id, $user2->id, $context->id); 528 $events = $sink->get_events(); 529 $sink->close(); 530 $this->assertCount(1, $events); 531 $event = $events[0]; 532 $this->assertInstanceOf('\core\event\role_assigned', $event); 533 $this->assertSame('role', $event->target); 534 $this->assertSame('role', $event->objecttable); 535 $this->assertEquals($role->id, $event->objectid); 536 $this->assertEquals($context->id, $event->contextid); 537 $this->assertEquals($user2->id, $event->relateduserid); 538 $this->assertCount(3, $event->other); 539 $this->assertEquals($raid, $event->other['id']); 540 $this->assertSame('', $event->other['component']); 541 $this->assertEquals(0, $event->other['itemid']); 542 $this->assertInstanceOf('moodle_url', $event->get_url()); 543 $this->assertSame('role_assigned', $event::get_legacy_eventname()); 544 $roles = get_all_roles(); 545 $rolenames = role_fix_names($roles, $context, ROLENAME_ORIGINAL, true); 546 $expectedlegacylog = array($course->id, 'role', 'assign', 547 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$role->id, $rolenames[$role->id], '', $USER->id); 548 $this->assertEventLegacyLogData($expectedlegacylog, $event); 549 } 550 551 /** 552 * Test role unassigning. 553 */ 554 public function test_role_unassign() { 555 global $DB, $USER; 556 557 $this->resetAfterTest(); 558 559 $user = $this->getDataGenerator()->create_user(); 560 $course = $this->getDataGenerator()->create_course(); 561 $role = $DB->get_record('role', array('shortname'=>'student')); 562 563 $context = context_course::instance($course->id); 564 role_assign($role->id, $user->id, $context->id); 565 $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 566 role_unassign($role->id, $user->id, $context->id); 567 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 568 569 role_assign($role->id, $user->id, $context->id, 'enrol_self', 1); 570 $this->assertTrue($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 571 role_unassign($role->id, $user->id, $context->id, 'enrol_self', 1); 572 $this->assertFalse($DB->record_exists('role_assignments', array('userid'=>$user->id, 'roleid'=>$role->id, 'contextid'=>$context->id))); 573 574 // Test event triggered. 575 576 role_assign($role->id, $user->id, $context->id); 577 $sink = $this->redirectEvents(); 578 role_unassign($role->id, $user->id, $context->id); 579 $events = $sink->get_events(); 580 $sink->close(); 581 $this->assertCount(1, $events); 582 $event = $events[0]; 583 $this->assertInstanceOf('\core\event\role_unassigned', $event); 584 $this->assertSame('role', $event->target); 585 $this->assertSame('role', $event->objecttable); 586 $this->assertEquals($role->id, $event->objectid); 587 $this->assertEquals($context->id, $event->contextid); 588 $this->assertEquals($user->id, $event->relateduserid); 589 $this->assertCount(3, $event->other); 590 $this->assertSame('', $event->other['component']); 591 $this->assertEquals(0, $event->other['itemid']); 592 $this->assertInstanceOf('moodle_url', $event->get_url()); 593 $roles = get_all_roles(); 594 $rolenames = role_fix_names($roles, $context, ROLENAME_ORIGINAL, true); 595 $expectedlegacylog = array($course->id, 'role', 'unassign', 596 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$role->id, $rolenames[$role->id], '', $USER->id); 597 $this->assertEventLegacyLogData($expectedlegacylog, $event); 598 } 599 600 /** 601 * Test role unassigning. 602 */ 603 public function test_role_unassign_all() { 604 global $DB; 605 606 $this->resetAfterTest(); 607 608 $user = $this->getDataGenerator()->create_user(); 609 $course = $this->getDataGenerator()->create_course(); 610 $role = $DB->get_record('role', array('shortname'=>'student')); 611 $role2 = $DB->get_record('role', array('shortname'=>'teacher')); 612 $syscontext = context_system::instance(); 613 $coursecontext = context_course::instance($course->id); 614 $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id)); 615 $modcontext = context_module::instance($page->cmid); 616 617 role_assign($role->id, $user->id, $syscontext->id); 618 role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1); 619 $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id))); 620 role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role->id)); 621 $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id))); 622 623 role_assign($role->id, $user->id, $syscontext->id); 624 role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1); 625 role_assign($role->id, $user->id, $modcontext->id); 626 $this->assertEquals(3, $DB->count_records('role_assignments', array('userid'=>$user->id))); 627 role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), false); 628 $this->assertEquals(2, $DB->count_records('role_assignments', array('userid'=>$user->id))); 629 role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id), true); 630 $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id))); 631 role_unassign_all(array('userid'=>$user->id)); 632 $this->assertEquals(0, $DB->count_records('role_assignments', array('userid'=>$user->id))); 633 634 role_assign($role->id, $user->id, $syscontext->id); 635 role_assign($role->id, $user->id, $coursecontext->id, 'enrol_self', 1); 636 role_assign($role->id, $user->id, $coursecontext->id); 637 role_assign($role->id, $user->id, $modcontext->id); 638 $this->assertEquals(4, $DB->count_records('role_assignments', array('userid'=>$user->id))); 639 role_unassign_all(array('userid'=>$user->id, 'contextid'=>$coursecontext->id, 'component'=>'enrol_self'), true, true); 640 $this->assertEquals(1, $DB->count_records('role_assignments', array('userid'=>$user->id))); 641 642 // Test events triggered. 643 644 role_assign($role2->id, $user->id, $coursecontext->id); 645 role_assign($role2->id, $user->id, $modcontext->id); 646 $sink = $this->redirectEvents(); 647 role_unassign_all(array('userid'=>$user->id, 'roleid'=>$role2->id)); 648 $events = $sink->get_events(); 649 $sink->close(); 650 $this->assertCount(2, $events); 651 $this->assertInstanceOf('\core\event\role_unassigned', $events[0]); 652 $this->assertInstanceOf('\core\event\role_unassigned', $events[1]); 653 } 654 655 /** 656 * Test role queries. 657 */ 658 public function test_get_roles_with_capability() { 659 global $DB; 660 661 $this->resetAfterTest(); 662 663 $syscontext = context_system::instance(); 664 $frontcontext = context_course::instance(SITEID); 665 $manager = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST); 666 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST); 667 668 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok. 669 $DB->delete_records('role_capabilities', array('capability'=>'moodle/backup:backupcourse')); 670 671 $roles = get_roles_with_capability('moodle/backup:backupcourse'); 672 $this->assertEquals(array(), $roles); 673 674 assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $manager->id, $syscontext->id); 675 assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $manager->id, $frontcontext->id); 676 assign_capability('moodle/backup:backupcourse', CAP_PREVENT, $teacher->id, $frontcontext->id); 677 678 $roles = get_roles_with_capability('moodle/backup:backupcourse'); 679 $this->assertEqualsCanonicalizing(array($teacher->id, $manager->id), array_keys($roles), true); 680 681 $roles = get_roles_with_capability('moodle/backup:backupcourse', CAP_ALLOW); 682 $this->assertEqualsCanonicalizing(array($manager->id), array_keys($roles), true); 683 684 $roles = get_roles_with_capability('moodle/backup:backupcourse', null, $syscontext); 685 $this->assertEqualsCanonicalizing(array($manager->id), array_keys($roles), true); 686 } 687 688 /** 689 * Test deleting of roles. 690 */ 691 public function test_delete_role() { 692 global $DB; 693 694 $this->resetAfterTest(); 695 696 $role = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST); 697 $user = $this->getDataGenerator()->create_user(); 698 role_assign($role->id, $user->id, context_system::instance()); 699 $course = $this->getDataGenerator()->create_course(); 700 $rolename = (object)array('roleid'=>$role->id, 'name'=>'Man', 'contextid'=>context_course::instance($course->id)->id); 701 $DB->insert_record('role_names', $rolename); 702 703 $this->assertTrue($DB->record_exists('role_assignments', array('roleid'=>$role->id))); 704 $this->assertTrue($DB->record_exists('role_capabilities', array('roleid'=>$role->id))); 705 $this->assertTrue($DB->record_exists('role_names', array('roleid'=>$role->id))); 706 $this->assertTrue($DB->record_exists('role_context_levels', array('roleid'=>$role->id))); 707 $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$role->id))); 708 $this->assertTrue($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id))); 709 $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$role->id))); 710 $this->assertTrue($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id))); 711 712 // Delete role and get event. 713 $sink = $this->redirectEvents(); 714 $result = delete_role($role->id); 715 $events = $sink->get_events(); 716 $sink->close(); 717 $event = array_pop($events); 718 719 $this->assertTrue($result); 720 $this->assertFalse($DB->record_exists('role', array('id'=>$role->id))); 721 $this->assertFalse($DB->record_exists('role_assignments', array('roleid'=>$role->id))); 722 $this->assertFalse($DB->record_exists('role_capabilities', array('roleid'=>$role->id))); 723 $this->assertFalse($DB->record_exists('role_names', array('roleid'=>$role->id))); 724 $this->assertFalse($DB->record_exists('role_context_levels', array('roleid'=>$role->id))); 725 $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$role->id))); 726 $this->assertFalse($DB->record_exists('role_allow_assign', array('allowassign'=>$role->id))); 727 $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$role->id))); 728 $this->assertFalse($DB->record_exists('role_allow_override', array('allowoverride'=>$role->id))); 729 730 // Test triggered event. 731 $this->assertInstanceOf('\core\event\role_deleted', $event); 732 $this->assertSame('role', $event->target); 733 $this->assertSame('role', $event->objecttable); 734 $this->assertSame($role->id, $event->objectid); 735 $this->assertEquals(context_system::instance(), $event->get_context()); 736 $this->assertSame($role->shortname, $event->other['shortname']); 737 $this->assertSame($role->description, $event->other['description']); 738 $this->assertSame($role->archetype, $event->other['archetype']); 739 740 $expectedlegacylog = array(SITEID, 'role', 'delete', 'admin/roles/manage.php?action=delete&roleid='.$role->id, 741 $role->shortname, ''); 742 $this->assertEventLegacyLogData($expectedlegacylog, $event); 743 } 744 745 /** 746 * Test fetching of all roles. 747 */ 748 public function test_get_all_roles() { 749 global $DB; 750 751 $this->resetAfterTest(); 752 753 $allroles = get_all_roles(); 754 $this->assertIsArray($allroles); 755 $initialrolescount = count($allroles); 756 $this->assertTrue($initialrolescount >= 8); // There are 8 roles is standard install. 757 $rolenames = array_column($allroles, 'shortname'); 758 foreach (get_role_archetypes() as $archetype) { 759 $this->assertContains($archetype, $rolenames); 760 } 761 762 $role = reset($allroles); 763 $role = (array)$role; 764 765 $this->assertEqualsCanonicalizing(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype'), 766 array_keys($role)); 767 768 foreach ($allroles as $roleid => $role) { 769 $this->assertEquals($role->id, $roleid); 770 } 771 772 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST); 773 $course = $this->getDataGenerator()->create_course(); 774 $coursecontext = context_course::instance($course->id); 775 $otherid = create_role('Other role', 'other', 'Some other role', ''); 776 $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 777 $DB->insert_record('role_names', $teacherename); 778 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id); 779 $DB->insert_record('role_names', $otherrename); 780 $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name'); 781 782 $allroles = get_all_roles($coursecontext); 783 $this->assertIsArray($allroles); 784 $this->assertCount($initialrolescount + 1, $allroles); 785 $role = reset($allroles); 786 $role = (array)$role; 787 788 $this->assertEqualsCanonicalizing(array('id', 'name', 'shortname', 'description', 'sortorder', 'archetype', 'coursealias'), array_keys($role)); 789 790 foreach ($allroles as $roleid => $role) { 791 $this->assertEquals($role->id, $roleid); 792 if (isset($renames[$roleid])) { 793 $this->assertSame($renames[$roleid], $role->coursealias); 794 } else { 795 $this->assertNull($role->coursealias); 796 } 797 } 798 } 799 800 /** 801 * Test getting of all archetypes. 802 */ 803 public function test_get_role_archetypes() { 804 $archetypes = get_role_archetypes(); 805 $this->assertCount(8, $archetypes); // There are 8 archetypes in standard install. 806 foreach ($archetypes as $k => $v) { 807 $this->assertSame($k, $v); 808 } 809 } 810 811 /** 812 * Test getting of roles with given archetype. 813 */ 814 public function test_get_archetype_roles() { 815 $this->resetAfterTest(); 816 817 // New install should have at least 1 role for each archetype. 818 $archetypes = get_role_archetypes(); 819 foreach ($archetypes as $archetype) { 820 $roles = get_archetype_roles($archetype); 821 $this->assertGreaterThanOrEqual(1, count($roles)); 822 $role = reset($roles); 823 $this->assertSame($archetype, $role->archetype); 824 } 825 826 create_role('New student role', 'student2', 'New student description', 'student'); 827 $roles = get_archetype_roles('student'); 828 $this->assertGreaterThanOrEqual(2, count($roles)); 829 } 830 831 /** 832 * Test aliased role names. 833 */ 834 public function test_role_get_name() { 835 global $DB; 836 837 $this->resetAfterTest(); 838 839 $allroles = $DB->get_records('role'); 840 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST); 841 $course = $this->getDataGenerator()->create_course(); 842 $coursecontext = context_course::instance($course->id); 843 $otherid = create_role('Other role', 'other', 'Some other role', ''); 844 $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 845 $DB->insert_record('role_names', $teacherename); 846 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id); 847 $DB->insert_record('role_names', $otherrename); 848 $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name'); 849 850 foreach ($allroles as $role) { 851 if (in_array($role->shortname, get_role_archetypes())) { 852 // Standard roles do not have a set name. 853 $this->assertSame('', $role->name); 854 } 855 // Get localised name from lang pack. 856 $name = role_get_name($role, null, ROLENAME_ORIGINAL); 857 $this->assertNotEmpty($name); 858 $this->assertNotEquals($role->shortname, $name); 859 860 if (isset($renames[$role->id])) { 861 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext)); 862 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS)); 863 $this->assertSame($renames[$role->id], role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW)); 864 $this->assertSame("{$renames[$role->id]} ($name)", role_get_name($role, $coursecontext, ROLENAME_BOTH)); 865 } else { 866 $this->assertSame($name, role_get_name($role, $coursecontext)); 867 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ALIAS)); 868 $this->assertNull(role_get_name($role, $coursecontext, ROLENAME_ALIAS_RAW)); 869 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_BOTH)); 870 } 871 $this->assertSame($name, role_get_name($role)); 872 $this->assertSame($name, role_get_name($role, $coursecontext, ROLENAME_ORIGINAL)); 873 $this->assertSame($name, role_get_name($role, null, ROLENAME_ORIGINAL)); 874 $this->assertSame($role->shortname, role_get_name($role, $coursecontext, ROLENAME_SHORT)); 875 $this->assertSame($role->shortname, role_get_name($role, null, ROLENAME_SHORT)); 876 $this->assertSame("$name ($role->shortname)", role_get_name($role, $coursecontext, ROLENAME_ORIGINALANDSHORT)); 877 $this->assertSame("$name ($role->shortname)", role_get_name($role, null, ROLENAME_ORIGINALANDSHORT)); 878 $this->assertNull(role_get_name($role, null, ROLENAME_ALIAS_RAW)); 879 } 880 } 881 882 /** 883 * Test tweaking of role name arrays. 884 */ 885 public function test_role_fix_names() { 886 global $DB; 887 888 $this->resetAfterTest(); 889 890 $teacher = $DB->get_record('role', array('shortname'=>'teacher'), '*', MUST_EXIST); 891 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 892 $otherid = create_role('Other role', 'other', 'Some other role', ''); 893 $anotherid = create_role('Another role', 'another', 'Yet another other role', ''); 894 $allroles = $DB->get_records('role'); 895 896 $syscontext = context_system::instance(); 897 $frontcontext = context_course::instance(SITEID); 898 $course = $this->getDataGenerator()->create_course(); 899 $coursecontext = context_course::instance($course->id); 900 $category = $DB->get_record('course_categories', array('id'=>$course->category), '*', MUST_EXIST); 901 $categorycontext = context_coursecat::instance($category->id); 902 903 $teacherename = (object)array('roleid'=>$teacher->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 904 $DB->insert_record('role_names', $teacherename); 905 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id); 906 $DB->insert_record('role_names', $otherrename); 907 $renames = $DB->get_records_menu('role_names', array('contextid'=>$coursecontext->id), '', 'roleid, name'); 908 909 // Make sure all localname contain proper values for each ROLENAME_ constant, 910 // note role_get_name() on frontpage is used to get the original name for future compatibility. 911 $roles = $allroles; 912 unset($roles[$student->id]); // Remove one role to make sure no role is added or removed. 913 $rolenames = array(); 914 foreach ($roles as $role) { 915 $rolenames[$role->id] = $role->name; 916 } 917 918 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT); 919 foreach ($alltypes as $type) { 920 $fixed = role_fix_names($roles, $coursecontext, $type); 921 $this->assertCount(count($roles), $fixed); 922 foreach ($fixed as $roleid => $rolename) { 923 $this->assertInstanceOf('stdClass', $rolename); 924 $role = $allroles[$roleid]; 925 $name = role_get_name($role, $coursecontext, $type); 926 $this->assertSame($name, $rolename->localname); 927 } 928 $fixed = role_fix_names($rolenames, $coursecontext, $type); 929 $this->assertCount(count($rolenames), $fixed); 930 foreach ($fixed as $roleid => $rolename) { 931 $role = $allroles[$roleid]; 932 $name = role_get_name($role, $coursecontext, $type); 933 $this->assertSame($name, $rolename); 934 } 935 } 936 } 937 938 /** 939 * Test role default allows. 940 */ 941 public function test_get_default_role_archetype_allows() { 942 $archetypes = get_role_archetypes(); 943 foreach ($archetypes as $archetype) { 944 945 $result = get_default_role_archetype_allows('assign', $archetype); 946 $this->assertIsArray($result); 947 948 $result = get_default_role_archetype_allows('override', $archetype); 949 $this->assertIsArray($result); 950 951 $result = get_default_role_archetype_allows('switch', $archetype); 952 $this->assertIsArray($result); 953 954 $result = get_default_role_archetype_allows('view', $archetype); 955 $this->assertIsArray($result); 956 } 957 958 $result = get_default_role_archetype_allows('assign', ''); 959 $this->assertSame(array(), $result); 960 961 $result = get_default_role_archetype_allows('override', ''); 962 $this->assertSame(array(), $result); 963 964 $result = get_default_role_archetype_allows('switch', ''); 965 $this->assertSame(array(), $result); 966 967 $result = get_default_role_archetype_allows('view', ''); 968 $this->assertSame(array(), $result); 969 970 $result = get_default_role_archetype_allows('assign', 'wrongarchetype'); 971 $this->assertSame(array(), $result); 972 $this->assertDebuggingCalled(); 973 974 $result = get_default_role_archetype_allows('override', 'wrongarchetype'); 975 $this->assertSame(array(), $result); 976 $this->assertDebuggingCalled(); 977 978 $result = get_default_role_archetype_allows('switch', 'wrongarchetype'); 979 $this->assertSame(array(), $result); 980 $this->assertDebuggingCalled(); 981 982 $result = get_default_role_archetype_allows('view', 'wrongarchetype'); 983 $this->assertSame(array(), $result); 984 $this->assertDebuggingCalled(); 985 } 986 987 /** 988 * Test allowing of role assignments. 989 */ 990 public function test_core_role_set_assign_allowed() { 991 global $DB, $CFG; 992 993 $this->resetAfterTest(); 994 995 $otherid = create_role('Other role', 'other', 'Some other role', ''); 996 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 997 998 $this->assertFalse($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id))); 999 core_role_set_assign_allowed($otherid, $student->id); 1000 $this->assertTrue($DB->record_exists('role_allow_assign', array('roleid'=>$otherid, 'allowassign'=>$student->id))); 1001 1002 // Test event trigger. 1003 $allowroleassignevent = \core\event\role_allow_assign_updated::create([ 1004 'context' => context_system::instance(), 1005 'objectid' => $otherid, 1006 'other' => ['targetroleid' => $student->id] 1007 ]); 1008 $sink = $this->redirectEvents(); 1009 $allowroleassignevent->trigger(); 1010 $events = $sink->get_events(); 1011 $sink->close(); 1012 $event = array_pop($events); 1013 $this->assertInstanceOf('\core\event\role_allow_assign_updated', $event); 1014 $mode = 'assign'; 1015 $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode)); 1016 $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl)); 1017 $this->assertEventLegacyLogData($expectedlegacylog, $event); 1018 } 1019 1020 /** 1021 * Test allowing of role overrides. 1022 */ 1023 public function test_core_role_set_override_allowed() { 1024 global $DB, $CFG; 1025 1026 $this->resetAfterTest(); 1027 1028 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1029 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1030 1031 $this->assertFalse($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id))); 1032 core_role_set_override_allowed($otherid, $student->id); 1033 $this->assertTrue($DB->record_exists('role_allow_override', array('roleid'=>$otherid, 'allowoverride'=>$student->id))); 1034 1035 // Test event trigger. 1036 $allowroleassignevent = \core\event\role_allow_override_updated::create([ 1037 'context' => context_system::instance(), 1038 'objectid' => $otherid, 1039 'other' => ['targetroleid' => $student->id] 1040 ]); 1041 $sink = $this->redirectEvents(); 1042 $allowroleassignevent->trigger(); 1043 $events = $sink->get_events(); 1044 $sink->close(); 1045 $event = array_pop($events); 1046 $this->assertInstanceOf('\core\event\role_allow_override_updated', $event); 1047 $mode = 'override'; 1048 $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode)); 1049 $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl)); 1050 $this->assertEventLegacyLogData($expectedlegacylog, $event); 1051 } 1052 1053 /** 1054 * Test allowing of role switching. 1055 */ 1056 public function test_core_role_set_switch_allowed() { 1057 global $DB, $CFG; 1058 1059 $this->resetAfterTest(); 1060 1061 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1062 $student = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1063 1064 $this->assertFalse($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id))); 1065 core_role_set_switch_allowed($otherid, $student->id); 1066 $this->assertTrue($DB->record_exists('role_allow_switch', array('roleid'=>$otherid, 'allowswitch'=>$student->id))); 1067 1068 // Test event trigger. 1069 $allowroleassignevent = \core\event\role_allow_switch_updated::create([ 1070 'context' => context_system::instance(), 1071 'objectid' => $otherid, 1072 'other' => ['targetroleid' => $student->id] 1073 ]); 1074 $sink = $this->redirectEvents(); 1075 $allowroleassignevent->trigger(); 1076 $events = $sink->get_events(); 1077 $sink->close(); 1078 $event = array_pop($events); 1079 $this->assertInstanceOf('\core\event\role_allow_switch_updated', $event); 1080 $mode = 'switch'; 1081 $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode)); 1082 $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl)); 1083 $this->assertEventLegacyLogData($expectedlegacylog, $event); 1084 } 1085 1086 /** 1087 * Test allowing of role switching. 1088 */ 1089 public function test_core_role_set_view_allowed() { 1090 global $DB, $CFG; 1091 1092 $this->resetAfterTest(); 1093 1094 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1095 $student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 1096 1097 $this->assertFalse($DB->record_exists('role_allow_view', array('roleid' => $otherid, 'allowview' => $student->id))); 1098 core_role_set_view_allowed($otherid, $student->id); 1099 $this->assertTrue($DB->record_exists('role_allow_view', array('roleid' => $otherid, 'allowview' => $student->id))); 1100 1101 // Test event trigger. 1102 $allowroleassignevent = \core\event\role_allow_view_updated::create([ 1103 'context' => context_system::instance(), 1104 'objectid' => $otherid, 1105 'other' => ['targetroleid' => $student->id] 1106 ]); 1107 $sink = $this->redirectEvents(); 1108 $allowroleassignevent->trigger(); 1109 $events = $sink->get_events(); 1110 $sink->close(); 1111 $event = array_pop($events); 1112 $this->assertInstanceOf('\core\event\role_allow_view_updated', $event); 1113 $mode = 'view'; 1114 $baseurl = new moodle_url('/admin/roles/allow.php', array('mode' => $mode)); 1115 $expectedlegacylog = array(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl)); 1116 $this->assertEventLegacyLogData($expectedlegacylog, $event); 1117 } 1118 1119 /** 1120 * Test returning of assignable roles in context. 1121 */ 1122 public function test_get_assignable_roles() { 1123 global $DB; 1124 1125 $this->resetAfterTest(); 1126 1127 $course = $this->getDataGenerator()->create_course(); 1128 $coursecontext = context_course::instance($course->id); 1129 1130 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1131 $teacher = $this->getDataGenerator()->create_user(); 1132 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1133 $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1134 $DB->insert_record('role_names', $teacherename); 1135 1136 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1137 $student = $this->getDataGenerator()->create_user(); 1138 role_assign($studentrole->id, $student->id, $coursecontext); 1139 1140 $contexts = $DB->get_records('context'); 1141 $users = $DB->get_records('user'); 1142 $allroles = $DB->get_records('role'); 1143 1144 // Evaluate all results for all users in all contexts. 1145 foreach ($users as $user) { 1146 $this->setUser($user); 1147 foreach ($contexts as $contextid => $unused) { 1148 $context = context_helper::instance_by_id($contextid); 1149 $roles = get_assignable_roles($context, ROLENAME_SHORT); 1150 foreach ($allroles as $roleid => $role) { 1151 if (isset($roles[$roleid])) { 1152 if (is_siteadmin()) { 1153 $this->assertTrue($DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid))); 1154 } else { 1155 $this->assertTrue(user_can_assign($context, $roleid), "u:$user->id r:$roleid"); 1156 } 1157 $this->assertEquals($role->shortname, $roles[$roleid]); 1158 } else { 1159 $allowed = $DB->record_exists('role_context_levels', array('contextlevel'=>$context->contextlevel, 'roleid'=>$roleid)); 1160 if (is_siteadmin()) { 1161 $this->assertFalse($allowed); 1162 } else { 1163 $this->assertFalse($allowed and user_can_assign($context, $roleid), "u:$user->id, r:{$allroles[$roleid]->name}, c:$context->contextlevel"); 1164 } 1165 } 1166 } 1167 } 1168 } 1169 1170 // Not-logged-in user. 1171 $this->setUser(0); 1172 foreach ($contexts as $contextid => $unused) { 1173 $context = context_helper::instance_by_id($contextid); 1174 $roles = get_assignable_roles($context, ROLENAME_SHORT); 1175 $this->assertSame(array(), $roles); 1176 } 1177 1178 // Test current user. 1179 $this->setUser(0); 1180 $admin = $DB->get_record('user', array('username'=>'admin'), '*', MUST_EXIST); 1181 $roles1 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin); 1182 $roles2 = get_assignable_roles($coursecontext, ROLENAME_SHORT, false, $admin->id); 1183 $this->setAdminUser(); 1184 $roles3 = get_assignable_roles($coursecontext, ROLENAME_SHORT); 1185 $this->assertSame($roles1, $roles3); 1186 $this->assertSame($roles2, $roles3); 1187 1188 // Test parameter defaults. 1189 $this->setAdminUser(); 1190 $roles1 = get_assignable_roles($coursecontext); 1191 $roles2 = get_assignable_roles($coursecontext, ROLENAME_ALIAS, false, $admin); 1192 $this->assertEquals($roles2, $roles1); 1193 1194 // Verify returned names - let's allow all roles everywhere to simplify this a bit. 1195 $alllevels = context_helper::get_all_levels(); 1196 $alllevels = array_keys($alllevels); 1197 foreach ($allroles as $roleid => $role) { 1198 set_role_contextlevels($roleid, $alllevels); 1199 } 1200 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT); 1201 foreach ($alltypes as $type) { 1202 $rolenames = role_fix_names($allroles, $coursecontext, $type); 1203 $roles = get_assignable_roles($coursecontext, $type, false, $admin); 1204 foreach ($roles as $roleid => $rolename) { 1205 $this->assertSame($rolenames[$roleid]->localname, $rolename); 1206 } 1207 } 1208 1209 // Verify counts. 1210 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT); 1211 foreach ($alltypes as $type) { 1212 $roles = get_assignable_roles($coursecontext, $type, false, $admin); 1213 list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($coursecontext, $type, true, $admin); 1214 $this->assertEquals($roles, $rolenames); 1215 foreach ($rolenames as $roleid => $name) { 1216 if ($roleid == $teacherrole->id or $roleid == $studentrole->id) { 1217 $this->assertEquals(1, $rolecounts[$roleid]); 1218 } else { 1219 $this->assertEquals(0, $rolecounts[$roleid]); 1220 } 1221 $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]); 1222 } 1223 } 1224 } 1225 1226 /** 1227 * Test user count of assignable roles in context where users are assigned the role via different components. 1228 */ 1229 public function test_get_assignable_roles_distinct_usercount() { 1230 global $DB; 1231 1232 $this->resetAfterTest(true); 1233 1234 $this->setAdminUser(); 1235 1236 $course = $this->getDataGenerator()->create_course(); 1237 $context = \context_course::instance($course->id); 1238 1239 $user1 = $this->getDataGenerator()->create_user(); 1240 $user2 = $this->getDataGenerator()->create_user(); 1241 1242 $studentrole = $DB->get_record('role', ['shortname' => 'student']); 1243 1244 // Assign each user the student role in course. 1245 role_assign($studentrole->id, $user1->id, $context->id); 1246 role_assign($studentrole->id, $user2->id, $context->id); 1247 1248 list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_SHORT, true); 1249 $this->assertEquals(2, $rolecounts[$studentrole->id]); 1250 1251 // Assign first user the student role in course again (this time via 'enrol_self' component). 1252 role_assign($studentrole->id, $user1->id, $context->id, 'enrol_self', 1); 1253 1254 // There are still only two distinct users. 1255 list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_SHORT, true); 1256 $this->assertEquals(2, $rolecounts[$studentrole->id]); 1257 } 1258 1259 /** 1260 * Test getting of all switchable roles. 1261 */ 1262 public function test_get_switchable_roles() { 1263 global $DB; 1264 1265 $this->resetAfterTest(); 1266 1267 $course = $this->getDataGenerator()->create_course(); 1268 $coursecontext = context_course::instance($course->id); 1269 1270 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1271 $teacher = $this->getDataGenerator()->create_user(); 1272 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1273 $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1274 $DB->insert_record('role_names', $teacherename); 1275 1276 $contexts = $DB->get_records('context'); 1277 $users = $DB->get_records('user'); 1278 $allroles = $DB->get_records('role'); 1279 1280 // Evaluate all results for all users in all contexts. 1281 foreach ($users as $user) { 1282 $this->setUser($user); 1283 foreach ($contexts as $contextid => $unused) { 1284 $context = context_helper::instance_by_id($contextid); 1285 $roles = get_switchable_roles($context); 1286 foreach ($allroles as $roleid => $role) { 1287 if (is_siteadmin()) { 1288 $this->assertTrue(isset($roles[$roleid])); 1289 } else { 1290 $parents = $context->get_parent_context_ids(true); 1291 $pcontexts = implode(',' , $parents); 1292 $allowed = $DB->record_exists_sql( 1293 "SELECT r.id 1294 FROM {role} r 1295 JOIN {role_allow_switch} ras ON ras.allowswitch = r.id 1296 JOIN {role_assignments} ra ON ra.roleid = ras.roleid 1297 WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid 1298 ", 1299 array('userid'=>$user->id, 'roleid'=>$roleid) 1300 ); 1301 if (isset($roles[$roleid])) { 1302 $this->assertTrue($allowed); 1303 } else { 1304 $this->assertFalse($allowed); 1305 } 1306 } 1307 1308 if (isset($roles[$roleid])) { 1309 $coursecontext = $context->get_course_context(false); 1310 $this->assertSame(role_get_name($role, $coursecontext), $roles[$roleid]); 1311 } 1312 } 1313 } 1314 } 1315 } 1316 1317 /** 1318 * Test getting of all overridable roles. 1319 */ 1320 public function test_get_overridable_roles() { 1321 global $DB; 1322 1323 $this->resetAfterTest(); 1324 1325 $course = $this->getDataGenerator()->create_course(); 1326 $coursecontext = context_course::instance($course->id); 1327 1328 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1329 $teacher = $this->getDataGenerator()->create_user(); 1330 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1331 $teacherename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1332 $DB->insert_record('role_names', $teacherename); 1333 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); // Any capability is ok. 1334 assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id); 1335 1336 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1337 $student = $this->getDataGenerator()->create_user(); 1338 role_assign($studentrole->id, $student->id, $coursecontext); 1339 1340 $contexts = $DB->get_records('context'); 1341 $users = $DB->get_records('user'); 1342 $allroles = $DB->get_records('role'); 1343 1344 // Evaluate all results for all users in all contexts. 1345 foreach ($users as $user) { 1346 $this->setUser($user); 1347 foreach ($contexts as $contextid => $unused) { 1348 $context = context_helper::instance_by_id($contextid); 1349 $roles = get_overridable_roles($context, ROLENAME_SHORT); 1350 foreach ($allroles as $roleid => $role) { 1351 $hascap = has_any_capability(array('moodle/role:safeoverride', 'moodle/role:override'), $context); 1352 if (is_siteadmin()) { 1353 $this->assertTrue(isset($roles[$roleid])); 1354 } else { 1355 $parents = $context->get_parent_context_ids(true); 1356 $pcontexts = implode(',' , $parents); 1357 $allowed = $DB->record_exists_sql( 1358 "SELECT r.id 1359 FROM {role} r 1360 JOIN {role_allow_override} rao ON r.id = rao.allowoverride 1361 JOIN {role_assignments} ra ON rao.roleid = ra.roleid 1362 WHERE ra.userid = :userid AND ra.contextid IN ($pcontexts) AND r.id = :roleid 1363 ", 1364 array('userid'=>$user->id, 'roleid'=>$roleid) 1365 ); 1366 if (isset($roles[$roleid])) { 1367 $this->assertTrue($hascap); 1368 $this->assertTrue($allowed); 1369 } else { 1370 $this->assertFalse($hascap and $allowed); 1371 } 1372 } 1373 1374 if (isset($roles[$roleid])) { 1375 $this->assertEquals($role->shortname, $roles[$roleid]); 1376 } 1377 } 1378 } 1379 } 1380 1381 // Test parameter defaults. 1382 $this->setAdminUser(); 1383 $roles1 = get_overridable_roles($coursecontext); 1384 $roles2 = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false); 1385 $this->assertEquals($roles2, $roles1); 1386 1387 $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT); 1388 foreach ($alltypes as $type) { 1389 $rolenames = role_fix_names($allroles, $coursecontext, $type); 1390 $roles = get_overridable_roles($coursecontext, $type, false); 1391 foreach ($roles as $roleid => $rolename) { 1392 $this->assertSame($rolenames[$roleid]->localname, $rolename); 1393 } 1394 } 1395 1396 // Verify counts. 1397 $roles = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false); 1398 list($rolenames, $rolecounts, $nameswithcounts) = get_overridable_roles($coursecontext, ROLENAME_ALIAS, true); 1399 $this->assertEquals($roles, $rolenames); 1400 foreach ($rolenames as $roleid => $name) { 1401 if ($roleid == $teacherrole->id) { 1402 $this->assertEquals(1, $rolecounts[$roleid]); 1403 } else { 1404 $this->assertEquals(0, $rolecounts[$roleid]); 1405 } 1406 $this->assertSame("$name ($rolecounts[$roleid])", $nameswithcounts[$roleid]); 1407 } 1408 } 1409 1410 /** 1411 * Test getting of all overridable roles. 1412 */ 1413 public function test_get_viewable_roles_course() { 1414 global $DB; 1415 1416 $this->resetAfterTest(); 1417 1418 $course = $this->getDataGenerator()->create_course(); 1419 $coursecontext = context_course::instance($course->id); 1420 1421 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 1422 $teacher = $this->getDataGenerator()->create_user(); 1423 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1424 1425 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 1426 $studentrolerename = (object) array('roleid' => $studentrole->id, 'name' => 'Učitel', 'contextid' => $coursecontext->id); 1427 $DB->insert_record('role_names', $studentrolerename); 1428 1429 // By default teacher can see student. 1430 $this->setUser($teacher); 1431 $viewableroles = get_viewable_roles($coursecontext); 1432 $this->assertContains($studentrolerename->name, array_values($viewableroles)); 1433 // Remove view permission. 1434 $DB->delete_records('role_allow_view', array('roleid' => $teacherrole->id, 'allowview' => $studentrole->id)); 1435 $viewableroles = get_viewable_roles($coursecontext); 1436 // Teacher can no longer see student role. 1437 $this->assertNotContains($studentrolerename->name, array_values($viewableroles)); 1438 // Allow again teacher to view student. 1439 core_role_set_view_allowed($teacherrole->id, $studentrole->id); 1440 // Teacher can now see student role. 1441 $viewableroles = get_viewable_roles($coursecontext); 1442 $this->assertContains($studentrolerename->name, array_values($viewableroles)); 1443 } 1444 1445 /** 1446 * Test getting of all overridable roles. 1447 */ 1448 public function test_get_viewable_roles_system() { 1449 global $DB; 1450 1451 $this->resetAfterTest(); 1452 1453 $context = context_system::instance(); 1454 1455 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 1456 $teacher = $this->getDataGenerator()->create_user(); 1457 role_assign($teacherrole->id, $teacher->id, $context); 1458 1459 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 1460 $studentrolename = role_get_name($studentrole, $context); 1461 1462 // By default teacher can see student. 1463 $this->setUser($teacher); 1464 $viewableroles = get_viewable_roles($context); 1465 $this->assertContains($studentrolename, array_values($viewableroles)); 1466 // Remove view permission. 1467 $DB->delete_records('role_allow_view', array('roleid' => $teacherrole->id, 'allowview' => $studentrole->id)); 1468 $viewableroles = get_viewable_roles($context); 1469 // Teacher can no longer see student role. 1470 $this->assertNotContains($studentrolename, array_values($viewableroles)); 1471 // Allow again teacher to view student. 1472 core_role_set_view_allowed($teacherrole->id, $studentrole->id); 1473 // Teacher can now see student role. 1474 $viewableroles = get_viewable_roles($context); 1475 $this->assertContains($studentrolename, array_values($viewableroles)); 1476 } 1477 1478 /** 1479 * Test we have context level defaults. 1480 */ 1481 public function test_get_default_contextlevels() { 1482 $archetypes = get_role_archetypes(); 1483 $alllevels = context_helper::get_all_levels(); 1484 foreach ($archetypes as $archetype) { 1485 $defaults = get_default_contextlevels($archetype); 1486 $this->assertIsArray($defaults); 1487 foreach ($defaults as $level) { 1488 $this->assertTrue(isset($alllevels[$level])); 1489 } 1490 } 1491 } 1492 1493 /** 1494 * Test role context level setup. 1495 */ 1496 public function test_set_role_contextlevels() { 1497 global $DB; 1498 1499 $this->resetAfterTest(); 1500 1501 $roleid = create_role('New student role', 'student2', 'New student description', 'student'); 1502 1503 $this->assertFalse($DB->record_exists('role_context_levels', array('roleid' => $roleid))); 1504 1505 set_role_contextlevels($roleid, array(CONTEXT_COURSE, CONTEXT_MODULE)); 1506 $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel'); 1507 $this->assertCount(2, $levels); 1508 $this->assertTrue(isset($levels[CONTEXT_COURSE])); 1509 $this->assertTrue(isset($levels[CONTEXT_MODULE])); 1510 1511 set_role_contextlevels($roleid, array(CONTEXT_COURSE)); 1512 $levels = $DB->get_records('role_context_levels', array('roleid' => $roleid), '', 'contextlevel, contextlevel'); 1513 $this->assertCount(1, $levels); 1514 $this->assertTrue(isset($levels[CONTEXT_COURSE])); 1515 } 1516 1517 /** 1518 * Test getting of role context levels 1519 */ 1520 public function test_get_roles_for_contextlevels() { 1521 global $DB; 1522 1523 $allroles = get_all_roles(); 1524 foreach (context_helper::get_all_levels() as $level => $unused) { 1525 $roles = get_roles_for_contextlevels($level); 1526 foreach ($allroles as $roleid => $unused) { 1527 $exists = $DB->record_exists('role_context_levels', array('contextlevel'=>$level, 'roleid'=>$roleid)); 1528 if (in_array($roleid, $roles)) { 1529 $this->assertTrue($exists); 1530 } else { 1531 $this->assertFalse($exists); 1532 } 1533 } 1534 } 1535 } 1536 1537 /** 1538 * Test default enrol roles. 1539 */ 1540 public function test_get_default_enrol_roles() { 1541 $this->resetAfterTest(); 1542 1543 $course = $this->getDataGenerator()->create_course(); 1544 $coursecontext = context_course::instance($course->id); 1545 1546 $id2 = create_role('New student role', 'student2', 'New student description', 'student'); 1547 set_role_contextlevels($id2, array(CONTEXT_COURSE)); 1548 1549 $allroles = get_all_roles(); 1550 $expected = array($id2=>$allroles[$id2]); 1551 1552 foreach (get_roles_for_contextlevels(CONTEXT_COURSE) as $roleid) { 1553 $expected[$roleid] = $roleid; 1554 } 1555 1556 $roles = get_default_enrol_roles($coursecontext); 1557 foreach ($allroles as $role) { 1558 $this->assertEquals(isset($expected[$role->id]), isset($roles[$role->id])); 1559 if (isset($roles[$role->id])) { 1560 $this->assertSame(role_get_name($role, $coursecontext), $roles[$role->id]); 1561 } 1562 } 1563 } 1564 1565 /** 1566 * Test getting of role users. 1567 */ 1568 public function test_get_role_users() { 1569 global $DB; 1570 1571 $this->resetAfterTest(); 1572 1573 $systemcontext = context_system::instance(); 1574 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1575 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1576 $noeditteacherrole = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST); 1577 $course = $this->getDataGenerator()->create_course(); 1578 $coursecontext = context_course::instance($course->id); 1579 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1580 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1581 $DB->insert_record('role_names', $teacherrename); 1582 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id); 1583 $DB->insert_record('role_names', $otherrename); 1584 1585 $user1 = $this->getDataGenerator()->create_user(array('firstname'=>'John', 'lastname'=>'Smith')); 1586 role_assign($teacherrole->id, $user1->id, $coursecontext->id); 1587 $user2 = $this->getDataGenerator()->create_user(array('firstname'=>'Jan', 'lastname'=>'Kovar')); 1588 role_assign($teacherrole->id, $user2->id, $systemcontext->id); 1589 $user3 = $this->getDataGenerator()->create_user(); 1590 $this->getDataGenerator()->enrol_user($user3->id, $course->id, $teacherrole->id); 1591 $user4 = $this->getDataGenerator()->create_user(); 1592 $this->getDataGenerator()->enrol_user($user4->id, $course->id, $studentrole->id); 1593 $this->getDataGenerator()->enrol_user($user4->id, $course->id, $noeditteacherrole->id); 1594 1595 $group = $this->getDataGenerator()->create_group(array('courseid'=>$course->id)); 1596 groups_add_member($group, $user3); 1597 1598 $users = get_role_users($teacherrole->id, $coursecontext); 1599 $this->assertCount(2, $users); 1600 $this->assertArrayHasKey($user1->id, $users); 1601 $this->assertEquals($users[$user1->id]->id, $user1->id); 1602 $this->assertEquals($users[$user1->id]->roleid, $teacherrole->id); 1603 $this->assertEquals($users[$user1->id]->rolename, $teacherrole->name); 1604 $this->assertEquals($users[$user1->id]->roleshortname, $teacherrole->shortname); 1605 $this->assertEquals($users[$user1->id]->rolecoursealias, $teacherrename->name); 1606 $this->assertArrayHasKey($user3->id, $users); 1607 $this->assertEquals($users[$user3->id]->id, $user3->id); 1608 $this->assertEquals($users[$user3->id]->roleid, $teacherrole->id); 1609 $this->assertEquals($users[$user3->id]->rolename, $teacherrole->name); 1610 $this->assertEquals($users[$user3->id]->roleshortname, $teacherrole->shortname); 1611 $this->assertEquals($users[$user3->id]->rolecoursealias, $teacherrename->name); 1612 1613 $users = get_role_users($teacherrole->id, $coursecontext, true); 1614 $this->assertCount(3, $users); 1615 1616 $users = get_role_users($teacherrole->id, $coursecontext, true, '', null, null, '', 2, 1); 1617 $this->assertCount(1, $users); 1618 1619 $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber'); 1620 $this->assertCount(2, $users); 1621 $this->assertArrayHasKey($user1->id, $users); 1622 $this->assertArrayHasKey($user3->id, $users); 1623 1624 $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email'); 1625 $this->assertDebuggingCalled('get_role_users() adding u.lastname, u.firstname to the query result because they were required by $sort but missing in $fields'); 1626 $this->assertCount(2, $users); 1627 $this->assertArrayHasKey($user1->id, $users); 1628 $this->assertObjectHasAttribute('lastname', $users[$user1->id]); 1629 $this->assertObjectHasAttribute('firstname', $users[$user1->id]); 1630 $this->assertArrayHasKey($user3->id, $users); 1631 $this->assertObjectHasAttribute('lastname', $users[$user3->id]); 1632 $this->assertObjectHasAttribute('firstname', $users[$user3->id]); 1633 1634 $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id AS id_alias'); 1635 $this->assertDebuggingCalled('get_role_users() adding u.lastname, u.firstname to the query result because they were required by $sort but missing in $fields'); 1636 $this->assertCount(2, $users); 1637 $this->assertArrayHasKey($user1->id, $users); 1638 $this->assertObjectHasAttribute('id_alias', $users[$user1->id]); 1639 $this->assertObjectHasAttribute('lastname', $users[$user1->id]); 1640 $this->assertObjectHasAttribute('firstname', $users[$user1->id]); 1641 $this->assertArrayHasKey($user3->id, $users); 1642 $this->assertObjectHasAttribute('id_alias', $users[$user3->id]); 1643 $this->assertObjectHasAttribute('lastname', $users[$user3->id]); 1644 $this->assertObjectHasAttribute('firstname', $users[$user3->id]); 1645 1646 $users = get_role_users($teacherrole->id, $coursecontext, false, 'u.id, u.email, u.idnumber', 'u.idnumber', null, $group->id); 1647 $this->assertCount(1, $users); 1648 $this->assertArrayHasKey($user3->id, $users); 1649 1650 $users = get_role_users($teacherrole->id, $coursecontext, true, 'u.id, u.email, u.idnumber, u.firstname', 'u.idnumber', null, '', '', '', 'u.firstname = :xfirstname', array('xfirstname'=>'John')); 1651 $this->assertCount(1, $users); 1652 $this->assertArrayHasKey($user1->id, $users); 1653 1654 $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false, 'ra.id', 'ra.id'); 1655 $this->assertDebuggingNotCalled(); 1656 $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false, 'ra.userid', 'ra.userid'); 1657 $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' . 1658 'role assignments id (ra.id) as unique field, you can use $fields param for it.'); 1659 $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, false); 1660 $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' . 1661 'role assignments id (ra.id) as unique field, you can use $fields param for it.'); 1662 $users = get_role_users(array($noeditteacherrole->id, $studentrole->id), $coursecontext, 1663 false, 'u.id, u.firstname', 'u.id, u.firstname'); 1664 $this->assertDebuggingCalled('get_role_users() without specifying one single roleid needs to be called prefixing ' . 1665 'role assignments id (ra.id) as unique field, you can use $fields param for it.'); 1666 } 1667 1668 /** 1669 * Test used role query. 1670 */ 1671 public function test_get_roles_used_in_context() { 1672 global $DB; 1673 1674 $this->resetAfterTest(); 1675 1676 $systemcontext = context_system::instance(); 1677 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1678 $course = $this->getDataGenerator()->create_course(); 1679 $coursecontext = context_course::instance($course->id); 1680 $otherid = create_role('Other role', 'other', 'Some other role', ''); 1681 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1682 $DB->insert_record('role_names', $teacherrename); 1683 $otherrename = (object)array('roleid'=>$otherid, 'name'=>'Ostatní', 'contextid'=>$coursecontext->id); 1684 $DB->insert_record('role_names', $otherrename); 1685 1686 $user1 = $this->getDataGenerator()->create_user(); 1687 role_assign($teacherrole->id, $user1->id, $coursecontext->id); 1688 1689 $roles = get_roles_used_in_context($coursecontext); 1690 $this->assertCount(1, $roles); 1691 $role = reset($roles); 1692 $roleid = key($roles); 1693 $this->assertEquals($roleid, $role->id); 1694 $this->assertEquals($teacherrole->id, $role->id); 1695 $this->assertSame($teacherrole->name, $role->name); 1696 $this->assertSame($teacherrole->shortname, $role->shortname); 1697 $this->assertEquals($teacherrole->sortorder, $role->sortorder); 1698 $this->assertSame($teacherrename->name, $role->coursealias); 1699 1700 $user2 = $this->getDataGenerator()->create_user(); 1701 role_assign($teacherrole->id, $user2->id, $systemcontext->id); 1702 role_assign($otherid, $user2->id, $systemcontext->id); 1703 1704 $roles = get_roles_used_in_context($systemcontext); 1705 $this->assertCount(2, $roles); 1706 } 1707 1708 /** 1709 * Test roles used in course. 1710 */ 1711 public function test_get_user_roles_in_course() { 1712 global $DB, $CFG; 1713 1714 $this->resetAfterTest(); 1715 1716 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1717 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1718 $managerrole = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST); 1719 $course = $this->getDataGenerator()->create_course(); 1720 $coursecontext = context_course::instance($course->id); 1721 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1722 $DB->insert_record('role_names', $teacherrename); 1723 1724 $roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs. 1725 $this->assertTrue(in_array($teacherrole->id, $roleids)); 1726 $this->assertTrue(in_array($studentrole->id, $roleids)); 1727 $this->assertFalse(in_array($managerrole->id, $roleids)); 1728 1729 $user1 = $this->getDataGenerator()->create_user(); 1730 role_assign($teacherrole->id, $user1->id, $coursecontext->id); 1731 role_assign($studentrole->id, $user1->id, $coursecontext->id); 1732 $user2 = $this->getDataGenerator()->create_user(); 1733 role_assign($studentrole->id, $user2->id, $coursecontext->id); 1734 $user3 = $this->getDataGenerator()->create_user(); 1735 $user4 = $this->getDataGenerator()->create_user(); 1736 role_assign($managerrole->id, $user4->id, $coursecontext->id); 1737 1738 $this->setAdminUser(); 1739 1740 $roles = get_user_roles_in_course($user1->id, $course->id); 1741 $this->assertEquals([ 1742 role_get_name($teacherrole, $coursecontext), 1743 role_get_name($studentrole, $coursecontext), 1744 ], array_map('strip_tags', explode(', ', $roles))); 1745 1746 $roles = get_user_roles_in_course($user2->id, $course->id); 1747 $this->assertEquals([ 1748 role_get_name($studentrole, $coursecontext), 1749 ], array_map('strip_tags', explode(', ', $roles))); 1750 1751 $roles = get_user_roles_in_course($user3->id, $course->id); 1752 $this->assertEmpty($roles); 1753 1754 // Managers should be able to see a link to their own role type, given they can assign it in the context. 1755 $this->setUser($user4); 1756 $roles = get_user_roles_in_course($user4->id, $course->id); 1757 $this->assertEquals([ 1758 role_get_name($managerrole, $coursecontext), 1759 ], array_map('strip_tags', explode(', ', $roles))); 1760 1761 // Managers should see 2 roles if viewing a user who has been enrolled as a student and a teacher in the course. 1762 $roles = get_user_roles_in_course($user1->id, $course->id); 1763 $this->assertEquals([ 1764 role_get_name($teacherrole, $coursecontext), 1765 role_get_name($studentrole, $coursecontext), 1766 ], array_map('strip_tags', explode(', ', $roles))); 1767 1768 // Students should not see the manager role if viewing a manager's profile. 1769 $this->setUser($user2); 1770 $roles = get_user_roles_in_course($user4->id, $course->id); 1771 $this->assertEmpty($roles); // Should see 0 roles on the manager's profile. 1772 } 1773 1774 /** 1775 * Test get_user_roles and get_users_roles 1776 */ 1777 public function test_get_user_roles() { 1778 global $DB, $CFG; 1779 1780 $this->resetAfterTest(); 1781 1782 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1783 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 1784 $course = $this->getDataGenerator()->create_course(); 1785 $coursecontext = context_course::instance($course->id); 1786 $teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id); 1787 $DB->insert_record('role_names', $teacherrename); 1788 1789 $roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs. 1790 1791 $user1 = $this->getDataGenerator()->create_user(); 1792 role_assign($teacherrole->id, $user1->id, $coursecontext->id); 1793 role_assign($studentrole->id, $user1->id, $coursecontext->id); 1794 $user2 = $this->getDataGenerator()->create_user(); 1795 role_assign($studentrole->id, $user2->id, $coursecontext->id); 1796 $user3 = $this->getDataGenerator()->create_user(); 1797 1798 $u1roles = get_user_roles($coursecontext, $user1->id); 1799 1800 $u2roles = get_user_roles($coursecontext, $user2->id); 1801 1802 $allroles = get_users_roles($coursecontext, [], false); 1803 $specificuserroles = get_users_roles($coursecontext, [$user1->id, $user2->id]); 1804 $this->assertEquals($u1roles, $allroles[$user1->id]); 1805 $this->assertEquals($u1roles, $specificuserroles[$user1->id]); 1806 $this->assertEquals($u2roles, $allroles[$user2->id]); 1807 $this->assertEquals($u2roles, $specificuserroles[$user2->id]); 1808 } 1809 1810 /** 1811 * Test has_capability(), has_any_capability() and has_all_capabilities(). 1812 */ 1813 public function test_has_capability_and_friends() { 1814 global $DB; 1815 1816 $this->resetAfterTest(); 1817 1818 $course = $this->getDataGenerator()->create_course(); 1819 $coursecontext = context_course::instance($course->id); 1820 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 1821 $teacher = $this->getDataGenerator()->create_user(); 1822 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1823 $admin = $DB->get_record('user', array('username'=>'admin')); 1824 1825 // Note: Here are used default capabilities, the full test is in permission evaluation bellow, 1826 // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user. 1827 1828 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupsection'))); 1829 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/backup:backupcourse'))); 1830 $this->assertTrue($DB->record_exists('capabilities', array('name'=>'moodle/site:approvecourse'))); 1831 1832 $sca = array('moodle/backup:backupsection', 'moodle/backup:backupcourse', 'moodle/site:approvecourse'); 1833 $sc = array('moodle/backup:backupsection', 'moodle/backup:backupcourse'); 1834 1835 $this->setUser(0); 1836 $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext)); 1837 $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext)); 1838 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext)); 1839 $this->assertFalse(has_any_capability($sca, $coursecontext)); 1840 $this->assertFalse(has_all_capabilities($sca, $coursecontext)); 1841 1842 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $teacher)); 1843 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $teacher)); 1844 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $teacher)); 1845 $this->assertTrue(has_any_capability($sca, $coursecontext, $teacher)); 1846 $this->assertTrue(has_all_capabilities($sc, $coursecontext, $teacher)); 1847 $this->assertFalse(has_all_capabilities($sca, $coursecontext, $teacher)); 1848 1849 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $admin)); 1850 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $admin)); 1851 $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext, $admin)); 1852 $this->assertTrue(has_any_capability($sca, $coursecontext, $admin)); 1853 $this->assertTrue(has_all_capabilities($sc, $coursecontext, $admin)); 1854 $this->assertTrue(has_all_capabilities($sca, $coursecontext, $admin)); 1855 1856 $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, $admin, false)); 1857 $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, $admin, false)); 1858 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $admin, false)); 1859 $this->assertFalse(has_any_capability($sca, $coursecontext, $admin, false)); 1860 $this->assertFalse(has_all_capabilities($sc, $coursecontext, $admin, false)); 1861 $this->assertFalse(has_all_capabilities($sca, $coursecontext, $admin, false)); 1862 1863 $this->setUser($teacher); 1864 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext)); 1865 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext)); 1866 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext)); 1867 $this->assertTrue(has_any_capability($sca, $coursecontext)); 1868 $this->assertTrue(has_all_capabilities($sc, $coursecontext)); 1869 $this->assertFalse(has_all_capabilities($sca, $coursecontext)); 1870 1871 $this->setAdminUser(); 1872 $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext)); 1873 $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext)); 1874 $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext)); 1875 $this->assertTrue(has_any_capability($sca, $coursecontext)); 1876 $this->assertTrue(has_all_capabilities($sc, $coursecontext)); 1877 $this->assertTrue(has_all_capabilities($sca, $coursecontext)); 1878 1879 $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, 0)); 1880 $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, 0)); 1881 $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, 0)); 1882 $this->assertFalse(has_any_capability($sca, $coursecontext, 0)); 1883 $this->assertFalse(has_all_capabilities($sca, $coursecontext, 0)); 1884 } 1885 1886 /** 1887 * Test that assigning a fake cap does not return. 1888 */ 1889 public function test_fake_capability() { 1890 global $DB; 1891 1892 $this->resetAfterTest(); 1893 1894 $course = $this->getDataGenerator()->create_course(); 1895 $coursecontext = context_course::instance($course->id); 1896 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 1897 $teacher = $this->getDataGenerator()->create_user(); 1898 1899 $fakecapname = 'moodle/fake:capability'; 1900 1901 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1902 $admin = $DB->get_record('user', array('username' => 'admin')); 1903 1904 // Test a capability which does not exist. 1905 // Note: Do not use assign_capability because it will not allow fake caps. 1906 $DB->insert_record('role_capabilities', (object) [ 1907 'contextid' => $coursecontext->id, 1908 'roleid' => $teacherrole->id, 1909 'capability' => $fakecapname, 1910 'permission' => CAP_ALLOW, 1911 'timemodified' => time(), 1912 'modifierid' => 0, 1913 ]); 1914 1915 // Check `has_capability`. 1916 $this->assertFalse(has_capability($fakecapname, $coursecontext, $teacher)); 1917 $this->assertDebuggingCalled("Capability \"{$fakecapname}\" was not found! This has to be fixed in code."); 1918 $this->assertFalse(has_capability($fakecapname, $coursecontext, $admin)); 1919 $this->assertDebuggingCalled("Capability \"{$fakecapname}\" was not found! This has to be fixed in code."); 1920 1921 // Check `get_with_capability_sql` (with uses `get_with_capability_join`). 1922 list($sql, $params) = get_with_capability_sql($coursecontext, $fakecapname); 1923 $users = $DB->get_records_sql($sql, $params); 1924 1925 $this->assertFalse(array_key_exists($teacher->id, $users)); 1926 $this->assertFalse(array_key_exists($admin->id, $users)); 1927 1928 // Check `get_users_by_capability`. 1929 $users = get_users_by_capability($coursecontext, $fakecapname); 1930 1931 $this->assertFalse(array_key_exists($teacher->id, $users)); 1932 $this->assertFalse(array_key_exists($admin->id, $users)); 1933 } 1934 1935 /** 1936 * Test that assigning a fake cap does not return. 1937 */ 1938 public function test_fake_capability_assign() { 1939 global $DB; 1940 1941 $this->resetAfterTest(); 1942 1943 $course = $this->getDataGenerator()->create_course(); 1944 $coursecontext = context_course::instance($course->id); 1945 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 1946 $teacher = $this->getDataGenerator()->create_user(); 1947 1948 $capability = 'moodle/fake:capability'; 1949 1950 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1951 $admin = $DB->get_record('user', array('username' => 'admin')); 1952 1953 $this->expectException('coding_exception'); 1954 $this->expectExceptionMessage("Capability '{$capability}' was not found! This has to be fixed in code."); 1955 assign_capability($capability, CAP_ALLOW, $teacherrole->id, $coursecontext); 1956 } 1957 1958 /** 1959 * Test that assigning a fake cap does not return. 1960 */ 1961 public function test_fake_capability_unassign() { 1962 global $DB; 1963 1964 $this->resetAfterTest(); 1965 1966 $course = $this->getDataGenerator()->create_course(); 1967 $coursecontext = context_course::instance($course->id); 1968 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); 1969 $teacher = $this->getDataGenerator()->create_user(); 1970 1971 $capability = 'moodle/fake:capability'; 1972 1973 role_assign($teacherrole->id, $teacher->id, $coursecontext); 1974 $admin = $DB->get_record('user', array('username' => 'admin')); 1975 1976 $this->expectException('coding_exception'); 1977 $this->expectExceptionMessage("Capability '{$capability}' was not found! This has to be fixed in code."); 1978 unassign_capability($capability, CAP_ALLOW, $teacherrole->id, $coursecontext); 1979 } 1980 1981 /** 1982 * Test that the caching in get_role_definitions() and get_role_definitions_uncached() 1983 * works as intended. 1984 */ 1985 public function test_role_definition_caching() { 1986 global $DB; 1987 1988 $this->resetAfterTest(); 1989 1990 // Get some role ids. 1991 $authenticatedrole = $DB->get_record('role', array('shortname' => 'user'), '*', MUST_EXIST); 1992 $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 1993 $emptyroleid = create_role('No capabilities', 'empty', 'A role with no capabilties'); 1994 $course = $this->getDataGenerator()->create_course(); 1995 $coursecontext = context_course::instance($course->id); 1996 1997 // Instantiate the cache instance, since that does DB queries (get_config) 1998 // and we don't care about those. 1999 cache::make('core', 'roledefs'); 2000 2001 // One database query is not necessarily one database read, it seems. Find out how many. 2002 $startdbreads = $DB->perf_get_reads(); 2003 $rs = $DB->get_recordset('user'); 2004 $rs->close(); 2005 $readsperquery = $DB->perf_get_reads() - $startdbreads; 2006 2007 // Now load some role definitions, and check when it queries the database. 2008 2009 // Load the capabilities for two roles. Should be one query. 2010 $startdbreads = $DB->perf_get_reads(); 2011 get_role_definitions([$authenticatedrole->id, $studentrole->id]); 2012 $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2013 2014 // Load the capabilities for same two roles. Should not query the DB. 2015 $startdbreads = $DB->perf_get_reads(); 2016 get_role_definitions([$authenticatedrole->id, $studentrole->id]); 2017 $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2018 2019 // Include a third role. Should do one DB query. 2020 $startdbreads = $DB->perf_get_reads(); 2021 get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]); 2022 $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2023 2024 // Repeat call. No DB queries. 2025 $startdbreads = $DB->perf_get_reads(); 2026 get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]); 2027 $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2028 2029 // Alter a role. 2030 role_change_permission($studentrole->id, $coursecontext, 'moodle/course:tag', CAP_ALLOW); 2031 2032 // Should now know to do one query. 2033 $startdbreads = $DB->perf_get_reads(); 2034 get_role_definitions([$authenticatedrole->id, $studentrole->id]); 2035 $this->assertEquals(1 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2036 2037 // Now clear the in-memory cache, and verify that it does not query the DB. 2038 // Cannot use accesslib_clear_all_caches_for_unit_testing since that also 2039 // clears the MUC cache. 2040 global $ACCESSLIB_PRIVATE; 2041 $ACCESSLIB_PRIVATE->cacheroledefs = array(); 2042 2043 // Get all roles. Should not need the DB. 2044 $startdbreads = $DB->perf_get_reads(); 2045 get_role_definitions([$authenticatedrole->id, $studentrole->id, $emptyroleid]); 2046 $this->assertEquals(0 * $readsperquery, $DB->perf_get_reads() - $startdbreads); 2047 } 2048 2049 /** 2050 * Tests get_user_capability_course() which checks a capability across all courses. 2051 */ 2052 public function test_get_user_capability_course() { 2053 global $CFG, $USER; 2054 2055 $this->resetAfterTest(); 2056 2057 $generator = $this->getDataGenerator(); 2058 $cap = 'moodle/course:view'; 2059 2060 // The structure being created here is this: 2061 // 2062 // All tests work with the single capability 'moodle/course:view'. 2063 // 2064 // ROLE DEF/OVERRIDE ROLE ASSIGNS 2065 // Role: Allow Prohib Empty Def user u1 u2 u3 u4 u5 u6 u7 u8 2066 // System ALLOW PROHIBIT A E A+E 2067 // cat1 ALLOW 2068 // C1 (ALLOW) P 2069 // C2 ALLOW E P 2070 // cat2 PREVENT 2071 // C3 ALLOW E 2072 // C4 2073 // Misc. A 2074 // C5 PREVENT A 2075 // C6 PROHIBIT 2076 // 2077 // Front-page and guest role stuff from the end of this test not included in the diagram. 2078 2079 // Create a role which allows course:view and one that prohibits it, and one neither. 2080 $allowroleid = $generator->create_role(); 2081 $prohibitroleid = $generator->create_role(); 2082 $emptyroleid = $generator->create_role(); 2083 $systemcontext = context_system::instance(); 2084 assign_capability($cap, CAP_ALLOW, $allowroleid, $systemcontext->id); 2085 assign_capability($cap, CAP_PROHIBIT, $prohibitroleid, $systemcontext->id); 2086 2087 // Create two categories (nested). 2088 $cat1 = $generator->create_category(); 2089 $cat2 = $generator->create_category(['parent' => $cat1->id]); 2090 2091 // Create six courses - two in cat1, two in cat2, and two in default category. 2092 // Shortnames are used for a sorting test. Otherwise they are not significant. 2093 $c1 = $generator->create_course(['category' => $cat1->id, 'shortname' => 'Z']); 2094 $c2 = $generator->create_course(['category' => $cat1->id, 'shortname' => 'Y']); 2095 $c3 = $generator->create_course(['category' => $cat2->id, 'shortname' => 'X']); 2096 $c4 = $generator->create_course(['category' => $cat2->id]); 2097 $c5 = $generator->create_course(); 2098 $c6 = $generator->create_course(); 2099 2100 // Category overrides: in cat 1, empty role is allowed; in cat 2, empty role is prevented. 2101 assign_capability($cap, CAP_ALLOW, $emptyroleid, 2102 context_coursecat::instance($cat1->id)->id); 2103 assign_capability($cap, CAP_PREVENT, $emptyroleid, 2104 context_coursecat::instance($cat2->id)->id); 2105 2106 // Course overrides: in C5, allow role is prevented; in C6, empty role is prohibited; in 2107 // C3, empty role is allowed. 2108 assign_capability($cap, CAP_PREVENT, $allowroleid, 2109 context_course::instance($c5->id)->id); 2110 assign_capability($cap, CAP_PROHIBIT, $emptyroleid, 2111 context_course::instance($c6->id)->id); 2112 assign_capability($cap, CAP_ALLOW, $emptyroleid, 2113 context_course::instance($c3->id)->id); 2114 assign_capability($cap, CAP_ALLOW, $prohibitroleid, 2115 context_course::instance($c2->id)->id); 2116 2117 // User 1 has no roles except default user role. 2118 $u1 = $generator->create_user(); 2119 2120 // It returns false (annoyingly) if there are no courses. 2121 $this->assertFalse(get_user_capability_course($cap, $u1->id, true, '', 'id')); 2122 2123 // Final override: in C1, default user role is allowed. 2124 assign_capability($cap, CAP_ALLOW, $CFG->defaultuserroleid, 2125 context_course::instance($c1->id)->id); 2126 2127 // Should now get C1 only. 2128 $courses = get_user_capability_course($cap, $u1->id, true, '', 'id'); 2129 $this->assert_course_ids([$c1->id], $courses); 2130 2131 // User 2 has allow role (system wide). 2132 $u2 = $generator->create_user(); 2133 role_assign($allowroleid, $u2->id, $systemcontext->id); 2134 2135 // Should get everything except C5. 2136 $courses = get_user_capability_course($cap, $u2->id, true, '', 'id'); 2137 $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id, $c6->id], $courses); 2138 2139 // User 3 has empty role (system wide). 2140 $u3 = $generator->create_user(); 2141 role_assign($emptyroleid, $u3->id, $systemcontext->id); 2142 2143 // Should get cat 1 courses but not cat2, except C3. 2144 $courses = get_user_capability_course($cap, $u3->id, true, '', 'id'); 2145 $this->assert_course_ids([$c1->id, $c2->id, $c3->id], $courses); 2146 2147 // User 4 has allow and empty role (system wide). 2148 $u4 = $generator->create_user(); 2149 role_assign($allowroleid, $u4->id, $systemcontext->id); 2150 role_assign($emptyroleid, $u4->id, $systemcontext->id); 2151 2152 // Should get everything except C5 and C6. 2153 $courses = get_user_capability_course($cap, $u4->id, true, '', 'id'); 2154 $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id], $courses); 2155 2156 // User 5 has allow role in default category only. 2157 $u5 = $generator->create_user(); 2158 role_assign($allowroleid, $u5->id, context_coursecat::instance($c5->category)->id); 2159 2160 // Should get C1 and the default category courses but not C5. 2161 $courses = get_user_capability_course($cap, $u5->id, true, '', 'id'); 2162 $this->assert_course_ids([$c1->id, $c6->id], $courses); 2163 2164 // User 6 has a bunch of course roles: prohibit role in C1, empty role in C3, allow role in 2165 // C6. 2166 $u6 = $generator->create_user(); 2167 role_assign($prohibitroleid, $u6->id, context_course::instance($c1->id)->id); 2168 role_assign($emptyroleid, $u6->id, context_course::instance($c3->id)->id); 2169 role_assign($allowroleid, $u6->id, context_course::instance($c5->id)->id); 2170 2171 // Should get C3 only because the allow role is prevented in C5. 2172 $courses = get_user_capability_course($cap, $u6->id, true, '', 'id'); 2173 $this->assert_course_ids([$c3->id], $courses); 2174 2175 // User 7 has empty role in C2. 2176 $u7 = $generator->create_user(); 2177 role_assign($emptyroleid, $u7->id, context_course::instance($c2->id)->id); 2178 2179 // Should get C1 by the default user role override, and C2 by the cat1 level override. 2180 $courses = get_user_capability_course($cap, $u7->id, true, '', 'id'); 2181 $this->assert_course_ids([$c1->id, $c2->id], $courses); 2182 2183 // User 8 has prohibit role as system context, to verify that prohibits can't be overridden. 2184 $u8 = $generator->create_user(); 2185 role_assign($prohibitroleid, $u8->id, context_course::instance($c2->id)->id); 2186 2187 // Should get C1 by the default user role override, no other courses because the prohibit cannot be overridden. 2188 $courses = get_user_capability_course($cap, $u8->id, true, '', 'id'); 2189 $this->assert_course_ids([$c1->id], $courses); 2190 2191 // Admin user gets everything.... 2192 $courses = get_user_capability_course($cap, get_admin()->id, true, '', 'id'); 2193 $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id, $c5->id, $c6->id], 2194 $courses); 2195 2196 // Unless you turn off doanything, when it only has the things a user with no role does. 2197 $courses = get_user_capability_course($cap, get_admin()->id, false, '', 'id'); 2198 $this->assert_course_ids([$c1->id], $courses); 2199 2200 // Using u3 as an example, test the limit feature. 2201 $courses = get_user_capability_course($cap, $u3->id, true, '', 'id', 2); 2202 $this->assert_course_ids([$c1->id, $c2->id], $courses); 2203 2204 // Check sorting. 2205 $courses = get_user_capability_course($cap, $u3->id, true, '', 'shortname'); 2206 $this->assert_course_ids([$c3->id, $c2->id, $c1->id], $courses); 2207 2208 // Check returned fields - default. 2209 $courses = get_user_capability_course($cap, $u3->id, true, '', 'id'); 2210 $this->assertEquals((object)['id' => $c1->id], $courses[0]); 2211 2212 // Add a selection of fields, including the context ones with special handling. 2213 $courses = get_user_capability_course($cap, $u3->id, true, 'shortname, ctxlevel, ctxdepth, ctxinstance', 'id'); 2214 $this->assertEquals((object)['id' => $c1->id, 'shortname' => 'Z', 'ctxlevel' => 50, 2215 'ctxdepth' => 3, 'ctxinstance' => $c1->id], $courses[0]); 2216 2217 // Test front page role - user 1 has no roles, but if we change the front page role 2218 // definition so that it has our capability, then they should see the front page course. 2219 // as well as C1. 2220 assign_capability($cap, CAP_ALLOW, $CFG->defaultfrontpageroleid, $systemcontext->id); 2221 $courses = get_user_capability_course($cap, $u1->id, true, '', 'id'); 2222 $this->assert_course_ids([SITEID, $c1->id], $courses); 2223 2224 // Check that temporary guest access (in this case, given on course 2 for user 1) 2225 // also is included, if it has this capability. 2226 assign_capability($cap, CAP_ALLOW, $CFG->guestroleid, $systemcontext->id); 2227 $this->setUser($u1); 2228 load_temp_course_role(context_course::instance($c2->id), $CFG->guestroleid); 2229 $courses = get_user_capability_course($cap, $USER->id, true, '', 'id'); 2230 $this->assert_course_ids([SITEID, $c1->id, $c2->id], $courses); 2231 } 2232 2233 /** 2234 * Extracts an array of course ids to make the above test script shorter. 2235 * 2236 * @param int[] $expected Array of expected course ids 2237 * @param stdClass[] $courses Array of course objects 2238 */ 2239 protected function assert_course_ids(array $expected, array $courses) { 2240 $courseids = array_map(function($c) { 2241 return $c->id; 2242 }, $courses); 2243 $this->assertEquals($expected, $courseids); 2244 } 2245 2246 /** 2247 * Test if course creator future capability lookup works. 2248 */ 2249 public function test_guess_if_creator_will_have_course_capability() { 2250 global $DB, $CFG, $USER; 2251 2252 $this->resetAfterTest(); 2253 2254 $category = $this->getDataGenerator()->create_category(); 2255 $course = $this->getDataGenerator()->create_course(array('category'=>$category->id)); 2256 2257 $syscontext = context_system::instance(); 2258 $categorycontext = context_coursecat::instance($category->id); 2259 $coursecontext = context_course::instance($course->id); 2260 $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); 2261 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); 2262 $creatorrole = $DB->get_record('role', array('shortname'=>'coursecreator'), '*', MUST_EXIST); 2263 $managerrole = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST); 2264 2265 $this->assertEquals($teacherrole->id, $CFG->creatornewroleid); 2266 2267 $creator = $this->getDataGenerator()->create_user(); 2268 $manager = $this->getDataGenerator()->create_user(); 2269 role_assign($managerrole->id, $manager->id, $categorycontext); 2270 2271 $this->assertFalse(has_capability('moodle/course:view', $categorycontext, $creator)); 2272 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator)); 2273 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator)); 2274 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator)); 2275 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $creator)); 2276 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $creator)); 2277 2278 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager)); 2279 $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext, $manager)); 2280 $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext, $manager)); 2281 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext, $manager->id)); 2282 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext, $manager->id)); 2283 2284 $this->assertEquals(0, $USER->id); 2285 $this->assertFalse(has_capability('moodle/course:view', $categorycontext)); 2286 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext)); 2287 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext)); 2288 $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext)); 2289 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext)); 2290 $this->assertFalse(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext)); 2291 2292 $this->setUser($manager); 2293 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext)); 2294 $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext)); 2295 $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext)); 2296 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext)); 2297 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext)); 2298 2299 $this->setAdminUser(); 2300 $this->assertTrue(has_capability('moodle/role:assign', $categorycontext)); 2301 $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext)); 2302 $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext)); 2303 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $categorycontext)); 2304 $this->assertTrue(guess_if_creator_will_have_course_capability('moodle/course:visibility', $coursecontext)); 2305 $this->setUser(0); 2306 2307 role_assign($creatorrole->id, $creator->id, $categorycontext); 2308 2309 $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator)); 2310 $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator)); 2311 $this->assertFalse(