Example #1
0
    /**
     * If dynamic data for this course-module is not yet available, gets it.
     *
     * This function is automatically called when requesting any course_modinfo property
     * that can be modified by modules (have a set_xxx method).
     *
     * Dynamic data is data which does not come directly from the cache but is calculated at
     * runtime based on the current user. Primarily this concerns whether the user can access
     * the module or not.
     *
     * As part of this function, the module's _cm_info_dynamic function from its lib.php will
     * be called (if it exists).
     * @return void
     */
    private function obtain_dynamic_data() {
        global $CFG;
        $userid = $this->modinfo->get_user_id();
        if ($this->state >= self::STATE_BUILDING_DYNAMIC || $userid == -1) {
            return;
        }
        $this->state = self::STATE_BUILDING_DYNAMIC;

        if (!empty($CFG->enableavailability)) {
            require_once($CFG->libdir. '/conditionlib.php');
            // Get availability information
            $ci = new condition_info($this);
            // Note that the modinfo currently available only includes minimal details (basic data)
            // but we know that this function does not need anything more than basic data.
            $this->available = $ci->is_available($this->availableinfo, true,
                    $userid, $this->modinfo);

            // Check parent section
            $parentsection = $this->modinfo->get_section_info($this->sectionnum);
            if (!$parentsection->available) {
                // Do not store info from section here, as that is already
                // presented from the section (if appropriate) - just change
                // the flag
                $this->available = false;
            }
        } else {
            $this->available = true;
        }

        // Update visible state for current user
        $this->update_user_visible();

        // Let module make dynamic changes at this point
        $this->call_mod_function('cm_info_dynamic');
        $this->state = self::STATE_DYNAMIC;
    }
Example #2
0
/**
 * Determine whether a course module is visible within a course,
 * this is different from instance_is_visible() - faster and visibility for user
 *
 * @global object
 * @global object
 * @uses DEBUG_DEVELOPER
 * @uses CONTEXT_MODULE
 * @uses CONDITION_MISSING_EXTRATABLE
 * @param object $cm object
 * @param int $userid empty means current user
 * @return bool Success
 */
function coursemodule_visible_for_user($cm, $userid = 0)
{
    global $USER, $CFG;
    if (empty($cm->id)) {
        debugging("Incorrect course module parameter!", DEBUG_DEVELOPER);
        return false;
    }
    if (empty($userid)) {
        $userid = $USER->id;
    }
    if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_MODULE, $cm->id), $userid)) {
        return false;
    }
    if ($CFG->enableavailability) {
        require_once $CFG->libdir . '/conditionlib.php';
        $ci = new condition_info($cm, CONDITION_MISSING_EXTRATABLE);
        if (!$ci->is_available($cm->availableinfo, false, $userid) and !has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_MODULE, $cm->id), $userid)) {
            return false;
        }
    }
    return groups_course_module_visible($cm, $userid);
}
Example #3
0
/**
 * Returns reference to full info about modules in course (including visibility).
 * Cached and as fast as possible (0 or 1 db query).
 *
 * @global object
 * @global object
 * @global object
 * @uses CONTEXT_MODULE
 * @uses MAX_MODINFO_CACHE_SIZE
 * @param mixed $course object or 'reset' string to reset caches, modinfo may be updated in db
 * @param int $userid Defaults to current user id
 * @return mixed courseinfo object or nothing if resetting
 */
