navigation MDL-25142 Fixed up differences in navigation between guest and normal...
authorSam Hemelryk <sam@moodle.com>
Thu, 11 Nov 2010 03:37:56 +0000 (03:37 +0000)
committerSam Hemelryk <sam@moodle.com>
Thu, 11 Nov 2010 03:37:56 +0000 (03:37 +0000)
As part of this patch I also introduced a new method in accesslib can_access_course that can be used
to check a users access to a course.
I also fixed a minor issue with guest access flag caching in require_login

enrol/guest/lib.php
lib/accesslib.php
lib/enrollib.php
lib/moodlelib.php
lib/navigationlib.php

index f31a468..570539c 100644 (file)
@@ -78,7 +78,7 @@ class enrol_guest_plugin extends enrol_plugin {
             // Temporarily assign them some guest role for this context
             $context = get_context_instance(CONTEXT_COURSE, $instance->courseid);
             $USER->access = load_temp_role($context, $CFG->guestroleid, $USER->access);
-            return ENROL_REQUIRE_LOGIN_CACHE_PERIOD;
+            return ENROL_REQUIRE_LOGIN_CACHE_PERIOD + time();
         }
 
         return false;
index d6d6a08..b393851 100755 (executable)
@@ -2978,6 +2978,93 @@ function is_enrolled($context, $user = null, $withcapability = '', $onlyactive =
     return true;
 }
 
