Exemple #1
0
/**
 * This function will empty a course of user data.
 * It will retain the activities and the structure of the course.
 * @param object $data an object containing all the settings including courseid (without magic quotes)
 * @return array status array of array component, item, error
 */
function reset_course_userdata($data)
{
    global $CFG, $USER;
    require_once $CFG->libdir . '/gradelib.php';
    require_once $CFG->dirroot . '/group/lib.php';
    $data->courseid = $data->id;
    $context = get_context_instance(CONTEXT_COURSE, $data->courseid);
    // calculate the time shift of dates
    if (!empty($data->reset_start_date)) {
        // time part of course startdate should be zero
        $data->timeshift = $data->reset_start_date - usergetmidnight($data->reset_start_date_old);
    } else {
        $data->timeshift = 0;
    }
    // result array: component, item, error
    $status = array();
    // start the resetting
    $componentstr = get_string('general');
    // move the course start time
    if (!empty($data->reset_start_date) and $data->timeshift) {
        // change course start data
        set_field('course', 'startdate', $data->reset_start_date, 'id', $data->courseid);
        // update all course and group events - do not move activity events
        $updatesql = "UPDATE {$CFG->prefix}event\n                         SET timestart = timestart + ({$data->timeshift})\n                       WHERE courseid={$data->courseid} AND instance=0";
        execute_sql($updatesql, false);
        $status[] = array('component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false);
    }
    if (!empty($data->reset_logs)) {
        delete_records('log', 'course', $data->courseid);
        $status[] = array('component' => $componentstr, 'item' => get_string('deletelogs'), 'error' => false);
    }
    if (!empty($data->reset_events)) {
        delete_records('event', 'courseid', $data->courseid);
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteevents', 'calendar'), 'error' => false);
    }
    if (!empty($data->reset_notes)) {
        require_once $CFG->dirroot . '/notes/lib.php';
        note_delete_all($data->courseid);
        $status[] = array('component' => $componentstr, 'item' => get_string('deletenotes', 'notes'), 'error' => false);
    }
    $componentstr = get_string('roles');
    if (!empty($data->reset_roles_overrides)) {
        $children = get_child_contexts($context);
        foreach ($children as $child) {
            delete_records('role_capabilities', 'contextid', $child->id);
        }
        delete_records('role_capabilities', 'contextid', $context->id);
        //force refresh for logged in users
        mark_context_dirty($context->path);
        $status[] = array('component' => $componentstr, 'item' => get_string('deletecourseoverrides', 'role'), 'error' => false);
    }
    if (!empty($data->reset_roles_local)) {
        $children = get_child_contexts($context);
        foreach ($children as $child) {
            role_unassign(0, 0, 0, $child->id);
        }
        //force refresh for logged in users
        mark_context_dirty($context->path);
        $status[] = array('component' => $componentstr, 'item' => get_string('deletelocalroles', 'role'), 'error' => false);
    }
    // First unenrol users - this cleans some of related user data too, such as forum subscriptions, tracking, etc.
    $data->unenrolled = array();
    if (!empty($data->reset_roles)) {
        foreach ($data->reset_roles as $roleid) {
            if ($users = get_role_users($roleid, $context, false, 'u.id', 'u.id ASC')) {
                foreach ($users as $user) {
                    role_unassign($roleid, $user->id, 0, $context->id);
                    if (!has_capability('moodle/course:view', $context, $user->id)) {
                        $data->unenrolled[$user->id] = $user->id;
                    }
                }
            }
        }
    }
    if (!empty($data->unenrolled)) {
        $status[] = array('component' => $componentstr, 'item' => get_string('unenrol') . ' (' . count($data->unenrolled) . ')', 'error' => false);
    }
    $componentstr = get_string('groups');
    // remove all group members
    if (!empty($data->reset_groups_members)) {
        groups_delete_group_members($data->courseid);
        $status[] = array('component' => $componentstr, 'item' => get_string('removegroupsmembers', 'group'), 'error' => false);
    }
    // remove all groups
    if (!empty($data->reset_groups_remove)) {
        groups_delete_groups($data->courseid, false);
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroups', 'group'), 'error' => false);
    }
    // remove all grouping members
    if (!empty($data->reset_groupings_members)) {
        groups_delete_groupings_groups($data->courseid, false);
        $status[] = array('component' => $componentstr, 'item' => get_string('removegroupingsmembers', 'group'), 'error' => false);
    }
    // remove all groupings
    if (!empty($data->reset_groupings_remove)) {
        groups_delete_groupings($data->courseid, false);
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroupings', 'group'), 'error' => false);
    }
    // Look in every instance of every module for data to delete
    $unsupported_mods = array();
    if ($allmods = get_records('modules')) {
        foreach ($allmods as $mod) {
            $modname = $mod->name;
            if (!count_records($modname, 'course', $data->courseid)) {
                continue;
                // skip mods with no instances
            }
            $modfile = $CFG->dirroot . '/mod/' . $modname . '/lib.php';
            $moddeleteuserdata = $modname . '_reset_userdata';
            // Function to delete user data
            if (file_exists($modfile)) {
                include_once $modfile;
                if (function_exists($moddeleteuserdata)) {
                    $modstatus = $moddeleteuserdata($data);
                    if (is_array($modstatus)) {
                        $status = array_merge($status, $modstatus);
                    } else {
                        debugging('Module ' . $modname . ' returned incorrect staus - must be an array!');
                    }
                } else {
                    $unsupported_mods[] = $mod;
                }
            } else {
                debugging('Missing lib.php in ' . $modname . ' module!');
            }
        }
    }
    // mention unsupported mods
    if (!empty($unsupported_mods)) {
        foreach ($unsupported_mods as $mod) {
            $status[] = array('component' => get_string('modulenameplural', $mod->name), 'item' => '', 'error' => get_string('resetnotimplemented'));
        }
    }
    $componentstr = get_string('gradebook', 'grades');
    // reset gradebook
    if (!empty($data->reset_gradebook_items)) {
        remove_course_grades($data->courseid, false);
        grade_grab_course_grades($data->courseid);
        grade_regrade_final_grades($data->courseid);
        $status[] = array('component' => $componentstr, 'item' => get_string('removeallcourseitems', 'grades'), 'error' => false);
    } else {
        if (!empty($data->reset_gradebook_grades)) {
            grade_course_reset($data->courseid);
            $status[] = array('component' => $componentstr, 'item' => get_string('removeallcoursegrades', 'grades'), 'error' => false);
        }
    }
    return $status;
}
Exemple #2
0
    /**
     * 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);
    }
function get_role_context_caps($roleid, $context)
{
    global $DB;
    //this is really slow!!!! - do not use above course context level!
    $result = array();
    $result[$context->id] = array();
    // first emulate the parent context capabilities merging into context
    $searchcontexts = array_reverse(get_parent_contexts($context));
    array_push($searchcontexts, $context->id);
    foreach ($searchcontexts as $cid) {
        if ($capabilities = $DB->get_records('role_capabilities', array('roleid' => $roleid, 'contextid' => $cid))) {
            foreach ($capabilities as $cap) {
                if (!array_key_exists($cap->capability, $result[$context->id])) {
                    $result[$context->id][$cap->capability] = 0;
                }
                $result[$context->id][$cap->capability] += $cap->permission;
            }
        }
    }
    // now go through the contexts bellow given context
    $searchcontexts = array_keys(get_child_contexts($context));
    foreach ($searchcontexts as $cid) {
        if ($capabilities = $DB->get_records('role_capabilities', array('roleid' => $roleid, 'contextid' => $cid))) {
            foreach ($capabilities as $cap) {
                if (!array_key_exists($cap->contextid, $result)) {
                    $result[$cap->contextid] = array();
                }
                $result[$cap->contextid][$cap->capability] = $cap->permission;
            }
        }
    }
    return $result;
}
Exemple #4
0
/**
 * This function will empty a course of user data.
 * It will retain the activities and the structure of the course.
 *
 * @param object $data an object containing all the settings including courseid (without magic quotes)
 * @return array status array of array component, item, error
 */
function reset_course_userdata($data)
{
    global $CFG, $USER, $DB;
    require_once $CFG->libdir . '/gradelib.php';
    require_once $CFG->libdir . '/completionlib.php';
    require_once $CFG->dirroot . '/group/lib.php';
    $data->courseid = $data->id;
    $context = get_context_instance(CONTEXT_COURSE, $data->courseid);
    // calculate the time shift of dates
    if (!empty($data->reset_start_date)) {
        // time part of course startdate should be zero
        $data->timeshift = $data->reset_start_date - usergetmidnight($data->reset_start_date_old);
    } else {
        $data->timeshift = 0;
    }
    // result array: component, item, error
    $status = array();
    // start the resetting
    $componentstr = get_string('general');
    // move the course start time
    if (!empty($data->reset_start_date) and $data->timeshift) {
        // change course start data
        $DB->set_field('course', 'startdate', $data->reset_start_date, array('id' => $data->courseid));
        // update all course and group events - do not move activity events
        $updatesql = "UPDATE {event}\n                         SET timestart = timestart + ?\n                       WHERE courseid=? AND instance=0";
        $DB->execute($updatesql, array($data->timeshift, $data->courseid));
        $status[] = array('component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false);
    }
    if (!empty($data->reset_logs)) {
        $DB->delete_records('log', array('course' => $data->courseid));
        $status[] = array('component' => $componentstr, 'item' => get_string('deletelogs'), 'error' => false);
    }
    if (!empty($data->reset_events)) {
        $DB->delete_records('event', array('courseid' => $data->courseid));
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteevents', 'calendar'), 'error' => false);
    }
    if (!empty($data->reset_notes)) {
        require_once $CFG->dirroot . '/notes/lib.php';
        note_delete_all($data->courseid);
        $status[] = array('component' => $componentstr, 'item' => get_string('deletenotes', 'notes'), 'error' => false);
    }
    if (!empty($data->delete_blog_associations)) {
        require_once $CFG->dirroot . '/blog/lib.php';
        blog_remove_associations_for_course($data->courseid);
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteblogassociations', 'blog'), 'error' => false);
    }
    if (!empty($data->reset_course_completion)) {
        // Delete course completion information
        $course = $DB->get_record('course', array('id' => $data->courseid));
        $cc = new completion_info($course);
        $cc->delete_course_completion_data();
        $status[] = array('component' => $componentstr, 'item' => get_string('deletecoursecompletiondata', 'completion'), 'error' => false);
    }
    $componentstr = get_string('roles');
    if (!empty($data->reset_roles_overrides)) {
        $children = get_child_contexts($context);
        foreach ($children as $child) {
            $DB->delete_records('role_capabilities', array('contextid' => $child->id));
        }
        $DB->delete_records('role_capabilities', array('contextid' => $context->id));
        //force refresh for logged in users
        mark_context_dirty($context->path);
        $status[] = array('component' => $componentstr, 'item' => get_string('deletecourseoverrides', 'role'), 'error' => false);
    }
    if (!empty($data->reset_roles_local)) {
        $children = get_child_contexts($context);
        foreach ($children as $child) {
            role_unassign_all(array('contextid' => $child->id));
        }
        //force refresh for logged in users
        mark_context_dirty($context->path);
        $status[] = array('component' => $componentstr, 'item' => get_string('deletelocalroles', 'role'), 'error' => false);
    }
    // First unenrol users - this cleans some of related user data too, such as forum subscriptions, tracking, etc.
    $data->unenrolled = array();
    if (!empty($data->unenrol_users)) {
        $plugins = enrol_get_plugins(true);
        $instances = enrol_get_instances($data->courseid, true);
        foreach ($instances as $key => $instance) {
            if (!isset($plugins[$instance->enrol])) {
                unset($instances[$key]);
                continue;
            }
            if (!$plugins[$instance->enrol]->allow_unenrol($instance)) {
                unset($instances[$key]);
            }
        }
        $sqlempty = $DB->sql_empty();
        foreach ($data->unenrol_users as $withroleid) {
            $sql = "SELECT DISTINCT ue.userid, ue.enrolid\n                      FROM {user_enrolments} ue\n                      JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)\n                      JOIN {context} c ON (c.contextlevel = :courselevel AND c.instanceid = e.courseid)\n                      JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.roleid = :roleid AND ra.userid = ue.userid)";
            $params = array('courseid' => $data->courseid, 'roleid' => $withroleid, 'courselevel' => CONTEXT_COURSE);
            $rs = $DB->get_recordset_sql($sql, $params);
            foreach ($rs as $ue) {
                if (!isset($instances[$ue->enrolid])) {
                    continue;
                }
                $plugins[$instances[$ue->enrolid]->enrol]->unenrol_user($instances[$ue->enrolid], $ue->userid);
                $data->unenrolled[$ue->userid] = $ue->userid;
            }
        }
    }
    if (!empty($data->unenrolled)) {
        $status[] = array('component' => $componentstr, 'item' => get_string('unenrol', 'enrol') . ' (' . count($data->unenrolled) . ')', 'error' => false);
    }
    $componentstr = get_string('groups');
    // remove all group members
    if (!empty($data->reset_groups_members)) {
        groups_delete_group_members($data->courseid);
        $status[] = array('component' => $componentstr, 'item' => get_string('removegroupsmembers', 'group'), 'error' => false);
    }
    // remove all groups
    if (!empty($data->reset_groups_remove)) {
        groups_delete_groups($data->courseid, false);
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroups', 'group'), 'error' => false);
    }
    // remove all grouping members
    if (!empty($data->reset_groupings_members)) {
        groups_delete_groupings_groups($data->courseid, false);
        $status[] = array('component' => $componentstr, 'item' => get_string('removegroupingsmembers', 'group'), 'error' => false);
    }
    // remove all groupings
    if (!empty($data->reset_groupings_remove)) {
        groups_delete_groupings($data->courseid, false);
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroupings', 'group'), 'error' => false);
    }
    // Look in every instance of every module for data to delete
    $unsupported_mods = array();
    if ($allmods = $DB->get_records('modules')) {
        foreach ($allmods as $mod) {
            $modname = $mod->name;
            if (!$DB->count_records($modname, array('course' => $data->courseid))) {
                continue;
                // skip mods with no instances
            }
            $modfile = $CFG->dirroot . '/mod/' . $modname . '/lib.php';
            $moddeleteuserdata = $modname . '_reset_userdata';
            // Function to delete user data
            if (file_exists($modfile)) {
                include_once $modfile;
                if (function_exists($moddeleteuserdata)) {
                    $modstatus = $moddeleteuserdata($data);
                    if (is_array($modstatus)) {
                        $status = array_merge($status, $modstatus);
                    } else {
                        debugging('Module ' . $modname . ' returned incorrect staus - must be an array!');
                    }
                } else {
                    $unsupported_mods[] = $mod;
                }
            } else {
                debugging('Missing lib.php in ' . $modname . ' module!');
            }
        }
    }
    // mention unsupported mods
    if (!empty($unsupported_mods)) {
        foreach ($unsupported_mods as $mod) {
            $status[] = array('component' => get_string('modulenameplural', $mod->name), 'item' => '', 'error' => get_string('resetnotimplemented'));
        }
    }
    $componentstr = get_string('gradebook', 'grades');
    // reset gradebook
    if (!empty($data->reset_gradebook_items)) {
        remove_course_grades($data->courseid, false);
        grade_grab_course_grades($data->courseid);
        grade_regrade_final_grades($data->courseid);
        $status[] = array('component' => $componentstr, 'item' => get_string('removeallcourseitems', 'grades'), 'error' => false);
    } else {
        if (!empty($data->reset_gradebook_grades)) {
            grade_course_reset($data->courseid);
            $status[] = array('component' => $componentstr, 'item' => get_string('removeallcoursegrades', 'grades'), 'error' => false);
        }
    }
    // reset comments
    if (!empty($data->reset_comments)) {
        require_once $CFG->dirroot . '/comment/lib.php';
        comment::reset_course_page_comments($context);
    }
    return $status;
}
/**
 * Removes multiple role assignments, parameters may contain:
 *   'roleid', 'userid', 'contextid', 'component', 'enrolid'.
 *
 * @param array $params role assignment parameters
 * @param bool $subcontexts unassign in subcontexts too
 * @param bool $includmanual include manual role assignments too
 * @return void
 */
function role_unassign_all(array $params, $subcontexts = false, $includemanual = false)
{
    global $USER, $CFG, $DB;
    if (!$params) {
        throw new coding_exception('Missing parameters in role_unsassign_all() call');
    }
    $allowed = array('roleid', 'userid', 'contextid', 'component', 'itemid');
    foreach ($params as $key => $value) {
        if (!in_array($key, $allowed)) {
            throw new coding_exception('Unknown role_unsassign_all() parameter key', 'key:' . $key);
        }
    }
    if (isset($params['component']) and $params['component'] !== '' and strpos($params['component'], '_') === false) {
        throw new coding_exception('Invalid component paramter in role_unsassign_all() call', 'component:' . $params['component']);
    }
    if ($includemanual) {
        if (!isset($params['component']) or $params['component'] === '') {
            throw new coding_exception('include manual parameter requires component parameter in role_unsassign_all() call');
        }
    }
    if ($subcontexts) {
        if (empty($params['contextid'])) {
            throw new coding_exception('subcontexts paramtere requires component parameter in role_unsassign_all() call');
        }
    }
    $ras = $DB->get_records('role_assignments', $params);
    foreach ($ras as $ra) {
        $DB->delete_records('role_assignments', array('id' => $ra->id));
        if ($context = get_context_instance_by_id($ra->contextid)) {
            // this is a bit expensive but necessary
            mark_context_dirty($context->path);
            /// If the user is the current user, then do full reload of capabilities too.
            if (!empty($USER->id) && $USER->id == $ra->userid) {
                load_all_capabilities();
            }
        }
        events_trigger('role_unassigned', $ra);
    }
    unset($ras);
    // process subcontexts
    if ($subcontexts and $context = get_context_instance_by_id($params['contextid'])) {
        $contexts = get_child_contexts($context);
        $mparams = $params;
        foreach ($contexts as $context) {
            $mparams['contextid'] = $context->id;
            $ras = $DB->get_records('role_assignments', $mparams);
            foreach ($ras as $ra) {
                $DB->delete_records('role_assignments', array('id' => $ra->id));
                // this is a bit expensive but necessary
                mark_context_dirty($context->path);
                /// If the user is the current user, then do full reload of capabilities too.
                if (!empty($USER->id) && $USER->id == $ra->userid) {
                    load_all_capabilities();
                }
                events_trigger('role_unassigned', $ra);
            }
        }
    }
    // do this once more for all manual role assignments
    if ($includemanual) {
        $params['component'] = '';
        role_unassign_all($params, $subcontexts, false);
    }
}
Exemple #6
0
 /**
  * Delete page_comments in whole course, used by course reset
  *
  * @param stdClass $context course context
  */
 public static function reset_course_page_comments($context) {
     global $DB;
     $contexts = array();
     $contexts[] = $context->id;
     $children = get_child_contexts($context);
     foreach ($children as $c) {
         $contexts[] = $c->id;
     }
     list($ids, $params) = $DB->get_in_or_equal($contexts);
     $DB->delete_records_select('comments', "commentarea='page_comments' AND contextid $ids", $params);
 }
Exemple #7
0
 function init_full()
 {
     global $COURSE;
     if ($this->full_init_done) {
         return;
     }
     if (empty($this->id)) {
         $this->id = 0;
         // avoid db errors
     }
     if ($this->id == $COURSE->id) {
         $this->courserecord = $COURSE;
     } else {
         $this->courserecord = get_record('course', 'id', $this->id);
     }
     if (empty($this->courserecord) && !defined('ADMIN_STICKYBLOCKS')) {
         error('Cannot fully initialize page: invalid course id ' . $this->id);
     }
     $this->context = get_context_instance(CONTEXT_COURSE, $this->id);
     // Preload - ensures that the context cache is populated
     // in one DB query...
     $this->childcontexts = get_child_contexts($this->context);
     // Mark we're done
     $this->full_init_done = true;
 }
 /**
  * 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);
 }
Exemple #9
0
/**
 * Recursive function which, given a context, find all its children context ids.
 * @param object $context.
 * @return array of children context ids.
 */
function get_child_contexts($context)
{
    global $CFG;
    $children = array();
    switch ($context->contextlevel) {
        case CONTEXT_BLOCK:
            // No children.
            return array();
            break;
        case CONTEXT_MODULE:
            // No children.
            return array();
            break;
        case CONTEXT_GROUP:
            // No children.
            return array();
            break;
        case CONTEXT_COURSE:
            // Find all block instances for the course.
            $page = new page_course();
            $page->id = $context->instanceid;
            $page->type = 'course-view';
            if ($blocks = blocks_get_by_page_pinned($page)) {
                foreach ($blocks['l'] as $leftblock) {
                    if ($child = get_context_instance(CONTEXT_BLOCK, $leftblock->id)) {
                        array_push($children, $child->id);
                    }
                }
                foreach ($blocks['r'] as $rightblock) {
                    if ($child = get_context_instance(CONTEXT_BLOCK, $rightblock->id)) {
                        array_push($children, $child->id);
                    }
                }
            }
            // Find all module instances for the course.
            if ($modules = get_records('course_modules', 'course', $context->instanceid)) {
                foreach ($modules as $module) {
                    if ($child = get_context_instance(CONTEXT_MODULE, $module->id)) {
                        array_push($children, $child->id);
                    }
                }
            }
            // Find all group instances for the course.
            if ($groupids = groups_get_groups($context->instanceid)) {
                foreach ($groupids as $groupid) {
                    if ($child = get_context_instance(CONTEXT_GROUP, $groupid)) {
                        array_push($children, $child->id);
                    }
                }
            }
            return $children;
            break;
        case CONTEXT_COURSECAT:
            // We need to get the contexts for:
            //   1) The subcategories of the given category
            //   2) The courses in the given category and all its subcategories
            //   3) All the child contexts for these courses
            $categories = get_all_subcategories($context->instanceid);
            // Add the contexts for all the subcategories.
            foreach ($categories as $catid) {
                if ($catci = get_context_instance(CONTEXT_COURSECAT, $catid)) {
                    array_push($children, $catci->id);
                }
            }
            // Add the parent category as well so we can find the contexts
            // for its courses.
            array_unshift($categories, $context->instanceid);
            foreach ($categories as $catid) {
                // Find all courses for the category.
                if ($courses = get_records('course', 'category', $catid)) {
                    foreach ($courses as $course) {
                        if ($courseci = get_context_instance(CONTEXT_COURSE, $course->id)) {
                            array_push($children, $courseci->id);
                            $children = array_merge($children, get_child_contexts($courseci));
                        }
                    }
                }
            }
            return $children;
            break;
        case CONTEXT_USER:
            // No children.
            return array();
            break;
        case CONTEXT_PERSONAL:
            // No children.
            return array();
            break;
        case CONTEXT_SYSTEM:
            // Just get all the contexts except for CONTEXT_SYSTEM level.
            $sql = 'SELECT c.id ' . 'FROM ' . $CFG->prefix . 'context AS c ' . 'WHERE contextlevel != ' . CONTEXT_SYSTEM;
            $contexts = get_records_sql($sql);
            foreach ($contexts as $cid) {
                array_push($children, $cid->id);
            }
            return $children;
            break;
        default:
            error('This is an unknown context (' . $context->contextlevel . ') in get_child_contexts!');
            return false;
    }
}