function &get_fast_modinfo(&$course, $userid = 0)
{
    global $CFG, $USER, $DB;
    require_once $CFG->dirroot . '/course/lib.php';
    if (!empty($CFG->enableavailability)) {
        require_once $CFG->libdir . '/conditionlib.php';
    }
    static $cache = array();
    if ($course === 'reset') {
        $cache = array();
        $nothing = null;
        return $nothing;
        // we must return some reference
    }
    if (empty($userid)) {
        $userid = $USER->id;
    }
    if (array_key_exists($course->id, $cache) and $cache[$course->id]->userid == $userid) {
        return $cache[$course->id];
    }
    if (empty($course->modinfo)) {
        // no modinfo yet - load it
        rebuild_course_cache($course->id);
        $course->modinfo = $DB->get_field('course', 'modinfo', array('id' => $course->id));
    }
    $modinfo = new object();
    $modinfo->courseid = $course->id;
    $modinfo->userid = $userid;
    $modinfo->sections = array();
    $modinfo->cms = array();
    $modinfo->instances = array();
    $modinfo->groups = null;
    // loaded only when really needed - the only one db query
    $info = unserialize($course->modinfo);
    if (!is_array($info)) {
        // hmm, something is wrong - lets try to fix it
        rebuild_course_cache($course->id);
        $course->modinfo = $DB->get_field('course', 'modinfo', array('id' => $course->id));
        $info = unserialize($course->modinfo);
        if (!is_array($info)) {
            return $modinfo;
        }
    }
    if ($info) {
        // detect if upgrade required
        $first = reset($info);
        if (!isset($first->id)) {
            rebuild_course_cache($course->id);
            $course->modinfo = $DB->get_field('course', 'modinfo', array('id' => $course->id));
            $info = unserialize($course->modinfo);
            if (!is_array($info)) {
                return $modinfo;
            }
        }
    }
    $modlurals = array();
    // If we haven't already preloaded contexts for the course, do it now
    preload_course_contexts($course->id);
    foreach ($info as $mod) {
        if (empty($mod->name)) {
            // something is wrong here
            continue;
        }
        // reconstruct minimalistic $cm
        $cm = new object();
        $cm->id = $mod->cm;
        $cm->instance = $mod->id;
        $cm->course = $course->id;
        $cm->modname = $mod->mod;
        $cm->name = urldecode($mod->name);
        $cm->visible = $mod->visible;
        $cm->sectionnum = $mod->section;
        $cm->groupmode = $mod->groupmode;
        $cm->groupingid = $mod->groupingid;
        $cm->groupmembersonly = $mod->groupmembersonly;
        $cm->indent = $mod->indent;
        $cm->completion = $mod->completion;
        $cm->extra = isset($mod->extra) ? urldecode($mod->extra) : '';
        $cm->icon = isset($mod->icon) ? $mod->icon : '';
        $cm->uservisible = true;
        if (!empty($CFG->enableavailability)) {
            // We must have completion information from modinfo. If it's not
            // there, cache needs rebuilding
            if (!isset($mod->availablefrom)) {
                debugging('enableavailability option was changed; rebuilding ' . 'cache for course ' . $course->id);
                rebuild_course_cache($course->id, true);
                // Re-enter this routine to do it all properly
                return get_fast_modinfo($course, $userid);
            }
            $cm->availablefrom = $mod->availablefrom;
            $cm->availableuntil = $mod->availableuntil;
            $cm->showavailability = $mod->showavailability;
            $cm->conditionscompletion = $mod->conditionscompletion;
            $cm->conditionsgrade = $mod->conditionsgrade;
        }
        // preload long names plurals and also check module is installed properly
        if (!isset($modlurals[$cm->modname])) {
            if (!file_exists("{$CFG->dirroot}/mod/{$cm->modname}/lib.php")) {
                continue;
            }
            $modlurals[$cm->modname] = get_string('modulenameplural', $cm->modname);
        }
        $cm->modplural = $modlurals[$cm->modname];
        $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
        if (!empty($CFG->enableavailability)) {
            // Unfortunately the next call really wants to call
            // get_fast_modinfo, but that would be recursive, so we fake up a
            // modinfo for it already
            if (empty($minimalmodinfo)) {
                $minimalmodinfo = new stdClass();
                $minimalmodinfo->cms = array();
                foreach ($info as $mod) {
                    $minimalcm = new stdClass();
                    $minimalcm->id = $mod->cm;
                    $minimalcm->name = urldecode($mod->name);
                    $minimalmodinfo->cms[$minimalcm->id] = $minimalcm;
                }
            }
            // Get availability information
            $ci = new condition_info($cm);
            $cm->available = $ci->is_available($cm->availableinfo, true, $userid, $minimalmodinfo);
        } else {
            $cm->available = true;
        }
        if ((!$cm->visible or !$cm->available) and !has_capability('moodle/course:viewhiddenactivities', $modcontext, $userid)) {
            $cm->uservisible = false;
        } else {
            if (!empty($CFG->enablegroupings) and !empty($cm->groupmembersonly) and !has_capability('moodle/site:accessallgroups', $modcontext, $userid)) {
                if (is_null($modinfo->groups)) {
                    $modinfo->groups = groups_get_user_groups($course->id, $userid);
                }
                if (empty($modinfo->groups[$cm->groupingid])) {
                    $cm->uservisible = false;
                }
            }
        }
        if (!isset($modinfo->instances[$cm->modname])) {
            $modinfo->instances[$cm->modname] = array();
        }
        $modinfo->instances[$cm->modname][$cm->instance] =& $cm;
        $modinfo->cms[$cm->id] =& $cm;
        // reconstruct sections
        if (!isset($modinfo->sections[$cm->sectionnum])) {
            $modinfo->sections[$cm->sectionnum] = array();
        }
        $modinfo->sections[$cm->sectionnum][] = $cm->id;
        unset($cm);
    }
    unset($cache[$course->id]);
    // prevent potential reference problems when switching users
    $cache[$course->id] = $modinfo;
    // Ensure cache does not use too much RAM
    if (count($cache) > MAX_MODINFO_CACHE_SIZE) {
        reset($cache);
        $key = key($cache);
        unset($cache[$key]);
    }
    return $cache[$course->id];
}
Example #4
0
 /**
  * If dynamic data for this course-module is not yet available, gets it.
  *
  * This function is automatically called when constructing course_modinfo, so users don't
  * need to call it.
  *
  * Dynamic data is data which does not come directly from the cache but is calculated at
  * runtime based on the current user. Primarily this concerns whether the user can access
  * the module or not.
  *
  * As part of this function, the module's _cm_info_dynamic function from its lib.php will
  * be called (if it exists).
  * @return void
  */
 public function obtain_dynamic_data()
 {
     global $CFG;
     if ($this->state >= self::STATE_DYNAMIC) {
         return;
     }
     $userid = $this->modinfo->get_user_id();
     if (!empty($CFG->enableavailability)) {
         // Get availability information
         $ci = new condition_info($this);
         // Note that the modinfo currently available only includes minimal details (basic data)
         // so passing it to this function is a bit dangerous as it would cause infinite
         // recursion if it tried to get dynamic data, however we know that this function only
         // uses basic data.
         $this->available = $ci->is_available($this->availableinfo, true, $userid, $this->modinfo);
     } else {
         $this->available = true;
     }
     // Update visible state for current user
     $this->update_user_visible();
     // Let module make dynamic changes at this point
     $this->call_mod_function('cm_info_dynamic');
     $this->state = self::STATE_DYNAMIC;
 }
 /**
  * Tests the is_available function for modules. This does not test all the
  * conditions and stuff, because it only needs to check that the system
  * connects through to the real availability API. Also tests
  * get_full_information function.
  */
 public function test_is_available()
 {
     // Create course.
     $generator = $this->getDataGenerator();
     $course = $generator->create_course();
     // Create activity with no restrictions and one with date restriction.
     $page1 = $generator->get_plugin_generator('mod_page')->create_instance(array('course' => $course));
     $time = time() + 100;
     $avail = '{"op":"|","show":true,"c":[{"type":"date","d":">=","t":' . $time . '}]}';
     $page2 = $generator->get_plugin_generator('mod_page')->create_instance(array('course' => $course, 'availability' => $avail));
     // No conditions.
     $ci = new condition_info((object) array('id' => $page1->cmid), CONDITION_MISSING_EVERYTHING);
     $this->assertDebuggingCalled();
     $this->assertTrue($ci->is_available($text, false, 0));
     $this->assertDebuggingCalled();
     $this->assertEquals('', $text);
     // Date condition.
     $ci = new condition_info((object) array('id' => $page2->cmid), CONDITION_MISSING_EVERYTHING);
     $this->assertDebuggingCalled();
     $this->assertFalse($ci->is_available($text));
     $this->assertDebuggingCalled();
     $expectedtime = userdate($time, get_string('strftimedate', 'langconfig'));
     $this->assertContains($expectedtime, $text);
     // Full information display.
     $text = $ci->get_full_information();
     $this->assertDebuggingCalled();
     $expectedtime = userdate($time, get_string('strftimedate', 'langconfig'));
     $this->assertContains($expectedtime, $text);
 }
 function test_is_available()
 {
     global $DB, $USER;
     $courseid = $this->make_course();
     // No conditions
     $cmid = $this->make_course_module($courseid);
     $ci = new condition_info((object) array('id' => $cmid), CONDITION_MISSING_EVERYTHING);
     $this->assertTrue($ci->is_available($text, false, 0));
     $this->assertEqual('', $text);
     // Time (from)
     $time = time() + 100;
     $cmid = $this->make_course_module($courseid, array('availablefrom' => $time));
     $ci = new condition_info((object) array('id' => $cmid), CONDITION_MISSING_EVERYTHING);
     $this->assertFalse($ci->is_available($text));
     $this->assert(new PatternExpectation('/' . preg_quote(userdate($time, get_string('strftimedate', 'langconfig'))) . '/'), $text);
     $time = time() - 100;
     $cmid = $this->make_course_module($courseid, array('availablefrom' => $time));
     $ci = new condition_info((object) array('id' => $cmid), CONDITION_MISSING_EVERYTHING);
     $this->assertTrue($ci->is_available($text));
     $this->assertEqual('', $text);
     $this->assert(new PatternExpectation('/' . preg_quote(userdate($time, get_string('strftimedate', 'langconfig'))) . '/'), $ci->get_full_information());
     // Time (until)
     $cmid = $this->make_course_module($courseid, array('availableuntil' => time() - 100));
     $ci = new condition_info((object) array('id' => $cmid), CONDITION_MISSING_EVERYTHING);
     $this->assertFalse($ci->is_available($text));
     $this->assertEqual('', $text);
     // Completion
     $oldid = $cmid;
     $cmid = $this->make_course_module($courseid);
     $this->make_section($courseid, array($oldid, $cmid));
     $oldcm = $DB->get_record('course_modules', array('id' => $oldid));
     $oldcm->completion = COMPLETION_TRACKING_MANUAL;
     $DB->update_record('course_modules', $oldcm);
     $ci = new condition_info((object) array('id' => $cmid), CONDITION_MISSING_EVERYTHING);
     $ci->add_completion_condition($oldid, COMPLETION_COMPLETE);
     $this->assertFalse($ci->is_available($text, false));
     $this->assertEqual(get_string('requires_completion_1', 'condition', 'xxx'), $text);
     $completion = new completion_info($DB->get_record('course', array('id' => $courseid)));
     $completion->update_state($oldcm, COMPLETION_COMPLETE);
     completion_info::wipe_session_cache();
     condition_info::wipe_session_cache();
     $this->assertTrue($ci->is_available($text));
     $this->assertFalse($ci->is_available($text, false, $USER->id + 1));
     completion_info::wipe_session_cache();
     condition_info::wipe_session_cache();
     $completion = new completion_info($DB->get_record('course', array('id' => $courseid)));
     $completion->update_state($oldcm, COMPLETION_INCOMPLETE);
     $this->assertFalse($ci->is_available($text));
     $ci->wipe_conditions();
     $ci->add_completion_condition($oldid, COMPLETION_INCOMPLETE);
     condition_info::wipe_session_cache();
     $this->assertTrue($ci->is_available($text));
     $this->assertTrue($ci->is_available($text, false, $USER->id + 1));
     condition_info::wipe_session_cache();
     $this->assertTrue($ci->is_available($text, true));
     // Grade
     $ci->wipe_conditions();
     // Add a fake grade item
     $gradeitemid = $DB->insert_record('grade_items', (object) array('courseid' => $courseid, 'itemname' => 'frog'));
     // Add a condition on a value existing...
     $ci->add_grade_condition($gradeitemid, null, null, true);
     $this->assertFalse($ci->is_available($text));
     $this->assertEqual(get_string('requires_grade_any', 'condition', 'frog'), $text);
     // Fake it existing
     $DB->insert_record('grade_grades', (object) array('itemid' => $gradeitemid, 'userid' => $USER->id, 'finalgrade' => 3.78));
     condition_info::wipe_session_cache();
     $this->assertTrue($ci->is_available($text));
     condition_info::wipe_session_cache();
     $this->assertTrue($ci->is_available($text, true));
     // Now require that user gets more than 3.78001
     $ci->wipe_conditions();
     $ci->add_grade_condition($gradeitemid, 3.78001, null, true);
     condition_info::wipe_session_cache();
     $this->assertFalse($ci->is_available($text));
     $this->assertEqual(get_string('requires_grade_min', 'condition', 'frog'), $text);
     // ...just on 3.78...
     $ci->wipe_conditions();
     $ci->add_grade_condition($gradeitemid, 3.78, null, true);
     condition_info::wipe_session_cache();
     $this->assertTrue($ci->is_available($text));
     // ...less than 3.78
     $ci->wipe_conditions();
     $ci->add_grade_condition($gradeitemid, null, 3.78, true);
     condition_info::wipe_session_cache();
     $this->assertFalse($ci->is_available($text));
     $this->assertEqual(get_string('requires_grade_max', 'condition', 'frog'), $text);
     // ...less than 3.78001
     $ci->wipe_conditions();
     $ci->add_grade_condition($gradeitemid, null, 3.78001, true);
     condition_info::wipe_session_cache();
     $this->assertTrue($ci->is_available($text));
     // ...in a range that includes it
     $ci->wipe_conditions();
     $ci->add_grade_condition($gradeitemid, 3, 4, true);
     condition_info::wipe_session_cache();
     $this->assertTrue($ci->is_available($text));
     // ...in a range that doesn't include it
     $ci->wipe_conditions();
     $ci->add_grade_condition($gradeitemid, 4, 5, true);
     condition_info::wipe_session_cache();
     $this->assertFalse($ci->is_available($text));
     $this->assertEqual(get_string('requires_grade_range', 'condition', 'frog'), $text);
 }
