diff --git a/lib/accesslib.php b/lib/accesslib.php index ed501689f5d..6eca1190d9b 100644 --- a/lib/accesslib.php +++ b/lib/accesslib.php @@ -545,6 +545,62 @@ function has_all_capabilities(array $capabilities, context $context, $user = nul return true; } +/** + * Is course creator going to have capability in a new course? + * + * This is intended to be used in enrolment plugins before or during course creation, + * do not use after the course is fully created. + * + * @category access + * + * @param string $capability the name of the capability to check. + * @param context $context course or category context where is course going to be created + * @param integer|stdClass $user A user id or object. By default (null) checks the permissions of the current user. + * @return boolean true if the user will have this capability. + * + * @throws coding_exception if different type of course submitted + */ +function will_have_course_capability($capability, context $context, $user = null) { + global $CFG; + + if ($context->contextlevel != CONTEXT_COURSE and $context->contextlevel != CONTEXT_COURSECAT) { + throw new coding_exception('Only course or course category context expected'); + } + + if (has_capability($capability, $context, $user)) { + // User already has the capability, it could be only removed if CAP_PROHIBIT + // was involved here, but we ignore that. + return true; + } + + if (!has_capability('moodle/course:create', $context, $user)) { + return false; + } + + if (!enrol_is_enabled('manual')) { + return false; + } + + if (empty($CFG->creatornewroleid)) { + return false; + } + + if ($context->contextlevel == CONTEXT_COURSE) { + if (is_viewing($context, $user, 'moodle/role:assign') or is_enrolled($context, $user, 'moodle/role:assign')) { + return false; + } + } else { + if (has_capability('moodle/course:view', $context, $user) and has_capability('moodle/role:assign', $context, $user)) { + return false; + } + } + + // Most likely they will be enrolled after the course creation is finished, + // does the new role have the required capability? + list($neededroles, $forbiddenroles) = get_roles_with_cap_in_context($context, $capability); + return isset($neededroles[$CFG->creatornewroleid]); +} + /** * Check if the user is an admin at the site level. * diff --git a/lib/tests/accesslib_test.php b/lib/tests/accesslib_test.php index 863cfc3e8cc..c9c8bd8f6fe 100644 --- a/lib/tests/accesslib_test.php +++ b/lib/tests/accesslib_test.php @@ -1493,6 +1493,131 @@ class accesslib_testcase extends advanced_testcase { $this->assertFalse(has_all_capabilities($sca, $coursecontext, 0)); } + /** + * Test if course creator future capability lookup works. + */ + public function test_will_have_course_capability() { + global $DB, $CFG, $USER; + + $this->resetAfterTest(); + + $category = $this->getDataGenerator()->create_category(); + $course = $this->getDataGenerator()->create_course(array('category'=>$category->id)); + + $syscontext = context_system::instance(); + $categorycontext = context_coursecat::instance($category->id); + $coursecontext = context_course::instance($course->id); + $studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST); + $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST); + $creatorrole = $DB->get_record('role', array('shortname'=>'coursecreator'), '*', MUST_EXIST); + $managerrole = $DB->get_record('role', array('shortname'=>'manager'), '*', MUST_EXIST); + + $this->assertEquals($teacherrole->id, $CFG->creatornewroleid); + + $creator = $this->getDataGenerator()->create_user(); + $manager = $this->getDataGenerator()->create_user(); + role_assign($managerrole->id, $manager->id, $categorycontext); + + $this->assertFalse(has_capability('moodle/course:view', $categorycontext, $creator)); + $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator)); + $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator)); + $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator)); + $this->assertFalse(will_have_course_capability('moodle/course:visibility', $categorycontext, $creator)); + $this->assertFalse(will_have_course_capability('moodle/course:visibility', $coursecontext, $creator)); + + $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager)); + $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext, $manager)); + $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext, $manager)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $categorycontext, $manager->id)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $coursecontext, $manager->id)); + + $this->assertEquals(0, $USER->id); + $this->assertFalse(has_capability('moodle/course:view', $categorycontext)); + $this->assertFalse(has_capability('moodle/role:assign', $categorycontext)); + $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext)); + $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext)); + $this->assertFalse(will_have_course_capability('moodle/course:visibility', $categorycontext)); + $this->assertFalse(will_have_course_capability('moodle/course:visibility', $coursecontext)); + + $this->setUser($manager); + $this->assertTrue(has_capability('moodle/role:assign', $categorycontext)); + $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext)); + $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $categorycontext)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $coursecontext)); + + $this->setAdminUser(); + $this->assertTrue(has_capability('moodle/role:assign', $categorycontext)); + $this->assertTrue(has_capability('moodle/course:visibility', $categorycontext)); + $this->assertTrue(has_capability('moodle/course:visibility', $coursecontext)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $categorycontext)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $coursecontext)); + $this->setUser(0); + + role_assign($creatorrole->id, $creator->id, $categorycontext); + + $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, $creator)); + $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator)); + $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $categorycontext, $creator)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $coursecontext, $creator)); + + $this->setUser($creator); + $this->assertFalse(has_capability('moodle/role:assign', $categorycontext, null)); + $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, null)); + $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, null)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $categorycontext, null)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $coursecontext, null)); + $this->setUser(0); + + set_config('creatornewroleid', $studentrole->id); + + $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $creator)); + $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $creator)); + $this->assertFalse(will_have_course_capability('moodle/course:visibility', $categorycontext, $creator)); + $this->assertFalse(will_have_course_capability('moodle/course:visibility', $coursecontext, $creator)); + + set_config('creatornewroleid', $teacherrole->id); + + role_change_permission($managerrole->id, $categorycontext, 'moodle/course:visibility', CAP_PREVENT); + role_assign($creatorrole->id, $manager->id, $categorycontext); + + $this->assertTrue(has_capability('moodle/course:view', $categorycontext, $manager)); + $this->assertTrue(has_capability('moodle/course:view', $coursecontext, $manager)); + $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager)); + $this->assertTrue(has_capability('moodle/role:assign', $coursecontext, $manager)); + $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager)); + $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager)); + $this->assertFalse(will_have_course_capability('moodle/course:visibility', $categorycontext, $manager)); + $this->assertFalse(will_have_course_capability('moodle/course:visibility', $coursecontext, $manager)); + + role_change_permission($managerrole->id, $categorycontext, 'moodle/course:view', CAP_PREVENT); + $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager)); + $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager)); + $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $categorycontext, $manager)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $coursecontext, $manager)); + + $this->getDataGenerator()->enrol_user($manager->id, $course->id, 0); + + $this->assertTrue(has_capability('moodle/role:assign', $categorycontext, $manager)); + $this->assertTrue(has_capability('moodle/role:assign', $coursecontext, $manager)); + $this->assertTrue(is_enrolled($coursecontext, $manager)); + $this->assertFalse(has_capability('moodle/course:visibility', $categorycontext, $manager)); + $this->assertFalse(has_capability('moodle/course:visibility', $coursecontext, $manager)); + $this->assertTrue(will_have_course_capability('moodle/course:visibility', $categorycontext, $manager)); + $this->assertFalse(will_have_course_capability('moodle/course:visibility', $coursecontext, $manager)); + + // Test problems. + + try { + will_have_course_capability('moodle/course:visibility', $syscontext, $creator); + $this->fail('Exception expected when non course/category contet passed to will_have_course_capability()'); + } catch (moodle_exception $e) { + $this->assertInstanceOf('coding_exception', $e); + } + } + /** * Test require_capability() exceptions. * @return void