/** * Test getting of all overridable roles. */ public function test_get_overridable_roles() { global $DB; $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $coursecontext = context_course::instance($course->id); $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); $teacher = $this->getDataGenerator()->create_user(); role_assign($teacherrole->id, $teacher->id, $coursecontext); $teacherename = (object) array('roleid' => $teacherrole->id, 'name' => 'Učitel', 'contextid' => $coursecontext->id); $DB->insert_record('role_names', $teacherename); $this->assertTrue($DB->record_exists('capabilities', array('name' => 'moodle/backup:backupcourse'))); // Any capability is ok. assign_capability('moodle/backup:backupcourse', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id); $studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); $student = $this->getDataGenerator()->create_user(); role_assign($studentrole->id, $student->id, $coursecontext); $contexts = $DB->get_records('context'); $users = $DB->get_records('user'); $allroles = $DB->get_records('role'); // Evaluate all results for all users in all contexts. foreach ($users as $user) { $this->setUser($user); foreach ($contexts as $contextid => $unused) { $context = context_helper::instance_by_id($contextid); $roles = get_overridable_roles($context, ROLENAME_SHORT); foreach ($allroles as $roleid => $role) { $hascap = has_any_capability(array('moodle/role:safeoverride', 'moodle/role:override'), $context); if (is_siteadmin()) { $this->assertTrue(isset($roles[$roleid])); } else { $parents = $context->get_parent_context_ids(true); $pcontexts = implode(',', $parents); $allowed = $DB->record_exists_sql("SELECT r.id\n FROM {role} r\n JOIN {role_allow_override} rao ON r.id = rao.allowoverride\n JOIN {role_assignments} ra ON rao.roleid = ra.roleid\n WHERE ra.userid = :userid AND ra.contextid IN ({$pcontexts}) AND r.id = :roleid\n ", array('userid' => $user->id, 'roleid' => $roleid)); if (isset($roles[$roleid])) { $this->assertTrue($hascap); $this->assertTrue($allowed); } else { $this->assertFalse($hascap and $allowed); } } if (isset($roles[$roleid])) { $this->assertEquals($role->shortname, $roles[$roleid]); } } } } // Test parameter defaults. $this->setAdminUser(); $roles1 = get_overridable_roles($coursecontext); $roles2 = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false); $this->assertEquals($roles2, $roles1); $alltypes = array(ROLENAME_ALIAS, ROLENAME_ALIAS_RAW, ROLENAME_BOTH, ROLENAME_ORIGINAL, ROLENAME_ORIGINALANDSHORT, ROLENAME_SHORT); foreach ($alltypes as $type) { $rolenames = role_fix_names($allroles, $coursecontext, $type); $roles = get_overridable_roles($coursecontext, $type, false); foreach ($roles as $roleid => $rolename) { $this->assertSame($rolenames[$roleid]->localname, $rolename); } } // Verify counts. $roles = get_overridable_roles($coursecontext, ROLENAME_ALIAS, false); list($rolenames, $rolecounts, $nameswithcounts) = get_overridable_roles($coursecontext, ROLENAME_ALIAS, true); $this->assertEquals($roles, $rolenames); foreach ($rolenames as $roleid => $name) { if ($roleid == $teacherrole->id) { $this->assertEquals(1, $rolecounts[$roleid]); } else { $this->assertEquals(0, $rolecounts[$roleid]); } $this->assertSame("{$name} ({$rolecounts[$roleid]})", $nameswithcounts[$roleid]); } }
/** * Called by pluginfile.php to serve files related to the 'question' core * component and for files belonging to qtypes. * * For files that relate to questions in a question_attempt, then we delegate to * a function in the component that owns the attempt (for example in the quiz, * or in core question preview) to get necessary inforation. * * (Note that, at the moment, all question file areas relate to questions in * attempts, so the If at the start of the last paragraph is always true.) * * Does not return, either calls send_file_not_found(); or serves the file. * * @package core_question * @category files * @param stdClass $course course settings object * @param stdClass $context context object * @param string $component the name of the component we are serving files for. * @param string $filearea the name of the file area. * @param array $args the remaining bits of the file path. * @param bool $forcedownload whether the user must be forced to download the file. * @param array $options additional options affecting the file serving */ function question_pluginfile($course, $context, $component, $filearea, $args, $forcedownload, array $options = array()) { global $DB, $CFG; // Special case, sending a question bank export. if ($filearea === 'export') { list($context, $course, $cm) = get_context_info_array($context->id); require_login($course, false, $cm); require_once $CFG->dirroot . '/question/editlib.php'; $contexts = new question_edit_contexts($context); // check export capability $contexts->require_one_edit_tab_cap('export'); $category_id = (int) array_shift($args); $format = array_shift($args); $cattofile = array_shift($args); $contexttofile = array_shift($args); $filename = array_shift($args); // load parent class for import/export require_once $CFG->dirroot . '/question/format.php'; require_once $CFG->dirroot . '/question/editlib.php'; require_once $CFG->dirroot . '/question/format/' . $format . '/format.php'; $classname = 'qformat_' . $format; if (!class_exists($classname)) { send_file_not_found(); } $qformat = new $classname(); if (!($category = $DB->get_record('question_categories', array('id' => $category_id)))) { send_file_not_found(); } $qformat->setCategory($category); $qformat->setContexts($contexts->having_one_edit_tab_cap('export')); $qformat->setCourse($course); if ($cattofile == 'withcategories') { $qformat->setCattofile(true); } else { $qformat->setCattofile(false); } if ($contexttofile == 'withcontexts') { $qformat->setContexttofile(true); } else { $qformat->setContexttofile(false); } if (!$qformat->exportpreprocess()) { send_file_not_found(); print_error('exporterror', 'question', $thispageurl->out()); } // export data to moodle file pool if (!($content = $qformat->exportprocess(true))) { send_file_not_found(); } send_file($content, $filename, 0, 0, true, true, $qformat->mime_type()); } // Normal case, a file belonging to a question. $qubaidorpreview = array_shift($args); // Two sub-cases: 1. A question being previewed outside an attempt/usage. if ($qubaidorpreview === 'preview') { $previewcontextid = (int) array_shift($args); $previewcomponent = array_shift($args); $questionid = (int) array_shift($args); $previewcontext = context_helper::instance_by_id($previewcontextid); $result = component_callback($previewcomponent, 'question_preview_pluginfile', array($previewcontext, $questionid, $context, $component, $filearea, $args, $forcedownload, $options), 'newcallbackmissing'); if ($result === 'newcallbackmissing' && ($filearea = 'questiontext')) { // Fall back to the legacy callback for backwards compatibility. debugging("Component {$previewcomponent} does not define the expected " . "{$previewcomponent}_question_preview_pluginfile callback. Falling back to the deprecated " . "{$previewcomponent}_questiontext_preview_pluginfile callback.", DEBUG_DEVELOPER); component_callback($previewcomponent, 'questiontext_preview_pluginfile', array($previewcontext, $questionid, $args, $forcedownload, $options)); } send_file_not_found(); } // 2. A question being attempted in the normal way. $qubaid = (int) $qubaidorpreview; $slot = (int) array_shift($args); $module = $DB->get_field('question_usages', 'component', array('id' => $qubaid)); if ($module === 'core_question_preview') { require_once $CFG->dirroot . '/question/previewlib.php'; return question_preview_question_pluginfile($course, $context, $component, $filearea, $qubaid, $slot, $args, $forcedownload, $options); } else { $dir = core_component::get_component_directory($module); if (!file_exists("{$dir}/lib.php")) { send_file_not_found(); } include_once "{$dir}/lib.php"; $filefunction = $module . '_question_pluginfile'; if (function_exists($filefunction)) { $filefunction($course, $context, $component, $filearea, $qubaid, $slot, $args, $forcedownload, $options); } // Okay, we're here so lets check for function without 'mod_'. if (strpos($module, 'mod_') === 0) { $filefunctionold = substr($module, 4) . '_question_pluginfile'; if (function_exists($filefunctionold)) { $filefunctionold($course, $context, $component, $filearea, $qubaid, $slot, $args, $forcedownload, $options); } } send_file_not_found(); } }
/** * Mark the specified toru step as shown for the current user. * * @param int $tourid The ID of the tour. * @param int $context The Context ID of the current page. * @param string $pageurl The path of the current page. * @param int $stepid The step id * @param int $stepindex The step index * @return array As described in complete_tour_returns */ public static function step_shown($tourid, $context, $pageurl, $stepid, $stepindex) { $params = self::validate_parameters(self::step_shown_parameters(), ['tourid' => $tourid, 'context' => $context, 'pageurl' => $pageurl, 'stepid' => $stepid, 'stepindex' => $stepindex]); $context = \context_helper::instance_by_id($params['context']); self::validate_context($context); $step = step::instance($params['stepid']); if ($step->get_tourid() != $params['tourid']) { throw new \moodle_exception('Incorrect tour specified.'); } \tool_usertours\event\step_shown::create(['contextid' => $context->id, 'objectid' => $params['stepid'], 'other' => ['pageurl' => $params['pageurl'], 'tourid' => $params['tourid'], 'stepindex' => $params['stepindex']]])->trigger(); return []; }