+/**
+ * Returns true if the user is able to access the course.
+ *
+ * This function is in no way, shape, or form a substitute for require_login.
+ * It should only be used in circumstances where it is not possible to call require_login
+ * such as the navigation.
+ *
+ * This function checks many of the methods of access to a course such as the view
+ * capability, enrollments, and guest access. It also makes use of the cache
+ * generated by require_login for guest access.
+ *
+ * The flags within the $USER object that are used here should NEVER be used outside
+ * of this function can_access_course and require_login. Doing so WILL break future
+ * versions.
+ *
+ * @global moodle_database $DB
+ * @param stdClass $context
+ * @param stdClass|null $user
+ * @param string $withcapability Check for this capability as well.
+ * @param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions
+ * @param boolean $trustcache If set to false guest access will always be checked
+ *                             against the enrolment plugins from the course, rather
+ *                             than the cache generated by require_login.
+ * @return boolean Returns true if the user is able to access the course
+ */
+function can_access_course($context, $user = null, $withcapability = '', $onlyactive = false, $trustcache = true) {
+    global $DB, $USER;
+
+    $coursecontext = get_course_context($context);
+    $courseid = $coursecontext->instanceid;
+
+    // First check the obvious, is the user viewing or is the user enrolled.
+    if (is_viewing($coursecontext, $user, $withcapability) || is_enrolled($coursecontext, $user, $withcapability, $onlyactive)) {
+        // How easy was that!
+        return true;
+    }
+
+    $access = false;
+    if (!isset($USER->enrol)) {
+        // Cache hasn't been generated yet so we can't trust it
+        $trustcache = false;
+        /**
+         * These flags within the $USER object should NEVER be used outside of this
+         * function can_access_course and the function require_login.
+         * Doing so WILL break future versions!!!!
+         */
+        $USER->enrol = array();
+        $USER->enrol['enrolled'] = array();
+        $USER->enrol['tempguest'] = array();
+    }
+
+    // If we don't trust the cache we need to check with the courses enrolment
+    // plugin instances to see if the user can access the course as a guest.
+    if (!$trustcache) {
+        // Ok, off to the database we go!
+        $instances = $DB->get_records('enrol', array('courseid'=>$courseid, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder, id ASC');
+        $enrols = enrol_get_plugins(true);
+        foreach($instances as $instance) {
+            if (!isset($enrols[$instance->enrol])) {
+                continue;
+            }
+            $until = $enrols[$instance->enrol]->try_guestaccess($instance);
+            if ($until !== false) {
+                // Never use me anywhere but here and require_login
+                $USER->enrol['tempguest'][$courseid] = $until;
+                $access = true;
+                break;
+            }
+        }
+    }
+
+    // If we don't already have access (from above) check the cache and see whether
+    // there is record of it in there.
+    if (!$access && isset($USER->enrol['tempguest'][$courseid])) {
+        // Never use me anywhere but here and require_login
+        if ($USER->enrol['tempguest'][$courseid] == 0) {
+            $access = true;
+        } else if ($USER->enrol['tempguest'][$courseid] > time()) {
+            $access = true;
+        } else {
+            //expired
+            unset($USER->enrol['tempguest'][$courseid]);
+        }
+    }
+    return $access;
+}
+
 /**
  * Returns array with sql code and parameters returning all ids
  * of users enrolled into course.
index 8e7741c..5c338b5 100644 (file)
@@ -958,6 +958,8 @@ abstract class enrol_plugin {
      * Attempt to automatically enrol current user in course without any interaction,
      * calling code has to make sure the plugin and instance are active.
      *
+     * This should return either a timestamp in the future or false.
+     *
      * @param stdClass $instance course enrol instance
      * @param stdClass $user record
      * @return bool|int false means not enrolled, integer means timeend
@@ -972,6 +974,8 @@ abstract class enrol_plugin {
      * Attempt to automatically gain temporary guest access to course,
      * calling code has to make sure the plugin and instance are active.
      *
+     * This should return either a timestamp in the future or false.
+     *
      * @param stdClass $instance course enrol instance
      * @param stdClass $user record
      * @return bool|int false means no guest access, integer means timeend
index ff9f666..a915dd8 100644 (file)
@@ -2540,6 +2540,7 @@ function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $
                     if (!isset($enrols[$instance->enrol])) {
                         continue;
                     }
+                    // Get a duration for the guestaccess, a timestamp in the future or false.
                     $until = $enrols[$instance->enrol]->try_autoenrol($instance);
                     if ($until !== false) {
                         $USER->enrol['enrolled'][$course->id] = $until;
@@ -2554,6 +2555,7 @@ function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $
                         if (!isset($enrols[$instance->enrol])) {
                             continue;
                         }
+                        // Get a duration for the guestaccess, a timestamp in the future or false.
                         $until = $enrols[$instance->enrol]->try_guestaccess($instance);
                         if ($until !== false) {
                             $USER->enrol['tempguest'][$course->id] = $until;
index 2733be2..318d1de 100644 (file)
@@ -990,7 +990,8 @@ class global_navigation extends navigation_node {
                 // course node and not populate it.
                 $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
                 // Not enrolled, can't view, and hasn't switched roles
-                if ((!is_enrolled($coursecontext) && !has_capability('moodle/course:view', $coursecontext) && !is_role_switched($course->id))) {
+
+                if (!can_access_course($coursecontext)) {
                     $coursenode->make_active();
                     $canviewcourseprofile = false;
                     break;
@@ -1014,7 +1015,7 @@ class global_navigation extends navigation_node {
                 // If the user is not enrolled then we only want to show the
                 // course node and not populate it.
                 $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
-                if ($course->id !== SITEID && !is_enrolled($coursecontext) && !has_capability('moodle/course:view', $coursecontext)) {
+                if (can_access_course($coursecontext)) {
                     if ($coursenode) {
                         $coursenode->make_active();
                     }
@@ -1069,7 +1070,7 @@ class global_navigation extends navigation_node {
                     // If the user is not enrolled then we only want to show the
                     // course node and not populate it.
                     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
-                    if (!is_enrolled($coursecontext) && !has_capability('moodle/course:view', $coursecontext)) {
+                    if (can_access_course($coursecontext)) {
                         $coursenode->make_active();
                         $canviewcourseprofile = false;
                         break;
@@ -1763,7 +1764,7 @@ class global_navigation extends navigation_node {
                     $usercoursenode->add(get_string('notes', 'notes'), $url, self::TYPE_SETTING);
                 }
 
-                if (has_capability('moodle/course:view', get_context_instance(CONTEXT_COURSE, $usercourse->id))) {
+                if (can_access_course(get_context_instance(CONTEXT_COURSE, $usercourse->id), $user->id)) {
                     $usercoursenode->add(get_string('entercourse'), new moodle_url('/course/view.php', array('id'=>$usercourse->id)), self::TYPE_SETTING, null, null, new pix_icon('i/course', ''));
                 }
 
@@ -3288,7 +3289,7 @@ class settings_navigation extends navigation_node {
                     return false;
                 }
             } else {
-                if ((!has_capability('moodle/user:viewdetails', $coursecontext) && !has_capability('moodle/user:viewdetails', $usercontext)) || !is_enrolled($coursecontext, $user->id)) {
+                if ((!has_capability('moodle/user:viewdetails', $coursecontext) && !has_capability('moodle/user:viewdetails', $usercontext)) || !can_access_course($coursecontext, $user->id)) {
                     return false;
                 }
                 if (groups_get_course_groupmode($course) == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $coursecontext)) {