From bbfdff344c8e14746929e9729a11fdff9d1f65af Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Sat, 5 Nov 2011 12:12:48 +0100 Subject: [PATCH] MDL-30131 improve current user enrol caching --- admin/enrol.php | 5 ++ enrol/guest/lib.php | 9 +++- enrol/instances.php | 3 ++ enrol/manual/edit.php | 6 +++ enrol/paypal/edit.php | 6 +++ enrol/self/edit.php | 6 +++ lib/accesslib.php | 121 ++++++++++++++++++------------------------ lib/enrollib.php | 108 +++++++++++++++++++++++++++++++++---- lib/moodlelib.php | 91 +++++++++++++------------------ 9 files changed, 222 insertions(+), 133 deletions(-) diff --git a/admin/enrol.php b/admin/enrol.php index efb4dc36113..2d53db9ca71 100644 --- a/admin/enrol.php +++ b/admin/enrol.php @@ -41,10 +41,13 @@ $all = enrol_get_plugins(false); $return = new moodle_url('/admin/settings.php', array('section'=>'manageenrols')); +$syscontext = context_system::instance(); + switch ($action) { case 'disable': unset($enabled[$enrol]); set_config('enrol_plugins_enabled', implode(',', array_keys($enabled))); + $syscontext->mark_dirty(); // resets all enrol caches break; case 'enable': @@ -54,6 +57,7 @@ switch ($action) { $enabled = array_keys($enabled); $enabled[] = $enrol; set_config('enrol_plugins_enabled', implode(',', $enabled)); + $syscontext->mark_dirty(); // resets all enrol caches break; case 'up': @@ -106,6 +110,7 @@ switch ($action) { } else { // Delete everything!! uninstall_plugin('enrol', $enrol); + $syscontext->mark_dirty(); // resets all enrol caches $a->plugin = $strplugin; $a->directory = "$CFG->dirroot/enrol/$enrol"; diff --git a/enrol/guest/lib.php b/enrol/guest/lib.php index 39516e14ba0..bf5aa3693ac 100644 --- a/enrol/guest/lib.php +++ b/enrol/guest/lib.php @@ -68,7 +68,6 @@ class enrol_guest_plugin extends enrol_plugin { * calling code has to make sure the plugin and instance are active. * * @param stdClass $instance course enrol instance - * @param stdClass $user record * @return bool|int false means no guest access, integer means end of cached time */ public function try_guestaccess(stdClass $instance) { @@ -78,7 +77,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); load_temp_course_role($context, $CFG->guestroleid); - return ENROL_REQUIRE_LOGIN_CACHE_PERIOD + time(); + return ENROL_MAX_TIMESTAMP; } return false; @@ -278,12 +277,18 @@ class enrol_guest_plugin extends enrol_plugin { $i = $instance->id; if (isset($data->{'enrol_guest_status_'.$i})) { + $reset = ($instance->status != $data->{'enrol_guest_status_'.$i}); + $instance->status = $data->{'enrol_guest_status_'.$i}; $instance->timemodified = time(); if ($instance->status == ENROL_INSTANCE_ENABLED) { $instance->password = $data->{'enrol_guest_password_'.$i}; } $DB->update_record('enrol', $instance); + + if ($reset) { + $context->mark_dirty(); + } } } } diff --git a/enrol/instances.php b/enrol/instances.php index 7f09d880648..fe5e74b48a7 100644 --- a/enrol/instances.php +++ b/enrol/instances.php @@ -98,6 +98,7 @@ if ($canconfig and $action and confirm_sesskey()) { if ($confirm) { $plugin->delete_instance($instance); + $context->mark_dirty(); // invalidate all enrol caches redirect($PAGE->url); } @@ -115,6 +116,7 @@ if ($canconfig and $action and confirm_sesskey()) { if ($instance->status == ENROL_INSTANCE_ENABLED) { $instance->status = ENROL_INSTANCE_DISABLED; $DB->update_record('enrol', $instance); + $context->mark_dirty(); // invalidate all enrol caches redirect($PAGE->url); } @@ -123,6 +125,7 @@ if ($canconfig and $action and confirm_sesskey()) { if ($instance->status == ENROL_INSTANCE_DISABLED) { $instance->status = ENROL_INSTANCE_ENABLED; $DB->update_record('enrol', $instance); + $context->mark_dirty(); // invalidate all enrol caches redirect($PAGE->url); } } diff --git a/enrol/manual/edit.php b/enrol/manual/edit.php index aa2edd17ea8..24079a93067 100644 --- a/enrol/manual/edit.php +++ b/enrol/manual/edit.php @@ -70,12 +70,18 @@ if ($mform->is_cancelled()) { } else if ($data = $mform->get_data()) { if ($instance->id) { + $reset = ($instance->status != $data->status); + $instance->status = $data->status; $instance->enrolperiod = $data->enrolperiod; $instance->roleid = $data->roleid; $instance->timemodified = time(); $DB->update_record('enrol', $instance); + if ($reset) { + $context->mark_dirty(); + } + } else { $fields = array('status'=>$data->status, 'enrolperiod'=>$data->enrolperiod, 'roleid'=>$data->roleid); $plugin->add_instance($course, $fields); diff --git a/enrol/paypal/edit.php b/enrol/paypal/edit.php index fdac861f93e..91c89e2fe24 100644 --- a/enrol/paypal/edit.php +++ b/enrol/paypal/edit.php @@ -65,6 +65,8 @@ if ($mform->is_cancelled()) { } else if ($data = $mform->get_data()) { if ($instance->id) { + $reset = ($instance->status != $data->status); + $instance->status = $data->status; $instance->name = $data->name; $instance->cost = $data->cost; @@ -76,6 +78,10 @@ if ($mform->is_cancelled()) { $instance->timemodified = time(); $DB->update_record('enrol', $instance); + if ($reset) { + $context->mark_dirty(); + } + } else { $fields = array('status'=>$data->status, 'name'=>$data->name, 'cost'=>$data->cost, 'currency'=>$data->currency, 'roleid'=>$data->roleid, 'enrolperiod'=>$data->enrolperiod, 'enrolstartdate'=>$data->enrolstartdate, 'enrolenddate'=>$data->enrolenddate); diff --git a/enrol/self/edit.php b/enrol/self/edit.php index 66d2212332b..4affcb7979a 100644 --- a/enrol/self/edit.php +++ b/enrol/self/edit.php @@ -65,6 +65,8 @@ if ($mform->is_cancelled()) { } else if ($data = $mform->get_data()) { if ($instance->id) { + $reset = ($instance->status != $data->status); + $instance->status = $data->status; $instance->name = $data->name; $instance->password = $data->password; @@ -80,6 +82,10 @@ if ($mform->is_cancelled()) { $instance->timemodified = time(); $DB->update_record('enrol', $instance); + if ($reset) { + $context->mark_dirty(); + } + } else { $fields = array('status'=>$data->status, 'name'=>$data->name, 'password'=>$data->password, 'customint1'=>$data->customint1, 'customint2'=>$data->customint2, 'customint3'=>$data->customint3, 'customint4'=>$data->customint4, 'customtext1'=>$data->customtext1, diff --git a/lib/accesslib.php b/lib/accesslib.php index 44793792c72..013d1ad476a 100644 --- a/lib/accesslib.php +++ b/lib/accesslib.php @@ -1122,7 +1122,9 @@ function load_all_capabilities() { // Clear to force a refresh unset($USER->mycourses); - unset($USER->enrol); + + // init/reset internal enrol caches - active course enrolments and temp access + $USER->enrol = array('enrolled'=>array(), 'tempguest'=>array()); } /** @@ -1172,15 +1174,18 @@ function reload_all_capabilities() { * @return void */ function load_temp_course_role(context_course $coursecontext, $roleid) { - global $USER; - - //TODO: this gets removed if there are any dirty contexts, we should probably store list of these temp roles somewhere (skodak) + global $USER, $SITE; if (empty($roleid)) { debugging('invalid role specified in load_temp_course_role()'); return; } + if ($coursecontext->instanceid == $SITE->id) { + debugging('Can not use temp roles on the frontpage'); + return; + } + if (!isset($USER->access)) { load_all_capabilities(); } @@ -1207,7 +1212,12 @@ function load_temp_course_role(context_course $coursecontext, $roleid) { * @return void */ function remove_temp_course_roles(context_course $coursecontext) { - global $DB, $USER; + global $DB, $USER, $SITE; + + if ($coursecontext->instanceid == $SITE->id) { + debugging('Can not use temp roles on the frontpage'); + return; + } if (empty($USER->access['ra'][$coursecontext->path])) { //no roles here, weird @@ -1877,6 +1887,8 @@ function is_viewing(context $context, $user = null, $withcapability = '') { * Returns true if user is enrolled (is participating) in course * this is intended for students and teachers. * + * Since 2.2 the result for active enrolments and current user are cached. + * * @param context $context * @param int|stdClass $user, if null $USER is used, otherwise user object or id expected * @param string $withcapability extra capability name @@ -1907,32 +1919,35 @@ function is_enrolled(context $context, $user = null, $withcapability = '', $only if ($coursecontext->instanceid == SITEID) { // everybody participates on frontpage } else { - if ($onlyactive) { - $sql = "SELECT ue.* - FROM {user_enrolments} ue - JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid) - JOIN {user} u ON u.id = ue.userid - WHERE ue.userid = :userid AND ue.status = :active AND e.status = :enabled AND u.deleted = 0"; - $params = array('enabled'=>ENROL_INSTANCE_ENABLED, 'active'=>ENROL_USER_ACTIVE, 'userid'=>$userid, 'courseid'=>$coursecontext->instanceid); - // this result should be very small, better not do the complex time checks in sql for now ;-) - $enrolments = $DB->get_records_sql($sql, $params); - $now = time(); - // make sure the enrol period is ok - $result = false; - foreach ($enrolments as $e) { - if ($e->timestart > $now) { - continue; + // try cached info first - the enrolled flag is set only when active enrolment present + if ($USER->id == $userid) { + $coursecontext->reload_if_dirty(); + if (isset($USER->enrol['enrolled'][$coursecontext->instanceid])) { + if ($USER->enrol['enrolled'][$coursecontext->instanceid] > time()) { + return true; } - if ($e->timeend and $e->timeend < $now) { - continue; - } - $result = true; - break; } - if (!$result) { + } + + if ($onlyactive) { + // look for active enrolments only + $until = enrol_get_enrolment_end($coursecontext->instanceid, $userid); + + if ($until === false) { return false; } + if ($USER->id == $userid) { + if ($until == 0) { + $until = ENROL_MAX_TIMESTAMP; + } + $USER->enrol['enrolled'][$coursecontext->instanceid] = $until; + if (isset($USER->enrol['tempguest'][$coursecontext->instanceid])) { + unset($USER->enrol['tempguest'][$coursecontext->instanceid]); + remove_temp_course_roles($coursecontext); + } + } + } else { // any enrolment is good for us here, even outdated, disabled or inactive $sql = "SELECT 'x' @@ -2031,57 +2046,22 @@ function can_access_course(stdClass $course, $user = null, $withcapability = '', // === from here we deal only with $USER === - // verify our caches - if (!isset($USER->enrol)) { - /** - * 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(); - } + $coursecontext->reload_if_dirty(); + if (isset($USER->enrol['enrolled'][$course->id])) { - if ($USER->enrol['enrolled'][$course->id] == 0) { - return true; - } else if ($USER->enrol['enrolled'][$course->id] > time()) { + if ($USER->enrol['enrolled'][$course->id] > time()) { return true; } } if (isset($USER->enrol['tempguest'][$course->id])) { - if ($USER->enrol['tempguest'][$course->id] == 0) { - return true; - } else if ($USER->enrol['tempguest'][$course->id] > time()) { + if ($USER->enrol['tempguest'][$course->id] > time()) { return true; } } - if (is_enrolled($coursecontext, $USER, '', true)) { - // active participants may always access - // TODO: refactor this into some new function - $now = time(); - $sql = "SELECT MAX(ue.timeend) - FROM {user_enrolments} ue - JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid) - JOIN {user} u ON u.id = ue.userid - WHERE ue.userid = :userid AND ue.status = :active AND e.status = :enabled AND u.deleted = 0 - AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)"; - $params = array('enabled'=>ENROL_INSTANCE_ENABLED, 'active'=>ENROL_USER_ACTIVE, - 'userid'=>$USER->id, 'courseid'=>$coursecontext->instanceid, 'now1'=>$now, 'now2'=>$now); - $until = $DB->get_field_sql($sql, $params); - if (!$until or $until > time() + ENROL_REQUIRE_LOGIN_CACHE_PERIOD) { - $until = time() + ENROL_REQUIRE_LOGIN_CACHE_PERIOD; - } - - $USER->enrol['enrolled'][$course->id] = $until; - - // remove traces of previous temp guest access - remove_temp_course_roles($coursecontext); - + if (is_enrolled($coursecontext, $USER, '', $onlyactive)) { return true; } - unset($USER->enrol['enrolled'][$course->id]); // if not enrolled try to gain temporary guest access $instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder, id ASC'); @@ -2090,14 +2070,17 @@ function can_access_course(stdClass $course, $user = null, $withcapability = '', if (!isset($enrols[$instance->enrol])) { continue; } - // Get a duration for the guestaccess, a timestamp in the future or false. + // Get a duration for the guest access, a timestamp in the future, 0 (always) or false. $until = $enrols[$instance->enrol]->try_guestaccess($instance); - if ($until !== false) { + if ($until !== false and $until > time()) { $USER->enrol['tempguest'][$course->id] = $until; return true; } } - unset($USER->enrol['tempguest'][$course->id]); + if (isset($USER->enrol['tempguest'][$course->id])) { + unset($USER->enrol['tempguest'][$course->id]); + remove_temp_course_roles($coursecontext); + } return false; } diff --git a/lib/enrollib.php b/lib/enrollib.php index 5ddf736c06c..53c80100925 100644 --- a/lib/enrollib.php +++ b/lib/enrollib.php @@ -39,9 +39,12 @@ define('ENROL_USER_ACTIVE', 0); /** User participation in course is suspended (used in user_enrolments->status) */ define('ENROL_USER_SUSPENDED', 1); -/** Enrol info is cached for this number of seconds in require_login() */ +/** @deprecated - enrol caching was reworked, use ENROL_MAX_TIMESTAMP instead */ define('ENROL_REQUIRE_LOGIN_CACHE_PERIOD', 1800); +/** The timestamp indicating forever */ +define('ENROL_MAX_TIMESTAMP', 2147483647); + /** When user disappears from external source, the enrolment is completely removed */ define('ENROL_EXT_REMOVED_UNENROL', 0); @@ -72,7 +75,7 @@ define('ENROL_EXT_REMOVED_SUSPENDNOROLES', 3); /** * Returns instances of enrol plugins - * @param bool $enable return enabled only + * @param bool $enabled return enabled only * @return array of enrol plugins name=>instance */ function enrol_get_plugins($enabled) { @@ -804,7 +807,7 @@ function enrol_user_delete($user) { /** * Called when course is about to be deleted. - * @param stdClass $object + * @param stdClass $course * @return void */ function enrol_course_delete($course) { @@ -885,6 +888,88 @@ function enrol_selfenrol_available($courseid) { return $result; } +/** + * This function returns the end of current active user enrolment. + * + * It deals correctly with multiple overlapping user enrolments. + * + * @param int $courseid + * @param int $userid + * @return int|bool timestamp when active enrolment ends, false means no active enrolment now, 0 means never + */ +function enrol_get_enrolment_end($courseid, $userid) { + global $DB; + + $sql = "SELECT ue.* + FROM {user_enrolments} ue + JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid) + JOIN {user} u ON u.id = ue.userid + WHERE ue.userid = :userid AND ue.status = :active AND e.status = :enabled AND u.deleted = 0"; + $params = array('enabled'=>ENROL_INSTANCE_ENABLED, 'active'=>ENROL_USER_ACTIVE, 'userid'=>$userid, 'courseid'=>$courseid); + + if (!$enrolments = $DB->get_records_sql($sql, $params)) { + return false; + } + + $changes = array(); + + foreach ($enrolments as $ue) { + $start = (int)$ue->timestart; + $end = (int)$ue->timeend; + if ($end != 0 and $end < $start) { + debugging('Invalid enrolment start or end in user_enrolment id:'.$ue->id); + continue; + } + if (isset($changes[$start])) { + $changes[$start] = $changes[$start] + 1; + } else { + $changes[$start] = 1; + } + if ($end === 0) { + // no end + } else if (isset($changes[$end])) { + $changes[$end] = $changes[$end] - 1; + } else { + $changes[$end] = -1; + } + } + + // let's sort then enrolment starts&ends and go through them chronologically, + // looking for current status and the next future end of enrolment + ksort($changes); + + $now = time(); + $current = 0; + $present = null; + + foreach ($changes as $time => $change) { + if ($time > $now) { + if ($present === null) { + // we have just went past current time + $present = $current; + if ($present < 1) { + // no enrolment active + return false; + } + } + if ($present !== null) { + // we are already in the future - look for possible end + if ($current + $change < 1) { + return $time; + } + } + } + $current += $change; + } + + if ($current > 0) { + return 0; + } else { + return false; + } +} + + /** * All enrol plugins should be based on this class, * this is also the main source of documentation. @@ -1051,7 +1136,6 @@ abstract class enrol_plugin { * 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 */ public function try_autoenrol(stdClass $instance) { @@ -1067,7 +1151,6 @@ abstract class enrol_plugin { * 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 */ public function try_guestaccess(stdClass $instance) { @@ -1142,10 +1225,12 @@ abstract class enrol_plugin { $ue->courseid = $courseid; $ue->enrol = $name; events_trigger('user_enrol_modified', $ue); + // resets current enrolment caches + $context->mark_dirty(); } if ($roleid) { - // this must be done after the enrolment event so that the role_assigned event is trigerred aftwerwards + // this must be done after the enrolment event so that the role_assigned event is triggered afterwards if ($this->roles_protected()) { role_assign($roleid, $userid, $context->id, 'enrol_'.$name, $instance->id); } else { @@ -1153,7 +1238,7 @@ abstract class enrol_plugin { } } - // reset primitive require_login() caching + // reset current user enrolment caching if ($userid == $USER->id) { if (isset($USER->enrol['enrolled'][$courseid])) { unset($USER->enrol['enrolled'][$courseid]); @@ -1210,6 +1295,7 @@ abstract class enrol_plugin { $ue->modifierid = $USER->id; $DB->update_record('user_enrolments', $ue); + context_course::instance($instance->courseid)->mark_dirty(); // reset enrol caches // trigger event $ue->courseid = $instance->courseid; @@ -1275,7 +1361,11 @@ abstract class enrol_plugin { $ue->lastenrol = true; // means user not enrolled any more events_trigger('user_unenrolled', $ue); } - // reset primitive require_login() caching + + // reset all enrol caches + $context->mark_dirty(); + + // reset current user enrolment caching if ($userid == $USER->id) { if (isset($USER->enrol['enrolled'][$courseid])) { unset($USER->enrol['enrolled'][$courseid]); @@ -1508,7 +1598,7 @@ abstract class enrol_plugin { * By defaults looks for manage links only. * * @param navigation_node $instancesnode - * @param object $instance + * @param stdClass $instance * @return void */ public function add_course_navigation($instancesnode, stdClass $instance) { diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 7780f7ffcbe..46dd51b0a5c 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -2758,13 +2758,6 @@ function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $ } } - // very simple enrolment caching - changes in course setting are not reflected immediately - if (!isset($USER->enrol)) { - $USER->enrol = array(); - $USER->enrol['enrolled'] = array(); - $USER->enrol['tempguest'] = array(); - } - $access = false; if (is_viewing($coursecontext, $USER)) { @@ -2773,10 +2766,12 @@ function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $ } else { if (isset($USER->enrol['enrolled'][$course->id])) { - if ($USER->enrol['enrolled'][$course->id] == 0) { - $access = true; - } else if ($USER->enrol['enrolled'][$course->id] > time()) { + if ($USER->enrol['enrolled'][$course->id] > time()) { $access = true; + if (isset($USER->enrol['tempguest'][$course->id])) { + unset($USER->enrol['tempguest'][$course->id]); + remove_temp_course_roles($coursecontext); + } } else { //expired unset($USER->enrol['enrolled'][$course->id]); @@ -2796,60 +2791,50 @@ function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $ if ($access) { // cache ok - } else if (is_enrolled($coursecontext, $USER, '', true)) { - // active participants may always access - // TODO: refactor this into some new function - $now = time(); - $sql = "SELECT MAX(ue.timeend) - FROM {user_enrolments} ue - JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid) - JOIN {user} u ON u.id = ue.userid - WHERE ue.userid = :userid AND ue.status = :active AND e.status = :enabled AND u.deleted = 0 - AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)"; - $params = array('enabled'=>ENROL_INSTANCE_ENABLED, 'active'=>ENROL_USER_ACTIVE, - 'userid'=>$USER->id, 'courseid'=>$coursecontext->instanceid, 'now1'=>$now, 'now2'=>$now); - $until = $DB->get_field_sql($sql, $params); - if (!$until or $until > time() + ENROL_REQUIRE_LOGIN_CACHE_PERIOD) { - $until = time() + ENROL_REQUIRE_LOGIN_CACHE_PERIOD; - } - - $USER->enrol['enrolled'][$course->id] = $until; - $access = true; - - // remove traces of previous temp guest access - remove_temp_course_roles($coursecontext); - } else { - $instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder, id ASC'); - $enrols = enrol_get_plugins(true); - // first ask all enabled enrol instances in course if they want to auto enrol user - foreach($instances as $instance) { - if (!isset($enrols[$instance->enrol])) { - continue; + $until = enrol_get_enrolment_end($coursecontext->instanceid, $USER->id); + if ($until !== false) { + // active participants may always access, a timestamp in the future, 0 (always) or false. + if ($until == 0) { + $until = ENROL_MAX_TIMESTAMP; } - // 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; - remove_temp_course_roles($coursecontext); - $access = true; - break; - } - } - // if not enrolled yet try to gain temporary guest access - if (!$access) { + $USER->enrol['enrolled'][$course->id] = $until; + $access = true; + + } else { + $instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder, id ASC'); + $enrols = enrol_get_plugins(true); + // first ask all enabled enrol instances in course if they want to auto enrol user foreach($instances as $instance) { 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); + // Get a duration for the enrolment, a timestamp in the future, 0 (always) or false. + $until = $enrols[$instance->enrol]->try_autoenrol($instance); if ($until !== false) { - $USER->enrol['tempguest'][$course->id] = $until; + if ($until == 0) { + $until = ENROL_MAX_TIMESTAMP; + } + $USER->enrol['enrolled'][$course->id] = $until; $access = true; break; } } + // if not enrolled yet try to gain temporary guest access + if (!$access) { + foreach($instances as $instance) { + if (!isset($enrols[$instance->enrol])) { + continue; + } + // Get a duration for the guest access, a timestamp in the future or false. + $until = $enrols[$instance->enrol]->try_guestaccess($instance); + if ($until !== false and $until > time()) { + $USER->enrol['tempguest'][$course->id] = $until; + $access = true; + break; + } + } + } } } }