function definition() { global $CFG, $DB; $mform = $this->_form; $course = $this->_customdata; $this->course = $course; $existing = $DB->get_records('enrol', array('enrol' => 'meta', 'courseid' => $course->id), '', 'customint1, id'); // TODO: this has to be done via ajax or else it will fail very badly on large sites! $courses = array('' => get_string('choosedots')); list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT c.id, c.fullname, c.shortname, c.visible {$select} FROM {course} c {$join} ORDER BY c.sortorder ASC"; $rs = $DB->get_recordset_sql($sql); foreach ($rs as $c) { if ($c->id == SITEID or $c->id == $course->id or isset($existing[$c->id])) { continue; } context_helper::preload_from_record($c); $coursecontext = context_course::instance($c->id); if (!$c->visible and !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { continue; } if (!has_capability('enrol/meta:selectaslinked', $coursecontext)) { continue; } $courses[$c->id] = $coursecontext->get_context_name(false); } $rs->close(); $mform->addElement('header', 'general', get_string('pluginname', 'enrol_meta')); $mform->addElement('select', 'link', get_string('linkedcourse', 'enrol_meta'), $courses); $mform->addRule('link', get_string('required'), 'required', null, 'client'); $mform->addElement('hidden', 'id', null); $mform->setType('id', PARAM_INT); $this->add_action_buttons(true, get_string('addinstance', 'enrol')); $this->set_data(array('id' => $course->id)); }
/** * A small functional test of accesslib functions and classes. * @return void */ public function test_everything_in_accesslib() { global $USER, $SITE, $CFG, $DB, $ACCESSLIB_PRIVATE; $this->resetAfterTest(true); $generator = $this->getDataGenerator(); // Fill the site with some real data $testcategories = array(); $testcourses = array(); $testpages = array(); $testblocks = array(); $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id'); $systemcontext = context_system::instance(); $frontpagecontext = context_course::instance(SITEID); // Add block to system context $bi = $generator->create_block('online_users'); context_block::instance($bi->id); $testblocks[] = $bi->id; // Some users $testusers = array(); for($i=0; $i<20; $i++) { $user = $generator->create_user(); $testusers[$i] = $user->id; $usercontext = context_user::instance($user->id); // Add block to user profile $bi = $generator->create_block('online_users', array('parentcontextid'=>$usercontext->id)); $testblocks[] = $bi->id; } // Deleted user - should be ignored everywhere, can not have context $generator->create_user(array('deleted'=>1)); // Add block to frontpage $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagecontext->id)); $frontpageblockcontext = context_block::instance($bi->id); $testblocks[] = $bi->id; // Add a resource to frontpage $page = $generator->create_module('page', array('course'=>$SITE->id)); $testpages[] = $page->id; $frontpagepagecontext = context_module::instance($page->cmid); // Add block to frontpage resource $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagepagecontext->id)); $frontpagepageblockcontext = context_block::instance($bi->id); $testblocks[] = $bi->id; // Some nested course categories with courses $manualenrol = enrol_get_plugin('manual'); $parentcat = 0; for($i=0; $i<5; $i++) { $cat = $generator->create_category(array('parent'=>$parentcat)); $testcategories[] = $cat->id; $catcontext = context_coursecat::instance($cat->id); $parentcat = $cat->id; if ($i >=4) { continue; } // Add resource to each category $bi = $generator->create_block('online_users', array('parentcontextid'=>$catcontext->id)); context_block::instance($bi->id); // Add a few courses to each category for($j=0; $j<6; $j++) { $course = $generator->create_course(array('category'=>$cat->id)); $testcourses[] = $course->id; $coursecontext = context_course::instance($course->id); if ($j >= 5) { continue; } // Add manual enrol instance $manualenrol->add_default_instance($DB->get_record('course', array('id'=>$course->id))); // Add block to each course $bi = $generator->create_block('online_users', array('parentcontextid'=>$coursecontext->id)); $testblocks[] = $bi->id; // Add a resource to each course $page = $generator->create_module('page', array('course'=>$course->id)); $testpages[] = $page->id; $modcontext = context_module::instance($page->cmid); // Add block to each module $bi = $generator->create_block('online_users', array('parentcontextid'=>$modcontext->id)); $testblocks[] = $bi->id; } } // Make sure all contexts were created properly $count = 1; //system $count += $DB->count_records('user', array('deleted'=>0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEquals($DB->count_records('context'), $count); $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0); $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0); // ====== context_helper::get_level_name() ================================ $levels = context_helper::get_all_levels(); foreach ($levels as $level=>$classname) { $name = context_helper::get_level_name($level); $this->assertFalse(empty($name)); } // ======= context::instance_by_id(), context_xxx::instance(); $context = context::instance_by_id($frontpagecontext->id); $this->assertSame($context->contextlevel, CONTEXT_COURSE); $this->assertFalse(context::instance_by_id(-1, IGNORE_MISSING)); try { context::instance_by_id(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $this->assertTrue(context_system::instance() instanceof context_system); $this->assertTrue(context_coursecat::instance($testcategories[0]) instanceof context_coursecat); $this->assertTrue(context_course::instance($testcourses[0]) instanceof context_course); $this->assertTrue(context_module::instance($testpages[0]) instanceof context_module); $this->assertTrue(context_block::instance($testblocks[0]) instanceof context_block); $this->assertFalse(context_coursecat::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_course::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_module::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_block::instance(-1, IGNORE_MISSING)); try { context_coursecat::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_course::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_module::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_block::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } // ======= $context->get_url(), $context->get_context_name(), $context->get_capabilities() ========= $testcontexts = array(); $testcontexts[CONTEXT_SYSTEM] = context_system::instance(); $testcontexts[CONTEXT_COURSECAT] = context_coursecat::instance($testcategories[0]); $testcontexts[CONTEXT_COURSE] = context_course::instance($testcourses[0]); $testcontexts[CONTEXT_MODULE] = context_module::instance($testpages[0]); $testcontexts[CONTEXT_BLOCK] = context_block::instance($testblocks[0]); foreach ($testcontexts as $context) { $name = $context->get_context_name(true, true); $this->assertFalse(empty($name)); $this->assertTrue($context->get_url() instanceof moodle_url); $caps = $context->get_capabilities(); $this->assertTrue(is_array($caps)); foreach ($caps as $cap) { $cap = (array)$cap; $this->assertSame(array_keys($cap), array('id', 'name', 'captype', 'contextlevel', 'component', 'riskbitmask')); } } unset($testcontexts); // ===== $context->get_course_context() ========================================= $this->assertFalse($systemcontext->get_course_context(false)); try { $systemcontext->get_course_context(); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $context = context_coursecat::instance($testcategories[0]); $this->assertFalse($context->get_course_context(false)); try { $context->get_course_context(); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $this->assertSame($frontpagecontext->get_course_context(true), $frontpagecontext); $this->assertSame($frontpagepagecontext->get_course_context(true), $frontpagecontext); $this->assertSame($frontpagepageblockcontext->get_course_context(true), $frontpagecontext); // ======= $context->get_parent_context(), $context->get_parent_contexts(), $context->get_parent_context_ids() ======= $userid = reset($testusers); $usercontext = context_user::instance($userid); $this->assertSame($usercontext->get_parent_context(), $systemcontext); $this->assertSame($usercontext->get_parent_contexts(), array($systemcontext->id=>$systemcontext)); $this->assertSame($usercontext->get_parent_contexts(true), array($usercontext->id=>$usercontext, $systemcontext->id=>$systemcontext)); $this->assertSame($systemcontext->get_parent_contexts(), array()); $this->assertSame($systemcontext->get_parent_contexts(true), array($systemcontext->id=>$systemcontext)); $this->assertSame($systemcontext->get_parent_context_ids(), array()); $this->assertSame($systemcontext->get_parent_context_ids(true), array($systemcontext->id)); $this->assertSame($frontpagecontext->get_parent_context(), $systemcontext); $this->assertSame($frontpagecontext->get_parent_contexts(), array($systemcontext->id=>$systemcontext)); $this->assertSame($frontpagecontext->get_parent_contexts(true), array($frontpagecontext->id=>$frontpagecontext, $systemcontext->id=>$systemcontext)); $this->assertSame($frontpagecontext->get_parent_context_ids(), array($systemcontext->id)); $this->assertEquals($frontpagecontext->get_parent_context_ids(true), array($frontpagecontext->id, $systemcontext->id)); $this->assertSame($systemcontext->get_parent_context(), false); $frontpagecontext = context_course::instance($SITE->id); $parent = $systemcontext; foreach ($testcategories as $catid) { $catcontext = context_coursecat::instance($catid); $this->assertSame($catcontext->get_parent_context(), $parent); $parent = $catcontext; } $this->assertSame($frontpagepagecontext->get_parent_context(), $frontpagecontext); $this->assertSame($frontpageblockcontext->get_parent_context(), $frontpagecontext); $this->assertSame($frontpagepageblockcontext->get_parent_context(), $frontpagepagecontext); // ====== $context->get_child_contexts() ================================ $CFG->debug = 0; $children = $systemcontext->get_child_contexts(); $CFG->debug = DEBUG_DEVELOPER; $this->assertEquals(count($children)+1, $DB->count_records('context')); $context = context_coursecat::instance($testcategories[3]); $children = $context->get_child_contexts(); $countcats = 0; $countcourses = 0; $countblocks = 0; foreach ($children as $child) { if ($child->contextlevel == CONTEXT_COURSECAT) { $countcats++; } if ($child->contextlevel == CONTEXT_COURSE) { $countcourses++; } if ($child->contextlevel == CONTEXT_BLOCK) { $countblocks++; } } $this->assertEquals(count($children), 8); $this->assertEquals($countcats, 1); $this->assertEquals($countcourses, 6); $this->assertEquals($countblocks, 1); $context = context_course::instance($testcourses[2]); $children = $context->get_child_contexts(); $this->assertEquals(count($children), 7); // depends on number of default blocks $context = context_module::instance($testpages[3]); $children = $context->get_child_contexts(); $this->assertEquals(count($children), 1); $context = context_block::instance($testblocks[1]); $children = $context->get_child_contexts(); $this->assertEquals(count($children), 0); unset($children); unset($countcats); unset($countcourses); unset($countblocks); // ======= context_helper::reset_caches() ============================ context_helper::reset_caches(); $this->assertEquals(context_inspection::test_context_cache_size(), 0); context_course::instance($SITE->id); $this->assertEquals(context_inspection::test_context_cache_size(), 1); // ======= context preloading ======================================== context_helper::reset_caches(); $sql = "SELECT ".context_helper::get_preload_record_columns_sql('c')." FROM {context} c WHERE c.contextlevel <> ".CONTEXT_SYSTEM; $records = $DB->get_records_sql($sql); $firstrecord = reset($records); $columns = context_helper::get_preload_record_columns('c'); $firstrecord = (array)$firstrecord; $this->assertSame(array_keys($firstrecord), array_values($columns)); context_helper::reset_caches(); foreach ($records as $record) { context_helper::preload_from_record($record); $this->assertEquals($record, new stdClass()); } $this->assertEquals(context_inspection::test_context_cache_size(), count($records)); unset($records); unset($columns); context_helper::reset_caches(); context_helper::preload_course($SITE->id); $this->assertEquals(7, context_inspection::test_context_cache_size()); // depends on number of default blocks // ====== assign_capability(), unassign_capability() ==================== $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertFalse($rc); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext->id); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertEquals($rc->permission, CAP_ALLOW); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext->id); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertEquals($rc->permission, CAP_ALLOW); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext, true); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertEquals($rc->permission, CAP_PREVENT); assign_capability('moodle/site:accessallgroups', CAP_INHERIT, $allroles['teacher'], $frontpagecontext); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertFalse($rc); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext); unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext, true); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertFalse($rc); unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext->id, true); unset($rc); accesslib_clear_all_caches(false); // must be done after assign_capability() // ======= role_assign(), role_unassign(), role_unassign_all() ============== $context = context_course::instance($testcourses[1]); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 0); role_assign($allroles['teacher'], $testusers[1], $context->id); role_assign($allroles['teacher'], $testusers[2], $context->id); role_assign($allroles['manager'], $testusers[1], $context->id); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 3); role_unassign($allroles['teacher'], $testusers[1], $context->id); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 2); role_unassign_all(array('contextid'=>$context->id)); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 0); unset($context); accesslib_clear_all_caches(false); // just in case // ====== has_capability(), get_users_by_capability(), role_switch(), reload_all_capabilities() and friends ======================== $adminid = get_admin()->id; $guestid = $CFG->siteguest; // Enrol some users into some courses $course1 = $DB->get_record('course', array('id'=>$testcourses[22]), '*', MUST_EXIST); $course2 = $DB->get_record('course', array('id'=>$testcourses[7]), '*', MUST_EXIST); $cms = $DB->get_records('course_modules', array('course'=>$course1->id), 'id'); $cm1 = reset($cms); $blocks = $DB->get_records('block_instances', array('parentcontextid'=>context_module::instance($cm1->id)->id), 'id'); $block1 = reset($blocks); $instance1 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course1->id)); $instance2 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course2->id)); for($i=0; $i<9; $i++) { $manualenrol->enrol_user($instance1, $testusers[$i], $allroles['student']); } $manualenrol->enrol_user($instance1, $testusers[8], $allroles['teacher']); $manualenrol->enrol_user($instance1, $testusers[9], $allroles['editingteacher']); for($i=10; $i<15; $i++) { $manualenrol->enrol_user($instance2, $testusers[$i], $allroles['student']); } $manualenrol->enrol_user($instance2, $testusers[15], $allroles['editingteacher']); // Add tons of role assignments - the more the better role_assign($allroles['coursecreator'], $testusers[11], context_coursecat::instance($testcategories[2])); role_assign($allroles['manager'], $testusers[12], context_coursecat::instance($testcategories[1])); role_assign($allroles['student'], $testusers[9], context_module::instance($cm1->id)); role_assign($allroles['teacher'], $testusers[8], context_module::instance($cm1->id)); role_assign($allroles['guest'], $testusers[13], context_course::instance($course1->id)); role_assign($allroles['teacher'], $testusers[7], context_block::instance($block1->id)); role_assign($allroles['manager'], $testusers[9], context_block::instance($block1->id)); role_assign($allroles['editingteacher'], $testusers[9], context_course::instance($course1->id)); role_assign($allroles['teacher'], $adminid, context_course::instance($course1->id)); role_assign($allroles['editingteacher'], $adminid, context_block::instance($block1->id)); // Add tons of overrides - the more the better assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpageblockcontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpageblockcontext, true); assign_capability('moodle/block:view', CAP_PROHIBIT, $allroles['guest'], $frontpageblockcontext, true); assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['user'], $frontpageblockcontext, true); assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['student'], $frontpageblockcontext, true); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $CFG->defaultuserroleid, $frontpagepagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagepagecontext, true); assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $frontpagepagecontext, true); assign_capability('mod/page:view', CAP_ALLOW, $allroles['user'], $frontpagepagecontext, true); assign_capability('moodle/page:view', CAP_ALLOW, $allroles['student'], $frontpagepagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext, true); assign_capability('mod/page:view', CAP_ALLOW, $allroles['guest'], $frontpagecontext, true); assign_capability('mod/page:view', CAP_PROHIBIT, $allroles['user'], $frontpagecontext, true); assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $systemcontext, true); accesslib_clear_all_caches(false); // must be done after assign_capability() // Extra tests for guests and not-logged-in users because they can not be verified by cross checking // with get_users_by_capability() where they are ignored $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, $guestid)); $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, $guestid)); $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, $guestid)); $this->assertFalse(has_capability('mod/page:view', $systemcontext, $guestid)); $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, 0)); $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, 0)); $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, 0)); $this->assertFalse(has_capability('mod/page:view', $systemcontext, 0)); $this->assertFalse(has_capability('moodle/course:create', $systemcontext, $testusers[11])); $this->assertTrue(has_capability('moodle/course:create', context_coursecat::instance($testcategories[2]), $testusers[11])); $this->assertFalse(has_capability('moodle/course:create', context_course::instance($testcourses[1]), $testusers[11])); $this->assertTrue(has_capability('moodle/course:create', context_course::instance($testcourses[19]), $testusers[11])); $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[1]), $testusers[9])); $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[19]), $testusers[9])); $this->assertFalse(has_capability('moodle/course:update', $systemcontext, $testusers[9])); // Test the list of enrolled users $coursecontext = context_course::instance($course1->id); $enrolled = get_enrolled_users($coursecontext); $this->assertEquals(count($enrolled), 10); for($i=0; $i<10; $i++) { $this->assertTrue(isset($enrolled[$testusers[$i]])); } $enrolled = get_enrolled_users($coursecontext, 'moodle/course:update'); $this->assertEquals(count($enrolled), 1); $this->assertTrue(isset($enrolled[$testusers[9]])); unset($enrolled); // role switching $userid = $testusers[9]; $USER = $DB->get_record('user', array('id'=>$userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); $this->assertFalse(is_role_switched($course1->id)); role_switch($allroles['student'], $coursecontext); $this->assertTrue(is_role_switched($course1->id)); $this->assertEquals($USER->access['rsw'][$coursecontext->path], $allroles['student']); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); role_switch(0, $coursecontext); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); $userid = $adminid; $USER = $DB->get_record('user', array('id'=>$userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $blockcontext = context_block::instance($block1->id); $this->assertTrue(has_capability('moodle/course:update', $blockcontext)); role_switch($allroles['student'], $coursecontext); $this->assertEquals($USER->access['rsw'][$coursecontext->path], $allroles['student']); $this->assertFalse(has_capability('moodle/course:update', $blockcontext)); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $blockcontext)); load_all_capabilities(); $this->assertTrue(has_capability('moodle/course:update', $blockcontext)); // temp course role for enrol $DB->delete_records('cache_flags', array()); // this prevents problem with dirty contexts immediately resetting the temp role - this is a known problem... $userid = $testusers[5]; $roleid = $allroles['editingteacher']; $USER = $DB->get_record('user', array('id'=>$userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); $this->assertFalse(isset($USER->access['ra'][$coursecontext->path][$roleid])); load_temp_course_role($coursecontext, $roleid); $this->assertEquals($USER->access['ra'][$coursecontext->path][$roleid], $roleid); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); remove_temp_course_roles($coursecontext); $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid)); load_temp_course_role($coursecontext, $roleid); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid)); $USER = new stdClass(); $USER->id = 0; // Now cross check has_capability() with get_users_by_capability(), each using different code paths, // they have to be kept in sync, usually only one of them breaks, so we know when something is wrong, // at the same time validate extra restrictions (guest read only no risks, admin exception, non existent and deleted users) $contexts = $DB->get_records('context', array(), 'id'); $contexts = array_values($contexts); $capabilities = $DB->get_records('capabilities', array(), 'id'); $capabilities = array_values($capabilities); $roles = array($allroles['guest'], $allroles['user'], $allroles['teacher'], $allroles['editingteacher'], $allroles['coursecreator'], $allroles['manager']); $userids = array_values($testusers); $userids[] = get_admin()->id; if (!PHPUNIT_LONGTEST) { $contexts = array_slice($contexts, 0, 10); $capabilities = array_slice($capabilities, 0, 5); $userids = array_slice($userids, 0, 5); } // Random time! //srand(666); foreach($userids as $userid) { // no guest or deleted // each user gets 0-10 random roles $rcount = rand(0, 10); for($j=0; $j<$rcount; $j++) { $roleid = $roles[rand(0, count($roles)-1)]; $contextid = $contexts[rand(0, count($contexts)-1)]->id; role_assign($roleid, $userid, $contextid); } } $permissions = array(CAP_ALLOW, CAP_PREVENT, CAP_INHERIT, CAP_PREVENT); $maxoverrides = count($contexts)*10; for($j=0; $j<$maxoverrides; $j++) { $roleid = $roles[rand(0, count($roles)-1)]; $contextid = $contexts[rand(0, count($contexts)-1)]->id; $permission = $permissions[rand(0,count($permissions)-1)]; $capname = $capabilities[rand(0, count($capabilities)-1)]->name; assign_capability($capname, $permission, $roleid, $contextid, true); } unset($permissions); unset($roles); accesslib_clear_all_caches(false); // must be done after assign_capability() // Test time - let's set up some real user, just in case the logic for USER affects the others... $USER = $DB->get_record('user', array('id'=>$testusers[3])); load_all_capabilities(); $userids[] = $CFG->siteguest; $userids[] = 0; // not-logged-in user $userids[] = -1; // non-existent user foreach ($contexts as $crecord) { $context = context::instance_by_id($crecord->id); if ($coursecontext = $context->get_course_context(false)) { $enrolled = get_enrolled_users($context); } else { $enrolled = array(); } foreach ($capabilities as $cap) { $allowed = get_users_by_capability($context, $cap->name, 'u.id, u.username'); if ($enrolled) { $enrolledwithcap = get_enrolled_users($context, $cap->name); } else { $enrolledwithcap = array(); } foreach ($userids as $userid) { if ($userid == 0 or isguestuser($userid)) { if ($userid == 0) { $CFG->forcelogin = true; $this->assertFalse(has_capability($cap->name, $context, $userid)); unset($CFG->forcelogin); } if (($cap->captype === 'write') or ($cap->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))) { $this->assertFalse(has_capability($cap->name, $context, $userid)); } $this->assertFalse(isset($allowed[$userid])); } else { if (is_siteadmin($userid)) { $this->assertTrue(has_capability($cap->name, $context, $userid, true)); } $hascap = has_capability($cap->name, $context, $userid, false); $this->assertSame($hascap, isset($allowed[$userid]), "Capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." "); if (isset($enrolled[$userid])) { $this->assertSame(isset($allowed[$userid]), isset($enrolledwithcap[$userid]), "Enrolment with capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." "); } } } } } // Back to nobody $USER = new stdClass(); $USER->id = 0; unset($contexts); unset($userids); unset($capabilities); // Now let's do all the remaining tests that break our carefully prepared fake site // ======= $context->mark_dirty() ======================================= $DB->delete_records('cache_flags', array()); accesslib_clear_all_caches(false); $systemcontext->mark_dirty(); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$systemcontext->path])); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$systemcontext->path])); // ======= $context->reload_if_dirty(); ================================= $DB->delete_records('cache_flags', array()); accesslib_clear_all_caches(false); load_all_capabilities(); $context = context_course::instance($testcourses[2]); $page = $DB->get_record('page', array('course'=>$testcourses[2])); $pagecontext = context_module::instance($page->id); $context->mark_dirty(); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path])); $USER->access['test'] = true; $context->reload_if_dirty(); $this->assertFalse(isset($USER->access['test'])); $context->mark_dirty(); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path])); $USER->access['test'] = true; $pagecontext->reload_if_dirty(); $this->assertFalse(isset($USER->access['test'])); // ======= context_helper::build_all_paths() ============================ $oldcontexts = $DB->get_records('context', array(), 'id'); $DB->set_field_select('context', 'path', NULL, "contextlevel <> ".CONTEXT_SYSTEM); $DB->set_field_select('context', 'depth', 0, "contextlevel <> ".CONTEXT_SYSTEM); context_helper::build_all_paths(); $newcontexts = $DB->get_records('context', array(), 'id'); $this->assertEquals($oldcontexts, $newcontexts); unset($oldcontexts); unset($newcontexts); // ======= $context->reset_paths() ====================================== $context = context_course::instance($testcourses[2]); $children = $context->get_child_contexts(); $context->reset_paths(false); $this->assertSame($DB->get_field('context', 'path', array('id'=>$context->id)), NULL); $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$context->id)), 0); foreach ($children as $child) { $this->assertSame($DB->get_field('context', 'path', array('id'=>$child->id)), NULL); $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$child->id)), 0); } $this->assertEquals(count($children)+1, $DB->count_records('context', array('depth'=>0))); $this->assertEquals(count($children)+1, $DB->count_records('context', array('path'=>NULL))); $context = context_course::instance($testcourses[2]); $context->reset_paths(true); $context = context_course::instance($testcourses[2]); $this->assertEquals($DB->get_field('context', 'path', array('id'=>$context->id)), $context->path); $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$context->id)), $context->depth); $this->assertEquals(0, $DB->count_records('context', array('depth'=>0))); $this->assertEquals(0, $DB->count_records('context', array('path'=>NULL))); // ====== $context->update_moved(); ====================================== accesslib_clear_all_caches(false); $DB->delete_records('cache_flags', array()); $course = $DB->get_record('course', array('id'=>$testcourses[0])); $context = context_course::instance($course->id); $oldpath = $context->path; $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}"); $categorycontext = context_coursecat::instance($miscid); $course->category = $miscid; $DB->update_record('course', $course); $context->update_moved($categorycontext); $context = context_course::instance($course->id); $this->assertEquals($context->get_parent_context(), $categorycontext); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$oldpath])); $this->assertTrue(isset($dirty[$context->path])); // ====== $context->delete_content() ===================================== context_helper::reset_caches(); $context = context_module::instance($testpages[3]); $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); $context->delete_content(); $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); // ====== $context->delete() ============================= context_helper::reset_caches(); $context = context_module::instance($testpages[4]); $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); $bi = $DB->get_record('block_instances', array('parentcontextid'=>$context->id)); $bicontext = context_block::instance($bi->id); $DB->delete_records('cache_flags', array()); $context->delete(); // should delete also linked blocks $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$context->path])); $this->assertFalse($DB->record_exists('context', array('id'=>$context->id))); $this->assertFalse($DB->record_exists('context', array('id'=>$bicontext->id))); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_MODULE, 'instanceid'=>$testpages[4]))); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK, 'instanceid'=>$bi->id))); $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); context_module::instance($testpages[4]); // ====== context_helper::delete_instance() ============================= context_helper::reset_caches(); $lastcourse = array_pop($testcourses); $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse))); $coursecontext = context_course::instance($lastcourse); $this->assertEquals(context_inspection::test_context_cache_size(), 1); $this->assertFalse($coursecontext->instanceid == CONTEXT_COURSE); $DB->delete_records('cache_flags', array()); context_helper::delete_instance(CONTEXT_COURSE, $lastcourse); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$coursecontext->path])); $this->assertEquals(context_inspection::test_context_cache_size(), 0); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse))); context_course::instance($lastcourse); // ======= context_helper::create_instances() ========================== $prevcount = $DB->count_records('context'); $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); context_helper::create_instances(null, true); $this->assertSame($DB->count_records('context'), $prevcount); $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0); $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0); $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); $DB->delete_records('block_instances', array()); $prevcount = $DB->count_records('context'); $DB->delete_records_select('context', 'contextlevel <> '.CONTEXT_SYSTEM); context_helper::create_instances(null, true); $this->assertSame($DB->count_records('context'), $prevcount); $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0); $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0); // ======= context_helper::cleanup_instances() ========================== $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}"); $DB->delete_records('course', array('id'=>$lastcourse)); $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}"); $DB->delete_records('course_categories', array('id'=>$lastcategory)); $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0"); $DB->delete_records('user', array('id'=>$lastuser)); $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id)); $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid)); context_helper::cleanup_instances(); $count = 1; //system $count += $DB->count_records('user', array('deleted'=>0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEquals($DB->count_records('context'), $count); // ======= context cache size restrictions ============================== $testusers= array(); for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) { $user = $generator->create_user(); $testusers[$i] = $user->id; } context_helper::create_instances(null, true); context_helper::reset_caches(); for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) { context_user::instance($testusers[$i]); if ($i == CONTEXT_CACHE_MAX_SIZE - 1) { $this->assertEquals(context_inspection::test_context_cache_size(), CONTEXT_CACHE_MAX_SIZE); } else if ($i == CONTEXT_CACHE_MAX_SIZE) { // once the limit is reached roughly 1/3 of records should be removed from cache $this->assertEquals(context_inspection::test_context_cache_size(), (int)(CONTEXT_CACHE_MAX_SIZE * (2/3) +102)); } } // We keep the first 100 cached $prevsize = context_inspection::test_context_cache_size(); for ($i=0; $i<100; $i++) { context_user::instance($testusers[$i]); $this->assertEquals(context_inspection::test_context_cache_size(), $prevsize); } context_user::instance($testusers[102]); $this->assertEquals(context_inspection::test_context_cache_size(), $prevsize+1); unset($testusers); // ================================================================= // ======= basic test of legacy functions ========================== // ================================================================= // note: watch out, the fake site might be pretty borked already $this->assertSame(get_system_context(), context_system::instance()); foreach ($DB->get_records('context') as $contextid=>$record) { $context = context::instance_by_id($contextid); $this->assertSame(get_context_instance_by_id($contextid), $context); $this->assertSame(get_context_instance($record->contextlevel, $record->instanceid), $context); $this->assertSame(get_parent_contexts($context), $context->get_parent_context_ids()); if ($context->id == SYSCONTEXTID) { $this->assertSame(get_parent_contextid($context), false); } else { $this->assertSame(get_parent_contextid($context), $context->get_parent_context()->id); } } $CFG->debug = 0; $children = get_child_contexts($systemcontext); $CFG->debug = DEBUG_DEVELOPER; $this->assertEquals(count($children), $DB->count_records('context')-1); unset($children); $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); create_contexts(); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK))); $DB->set_field('context', 'depth', 0, array('contextlevel'=>CONTEXT_BLOCK)); build_context_path(); $this->assertFalse($DB->record_exists('context', array('depth'=>0))); $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}"); $DB->delete_records('course', array('id'=>$lastcourse)); $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}"); $DB->delete_records('course_categories', array('id'=>$lastcategory)); $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0"); $DB->delete_records('user', array('id'=>$lastuser)); $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id)); $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid)); cleanup_contexts(); $count = 1; //system $count += $DB->count_records('user', array('deleted'=>0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEquals($DB->count_records('context'), $count); context_helper::reset_caches(); preload_course_contexts($SITE->id); $this->assertEquals(context_inspection::test_context_cache_size(), 1); context_helper::reset_caches(); list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx'); $sql = "SELECT c.id $select FROM {course_categories} c $join"; $records = $DB->get_records_sql($sql); foreach ($records as $record) { context_instance_preload($record); $record = (array)$record; $this->assertEquals(1, count($record)); // only id left } $this->assertEquals(count($records), context_inspection::test_context_cache_size()); accesslib_clear_all_caches(true); $DB->delete_records('cache_flags', array()); mark_context_dirty($systemcontext->path); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$systemcontext->path])); accesslib_clear_all_caches(false); $DB->delete_records('cache_flags', array()); $course = $DB->get_record('course', array('id'=>$testcourses[2])); $context = get_context_instance(CONTEXT_COURSE, $course->id); $oldpath = $context->path; $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}"); $categorycontext = context_coursecat::instance($miscid); $course->category = $miscid; $DB->update_record('course', $course); context_moved($context, $categorycontext); $context = get_context_instance(CONTEXT_COURSE, $course->id); $this->assertEquals($context->get_parent_context(), $categorycontext); $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2]))); delete_context(CONTEXT_COURSE, $testcourses[2]); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2]))); $name = get_contextlevel_name(CONTEXT_COURSE); $this->assertFalse(empty($name)); $context = get_context_instance(CONTEXT_COURSE, $testcourses[2]); $name = print_context_name($context); $this->assertFalse(empty($name)); $url = get_context_url($coursecontext); $this->assertFalse($url instanceof modole_url); $page = $DB->get_record('page', array('id'=>$testpages[7])); $context = get_context_instance(CONTEXT_MODULE, $page->id); $coursecontext = get_course_context($context); $this->assertEquals($coursecontext->contextlevel, CONTEXT_COURSE); $this->assertEquals(get_courseid_from_context($context), $page->course); $caps = fetch_context_capabilities($systemcontext); $this->assertTrue(is_array($caps)); unset($caps); }
/** * Get course participant's details * @param array $userlist array of user ids and according course ids * @return array An array of arrays describing course participants */ public static function get_course_participants_by_id($userlist) { global $CFG, $USER, $DB; require_once($CFG->dirroot . "/user/lib.php"); require_once($CFG->dirroot . "/user/profile/lib.php"); //custom field library require_once($CFG->dirroot . "/lib/filelib.php"); // file handling on description and friends $isadmin = is_siteadmin($USER); $params = self::validate_parameters(self::get_course_participants_by_id_parameters(), array('userlist'=>$userlist)); $userids = array(); $courseids = array(); foreach ($params['userlist'] as $value) { $userids[] = $value['userid']; $courseids[$value['userid']] = $value['courseid']; } // cache all courses $courses = array(); list($cselect, $cjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); list($sqlcourseids, $params) = $DB->get_in_or_equal(array_unique($courseids)); $coursesql = "SELECT c.* $uselect FROM {course} c $cjoin WHERE c.id $sqlcourseids"; $rs = $DB->get_recordset_sql($coursesql, $params); foreach ($rs as $course) { // adding course contexts to cache context_instance_preload($course); // cache courses $courses[$course->id] = $course; } $rs->close(); list($uselect, $ujoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx'); list($sqluserids, $params) = $DB->get_in_or_equal($userids); $usersql = "SELECT u.* $uselect FROM {user} u $ujoin WHERE u.id $sqluserids"; $users = $DB->get_recordset_sql($usersql, $params); $result = array(); foreach ($users as $user) { if (!empty($user->deleted)) { continue; } context_instance_preload($user); $usercontext = get_context_instance(CONTEXT_USER, $user->id); $course = $courses[$courseids[$user->id]]; $context = get_context_instance(CONTEXT_COURSE, $courseids[$user->id]); $hasviewdetailscap = has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext); self::validate_context($context); $currentuser = ($user->id == $USER->id); if (!$currentuser && !$hasviewdetailscap && !has_coursecontact_role($user->id)) { throw new moodle_exception('usernotavailable', 'error'); } $userarray = array(); //basic fields $userarray['id'] = $user->id; if ($isadmin) { $userarray['username'] = $user->username; } if ($isadmin or has_capability('moodle/site:viewfullnames', $context)) { $userarray['firstname'] = $user->firstname; $userarray['lastname'] = $user->lastname; } $userarray['fullname'] = fullname($user); //Custom fields (matching /user/profile/lib.php - profile_display_fields code logic) $userarray['customfields'] = array(); $fields = $DB->get_recordset_sql("SELECT f.* FROM {user_info_field} f JOIN {user_info_category} c ON f.categoryid=c.id ORDER BY c.sortorder ASC, f.sortorder ASC"); foreach ($fields as $field) { require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php'); $newfield = 'profile_field_'.$field->datatype; $formfield = new $newfield($field->id, $user->id); if ($formfield->is_visible() and !$formfield->is_empty()) { $userarray['customfields'][] = array('name' => $formfield->field->name, 'value' => $formfield->data, 'type' => $field->datatype, 'shortname' => $formfield->field->shortname); } } $fields->close(); //image profiles urls (public, no permission required in fact) $profileimageurl = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f1'); $userarray['profileimageurl'] = $profileimageurl->out(false); $profileimageurlsmall = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f2'); $userarray['profileimageurlsmall'] = $profileimageurlsmall->out(false); //hidden user field if (has_capability('moodle/course:viewhiddenuserfields', $context)) { $hiddenfields = array(); } else { $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields)); } if (isset($user->description) && (!isset($hiddenfields['description']) or $isadmin)) { if (empty($CFG->profilesforenrolledusersonly) || $currentuser) { $user->description = file_rewrite_pluginfile_urls($user->description, 'pluginfile.php', $context->id, 'user', 'profile', null); $userarray['description'] = $user->description; $userarray['descriptionformat'] = $user->descriptionformat; } } if ((! isset($hiddenfields['country']) or $isadmin) && $user->country) { $userarray['country'] = $user->country; } if ((! isset($hiddenfields['city']) or $isadmin) && $user->city) { $userarray['city'] = $user->city; } if (has_capability('moodle/course:viewhiddenuserfields', $context)) { if ($user->address) { $userarray['address'] = $user->address; } if ($user->phone1) { $userarray['phone1'] = $user->phone1; } if ($user->phone2) { $userarray['phone2'] = $user->phone2; } } if ($currentuser or $user->maildisplay == 1 or has_capability('moodle/course:useremail', $context) or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER))) { $userarray['email'] = $user->email;; } if ($user->url && (!isset($hiddenfields['webpage']) or $isadmin)) { $url = $user->url; if (strpos($user->url, '://') === false) { $url = 'http://'. $url; } $user->url = clean_param($user->url, PARAM_URL); $userarray['url'] = $user->url; } if ($user->icq && (!isset($hiddenfields['icqnumber']) or $isadmin)) { $userarray['icq'] = $user->icq; } if ($user->skype && (!isset($hiddenfields['skypeid']) or $isadmin)) { $userarray['skype'] = $user->skype; } if ($user->yahoo && (!isset($hiddenfields['yahooid']) or $isadmin)) { $userarray['yahoo'] = $user->yahoo; } if ($user->aim && (!isset($hiddenfields['aimid']) or $isadmin)) { $userarray['aim'] = $user->aim; } if ($user->msn && (!isset($hiddenfields['msnid']) or $isadmin)) { $userarray['msn'] = $user->msn; } if ((!isset($hiddenfields['firstaccess'])) or $isadmin) { if ($user->firstaccess) { $userarray['firstaccess'] = $user->firstaccess; } else { $userarray['firstaccess'] = 0; } } if ((!isset($hiddenfields['lastaccess'])) or $isadmin) { if ($user->lastaccess) { $userarray['lastaccess'] = $user->lastaccess; } else { $userarray['lastaccess'] = 0; } } /// Printing tagged interests if (!empty($CFG->usetags)) { require_once($CFG->dirroot . '/tag/lib.php'); if ($interests = tag_get_tags_csv('user', $user->id, TAG_RETURN_TEXT) ) { $userarray['interests'] = $interests; } } //Departement/Institution are not displayed on any profile, however you can get them from editing profile. if ($isadmin or $currentuser) { if ($user->institution) { $userarray['institution'] = $user->institution; } if (isset($user->department)) { //isset because it's ok to have department 0 $userarray['department'] = $user->department; } } // not a big secret $userarray['roles'] = array(); $roles = get_user_roles($context, $user->id, false); foreach ($roles as $role) { $userarray['roles'][] = array( 'roleid' => $role->roleid, 'name' => $role->name, 'shortname' => $role->shortname, 'sortorder' => $role->sortorder ); } // If groups are in use and enforced throughout the course, then make sure we can meet in at least one course level group if (has_capability('moodle/site:accessallgroups', $context)) { $usergroups = groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid, 'g.id, g.name,g.description'); foreach ($usergroups as $group) { $group->description = file_rewrite_pluginfile_urls($group->description, 'pluginfile.php', $context->id, 'group', 'description', $group->id); $userarray['groups'][] = array('id'=>$group->id, 'name'=>$group->name, 'description'=>$group->description); } } $result[] = $userarray; } $users->close(); return $result; }
/** * Gets all of the courses where the provided user has posted in a forum. * * @global moodle_database $DB The database connection * @param stdClass $user The user who's posts we are looking for * @param bool $discussionsonly If true only look for discussions started by the user * @param bool $includecontexts If set to trye contexts for the courses will be preloaded * @param int $limitfrom The offset of records to return * @param int $limitnum The number of records to return * @return array An array of courses */ function forum_get_courses_user_posted_in($user, $discussionsonly = false, $includecontexts = true, $limitfrom = null, $limitnum = null) { global $DB; // If we are only after discussions we need only look at the forum_discussions // table and join to the userid there. If we are looking for posts then we need // to join to the forum_posts table. if (!$discussionsonly) { $joinsql = 'JOIN {forum_discussions} fd ON fd.course = c.id JOIN {forum_posts} fp ON fp.discussion = fd.id'; $wheresql = 'fp.userid = :userid'; $params = array('userid' => $user->id); } else { $joinsql = 'JOIN {forum_discussions} fd ON fd.course = c.id'; $wheresql = 'fd.userid = :userid'; $params = array('userid' => $user->id); } // Join to the context table so that we can preload contexts if required. if ($includecontexts) { list($ctxselect, $ctxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); } else { $ctxselect = ''; $ctxjoin = ''; } // Now we need to get all of the courses to search. // All courses where the user has posted within a forum will be returned. $sql = "SELECT DISTINCT c.* $ctxselect FROM {course} c $joinsql $ctxjoin WHERE $wheresql"; $courses = $DB->get_records_sql($sql, $params, $limitfrom, $limitnum); if ($includecontexts) { array_map('context_instance_preload', $courses); } return $courses; }
/** * This function gets called by {@link load_user_settings()} and actually works out * what can be shown/done * * @global moodle_database $DB * @param int $courseid The current course' id * @param int $userid The user id to load for * @param string $gstitle The string to pass to get_string for the branch title * @return navigation_node|false */ protected function generate_user_settings($courseid, $userid, $gstitle = 'usercurrentsettings') { global $DB, $CFG, $USER, $SITE; if ($courseid != SITEID) { if (!empty($this->page->course->id) && $this->page->course->id == $courseid) { $course = $this->page->course; } else { list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT c.* {$select} FROM {course} c {$join} WHERE c.id = :courseid"; $course = $DB->get_record_sql($sql, array('courseid' => $courseid), MUST_EXIST); context_instance_preload($course); } } else { $course = $SITE; } $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); // Course context $systemcontext = get_system_context(); $currentuser = $USER->id == $userid; if ($currentuser) { $user = $USER; $usercontext = get_context_instance(CONTEXT_USER, $user->id); // User context } else { list($select, $join) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx'); $sql = "SELECT u.* {$select} FROM {user} u {$join} WHERE u.id = :userid"; $user = $DB->get_record_sql($sql, array('userid' => $userid), IGNORE_MISSING); if (!$user) { return false; } context_instance_preload($user); // Check that the user can view the profile $usercontext = get_context_instance(CONTEXT_USER, $user->id); // User context $canviewuser = has_capability('moodle/user:viewdetails', $usercontext); if ($course->id == SITEID) { if ($CFG->forceloginforprofiles && !has_coursecontact_role($user->id) && !$canviewuser) { // Reduce possibility of "browsing" userbase at site level // Teachers can browse and be browsed at site level. If not forceloginforprofiles, allow access (bug #4366) return false; } } else { $canviewusercourse = has_capability('moodle/user:viewdetails', $coursecontext); $canaccessallgroups = has_capability('moodle/site:accessallgroups', $coursecontext); if (!$canviewusercourse && !$canviewuser || !can_access_course($coursecontext, $user->id)) { return false; } if (!$canaccessallgroups && groups_get_course_groupmode($course) == SEPARATEGROUPS) { // If groups are in use, make sure we can see that group return false; } } } $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $this->page->context)); $key = $gstitle; if ($gstitle != 'usercurrentsettings') { $key .= $userid; } // Add a user setting branch $usersetting = $this->add(get_string($gstitle, 'moodle', $fullname), null, self::TYPE_CONTAINER, null, $key); $usersetting->id = 'usersettings'; if ($this->page->context->contextlevel == CONTEXT_USER && $this->page->context->instanceid == $user->id) { // Automatically start by making it active $usersetting->make_active(); } // Check if the user has been deleted if ($user->deleted) { if (!has_capability('moodle/user:update', $coursecontext)) { // We can't edit the user so just show the user deleted message $usersetting->add(get_string('userdeleted'), null, self::TYPE_SETTING); } else { // We can edit the user so show the user deleted message and link it to the profile if ($course->id == SITEID) { $profileurl = new moodle_url('/user/profile.php', array('id' => $user->id)); } else { $profileurl = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id)); } $usersetting->add(get_string('userdeleted'), $profileurl, self::TYPE_SETTING); } return true; } $userauthplugin = false; if (!empty($user->auth)) { $userauthplugin = get_auth_plugin($user->auth); } // Add the profile edit link if (isloggedin() && !isguestuser($user) && !is_mnet_remote_user($user)) { if (($currentuser || is_siteadmin($USER) || !is_siteadmin($user)) && has_capability('moodle/user:update', $systemcontext)) { $url = new moodle_url('/user/editadvanced.php', array('id' => $user->id, 'course' => $course->id)); $usersetting->add(get_string('editmyprofile'), $url, self::TYPE_SETTING); } else { if (has_capability('moodle/user:editprofile', $usercontext) && !is_siteadmin($user) || $currentuser && has_capability('moodle/user:editownprofile', $systemcontext)) { if ($userauthplugin && $userauthplugin->can_edit_profile()) { $url = $userauthplugin->edit_profile_url(); if (empty($url)) { $url = new moodle_url('/user/edit.php', array('id' => $user->id, 'course' => $course->id)); } $usersetting->add(get_string('editmyprofile'), $url, self::TYPE_SETTING); } } } } // Change password link if ($userauthplugin && $currentuser && !session_is_loggedinas() && !isguestuser() && has_capability('moodle/user:changeownpassword', $systemcontext) && $userauthplugin->can_change_password()) { $passwordchangeurl = $userauthplugin->change_password_url(); if (empty($passwordchangeurl)) { $passwordchangeurl = new moodle_url('/login/change_password.php', array('id' => $course->id)); } $usersetting->add(get_string("changepassword"), $passwordchangeurl, self::TYPE_SETTING); } // View the roles settings if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override', 'moodle/role:manage'), $usercontext)) { $roles = $usersetting->add(get_string('roles'), null, self::TYPE_SETTING); $url = new moodle_url('/admin/roles/usersroles.php', array('userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('thisusersroles', 'role'), $url, self::TYPE_SETTING); $assignableroles = get_assignable_roles($usercontext, ROLENAME_BOTH); if (!empty($assignableroles)) { $url = new moodle_url('/admin/roles/assign.php', array('contextid' => $usercontext->id, 'userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('assignrolesrelativetothisuser', 'role'), $url, self::TYPE_SETTING); } if (has_capability('moodle/role:review', $usercontext) || count(get_overridable_roles($usercontext, ROLENAME_BOTH)) > 0) { $url = new moodle_url('/admin/roles/permissions.php', array('contextid' => $usercontext->id, 'userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('permissions', 'role'), $url, self::TYPE_SETTING); } $url = new moodle_url('/admin/roles/check.php', array('contextid' => $usercontext->id, 'userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('checkpermissions', 'role'), $url, self::TYPE_SETTING); } // Portfolio if ($currentuser && !empty($CFG->enableportfolios) && has_capability('moodle/portfolio:export', $systemcontext)) { require_once $CFG->libdir . '/portfoliolib.php'; if (portfolio_instances(true, false)) { $portfolio = $usersetting->add(get_string('portfolios', 'portfolio'), null, self::TYPE_SETTING); $url = new moodle_url('/user/portfolio.php', array('courseid' => $course->id)); $portfolio->add(get_string('configure', 'portfolio'), $url, self::TYPE_SETTING); $url = new moodle_url('/user/portfoliologs.php', array('courseid' => $course->id)); $portfolio->add(get_string('logs', 'portfolio'), $url, self::TYPE_SETTING); } } $enablemanagetokens = false; if (!empty($CFG->enablerssfeeds)) { $enablemanagetokens = true; } else { if (!is_siteadmin($USER->id) && !empty($CFG->enablewebservices) && has_capability('moodle/webservice:createtoken', get_system_context())) { $enablemanagetokens = true; } } // Security keys if ($currentuser && $enablemanagetokens) { $url = new moodle_url('/user/managetoken.php', array('sesskey' => sesskey())); $usersetting->add(get_string('securitykeys', 'webservice'), $url, self::TYPE_SETTING); } // Repository if (!$currentuser && $usercontext->contextlevel == CONTEXT_USER) { if (!$this->cache->cached('contexthasrepos' . $usercontext->id)) { require_once $CFG->dirroot . '/repository/lib.php'; $editabletypes = repository::get_editable_types($usercontext); $haseditabletypes = !empty($editabletypes); unset($editabletypes); $this->cache->set('contexthasrepos' . $usercontext->id, $haseditabletypes); } else { $haseditabletypes = $this->cache->{'contexthasrepos' . $usercontext->id}; } if ($haseditabletypes) { $url = new moodle_url('/repository/manage_instances.php', array('contextid' => $usercontext->id)); $usersetting->add(get_string('repositories', 'repository'), $url, self::TYPE_SETTING); } } // Messaging if ($currentuser && has_capability('moodle/user:editownmessageprofile', $systemcontext) || !isguestuser($user) && has_capability('moodle/user:editmessageprofile', $usercontext) && !is_primary_admin($user->id)) { $url = new moodle_url('/message/edit.php', array('id' => $user->id, 'course' => $course->id)); $usersetting->add(get_string('editmymessage', 'message'), $url, self::TYPE_SETTING); } // Blogs if ($currentuser && !empty($CFG->bloglevel)) { $blog = $usersetting->add(get_string('blogs', 'blog'), null, navigation_node::TYPE_CONTAINER, null, 'blogs'); $blog->add(get_string('preferences', 'blog'), new moodle_url('/blog/preferences.php'), navigation_node::TYPE_SETTING); if (!empty($CFG->useexternalblogs) && $CFG->maxexternalblogsperuser > 0 && has_capability('moodle/blog:manageexternal', get_context_instance(CONTEXT_SYSTEM))) { $blog->add(get_string('externalblogs', 'blog'), new moodle_url('/blog/external_blogs.php'), navigation_node::TYPE_SETTING); $blog->add(get_string('addnewexternalblog', 'blog'), new moodle_url('/blog/external_blog_edit.php'), navigation_node::TYPE_SETTING); } } // Login as ... if (!$user->deleted and !$currentuser && !session_is_loggedinas() && has_capability('moodle/user:loginas', $coursecontext) && !is_siteadmin($user->id)) { $url = new moodle_url('/course/loginas.php', array('id' => $course->id, 'user' => $user->id, 'sesskey' => sesskey())); $usersetting->add(get_string('loginas'), $url, self::TYPE_SETTING); } return $usersetting; }
function online_assignment_cleanup($output = false) { global $CFG, $DB, $OUTPUT; if ($output) { echo $OUTPUT->heading('Online Assignment Cleanup'); echo '<center>'; } /// We don't want to run this code if we are doing an upgrade from an assignment /// version earlier than 2005041400 /// because the assignment type field will not exist $amv = $DB->get_field('modules', 'version', array('name' => 'assignment')); if ((int) $amv < 2005041400) { if ($output) { echo '</center>'; } return; } /// get the module id for assignments from db $arecord = $DB->get_record('modules', array('name', 'assignment')); $aid = $arecord->id; /// get a list of all courses on this site list($ctxselect, $ctxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT c.* {$ctxselect} FROM {course} c {$ctxjoin}"; $courses = $DB->get_records_sql($sql); /// cycle through each course foreach ($courses as $course) { context_instance_preload($course); $context = get_context_instance(CONTEXT_COURSE, $course->id); if (empty($course->fullname)) { $fullname = get_string('course') . ': ' . $course->id; } else { $fullname = format_string($course->fullname, true, array('context' => $context)); } if ($output) { echo $OUTPUT->heading($fullname); } /// retrieve a list of sections beyond what is currently being shown $sql = "SELECT *\n FROM {course_sections}\n WHERE course=? AND section>?\n ORDER BY section ASC"; $params = array($course->id, $course->numsections); if (!($xsections = $DB->get_records_sql($sql, $params))) { if ($output) { echo 'No extra sections<br />'; } continue; } /// cycle through each of the xtra sections foreach ($xsections as $xsection) { if ($output) { echo 'Checking Section: ' . $xsection->section . '<br />'; } /// grab any module instances from the sequence field if (!empty($xsection->sequence)) { $instances = explode(',', $xsection->sequence); /// cycle through the instances foreach ($instances as $instance) { /// is this an instance of an online assignment $sql = "SELECT a.id\n FROM {course_modules} cm, {assignment} a\n WHERE cm.id = ? AND cm.module = ? AND\n cm.instance = a.id AND a.assignmenttype = 'online'"; $params = array($instance, $aid); /// if record exists then we need to move instance to it's correct section if ($DB->record_exists_sql($sql, $params)) { /// check the new section id /// the journal update erroneously stored it in course_sections->section $newsection = $xsection->section; /// double check the new section if ($newsection > $course->numsections) { /// get the record for section 0 for this course if (!($zerosection = $DB->get_record('course_sections', array('course' => $course->id, 'section' => '0')))) { continue; } $newsection = $zerosection->id; } /// grab the section record if (!($section = $DB->get_record('course_sections', array('id' => $newsection)))) { if ($output) { echo 'Serious error: Cannot retrieve section: ' . $newsection . ' for course: ' . $fullname . '<br />'; } continue; } /// explode the sequence if (($sequence = explode(',', $section->sequence)) === false) { $sequence = array(); } /// add instance to correct section array_push($sequence, $instance); /// implode the sequence $section->sequence = implode(',', $sequence); $DB->set_field('course_sections', 'sequence', $section->sequence, array('id' => $section->id)); /// now we need to remove the instance from the old sequence /// grab the old section record if (!($section = $DB->get_record('course_sections', array('id' => $xsection->id)))) { if ($output) { echo 'Serious error: Cannot retrieve old section: ' . $xsection->id . ' for course: ' . $fullname . '<br />'; } continue; } /// explode the sequence if (($sequence = explode(',', $section->sequence)) === false) { $sequence = array(); } /// remove the old value from the array $key = array_search($instance, $sequence); unset($sequence[$key]); /// implode the sequence $section->sequence = implode(',', $sequence); $DB->set_field('course_sections', 'sequence', $section->sequence, array('id' => $section->id)); if ($output) { echo 'Online Assignment (instance ' . $instance . ') moved from section ' . $section->id . ': to section ' . $newsection . '<br />'; } } } } /// if the summary and sequence are empty then remove this section if (empty($xsection->summary) and empty($xsection->sequence)) { $DB->delete_records('course_sections', array('id' => $xsection->id)); if ($output) { echo 'Deleting empty section ' . $xsection->section . '<br />'; } } } } echo '</center>'; }
/** * This method actually loads the blocks for our page from the database. * * @param boolean|null $includeinvisible * null (default) - load hidden blocks if $this->page->user_is_editing(); * true - load hidden blocks. * false - don't load hidden blocks. */ public function load_blocks($includeinvisible = null) { global $DB, $CFG; if (!is_null($this->birecordsbyregion)) { // Already done. return; } if ($CFG->version < 2009050619) { // Upgrade/install not complete. Don't try too show any blocks. $this->birecordsbyregion = array(); return; } // Ensure we have been initialised. if (is_null($this->defaultregion)) { $this->page->initialise_theme_and_output(); // If there are still no block regions, then there are no blocks on this page. if (empty($this->regions)) { $this->birecordsbyregion = array(); return; } } // Check if we need to load normal blocks if ($this->fakeblocksonly) { $this->birecordsbyregion = $this->prepare_per_region_arrays(); return; } if (is_null($includeinvisible)) { $includeinvisible = $this->page->user_is_editing(); } if ($includeinvisible) { $visiblecheck = ''; } else { $visiblecheck = 'AND (bp.visible = 1 OR bp.visible IS NULL)'; } $context = $this->page->context; $contexttest = 'bi.parentcontextid = :contextid2'; $parentcontextparams = array(); $parentcontextids = get_parent_contexts($context); if ($parentcontextids) { list($parentcontexttest, $parentcontextparams) = $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED, 'parentcontext'); $contexttest = "({$contexttest} OR (bi.showinsubcontexts = 1 AND bi.parentcontextid {$parentcontexttest}))"; } $pagetypepatterns = matching_page_type_patterns($this->page->pagetype); list($pagetypepatterntest, $pagetypepatternparams) = $DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED, 'pagetypepatterntest'); list($ccselect, $ccjoin) = context_instance_preload_sql('bi.id', CONTEXT_BLOCK, 'ctx'); $params = array('subpage1' => $this->page->subpage, 'subpage2' => $this->page->subpage, 'contextid1' => $context->id, 'contextid2' => $context->id, 'pagetype' => $this->page->pagetype); if ($this->page->subpage === '') { $params['subpage1'] = $DB->sql_empty(); $params['subpage2'] = $DB->sql_empty(); } $sql = "SELECT\n bi.id,\n bp.id AS blockpositionid,\n bi.blockname,\n bi.parentcontextid,\n bi.showinsubcontexts,\n bi.pagetypepattern,\n bi.subpagepattern,\n bi.defaultregion,\n bi.defaultweight,\n COALESCE(bp.visible, 1) AS visible,\n COALESCE(bp.region, bi.defaultregion) AS region,\n COALESCE(bp.weight, bi.defaultweight) AS weight,\n bi.configdata\n {$ccselect}\n\n FROM {block_instances} bi\n JOIN {block} b ON bi.blockname = b.name\n LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id\n AND bp.contextid = :contextid1\n AND bp.pagetype = :pagetype\n AND bp.subpage = :subpage1\n {$ccjoin}\n\n WHERE\n {$contexttest}\n AND bi.pagetypepattern {$pagetypepatterntest}\n AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2)\n {$visiblecheck}\n AND b.visible = 1\n\n ORDER BY\n COALESCE(bp.region, bi.defaultregion),\n COALESCE(bp.weight, bi.defaultweight),\n bi.id"; $blockinstances = $DB->get_recordset_sql($sql, $params + $parentcontextparams + $pagetypepatternparams); $this->birecordsbyregion = $this->prepare_per_region_arrays(); $unknown = array(); foreach ($blockinstances as $bi) { context_instance_preload($bi); if ($this->is_known_region($bi->region)) { $this->birecordsbyregion[$bi->region][] = $bi; } else { $unknown[] = $bi; } } // Pages don't necessarily have a defaultregion. The one time this can // happen is when there are no theme block regions, but the script itself // has a block region in the main content area. if (!empty($this->defaultregion)) { $this->birecordsbyregion[$this->defaultregion] = array_merge($this->birecordsbyregion[$this->defaultregion], $unknown); } }
/** * Returns an array of grades calculated by aggregating item ratings. * @param object $options { * userid => int the id of the user whose items have been rated. NOT the user who submitted the ratings. 0 to update all. [required] * aggregationmethod => int the aggregation method to apply when calculating grades ie RATING_AGGREGATE_AVERAGE [required] * scaleid => int the scale from which the user can select a rating. Used for bounds checking. [required] * itemtable => int the table containing the items [required] * itemtableusercolum => int the column of the user table containing the item owner's user id [required] * * contextid => int the context in which the rated items exist [optional] * * modulename => string the name of the module [optional] * moduleid => int the id of the module instance [optional] * * @return array the array of the user's grades */ public function get_user_grades($options) { global $DB; $contextid = null; //if the calling code doesn't supply a context id we'll have to figure it out if( !empty($options->contextid) ) { $contextid = $options->contextid; } else if( !empty($options->cmid) ) { //not implemented as not currently used although cmid is potentially available (the forum supplies it) //Is there a convenient way to get a context id from a cm id? //$cmidnumber = $options->cmidnumber; } else if ( !empty($options->modulename) && !empty($options->moduleid) ) { $modulename = $options->modulename; $moduleid = intval($options->moduleid); //going direct to the db for the context id seems wrong list($ctxselect, $ctxjoin) = context_instance_preload_sql('cm.id', CONTEXT_MODULE, 'ctx'); $sql = "SELECT cm.* $ctxselect FROM {course_modules} cm LEFT JOIN {modules} mo ON mo.id = cm.module LEFT JOIN {{$modulename}} m ON m.id = cm.instance $ctxjoin WHERE mo.name=:modulename AND m.id=:moduleid"; $contextrecord = $DB->get_record_sql($sql, array('modulename'=>$modulename, 'moduleid'=>$moduleid), '*', MUST_EXIST); $contextid = $contextrecord->ctxid; } $params = array(); $params['contextid']= $contextid; $itemtable = $options->itemtable; $itemtableusercolumn= $options->itemtableusercolumn; $scaleid = $options->scaleid; $aggregationstring = $this->get_aggregation_method($options->aggregationmethod); //if userid is not 0 we only want the grade for a single user $singleuserwhere = ''; if ($options->userid!=0) { $params['userid1'] = intval($options->userid); $singleuserwhere = "AND i.{$itemtableusercolumn} = :userid1"; } //MDL-24648 The where line used to be "WHERE (r.contextid is null or r.contextid=:contextid)" //r.contextid will be null for users who haven't been rated yet //no longer including users who haven't been rated to reduce memory requirements $sql = "SELECT u.id as id, u.id AS userid, $aggregationstring(r.rating) AS rawgrade FROM {user} u LEFT JOIN {{$itemtable}} i ON u.id=i.{$itemtableusercolumn} LEFT JOIN {rating} r ON r.itemid=i.id WHERE r.contextid=:contextid $singleuserwhere GROUP BY u.id"; $results = $DB->get_records_sql($sql, $params); if ($results) { $scale = null; $max = 0; if ($options->scaleid >= 0) { //numeric $max = $options->scaleid; } else { //custom scales $scale = $DB->get_record('scale', array('id' => -$options->scaleid)); if ($scale) { $scale = explode(',', $scale->scale); $max = count($scale); } else { debugging('rating_manager::get_user_grades() received a scale ID that doesnt exist'); } } // it could throw off the grading if count and sum returned a rawgrade higher than scale // so to prevent it we review the results and ensure that rawgrade does not exceed the scale, if it does we set rawgrade = scale (i.e. full credit) foreach ($results as $rid=>$result) { if ($options->scaleid >= 0) { //numeric if ($result->rawgrade > $options->scaleid) { $results[$rid]->rawgrade = $options->scaleid; } } else { //scales if (!empty($scale) && $result->rawgrade > $max) { $results[$rid]->rawgrade = $max; } } } } return $results; }
/** * Get course participants details * @param int $courseid course id * @param array $options options { * 'name' => option name * 'value' => option value * } * @return array An array of users */ public static function get_users_by_courseid($courseid, $options) { global $CFG, $USER, $DB; require_once($CFG->dirroot . "/user/lib.php"); $params = self::validate_parameters( self::get_users_by_courseid_parameters(), array( 'courseid'=>$courseid, 'options'=>$options ) ); $withcapability = ''; $groupid = 0; $onlyactive = false; foreach ($options as $option) { switch ($option['name']) { case 'withcapability': $withcapability = $option['value']; break; case 'groupid': $groupid = (int)$option['value']; break; case 'onlyactive': $onlyactive = !empty($option['value']); break; } } // to overwrite this parameter, you need role:review capability if ($withcapability) { require_capability('moodle/role:review', $coursecontext); } // need accessallgroups capability if you want to overwrite this option if (!empty($groupid) && groups_is_member($groupid)) { require_capability('moodle/site:accessallgroups', $context); } // to overwrite this option, you need course:enrolereview permission if ($onlyactive) { require_capability('moodle/course:enrolreview', $coursecontext); } list($coursectxselect, $coursectxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $coursesql = "SELECT c.* $coursectxselect FROM {course} c $coursectxjoin WHERE c.id = $courseid"; $course = $DB->get_record_sql($coursesql); context_instance_preload($course); $coursecontext = get_context_instance(CONTEXT_COURSE, $params['courseid']); if ($courseid == SITEID) { $context = get_system_context(); } else { $context = $coursecontext; } try { self::validate_context($context); } catch (Exception $e) { $exceptionparam = new stdClass(); $exceptionparam->message = $e->getMessage(); $exceptionparam->courseid = $params['courseid']; throw new moodle_exception(get_string('errorcoursecontextnotvalid' , 'webservice', $exceptionparam)); } list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive); list($ctxselect, $ctxjoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx'); $records = $DB->get_records_sql($enrolledsql, $enrolledparams); $sqlparams['courseid'] = $courseid; $sql = "SELECT u.* $ctxselect FROM {user} u $ctxjoin WHERE u.id IN ($enrolledsql) ORDER BY u.id ASC"; $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams); $users = array(); foreach ($enrolledusers as $user) { if (!empty($user->deleted)) { continue; } context_instance_preload($user); if ($userdetails = user_get_user_details($user, $course)) { $users[] = $userdetails; } } $enrolledusers->close(); return $users; }
/** * Returns list of courses user is enrolled into. * * - $fields is an array of fieldnames to ADD * so name the fields you really need, which will * be added and uniq'd * * @param int $userid * @param bool $onlyactive return only active enrolments in courses user may see * @param string|array $fields * @param string $sort * @return array */ function enrol_get_users_courses($userid, $onlyactive = false, $fields = NULL, $sort = 'visible DESC,sortorder ASC') { global $DB; // Guest account does not have any courses if (isguestuser($userid) or empty($userid)) { return(array()); } $basefields = array('id', 'category', 'sortorder', 'shortname', 'fullname', 'idnumber', 'startdate', 'visible', 'groupmode', 'groupmodeforce'); if (empty($fields)) { $fields = $basefields; } else if (is_string($fields)) { // turn the fields from a string to an array $fields = explode(',', $fields); $fields = array_map('trim', $fields); $fields = array_unique(array_merge($basefields, $fields)); } else if (is_array($fields)) { $fields = array_unique(array_merge($basefields, $fields)); } else { throw new coding_exception('Invalid $fileds parameter in enrol_get_my_courses()'); } if (in_array('*', $fields)) { $fields = array('*'); } $orderby = ""; $sort = trim($sort); if (!empty($sort)) { $rawsorts = explode(',', $sort); $sorts = array(); foreach ($rawsorts as $rawsort) { $rawsort = trim($rawsort); if (strpos($rawsort, 'c.') === 0) { $rawsort = substr($rawsort, 2); } $sorts[] = trim($rawsort); } $sort = 'c.'.implode(',c.', $sorts); $orderby = "ORDER BY $sort"; } $params = array('siteid'=>SITEID); if ($onlyactive) { $subwhere = "WHERE ue.status = :active AND e.status = :enabled AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)"; $params['now1'] = round(time(), -2); // improves db caching $params['now2'] = $params['now1']; $params['active'] = ENROL_USER_ACTIVE; $params['enabled'] = ENROL_INSTANCE_ENABLED; } else { $subwhere = ""; } $coursefields = 'c.' .join(',c.', $fields); list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); //note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why we have the subselect there $sql = "SELECT $coursefields $ccselect FROM {course} c JOIN (SELECT DISTINCT e.courseid FROM {enrol} e JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid) $subwhere ) en ON (en.courseid = c.id) $ccjoin WHERE c.id <> :siteid $orderby"; $params['userid'] = $userid; $courses = $DB->get_records_sql($sql, $params); // preload contexts and check visibility foreach ($courses as $id=>$course) { context_instance_preload($course); if ($onlyactive) { if (!$course->visible) { if (!$context = get_context_instance(CONTEXT_COURSE, $id)) { unset($courses[$id]); continue; } if (!has_capability('moodle/course:viewhiddencourses', $context, $userid)) { unset($courses[$id]); continue; } } } $courses[$id] = $course; } //wow! Is that really all? :-D return $courses; }
/** * Loads of the the courses in Moodle into the navigation. * * @param string|array $categoryids Either a string or array of category ids to load courses for * @return array An array of navigation_node */ protected function load_all_courses($categoryids=null) { global $CFG, $DB, $USER; if ($categoryids !== null) { if (is_array($categoryids)) { list ($select, $params) = $DB->get_in_or_equal($categoryids); } else { $select = '= ?'; $params = array($categoryids); } array_unshift($params, SITEID); $select = ' AND c.category '.$select; } else { $params = array(SITEID); $select = ''; } list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT c.id,c.sortorder,c.visible,c.fullname,c.shortname,c.category,cat.path AS categorypath $ccselect FROM {course} c $ccjoin LEFT JOIN {course_categories} cat ON cat.id=c.category WHERE c.id <> ?$select ORDER BY c.sortorder ASC"; $limit = 20; if (!empty($CFG->navcourselimit)) { $limit = $CFG->navcourselimit; } $courses = $DB->get_records_sql($sql, $params, 0, $limit); $coursenodes = array(); foreach ($courses as $course) { context_instance_preload($course); $coursenodes[$course->id] = $this->add_course($course); } return $coursenodes; }
/** * Return a list of current user contacts * This function checks if the current user can send messages to all the users or only to managers * * @param int $group Group to filter * @param string $fi Firstname initial to filter * @param string $li Lastname initial to filter * @param int $roleid Role id to filter * @return array Array of contacts */ public function get_contacts($group, $fi, $li, $roleid) { global $DB, $OUTPUT, $SESSION, $USER; if (!$this->cansend) { return array(); } // Cache (see refresh cache bellow) $hash = "-{$group}-{$fi}-{$li}-{$roleid}-"; if (isset($SESSION->jmailcache->contacts[$this->course->id][$hash])) { // Problem when sending messages to new users. //return $SESSION->jmailcache->contacts[$this->course->id][$hash]; } if (!$this->globalinbox) { if (!has_capability('moodle/course:viewparticipants', $this->context)) { return array(); } } $groupmode = groups_get_course_groupmode($this->course); // Groups are being used $currentgroup = groups_get_course_group($this->course, true); if (!$currentgroup) { // To make some other functions work better later $currentgroup = NULL; } $this->isseparategroups = ($this->course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $this->context)); if ($this->isseparategroups and !$currentgroup) { return array(); } $capability = null; // Users without cansendtoall capability cand send only to managers // Managers are those who can send to all messages if (!$this->cansendtoall and $this->cansendtomanagers) { $capability = "block/jmail:sendtoall"; } list($esql, $params) = get_enrolled_sql($this->context, $capability, $currentgroup, true); $joins = array("FROM {user} u"); $wheres = array(); $select = "SELECT u.id, u.firstname, u.lastname, u.picture, u.imagealt, u.email"; $joins[] = "JOIN ({$esql}) e ON e.id = u.id"; // course enrolled users only $params['courseid'] = $this->course->id; // performance hacks - we preload user contexts together with accounts list($ccselect, $ccjoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx'); $select .= $ccselect; $joins[] = $ccjoin; if ($roleid) { $contextlist = get_related_contexts_string($this->context); $wheres[] = "u.id IN (SELECT userid FROM {role_assignments} WHERE roleid = :roleid AND contextid {$contextlist})"; $params['roleid'] = $roleid; } if ($fi) { $wheres[] = $DB->sql_like('firstname', ':search1', false, false); $params['search1'] = "{$fi}%"; } if ($li) { $wheres[] = $DB->sql_like('lastname', ':search2', false, false); $params['search2'] = "{$li}%"; } if (!empty($this->config->filterfield)) { $wheres[] = "u." . $this->config->filterfield . " = :filterfield"; $params['filterfield'] = $USER->{$this->config->filterfield}; } $from = implode("\n", $joins); if ($wheres) { $where = "WHERE " . implode(" AND ", $wheres); } else { $where = ""; } $sort = ''; $start = ''; $end = ''; $userlist = $DB->get_records_sql("{$select} {$from} {$where} {$sort}", $params, $start, $end); if ($userlist) { foreach ($userlist as $key => $u) { $userlist[$key]->fullname = fullname($u); $userlist[$key]->profileimage = $OUTPUT->user_picture($u); unset($userlist[$key]->email); } } $SESSION->jmailcache->contacts[$this->course->id][$hash] = $userlist; return $userlist; }
/** * Get user information * - This function is matching the permissions of /user/profil.php * - It is also matching some permissions from /user/editadvanced.php for the following fields: * auth, confirmed, idnumber, lang, theme, timezone, mailformat * * @param array $userids array of user ids * @return array An array of arrays describing users * @since Moodle 2.2 */ public static function get_users_by_id($userids) { global $CFG, $USER, $DB; require_once $CFG->dirroot . "/user/lib.php"; //iteramos los parametros y reemplazamos por los ID if (is_array($userids)) { foreach ($userids as $indice => $dni) { $u = $DB->get_record('user', array('username' => $dni)); if (is_object($u)) { $userids[$indice] = $u->id; } } } $params = self::validate_parameters(self::get_users_by_id_parameters(), array('userids' => $userids)); list($uselect, $ujoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx'); list($sqluserids, $params) = $DB->get_in_or_equal($userids); $usersql = "SELECT u.* {$uselect}\n FROM {user} u {$ujoin}\n WHERE u.id {$sqluserids}"; $users = $DB->get_recordset_sql($usersql, $params); $result = array(); $hasuserupdatecap = has_capability('moodle/user:update', get_system_context()); foreach ($users as $user) { if (!empty($user->deleted)) { continue; } context_instance_preload($user); $usercontext = get_context_instance(CONTEXT_USER, $user->id); self::validate_context($usercontext); $currentuser = $user->id == $USER->id; if ($userarray = user_get_user_details($user)) { //fields matching permissions from /user/editadvanced.php if ($currentuser or $hasuserupdatecap) { $userarray['auth'] = $user->auth; $userarray['confirmed'] = $user->confirmed; $userarray['idnumber'] = $user->idnumber; $userarray['lang'] = $user->lang; $userarray['theme'] = $user->theme; $userarray['timezone'] = $user->timezone; $userarray['mailformat'] = $user->mailformat; } $result[] = $userarray; } } $users->close(); return $result; }
/** * A small functional test of accesslib functions and classes. */ public function test_everything_in_accesslib() { global $USER, $SITE, $CFG, $DB, $ACCESSLIB_PRIVATE; // First of all finalize the session, we must not carry over any of this mess to the next page via SESSION!!! session_get_instance()->write_close(); // hack - this is going to take very long time set_time_limit(3600); // Get rid of current user that would not work anyway, // do NOT even think about using $this->switch_global_user_id()! if (!isset($this->accesslibprevuser)) { $this->accesslibprevuser = clone $USER; $USER = new stdClass(); $USER->id = 0; } // Backup $SITE global if (!isset($this->accesslibprevsite)) { $this->accesslibprevsite = $SITE; } // Switch DB, if it somehow fails or you specified wrong unittest prefix it will nuke real data, you have been warned! $this->switch_to_test_db(); // Let's switch the CFG $prevcfg = clone $CFG; $this->switch_to_test_cfg(); $CFG->config_php_settings = $prevcfg->config_php_settings; $CFG->noemailever = true; $CFG->admin = $prevcfg->admin; $CFG->lang = 'en'; $CFG->tempdir = $prevcfg->tempdir; $CFG->cachedir = $prevcfg->cachedir; $CFG->directorypermissions = $prevcfg->directorypermissions; $CFG->filepermissions = $prevcfg->filepermissions; // Reset all caches accesslib_clear_all_caches_for_unit_testing(); // Add some core tables - this is known to break constantly because we keep adding dependencies... $tablenames = array('config', 'config_plugins', 'modules', 'course', 'course_modules', 'course_sections', 'course_categories', 'mnet_host', 'mnet_application', 'capabilities', 'context', 'context_temp', 'role', 'role_capabilities', 'role_allow_switch', 'license', 'my_pages', 'block', 'block_instances', 'block_positions', 'role_allow_assign', 'role_allow_override', 'role_assignments', 'role_context_levels', 'enrol', 'user_enrolments', 'filter_active', 'filter_config', 'comments', 'user', 'groups_members', 'cache_flags', 'events_handlers', 'user_lastaccess', 'rating', 'files', 'role_names', 'user_preferences'); $this->create_test_tables($tablenames, 'lib'); // Create all core default records and default settings require_once "{$CFG->libdir}/db/install.php"; xmldb_main_install(); // installs the capabilities too // Fake mod_page install $tablenames = array('page'); $this->create_test_tables($tablenames, 'mod/page'); $module = new stdClass(); require $CFG->dirroot . '/mod/page/version.php'; $module->name = 'page'; $pagemoduleid = $DB->insert_record('modules', $module); update_capabilities('mod_page'); // Fake block_online_users install $plugin = new stdClass(); $plugin->version = NULL; $plugin->cron = 0; include $CFG->dirroot . '/blocks/online_users/version.php'; $plugin->name = 'online_users'; $onlineusersblockid = $DB->insert_record('block', $plugin); update_capabilities('block_online_users'); // Finish roles setup set_config('defaultfrontpageroleid', $DB->get_field('role', 'id', array('archetype' => 'frontpage'))); set_config('defaultuserroleid', $DB->get_field('role', 'id', array('archetype' => 'user'))); set_config('notloggedinroleid', $DB->get_field('role', 'id', array('archetype' => 'guest'))); set_config('rolesactive', 1); // Init manual enrol set_config('status', ENROL_INSTANCE_ENABLED, 'enrol_manual'); set_config('defaultperiod', 0, 'enrol_manual'); $manualenrol = enrol_get_plugin('manual'); // Fill the site with some real data $testcategories = array(); $testcourses = array(); $testpages = array(); $testblocks = array(); $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id'); $systemcontext = context_system::instance(); $frontpagecontext = context_course::instance(SITEID); // Add block to system context $bi = new stdClass(); $bi->blockname = 'online_users'; $bi->parentcontextid = $systemcontext->id; $bi->showinsubcontexts = 1; $bi->pagetypepattern = ''; $bi->subpagepattern = ''; $bi->defaultregion = ''; $bi->defaultweight = 0; $bi->configdata = ''; $biid = $DB->insert_record('block_instances', $bi); context_block::instance($biid); $testblocks[] = $biid; // Some users $testusers = array(); for ($i = 0; $i < 20; $i++) { $user = new stdClass(); $user->auth = 'manual'; $user->firstname = 'user' . $i; $user->lastname = 'user' . $i; $user->username = '******' . $i; $user->password = '******'; $user->email = "user{$i}@example.com"; $user->confirmed = 1; $user->mnethostid = $CFG->mnet_localhost_id; $user->lang = $CFG->lang; $user->maildisplay = 1; $user->timemodified = time(); $user->deleted = 0; $user->lastip = '0.0.0.0'; $userid = $DB->insert_record('user', $user); $testusers[$i] = $userid; $usercontext = context_user::instance($userid); // Add block to user profile $bi->parentcontextid = $usercontext->id; $biid = $DB->insert_record('block_instances', $bi); context_block::instance($biid); $testblocks[] = $biid; } // Deleted user - should be ignored everywhere, can not have context $user = new stdClass(); $user->auth = 'manual'; $user->firstname = ''; $user->lastname = ''; $user->username = '******'; $user->password = ''; $user->email = ''; $user->confirmed = 1; $user->mnethostid = $CFG->mnet_localhost_id; $user->lang = $CFG->lang; $user->maildisplay = 1; $user->timemodified = time(); $user->deleted = 1; $user->lastip = '0.0.0.0'; $DB->insert_record('user', $user); unset($user); // Add block to frontpage $bi->parentcontextid = $frontpagecontext->id; $biid = $DB->insert_record('block_instances', $bi); $frontpageblockcontext = context_block::instance($biid); $testblocks[] = $biid; // Add a resource to frontpage $page = new stdClass(); $page->course = $SITE->id; $page->intro = '...'; $page->introformat = FORMAT_HTML; $page->content = '...'; $page->contentformat = FORMAT_HTML; $pageid = $DB->insert_record('page', $page); $testpages[] = $pageid; $cm = new stdClass(); $cm->course = $SITE->id; $cm->module = $pagemoduleid; $cm->section = 1; $cm->instance = $pageid; $cmid = $DB->insert_record('course_modules', $cm); $frontpagepagecontext = context_module::instance($cmid); // Add block to frontpage resource $bi->parentcontextid = $frontpagepagecontext->id; $biid = $DB->insert_record('block_instances', $bi); $frontpagepageblockcontext = context_block::instance($biid); $testblocks[] = $biid; // Some nested course categories with courses require_once "{$CFG->dirroot}/course/lib.php"; $path = ''; $parentcat = 0; for ($i = 0; $i < 5; $i++) { $cat = new stdClass(); $cat->name = 'category' . $i; $cat->parent = $parentcat; $cat->depth = $i + 1; $cat->sortorder = MAX_COURSES_IN_CATEGORY * ($i + 2); $cat->timemodified = time(); $catid = $DB->insert_record('course_categories', $cat); $path = $path . '/' . $catid; $DB->set_field('course_categories', 'path', $path, array('id' => $catid)); $parentcat = $catid; $testcategories[] = $catid; $catcontext = context_coursecat::instance($catid); if ($i >= 4) { continue; } // Add resource to each category $bi->parentcontextid = $catcontext->id; $biid = $DB->insert_record('block_instances', $bi); context_block::instance($biid); // Add a few courses to each category for ($j = 0; $j < 6; $j++) { $course = new stdClass(); $course->fullname = 'course' . $j; $course->shortname = 'c' . $j; $course->summary = 'bah bah bah'; $course->newsitems = 0; $course->numsections = 1; $course->category = $catid; $course->format = 'topics'; $course->timecreated = time(); $course->visible = 1; $course->timemodified = $course->timecreated; $courseid = $DB->insert_record('course', $course); $section = new stdClass(); $section->course = $courseid; $section->section = 0; $section->summaryformat = FORMAT_HTML; $DB->insert_record('course_sections', $section); $section->section = 1; $DB->insert_record('course_sections', $section); $testcourses[] = $courseid; $coursecontext = context_course::instance($courseid); if ($j >= 5) { continue; } // Add manual enrol instance $manualenrol->add_default_instance($DB->get_record('course', array('id' => $courseid))); // Add block to each course $bi->parentcontextid = $coursecontext->id; $biid = $DB->insert_record('block_instances', $bi); context_block::instance($biid); $testblocks[] = $biid; // Add a resource to each course $page->course = $courseid; $pageid = $DB->insert_record('page', $page); $testpages[] = $pageid; $cm->course = $courseid; $cm->instance = $pageid; $cm->id = $DB->insert_record('course_modules', $cm); $modcontext = context_module::instance($cm->id); // Add block to each module $bi->parentcontextid = $modcontext->id; $biid = $DB->insert_record('block_instances', $bi); context_block::instance($biid); $testblocks[] = $biid; } } // Make sure all contexts were created properly $count = 1; //system $count += $DB->count_records('user', array('deleted' => 0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEqual($DB->count_records('context'), $count); $this->assertEqual($DB->count_records('context', array('depth' => 0)), 0); $this->assertEqual($DB->count_records('context', array('path' => NULL)), 0); // ====== context_helper::get_level_name() ================================ $levels = context_helper::get_all_levels(); foreach ($levels as $level => $classname) { $name = context_helper::get_level_name($level); $this->assertFalse(empty($name)); } // ======= context::instance_by_id(), context_xxx::instance(); $context = context::instance_by_id($frontpagecontext->id); $this->assertidentical($context->contextlevel, CONTEXT_COURSE); $this->assertFalse(context::instance_by_id(-1, IGNORE_MISSING)); try { context::instance_by_id(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $this->assertTrue(context_system::instance() instanceof context_system); $this->assertTrue(context_coursecat::instance($testcategories[0]) instanceof context_coursecat); $this->assertTrue(context_course::instance($testcourses[0]) instanceof context_course); $this->assertTrue(context_module::instance($testpages[0]) instanceof context_module); $this->assertTrue(context_block::instance($testblocks[0]) instanceof context_block); $this->assertFalse(context_coursecat::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_course::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_module::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_block::instance(-1, IGNORE_MISSING)); try { context_coursecat::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_course::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_module::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_block::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } // ======= $context->get_url(), $context->get_context_name(), $context->get_capabilities() ========= $testcontexts = array(); $testcontexts[CONTEXT_SYSTEM] = context_system::instance(); $testcontexts[CONTEXT_COURSECAT] = context_coursecat::instance($testcategories[0]); $testcontexts[CONTEXT_COURSE] = context_course::instance($testcourses[0]); $testcontexts[CONTEXT_MODULE] = context_module::instance($testpages[0]); $testcontexts[CONTEXT_BLOCK] = context_block::instance($testblocks[0]); foreach ($testcontexts as $context) { $name = $context->get_context_name(true, true); $this->assertFalse(empty($name)); $this->assertTrue($context->get_url() instanceof moodle_url); $caps = $context->get_capabilities(); $this->assertTrue(is_array($caps)); foreach ($caps as $cap) { $cap = (array) $cap; $this->assertIdentical(array_keys($cap), array('id', 'name', 'captype', 'contextlevel', 'component', 'riskbitmask')); } } unset($testcontexts); // ===== $context->get_course_context() ========================================= $this->assertFalse($systemcontext->get_course_context(false)); try { $systemcontext->get_course_context(); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $context = context_coursecat::instance($testcategories[0]); $this->assertFalse($context->get_course_context(false)); try { $context->get_course_context(); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $this->assertIdentical($frontpagecontext->get_course_context(true), $frontpagecontext); $this->assertIdentical($frontpagepagecontext->get_course_context(true), $frontpagecontext); $this->assertIdentical($frontpagepageblockcontext->get_course_context(true), $frontpagecontext); // ======= $context->get_parent_context(), $context->get_parent_contexts(), $context->get_parent_context_ids() ======= $userid = reset($testusers); $usercontext = context_user::instance($userid); $this->assertIdentical($usercontext->get_parent_context(), $systemcontext); $this->assertIdentical($usercontext->get_parent_contexts(), array($systemcontext->id => $systemcontext)); $this->assertIdentical($usercontext->get_parent_contexts(true), array($usercontext->id => $usercontext, $systemcontext->id => $systemcontext)); $this->assertIdentical($systemcontext->get_parent_contexts(), array()); $this->assertIdentical($systemcontext->get_parent_contexts(true), array($systemcontext->id => $systemcontext)); $this->assertIdentical($systemcontext->get_parent_context_ids(), array()); $this->assertIdentical($systemcontext->get_parent_context_ids(true), array($systemcontext->id)); $this->assertIdentical($frontpagecontext->get_parent_context(), $systemcontext); $this->assertIdentical($frontpagecontext->get_parent_contexts(), array($systemcontext->id => $systemcontext)); $this->assertIdentical($frontpagecontext->get_parent_contexts(true), array($frontpagecontext->id => $frontpagecontext, $systemcontext->id => $systemcontext)); $this->assertIdentical($frontpagecontext->get_parent_context_ids(), array($systemcontext->id)); $this->assertEqual($frontpagecontext->get_parent_context_ids(true), array($frontpagecontext->id, $systemcontext->id)); $this->assertIdentical($systemcontext->get_parent_context(), false); $frontpagecontext = context_course::instance($SITE->id); $parent = $systemcontext; foreach ($testcategories as $catid) { $catcontext = context_coursecat::instance($catid); $this->assertIdentical($catcontext->get_parent_context(), $parent); $parent = $catcontext; } $this->assertIdentical($frontpagepagecontext->get_parent_context(), $frontpagecontext); $this->assertIdentical($frontpageblockcontext->get_parent_context(), $frontpagecontext); $this->assertIdentical($frontpagepageblockcontext->get_parent_context(), $frontpagepagecontext); // ====== $context->get_child_contexts() ================================ $children = $systemcontext->get_child_contexts(); $this->assertEqual(count($children) + 1, $DB->count_records('context')); $context = context_coursecat::instance($testcategories[3]); $children = $context->get_child_contexts(); $countcats = 0; $countcourses = 0; $countblocks = 0; foreach ($children as $child) { if ($child->contextlevel == CONTEXT_COURSECAT) { $countcats++; } if ($child->contextlevel == CONTEXT_COURSE) { $countcourses++; } if ($child->contextlevel == CONTEXT_BLOCK) { $countblocks++; } } $this->assertEqual(count($children), 8); $this->assertEqual($countcats, 1); $this->assertEqual($countcourses, 6); $this->assertEqual($countblocks, 1); $context = context_course::instance($testcourses[2]); $children = $context->get_child_contexts(); $this->assertEqual(count($children), 3); $context = context_module::instance($testpages[3]); $children = $context->get_child_contexts(); $this->assertEqual(count($children), 1); $context = context_block::instance($testblocks[1]); $children = $context->get_child_contexts(); $this->assertEqual(count($children), 0); unset($children); unset($countcats); unset($countcourses); unset($countblocks); // ======= context_helper::reset_caches() ============================ context_helper::reset_caches(); $this->assertEqual(context_inspection::test_context_cache_size(), 0); context_course::instance($SITE->id); $this->assertEqual(context_inspection::test_context_cache_size(), 1); // ======= context preloading ======================================== context_helper::reset_caches(); $sql = "SELECT " . context_helper::get_preload_record_columns_sql('c') . "\n FROM {context} c\n WHERE c.contextlevel <> " . CONTEXT_SYSTEM; $records = $DB->get_records_sql($sql); $firstrecord = reset($records); $columns = context_helper::get_preload_record_columns('c'); $firstrecord = (array) $firstrecord; $this->assertIdentical(array_keys($firstrecord), array_values($columns)); context_helper::reset_caches(); foreach ($records as $record) { context_helper::preload_from_record($record); $this->assertIdentical($record, new stdClass()); } $this->assertEqual(context_inspection::test_context_cache_size(), count($records)); unset($records); unset($columns); context_helper::reset_caches(); context_helper::preload_course($SITE->id); $this->assertEqual(context_inspection::test_context_cache_size(), 4); // ====== assign_capability(), unassign_capability() ==================== $rc = $DB->get_record('role_capabilities', array('contextid' => $frontpagecontext->id, 'roleid' => $allroles['teacher'], 'capability' => 'moodle/site:accessallgroups')); $this->assertFalse($rc); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext->id); $rc = $DB->get_record('role_capabilities', array('contextid' => $frontpagecontext->id, 'roleid' => $allroles['teacher'], 'capability' => 'moodle/site:accessallgroups')); $this->assertEqual($rc->permission, CAP_ALLOW); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext->id); $rc = $DB->get_record('role_capabilities', array('contextid' => $frontpagecontext->id, 'roleid' => $allroles['teacher'], 'capability' => 'moodle/site:accessallgroups')); $this->assertEqual($rc->permission, CAP_ALLOW); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext, true); $rc = $DB->get_record('role_capabilities', array('contextid' => $frontpagecontext->id, 'roleid' => $allroles['teacher'], 'capability' => 'moodle/site:accessallgroups')); $this->assertEqual($rc->permission, CAP_PREVENT); assign_capability('moodle/site:accessallgroups', CAP_INHERIT, $allroles['teacher'], $frontpagecontext); $rc = $DB->get_record('role_capabilities', array('contextid' => $frontpagecontext->id, 'roleid' => $allroles['teacher'], 'capability' => 'moodle/site:accessallgroups')); $this->assertFalse($rc); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext); unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext, true); $rc = $DB->get_record('role_capabilities', array('contextid' => $frontpagecontext->id, 'roleid' => $allroles['teacher'], 'capability' => 'moodle/site:accessallgroups')); $this->assertFalse($rc); unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext->id, true); unset($rc); accesslib_clear_all_caches(false); // must be done after assign_capability() // ======= role_assign(), role_unassign(), role_unassign_all() ============== $context = context_course::instance($testcourses[1]); $this->assertEqual($DB->count_records('role_assignments', array('contextid' => $context->id)), 0); role_assign($allroles['teacher'], $testusers[1], $context->id); role_assign($allroles['teacher'], $testusers[2], $context->id); role_assign($allroles['manager'], $testusers[1], $context->id); $this->assertEqual($DB->count_records('role_assignments', array('contextid' => $context->id)), 3); role_unassign($allroles['teacher'], $testusers[1], $context->id); $this->assertEqual($DB->count_records('role_assignments', array('contextid' => $context->id)), 2); role_unassign_all(array('contextid' => $context->id)); $this->assertEqual($DB->count_records('role_assignments', array('contextid' => $context->id)), 0); unset($context); accesslib_clear_all_caches(false); // just in case // ====== has_capability(), get_users_by_capability(), role_switch(), reload_all_capabilities() and friends ======================== $adminid = get_admin()->id; $guestid = $CFG->siteguest; // Enrol some users into some courses $course1 = $DB->get_record('course', array('id' => $testcourses[22]), '*', MUST_EXIST); $course2 = $DB->get_record('course', array('id' => $testcourses[7]), '*', MUST_EXIST); $cms = $DB->get_records('course_modules', array('course' => $course1->id), 'id'); $cm1 = reset($cms); $blocks = $DB->get_records('block_instances', array('parentcontextid' => context_module::instance($cm1->id)->id), 'id'); $block1 = reset($blocks); $instance1 = $DB->get_record('enrol', array('enrol' => 'manual', 'courseid' => $course1->id)); $instance2 = $DB->get_record('enrol', array('enrol' => 'manual', 'courseid' => $course2->id)); for ($i = 0; $i < 9; $i++) { $manualenrol->enrol_user($instance1, $testusers[$i], $allroles['student']); } $manualenrol->enrol_user($instance1, $testusers[8], $allroles['teacher']); $manualenrol->enrol_user($instance1, $testusers[9], $allroles['editingteacher']); for ($i = 10; $i < 15; $i++) { $manualenrol->enrol_user($instance2, $testusers[$i], $allroles['student']); } $manualenrol->enrol_user($instance2, $testusers[15], $allroles['editingteacher']); // Add tons of role assignments - the more the better role_assign($allroles['coursecreator'], $testusers[11], context_coursecat::instance($testcategories[2])); role_assign($allroles['manager'], $testusers[12], context_coursecat::instance($testcategories[1])); role_assign($allroles['student'], $testusers[9], context_module::instance($cm1->id)); role_assign($allroles['teacher'], $testusers[8], context_module::instance($cm1->id)); role_assign($allroles['guest'], $testusers[13], context_course::instance($course1->id)); role_assign($allroles['teacher'], $testusers[7], context_block::instance($block1->id)); role_assign($allroles['manager'], $testusers[9], context_block::instance($block1->id)); role_assign($allroles['editingteacher'], $testusers[9], context_course::instance($course1->id)); role_assign($allroles['teacher'], $adminid, context_course::instance($course1->id)); role_assign($allroles['editingteacher'], $adminid, context_block::instance($block1->id)); // Add tons of overrides - the more the better assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpageblockcontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpageblockcontext, true); assign_capability('moodle/block:view', CAP_PROHIBIT, $allroles['guest'], $frontpageblockcontext, true); assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['user'], $frontpageblockcontext, true); assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['student'], $frontpageblockcontext, true); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $CFG->defaultuserroleid, $frontpagepagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagepagecontext, true); assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $frontpagepagecontext, true); assign_capability('mod/page:view', CAP_ALLOW, $allroles['user'], $frontpagepagecontext, true); assign_capability('moodle/page:view', CAP_ALLOW, $allroles['student'], $frontpagepagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext, true); assign_capability('mod/page:view', CAP_ALLOW, $allroles['guest'], $frontpagecontext, true); assign_capability('mod/page:view', CAP_PROHIBIT, $allroles['user'], $frontpagecontext, true); assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $systemcontext, true); accesslib_clear_all_caches(false); // must be done after assign_capability() // Extra tests for guests and not-logged-in users because they can not be verified by cross checking // with get_users_by_capability() where they are ignored $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, $guestid)); $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, $guestid)); $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, $guestid)); $this->assertFalse(has_capability('mod/page:view', $systemcontext, $guestid)); $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, 0)); $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, 0)); $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, 0)); $this->assertFalse(has_capability('mod/page:view', $systemcontext, 0)); $this->assertFalse(has_capability('moodle/course:create', $systemcontext, $testusers[11])); $this->assertTrue(has_capability('moodle/course:create', context_coursecat::instance($testcategories[2]), $testusers[11])); $this->assertFalse(has_capability('moodle/course:create', context_course::instance($testcourses[1]), $testusers[11])); $this->assertTrue(has_capability('moodle/course:create', context_course::instance($testcourses[19]), $testusers[11])); $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[1]), $testusers[9])); $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[19]), $testusers[9])); $this->assertFalse(has_capability('moodle/course:update', $systemcontext, $testusers[9])); // Test the list of enrolled users $coursecontext = context_course::instance($course1->id); $enrolled = get_enrolled_users($coursecontext); $this->assertEqual(count($enrolled), 10); for ($i = 0; $i < 10; $i++) { $this->assertTrue(isset($enrolled[$testusers[$i]])); } $enrolled = get_enrolled_users($coursecontext, 'moodle/course:update'); $this->assertEqual(count($enrolled), 1); $this->assertTrue(isset($enrolled[$testusers[9]])); unset($enrolled); // role switching $userid = $testusers[9]; $USER = $DB->get_record('user', array('id' => $userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); $this->assertFalse(is_role_switched($course1->id)); role_switch($allroles['student'], $coursecontext); $this->assertTrue(is_role_switched($course1->id)); $this->assertEqual($USER->access['rsw'][$coursecontext->path], $allroles['student']); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); role_switch(0, $coursecontext); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); $userid = $adminid; $USER = $DB->get_record('user', array('id' => $userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $blockcontext = context_block::instance($block1->id); $this->assertTrue(has_capability('moodle/course:update', $blockcontext)); role_switch($allroles['student'], $coursecontext); $this->assertEqual($USER->access['rsw'][$coursecontext->path], $allroles['student']); $this->assertFalse(has_capability('moodle/course:update', $blockcontext)); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $blockcontext)); load_all_capabilities(); $this->assertTrue(has_capability('moodle/course:update', $blockcontext)); // temp course role for enrol $DB->delete_records('cache_flags', array()); // this prevents problem with dirty contexts immediately resetting the temp role - this is a known problem... $userid = $testusers[5]; $roleid = $allroles['editingteacher']; $USER = $DB->get_record('user', array('id' => $userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); $this->assertFalse(isset($USER->access['ra'][$coursecontext->path][$roleid])); load_temp_course_role($coursecontext, $roleid); $this->assertEqual($USER->access['ra'][$coursecontext->path][$roleid], $roleid); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); remove_temp_course_roles($coursecontext); $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid)); load_temp_course_role($coursecontext, $roleid); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid)); $USER = new stdClass(); $USER->id = 0; // Now cross check has_capability() with get_users_by_capability(), each using different code paths, // they have to be kept in sync, usually only one of them breaks, so we know when something is wrong, // at the same time validate extra restrictions (guest read only no risks, admin exception, non existent and deleted users) $contexts = $DB->get_records('context', array(), 'id'); $contexts = array_values($contexts); $capabilities = $DB->get_records('capabilities', array(), 'id'); $capabilities = array_values($capabilities); $roles = array($allroles['guest'], $allroles['user'], $allroles['teacher'], $allroles['editingteacher'], $allroles['coursecreator'], $allroles['manager']); // Random time! srand(666); foreach ($testusers as $userid) { // no guest or deleted // each user gets 0-20 random roles $rcount = rand(0, 10); for ($j = 0; $j < $rcount; $j++) { $roleid = $roles[rand(0, count($roles) - 1)]; $contextid = $contexts[rand(0, count($contexts) - 1)]->id; role_assign($roleid, $userid, $contextid); } } $permissions = array(CAP_ALLOW, CAP_PREVENT, CAP_INHERIT, CAP_PREVENT); for ($j = 0; $j < 10000; $j++) { $roleid = $roles[rand(0, count($roles) - 1)]; $contextid = $contexts[rand(0, count($contexts) - 1)]->id; $permission = $permissions[rand(0, count($permissions) - 1)]; $capname = $capabilities[rand(0, count($capabilities) - 1)]->name; assign_capability($capname, $permission, $roleid, $contextid, true); } unset($permissions); unset($roles); unset($contexts); unset($users); unset($capabilities); accesslib_clear_all_caches(false); // must be done after assign_capability() // Test time - let's set up some real user, just in case the logic for USER affects the others... $USER = $DB->get_record('user', array('id' => $testusers[3])); load_all_capabilities(); $contexts = $DB->get_records('context', array(), 'id'); $users = $DB->get_records('user', array(), 'id', 'id'); $capabilities = $DB->get_records('capabilities', array(), 'id'); $users[0] = null; // not-logged-in user $users[-1] = null; // non-existent user foreach ($contexts as $crecord) { $context = context::instance_by_id($crecord->id); if ($coursecontext = $context->get_course_context(false)) { $enrolled = get_enrolled_users($context); } else { $enrolled = array(); } foreach ($capabilities as $cap) { $allowed = get_users_by_capability($context, $cap->name, 'u.id, u.username'); if ($enrolled) { $enrolledwithcap = get_enrolled_users($context, $cap->name); } else { $enrolledwithcap = array(); } foreach ($users as $userid => $unused) { if ($userid == 0 or isguestuser($userid)) { if ($userid == 0) { $CFG->forcelogin = true; $this->assertFalse(has_capability($cap->name, $context, $userid)); unset($CFG->forcelogin); } if ($cap->captype === 'write' or $cap->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS)) { $this->assertFalse(has_capability($cap->name, $context, $userid)); } $this->assertFalse(isset($allowed[$userid])); } else { if (is_siteadmin($userid)) { $this->assertTrue(has_capability($cap->name, $context, $userid, true)); } $hascap = has_capability($cap->name, $context, $userid, false); $this->assertIdentical($hascap, isset($allowed[$userid]), "Capability result mismatch user:{$userid}, context:{$context->id}, {$cap->name}, hascap: " . (int) $hascap . " "); if (isset($enrolled[$userid])) { $this->assertIdentical(isset($allowed[$userid]), isset($enrolledwithcap[$userid]), "Enrolment with capability result mismatch user:{$userid}, context:{$context->id}, {$cap->name}, hascap: " . (int) $hascap . " "); } } } } } // Back to nobody $USER = new stdClass(); $USER->id = 0; unset($contexts); unset($users); unset($capabilities); // Now let's do all the remaining tests that break our carefully prepared fake site // ======= $context->mark_dirty() ======================================= $DB->delete_records('cache_flags', array()); accesslib_clear_all_caches(false); $systemcontext->mark_dirty(); $dirty = get_cache_flags('accesslib/dirtycontexts', time() - 2); $this->assertTrue(isset($dirty[$systemcontext->path])); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$systemcontext->path])); // ======= $context->reload_if_dirty(); ================================= $DB->delete_records('cache_flags', array()); accesslib_clear_all_caches(false); load_all_capabilities(); $context = context_course::instance($testcourses[2]); $page = $DB->get_record('page', array('course' => $testcourses[2])); $pagecontext = context_module::instance($page->id); $context->mark_dirty(); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path])); $USER->access['test'] = true; $context->reload_if_dirty(); $this->assertFalse(isset($USER->access['test'])); $context->mark_dirty(); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path])); $USER->access['test'] = true; $pagecontext->reload_if_dirty(); $this->assertFalse(isset($USER->access['test'])); // ======= context_helper::build_all_paths() ============================ $oldcontexts = $DB->get_records('context', array(), 'id'); $DB->set_field_select('context', 'path', NULL, "contextlevel <> " . CONTEXT_SYSTEM); $DB->set_field_select('context', 'depth', 0, "contextlevel <> " . CONTEXT_SYSTEM); context_helper::build_all_paths(); $newcontexts = $DB->get_records('context', array(), 'id'); $this->assertIdentical($oldcontexts, $newcontexts); unset($oldcontexts); unset($newcontexts); // ======= $context->reset_paths() ====================================== $context = context_course::instance($testcourses[2]); $children = $context->get_child_contexts(); $context->reset_paths(false); $this->assertIdentical($DB->get_field('context', 'path', array('id' => $context->id)), NULL); $this->assertEqual($DB->get_field('context', 'depth', array('id' => $context->id)), 0); foreach ($children as $child) { $this->assertIdentical($DB->get_field('context', 'path', array('id' => $child->id)), NULL); $this->assertEqual($DB->get_field('context', 'depth', array('id' => $child->id)), 0); } $this->assertEqual(count($children) + 1, $DB->count_records('context', array('depth' => 0))); $this->assertEqual(count($children) + 1, $DB->count_records('context', array('path' => NULL))); $context = context_course::instance($testcourses[2]); $context->reset_paths(true); $context = context_course::instance($testcourses[2]); $this->assertEqual($DB->get_field('context', 'path', array('id' => $context->id)), $context->path); $this->assertEqual($DB->get_field('context', 'depth', array('id' => $context->id)), $context->depth); $this->assertEqual(0, $DB->count_records('context', array('depth' => 0))); $this->assertEqual(0, $DB->count_records('context', array('path' => NULL))); // ====== $context->update_moved(); ====================================== accesslib_clear_all_caches(false); $DB->delete_records('cache_flags', array()); $course = $DB->get_record('course', array('id' => $testcourses[0])); $context = context_course::instance($course->id); $oldpath = $context->path; $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}"); $categorycontext = context_coursecat::instance($miscid); $course->category = $miscid; $DB->update_record('course', $course); $context->update_moved($categorycontext); $context = context_course::instance($course->id); $this->assertIdentical($context->get_parent_context(), $categorycontext); $dirty = get_cache_flags('accesslib/dirtycontexts', time() - 2); $this->assertTrue(isset($dirty[$oldpath])); $this->assertTrue(isset($dirty[$context->path])); // ====== $context->delete_content() ===================================== context_helper::reset_caches(); $context = context_module::instance($testpages[3]); $this->assertTrue($DB->record_exists('context', array('id' => $context->id))); $this->assertEqual(1, $DB->count_records('block_instances', array('parentcontextid' => $context->id))); $context->delete_content(); $this->assertTrue($DB->record_exists('context', array('id' => $context->id))); $this->assertEqual(0, $DB->count_records('block_instances', array('parentcontextid' => $context->id))); // ====== $context->delete() ============================= context_helper::reset_caches(); $context = context_module::instance($testpages[4]); $this->assertTrue($DB->record_exists('context', array('id' => $context->id))); $this->assertEqual(1, $DB->count_records('block_instances', array('parentcontextid' => $context->id))); $bi = $DB->get_record('block_instances', array('parentcontextid' => $context->id)); $bicontext = context_block::instance($bi->id); $DB->delete_records('cache_flags', array()); $context->delete(); // should delete also linked blocks $dirty = get_cache_flags('accesslib/dirtycontexts', time() - 2); $this->assertTrue(isset($dirty[$context->path])); $this->assertFalse($DB->record_exists('context', array('id' => $context->id))); $this->assertFalse($DB->record_exists('context', array('id' => $bicontext->id))); $this->assertFalse($DB->record_exists('context', array('contextlevel' => CONTEXT_MODULE, 'instanceid' => $testpages[4]))); $this->assertFalse($DB->record_exists('context', array('contextlevel' => CONTEXT_BLOCK, 'instanceid' => $bi->id))); $this->assertEqual(0, $DB->count_records('block_instances', array('parentcontextid' => $context->id))); context_module::instance($testpages[4]); // ====== context_helper::delete_instance() ============================= context_helper::reset_caches(); $lastcourse = array_pop($testcourses); $this->assertTrue($DB->record_exists('context', array('contextlevel' => CONTEXT_COURSE, 'instanceid' => $lastcourse))); $coursecontext = context_course::instance($lastcourse); $this->assertEqual(context_inspection::test_context_cache_size(), 1); $this->assertFalse($coursecontext->instanceid == CONTEXT_COURSE); $DB->delete_records('cache_flags', array()); context_helper::delete_instance(CONTEXT_COURSE, $lastcourse); $dirty = get_cache_flags('accesslib/dirtycontexts', time() - 2); $this->assertTrue(isset($dirty[$coursecontext->path])); $this->assertEqual(context_inspection::test_context_cache_size(), 0); $this->assertFalse($DB->record_exists('context', array('contextlevel' => CONTEXT_COURSE, 'instanceid' => $lastcourse))); context_course::instance($lastcourse); // ======= context_helper::create_instances() ========================== $prevcount = $DB->count_records('context'); $DB->delete_records('context', array('contextlevel' => CONTEXT_BLOCK)); context_helper::create_instances(null, true); $this->assertIdentical($DB->count_records('context'), $prevcount); $this->assertEqual($DB->count_records('context', array('depth' => 0)), 0); $this->assertEqual($DB->count_records('context', array('path' => NULL)), 0); $DB->delete_records('context', array('contextlevel' => CONTEXT_BLOCK)); $DB->delete_records('block_instances', array()); $prevcount = $DB->count_records('context'); $DB->delete_records_select('context', 'contextlevel <> ' . CONTEXT_SYSTEM); context_helper::create_instances(null, true); $this->assertIdentical($DB->count_records('context'), $prevcount); $this->assertEqual($DB->count_records('context', array('depth' => 0)), 0); $this->assertEqual($DB->count_records('context', array('path' => NULL)), 0); // ======= context_helper::cleanup_instances() ========================== $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}"); $DB->delete_records('course', array('id' => $lastcourse)); $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}"); $DB->delete_records('course_categories', array('id' => $lastcategory)); $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0"); $DB->delete_records('user', array('id' => $lastuser)); $DB->delete_records('block_instances', array('parentcontextid' => $frontpagepagecontext->id)); $DB->delete_records('course_modules', array('id' => $frontpagepagecontext->instanceid)); context_helper::cleanup_instances(); $count = 1; //system $count += $DB->count_records('user', array('deleted' => 0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEqual($DB->count_records('context'), $count); // ======= context cache size restrictions ============================== $testusers = array(); for ($i = 0; $i < CONTEXT_CACHE_MAX_SIZE + 100; $i++) { $user = new stdClass(); $user->auth = 'manual'; $user->firstname = 'xuser' . $i; $user->lastname = 'xuser' . $i; $user->username = '******' . $i; $user->password = '******'; $user->email = "xuser{$i}@example.com"; $user->confirmed = 1; $user->mnethostid = $CFG->mnet_localhost_id; $user->lang = $CFG->lang; $user->maildisplay = 1; $user->timemodified = time(); $user->lastip = '0.0.0.0'; $userid = $DB->insert_record('user', $user); $testusers[$i] = $userid; } context_helper::create_instances(null, true); context_helper::reset_caches(); for ($i = 0; $i < CONTEXT_CACHE_MAX_SIZE + 100; $i++) { context_user::instance($testusers[$i]); if ($i == CONTEXT_CACHE_MAX_SIZE - 1) { $this->assertEqual(context_inspection::test_context_cache_size(), CONTEXT_CACHE_MAX_SIZE); } else { if ($i == CONTEXT_CACHE_MAX_SIZE) { // once the limit is reached roughly 1/3 of records should be removed from cache $this->assertEqual(context_inspection::test_context_cache_size(), (int) (CONTEXT_CACHE_MAX_SIZE * (2 / 3) + 102)); } } } // We keep the first 100 cached $prevsize = context_inspection::test_context_cache_size(); for ($i = 0; $i < 100; $i++) { context_user::instance($testusers[$i]); $this->assertEqual(context_inspection::test_context_cache_size(), $prevsize); } context_user::instance($testusers[102]); $this->assertEqual(context_inspection::test_context_cache_size(), $prevsize + 1); unset($testusers); // ================================================================= // ======= basic test of legacy functions ========================== // ================================================================= // note: watch out, the fake site might be pretty borked already $this->assertIdentical(get_system_context(), context_system::instance()); foreach ($DB->get_records('context') as $contextid => $record) { $context = context::instance_by_id($contextid); $this->assertIdentical(get_context_instance_by_id($contextid), $context); $this->assertIdentical(get_context_instance($record->contextlevel, $record->instanceid), $context); $this->assertIdentical(get_parent_contexts($context), $context->get_parent_context_ids()); if ($context->id == SYSCONTEXTID) { $this->assertIdentical(get_parent_contextid($context), false); } else { $this->assertIdentical(get_parent_contextid($context), $context->get_parent_context()->id); } } $children = get_child_contexts($systemcontext); $this->assertEqual(count($children), $DB->count_records('context') - 1); unset($children); $DB->delete_records('context', array('contextlevel' => CONTEXT_BLOCK)); create_contexts(); $this->assertFalse($DB->record_exists('context', array('contextlevel' => CONTEXT_BLOCK))); $DB->set_field('context', 'depth', 0, array('contextlevel' => CONTEXT_BLOCK)); build_context_path(); $this->assertFalse($DB->record_exists('context', array('depth' => 0))); $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}"); $DB->delete_records('course', array('id' => $lastcourse)); $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}"); $DB->delete_records('course_categories', array('id' => $lastcategory)); $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0"); $DB->delete_records('user', array('id' => $lastuser)); $DB->delete_records('block_instances', array('parentcontextid' => $frontpagepagecontext->id)); $DB->delete_records('course_modules', array('id' => $frontpagepagecontext->instanceid)); cleanup_contexts(); $count = 1; //system $count += $DB->count_records('user', array('deleted' => 0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEqual($DB->count_records('context'), $count); context_helper::reset_caches(); preload_course_contexts($SITE->id); $this->assertEqual(context_inspection::test_context_cache_size(), 1); context_helper::reset_caches(); list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx'); $sql = "SELECT c.id {$select} FROM {course_categories} c {$join}"; $records = $DB->get_records_sql($sql); foreach ($records as $record) { context_instance_preload($record); $record = (array) $record; $this->assertEqual(1, count($record)); // only id left } $this->assertEqual(count($records), context_inspection::test_context_cache_size()); accesslib_clear_all_caches(true); $DB->delete_records('cache_flags', array()); mark_context_dirty($systemcontext->path); $dirty = get_cache_flags('accesslib/dirtycontexts', time() - 2); $this->assertTrue(isset($dirty[$systemcontext->path])); accesslib_clear_all_caches(false); $DB->delete_records('cache_flags', array()); $course = $DB->get_record('course', array('id' => $testcourses[2])); $context = get_context_instance(CONTEXT_COURSE, $course->id); $oldpath = $context->path; $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}"); $categorycontext = context_coursecat::instance($miscid); $course->category = $miscid; $DB->update_record('course', $course); context_moved($context, $categorycontext); $context = get_context_instance(CONTEXT_COURSE, $course->id); $this->assertIdentical($context->get_parent_context(), $categorycontext); $this->assertTrue($DB->record_exists('context', array('contextlevel' => CONTEXT_COURSE, 'instanceid' => $testcourses[2]))); delete_context(CONTEXT_COURSE, $testcourses[2]); $this->assertFalse($DB->record_exists('context', array('contextlevel' => CONTEXT_COURSE, 'instanceid' => $testcourses[2]))); $name = get_contextlevel_name(CONTEXT_COURSE); $this->assertFalse(empty($name)); $context = get_context_instance(CONTEXT_COURSE, $testcourses[2]); $name = print_context_name($context); $this->assertFalse(empty($name)); $url = get_context_url($coursecontext); $this->assertFalse($url instanceof modole_url); $page = $DB->get_record('page', array('id' => $testpages[7])); $context = get_context_instance(CONTEXT_MODULE, $page->id); $coursecontext = get_course_context($context); $this->assertEqual($coursecontext->contextlevel, CONTEXT_COURSE); $this->assertEqual(get_courseid_from_context($context), $page->course); $caps = fetch_context_capabilities($systemcontext); $this->assertTrue(is_array($caps)); unset($caps); }
/** * Retrieve course records with the course managers and other related records * that we need for print_course(). This allows print_courses() to do its job * in a constant number of DB queries, regardless of the number of courses, * role assignments, etc. * * The returned array is indexed on c.id, and each course will have * - $course->managers - array containing RA objects that include a $user obj * with the minimal fields needed for fullname() * * @deprecated since 2.5 * * To get list of all courses with course contacts ('managers') use * coursecat::get(0)->get_courses(array('recursive' => true, 'coursecontacts' => true)); * * To get list of courses inside particular category use * coursecat::get($id)->get_courses(array('coursecontacts' => true)); * * Additionally you can specify sort order, offset and maximum number of courses, * see {@link coursecat::get_courses()} * * Please note that code of this function is not changed to use coursecat class because * coursecat::get_courses() returns result in slightly different format. Also note that * get_courses_wmanagers() DOES NOT check that users are enrolled in the course and * coursecat::get_courses() does. * * @global object * @global object * @global object * @uses CONTEXT_COURSE * @uses CONTEXT_SYSTEM * @uses CONTEXT_COURSECAT * @uses SITEID * @param int|string $categoryid Either the categoryid for the courses or 'all' * @param string $sort A SQL sort field and direction * @param array $fields An array of additional fields to fetch * @return array */ function get_courses_wmanagers($categoryid = 0, $sort = "c.sortorder ASC", $fields = array()) { /* * The plan is to * * - Grab the courses JOINed w/context * * - Grab the interesting course-manager RAs * JOINed with a base user obj and add them to each course * * So as to do all the work in 2 DB queries. The RA+user JOIN * ends up being pretty expensive if it happens over _all_ * courses on a large site. (Are we surprised!?) * * So this should _never_ get called with 'all' on a large site. * */ global $USER, $CFG, $DB; debugging('Function get_courses_wmanagers() is deprecated, please use coursecat::get_courses()', DEBUG_DEVELOPER); $params = array(); $allcats = false; // bool flag if ($categoryid === 'all') { $categoryclause = ''; $allcats = true; } elseif (is_numeric($categoryid)) { $categoryclause = "c.category = :catid"; $params['catid'] = $categoryid; } else { debugging("Could not recognise categoryid = {$categoryid}"); $categoryclause = ''; } $basefields = array('id', 'category', 'sortorder', 'shortname', 'fullname', 'idnumber', 'startdate', 'visible', 'newsitems', 'groupmode', 'groupmodeforce'); if (!is_null($fields) && is_string($fields)) { if (empty($fields)) { $fields = $basefields; } else { // turn the fields from a string to an array that // get_user_courses_bycap() will like... $fields = explode(',', $fields); $fields = array_map('trim', $fields); $fields = array_unique(array_merge($basefields, $fields)); } } elseif (is_array($fields)) { $fields = array_merge($basefields, $fields); } $coursefields = 'c.' . join(',c.', $fields); if (empty($sort)) { $sortstatement = ""; } else { $sortstatement = "ORDER BY {$sort}"; } $where = 'WHERE c.id != ' . SITEID; if ($categoryclause !== '') { $where = "{$where} AND {$categoryclause}"; } // pull out all courses matching the cat list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT {$coursefields} {$ccselect}\n FROM {course} c\n {$ccjoin}\n {$where}\n {$sortstatement}"; $catpaths = array(); $catpath = NULL; if ($courses = $DB->get_records_sql($sql, $params)) { // loop on courses materialising // the context, and prepping data to fetch the // managers efficiently later... foreach ($courses as $k => $course) { context_helper::preload_from_record($course); $coursecontext = context_course::instance($course->id); $courses[$k] = $course; $courses[$k]->managers = array(); if ($allcats === false) { // single cat, so take just the first one... if ($catpath === NULL) { $catpath = preg_replace(':/\\d+$:', '', $coursecontext->path); } } else { // chop off the contextid of the course itself // like dirname() does... $catpaths[] = preg_replace(':/\\d+$:', '', $coursecontext->path); } } } else { return array(); // no courses! } $CFG->coursecontact = trim($CFG->coursecontact); if (empty($CFG->coursecontact)) { return $courses; } $managerroles = explode(',', $CFG->coursecontact); $catctxids = ''; if (count($managerroles)) { if ($allcats === true) { $catpaths = array_unique($catpaths); $ctxids = array(); foreach ($catpaths as $cpath) { $ctxids = array_merge($ctxids, explode('/', substr($cpath, 1))); } $ctxids = array_unique($ctxids); $catctxids = implode(',', $ctxids); unset($catpaths); unset($cpath); } else { // take the ctx path from the first course // as all categories will be the same... $catpath = substr($catpath, 1); $catpath = preg_replace(':/\\d+$:', '', $catpath); $catctxids = str_replace('/', ',', $catpath); } if ($categoryclause !== '') { $categoryclause = "AND {$categoryclause}"; } /* * Note: Here we use a LEFT OUTER JOIN that can * "optionally" match to avoid passing a ton of context * ids in an IN() clause. Perhaps a subselect is faster. * * In any case, this SQL is not-so-nice over large sets of * courses with no $categoryclause. * */ $sql = "SELECT ctx.path, ctx.instanceid, ctx.contextlevel,\n r.id AS roleid, r.name AS rolename, r.shortname AS roleshortname,\n rn.name AS rolecoursealias, u.id AS userid, u.firstname, u.lastname\n FROM {role_assignments} ra\n JOIN {context} ctx ON ra.contextid = ctx.id\n JOIN {user} u ON ra.userid = u.id\n JOIN {role} r ON ra.roleid = r.id\n LEFT JOIN {role_names} rn ON (rn.contextid = ctx.id AND rn.roleid = r.id)\n LEFT OUTER JOIN {course} c\n ON (ctx.instanceid=c.id AND ctx.contextlevel=" . CONTEXT_COURSE . ")\n WHERE ( c.id IS NOT NULL"; // under certain conditions, $catctxids is NULL if ($catctxids == NULL) { $sql .= ") "; } else { $sql .= " OR ra.contextid IN ({$catctxids}) )"; } $sql .= "AND ra.roleid IN ({$CFG->coursecontact})\n {$categoryclause}\n ORDER BY r.sortorder ASC, ctx.contextlevel ASC, ra.sortorder ASC"; $rs = $DB->get_recordset_sql($sql, $params); // This loop is fairly stupid as it stands - might get better // results doing an initial pass clustering RAs by path. foreach ($rs as $ra) { $user = new stdClass(); $user->id = $ra->userid; unset($ra->userid); $user->firstname = $ra->firstname; unset($ra->firstname); $user->lastname = $ra->lastname; unset($ra->lastname); $ra->user = $user; if ($ra->contextlevel == CONTEXT_SYSTEM) { foreach ($courses as $k => $course) { $courses[$k]->managers[] = $ra; } } else { if ($ra->contextlevel == CONTEXT_COURSECAT) { if ($allcats === false) { // It always applies foreach ($courses as $k => $course) { $courses[$k]->managers[] = $ra; } } else { foreach ($courses as $k => $course) { $coursecontext = context_course::instance($course->id); // Note that strpos() returns 0 as "matched at pos 0" if (strpos($coursecontext->path, $ra->path . '/') === 0) { // Only add it to subpaths $courses[$k]->managers[] = $ra; } } } } else { // course-level if (!array_key_exists($ra->instanceid, $courses)) { //this course is not in a list, probably a frontpage course continue; } $courses[$ra->instanceid]->managers[] = $ra; } } } $rs->close(); } return $courses; }
/** * Returns the default courses to display on the calendar when there isn't a specific * course to display. * * @return array $courses Array of courses to display */ function calendar_get_default_courses() { global $CFG, $DB; if (!isloggedin()) { return array(); } $courses = array(); if (!empty($CFG->calendar_adminseesall) && has_capability('moodle/calendar:manageentries', context_system::instance())) { list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT c.* {$select}\n FROM {course} c\n {$join}\n WHERE EXISTS (SELECT 1 FROM {event} e WHERE e.courseid = c.id)\n "; $courses = $DB->get_records_sql($sql, null, 0, 20); foreach ($courses as $course) { context_helper::preload_from_record($course); } return $courses; } $courses = enrol_get_my_courses(); return $courses; }
/** * * @global moodle_database $DB */ protected function get_searchsql() { global $DB; list($ctxselect, $ctxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx'); $params = array('namesearch' => '%' . $this->get_search() . '%'); $select = " SELECT c.id,c.name,c.visible,c.sortorder,c.description,c.descriptionformat "; $from = " FROM {course_categories} c "; $where = " WHERE " . $DB->sql_like('c.name', ':namesearch', false); $orderby = " ORDER BY c.sortorder"; return array($select . $ctxselect . $from . $ctxjoin . $where . $orderby, $params); }
/** * Get course participants details * * @param int $courseid course id * @param array $options options { * 'name' => option name * 'value' => option value * } * @return array An array of users */ public static function get_enrolled_users($courseid, $options = array()) { global $CFG, $USER, $DB; require_once $CFG->dirroot . "/user/lib.php"; $params = self::validate_parameters(self::get_enrolled_users_parameters(), array('courseid' => $courseid, 'options' => $options)); $withcapability = ''; $groupid = 0; $onlyactive = false; $userfields = array(); $limitfrom = 0; $limitnumber = 0; foreach ($options as $option) { switch ($option['name']) { case 'withcapability': $withcapability = $option['value']; break; case 'groupid': $groupid = (int) $option['value']; break; case 'onlyactive': $onlyactive = !empty($option['value']); break; case 'userfields': $thefields = explode(',', $option['value']); foreach ($thefields as $f) { $userfields[] = clean_param($f, PARAM_ALPHANUMEXT); } case 'limitfrom': $limitfrom = clean_param($option['value'], PARAM_INT); break; case 'limitnumber': $limitnumber = clean_param($option['value'], PARAM_INT); break; } } $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); $coursecontext = context_course::instance($courseid, IGNORE_MISSING); if ($courseid == SITEID) { $context = get_system_context(); } else { $context = $coursecontext; } try { self::validate_context($context); } catch (Exception $e) { $exceptionparam = new stdClass(); $exceptionparam->message = $e->getMessage(); $exceptionparam->courseid = $params['courseid']; throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam); } if ($courseid == SITEID) { require_capability('moodle/site:viewparticipants', $context); } else { require_capability('moodle/course:viewparticipants', $context); } // to overwrite this parameter, you need role:review capability if ($withcapability) { require_capability('moodle/role:review', $coursecontext); } // need accessallgroups capability if you want to overwrite this option if (!empty($groupid) && groups_is_member($groupid)) { require_capability('moodle/site:accessallgroups', $coursecontext); } // to overwrite this option, you need course:enrolereview permission if ($onlyactive) { require_capability('moodle/course:enrolreview', $coursecontext); } list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive); list($ctxselect, $ctxjoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx'); $sqlparams['courseid'] = $courseid; $sql = "SELECT u.* {$ctxselect}\n FROM {user} u {$ctxjoin}\n WHERE u.id IN ({$enrolledsql})\n ORDER BY u.id ASC"; $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber); $users = array(); foreach ($enrolledusers as $user) { context_instance_preload($user); if ($userdetails = user_get_user_details($user, $course, $userfields)) { $users[] = $userdetails; } } $enrolledusers->close(); return $users; }
/** * A list of courses that match a search * * @global object * @global object * @param array $searchterms An array of search criteria * @param string $sort A field and direction to sort by * @param int $page The page number to get * @param int $recordsperpage The number of records per page * @param int $totalcount Passed in by reference. * @return object {@link $COURSE} records */ function get_courses_search($searchterms, $sort, $page, $recordsperpage, &$totalcount) { global $CFG, $DB; if ($DB->sql_regex_supported()) { $REGEXP = $DB->sql_regex(true); $NOTREGEXP = $DB->sql_regex(false); } $searchcond = array(); $params = array(); $i = 0; // Thanks Oracle for your non-ansi concat and type limits in coalesce. MDL-29912 if ($DB->get_dbfamily() == 'oracle') { $concat = "(c.summary|| ' ' || c.fullname || ' ' || c.idnumber || ' ' || c.shortname)"; } else { $concat = $DB->sql_concat("COALESCE(c.summary, '')", "' '", 'c.fullname', "' '", 'c.idnumber', "' '", 'c.shortname'); } foreach ($searchterms as $searchterm) { $i++; $NOT = false; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle /// will use it to simulate the "-" operator with LIKE clause /// Under Oracle and MSSQL, trim the + and - operators and perform /// simpler LIKE (or NOT LIKE) queries if (!$DB->sql_regex_supported()) { if (substr($searchterm, 0, 1) == '-') { $NOT = true; } $searchterm = trim($searchterm, '+-'); } // TODO: +- may not work for non latin languages if (substr($searchterm, 0, 1) == '+') { $searchterm = trim($searchterm, '+-'); $searchterm = preg_quote($searchterm, '|'); $searchcond[] = "{$concat} {$REGEXP} :ss{$i}"; $params['ss' . $i] = "(^|[^a-zA-Z0-9]){$searchterm}([^a-zA-Z0-9]|\$)"; } else { if (substr($searchterm, 0, 1) == "-") { $searchterm = trim($searchterm, '+-'); $searchterm = preg_quote($searchterm, '|'); $searchcond[] = "{$concat} {$NOTREGEXP} :ss{$i}"; $params['ss' . $i] = "(^|[^a-zA-Z0-9]){$searchterm}([^a-zA-Z0-9]|\$)"; } else { $searchcond[] = $DB->sql_like($concat, ":ss{$i}", false, true, $NOT); $params['ss' . $i] = "%{$searchterm}%"; } } } if (empty($searchcond)) { $totalcount = 0; return array(); } $searchcond = implode(" AND ", $searchcond); $courses = array(); $c = 0; // counts how many visible courses we've seen // Tiki pagination $limitfrom = $page * $recordsperpage; $limitto = $limitfrom + $recordsperpage; list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $fields = array_diff(array_keys($DB->get_columns('course')), array('modinfo', 'sectioncache')); $sql = "SELECT c." . join(',c.', $fields) . " {$ccselect}\n FROM {course} c\n {$ccjoin}\n WHERE {$searchcond} AND c.id <> " . SITEID . "\n ORDER BY {$sort}"; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $course) { if (!$course->visible) { // preload contexts only for hidden courses or courses we need to return context_instance_preload($course); $coursecontext = context_course::instance($course->id); if (!has_capability('moodle/course:viewhiddencourses', $coursecontext)) { continue; } } // Don't exit this loop till the end // we need to count all the visible courses // to update $totalcount if ($c >= $limitfrom && $c < $limitto) { $courses[$course->id] = $course; } $c++; } $rs->close(); // our caller expects 2 bits of data - our return // array, and an updated $totalcount $totalcount = $c; return $courses; }
list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT c.* {$select} FROM {course} c\n {$join} JOIN {block_instances} bi ON bi.parentcontextid = ctx.id\n WHERE bi.blockname = ?"; $courses = $DB->get_records_sql($sql, array($blockname)); $totalcount = count($courses); // Keep only chunk of array which you want to display if ($totalcount > $perpage) { $courses = array_chunk($courses, $perpage, true); $courses = $courses[$page]; } foreach ($courses as $course) { $courses[$course->id] = $course; } } elseif (!empty($modulelist) and confirm_sesskey()) { // get list of courses containing modules $modulename = $modulelist; list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT c.* {$select} FROM {course} c {$join}\n WHERE c.id IN (SELECT DISTINCT cc.id FROM {" . $modulelist . "} module, {course} cc\n WHERE module.course = cc.id)"; $courselist = $DB->get_records_sql($sql); $courses = array(); if (!empty($courselist)) { $firstcourse = $page * $perpage; $lastcourse = $page * $perpage + $perpage - 1; $i = 0; foreach ($courselist as $course) { if ($i >= $firstcourse && $i <= $lastcourse) { $courses[$course->id] = $course; } $i++; } } $totalcount = count($courselist);
/** * This function generates a structured array of courses and categories. * * The depth of categories is limited by $CFG->maxcategorydepth however there * is no limit on the number of courses! * * Suitable for use with the course renderers course_category_tree method: * $renderer = $PAGE->get_renderer('core','course'); * echo $renderer->course_category_tree(get_course_category_tree()); * * @global moodle_database $DB * @param int $id * @param int $depth */ function get_course_category_tree($id = 0, $depth = 0) { global $DB, $CFG; $viewhiddencats = has_capability('moodle/category:viewhiddencategories', get_context_instance(CONTEXT_SYSTEM)); $categories = get_child_categories($id); $categoryids = array(); foreach ($categories as $key => &$category) { if (!$category->visible && !$viewhiddencats) { unset($categories[$key]); continue; } $categoryids[$category->id] = $category; if (empty($CFG->maxcategorydepth) || $depth <= $CFG->maxcategorydepth) { list($category->categories, $subcategories) = get_course_category_tree($category->id, $depth + 1); foreach ($subcategories as $subid => $subcat) { $categoryids[$subid] = $subcat; } $category->courses = array(); } } if ($depth > 0) { // This is a recursive call so return the required array return array($categories, $categoryids); } // The depth is 0 this function has just been called so we can finish it off list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); list($catsql, $catparams) = $DB->get_in_or_equal(array_keys($categoryids)); $sql = "SELECT\n c.id,c.sortorder,c.visible,c.fullname,c.shortname,c.summary,c.category\n {$ccselect}\n FROM {course} c\n {$ccjoin}\n WHERE c.category {$catsql} ORDER BY c.sortorder ASC"; if ($courses = $DB->get_records_sql($sql, $catparams)) { // loop throught them foreach ($courses as $course) { if ($course->id == SITEID) { continue; } context_instance_preload($course); if (!empty($course->visible) || has_capability('moodle/course:viewhiddencourses', get_context_instance(CONTEXT_COURSE, $course->id))) { $categoryids[$course->category]->courses[$course->id] = $course; } } } return $categories; }
/** * Returns list of courses user is enrolled into without any capability checks * - $fields is an array of fieldnames to ADD * so name the fields you really need, which will * be added and uniq'd * * @param int $userid * @param bool $onlyactive return only active enrolments in courses user may see * @param string|array $fields * @param string $sort * @return array */ function enrol_get_all_users_courses($userid, $categoryid, $cattype, $onlyactive = false, $fields = NULL, $sort = 'visible DESC,sortorder ASC') { global $DB; // Guest account does not have any courses if (isguestuser($userid) or empty($userid)) { return array(); } /** * summary field is added in $basefields - Kesavamoorthy - 20/02/2013 */ $basefields = array('id', 'category', 'sortorder', 'shortname', 'fullname', 'idnumber', 'startdate', 'visible', 'groupmode', 'groupmodeforce', 'summary'); if (empty($fields)) { $fields = $basefields; } else { if (is_string($fields)) { // turn the fields from a string to an array $fields = explode(',', $fields); $fields = array_map('trim', $fields); $fields = array_unique(array_merge($basefields, $fields)); } else { if (is_array($fields)) { $fields = array_unique(array_merge($basefields, $fields)); } else { throw new coding_exception('Invalid $fileds parameter in enrol_get_my_courses()'); } } } if (in_array('*', $fields)) { $fields = array('*'); } $orderby = ""; $sort = trim($sort); if (!empty($sort)) { $rawsorts = explode(',', $sort); $sorts = array(); foreach ($rawsorts as $rawsort) { $rawsort = trim($rawsort); if (strpos($rawsort, 'c.') === 0) { $rawsort = substr($rawsort, 2); } $sorts[] = trim($rawsort); } $sort = 'c.' . implode(',c.', $sorts); $orderby = "ORDER BY {$sort}"; } $params = array('siteid' => SITEID); if ($onlyactive) { $subwhere = "WHERE ue.status = :active AND e.status = :enabled AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)"; $params['now1'] = round(time(), -2); // improves db caching $params['now2'] = $params['now1']; $params['active'] = ENROL_USER_ACTIVE; $params['enabled'] = ENROL_INSTANCE_ENABLED; } else { $subwhere = ""; } $coursefields = 'c.' . join(',c.', $fields); list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); //note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why we have the subselect there if ($cattype == '') { $sql = "SELECT {$coursefields} {$ccselect}\n FROM {course} c\n JOIN (SELECT DISTINCT e.courseid\n FROM {enrol} e\n JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid)\n {$subwhere}\n ) en ON (en.courseid = c.id)\n {$ccjoin}\n WHERE c.id <> :siteid AND c.category = :categoryid\n {$orderby}"; } else { $sql = "SELECT {$coursefields}\n FROM {course} c\n \n WHERE c.id <> :siteid AND c.category = :categoryid\n {$orderby}"; } $params['userid'] = $userid; $params['categoryid'] = $categoryid; $courses = $DB->get_records_sql($sql, $params); return $courses; }
/** * Returns a sorted list of categories. Each category object has a context * property that is a context object. * * When asking for $parent='none' it will return all the categories, regardless * of depth. Wheen asking for a specific parent, the default is to return * a "shallow" resultset. Pass false to $shallow and it will return all * the child categories as well. * * @global object * @uses CONTEXT_COURSECAT * @param string $parent The parent category if any * @param string $sort the sortorder * @param bool $shallow - set to false to get the children too * @return array of categories */ function get_categories($parent = 'none', $sort = NULL, $shallow = true) { global $DB; if ($sort === NULL) { $sort = 'ORDER BY cc.sortorder ASC'; } elseif ($sort === '') { // leave it as empty } else { $sort = "ORDER BY {$sort}"; } list($ccselect, $ccjoin) = context_instance_preload_sql('cc.id', CONTEXT_COURSECAT, 'ctx'); if ($parent === 'none') { $sql = "SELECT cc.* {$ccselect}\n FROM {course_categories} cc\n {$ccjoin}\n {$sort}"; $params = array(); } elseif ($shallow) { $sql = "SELECT cc.* {$ccselect}\n FROM {course_categories} cc\n {$ccjoin}\n WHERE cc.parent=?\n {$sort}"; $params = array($parent); } else { $sql = "SELECT cc.* {$ccselect}\n FROM {course_categories} cc\n {$ccjoin}\n JOIN {course_categories} ccp\n ON ((cc.parent = ccp.id) OR (cc.path LIKE " . $DB->sql_concat('ccp.path', "'/%'") . "))\n WHERE ccp.id=?\n {$sort}"; $params = array($parent); } $categories = array(); $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $cat) { context_instance_preload($cat); $catcontext = get_context_instance(CONTEXT_COURSECAT, $cat->id); if ($cat->visible || has_capability('moodle/category:viewhiddencategories', $catcontext)) { $categories[$cat->id] = $cat; } } $rs->close(); return $categories; }
} else { $select = "SELECT u.id, u.username, u.firstname, u.lastname, u.email, u.city, u.country, u.picture, u.lang, u.timezone, u.maildisplay, u.imagealt, COALESCE(ul.timeaccess, 0) AS lastaccess$extrasql"; $joins[] = "JOIN ($esql) e ON e.id = u.id"; // course enrolled users only $joins[] = "LEFT JOIN {user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = :courseid)"; // not everybody accessed course yet $params['courseid'] = $course->id; if ($accesssince) { $wheres[] = get_course_lastaccess_sql($accesssince); } } // performance hacks - we preload user contexts together with accounts list($ccselect, $ccjoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx'); $select .= $ccselect; $joins[] = $ccjoin; // limit list to users with some role only if ($roleid) { $wheres[] = "u.id IN (SELECT userid FROM {role_assignments} WHERE roleid = :roleid AND contextid $contextlist)"; $params['roleid'] = $roleid; } $from = implode("\n", $joins); if ($wheres) { $where = "WHERE " . implode(" AND ", $wheres); } else { $where = "";
* @copyright 2011 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require '../../config.php'; require_once "{$CFG->dirroot}/enrol/locallib.php"; require_once "{$CFG->dirroot}/enrol/renderer.php"; $ueid = required_param('ue', PARAM_INT); // user enrolment id $filter = optional_param('ifilter', 0, PARAM_INT); $confirm = optional_param('confirm', false, PARAM_BOOL); // Get the user enrolment object $ue = $DB->get_record('user_enrolments', array('id' => $ueid), '*', MUST_EXIST); // Get the user for whom the enrolment is $user = $DB->get_record('user', array('id' => $ue->userid), '*', MUST_EXIST); // Get the course the enrolment is to list($ctxsql, $ctxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT c.* {$ctxsql}\n FROM {course} c\n LEFT JOIN {enrol} e ON e.courseid = c.id\n {$ctxjoin}\n WHERE e.id = :enrolid"; $params = array('enrolid' => $ue->enrolid); $course = $DB->get_record_sql($sql, $params, MUST_EXIST); context_instance_preload($course); if ($course->id == SITEID) { redirect(new moodle_url('/')); } require_login($course); require_capability("enrol/globalclassroom:unenrol", get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST)); $manager = new course_enrolment_manager($PAGE, $course, $filter); $table = new course_enrolment_users_table($manager, $PAGE); // The URL of the enrolled users page for the course. $usersurl = new moodle_url('/enrol/users.php', array('id' => $course->id)); // The URl to return the user too after this screen. $returnurl = new moodle_url($usersurl, $manager->get_url_params() + $table->get_url_params());
/** * Get course participant's details * * @param array $userlist array of user ids and according course ids * @return array An array of arrays describing course participants * @since Moodle 2.2 */ public static function get_course_user_profiles($userlist) { global $CFG, $USER, $DB; require_once $CFG->dirroot . "/user/lib.php"; $params = self::validate_parameters(self::get_course_user_profiles_parameters(), array('userlist' => $userlist)); $userids = array(); $courseids = array(); foreach ($params['userlist'] as $value) { $userids[] = $value['userid']; $courseids[$value['userid']] = $value['courseid']; } // cache all courses $courses = array(); list($cselect, $cjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); list($sqlcourseids, $params) = $DB->get_in_or_equal(array_unique($courseids)); $coursesql = "SELECT c.* {$cselect}\n FROM {course} c {$cjoin}\n WHERE c.id {$sqlcourseids}"; $rs = $DB->get_recordset_sql($coursesql, $params); foreach ($rs as $course) { // adding course contexts to cache context_instance_preload($course); // cache courses $courses[$course->id] = $course; } $rs->close(); list($uselect, $ujoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx'); list($sqluserids, $params) = $DB->get_in_or_equal($userids); $usersql = "SELECT u.* {$uselect}\n FROM {user} u {$ujoin}\n WHERE u.id {$sqluserids}"; $users = $DB->get_recordset_sql($usersql, $params); $result = array(); foreach ($users as $user) { if (!empty($user->deleted)) { continue; } context_instance_preload($user); $course = $courses[$courseids[$user->id]]; $context = context_course::instance($courseids[$user->id], IGNORE_MISSING); self::validate_context($context); if ($userarray = user_get_user_details($user, $course)) { $result[] = $userarray; } } $users->close(); return $result; }
/** * Loads the courses in Moodle into the navigation. * * @global moodle_database $DB * @param string|array $categoryids An array containing categories to load courses * for, OR null to load courses for all categories. * @return array An array of navigation_nodes one for each course */ protected function load_all_courses($categoryids = null) { global $CFG, $DB, $SITE; // Work out the limit of courses. $limit = 20; if (!empty($CFG->navcourselimit)) { $limit = $CFG->navcourselimit; } $toload = empty($CFG->navshowallcourses) ? self::LOAD_ROOT_CATEGORIES : self::LOAD_ALL_CATEGORIES; // If we are going to show all courses AND we are showing categories then // to save us repeated DB calls load all of the categories now if ($this->show_categories()) { $this->load_all_categories($toload); } // Will be the return of our efforts $coursenodes = array(); // Check if we need to show categories. if ($this->show_categories()) { // Hmmm we need to show categories... this is going to be painful. // We now need to fetch up to $limit courses for each category to // be displayed. if ($categoryids !== null) { if (!is_array($categoryids)) { $categoryids = array($categoryids); } list($categorywhere, $categoryparams) = $DB->get_in_or_equal($categoryids, SQL_PARAMS_NAMED, 'cc'); $categorywhere = 'WHERE cc.id ' . $categorywhere; } else { if ($toload == self::LOAD_ROOT_CATEGORIES) { $categorywhere = 'WHERE cc.depth = 1 OR cc.depth = 2'; $categoryparams = array(); } else { $categorywhere = ''; $categoryparams = array(); } } // First up we are going to get the categories that we are going to // need so that we can determine how best to load the courses from them. $sql = "SELECT cc.id, COUNT(c.id) AS coursecount\n FROM {course_categories} cc\n LEFT JOIN {course} c ON c.category = cc.id\n {$categorywhere}\n GROUP BY cc.id"; $categories = $DB->get_recordset_sql($sql, $categoryparams); $fullfetch = array(); $partfetch = array(); foreach ($categories as $category) { if (!$this->can_add_more_courses_to_category($category->id)) { continue; } if ($category->coursecount > $limit * 5) { $partfetch[] = $category->id; } else { if ($category->coursecount > 0) { $fullfetch[] = $category->id; } } } $categories->close(); if (count($fullfetch)) { // First up fetch all of the courses in categories where we know that we are going to // need the majority of courses. list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); list($categoryids, $categoryparams) = $DB->get_in_or_equal($fullfetch, SQL_PARAMS_NAMED, 'lcategory'); $sql = "SELECT c.id, c.sortorder, c.visible, c.fullname, c.shortname, c.category {$ccselect}\n FROM {course} c\n {$ccjoin}\n WHERE c.category {$categoryids}\n ORDER BY c.sortorder ASC"; $coursesrs = $DB->get_recordset_sql($sql, $categoryparams); foreach ($coursesrs as $course) { if ($course->id == $SITE->id) { // This should not be necessary, frontpage is not in any category. continue; } if (array_key_exists($course->id, $this->addedcourses)) { // It is probably better to not include the already loaded courses // directly in SQL because inequalities may confuse query optimisers // and may interfere with query caching. continue; } if (!$this->can_add_more_courses_to_category($course->category)) { continue; } context_instance_preload($course); if (!$course->visible && !is_role_switched($course->id) && !has_capability('moodle/course:viewhiddencourses', get_context_instance(CONTEXT_COURSE, $course->id))) { continue; } $coursenodes[$course->id] = $this->add_course($course); } $coursesrs->close(); } if (count($partfetch)) { // Next we will work our way through the categories where we will likely only need a small // proportion of the courses. foreach ($partfetch as $categoryid) { list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT c.id, c.sortorder, c.visible, c.fullname, c.shortname, c.category {$ccselect}\n FROM {course} c\n {$ccjoin}\n WHERE c.category = :categoryid\n ORDER BY c.sortorder ASC"; $courseparams = array('categoryid' => $categoryid); $coursesrs = $DB->get_recordset_sql($sql, $courseparams, 0, $limit * 5); foreach ($coursesrs as $course) { if ($course->id == $SITE->id) { // This should not be necessary, frontpage is not in any category. continue; } if (array_key_exists($course->id, $this->addedcourses)) { // It is probably better to not include the already loaded courses // directly in SQL because inequalities may confuse query optimisers // and may interfere with query caching. // This also helps to respect expected $limit on repeated executions. continue; } if (!$this->can_add_more_courses_to_category($course->category)) { break; } context_instance_preload($course); if (!$course->visible && !is_role_switched($course->id) && !has_capability('moodle/course:viewhiddencourses', get_context_instance(CONTEXT_COURSE, $course->id))) { continue; } $coursenodes[$course->id] = $this->add_course($course); } $coursesrs->close(); } } } else { // Prepare the SQL to load the courses and their contexts list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); list($courseids, $courseparams) = $DB->get_in_or_equal(array_keys($this->addedcourses), SQL_PARAMS_NAMED, 'lc', false); $sql = "SELECT c.id, c.sortorder, c.visible, c.fullname, c.shortname, c.category {$ccselect}\n FROM {course} c\n {$ccjoin}\n WHERE c.id {$courseids}\n ORDER BY c.sortorder ASC"; $coursesrs = $DB->get_recordset_sql($sql, $courseparams); foreach ($coursesrs as $course) { if ($course->id == $SITE->id) { // frotpage is not wanted here continue; } context_instance_preload($course); if (!$course->visible && !is_role_switched($course->id) && !has_capability('moodle/course:viewhiddencourses', get_context_instance(CONTEXT_COURSE, $course->id))) { continue; } $coursenodes[$course->id] = $this->add_course($course); if (count($coursenodes) >= $limit) { break; } } $coursesrs->close(); } return $coursenodes; }
/** * Returns the default courses to display on the calendar when there isn't a specific * course to display. * * @return array $courses Array of courses to display */ function calendar_get_default_courses() { global $CFG, $DB; if (!isloggedin()) { return array(); } $courses = array(); if (!empty($CFG->calendar_adminseesall) && has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_SYSTEM))) { list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $sql = "SELECT DISTINCT c.* {$select}\n FROM {course} c\n JOIN {event} e ON e.courseid = c.id\n {$join}"; $courses = $DB->get_records_sql($sql, null, 0, 20); foreach ($courses as $course) { context_instance_preload($course); } return $courses; } $courses = enrol_get_my_courses(); return $courses; }