Example #7
0
/**
 * This function checks that the current user is logged in and has the
 * required privileges
 *
 * This function checks that the current user is logged in, and optionally
 * whether they are allowed to be in a particular course and view a particular
 * course module.
 * If they are not logged in, then it redirects them to the site login unless
 * $autologinguest is set and {@link $CFG}->autologinguests is set to 1 in which
 * case they are automatically logged in as guests.
 * If $courseid is given and the user is not enrolled in that course then the
 * user is redirected to the course enrolment page.
 * If $cm is given and the coursemodule is hidden and the user is not a teacher
 * in the course then the user is redirected to the course home page.
 *
 * @uses $CFG
 * @uses $SESSION
 * @uses $USER
 * @uses $FULLME
 * @uses SITEID
 * @uses $COURSE
 * @param mixed $courseorid id of the course or course object
 * @param bool $autologinguest
 * @param object $cm course module object
 * @param bool $setwantsurltome Define if we want to set $SESSION->wantsurl, defaults to
 *             true. Used to avoid (=false) some scripts (file.php...) to set that variable,
 *             in order to keep redirects working properly. MDL-14495
 */
function require_login($courseorid = 0, $autologinguest = true, $cm = null, $setwantsurltome = true)
{
    global $CFG, $SESSION, $USER, $COURSE, $FULLME, $PAGE, $SITE, $DB;
    /// setup global $COURSE, themes, language and locale
    if (!empty($courseorid)) {
        if (is_object($courseorid)) {
            $course = $courseorid;
        } else {
            if ($courseorid == SITEID) {
                $course = clone $SITE;
            } else {
                $course = $DB->get_record('course', array('id' => $courseorid));
                if (!$course) {
                    throw new moodle_exception('invalidcourseid');
                }
            }
        }
        $PAGE->set_course($course);
    } else {
        // If $PAGE->course, and hence $PAGE->context, have not already been set
        // up properly, set them up now.
        $PAGE->set_course($PAGE->course);
    }
    /// If the user is not even logged in yet then make sure they are
    if (!isloggedin()) {
        //NOTE: $USER->site check was obsoleted by session test cookie,
        //      $USER->confirmed test is in login/index.php
        if ($setwantsurltome) {
            $SESSION->wantsurl = $FULLME;
        }
        if (!empty($_SERVER['HTTP_REFERER'])) {
            $SESSION->fromurl = $_SERVER['HTTP_REFERER'];
        }
        if ($autologinguest and !empty($CFG->guestloginbutton) and !empty($CFG->autologinguests) and ($COURSE->id == SITEID or $COURSE->guest)) {
            $loginguest = true;
        } else {
            $loginguest = false;
        }
        redirect(get_login_url($loginguest));
        exit;
        // never reached
    }
    /// loginas as redirection if needed
    if ($COURSE->id != SITEID and session_is_loggedinas()) {
        if ($USER->loginascontext->contextlevel == CONTEXT_COURSE) {
            if ($USER->loginascontext->instanceid != $COURSE->id) {
                print_error('loginasonecourse', '', $CFG->wwwroot . '/course/view.php?id=' . $USER->loginascontext->instanceid);
            }
        }
    }
    /// check whether the user should be changing password (but only if it is REALLY them)
    if (get_user_preferences('auth_forcepasswordchange') && !session_is_loggedinas()) {
        $userauth = get_auth_plugin($USER->auth);
        if ($userauth->can_change_password()) {
            $SESSION->wantsurl = $FULLME;
            if ($changeurl = $userauth->change_password_url()) {
                //use plugin custom url
                redirect($changeurl);
            } else {
                //use moodle internal method
                if (empty($CFG->loginhttps)) {
                    redirect($CFG->wwwroot . '/login/change_password.php');
                } else {
                    $wwwroot = str_replace('http:', 'https:', $CFG->wwwroot);
                    redirect($wwwroot . '/login/change_password.php');
                }
            }
        } else {
            print_error('nopasswordchangeforced', 'auth');
        }
    }
    /// Check that the user account is properly set up
    if (user_not_fully_set_up($USER)) {
        $SESSION->wantsurl = $FULLME;
        redirect($CFG->wwwroot . '/user/edit.php?id=' . $USER->id . '&course=' . SITEID);
    }
    /// Make sure the USER has a sesskey set up.  Used for checking script parameters.
    sesskey();
    // Check that the user has agreed to a site policy if there is one
    if (!empty($CFG->sitepolicy)) {
        if (!$USER->policyagreed) {
            $SESSION->wantsurl = $FULLME;
            redirect($CFG->wwwroot . '/user/policy.php');
        }
    }
    // Fetch the system context, we are going to use it a lot.
    $sysctx = get_context_instance(CONTEXT_SYSTEM);
    /// If the site is currently under maintenance, then print a message
    if (!has_capability('moodle/site:config', $sysctx)) {
        if (file_exists($CFG->dataroot . '/' . SITEID . '/maintenance.html')) {
            print_maintenance_message();
            exit;
        }
    }
    /// groupmembersonly access control
    if (!empty($CFG->enablegroupings) and $cm and $cm->groupmembersonly and !has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id))) {
        if (isguestuser() or !groups_has_membership($cm)) {
            print_error('groupmembersonlyerror', 'group', $CFG->wwwroot . '/course/view.php?id=' . $cm->course);
        }
    }
    // Fetch the course context, and prefetch its child contexts
    if (!isset($COURSE->context)) {
        if (!($COURSE->context = get_context_instance(CONTEXT_COURSE, $COURSE->id))) {
            print_error('nocontext');
        }
    }
    if (!empty($cm) && !isset($cm->context)) {
        if (!($cm->context = get_context_instance(CONTEXT_MODULE, $cm->id))) {
            print_error('nocontext');
        }
    }
    // Conditional activity access control
    if (!empty($CFG->enableavailability) and $cm) {
        // We cache conditional access in session
        if (!isset($SESSION->conditionaccessok)) {
            $SESSION->conditionaccessok = array();
        }
        // If you have been allowed into the module once then you are allowed
        // in for rest of session, no need to do conditional checks
        if (!array_key_exists($cm->id, $SESSION->conditionaccessok)) {
            // Get condition info (does a query for the availability table)
            require_once $CFG->libdir . '/conditionlib.php';
            $ci = new condition_info($cm, CONDITION_MISSING_EXTRATABLE);
            // Check condition for user (this will do a query if the availability
            // information depends on grade or completion information)
            if ($ci->is_available($junk) || has_capability('moodle/course:viewhiddenactivities', $cm->context)) {
                $SESSION->conditionaccessok[$cm->id] = true;
            } else {
                print_error('activityiscurrentlyhidden');
            }
        }
    }
    if ($COURSE->id == SITEID) {
        /// Eliminate hidden site activities straight away
        if (!empty($cm) && !$cm->visible && !has_capability('moodle/course:viewhiddenactivities', $cm->context)) {
            redirect($CFG->wwwroot, get_string('activityiscurrentlyhidden'));
        }
        user_accesstime_log($COURSE->id);
        /// Access granted, update lastaccess times
        return;
    } else {
        /// Check if the user can be in a particular course
        if (empty($USER->access['rsw'][$COURSE->context->path])) {
            //
            // MDL-13900 - If the course or the parent category are hidden
            // and the user hasn't the 'course:viewhiddencourses' capability, prevent access
            //
            if (!($COURSE->visible && course_parent_visible($COURSE)) && !has_capability('moodle/course:viewhiddencourses', $COURSE->context)) {
                print_header_simple();
                notice(get_string('coursehidden'), $CFG->wwwroot . '/');
            }
        }
        /// Non-guests who don't currently have access, check if they can be allowed in as a guest
        if ($USER->username != 'guest' and !has_capability('moodle/course:view', $COURSE->context)) {
            if ($COURSE->guest == 1) {
                // Temporarily assign them guest role for this context, if it fails later user is asked to enrol
                $USER->access = load_temp_role($COURSE->context, $CFG->guestroleid, $USER->access);
            }
        }
        /// If the user is a guest then treat them according to the course policy about guests
        if (has_capability('moodle/legacy:guest', $COURSE->context, NULL, false)) {
            if (has_capability('moodle/site:doanything', $sysctx)) {
                // administrators must be able to access any course - even if somebody gives them guest access
                user_accesstime_log($COURSE->id);
                /// Access granted, update lastaccess times
                return;
            }
            switch ($COURSE->guest) {
                /// Check course policy about guest access
                case 1:
                    /// Guests always allowed
                    if (!has_capability('moodle/course:view', $COURSE->context)) {
                        // Prohibited by capability
                        print_header_simple();
                        notice(get_string('guestsnotallowed', '', format_string($COURSE->fullname)), get_login_url());
                    }
                    if (!empty($cm) and !$cm->visible) {
                        // Not allowed to see module, send to course page
                        redirect($CFG->wwwroot . '/course/view.php?id=' . $cm->course, get_string('activityiscurrentlyhidden'));
                    }
                    user_accesstime_log($COURSE->id);
                    /// Access granted, update lastaccess times
                    return;
                    // User is allowed to see this course
                    break;
                case 2:
                    /// Guests allowed with key
                    if (!empty($USER->enrolkey[$COURSE->id])) {
                        // Set by enrol/manual/enrol.php
                        user_accesstime_log($COURSE->id);
                        /// Access granted, update lastaccess times
                        return true;
                    }
                    //  otherwise drop through to logic below (--> enrol.php)
                    break;
                default:
                    /// Guests not allowed
                    $strloggedinasguest = get_string('loggedinasguest');
                    print_header_simple('', '', build_navigation(array(array('name' => $strloggedinasguest, 'link' => null, 'type' => 'misc'))));
                    if (empty($USER->access['rsw'][$COURSE->context->path])) {
                        // Normal guest
                        notice(get_string('guestsnotallowed', '', format_string($COURSE->fullname)), get_login_url());
                    } else {
                        notify(get_string('guestsnotallowed', '', format_string($COURSE->fullname)));
                        echo '<div class="notifyproblem">' . switchroles_form($COURSE->id) . '</div>';
                        print_footer($COURSE);
                        exit;
                    }
                    break;
            }
            /// For non-guests, check if they have course view access
        } else {
            if (has_capability('moodle/course:view', $COURSE->context)) {
                if (session_is_loggedinas()) {
                    // Make sure the REAL person can also access this course
                    $realuser = session_get_realuser();
                    if (!has_capability('moodle/course:view', $COURSE->context, $realuser->id)) {
                        print_header_simple();
                        notice(get_string('studentnotallowed', '', fullname($USER, true)), $CFG->wwwroot . '/');
                    }
                }
                /// Make sure they can read this activity too, if specified
                if (!empty($cm) && !$cm->visible && !has_capability('moodle/course:viewhiddenactivities', $cm->context)) {
                    redirect($CFG->wwwroot . '/course/view.php?id=' . $cm->course, get_string('activityiscurrentlyhidden'));
                }
                user_accesstime_log($COURSE->id);
                /// Access granted, update lastaccess times
                return;
                // User is allowed to see this course
            }
        }
        /// Currently not enrolled in the course, so see if they want to enrol
        $SESSION->wantsurl = $FULLME;
        redirect($CFG->wwwroot . '/course/enrol.php?id=' . $COURSE->id);
        die;
    }
}
 /**
  * Checks whether a user can be subscribed to the forum, regardless of
  * subscription option. Includes a variety of other checks. [These are
  * supposed to be the same as checks done when building the list of people
  * for email.]
  * @param int $userid User ID or 0 for current
  * @return bool True if user can be subscribed
  */
 private function can_be_subscribed($userid = 0)
 {
     global $USER;
     $userid = mod_forumng_utils::get_real_userid($userid);
     $cm = $this->get_course_module();
     $course = $this->get_course();
     $context = $this->get_context();
     // Guests cannot subscribe
     if (!isloggedin() || isguestuser($userid)) {
         return false;
     }
     // Get from cache if possible
     if (!isset($this->cache->can_be_subscribed)) {
         $this->cache->can_be_subscribed = array();
     }
     if (array_key_exists($userid, $this->cache->can_be_subscribed)) {
         return $this->cache->can_be_subscribed[$userid];
     }
     // This is not a loop, just so I can use break
     do {
         // Check user can see forum
         if (!has_capability('mod/forumng:viewdiscussion', $context, $userid)) {
             $result = false;
             break;
         }
         // For current user, can take shortcut
         if ($userid == $USER->id) {
             if (empty($cm->uservisible)) {
                 $uservisible = false;
             } else {
                 $uservisible = true;
             }
             if (!$uservisible) {
                 $result = false;
                 break;
             }
         } else {
             $visible = $cm->visible;
             // Note: It is pretty terrible that this code is placed here.
             // Shouldn't there be a function in cm_info to do this? :(
             // Unfortunately I didn't think of that when redesigning
             // cm_info, it can only work for current user.
             $conditioninfo = new condition_info($cm);
             $visible = $visible && $conditioninfo->is_available($crap, false, $userid);
             if (!$visible && !has_capability('moodle/site:viewhiddenactivities', $context, $userid)) {
                 $result = false;
                 break;
             }
             if ($cm->groupmembersonly && !has_capability('moodle/site:accessallgroups', $context, $userid)) {
                 // If the forum is restricted to group members only, then
                 // limit it to people within groups on the course - or
                 // groups in the grouping, if one is selected
                 $groupobjs = groups_get_all_groups($course->id, $userid, $cm->groupingid, 'g.id');
                 if (!$groupobjs || count($groupobjs) == 0) {
                     $result = false;
                     break;
                 }
             }
         }
         $result = true;
         break;
     } while (false);
     $this->cache->can_be_subscribed[$userid] = $result;
     return $result;
 }
 /**
  * Created to accomodate forumng on shared activities
  * where the shared activites course does not hold cm information
  * in the course table's modinfo field
  * @param $course
  * @param $cmid
  * @return $modinfo
  */
 private function get_fast_modinfo($course, $cmid)
 {
     global $CFG;
     if (class_exists('ouflags')) {
         require_once $CFG->dirroot . '/course/format/sharedactv/sharedactv.php';
         if (sharedactv_is_magic_course($course)) {
             // get_fast_modinfo will only ever return a minimal object, so build own
             $modinfo = new object();
             $modinfo->courseid = $course->id;
             $modinfo->userid = 0;
             $modinfo->sections = array();
             $modinfo->instances = array();
             $modinfo->groups = null;
             if (!($cm = get_coursemodule_from_id('forumng', $cmid, $course->id))) {
                 throw new forum_exception('Could not find the forum course module.');
             }
             if (!empty($CFG->enableavailability)) {
                 $cm->conditionscompletion = array();
                 $cm->conditionsgrade = array();
                 // Unfortunately the next call really wants to call
                 // get_fast_modinfo, but that would be recursive, so we fake up a
                 // modinfo for it already
                 if (empty($minimalmodinfo)) {
                     $minimalmodinfo = new stdClass();
                     $minimalmodinfo->cms = array();
                     $minimalcm = new stdClass();
                     $minimalcm->id = $cmid;
                     $minimalcm->name = 'forumng';
                     $minimalmodinfo->cms[$cmid] = $minimalcm;
                 }
                 // Get availability information
                 $ci = new condition_info($cm);
                 $cm->available = $ci->is_available($cm->availableinfo, true, 0, $minimalmodinfo);
             } else {
                 $cm->available = true;
             }
             $cm->uservisible = true;
             $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
             if ((!$cm->visible or !$cm->available) and !has_capability('moodle/course:viewhiddenactivities', $modcontext, 0)) {
                 $cm->uservisible = false;
             } else {
                 if (!empty($CFG->enablegroupings) and !empty($cm->groupmembersonly) and !has_capability('moodle/site:accessallgroups', $modcontext, 0)) {
                     if (is_null($modinfo->groups)) {
                         $modinfo->groups = groups_get_user_groups($course->id, 0);
                     }
                     if (empty($modinfo->groups[$cm->groupingid])) {
                         $cm->uservisible = false;
                     }
                 }
             }
             $modinfo->cms = array($cmid => $cm);
         } else {
             $modinfo = get_fast_modinfo($course);
         }
     } else {
         $modinfo = get_fast_modinfo($course);
     }
     return $modinfo;
 }