$countfields = 'SELECT COUNT(u.id)';
$sql = " FROM {user} u
- WHERE u.id IN ($enrolsql) $wherecondition
- AND u.id NOT IN (
- SELECT r.userid
- FROM {role_assignments} r
- WHERE r.contextid = :contextid
- AND r.roleid = :roleid)";
+ LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.roleid = :roleid AND ra.contextid = :contextid)
+ WHERE u.id IN ($enrolsql)
+ $wherecondition
+ AND ra.id IS NULL";
$order = ' ORDER BY lastname ASC, firstname ASC';
$params['contextid'] = $this->context->id;
$context = context::instance_by_id($contextid);
// Print the context name.
- echo $OUTPUT->heading($context->get_context_name(), 4, 'contextname');
+ echo $OUTPUT->heading(html_writer::link($context->get_url(), $context->get_context_name()),
+ 4, 'contextname');
// If there are any role assignments here, print them.
foreach ($contexts[$contextid]->roleassignments as $ra) {
}
$a = new stdClass;
$a->fullname = $fullname;
- $a->contextlevel = get_contextlevel_name($context->contextlevel);
+ $a->contextlevel = $context->get_level_name();
if ($context->contextlevel == CONTEXT_SYSTEM) {
$strgoto = get_string('gotoassignsystemroles', 'role');
$strcheck = get_string('checksystempermissionsfor', 'role', $a);
$setting = new admin_setting_configcheckbox('cachejs', new lang_string('cachejs', 'admin'), new lang_string('cachejs_help', 'admin'), 1);
$setting->set_updatedcallback('js_reset_all_caches');
$temp->add($setting);
+ $temp->add(new admin_setting_configcheckbox('modchooserdefault', new lang_string('modchooserdefault', 'admin'), new lang_string('configmodchooserdefault', 'admin'), 1));
$ADMIN->add('appearance', $temp);
// link to tag management interface
$temp->add(new admin_setting_configselect('moodlecourse/legacyfiles', new lang_string('courselegacyfiles'), new lang_string('courselegacyfiles_help'), key($choices), $choices));
}
+ $choices = array();
+ $choices[COURSE_DISPLAY_SINGLEPAGE] = new lang_string('coursedisplay_single');
+ $choices[COURSE_DISPLAY_MULTIPAGE] = new lang_string('coursedisplay_multi');
+ $temp->add(new admin_setting_configselect('moodlecourse/coursedisplay', new lang_string('coursedisplay'), new lang_string('coursedisplay_help'), COURSE_DISPLAY_SINGLEPAGE, $choices));
+
$temp->add(new admin_setting_heading('groups', new lang_string('groups', 'group'), ''));
$choices = array();
$choices[NOGROUPS] = new lang_string('groupsnone', 'group');
$temp->add(new admin_setting_heading('iplookup', new lang_string('iplookup', 'admin'), new lang_string('iplookupinfo', 'admin')));
$temp->add(new admin_setting_configfile('geoipfile', new lang_string('geoipfile', 'admin'), new lang_string('configgeoipfile', 'admin', $CFG->dataroot.'/geoip/'), $CFG->dataroot.'/geoip/GeoLiteCity.dat'));
- $temp->add(new admin_setting_configtext('googlemapkey', new lang_string('googlemapkey', 'admin'), new lang_string('configgooglemapkey', 'admin', $CFG->wwwroot), ''));
+ $temp->add(new admin_setting_configtext('googlemapkey', new lang_string('googlemapkey', 'admin'), new lang_string('configgooglemapkey', 'admin', $CFG->wwwroot), '', PARAM_RAW, 60));
+ $temp->add(new admin_setting_configtext('googlemapkey3', new lang_string('googlemapkey3', 'admin'), new lang_string('googlemapkey3_help', 'admin'), '', PARAM_RAW, 60));
$temp->add(new admin_setting_configtext('allcountrycodes', new lang_string('allcountrycodes', 'admin'), new lang_string('configallcountrycodes', 'admin'), '', '/^(?:\w+(?:,\w+)*)?$/'));
} else if ($drop) {
// make sure tests do not run in parallel
phpunit_util::acquire_test_lock();
- phpunit_util::drop_site();
+ phpunit_util::drop_site(true);
// note: we must stop here because $CFG is messed up and we can not reinstall, sorry
exit(0);
if ($duration > 0) { // sanity check
$timeend = $today + $duration;
}
+ } else if ($manualcache[$courseid]->enrolperiod > 0) {
+ $timeend = $today + $manualcache[$courseid]->enrolperiod;
}
$manual->enrol_user($manualcache[$courseid], $user->id, $rid, $today, $timeend);
} else if ($user->secret == $confirmsecret) { // They have provided the secret key to get in
$DB->set_field("user", "confirmed", 1, array("id"=>$user->id));
- $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+ if ($user->firstaccess == 0) {
+ $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+ }
return AUTH_CONFIRM_OK;
}
} else {
return AUTH_CONFIRM_FAIL;
}
$DB->set_field('user', 'confirmed', 1, array('id'=>$user->id));
- $DB->set_field('user', 'firstaccess', time(), array('id'=>$user->id));
+ if ($user->firstaccess == 0) {
+ $DB->set_field('user', 'firstaccess', time(), array('id'=>$user->id));
+ }
return AUTH_CONFIRM_OK;
}
} else {
return AUTH_CONFIRM_ALREADY;
} else {
$DB->set_field("user", "confirmed", 1, array("id"=>$user->id));
- $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+ if ($user->firstaccess == 0) {
+ $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+ }
return AUTH_CONFIRM_OK;
}
} else {
// Define activity_userinfo. Dependent of:
// - users root setting
// - section_userinfo setting (if exists)
- // - activity_included setting
+ // - activity_included setting.
$settingname = $settingprefix . 'userinfo';
- $selectvalues = array(0=>get_string('no')); // Safer options
- $defaultvalue = false; // Safer default
+ $defaultvalue = false;
if (isset($this->info->settings[$settingname]) && $this->info->settings[$settingname]) { // Only enabled when available
- $selectvalues = array(1=>get_string('yes'), 0=>get_string('no'));
$defaultvalue = true;
}
+
$activity_userinfo = new restore_activity_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue);
- $activity_userinfo->set_ui(new backup_setting_ui_select($activity_userinfo, get_string('includeuserinfo','backup'), $selectvalues));
+ if (!$defaultvalue) {
+ // This is a bit hacky, but if there is no user data to restore, then
+ // we replace the standard check-box with a select menu with the
+ // single choice 'No', and the select menu is clever enough that if
+ // there is only one choice, it just displays a static string.
+ //
+ // It would probably be better design to have a special UI class
+ // setting_ui_checkbox_or_no, rather than this hack, but I am not
+ // going to do that today.
+ $activity_userinfo->set_ui(new backup_setting_ui_select($activity_userinfo, '-',
+ array(0 => get_string('no'))));
+ } else {
+ $activity_userinfo->get_ui()->set_label('-');
+ }
+
$this->add_setting($activity_userinfo);
+
// Look for "users" root setting
$users = $this->plan->get_setting('users');
$users->add_dependency($activity_userinfo);
+
// Look for "section_userinfo" section setting (if exists)
$settingname = 'section_' . $this->info->sectionid . '_userinfo';
if ($this->plan->setting_exists($settingname)) {
$section_userinfo = $this->plan->get_setting($settingname);
$section_userinfo->add_dependency($activity_userinfo);
}
- // Look for "activity_included" setting
+
+ // Look for "activity_included" setting.
$activity_included->add_dependency($activity_userinfo);
- // End of common activity settings, let's add the particular ones
+ // End of common activity settings, let's add the particular ones.
$this->define_my_settings();
}
// Define section_userinfo. Dependent of:
// - users root setting
- // - section_included setting
+ // - section_included setting.
$settingname = $settingprefix . 'userinfo';
- $selectvalues = array(0=>get_string('no')); // Safer options
- $defaultvalue = false; // Safer default
+ $defaultvalue = false;
if (isset($this->info->settings[$settingname]) && $this->info->settings[$settingname]) { // Only enabled when available
- $selectvalues = array(1=>get_string('yes'), 0=>get_string('no'));
$defaultvalue = true;
}
+
$section_userinfo = new restore_section_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue);
- $section_userinfo->set_ui(new backup_setting_ui_select($section_userinfo, get_string('includeuserinfo','backup'), $selectvalues));
+ if (!$defaultvalue) {
+ // This is a bit hacky, but if there is no user data to restore, then
+ // we replace the standard check-box with a select menu with the
+ // single choice 'No', and the select menu is clever enough that if
+ // there is only one choice, it just displays a static string.
+ //
+ // It would probably be better design to have a special UI class
+ // setting_ui_checkbox_or_no, rather than this hack, but I am not
+ // going to do that today.
+ $section_userinfo->set_ui(new backup_setting_ui_select($section_userinfo, get_string('includeuserinfo','backup'),
+ array(0 => get_string('no'))));
+ } else {
+ $section_userinfo->get_ui()->set_label(get_string('includeuserinfo','backup'));
+ }
+
$this->add_setting($section_userinfo);
- // Look for "users" root setting
+
+ // Look for "users" root setting.
$users = $this->plan->get_setting('users');
$users->add_dependency($section_userinfo);
- // Look for "section_included" section setting
+
+ // Look for "section_included" section setting.
$section_included->add_dependency($section_userinfo);
}
}
// Get all sections belonging to requested course
$sectionsarr = array();
- $sections = $DB->get_records('course_sections', array('course' => $courseid));
+ $sections = $DB->get_records('course_sections', array('course' => $courseid), 'section');
foreach ($sections as $section) {
$sectionsarr[] = $section->id;
}
$nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup($admin->timezone, $now);
$showtime = "undefined";
if ($nextstarttime > 0) {
- $showtime = userdate($nextstarttime,"",$admin->timezone);
+ $showtime = date('r', $nextstarttime);
}
$rs = $DB->get_recordset('course');
}
// Skip courses that do not yet need backup
- $skipped = !(($backupcourse->nextstarttime >= 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
+ $skipped = !(($backupcourse->nextstarttime > 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
+ if ($skipped && $backupcourse->nextstarttime != $nextstarttime) {
+ $backupcourse->nextstarttime = $nextstarttime;
+ $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
+ $DB->update_record('backup_courses', $backupcourse);
+ mtrace('Backup of \'' . $course->fullname . '\' is scheduled on ' . $showtime);
+ }
+
// Skip backup of unavailable courses that have remained unmodified in a month
if (!$skipped && empty($course->visible) && ($now - $course->timemodified) > 31*24*60*60) { //Hidden + settings were unmodified last month
//Check log if there were any modifications to the course content
$skipped = true;
}
}
+
//Now we backup every non-skipped course
if (!$skipped) {
- mtrace('Backing up '.$course->fullname, '...');
+ mtrace('Backing up '.$course->fullname.'...');
//We have to send a email because we have included at least one backup
$emailpending = true;
self::BACKUP_STATUS_SKIPPED => 0,
);
- $statuses = $DB->get_records_sql('SELECT DISTINCT bc.laststatus, COUNT(bc.courseid) statuscount FROM {backup_courses} bc GROUP BY bc.laststatus');
+ $statuses = $DB->get_records_sql('SELECT DISTINCT bc.laststatus, COUNT(bc.courseid) AS statuscount FROM {backup_courses} bc GROUP BY bc.laststatus');
foreach ($statuses as $status) {
if (empty($status->statuscount)) {
/**
* Works out the next time the automated backup should be run.
*
- * @param mixed $timezone
- * @param int $now
- * @return int
+ * @param mixed $timezone user timezone
+ * @param int $now timestamp, should not be in the past, most likely time()
+ * @return int timestamp of the next execution at server time
*/
public static function calculate_next_automated_backup($timezone, $now) {
- $result = -1;
+ $result = 0;
$config = get_config('backup');
- $midnight = usergetmidnight($now, $timezone);
+ $autohour = $config->backup_auto_hour;
+ $automin = $config->backup_auto_minute;
+
+ // Gets the user time relatively to the server time.
$date = usergetdate($now, $timezone);
+ $usertime = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
+ $diff = $now - $usertime;
- // Get number of days (from today) to execute backups
+ // Get number of days (from user's today) to execute backups.
$automateddays = substr($config->backup_auto_weekdays, $date['wday']) . $config->backup_auto_weekdays;
- $daysfromtoday = strpos($automateddays, "1", 1);
+ $daysfromnow = strpos($automateddays, "1");
- // If we can't find the next day, we set it to tomorrow
- if (empty($daysfromtoday)) {
- $daysfromtoday = 1;
+ // Error, there are no days to schedule the backup for.
+ if ($daysfromnow === false) {
+ return 0;
}
- // If some day has been found
- if ($daysfromtoday !== false) {
- // Calculate distance
- $dist = ($daysfromtoday * 86400) + // Days distance
- ($config->backup_auto_hour * 3600) + // Hours distance
- ($config->backup_auto_minute * 60); // Minutes distance
- $result = $midnight + $dist;
+ // Checks if the date would happen in the future (of the user).
+ $userresult = mktime($autohour, $automin, 0, $date['mon'], $date['mday'] + $daysfromnow, $date['year']);
+ if ($userresult <= $usertime) {
+ // If not, we skip the first scheduled day, that should fix it.
+ $daysfromnow = strpos($automateddays, "1", 1);
+ $userresult = mktime($autohour, $automin, 0, $date['mon'], $date['mday'] + $daysfromnow, $date['year']);
}
- // If that time is past, call the function recursively to obtain the next valid day
- if ($result > 0 && $result < time()) {
- $result = self::calculate_next_automated_backup($timezone, $result);
+ // Now we generate the time relative to the server.
+ $result = $userresult + $diff;
+
+ // If that time is past, call the function recursively to obtain the next valid day.
+ if ($result <= $now) {
+ // Checking time() in here works, but makes PHPUnit Tests extremely hard to predict.
+ // $now should never be earlier than time() anyway...
+ $result = self::calculate_next_automated_backup($timezone, $now + DAYSECS);
}
return $result;
$config = get_config('backup');
$active = (int)$config->backup_auto_active;
- if ($active === self::AUTO_BACKUP_DISABLED || ($rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL)) {
+ $weekdays = (string)$config->backup_auto_weekdays;
+
+ // In case of automated backup also check that it is scheduled for at least one weekday.
+ if ($active === self::AUTO_BACKUP_DISABLED ||
+ ($rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL) ||
+ ($rundirective == self::RUN_ON_SCHEDULE && strpos($weekdays, '1') === false)) {
return self::STATE_DISABLED;
} else if (!empty($config->backup_auto_running)) {
// Detect if the backup_auto_running semaphore is a valid one
if (!empty($dir) && ($storage == 1 || $storage == 2)) {
// Calculate backup filename regex, ignoring the date/time/info parts that can be
// variable, depending of languages, formats and automated backup settings
- $filename = $backupword . '-' . backup::FORMAT_MOODLE . '-' . backup::TYPE_1COURSE . '-' .$course->id . '-';
+
+
+ // MDL-33531: use different filenames depending on backup_shortname option
+ if ( !empty($config->backup_shortname) ) {
+ $context = get_context_instance(CONTEXT_COURSE, $course->id);
+ $courseref = format_string($course->shortname, true, array('context' => $context));
+ $courseref = str_replace(' ', '_', $courseref);
+ $courseref = textlib::strtolower(trim(clean_filename($courseref), '_'));
+ } else {
+ $courseref = $course->id;
+ }
+ $filename = $backupword . '-' . backup::FORMAT_MOODLE . '-' . backup::TYPE_1COURSE . '-' .$courseref . '-';
$regex = '#^'.preg_quote($filename, '#').'.*\.mbz$#';
// Store all the matching files into fullpath => timemodified array
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for backups cron helper.
+ *
+ * @package core_backup
+ * @category phpunit
+ * @copyright 2012 Frédéric Massart <fred@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/backup/util/helper/backup_cron_helper.class.php');
+
+/**
+ * Unit tests for backup cron helper
+ */
+class backup_cron_helper_testcase extends advanced_testcase {
+
+ /**
+ * Test {@link backup_cron_automated_helper::calculate_next_automated_backup}.
+ */
+ public function test_next_automated_backup() {
+ $this->resetAfterTest();
+ set_config('backup_auto_active', '1', 'backup');
+
+ // Notes
+ // - backup_auto_weekdays starts on Sunday
+ // - Tests cannot be done in the past
+ // - Only the DST on the server side is handled.
+
+ // Every Tue and Fri at 11pm.
+ set_config('backup_auto_weekdays', '0010010', 'backup');
+ set_config('backup_auto_hour', '23', 'backup');
+ set_config('backup_auto_minute', '0', 'backup');
+ $timezone = 99;
+
+ $now = strtotime('next Monday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+ $now = strtotime('next Tuesday 18:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+ $now = strtotime('next Wednesday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+ $now = strtotime('next Thursday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+ $now = strtotime('next Friday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+ $now = strtotime('next Saturday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+ $now = strtotime('next Sunday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+ // Every Sun and Sat at 12pm.
+ set_config('backup_auto_weekdays', '1000001', 'backup');
+ set_config('backup_auto_hour', '0', 'backup');
+ set_config('backup_auto_minute', '0', 'backup');
+ $timezone = 99;
+
+ $now = strtotime('next Monday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Tuesday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Wednesday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Thursday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Friday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Saturday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Sunday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+ // Every Sun at 4am.
+ set_config('backup_auto_weekdays', '1000000', 'backup');
+ set_config('backup_auto_hour', '4', 'backup');
+ set_config('backup_auto_minute', '0', 'backup');
+ $timezone = 99;
+
+ $now = strtotime('next Monday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+ $now = strtotime('next Tuesday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+ $now = strtotime('next Wednesday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+ $now = strtotime('next Thursday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+ $now = strtotime('next Friday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+ $now = strtotime('next Saturday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+ $now = strtotime('next Sunday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+ // Every day but Wed at 8:30pm.
+ set_config('backup_auto_weekdays', '1110111', 'backup');
+ set_config('backup_auto_hour', '20', 'backup');
+ set_config('backup_auto_minute', '30', 'backup');
+ $timezone = 99;
+
+ $now = strtotime('next Monday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('1-20:30', date('w-H:i', $next));
+
+ $now = strtotime('next Tuesday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('2-20:30', date('w-H:i', $next));
+
+ $now = strtotime('next Wednesday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('4-20:30', date('w-H:i', $next));
+
+ $now = strtotime('next Thursday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('4-20:30', date('w-H:i', $next));
+
+ $now = strtotime('next Friday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('5-20:30', date('w-H:i', $next));
+
+ $now = strtotime('next Saturday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('6-20:30', date('w-H:i', $next));
+
+ $now = strtotime('next Sunday 17:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0-20:30', date('w-H:i', $next));
+
+ // Sun, Tue, Thu, Sat at 12pm.
+ set_config('backup_auto_weekdays', '1010101', 'backup');
+ set_config('backup_auto_hour', '0', 'backup');
+ set_config('backup_auto_minute', '0', 'backup');
+ $timezone = 99;
+
+ $now = strtotime('next Monday 13:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('2-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Tuesday 13:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('4-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Wednesday 13:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('4-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Thursday 13:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Friday 13:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Saturday 13:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0-00:00', date('w-H:i', $next));
+
+ $now = strtotime('next Sunday 13:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('2-00:00', date('w-H:i', $next));
+
+ // None.
+ set_config('backup_auto_weekdays', '0000000', 'backup');
+ set_config('backup_auto_hour', '15', 'backup');
+ set_config('backup_auto_minute', '30', 'backup');
+ $timezone = 99;
+
+ $now = strtotime('next Sunday 13:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals('0', $next);
+
+ // Playing with timezones.
+ set_config('backup_auto_weekdays', '1111111', 'backup');
+ set_config('backup_auto_hour', '20', 'backup');
+ set_config('backup_auto_minute', '00', 'backup');
+
+ $timezone = 99;
+ date_default_timezone_set('Australia/Perth');
+ $now = strtotime('18:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+ $timezone = 99;
+ date_default_timezone_set('Europe/Brussels');
+ $now = strtotime('18:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+ $timezone = 99;
+ date_default_timezone_set('America/New_York');
+ $now = strtotime('18:00:00');
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+ // Viva Australia! (UTC+8).
+ date_default_timezone_set('Australia/Perth');
+ $now = strtotime('18:00:00');
+
+ $timezone = -10.0; // 12am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals(date('w-14:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+ $timezone = -5.0; // 5am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals(date('w-09:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+ $timezone = 0.0; // 10am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals(date('w-04:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+ $timezone = 3.0; // 1pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals(date('w-01:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+ $timezone = 8.0; // 6pm for the user (same than the server).
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+ $timezone = 9.0; // 7pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals(date('w-19:00'), date('w-H:i', $next));
+
+ $timezone = 13.0; // 12am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $this->assertEquals(date('w-15:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+ // Let's have a Belgian beer! (UTC+1 / UTC+2 DST).
+ date_default_timezone_set('Europe/Brussels');
+ $now = strtotime('18:00:00');
+ $dst = date('I');
+
+ $timezone = -10.0; // 7am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = -5.0; // 12pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 0.0; // 5pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-21:00') : date('w-22:00');
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 3.0; // 8pm for the user (note the expected time is today while in DST).
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-18:00', strtotime('tomorrow')) : date('w-19:00');
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 8.0; // 1am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-13:00', strtotime('tomorrow')) : date('w-14:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 9.0; // 2am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 13.0; // 6am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-08:00', strtotime('tomorrow')) : date('w-09:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ // The big apple! (UTC-5 / UTC-4 DST).
+ date_default_timezone_set('America/New_York');
+ $now = strtotime('18:00:00');
+ $dst = date('I');
+
+ $timezone = -10.0; // 1pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-01:00', strtotime('tomorrow')) : date('w-02:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = -5.0; // 6pm for the user (server time).
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-20:00') : date('w-21:00');
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 0.0; // 11pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-15:00', strtotime('tomorrow')) : date('w-16:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 3.0; // 2am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 8.0; // 7am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 9.0; // 8am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-06:00', strtotime('tomorrow')) : date('w-07:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 13.0; // 6am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ // Some more timezone tests
+ set_config('backup_auto_weekdays', '0100001', 'backup');
+ set_config('backup_auto_hour', '20', 'backup');
+ set_config('backup_auto_minute', '00', 'backup');
+
+ date_default_timezone_set('Europe/Brussels');
+ $now = strtotime('next Monday 18:00:00');
+ $dst = date('I');
+
+ $timezone = -12.0; // 1pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '2-09:00' : '2-10:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = -4.0; // 1pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '2-01:00' : '2-02:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 0.0; // 5pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '1-21:00' : '1-22:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 2.0; // 7pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '1-19:00' : '1-20:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 4.0; // 9pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '6-17:00' : '6-18:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 12.0; // 6am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '6-09:00' : '6-10:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ // Some more timezone tests
+ set_config('backup_auto_weekdays', '0100001', 'backup');
+ set_config('backup_auto_hour', '02', 'backup');
+ set_config('backup_auto_minute', '00', 'backup');
+
+ date_default_timezone_set('America/New_York');
+ $now = strtotime('next Monday 04:00:00');
+ $dst = date('I');
+
+ $timezone = -12.0; // 8pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '1-09:00' : '1-10:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = -4.0; // 4am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '6-01:00' : '6-02:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 0.0; // 8am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '5-21:00' : '5-22:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 2.0; // 10am for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '5-19:00' : '5-20:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 4.0; // 12pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '5-17:00' : '5-18:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ $timezone = 12.0; // 8pm for the user.
+ $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+ $expected = !$dst ? '5-09:00' : '5-10:00';
+ $this->assertEquals($expected, date('w-H:i', $next));
+
+ }
+}
* @global moodle_page $PAGE
*/
function definition_after_data() {
- global $PAGE;
$buttonarray=array();
$buttonarray[] = $this->_form->createElement('submit', 'submitbutton', get_string($this->uistage->get_ui()->get_name().'stage'.$this->uistage->get_stage().'action', 'backup'), array('class'=>'proceedbutton'));
if (!$this->uistage->is_first_stage()) {
$this->_form->addGroup($buttonarray, 'buttonar', '', array(' '), false);
$this->_form->closeHeaderBefore('buttonar');
- $config = new stdClass;
- $config->title = get_string('confirmcancel', 'backup');
- $config->question = get_string('confirmcancelquestion', 'backup');
- $config->yesLabel = get_string('confirmcancelyes', 'backup');
- $config->noLabel = get_string('confirmcancelno', 'backup');
- $PAGE->requires->yui_module('moodle-backup-confirmcancel', 'M.core_backup.watch_cancel_buttons', array($config));
+ $this->_definition_finalized = true;
}
+
/**
* Closes any open divs
*/
* Displays the form
*/
public function display() {
+ global $PAGE;
+
$this->require_definition_after_data();
+
+ $config = new stdClass;
+ $config->title = get_string('confirmcancel', 'backup');
+ $config->question = get_string('confirmcancelquestion', 'backup');
+ $config->yesLabel = get_string('confirmcancelyes', 'backup');
+ $config->noLabel = get_string('confirmcancelno', 'backup');
+ $PAGE->requires->yui_module('moodle-backup-confirmcancel', 'M.core_backup.watch_cancel_buttons', array($config));
+
+ $PAGE->requires->yui_module('moodle-backup-backupselectall', 'M.core_backup.select_all_init',
+ array(array('select' => get_string('select'), 'all' => get_string('all'), 'none' => get_string('none'))));
+
parent::display();
}
*/
public function require_definition_after_data() {
if (!$this->_definition_finalized) {
- $this->_definition_finalized = true;
$this->definition_after_data();
}
}
--- /dev/null
+YUI.add('moodle-backup-backupselectall', function(Y) {
+
+// Namespace for the backup
+M.core_backup = M.core_backup || {};
+
+/**
+ * Adds select all/none links to the top of the backup/restore/import schema page.
+ */
+M.core_backup.select_all_init = function(str) {
+ var formid = null;
+
+ var helper = function(e, check, type) {
+ e.preventDefault();
+
+ var len = type.length;
+ Y.all('input[type="checkbox"]').each(function(checkbox) {
+ var name = checkbox.get('name');
+ if (name.substring(name.length - len) == type) {
+ checkbox.set('checked', check);
+ }
+ });
+
+ // At this point, we really need to persuade the form we are part of to
+ // update all of its disabledIf rules. However, as far as I can see,
+ // given the way that lib/form/form.js is written, that is impossible.
+ if (formid && M.form) {
+ M.form.updateFormState(formid);
+ }
+ };
+
+ var html_generator = function(classname, idtype) {
+ return '<div class="' + classname + '">' +
+ '<div class="fitem fitem_fcheckbox">' +
+ '<div class="fitemtitle">' + str.select + '</div>' +
+ '<div class="felement">' +
+ '<a id="backup-all-' + idtype + '" href="#">' + str.all + '</a> / ' +
+ '<a id="backup-none-' + idtype + '" href="#">' + str.none + '</a>' +
+ '</div>' +
+ '</div>' +
+ '</div>';
+ };
+
+ var firstsection = Y.one('fieldset#coursesettings .fcontainer.clearfix .grouped_settings.section_level');
+ if (!firstsection) {
+ // This is not a relevant page.
+ return;
+ }
+ if (!firstsection.one('.felement.fcheckbox')) {
+ // No checkboxes.
+ return;
+ }
+
+ formid = firstsection.ancestor('form').getAttribute('id');
+
+ var withuserdata = false;
+ Y.all('input[type="checkbox"]').each(function(checkbox) {
+ var name = checkbox.get('name');
+ if (name.substring(name.length - 9) == '_userdata') {
+ withuserdata = '_userdata';
+ } else if (name.substring(name.length - 9) == '_userinfo') {
+ withuserdata = '_userinfo';
+ }
+ });
+
+ var html = html_generator('include_setting section_level', 'included');
+ if (withuserdata) {
+ html += html_generator('normal_setting', 'userdata');
+ }
+ var links = Y.Node.create('<div class="grouped_settings section_level">' + html + '</div>');
+ firstsection.insert(links, 'before');
+
+ Y.one('#backup-all-included').on('click', function(e) { helper(e, true, '_included'); });
+ Y.one('#backup-none-included').on('click', function(e) { helper(e, false, '_included'); });
+ if (withuserdata) {
+ Y.one('#backup-all-userdata').on('click', function(e) { helper(e, true, withuserdata); });
+ Y.one('#backup-none-userdata').on('click', function(e) { helper(e, false, withuserdata); });
+ }
+}
+
+}, '@VERSION@', {'requires':['base','node','event', 'node-event-simulate']});
$icon = html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('i/group'),
'class' => 'icon', 'alt' => get_string('addcourse', 'block_community')));
$addcourseurl = new moodle_url('/blocks/community/communitycourse.php',
- array('add' => true, 'courseid' => $coursecontext->instanceid));
+ array('add' => true, 'courseid' => $this->page->course->id));
$searchlink = html_writer::tag('a', $icon . ' ' . get_string('addcourse', 'block_community'),
array('href' => $addcourseurl->out(false)));
$this->content->items[] = $searchlink;
'alt' => get_string('removecommunitycourse', 'block_community')));
$deleteurl = new moodle_url('/blocks/community/communitycourse.php',
array('remove' => true,
- 'courseid' => $coursecontext->instanceid,
+ 'courseid' => $this->page->course->id,
'communityid' => $course->id, 'sesskey' => sesskey()));
$deleteatag = html_writer::tag('a', $deleteicon, array('href' => $deleteurl));
$courses_limit = $courses_limit + 1;
}
- $courses = enrol_get_my_courses('id, shortname, modinfo', 'visible DESC,sortorder ASC', $courses_limit);
+ $courses = enrol_get_my_courses('id, shortname, modinfo, sectioncache', 'visible DESC,sortorder ASC', $courses_limit);
$site = get_site();
$course = $site; //just in case we need the old global $course hack
$tooltiptext = get_string('rsssubscriberssposts','forum');
}
if (!isloggedin()) {
- $userid = 0;
+ $userid = $CFG->siteguest;
} else {
$userid = $USER->id;
}
global $CFG, $COURSE, $SITE, $USER, $SCRIPT, $OUTPUT;
if (empty($CFG->usetags)) {
+ $this->content = new stdClass();
$this->content->text = '';
if ($this->page->user_is_editing()) {
$this->content->text = get_string('disabledtags', 'block_tags');
$allmodnames = array();
if (!empty($CFG->useblogassociations)) {
- if ((!empty($entry->courseassoc) || (!empty($courseid) && empty($modid))) && has_capability('moodle/blog:associatecourse', $sitecontext)) {
+ if ((!empty($entry->courseassoc) || (!empty($courseid) && empty($modid)))) {
if (!empty($courseid)) {
$course = $DB->get_record('course', array('id' => $courseid));
- $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
- $context = get_context_instance(CONTEXT_COURSE, $courseid);
+ $context = context_course::instance($courseid);
$a = new stdClass();
$a->coursename = format_string($course->fullname, true, array('context' => $context));
$contextid = $context->id;
} else {
+ $context = context::instance_by_id($entry->courseassoc);
$sql = 'SELECT fullname FROM {course} cr LEFT JOIN {context} ct ON ct.instanceid = cr.id WHERE ct.id = ?';
$a = new stdClass();
$a->coursename = $DB->get_field_sql($sql, array($entry->courseassoc));
$contextid = $entry->courseassoc;
}
- $mform->addElement('advcheckbox', 'courseassoc', get_string('associatewithcourse', 'blog', $a), null, null, array(0, $contextid));
- $mform->setDefault('courseassoc', $contextid);
- } else if ((!empty($entry->modassoc) || !empty($modid)) && has_capability('moodle/blog:associatemodule', $sitecontext)) {
+ if (has_capability('moodle/blog:associatecourse', $context)) {
+ $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));\r
+ $mform->addElement('advcheckbox', 'courseassoc', get_string('associatewithcourse', 'blog', $a), null, null, array(0, $contextid));\r
+ $mform->setDefault('courseassoc', $contextid);
+ }
+
+ } else if ((!empty($entry->modassoc) || !empty($modid))) {
if (!empty($modid)) {
$mod = get_coursemodule_from_id(false, $modid);
$a = new stdClass();
$modid = $context->instanceid;
}
- $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
- $mform->addElement('advcheckbox', 'modassoc', get_string('associatewithmodule', 'blog', $a), null, null, array(0, $context->id));
- $mform->setDefault('modassoc', $context->id);
+ if (has_capability('moodle/blog:associatemodule', $context)) {
+ $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
+ $mform->addElement('advcheckbox', 'modassoc', get_string('associatewithmodule', 'blog', $a), null, null, array(0, $context->id));
+ $mform->setDefault('modassoc', $context->id);
+ }
}
}
global $CFG, $DB, $USER;
$errors = array();
- $sitecontext = get_context_instance(CONTEXT_SYSTEM);
// validate course association
- if (!empty($data['courseassoc']) && has_capability('moodle/blog:associatecourse', $sitecontext)) {
+ if (!empty($data['courseassoc'])) {
$coursecontext = context::instance_by_id($data['courseassoc'], IGNORE_MISSING);
- if ($coursecontext and $coursecontext->contextlevel == CONTEXT_COURSE) {
+ $canassociatecourse = has_capability('moodle/blog:associatecourse', $coursecontext);
+ if ($coursecontext->contextlevel == CONTEXT_COURSE && $canassociatecourse) {
if (!is_enrolled($coursecontext) and !is_viewing($coursecontext)) {
$errors['courseassoc'] = get_string('studentnotallowed', '', fullname($USER, true));
}
$modcontextid = $data['modassoc'];
$modcontext = context::instance_by_id($modcontextid, IGNORE_MISSING);
- if ($modcontext and $modcontext->contextlevel == CONTEXT_MODULE) {
+ $canassociatemodule = has_capability('moodle/blog:associatecourse', $modcontext);
+ if ($modcontext->contextlevel == CONTEXT_MODULE && $canassociatemodule) {
// get context of the mod's course
$coursecontext = $modcontext->get_course_context(true);
}
// Check that the user can associate with the course
- $sitecontext = get_context_instance(CONTEXT_SYSTEM);
- if (!has_capability('moodle/blog:associatecourse', $sitecontext)) {
+ $sitecontext = context_system::instance();
+ $coursecontext = context_course::instance($course->id);
+ if (!has_capability('moodle/blog:associatecourse', $coursecontext)) {
return $options;
}
// Generate the cache key
return $courseoptions[$key];
}
- $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
$canparticipate = (is_enrolled($coursecontext) or is_viewing($coursecontext));
if (has_capability('moodle/blog:view', $coursecontext)) {
}
// Check the user can associate with the module
- $sitecontext = get_context_instance(CONTEXT_SYSTEM);
- if (!has_capability('moodle/blog:associatemodule', $sitecontext)) {
+ $modcontext = context_module::instance($module->id);
+ $sitecontext = context_system::instance();
+ if (!has_capability('moodle/blog:associatemodule', $modcontext)) {
return $options;
}
return $moduleoptions[$module->id];
}
- $modcontext = get_context_instance(CONTEXT_MODULE, $module->id);
$canparticipate = (is_enrolled($modcontext) or is_viewing($modcontext));
if (has_capability('moodle/blog:view', $modcontext)) {
$PAGE->set_pagelayout('standard');
- if (!empty($modid) && $CFG->useblogassociations && has_capability('moodle/blog:associatemodule', $sitecontext)) { // modid always overrides courseid, so the $course object may be reset here
+ // modid always overrides courseid, so the $course object may be reset here
+ if (!empty($modid) && $CFG->useblogassociations) {
+
$headers['filters']['module'] = $modid;
// A groupid param may conflict with this coursemod's courseid. Ignore groupid in that case
$courseid = $DB->get_field('course_modules', 'course', array('id'=>$modid));
array(COURSE_DISPLAY_SINGLEPAGE => get_string('coursedisplay_single'),
COURSE_DISPLAY_MULTIPAGE => get_string('coursedisplay_multi')));
$mform->addHelpButton('coursedisplay', 'coursedisplay');
- $mform->setDefault('coursedisplay', COURSE_DISPLAY_SINGLEPAGE);
+ $mform->setDefault('coursedisplay', $courseconfig->coursedisplay);
for ($i = 0; $i <= $courseconfig->maxsections; $i++) {
$sectionmenu[$i] = "$i";
return array();
}
- if (!has_capability('moodle/course:update', context_course::instance($course->id))) {
- return array();
- }
+ $coursecontext = context_course::instance($course->id);
if ($onsectionpage) {
$baseurl = course_get_url($course, $section->section);
$controls = array();
$url = clone($baseurl);
- if ($section->visible) { // Show the hide/show eye.
- $strhidefromothers = get_string('hidefromothers', 'format_'.$course->format);
- $url->param('hide', $section->section);
- $controls[] = html_writer::link($url,
- html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/hide'),
- 'class' => 'icon hide', 'alt' => $strhidefromothers)),
- array('title' => $strhidefromothers, 'class' => 'editing_showhide'));
- } else {
- $strshowfromothers = get_string('showfromothers', 'format_'.$course->format);
- $url->param('show', $section->section);
- $controls[] = html_writer::link($url,
- html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/show'),
- 'class' => 'icon hide', 'alt' => $strshowfromothers)),
- array('title' => $strshowfromothers, 'class' => 'editing_showhide'));
+ if (has_capability('moodle/course:sectionvisibility', $coursecontext)) {
+ if ($section->visible) { // Show the hide/show eye.
+ $strhidefromothers = get_string('hidefromothers', 'format_'.$course->format);
+ $url->param('hide', $section->section);
+ $controls[] = html_writer::link($url,
+ html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/hide'),
+ 'class' => 'icon hide', 'alt' => $strhidefromothers)),
+ array('title' => $strhidefromothers, 'class' => 'editing_showhide'));
+ } else {
+ $strshowfromothers = get_string('showfromothers', 'format_'.$course->format);
+ $url->param('show', $section->section);
+ $controls[] = html_writer::link($url,
+ html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/show'),
+ 'class' => 'icon hide', 'alt' => $strshowfromothers)),
+ array('title' => $strshowfromothers, 'class' => 'editing_showhide'));
+ }
}
- if (!$onsectionpage) {
+ if (!$onsectionpage && has_capability('moodle/course:update', $coursecontext)) {
$url = clone($baseurl);
if ($section->section > 1) { // Add a arrow to move section up.
$url->param('section', $section->section);
$renderer = $PAGE->get_renderer('format_topics');
-if (!empty($displaysection) && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
+if (!empty($displaysection)) {
$renderer->print_single_section_page($course, $sections, $mods, $modnames, $modnamesused, $displaysection);
} else {
$renderer->print_multiple_section_page($course, $sections, $mods, $modnames, $modnamesused);
return array();
}
- if (!has_capability('moodle/course:update', context_course::instance($course->id))) {
- return array();
- }
+ $coursecontext = context_course::instance($course->id);
if ($onsectionpage) {
$url = course_get_url($course, $section->section);
$url->param('sesskey', sesskey());
$controls = array();
- if ($course->marker == $section->section) { // Show the "light globe" on/off.
- $url->param('marker', 0);
- $controls[] = html_writer::link($url,
- html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/marked'),
- 'class' => 'icon ', 'alt' => get_string('markedthistopic'))),
- array('title' => get_string('markedthistopic'), 'class' => 'editing_highlight'));
- } else {
- $url->param('marker', $section->section);
- $controls[] = html_writer::link($url,
- html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/marker'),
- 'class' => 'icon', 'alt' => get_string('markthistopic'))),
- array('title' => get_string('markthistopic'), 'class' => 'editing_highlight'));
+ if (has_capability('moodle/course:setcurrentsection', $coursecontext)) {
+ if ($course->marker == $section->section) { // Show the "light globe" on/off.
+ $url->param('marker', 0);
+ $controls[] = html_writer::link($url,
+ html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/marked'),
+ 'class' => 'icon ', 'alt' => get_string('markedthistopic'))),
+ array('title' => get_string('markedthistopic'), 'class' => 'editing_highlight'));
+ } else {
+ $url->param('marker', $section->section);
+ $controls[] = html_writer::link($url,
+ html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/marker'),
+ 'class' => 'icon', 'alt' => get_string('markthistopic'))),
+ array('title' => get_string('markthistopic'), 'class' => 'editing_highlight'));
+ }
}
return array_merge($controls, parent::section_edit_controls($course, $section, $onsectionpage));
$renderer = $PAGE->get_renderer('format_weeks');
-if (!empty($displaysection) && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
+if (!empty($displaysection)) {
$renderer->print_single_section_page($course, $sections, $mods, $modnames, $modnamesused, $displaysection);
} else {
$renderer->print_multiple_section_page($course, $sections, $mods, $modnames, $modnamesused);
define('MOD_CLASS_ACTIVITY', 0);
define('MOD_CLASS_RESOURCE', 1);
-define('COURSE_DISPLAY_SINGLEPAGE', 0); // display all sections on one page
-define('COURSE_DISPLAY_MULTIPAGE', 1); // split pages into a page per section
-
function make_log_url($module, $url) {
switch ($module) {
case 'course':
$modchooser.= html_writer::end_tag('div');
// Wrap the normal output in a noscript div
- $usemodchooser = get_user_preferences('usemodchooser', 1);
+ $usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault);
if ($usemodchooser) {
$output = html_writer::tag('div', $output, array('class' => 'hiddenifjs addresourcedropdown'));
$modchooser = html_writer::tag('div', $modchooser, array('class' => 'visibleifjs addresourcemodchooser'));
return $cats;
}
-/**
- * Gets the name of a course to be displayed when showing a list of courses.
- * By default this is just $course->fullname but user can configure it. The
- * result of this function should be passed through print_string.
- * @param object $course Moodle course object
- * @return string Display name of course (either fullname or short + fullname)
- */
-function get_course_display_name_for_list($course) {
- global $CFG;
- if (!empty($CFG->courselistshortnames)) {
- return $course->shortname . ' ' .$course->fullname;
- } else {
- return $course->fullname;
- }
-}
-
/**
* Prints the category info in indented fashion
* This function is only used by print_whole_category_list() above
$mform->setAdvanced('user');
}
- $sectiontitle = get_string('sectionname', 'format_'.$COURSE->format);
-
$options = array(''=>get_string('allactivities'));
$modsused = array();
$mform->addElement('checkbox', 'reset_logs', get_string('deletelogs'));
$mform->addElement('checkbox', 'reset_notes', get_string('deletenotes', 'notes'));
$mform->addElement('checkbox', 'reset_comments', get_string('deleteallcomments', 'moodle'));
- $mform->addElement('checkbox', 'reset_course_completion', get_string('deletecoursecompletiondata', 'completion'));
+ $mform->addElement('checkbox', 'reset_completion', get_string('deletecompletiondata', 'completion'));
$mform->addElement('checkbox', 'delete_blog_associations', get_string('deleteblogassociations', 'blog'));
$mform->addHelpButton('delete_blog_associations', 'deleteblogassociations', 'blog');
switch ($class) {
case 'section':
- require_capability('moodle/course:update', $coursecontext);
if (!$DB->record_exists('course_sections', array('course'=>$course->id, 'section'=>$id))) {
throw new moodle_exception('AJAX commands.php: Bad Section ID '.$id);
switch ($field) {
case 'visible':
+ require_capability('moodle/course:sectionvisibility', $coursecontext);
$resourcestotoggle = set_section_visible($course->id, $id, $value);
echo json_encode(array('resourcestotoggle' => $resourcestotoggle));
break;
case 'move':
+ require_capability('moodle/course:update', $coursecontext);
move_section_to($course, $id, $value);
// See if format wants to do something about it
$libfile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php';
case 'course':
switch($field) {
case 'marker':
- require_capability('moodle/course:update', $coursecontext);
+ require_capability('moodle/course:setcurrentsection', $coursecontext);
course_set_marker($course->id, $value);
break;
}
$course2['format'] = 'weeks';
$course2['showgrades'] = 1;
$course2['newsitems'] = 3;
- $course2['startdate'] = 32882306400; // 01/01/3012
+ $course2['startdate'] = 1420092000; // 01/01/2015
$course2['numsections'] = 4;
$course2['maxbytes'] = 100000;
$course2['showreports'] = 1;
$logparam = 'id='. $course->id;
$loglabel = 'view';
$infoid = $course->id;
- if(!empty($section)) {
+ if ($section and $section > 0) {
$loglabel = 'view section';
// Get section details and check it exists.
set_user_preference('usemodchooser', $modchooser);
}
- if (has_capability('moodle/course:update', $context)) {
+ if (has_capability('moodle/course:sectionvisibility', $context)) {
if ($hide && confirm_sesskey()) {
set_section_visible($course->id, $hide, '0');
redirect($PAGE->url);
set_section_visible($course->id, $show, '1');
redirect($PAGE->url);
}
+ }
+ if (has_capability('moodle/course:update', $context)) {
if (!empty($section)) {
if (!empty($move) and confirm_sesskey()) {
$destsection = $section + $move;
$searchmenu = array('orderid' => $authstrs->orderid, 'transid' => $authstrs->transid, 'cclastfour' => $authstrs->cclastfour);
$buttons = "<form method='post' action='index.php' autocomplete='off'><div>";
+ $buttons .= html_writer::label(get_string('orderdetails', 'enrol_authorize'), 'menusearchtype', false, array('class' => 'accesshide'));
$buttons .= html_writer::select($searchmenu, 'searchtype', $searchtype, false);
- $buttons .= "<input type='text' size='16' name='searchquery' value='' />";
+ $buttons .= html_writer::label(get_string('search'), 'searchquery', false, array('class' => 'accesshide'));
+ $buttons .= "<input id='searchquery' type='text' size='16' name='searchquery' value='' />";
$buttons .= "<input type='submit' value='$strs->search' />";
$buttons .= "</div></form>";
<?php
-
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
* CLI sync for full category enrol synchronisation.
*
* Sample execution:
- * $sudo -u www-data /usr/bin/php /var/www/moodle/enrol/category/cli/sync.php
+ * $ sudo -u www-data /usr/bin/php /var/www/moodle/enrol/category/cli/sync.php
*
* Notes:
* - it is required to use the web server account when executing PHP CLI scripts
* - you need to change the "www-data" to match the apache user account
* - use "su" if "sudo" not available
*
- * @package enrol
- * @subpackage category
+ * @package enrol_category
* @copyright 2010 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php');
require_once("$CFG->dirroot/enrol/category/locallib.php");
+require_once("$CFG->libdir/clilib.php");
+
+// Now get cli options.
+list($options, $unrecognized) = cli_get_params(array('verbose'=>false, 'help'=>false), array('v'=>'verbose', 'h'=>'help'));
+
+if ($unrecognized) {
+ $unrecognized = implode("\n ", $unrecognized);
+ cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
+}
+
+if ($options['help']) {
+ $help =
+ "Execute course category enrolment sync.
+
+Options:
+-v, --verbose Print verbose progess information
+-h, --help Print out this help
+
+Example:
+\$ sudo -u www-data /usr/bin/php enrol/category/cli/sync.php
+";
+ echo $help;
+ die;
+}
+
if (!enrol_is_enabled('category')) {
- die('enrol_category plugin is disabled, sync is disabled');
+ cli_error('enrol_category plugin is disabled, synchronisation stopped', 2);
}
-enrol_category_sync_full();
+$verbose = !empty($options['verbose']);
+return enrol_category_sync_full($verbose);
defined('MOODLE_INTERNAL') || die();
$capabilities = array(
- // marks roles that have category role assignments synchronised to course enrolments
+ // Marks roles that have category role assignments synchronised to course enrolments
// overrides below system context are ignored (for performance reasons).
- // by default his is not allowed in new installs, admins have to explicitly allow category enrolments
+ // By default his is not allowed in new installs, admins have to explicitly allow category enrolments.
'enrol/category:synchronised' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
/**
* Category enrolment plugin event handler definition.
*
- * @package enrol_category
- * @category event
+ * @package enrol_category
+ * @category event
* @copyright 2010 Petr Skoda {@link http://skodak.org}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
<?php
-
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
/**
* category enrolment plugin installation.
*
- * @package enrol
- * @subpackage category
+ * @package enrol_category
* @copyright 2010 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
<?php
-
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
- * Strings for component 'enrol_category', language 'en', branch 'MOODLE_20_STABLE'
+ * Strings for component 'enrol_category', language 'en'.
*
- * @package enrol
- * @subpackage category
+ * @package enrol_category
* @copyright 2010 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
<?php
-
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
/**
* Category enrolment plugin.
*
- * @package enrol
- * @subpackage category
+ * @package enrol_category
* @copyright 2010 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
+
/**
* category enrolment plugin implementation.
- * @author Petr Skoda
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author Petr Skoda
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class enrol_category_plugin extends enrol_plugin {
/**
* Is it possible to delete enrol instance via standard UI?
*
- * @param object $instance
+ * @param stdClass $instance
* @return bool
*/
public function instance_deleteable($instance) {
if (!enrol_is_enabled('category')) {
return true;
}
- // allow delete only when no synced users here
+ // Allow delete only when no synced users here.
return !$DB->record_exists('user_enrolments', array('enrolid'=>$instance->id));
}
* @return moodle_url page url
*/
public function get_newinstance_link($courseid) {
- // instances are added automatically as necessary
- return NULL;
+ // Instances are added automatically as necessary.
+ return null;
}
/**
* Called after updating/inserting course.
*
* @param bool $inserted true if course just inserted
- * @param object $course
- * @param object $data form data
+ * @param stdClass $course
+ * @param stdClass $data form data
* @return void
*/
public function course_updated($inserted, $course, $data) {
return;
}
- // sync category enrols
+ // Sync category enrols.
require_once("$CFG->dirroot/enrol/category/locallib.php");
enrol_category_sync_course($course);
}
}
-
-
<?php
-
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
/**
* Local stuff for category enrolment plugin.
*
- * @package enrol
- * @subpackage category
+ * @package enrol_category
* @copyright 2010 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
+
/**
* Event handler for category enrolment plugin.
*
* it may fail sometimes, so we always do a full sync in cron too.
*/
class enrol_category_handler {
+ /**
+ * Triggered when user is assigned a new role.
+ * @static
+ * @param stdClass $ra
+ * @return bool
+ */
public static function role_assigned($ra) {
global $DB;
return true;
}
- //only category level roles are interesting
+ // Only category level roles are interesting.
$parentcontext = get_context_instance_by_id($ra->contextid);
if ($parentcontext->contextlevel != CONTEXT_COURSECAT) {
return true;
}
- // make sure the role is to be actually synchronised
- // please note we are ignoring overrides of the synchronised capability (for performance reasons in full sync)
- $syscontext = get_context_instance(CONTEXT_SYSTEM);
+ // Make sure the role is to be actually synchronised,
+ // please note we are ignoring overrides of the synchronised capability (for performance reasons in full sync).
+ $syscontext = context_system::instance();
if (!$DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$ra->roleid, 'capability'=>'enrol/category:synchronised', 'permission'=>CAP_ALLOW))) {
return true;
}
- // add necessary enrol instances
+ // Add necessary enrol instances.
$plugin = enrol_get_plugin('category');
$sql = "SELECT c.*
FROM {course} c
}
$rs->close();
- // now look for missing enrols
+ // Now look for missing enrolments.
$sql = "SELECT e.*
FROM {course} c
JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel AND ctx.path LIKE :match)
return true;
}
+ /**
+ * Triggered when user role is unassigned.
+ * @static
+ * @param stdClass $ra
+ * @return bool
+ */
public static function role_unassigned($ra) {
global $DB;
return true;
}
- // only category level roles are interesting
+ // Only category level roles are interesting.
$parentcontext = get_context_instance_by_id($ra->contextid);
if ($parentcontext->contextlevel != CONTEXT_COURSECAT) {
return true;
}
- // now this is going to be a bit slow, take all enrolments in child courses and verify each separately
- $syscontext = get_context_instance(CONTEXT_SYSTEM);
+ // Now this is going to be a bit slow, take all enrolments in child courses and verify each separately.
+ $syscontext = context_system::instance();
if (!$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext)) {
return true;
}
$params['userid'] = $ra->userid;
foreach ($rs as $instance) {
- $coursecontext = get_context_instance(CONTEXT_COURSE, $instance->courseid);
+ $coursecontext = context_course::instance($instance->courseid);
$contextids = get_parent_contexts($coursecontext);
- array_pop($contextids); // remove system context, we are interested in categories only
+ array_pop($contextids); // Remove system context, we are interested in categories only.
list($contextids, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'c');
$params = array_merge($params, $contextparams);
FROM {role_assignments} ra
WHERE ra.userid = :userid AND ra.contextid $contextids AND ra.roleid $roleids";
if (!$DB->record_exists_sql($sql, $params)) {
- // user does not have any interesting role in any parent context, let's unenrol
+ // User does not have any interesting role in any parent context, let's unenrol.
$plugin->unenrol_user($instance, $ra->userid);
}
}
/**
* Sync all category enrolments in one course
- * @param int $courseid course id
+ * @param stdClass $course
* @return void
*/
function enrol_category_sync_course($course) {
$plugin = enrol_get_plugin('category');
- $syscontext = get_context_instance(CONTEXT_SYSTEM);
+ $syscontext = context_system::instance();
$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext);
if (!$roles) {
- //nothing to sync, so remove the instance completely if exists
+ // Nothing to sync, so remove the instance completely if exists.
if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {
foreach ($instances as $instance) {
$plugin->delete_instance($instance);
return;
}
- // first find out if any parent category context contains interesting role assignments
- $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
+ // First find out if any parent category context contains interesting role assignments.
+ $coursecontext = context_course::instance($course->id);
$contextids = get_parent_contexts($coursecontext);
- array_pop($contextids); // remove system context, we are interested in categories only
+ array_pop($contextids); // Remove system context, we are interested in categories only.
list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r');
list($contextids, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'c');
WHERE roleid $roleids AND contextid $contextids";
if (!$DB->record_exists_sql($sql, $params)) {
if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {
- // should be max one instance, but anyway
+ // Should be max one instance, but anyway.
foreach ($instances as $instance) {
$plugin->delete_instance($instance);
}
return;
}
- // make sure the enrol instance exists - there should be always only one instance
+ // Make sure the enrol instance exists - there should be always only one instance.
$delinstances = array();
if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {
$instance = array_shift($instances);
$instance = $DB->get_record('enrol', array('id'=>$i));
}
- // add new enrolments
+ // Add new enrolments.
$sql = "SELECT ra.userid, ra.estart
FROM (SELECT xra.userid, MIN(xra.timemodified) AS estart
FROM {role_assignments} xra
}
$rs->close();
- // remove unwanted enrolments
+ // Remove unwanted enrolments.
$sql = "SELECT DISTINCT ue.userid
FROM {user_enrolments} ue
LEFT JOIN {role_assignments} ra ON (ra.roleid $roleids AND ra.contextid $contextids AND ra.userid = ue.userid)
$rs->close();
if ($delinstances) {
- // we have to do this as the last step in order to prevent temporary unenrolment
+ // We have to do this as the last step in order to prevent temporary unenrolment.
foreach ($delinstances as $delinstance) {
$plugin->delete_instance($delinstance);
}
}
}
-function enrol_category_sync_full() {
+/**
+ * Synchronise courses in all categories.
+ *
+ * It gets out-of-sync if:
+ * - you move course to different category
+ * - reorder categories
+ * - disable enrol_category and enable it again
+ *
+ * @param bool $verbose
+ * @return int exit code - 0 is ok, 1 means error, 2 if plugin disabled
+ */
+function enrol_category_sync_full($verbose = false) {
global $DB;
if (!enrol_is_enabled('category')) {
- return;
+ return 2;
}
- // we may need a lot of time here
+ // We may need a lot of time here.
@set_time_limit(0);
$plugin = enrol_get_plugin('category');
- $syscontext = get_context_instance(CONTEXT_SYSTEM);
+ $syscontext = context_system::instance();
- // any interesting roles worth synchronising?
+ // Any interesting roles worth synchronising?
if (!$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext)) {
// yay, nothing to do, so let's remove all leftovers
+ if ($verbose) {
+ mtrace("No roles with 'enrol/category:synchronised' capability found.");
+ }
if ($instances = $DB->get_records('enrol', array('enrol'=>'category'))) {
foreach ($instances as $instance) {
+ if ($verbose) {
+ mtrace(" deleting category enrol instance from course {$instance->courseid}");
+ }
$plugin->delete_instance($instance);
}
}
- return;
+ return 0;
+ }
+ $rolenames = array();
+ foreach($roles as $role) {
+ $rolenames[$role->id] = $role->shortname;
+ }
+ if ($verbose) {
+ mtrace('Synchronising category enrolments for roles: '.implode(', ', $rolenames).'...');
}
list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r');
$params['courselevel'] = CONTEXT_COURSE;
$params['catlevel'] = CONTEXT_COURSECAT;
- // first of all add necessary enrol instances to all courses
+ // First of all add necessary enrol instances to all courses.
$parentcat = $DB->sql_concat("cat.path", "'/%'");
- // need whole course records to be used by add_instance(), use inner view (ci) to
+ $parentcctx = $DB->sql_concat("cctx.path", "'/%'");
+ // Need whole course records to be used by add_instance(), use inner view (ci) to
// get distinct records only.
// TODO: Moodle 2.1. Improve enrol API to accept courseid / courserec
$sql = "SELECT c.*
}
$rs->close();
- // now look for courses that do not have any interesting roles in parent contexts,
- // but still have the instance and delete them
+ // Now look for courses that do not have any interesting roles in parent contexts,
+ // but still have the instance and delete them.
$sql = "SELECT e.*
FROM {enrol} e
JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
- LEFT JOIN (SELECT DISTINCT cctx.path
- FROM {course_categories} cc
+ LEFT JOIN ({course_categories} cc
JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)
JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)
- ) cat ON (ctx.path LIKE $parentcat)
- WHERE e.enrol = 'category' AND cat.path IS NULL";
+ ) ON (ctx.path LIKE $parentcctx)
+ WHERE e.enrol = 'category' AND cc.id IS NULL";
$rs = $DB->get_recordset_sql($sql, $params);
foreach($rs as $instance) {
}
$rs->close();
- // add missing enrolments
+ // Add missing enrolments.
$sql = "SELECT e.*, cat.userid, cat.estart
FROM {enrol} e
JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
unset($instance->userid);
unset($instance->estart);
$plugin->enrol_user($instance, $userid, null, $estart);
+ if ($verbose) {
+ mtrace(" enrolling: user $userid ==> course $instance->courseid");
+ }
}
$rs->close();
- // remove stale enrolments
+ // Remove stale enrolments.
$sql = "SELECT e.*, ue.userid
FROM {enrol} e
JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
JOIN {user_enrolments} ue ON (ue.enrolid = e.id)
- LEFT JOIN (SELECT DISTINCT cctx.path, ra.userid
- FROM {course_categories} cc
+ LEFT JOIN ({course_categories} cc
JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)
JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)
- ) cat ON (ctx.path LIKE $parentcat AND cat.userid = ue.userid)
- WHERE e.enrol = 'category' AND cat.userid IS NULL";
+ ) ON (ctx.path LIKE $parentcctx AND ra.userid = ue.userid)
+ WHERE e.enrol = 'category' AND cc.id IS NULL";
$rs = $DB->get_recordset_sql($sql, $params);
foreach($rs as $instance) {
$userid = $instance->userid;
unset($instance->userid);
$plugin->unenrol_user($instance, $userid);
+ if ($verbose) {
+ mtrace(" unenrolling: user $userid ==> course $instance->courseid");
+ }
}
$rs->close();
+
+ if ($verbose) {
+ mtrace('...user enrolment synchronisation finished.');
+ }
+
+ return 0;
}
<?php
-
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
- * category enrolment plugin settings and presets.
+ * Category enrolment plugin settings and presets.
*
- * @package enrol
- * @subpackage category
+ * @package enrol_category
* @copyright 2010 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
//--- enrol instance defaults ----------------------------------------------------------------------------
}
-
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Category enrolment sync functional test.
+ *
+ * @package enrol_category
+ * @category phpunit
+ * @copyright 2012 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot.'/enrol/category/locallib.php');
+
+class enrol_category_testcase extends advanced_testcase {
+
+ protected function enable_plugin() {
+ $enabled = enrol_get_plugins(true);
+ $enabled['category'] = true;
+ $enabled = array_keys($enabled);
+ set_config('enrol_plugins_enabled', implode(',', $enabled));
+ }
+
+ protected function disable_plugin() {
+ $enabled = enrol_get_plugins(true);
+ unset($enabled['category']);
+ $enabled = array_keys($enabled);
+ set_config('enrol_plugins_enabled', implode(',', $enabled));
+ }
+
+ protected function enable_role_sync($roleid) {
+ global $DB;
+
+ $syscontext = context_system::instance();
+
+ if ($rc = $DB->record_exists('role_capabilities', array('capability'=>'enrol/category:synchronised', 'roleid'=>$roleid, 'contextid'=>$syscontext->id))) {
+ if ($rc->permission != CAP_ALLOW) {
+ $rc->permission = CAP_ALLOW;
+ $DB->update_record('role_capabilities', $rc);
+ }
+ } else {
+ $rc = new stdClass();
+ $rc->capability = 'enrol/category:synchronised';
+ $rc->roleid = $roleid;
+ $rc->contextid = $syscontext->id;
+ $rc->permission = CAP_ALLOW;
+ $rc->timemodified = time();
+ $rc->modifierid = 0;
+ $DB->insert_record('role_capabilities', $rc);
+ }
+ }
+
+ protected function disable_role_sync($roleid) {
+ global $DB;
+
+ $syscontext = context_system::instance();
+
+ $DB->delete_records('role_capabilities', array('capability'=>'enrol/category:synchronised', 'roleid'=>$roleid, 'contextid'=>$syscontext->id));
+ }
+
+ /**
+ * Test utility methods used in syn test, fail here means something
+ * in core accesslib was changed, but it is possible that only this test
+ * is affected, nto the plugin itself...
+ */
+ public function test_utils() {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ $syscontext = context_system::instance();
+
+ $this->assertFalse(enrol_is_enabled('category'));
+ $this->enable_plugin();
+ $this->assertTrue(enrol_is_enabled('category'));
+
+ $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext);
+ $this->assertEmpty($roles);
+
+ $studentrole = $DB->get_record('role', array('shortname'=>'student'));
+ $this->assertNotEmpty($studentrole);
+
+ $this->enable_role_sync($studentrole->id);
+ $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext);
+ $this->assertEquals(1, count($roles));
+ $this->assertEquals($studentrole, reset($roles));
+
+ $this->disable_role_sync($studentrole->id);
+ $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext);
+ $this->assertEmpty($roles);
+ }
+
+ public function test_handler_sync() {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ // Setup a few courses and categories.
+
+ $studentrole = $DB->get_record('role', array('shortname'=>'student'));
+ $this->assertNotEmpty($studentrole);
+ $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
+ $this->assertNotEmpty($teacherrole);
+ $managerrole = $DB->get_record('role', array('shortname'=>'manager'));
+ $this->assertNotEmpty($managerrole);
+
+ $cat1 = $this->getDataGenerator()->create_category();
+ $cat2 = $this->getDataGenerator()->create_category();
+ $cat3 = $this->getDataGenerator()->create_category(array('parent'=>$cat2->id));
+
+ $course1 = $this->getDataGenerator()->create_course(array('category'=>$cat1->id));
+ $course2 = $this->getDataGenerator()->create_course(array('category'=>$cat2->id));
+ $course3 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+ $course4 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+
+ $user1 = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
+ $user3 = $this->getDataGenerator()->create_user();
+ $user4 = $this->getDataGenerator()->create_user();
+
+ $this->enable_role_sync($studentrole->id);
+ $this->enable_role_sync($teacherrole->id);
+ $this->enable_plugin();
+
+ $this->assertEquals(0, $DB->count_records('role_assignments', array()));
+ $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+
+ // Test assign event.
+
+ role_assign($managerrole->id, $user1->id, context_coursecat::instance($cat1->id));
+ role_assign($managerrole->id, $user3->id, context_course::instance($course1->id));
+ role_assign($managerrole->id, $user3->id, context_course::instance($course2->id));
+ $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+
+ role_assign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course2->id), $user1->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user1->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course4->id), $user1->id));
+ $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+ role_assign($managerrole->id, $user2->id, context_coursecat::instance($cat3->id));
+ $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+ role_assign($teacherrole->id, $user4->id, context_coursecat::instance($cat1->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user4->id));
+ $this->assertEquals(4, $DB->count_records('user_enrolments', array()));
+
+ // Test role unassigned event.
+
+ role_unassign($teacherrole->id, $user4->id, context_coursecat::instance($cat1->id)->id);
+ $this->assertFalse(is_enrolled(context_course::instance($course1->id), $user4->id));
+ $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+ // Make sure handlers are disabled when plugin disabled.
+
+ $this->disable_plugin();
+ role_unassign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id)->id);
+ $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+ role_assign($studentrole->id, $user3->id, context_coursecat::instance($cat1->id));
+ $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+ }
+
+ public function test_sync_course() {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ // Setup a few courses and categories.
+
+ $studentrole = $DB->get_record('role', array('shortname'=>'student'));
+ $this->assertNotEmpty($studentrole);
+ $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
+ $this->assertNotEmpty($teacherrole);
+ $managerrole = $DB->get_record('role', array('shortname'=>'manager'));
+ $this->assertNotEmpty($managerrole);
+
+ $cat1 = $this->getDataGenerator()->create_category();
+ $cat2 = $this->getDataGenerator()->create_category();
+ $cat3 = $this->getDataGenerator()->create_category(array('parent'=>$cat2->id));
+
+ $course1 = $this->getDataGenerator()->create_course(array('category'=>$cat1->id));
+ $course2 = $this->getDataGenerator()->create_course(array('category'=>$cat2->id));
+ $course3 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+ $course4 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+
+ $user1 = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
+ $user3 = $this->getDataGenerator()->create_user();
+ $user4 = $this->getDataGenerator()->create_user();
+
+ $this->enable_role_sync($studentrole->id);
+ $this->enable_role_sync($teacherrole->id);
+ $this->enable_plugin();
+
+ $this->assertEquals(0, $DB->count_records('role_assignments', array()));
+ role_assign($managerrole->id, $user1->id, context_coursecat::instance($cat1->id));
+ role_assign($managerrole->id, $user3->id, context_course::instance($course1->id));
+ role_assign($managerrole->id, $user3->id, context_course::instance($course2->id));
+ $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+
+
+ $this->disable_plugin(); // Stops the event handlers.
+ role_assign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id));
+ $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+ $this->enable_plugin();
+ enrol_category_sync_course($course2);
+ $this->assertTrue(is_enrolled(context_course::instance($course2->id), $user1->id));
+ $this->assertFalse(is_enrolled(context_course::instance($course3->id), $user1->id));
+ $this->assertFalse(is_enrolled(context_course::instance($course4->id), $user1->id));
+ $this->assertEquals(1, $DB->count_records('user_enrolments', array()));
+
+ enrol_category_sync_course($course2);
+ enrol_category_sync_course($course3);
+ enrol_category_sync_course($course4);
+ $this->assertFalse(is_enrolled(context_course::instance($course1->id), $user1->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course2->id), $user1->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user1->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course4->id), $user1->id));
+ $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+ $this->disable_plugin(); // Stops the event handlers.
+ role_assign($studentrole->id, $user2->id, context_coursecat::instance($cat1->id));
+ role_assign($teacherrole->id, $user4->id, context_coursecat::instance($cat1->id));
+ role_unassign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id)->id);
+ $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+ $this->enable_plugin();
+ enrol_category_sync_course($course2);
+ $this->assertFalse(is_enrolled(context_course::instance($course2->id), $user1->id));
+ $this->assertFalse(is_enrolled(context_course::instance($course2->id), $user2->id));
+ $this->assertFalse(is_enrolled(context_course::instance($course2->id), $user4->id));
+ enrol_category_sync_course($course1);
+ enrol_category_sync_course($course3);
+ enrol_category_sync_course($course4);
+ $this->assertEquals(2, $DB->count_records('user_enrolments', array()));
+ $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user2->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user4->id));
+
+ $this->disable_role_sync($studentrole->id);
+ enrol_category_sync_course($course1);
+ enrol_category_sync_course($course2);
+ enrol_category_sync_course($course3);
+ enrol_category_sync_course($course4);
+ $this->assertEquals(1, $DB->count_records('user_enrolments', array()));
+ $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user4->id));
+
+ $this->assertEquals(1, $DB->count_records('enrol', array('enrol'=>'category')));
+ $this->disable_role_sync($teacherrole->id);
+ enrol_category_sync_course($course1);
+ enrol_category_sync_course($course2);
+ enrol_category_sync_course($course3);
+ enrol_category_sync_course($course4);
+ $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+ $this->assertEquals(0, $DB->count_records('enrol', array('enrol'=>'category')));
+ }
+
+ public function test_sync_full() {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ // Setup a few courses and categories.
+
+ $studentrole = $DB->get_record('role', array('shortname'=>'student'));
+ $this->assertNotEmpty($studentrole);
+ $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
+ $this->assertNotEmpty($teacherrole);
+ $managerrole = $DB->get_record('role', array('shortname'=>'manager'));
+ $this->assertNotEmpty($managerrole);
+
+ $cat1 = $this->getDataGenerator()->create_category();
+ $cat2 = $this->getDataGenerator()->create_category();
+ $cat3 = $this->getDataGenerator()->create_category(array('parent'=>$cat2->id));
+
+ $course1 = $this->getDataGenerator()->create_course(array('category'=>$cat1->id));
+ $course2 = $this->getDataGenerator()->create_course(array('category'=>$cat2->id));
+ $course3 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+ $course4 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+
+ $user1 = $this->getDataGenerator()->create_user();
+ $user2 = $this->getDataGenerator()->create_user();
+ $user3 = $this->getDataGenerator()->create_user();
+ $user4 = $this->getDataGenerator()->create_user();
+
+ $this->enable_role_sync($studentrole->id);
+ $this->enable_role_sync($teacherrole->id);
+ $this->enable_plugin();
+
+ $this->assertEquals(0, $DB->count_records('role_assignments', array()));
+ role_assign($managerrole->id, $user1->id, context_coursecat::instance($cat1->id));
+ role_assign($managerrole->id, $user3->id, context_course::instance($course1->id));
+ role_assign($managerrole->id, $user3->id, context_course::instance($course2->id));
+ $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+
+ $result = enrol_category_sync_full();
+ $this->assertSame(0, $result);
+
+ $this->disable_plugin();
+ role_assign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id));
+ $this->enable_plugin();
+ $result = enrol_category_sync_full();
+ $this->assertSame(0, $result);
+ $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+ $this->assertTrue(is_enrolled(context_course::instance($course2->id), $user1->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user1->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course4->id), $user1->id));
+
+ $this->disable_plugin();
+ role_unassign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id)->id);
+ role_assign($studentrole->id, $user2->id, context_coursecat::instance($cat1->id));
+ role_assign($teacherrole->id, $user4->id, context_coursecat::instance($cat1->id));
+ role_assign($teacherrole->id, $user3->id, context_coursecat::instance($cat2->id));
+ role_assign($managerrole->id, $user3->id, context_course::instance($course3->id));
+ $this->enable_plugin();
+ $result = enrol_category_sync_full();
+ $this->assertSame(0, $result);
+ $this->assertEquals(5, $DB->count_records('user_enrolments', array()));
+ $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user2->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user4->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course2->id), $user3->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user3->id));
+ $this->assertTrue(is_enrolled(context_course::instance($course4->id), $user3->id));
+
+ // Cleanup everything.
+
+ $this->assertNotEmpty($DB->count_records('role_assignments', array()));
+ $this->assertNotEmpty($DB->count_records('user_enrolments', array()));
+
+ $this->disable_plugin();
+ role_unassign_all(array('roleid'=>$studentrole->id));
+ role_unassign_all(array('roleid'=>$managerrole->id));
+ role_unassign_all(array('roleid'=>$teacherrole->id));
+
+ $result = enrol_category_sync_full();
+ $this->assertSame(2, $result);
+ $this->assertEquals(0, $DB->count_records('role_assignments', array()));
+ $this->assertNotEmpty($DB->count_records('user_enrolments', array()));
+ $this->disable_role_sync($studentrole->id);
+ $this->disable_role_sync($teacherrole->id);
+
+ $this->enable_plugin();
+ $result = enrol_category_sync_full();
+ $this->assertSame(0, $result);
+ $this->assertEquals(0, $DB->count_records('role_assignments', array()));
+ $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+ $this->assertEquals(0, $DB->count_records('enrol', array('enrol'=>'category')));
+ }
+}
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2012061700; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2012061700; // Requires this Moodle version
+$plugin->version = 2012081800; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2012062501; // Requires this Moodle version
$plugin->component = 'enrol_category'; // Full name of the plugin (used for diagnostics)
-$plugin->cron = 60;
\ No newline at end of file
+$plugin->cron = 60;
* @return void
*/
public function course_updated($inserted, $course, $data) {
- global $CFG;
-
- if (!$inserted) {
- // sync cohort enrols
- require_once("$CFG->dirroot/enrol/cohort/locallib.php");
- enrol_cohort_sync($course->id);
- } else {
- // cohorts are never inserted automatically
- }
-
+ // It turns out there is no need for cohorts to deal with this hook, see MDL-34870.
}
/**
if (preg_match('{<description>.*?<short>(.*?)</short>.*?</description>}is', $tagcontents, $matches)) {
$group->shortName = trim($matches[1]);
}
+ if (preg_match('{<description>.*?<full>(.*?)</full>.*?</description>}is', $tagcontents, $matches)) {
+ $group->fulldescription = trim($matches[1]);
+ }
if (preg_match('{<org>.*?<orgunit>(.*?)</orgunit>.*?</org>}is', $tagcontents, $matches)) {
$group->category = trim($matches[1]);
}
$courseconfig = get_config('moodlecourse'); // Load Moodle Course shell defaults
$course = new stdClass();
$course->fullname = $group->description;
- $course->shortname = $group->shortName;;
+ $course->shortname = $group->shortName;
+ if (!empty($group->fulldescription)) {
+ $course->summary = format_text($group->fulldescription, FORMAT_HTML);
+ }
$course->idnumber = $coursecode;
$course->format = $courseconfig->format;
$course->visible = $courseconfig->visible;
global $DB, $CFG;
// Add some additional sensible conditions
- $tests = array("id <> :guestid", 'u.deleted = 0', 'u.confirmed = 1');
+ $tests = array("u.id <> :guestid", 'u.deleted = 0', 'u.confirmed = 1');
$params = array('guestid' => $CFG->siteguest);
if (!empty($search)) {
$conditions = get_extra_user_fields($this->get_context());
$fields = 'SELECT '.$ufields;
$countfields = 'SELECT COUNT(1)';
$sql = " FROM {user} u
+ LEFT JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid)
WHERE $wherecondition
- AND u.id NOT IN (SELECT ue.userid
- FROM {user_enrolments} ue
- JOIN {enrol} e ON (e.id = ue.enrolid AND e.id = :enrolid))";
+ AND ue.id IS NULL";
$order = ' ORDER BY u.lastname ASC, u.firstname ASC';
$params['enrolid'] = $enrolid;
$totalusers = $DB->count_records_sql($countfields . $sql, $params);
$fields = 'SELECT '.user_picture::fields('u', array('username','lastaccess'));
$countfields = 'SELECT COUNT(u.id)';
$sql = " FROM {user} u
+ LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.contextid = :contextid)
WHERE $wherecondition
- AND u.id NOT IN (
- SELECT u.id
- FROM {role_assignments} r, {user} u
- WHERE r.contextid = :contextid AND
- u.id = r.userid)";
+ AND ra.id IS NULL";
$order = ' ORDER BY lastname ASC, firstname ASC';
$params['contextid'] = $this->context->id;
$today = time();
$today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0);
$startdateoptions[3] = get_string('today') . ' (' . userdate($today, $timeformat) . ')' ;
+ $defaultduration = $instance->enrolperiod > 0 ? $instance->enrolperiod / 86400 : '';
$modules = array('moodle-enrol_manual-quickenrolment', 'moodle-enrol_manual-quickenrolment-skin');
$arguments = array(
'url' => $manager->get_moodlepage()->url->out(false),
'optionsStartDate' => $startdateoptions,
'defaultRole' => $instance->roleid,
+ 'defaultDuration' => $defaultduration,
'disableGradeHistory' => $CFG->disablegradehistory,
'recoverGradesDefault'=> ''
);
$countfields = 'SELECT COUNT(1)';
$sql = " FROM {user} u
- WHERE $wherecondition AND
- u.id NOT IN (
- SELECT ue.userid
- FROM {user_enrolments} ue
- JOIN {enrol} e ON (e.id = ue.enrolid AND e.id = :enrolid))";
+ LEFT JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid)
+ WHERE $wherecondition
+ AND ue.id IS NULL";
$order = ' ORDER BY u.lastname ASC, u.firstname ASC';
if (!$this->is_validating()) {
<div class="enroloptions">
- <p><label for="roleid"><?php print_string('assignrole', 'enrol_manual') ?></label><br />
+ <p><label for="menuroleid"><?php print_string('assignrole', 'enrol_manual') ?></label><br />
<?php echo html_writer::select($roles, 'roleid', $roleid, false); ?></p>
- <p><label for="extendperiod"><?php print_string('enrolperiod', 'enrol') ?></label><br />
+ <p><label for="menuextendperiod"><?php print_string('enrolperiod', 'enrol') ?></label><br />
<?php echo html_writer::select($periodmenu, 'extendperiod', $defaultperiod, $unlimitedperiod); ?></p>
- <p><label for="extendbase"><?php print_string('startingfrom') ?></label><br />
+ <p><label for="menuextendbase"><?php print_string('startingfrom') ?></label><br />
<?php echo html_writer::select($basemenu, 'extendbase', $extendbase, false); ?></p>
</div>
$mform->addHelpButton('customint4', 'sendcoursewelcomemessage', 'enrol_self');
$mform->addElement('textarea', 'customtext1', get_string('customwelcomemessage', 'enrol_self'), array('cols'=>'60', 'rows'=>'8'));
+ $mform->addHelpButton('customtext1', 'customwelcomemessage', 'enrol_self');
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
}
return $roles;
}
-}
\ No newline at end of file
+}
*/
$string['customwelcomemessage'] = 'Custom welcome message';
+$string['customwelcomemessage_help'] = 'A custom welcome message may be added as plain text or Moodle-auto format, including HTML tags and multi-lang tags.
+
+The following placeholders may be included in the message:
+
+* Course name {$a->coursename}
+* Link to user\'s profile page {$a->profileurl}';
$string['defaultrole'] = 'Default role assignment';
$string['defaultrole_desc'] = 'Select role which should be assigned to users during self enrolment';
$string['editenrolment'] = 'Edit enrolment';
if (empty($instance->name)) {
if (!empty($instance->roleid) and $role = $DB->get_record('role', array('id'=>$instance->roleid))) {
- $role = ' (' . role_get_name($role, get_context_instance(CONTEXT_COURSE, $instance->courseid)) . ')';
+ $role = ' (' . role_get_name($role, context_course::instance($instance->courseid, IGNORE_MISSING)) . ')';
} else {
$role = '';
}
throw new coding_exception('Invalid enrol instance type!');
}
- $context = get_context_instance(CONTEXT_COURSE, $instance->courseid);
+ $context = context_course::instance($instance->courseid);
if (has_capability('enrol/self:config', $context)) {
$managelink = new moodle_url('/enrol/self/edit.php', array('courseid'=>$instance->courseid, 'id'=>$instance->id));
$instancesnode->add($this->get_instance_name($instance), $managelink, navigation_node::TYPE_SETTING);
if ($instance->enrol !== 'self') {
throw new coding_exception('invalid enrol instance!');
}
- $context = get_context_instance(CONTEXT_COURSE, $instance->courseid);
+ $context = context_course::instance($instance->courseid);
$icons = array();
* @return moodle_url page url
*/
public function get_newinstance_link($courseid) {
- $context = get_context_instance(CONTEXT_COURSE, $courseid, MUST_EXIST);
+ $context = context_course::instance($courseid, MUST_EXIST);
if (!has_capability('moodle/course:enrolconfig', $context) or !has_capability('enrol/self:config', $context)) {
return NULL;
global $CFG, $DB;
$course = $DB->get_record('course', array('id'=>$instance->courseid), '*', MUST_EXIST);
+ $context = context_course::instance($course->id);
$a = new stdClass();
- $a->coursename = format_string($course->fullname);
+ $a->coursename = format_string($course->fullname, true, array('context'=>$context));
$a->profileurl = "$CFG->wwwroot/user/view.php?id=$user->id&course=$course->id";
if (trim($instance->customtext1) !== '') {
$message = $instance->customtext1;
$message = str_replace('{$a->coursename}', $a->coursename, $message);
$message = str_replace('{$a->profileurl}', $a->profileurl, $message);
+ if (strpos($message, '<') === false) {
+ // Plain text only.
+ $messagetext = $message;
+ $messagehtml = text_to_html($messagetext, null, false, true);
+ } else {
+ // This is most probably the tag/newline soup known as FORMAT_MOODLE.
+ $messagehtml = format_text($message, FORMAT_MOODLE, array('context'=>$context, 'para'=>false, 'newlines'=>true, 'filter'=>true));
+ $messagetext = html_to_text($messagehtml);
+ }
} else {
- $message = get_string('welcometocoursetext', 'enrol_self', $a);
+ $messagetext = get_string('welcometocoursetext', 'enrol_self', $a);
+ $messagehtml = text_to_html($messagetext, null, false, true);
}
- $subject = get_string('welcometocourse', 'enrol_self', format_string($course->fullname));
+ $subject = get_string('welcometocourse', 'enrol_self', format_string($course->fullname, true, array('context'=>$context)));
- $context = get_context_instance(CONTEXT_COURSE, $course->id);
$rusers = array();
if (!empty($CFG->coursecontact)) {
$croles = explode(',', $CFG->coursecontact);
}
//directly emailing welcome message rather than using messaging
- email_to_user($user, $contact, $subject, $message);
+ email_to_user($user, $contact, $subject, $messagetext, $messagehtml);
}
/**
<form action="algebradebug.php" method="get"
target="inlineframe">
<center>
- <input type="text" name="algebra" size="50"
+ <label for="algebra" class="accesshide"><?php print_string('algebraicexpression', 'filter_algebra'); ?></label>
+ <input type="text" id="algebra" name="algebra" size="50"
value="sin(z)/(x^2+y^2)" />
</center>
<ol>
*/
$string['filtername'] = 'Algebra notation';
+$string['algebraicexpression'] = 'Algebraic expression';
} else {
$activechoices[TEXTFILTER_INHERIT] = $strdefaultoff;
}
- $row[] = html_writer::select($activechoices, str_replace('/', '_', $filter), $filterinfo->localstate, false);
+ $filtername = str_replace('/', '_', $filter);
+ $select = html_writer::label($filterinfo->localstate, 'menu'. $filtername, false, array('class' => 'accesshide'));
+ $select .= html_writer::select($activechoices, $filtername, $filterinfo->localstate, false);
+ $row[] = $select;
// Settings link, if required
if ($settingscol) {
if (!$courseid) {
require_once $CFG->libdir.'/adminlib.php';
- admin_externalpage_setup('scales');
+ admin_externalpage_setup('outcomes');
}
// default return url
$name .= '<div class="error"><span class="error">' . $errors[$grade_item->id].'</span><br />'."\n";
$closingdiv = "</div>\n";
}
+ $name .= '<label class="accesshide" for="id_idnumber_' . $grade_item->id . '">' . get_string('gradeitems', 'grades') .'</label>';
$name .= '<input class="idnumber" id="id_idnumber_'.$grade_item->id.'" type="text" name="idnumbers['.$grade_item->id.']" />' . "\n";
$name .= $closingdiv;
}
if (!$moving && count($grade_edit_tree->categories) > 1) {
echo '<br /><br />';
echo '<input type="hidden" name="bulkmove" value="0" id="bulkmoveinput" />';
- echo get_string('moveselectedto', 'grades') . ' ';
$attributes = array('id'=>'menumoveafter');
+ echo html_writer::label(get_string('moveselectedto', 'grades'), 'menumoveafter');
echo html_writer::select($grade_edit_tree->categories, 'moveafter', '', array(''=>'choosedots'), $attributes);
$OUTPUT->add_action_handler(new component_action('change', 'submit_bulk_move'), 'menumoveafter');
echo '<div id="noscriptgradetreeform" class="hiddenifjs">
} else {
$attributes = array();
$attributes['id'] = 'aggregation_'.$category->id;
- $aggregation = html_writer::select($options, 'aggregation_'.$category->id, $category->aggregation, null, $attributes);
+ $aggregation = html_writer::label(get_string('aggregation', 'grades'), 'aggregation_'.$category->id, false, array('class' => 'accesshide'));
+ $aggregation .= html_writer::select($options, 'aggregation_'.$category->id, $category->aggregation, null, $attributes);
$action = new component_action('change', 'update_category_aggregation', array('courseid' => $params['id'], 'category' => $category->id, 'sesskey' => sesskey()));
$OUTPUT->add_action_handler($action, 'aggregation_'.$category->id);
}
$modulename = substr($modulename, 4);
if ($dbman->table_exists($modulename)) {
$cm = get_coursemodule_from_id($modulename, $context->instanceid);
- $this->moduleinstance = $DB->get_record($modulename, array("id"=>$cm->instance));
+ if (!empty($cm)) { // This should only occur when the course is being deleted.
+ $this->moduleinstance = $DB->get_record($modulename, array("id"=>$cm->instance));
+ }
}
}
}
$leveltemplate .= html_writer::start_tag('div', array('class' => 'level-wrapper'));
if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
$definition = html_writer::tag('textarea', htmlspecialchars($level['definition']), array('name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'cols' => '10', 'rows' => '4'));
- $score = html_writer::empty_tag('input', array('type' => 'text', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '3', 'value' => $level['score']));
+ $score = html_writer::label(get_string('criterionempty', 'gradingform_rubric'), '{NAME}criteria{CRITERION-id}levels{LEVEL-id}', false, array('class' => 'accesshide'));
+ $score .= html_writer::empty_tag('input', array('type' => 'text','id' => '{NAME}criteria{CRITERION-id}levels{LEVEL-id}', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '3', 'value' => $level['score']));
} else {
if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
$leveltemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'value' => $level['definition']));
switch ($option) {
case 'sortlevelsasc':
// Display option as dropdown
- $html .= html_writer::tag('span', get_string($option, 'gradingform_rubric'), array('class' => 'label'));
+ $html .= html_writer::label(get_string($option, 'gradingform_rubric'), $attrs['id'], false, array('class' => 'label'));
$value = (int)(!!$value); // make sure $value is either 0 or 1
if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
$selectoptions = array(0 => get_string($option.'0', 'gradingform_rubric'), 1 => get_string($option.'1', 'gradingform_rubric'));
public function display_regrade_confirmation($elementname, $changelevel, $value) {
$html = html_writer::start_tag('div', array('class' => 'gradingform_rubric-regrade'));
if ($changelevel<=2) {
- $html .= get_string('regrademessage1', 'gradingform_rubric');
+ $html .= html_writer::label(get_string('regrademessage1', 'gradingform_rubric'), 'menu' . $elementname . 'regrade');
$selectoptions = array(
0 => get_string('regradeoption0', 'gradingform_rubric'),
1 => get_string('regradeoption1', 'gradingform_rubric')
// finally print/return the popup form
if ($count > 1) {
$select = new url_select($menu, $active, null, 'choosepluginreport');
-
+ $select->set_label(get_string('gradereport', 'grades'), array('class' => 'accesshide'));
if ($return) {
return $OUTPUT->render($select);
} else {
$nogradestr = $this->get_lang_string('nooutcome', 'grades');
}
$attributes = array('tabindex' => $tabindices[$item->id]['grade'], 'id'=>'grade_'.$userid.'_'.$item->id);
- $itemcell->text .= html_writer::select($scaleopt, 'grade_'.$userid.'_'.$item->id, $gradeval, array(-1=>$nogradestr), $attributes);;
+ $itemcell->text .= html_writer::label(get_string('typescale', 'grades'), $attributes['id'], false, array('class' => 'accesshide'));
+ $itemcell->text .= html_writer::select($scaleopt, 'grade_'.$userid.'_'.$item->id, $gradeval, array(-1=>$nogradestr), $attributes);
} elseif(!empty($scale)) {
$scales = explode(",", $scale->scale);
$string['pathshead'] = 'Potvrdit cesty';
$string['pathsrodataroot'] = 'Do datového adresáře nelze zapisovat.';
$string['pathsroparentdataroot'] = 'Do nadřazeného adresáře ({$a->parent}) nelze zapisovat. Datový adresář ({$a->dataroot}) nemůže být tímto průvodcem instalací vytvořen.';
+$string['pathssubadmindir'] = 'Na některých serverech je URL adresa /admin vyhrazena pro speciální účely (např. pro ovládací panel). Na takových serverech může dojít ke kolizi se standardním umístěním stránek pro správu Moodle. Máte-li tento problém, přejmenujte adresář <eM>admin</em> ve vaší instalaci Moodle a sem zadejte jeho nový název - například <em>moodleadmin</em>. Všechny generované odkazy na stránky správy Moodle budou používat tento nový název.';
+$string['pathssubdataroot'] = 'Moodle potřebuje prostor, kam si bude ukládat nahrané soubory a další údaje. K tomuto adresáři musí mít proces webového serveru právo ke čtení i k zápisu (webový server bývá většinou spouštěn pod uživatelem "www-data" nebo "apache"). Tento adresář ale zároveň nesmí být dostupný přímo přes webové rozhraní. Instalační skript se pokusí tento adresář vytvořit, pokud nebude existovat.';
$string['pathssubdirroot'] = 'Absolutní cesta k adresáři s instalací Moodle';
+$string['pathssubwwwroot'] = 'Zadejte úplnou webovou adresu, na níž bude Moodle dostupný. Moodle potřebuje jedinečnou adresu, není možné jej provozovat na několika URL současně. Používáte-li několik veřejných domén, musíte si sami nastavit permanentní přesměrování na jednu z nich a tu pak použít. Pokud je váš server dostupný z vnější a z vnitřní sítě pod různými IP adresami, použijte jeho veřejnou adresu a nastavte si váš DNS server tak, že ji mohou používat i uživatelé z vnitřní sítě.';
$string['pathsunsecuredataroot'] = 'Umístění datového adresáře není bezpečné';
$string['pathswrongadmindir'] = 'Adresář pro správu serveru (admin) neexistuje';
$string['phpextension'] = '{$a} PHP rozšíření';
$string['cliincorrectvalueretry'] = 'Rangt gildi, vinsamlegast reyndu aftur';
$string['clitypevalue'] = 'Sláðu inn gildi';
$string['clitypevaluedefault'] = 'Sláðu inn gildi, sláðu á Enter hnappinn á lyklaborðinu til að nota sjálfgefið gildi ({$a})';
+$string['cliunknowoption'] = 'Óþekktir valkostir:
+ {$a}
+Vinsamlegast notaðu --help valkostinn.';
$string['environmentrequireinstall'] = 'verður að vera uppsett og virkjað';
$string['environmentrequireversion'] = 'krafist er útgáfu {$a->needed} en þú notast við útgáfu {$a->current}';
defined('MOODLE_INTERNAL') || die();
+$string['clianswerno'] = 'n';
+$string['cliansweryes'] = 't';
+$string['cliincorrectvalueerror'] = 'Klaida, klaidinga "{$a->option}" reikšmė "{$a->value}"';
+$string['cliincorrectvalueretry'] = 'Klaidinga reikšmė, bandykite dar kartą';
+$string['clitypevalue'] = 'tipo reikšmė';
+$string['clitypevaluedefault'] = 'tipo reikšmė, paspauskite „Enter“, jei norite naudoti numatytąją reikšmę ({$a})';
+$string['cliunknowoption'] = 'Neatpažintos parinktys: {$a} naudokite --žinyno parinktį.';
+$string['cliyesnoprompt'] = 'įveskite t (taip) arba n (ne)';
$string['environmentrequireinstall'] = 'turi būti įdiegta ir įgalinta';
-$string['environmentrequireversion'] = 'reikalinga $a-needed, o Jūs turite $a-current';
+$string['environmentrequireversion'] = 'reikalinga {$a->needed} versija, o Jūs turite {$a->current}';
defined('MOODLE_INTERNAL') || die();
$string['language'] = 'Kalba';
-$string['next'] = 'Toliau';
+$string['next'] = 'Pirmyn';
$string['previous'] = 'Ankstesnis';
$string['reload'] = 'Įkelti iš naujo';
defined('MOODLE_INTERNAL') || die();
+$string['parentlanguage'] = '';
$string['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Nederlands';
$PAGE->set_heading($title);
echo $OUTPUT->header();
-if (empty($CFG->googlemapkey)) {
+if (empty($CFG->googlemapkey) and empty($CFG->googlemapkey3)) {
$imgwidth = 620;
$imgheight = 310;
$dotwidth = 18;
echo '</div>';
echo '<div id="note">'.$info['note'].'</div>';
-} else {
+} else if (empty($CFG->googlemapkey3)) {
$PAGE->requires->js(new moodle_url("http://maps.google.com/maps?file=api&v=2&key=$CFG->googlemapkey"));
$module = array('name'=>'core_iplookup', 'fullpath'=>'/iplookup/module.js');
$PAGE->requires->js_init_call('M.core_iplookup.init', array($info['latitude'], $info['longitude']), true, $module);
+ echo '<div id="map" style="width: 650px; height: 360px"></div>';
+ echo '<div id="note">'.$info['note'].'</div>';
+
+} else {
+ if (strpos($CFG->wwwroot, 'https:') === 0) {
+ $PAGE->requires->js(new moodle_url('https://maps.googleapis.com/maps/api/js', array('key'=>$CFG->googlemapkey3, 'sensor'=>'false')));
+ } else {
+ $PAGE->requires->js(new moodle_url('http://maps.googleapis.com/maps/api/js', array('key'=>$CFG->googlemapkey3, 'sensor'=>'false')));
+ }
+ $module = array('name'=>'core_iplookup', 'fullpath'=>'/iplookup/module.js');
+ $PAGE->requires->js_init_call('M.core_iplookup.init3', array($info['latitude'], $info['longitude'], $ip), true, $module);
+
echo '<div id="map" style="width: 650px; height: 360px"></div>';
echo '<div id="note">'.$info['note'].'</div>';
}
}, document.body);
}
};
+
+M.core_iplookup.init3 = function(Y, latitude, longitude, ip) {
+ var ipLatlng = new google.maps.LatLng(latitude, longitude);
+
+ var mapOptions = {
+ center: ipLatlng,
+ zoom: 6,
+ mapTypeId: google.maps.MapTypeId.ROADMAP
+ };
+
+ var map = new google.maps.Map(document.getElementById("map"), mapOptions);
+
+ var marker = new google.maps.Marker({
+ position: ipLatlng,
+ map: map,
+ title: ip
+ });
+};
$string['configforceloginforprofiles'] = 'This setting forces people to login as a real (non-guest) account before viewing any user\'s profile. If you disabled this setting, you may find that some users post advertising (spam) or other inappropriate content in their profiles, which is then visible to the whole world.';
$string['configfrontpage'] = 'The items selected above will be displayed on the site\'s front page.';
$string['configfrontpageloggedin'] = 'The items selected above will be displayed on the site\'s front page when a user is logged in.';
-$string['configfullnamedisplay'] = 'This defines how names are shown when they are displayed in full. For most mono-lingual sites the most efficient setting is the default "First name + Surname", but you may choose to hide surnames altogether, or to leave it up to the current language pack to decide (some languages have different conventions).';
+$string['configfullnamedisplay'] = 'This defines how names are shown when they are displayed in full. For most mono-lingual sites the most efficient setting is "First name + Surname", but you may choose to hide surnames altogether, or to leave it up to the current language pack to decide (some languages have different conventions).';
$string['configgdversion'] = 'Indicate the version of GD that is installed. The version shown by default is the one that has been auto-detected. Don\'t change this unless you really know what you\'re doing.';
$string['configgeoipfile'] = 'Location of GeoIP City binary data file. This file is not part of Moodle distribution and must be obtained separately from <a href="http://www.maxmind.com/">MaxMind</a>. You can either buy a commercial version or use the free version.<br />Simply download <a href="http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz" >http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz</a> and extract it into "{$a}" directory on your server.';
$string['configgetremoteaddrconf'] = 'If your server is behind a reverse proxy, you can use this setting to specify which HTTP headers can be trusted to contain the remote IP address. The headers are read in order, using the first one that is available.';
-$string['configgooglemapkey'] = 'You need to enter a special key to use Google Maps for IP address lookup visualization. You can obtain the key free of charge at <a href="http://code.google.com/apis/maps/signup.html" >http://code.google.com/apis/maps/signup.html</a>.<br />Your web site URL is: {$a}';
+$string['configgooglemapkey'] = 'You need to enter a special key to use Google Maps for IP address lookup visualization. You can obtain the key free of charge at <a href="https://developers.google.com/maps/documentation/javascript/v2/introduction#Obtaining_Key">https://developers.google.com/maps/documentation/javascript/v2/introduction#Obtaining_Key</a>.<br />Your web site URL is: {$a}';
$string['configgradebookroles'] = 'This setting allows you to control who appears on the gradebook. Users need to have at least one of these roles in a course to be shown in the gradebook for that course.';
$string['configgradeexport'] = 'Choose which gradebook export formats are your primary methods for exporting grades. Chosen plugins will then set and use a "last exported" field for every grade. For example, this might result in exported records being identified as being "new" or "updated". If you are not sure about this then leave everything unchecked.';
$string['confighiddenuserfields'] = 'Select which user information fields you wish to hide from other users other than course teachers/admins. This will increase student privacy. Hold CTRL key to select multiple fields.';
$string['configminpasswordlower'] = 'Passwords must have at least these many lower case letters.';
$string['configminpasswordnonalphanum'] = 'Passwords must have at least these many non-alphanumeric characters.';
$string['configminpasswordupper'] = 'Passwords must have at least these many upper case letters.';
+$string['configmodchooserdefault'] = 'Should the activity chooser be presented to users by default?';
$string['configmycoursesperpage'] = 'Maximum number of courses to display in any list of a user\'s own courses';
$string['configmymoodleredirect'] = 'This setting forces redirects to /my on login for non-admins and replaces the top level site navigation with /my';
$string['configmypagelocked'] = 'This setting prevents the default page from being edited by any non-admins';
$string['country'] = 'Default country';
$string['coursecontact'] = 'Course contacts';
$string['coursecontact_desc'] = 'This setting allows you to control who appears on the course description. Users need to have at least one of these roles in a course to be shown on the course description for that course.';
-$string['courselistshortnames'] = 'Display short names';
-$string['courselistshortnames_desc'] = 'Show short name as well as full name when displaying lists of courses.';
+$string['courselistshortnames'] = 'Display extended course names';
+$string['courselistshortnames_desc'] = 'When showing lists of courses, or when referring to courses on administration screens, show the course short name as well as the full name. In fact, when you turn this setting on, the display uses the \'courseextendednamedisplay\' language string, so you can changewhat is displayed using Language customisation.';
$string['coursemgmt'] = 'Add/edit courses';
$string['courseoverview'] = 'Course overview';
$string['courserequestnotify'] = 'Course request notification';
$string['globalswarning'] = '<p><strong>SECURITY WARNING!</strong></p><p> To operate properly, Moodle requires <br />that you make certain changes to your current PHP settings.</p><p>You <em>must</em> set <code>register_globals=off</code>.</p><p>This setting is controlled by editing your <code>php.ini</code>, Apache/IIS <br />configuration or <code>.htaccess</code> file.</p>';
$string['groupenrolmentkeypolicy'] = 'Group enrolment key policy';
$string['groupenrolmentkeypolicy_desc'] = 'Turning this on will make Moodle check group enrolment keys against a valid password policy.';
-$string['googlemapkey'] = 'Google Maps API key';
+$string['googlemapkey'] = 'Google Maps API V2 key';
+$string['googlemapkey3'] = 'Google Maps API V3 key';
+$string['googlemapkey3_help'] = 'You need to enter a special key to use Google Maps for IP address lookup visualization. You can obtain the key free of charge at <a href="https://developers.google.com/maps/documentation/javascript/tutorial#api_key" target="_blank">https://developers.google.com/maps/documentation/javascript/tutorial#api_key</a>';
$string['gotofirst'] = 'Go to first missing string';
$string['gradebook'] = 'Gradebook';
$string['gradebookroles'] = 'Graded roles';
$string['mnetrestore_extusers_mismatch'] = '<strong>Note:</strong> This backup file apparently originates from a different Moodle installation and contains remote Moodle Network user accounts that may fail to restore. This operation is unsupported. If you are certain that it was created on this Moodle installation, or you can ensure that all the needed Moodle Network Hosts are configured, you may want to still try the restore.';
$string['mnetrestore_extusers_noadmin'] = '<strong>Note:</strong> This backup file seems to come from a different Moodle installation and contains remote Moodle Network user accounts. You are not allowed to execute this type of restore. Contact the administrator of the site or, alternatively, restore this course without any user information (modules, files...)';
$string['mnetrestore_extusers_switchuserauth'] = 'Remote Moodle Network user {$a->username} (coming from {$a->mnethosturl}) switched to local {$a->auth} authenticated user.';
+$string['modchooserdefault'] = 'Activity chooser default';
$string['modeditdefaults'] = 'Default values for activity settings';
$string['modsettings'] = 'Manage activities';
$string['modulesecurity'] = 'Module security';
$string['configenablecompletion'] = 'When enabled, this lets you turn on completion tracking (progress) features at course level.';
$string['csvdownload'] = 'Download in spreadsheet format (UTF-8 .csv)';
$string['deletecoursecompletiondata'] = 'Delete course completion data';
+$string['deletecompletiondata'] = 'Delete completion data';
$string['enablecompletion'] = 'Enable completion tracking';
$string['err_noactivities'] = 'Completion information is not enabled for any activity, so none can be displayed. You can enable completion information by editing the settings for an activity.';
$string['err_nousers'] = 'There are no students on this course or group for whom completion information is displayed. (By default, completion information is displayed only for students, so if there are no students, you will see this error. Administrators can alter this option via the admin screens.)';
$string['message'] = 'Message';
$string['messagehistory'] = 'Message history';
$string['messagehistoryfull'] = 'All messages';
+$string['messagenavigation'] = 'Message navigation:';
$string['messages'] = 'Messages';
$string['messaging'] = 'Messaging';
$string['messagingblockednoncontact'] = '{$a} will not be able to reply as you have blocked non-contacts';
$string['coursedisplay_single'] = 'Show all sections on one page';
$string['coursedisplay_multi'] = 'Show one section per page';
$string['coursedeleted'] = 'Deleted course {$a}';
+$string['courseextendednamedisplay'] = '{$a->shortname} {$a->fullname}';
$string['coursefiles'] = 'Legacy course files';
$string['coursefilesedit'] = 'Edit legacy course files';
$string['coursefileswarning'] = 'Course files are deprecated';
* Personal - The note will be visible only to you
* Course - The note will be visible to teachers in this course
* Site - The note will be visible to teachers in all courses';
+$string['selectnotestate'] = "Select note state";
$string['site'] = 'site';
$string['sitenotes'] = 'Site notes';
$string['unknown'] = 'unknown';
if ($short){
$name .= format_string($course->shortname, true, array('context' => $this));
} else {
- $name .= format_string($course->fullname);
+ $name .= format_string(get_course_display_name_for_list($course));
}
}
}
if (!$this->page->theme->enable_dock) {
return false;
}
+
+ // Do not dock the region when the user attemps to move a block.
+ if ($this->movingblock) {
+ return false;
+ }
+
$this->check_is_loaded();
$this->ensure_content_created($region, $output);
foreach($this->visibleblockcontent[$region] as $instance) {
$this->timecompleted = $timecomplete;
// Save record
- return $this->_save();
+ if ($result = $this->_save()) {
+ events_trigger('course_completed', $this->get_record_data());
+ }
+
+ return $result;
}
/**
$DB->delete_records('course_completion_crit_compl', array('course' => $this->course_id));
}
+ /**
+ * Deletes all activity and course completion data for an entire course
+ * (the below delete_all_state function does this for a single activity).
+ *
+ * Used by course reset page.
+ */
+ public function delete_all_completion_data() {
+ global $DB;
+
+ // Delete from database.
+ $DB->delete_records_select('course_modules_completion',
+ 'coursemoduleid IN (SELECT id FROM {course_modules} WHERE course=?)',
+ array($this->course_id));
+
+ // Reset cache for current user.
+ if (isset($SESSION->completioncache) &&
+ array_key_exists($this->course_id, $SESSION->completioncache)) {
+
+ unset($SESSION->completioncache[$this->course_id]);
+ }
+
+ // Wipe course completion data too.
+ $this->delete_course_completion_data();
+ }
+
/**
* Deletes completion state related to an activity for all users.
*
}
+ // Run question bank clean-up.
+ mtrace("Starting the question bank cron...", '');
+ require_once($CFG->libdir . '/questionlib.php');
+ question_bank::cron();
+ mtrace('done.');
+
+
//Run registration updated cron
mtrace(get_string('siteupdatesstart', 'hub'));
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
upgrade_main_savepoint(true, 2012062501.06);
}
+ if ($oldversion < 2012062501.08) {
+ // Drop obsolete question upgrade field that should have been added to the install.xml.
+ $table = new xmldb_table('question');
+ $field = new xmldb_field('oldquestiontextformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
+
+ if ($dbman->field_exists($table, $field)) {
+ $dbman->drop_field($table, $field);
+ }
+
+ upgrade_main_savepoint(true, 2012062501.08);
+ }
+
return true;
}
$column = (object)array_change_key_case((array)$column, CASE_LOWER);
if (stripos($column->type, 'unsigned') !== false) {
+ $maxvalue = 0;
+ if (preg_match('/^int/i', $column->type)) {
+ $maxvalue = 2147483647;
+ } else if (preg_match('/^medium/i', $column->type)) {
+ $maxvalue = 8388607;
+ } else if (preg_match('/^smallint/i', $column->type)) {
+ $maxvalue = 32767;
+ } else if (preg_match('/^tinyint/i', $column->type)) {
+ $maxvalue = 127;
+ }
+ if ($maxvalue) {
+ // Make sure nobody is abusing our integer ranges - moodle int sizes are in digits, not bytes!!!
+ $invalidcount = $DB->get_field_sql("SELECT COUNT('x') FROM `{{$table}}` WHERE `$column->field` > :maxnumber", array('maxnumber'=>$maxvalue));
+ if ($invalidcount) {
+ throw new moodle_exception('notlocalisederrormessage', 'error', new moodle_url('/admin/'), "Database table '{$table}'' contains unsigned column '{$column->field}' with $invalidcount values that are out of allowed range, upgrade can not continue.");
+ }
+ }
$type = preg_replace('/unsigned/i', 'signed', $column->type);
$notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
$default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : '';
}
}
- if ('publishstate' === 'public') {
+ if ($entry->publishstate === 'public') {
if ($CFG->forcelogin) {
require_login();
}
- } else if ('publishstate' === 'site') {
+ } else if ($entry->publishstate === 'site') {
require_login();
//ok
- } else if ('publishstate' === 'draft') {
+ } else if ($entry->publishstate === 'draft') {
require_login();
if ($USER->id != $entry->userid) {
send_file_not_found();
$this->_options['maxbytes'] = get_max_upload_file_size($CFG->maxbytes, $options['maxbytes']);
}
if (!$this->_options['context']) {
- $this->_options['context'] = get_context_instance(CONTEXT_SYSTEM);
+ // trying to set context to the current page context to make legacy files show in filepicker (e.g. forum post)
+ if (!empty($PAGE->context->id)) {
+ $this->_options['context'] = $PAGE->context;
+ } else {
+ $this->_options['context'] = context_system::instance();
+ }
}
$this->_options['trusted'] = trusttext_trusted($this->_options['context']);
parent::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
return M.form.showAdvanced;
};
+/**
+ * Stores a list of the dependencyManager for each form on the page.
+ */
+M.form.dependencyManagers = {};
+
/**
* Initialises a manager for a forms dependencies.
* This should happen once per form.
return this.checkDependencies(null);
},
/**
- * Gets all elements in the form by thier name and returns
+ * Gets all elements in the form by their name and returns
* a YUI NodeList
* @return Y.NodeList
*/
return dependencyManager;
})();
- return new M.form.dependencyManager();
-};
\ No newline at end of file
+ M.form.dependencyManagers[formid] = new M.form.dependencyManager();
+ return M.form.dependencyManagers[formid];
+};
+
+/**
+ * Update the state of a form. You need to call this after, for example, changing
+ * the state of some of the form input elements in your own code, in order that
+ * things like the disableIf state of elements can be updated.
+ */
+M.form.updateFormState = function(formid) {
+ if (formid in M.form.dependencyManagers) {
+ M.form.dependencyManagers[formid].checkDependencies(null);
+ }
+};
'year' => 2011,
'usertimezone' => 0.0,
'timezone' => 0.0,
- 'timestamp' => 1309449600
+ 'timestamp' => 1309478400 // 6am at UTC+0
),
array (
'day' => 1,
'year' => 2011,
'usertimezone' => 0.0,
'timezone' => 99,
- 'timestamp' => 1309449600
+ 'timestamp' => 1309478400 // 6am at UTC+0
)
);
}
'year' => 2011,
'usertimezone' => 0.0,
'timezone' => 0.0,
- 'timestamp' => 1309449600
+ 'timestamp' => 1309478400 // 6am at UTC+0
),
array (
'minute' => 0,
'year' => 2011,
'usertimezone' => 0.0,
'timezone' => 99,
- 'timestamp' => 1309449600
+ 'timestamp' => 1309478400 // 6am at UTC+0
)
);
}
$function = 'M.form.dateselector.init_date_selectors';
$config = array(array(
'firstdayofweek' => get_string('firstdayofweek', 'langconfig'),
- 'mon' => strftime('%a', 360000), // 5th Jan 1970 at 12pm
- 'tue' => strftime('%a', 446400),
- 'wed' => strftime('%a', 532800),
- 'thu' => strftime('%a', 619200),
- 'fri' => strftime('%a', 705600),
- 'sat' => strftime('%a', 792000),
- 'sun' => strftime('%a', 878400),
- 'january' => strftime('%B', 14400), // 1st Jan 1970 at 12pm
- 'february' => strftime('%B', 2692800),
- 'march' => strftime('%B', 5112000),
- 'april' => strftime('%B', 7790400),
- 'may' => strftime('%B', 10382400),
- 'june' => strftime('%B', 13060800),
- 'july' => strftime('%B', 15652800),
- 'august' => strftime('%B', 18331200),
- 'september' => strftime('%B', 21009600),
- 'october' => strftime('%B', 23601600),
- 'november' => strftime('%B', 26280000),
- 'december' => strftime('%B', 28872000)
+ 'mon' => strftime('%a', strtotime("Monday")), // 5th Jan 1970 at 12pm
+ 'tue' => strftime('%a', strtotime("Tuesday")),
+ 'wed' => strftime('%a', strtotime("Wednesday")),
+ 'thu' => strftime('%a', strtotime("Thursday")),
+ 'fri' => strftime('%a', strtotime("Friday")),
+ 'sat' => strftime('%a', strtotime("Saturday")),
+ 'sun' => strftime('%a', strtotime("Sunday")),
+ 'january' => strftime('%B', strtotime("January")), // 1st Jan 1970 at 12pm
+ 'february' => strftime('%B', strtotime("February")),
+ 'march' => strftime('%B', strtotime("March")),
+ 'april' => strftime('%B', strtotime("April")),
+ 'may' => strftime('%B', strtotime("May")),
+ 'june' => strftime('%B', strtotime("June")),
+ 'july' => strftime('%B', strtotime("July")),
+ 'august' => strftime('%B', strtotime("August")),
+ 'september' => strftime('%B', strtotime("September")),
+ 'october' => strftime('%B', strtotime("October")),
+ 'november' => strftime('%B', strtotime("November")),
+ 'december' => strftime('%B', strtotime("December"))
));
$PAGE->requires->yui_module($module, $function, $config);
$done = true;
// Standardise score to the new grade range
// NOTE: this is not compatible with current assignment grading
- if ($this->itemmodule != 'assignment' and ($rawmin != $this->grademin or $rawmax != $this->grademax)) {
+ $isassignmentmodule = ($this->itemmodule == 'assignment') || ($this->itemmodule == 'assign');
+ if (!$isassignmentmodule && ($rawmin != $this->grademin or $rawmax != $this->grademax)) {
$rawgrade = grade_grade::standardise_score($rawgrade, $rawmin, $rawmax, $this->grademin, $this->grademax);
}
if (!args.url.match(/https?:\/\//)) {
fullurl = M.cfg.wwwroot + args.url;
}
+ if (args.fullscreen) {
+ args.options = args.options.
+ replace(/top=\d+/, 'top=0').
+ replace(/left=\d+/, 'left=0').
+ replace(/width=\d+/, 'width=' + screen.availWidth).
+ replace(/height=\d+/, 'height=' + screen.availHeight);
+ }
var windowobj = window.open(fullurl,args.name,args.options);
if (!windowobj) {
return true;
}
+
if (args.fullscreen) {
- windowobj.moveTo(0,0);
- windowobj.resizeTo(screen.availWidth,screen.availHeight);
+ // In some browser / OS combinations (E.g. Chrome on Windows), the
+ // window initially opens slighly too big. The width and heigh options
+ // seem to control the area inside the browser window, so what with
+ // scroll-bars, etc. the actual window is bigger than the screen.
+ // Therefore, we need to fix things up after the window is open.
+ var hackcount = 100;
+ var get_size_exactly_right = function() {
+ windowobj.moveTo(0, 0);
+ windowobj.resizeTo(screen.availWidth, screen.availHeight);
+
+ // Unfortunately, it seems that in Chrome on Ubuntu, if you call
+ // something like windowobj.resizeTo(1280, 1024) too soon (up to
+ // about 50ms) after the window is open, then it actually behaves
+ // as if you called windowobj.resizeTo(0, 0). Therefore, we need to
+ // check that the resize actually worked, and if not, repeatedly try
+ // again after a short delay until it works (but with a limit of
+ // hackcount repeats.
+ if (hackcount > 0 && (windowobj.innerHeight < 10 || windowobj.innerWidth < 10)) {
+ hackcount -= 1;
+ setTimeout(get_size_exactly_right, 10);
+ }
+ }
+ setTimeout(get_size_exactly_right, 0);
}
windowobj.focus();
$output = <<<OET
<span class="mediaplugin mediaplugin_vimeo">
-<iframe title="$info" src="http://player.vimeo.com/video/$videoid"
+<iframe title="$info" src="https://player.vimeo.com/video/$videoid"
width="$width" height="$height" frameborder="0"></iframe>
</span>
OET;
protected function get_regex() {
// Initial part of link.
- $start = '~^http://vimeo\.com/';
+ $start = '~^https?://vimeo\.com/';
// Middle bit: either watch?v= or v/.
$middle = '([0-9]+)';
return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
if (empty($CFG->xmlstrictheaders)) {
return <<<OET
-<iframe title="$info" width="$width" height="$height"
- src="$site/embed/$videoid?rel=0&wmode=transparent" frameborder="0" allowfullscreen></iframe>
+<span class="mediaplugin mediaplugin_youtube">
+<iframe title="$info" width="$width" height="$height" src="https://$site/embed/$videoid?rel=0&wmode=transparent" frameborder="0" allowfullscreen="1"></iframe>
+</span>
OET;
}
$output = <<<OET
<span class="mediaplugin mediaplugin_youtube">
<object title="$info" type="application/x-shockwave-flash"
- data="$site/v/$videoid&fs=1&rel=0" width="$width" height="$height">
+ data="https://$site/v/$videoid&fs=1&rel=0" width="$width" height="$height">
<param name="movie" value="$site/v/$videoid&fs=1&rel=0" />
<param name="FlashVars" value="playerMode=embedded" />
<param name="allowFullScreen" value="true" />
protected function get_regex() {
// Initial part of link.
- $start = '~^(https?://www\.youtube(-nocookie)?\.com)/';
+ $start = '~^https?://(www\.youtube(-nocookie)?\.com)/';
// Middle bit: either watch?v= or v/.
$middle = '(?:watch\?v=|v/)([a-z0-9\-_]+)';
return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
self::pick_video_size($width, $height);
- // TODO: iframe HTML 5 video not implemented and object does not work
- // on iOS devices.
- $fallback = core_media_player::PLACEHOLDER;
- $output = <<<OET
+ return <<<OET
<span class="mediaplugin mediaplugin_youtube">
-<object title="$info" type="application/x-shockwave-flash"
- data="$site/p/$playlist&fs=1&rel=0" width="$width" height="$height">
- <param name="movie" value="$site/v/$playlist&fs=1&rel=0" />
- <param name="FlashVars" value="playerMode=embedded" />
- <param name="allowFullScreen" value="true" />
-$fallback</object>
+<iframe width="$width" height="$height" src="https://$site/embed/videoseries?list=$playlist" frameborder="0" allowfullscreen="1"></iframe>
</span>
OET;
-
- return $output;
}
protected function get_regex() {
// Initial part of link.
- $start = '~^(https?://www\.youtube(-nocookie)?\.com)/';
+ $start = '~^https?://(www\.youtube(-nocookie)?\.com)/';
// Middle bit: either view_play_list?p= or p/ (doesn't work on youtube) or playlist?list=.
$middle = '(?:view_play_list\?p=|p/|playlist\?list=)([a-z0-9\-_]+)';
return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
//TODO: we need to solve problems with database transactions here somehow, for now we just prevent transactions - sorry
$DB->transactions_forbidden();
- if (is_int($eventdata->userto)) {
+ if (is_number($eventdata->userto)) {
$eventdata->userto = $DB->get_record('user', array('id' => $eventdata->userto));
}
if (is_int($eventdata->userfrom)) {
*/
define('USER_CAN_IGNORE_FILE_SIZE_LIMITS', -1);
+/**
+ * Course display settings
+ */
+define('COURSE_DISPLAY_SINGLEPAGE', 0); // display all sections on one page
+define('COURSE_DISPLAY_MULTIPAGE', 1); // split pages into a page per section
+
/// PARAMETER HANDLING ////////////////////////////////////////////////////
/**
$tz = 99;
- while(($tz == '' || $tz == 99 || $tz == NULL) && $next = each($timezones)) {
+ // Loop while $tz is, empty but not zero, or 99, and there is another timezone is the array
+ while(((empty($tz) && !is_numeric($tz)) || $tz == 99) && $next = each($timezones)) {
$tz = $next['value'];
}
-
return is_numeric($tz) ? (float) $tz : $tz;
}
function update_user_login_times() {
global $USER, $DB;
+ $now = time();
+
$user = new stdClass();
+ $user->id = $USER->id;
+
+ // Make sure all users that logged in have some firstaccess.
+ if ($USER->firstaccess == 0) {
+ $USER->firstaccess = $user->firstaccess = $now;
+ }
+
+ // Store the previous current as lastlogin.
$USER->lastlogin = $user->lastlogin = $USER->currentlogin;
- $USER->currentlogin = $user->lastaccess = $user->currentlogin = time();
- $user->id = $USER->id;
+ $USER->currentlogin = $user->currentlogin = $now;
+
+ // Function user_accesstime_log() may not update immediately, better do it here.
+ $USER->lastaccess = $user->lastaccess = $now;
+ $USER->lastip = $user->lastip = getremoteaddr();
$DB->update_record('user', $user);
return true;
$DB->set_field('user', 'auth', $auth, array('username'=>$username));
$user->auth = $auth;
}
- if (empty($user->firstaccess)) { //prevent firstaccess from remaining 0 for manual account that never required confirmation
- $DB->set_field('user','firstaccess', $user->timemodified, array('id' => $user->id));
- $user->firstaccess = $user->timemodified;
- }
update_internal_user_password($user, $password); // just in case salt or encoding were changed (magic quotes too one day)
$status[] = array('component'=>$componentstr, 'item'=>get_string('deleteblogassociations', 'blog'), 'error'=>false);
}
- if (!empty($data->reset_course_completion)) {
- // Delete course completion information
+ if (!empty($data->reset_completion)) {
+ // Delete course and activity 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);
+ $cc->delete_all_completion_data();
+ $status[] = array('component' => $componentstr,
+ 'item' => get_string('deletecompletiondata', 'completion'), 'error' => false);
}
$componentstr = get_string('roles');
}
}
- if ($sitebytes and $sitebytes < $minimumsize) {
+ if (($sitebytes > 0) and ($sitebytes < $minimumsize)) {
$minimumsize = $sitebytes;
}
- if ($coursebytes and $coursebytes < $minimumsize) {
+ if (($coursebytes > 0) and ($coursebytes < $minimumsize)) {
$minimumsize = $coursebytes;
}
- if ($modulebytes and $modulebytes < $minimumsize) {
+ if (($modulebytes > 0) and ($modulebytes < $minimumsize)) {
$minimumsize = $modulebytes;
}
if (empty($version)) {
return true; // no version specified
}
- if (preg_match("/Opera\/([0-9\.]+)/i", $agent, $match)) {
+ // Recent Opera useragents have Version/ with the actual version, e.g.:
+ // Opera/9.80 (Windows NT 6.1; WOW64; U; en) Presto/2.10.289 Version/12.01
+ // That's Opera 12.01, not 9.8.
+ if (preg_match("/Version\/([0-9\.]+)/i", $agent, $match)) {
+ if (version_compare($match[1], $version) >= 0) {
+ return true;
+ }
+ } else if (preg_match("/Opera\/([0-9\.]+)/i", $agent, $match)) {
if (version_compare($match[1], $version) >= 0) {
return true;
}
if (empty($version)) {
return true; // no version specified
}
- if (preg_match("/AppleWebKit\/([0-9]+)/i", $agent, $match)) {
+ if (preg_match("/AppleWebKit\/([0-9.]+)/i", $agent, $match)) {
if (version_compare($match[1], $version) >= 0) {
return true;
}
if (empty($version)) {
return true; // no version specified
}
- if (preg_match("/AppleWebKit\/([0-9]+)/i", $agent, $match)) {
+ if (preg_match("/AppleWebKit\/([0-9.]+)/i", $agent, $match)) {
if (version_compare($match[1], $version) >= 0) {
return true;
}
*/
function can_use_rotated_text() {
global $USER;
- return ajaxenabled(array('Firefox' => 2.0)) && !$USER->screenreader;;
+ return (check_browser_version('MSIE', 9) || check_browser_version('Firefox', 2) ||
+ check_browser_version('Chrome', 21) || check_browser_version('Safari', 536.25) ||
+ check_browser_version('Opera', 12) || check_browser_version('Safari iOS', 533)) &&
+ !$USER->screenreader;
}
/**
return HOMEPAGE_SITE;
}
+/**
+ * Gets the name of a course to be displayed when showing a list of courses.
+ * By default this is just $course->fullname but user can configure it. The
+ * result of this function should be passed through print_string.
+ * @param object $course Moodle course object
+ * @return string Display name of course (either fullname or short + fullname)
+ */
+function get_course_display_name_for_list($course) {
+ global $CFG;
+ if (!empty($CFG->courselistshortnames)) {
+ return get_string('courseextendednamedisplay', '', $course);
+ } else {
+ return $course->fullname;
+ }
+}
+
/**
* The lang_string class
*
// Add the module chooser toggle
$modchoosertoggleurl = clone($baseurl);
if ($this->page->user_is_editing() && course_ajax_enabled($course)) {
- if ($usemodchooser = get_user_preferences('usemodchooser', 1)) {
+ if ($usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault)) {
$modchoosertogglestring = get_string('modchooserdisable', 'moodle');
$modchoosertoggleurl->param('modchooser', 'off');
} else {
* @return bool
*/
function phpunit_bootstrap_is_cygwin() {
- if (empty($_SERVER['SHELL']) or empty($_SERVER['OS'])) {
+ if (empty($_SERVER['OS']) or $_SERVER['OS'] !== 'Windows_NT') {
+ return false;
+
+ } else if (!empty($_SERVER['SHELL']) and $_SERVER['SHELL'] === '/bin/bash') {
+ return true;
+
+ } else if (!empty($_SERVER['TERM']) and $_SERVER['TERM'] === 'cygwin') {
+ return true;
+
+ } else {
return false;
}
- return ($_SERVER['OS'] === 'Windows_NT' and $_SERVER['SHELL'] === '/bin/bash');
}
}
if (!isset($record['descriptionformat'])) {
- $record['description'] = FORMAT_MOODLE;
+ $record['descriptionformat'] = FORMAT_MOODLE;
}
if (!isset($record['parent'])) {
- $record['descriptionformat'] = 0;
+ $record['parent'] = 0;
}
if (empty($record['parent'])) {
$record['numsections'] = 5;
}
- if (!isset($record['description'])) {
- $record['description'] = "Test course $i\n$this->loremipsum";
+ if (!isset($record['summary'])) {
+ $record['summary'] = "Test course $i\n$this->loremipsum";
}
- if (!isset($record['descriptionformat'])) {
- $record['description'] = FORMAT_MOODLE;
+ if (!isset($record['summaryformat'])) {
+ $record['summaryformat'] = FORMAT_MOODLE;
}
if (!isset($record['category'])) {
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class Hint_ResultPrinter extends PHPUnit_TextUI_ResultPrinter {
+ public function __construct() {
+ // ARRGH - PHPUnit does not give us commandline arguments or xml config, so let's hack hard!
+ if (defined('DEBUG_BACKTRACE_PROVIDE_OBJECT')) {
+ $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);
+ if (isset($backtrace[2]['object']) and ($backtrace[2]['object'] instanceof PHPUnit_TextUI_Command)) {
+ list($verbose, $colors, $debug) = Hacky_TextUI_Command_reader::get_settings_hackery($backtrace[2]['object']);
+ parent::__construct(null, $verbose, $colors, $debug);
+ return;
+ }
+ }
+ // Fallback if something goes wrong.
+ parent::__construct(null, false, false, false);
+ }
+
protected function printDefectTrace(PHPUnit_Framework_TestFailure $defect) {
global $CFG;
$this->write("\nTo re-run:\n $executable $testName $file\n");
}
}
+
+
+/**
+ * Class used in bloody hack that works around result printer constructor troubles.
+ *
+ * @package core
+ * @category phpunit
+ * @copyright 2012 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class Hacky_TextUI_Command_reader extends PHPUnit_TextUI_Command {
+ public static function get_settings_hackery(PHPUnit_TextUI_Command $toread) {
+ $arguments = $toread->arguments;
+ $config = PHPUnit_Util_Configuration::getInstance($arguments['configuration'])->getPHPUnitConfiguration();
+
+ $verbose = isset($config['verbose']) ? $config['verbose'] : false;
+ $verbose = isset($arguments['verbose']) ? $arguments['verbose'] : $verbose;
+
+ $colors = isset($config['colors']) ? $config['colors'] : false;
+ $colors = isset($arguments['colors']) ? $arguments['colors'] : $colors;
+
+ $debug = isset($config['debug']) ? $config['debug'] : false;
+ $debug = isset($arguments['debug']) ? $arguments['debug'] : $debug;
+
+ return array($verbose, $colors, $debug);
+ }
+}
* Note: To be used from CLI scripts only.
*
* @static
+ * @param bool $displayprogress if true, this method will echo progress information.
* @return void may terminate execution with exit code
*/
- public static function drop_site() {
+ public static function drop_site($displayprogress = false) {
global $DB, $CFG;
if (!self::is_test_site()) {
phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, 'Can not drop non-test site!!');
}
- // purge dataroot
+ // Purge dataroot
+ if ($displayprogress) {
+ echo "Purging dataroot:\n";
+ }
self::reset_dataroot();
phpunit_bootstrap_initdataroot($CFG->dataroot);
$keep = array('.', '..', 'lock', 'webrunner.xml');
unset($tables['config']);
$tables['config'] = 'config';
}
+
+ if ($displayprogress) {
+ echo "Dropping tables:\n";
+ }
+ $dotsonline = 0;
foreach ($tables as $tablename) {
$table = new xmldb_table($tablename);
$DB->get_manager()->drop_table($table);
+
+ if ($dotsonline == 60) {
+ if ($displayprogress) {
+ echo "\n";
+ }
+ $dotsonline = 0;
+ }
+ if ($displayprogress) {
+ echo '.';
+ }
+ $dotsonline += 1;
+ }
+ if ($displayprogress) {
+ echo "\n";
}
}
$count = $DB->count_records('course_categories');
$category = $generator->create_category();
$this->assertEquals($count+1, $DB->count_records('course_categories'));
+ $this->assertRegExp('/^Course category \d/', $category->name);
+ $this->assertSame('', $category->idnumber);
+ $this->assertRegExp('/^Test course category \d/', $category->description);
+ $this->assertSame(FORMAT_MOODLE, $category->descriptionformat);
$count = $DB->count_records('course');
$course = $generator->create_course();
$this->assertEquals($count+1, $DB->count_records('course'));
+ $this->assertRegExp('/^Test course \d/', $course->fullname);
+ $this->assertRegExp('/^tc_\d/', $course->shortname);
+ $this->assertSame('', $course->idnumber);
+ $this->assertSame('topics', $course->format);
+ $this->assertEquals(0, $course->newsitems);
+ $this->assertEquals(5, $course->numsections);
+ $this->assertRegExp('/^Test course \d/', $course->summary);
+ $this->assertSame(FORMAT_MOODLE, $course->summaryformat);
$section = $generator->create_course_section(array('course'=>$course->id, 'section'=>3));
$this->assertEquals($course->id, $section->course);
+++ /dev/null
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Unit tests for backups.
- *
- * @package core
- * @category phpunit
- * @copyright 2012 Frédéric Massart <fred@moodle.com>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-require_once($CFG->dirroot . '/backup/util/helper/backup_cron_helper.class.php');
-
-/**
- * Unit tests for backup system
- */
-class backup_testcase extends advanced_testcase {
-
- public function test_next_automated_backup() {
-
- $this->resetAfterTest();
- $admin = get_admin();
- $timezone = $admin->timezone;
-
- // Notes
- // - The next automated backup will never be on the same date than $now
- // - backup_auto_weekdays starts on Sunday
- // - Tests cannot be done in the past.
-
- // Every Wed and Sat at 11pm.
- set_config('backup_auto_active', '1', 'backup');
- set_config('backup_auto_weekdays', '0010010', 'backup');
- set_config('backup_auto_hour', '23', 'backup');
- set_config('backup_auto_minute', '0', 'backup');
-
- $now = strtotime('next Monday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('2-23:00', date('w-H:i', $next));
-
- $now = strtotime('next Tuesday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('5-23:00', date('w-H:i', $next));
-
- $now = strtotime('next Wednesday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('5-23:00', date('w-H:i', $next));
-
- $now = strtotime('next Thursday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('5-23:00', date('w-H:i', $next));
-
- $now = strtotime('next Friday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('2-23:00', date('w-H:i', $next));
-
- $now = strtotime('next Saturday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('2-23:00', date('w-H:i', $next));
-
- $now = strtotime('next Sunday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('2-23:00', date('w-H:i', $next));
-
- // Every Sun and Sat at 12pm.
- set_config('backup_auto_active', '1', 'backup');
- set_config('backup_auto_weekdays', '1000001', 'backup');
- set_config('backup_auto_hour', '0', 'backup');
- set_config('backup_auto_minute', '0', 'backup');
-
- $now = strtotime('next Monday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('6-00:00', date('w-H:i', $next));
-
- $now = strtotime('next Tuesday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('6-00:00', date('w-H:i', $next));
-
- $now = strtotime('next Wednesday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('6-00:00', date('w-H:i', $next));
-
- $now = strtotime('next Thursday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('6-00:00', date('w-H:i', $next));
-
- $now = strtotime('next Friday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('6-00:00', date('w-H:i', $next));
-
- $now = strtotime('next Saturday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('0-00:00', date('w-H:i', $next));
-
- $now = strtotime('next Sunday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('6-00:00', date('w-H:i', $next));
-
- // Every Sun at 4am.
- set_config('backup_auto_active', '1', 'backup');
- set_config('backup_auto_weekdays', '1000000', 'backup');
- set_config('backup_auto_hour', '4', 'backup');
- set_config('backup_auto_minute', '0', 'backup');
-
- $now = strtotime('next Monday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('0-04:00', date('w-H:i', $next));
-
- $now = strtotime('next Tuesday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('0-04:00', date('w-H:i', $next));
-
- $now = strtotime('next Wednesday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('0-04:00', date('w-H:i', $next));
-
- $now = strtotime('next Thursday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('0-04:00', date('w-H:i', $next));
-
- $now = strtotime('next Friday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('0-04:00', date('w-H:i', $next));
-
- $now = strtotime('next Saturday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('0-04:00', date('w-H:i', $next));
-
- $now = strtotime('next Sunday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('0-04:00', date('w-H:i', $next));
-
- // Every day but Wed at 8:30pm.
- set_config('backup_auto_active', '1', 'backup');
- set_config('backup_auto_weekdays', '1110111', 'backup');
- set_config('backup_auto_hour', '20', 'backup');
- set_config('backup_auto_minute', '30', 'backup');
-
- $now = strtotime('next Monday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('2-20:30', date('w-H:i', $next));
-
- $now = strtotime('next Tuesday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('4-20:30', date('w-H:i', $next));
-
- $now = strtotime('next Wednesday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('4-20:30', date('w-H:i', $next));
-
- $now = strtotime('next Thursday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('5-20:30', date('w-H:i', $next));
-
- $now = strtotime('next Friday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('6-20:30', date('w-H:i', $next));
-
- $now = strtotime('next Saturday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('0-20:30', date('w-H:i', $next));
-
- $now = strtotime('next Sunday');
- $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
- $this->assertEquals('1-20:30', date('w-H:i', $next));
-
- }
-}
// Format: youtube playlist.
$url = new moodle_url('http://www.youtube.com/view_play_list?p=PL6E18E2927047B662');
$t = $renderer->embed_url($url);
- $this->assertTrue(self::str_contains($t, '</object>'));
+ $this->assertTrue(self::str_contains($t, '</iframe>'));
$url = new moodle_url('http://www.youtube.com/playlist?list=PL6E18E2927047B662');
$t = $renderer->embed_url($url);
- $this->assertTrue(self::str_contains($t, '</object>'));
+ $this->assertTrue(self::str_contains($t, '</iframe>'));
$url = new moodle_url('http://www.youtube.com/p/PL6E18E2927047B662');
$t = $renderer->embed_url($url);
- $this->assertTrue(self::str_contains($t, '</object>'));
+ $this->assertTrue(self::str_contains($t, '</iframe>'));
// Format: vimeo.
$url = new moodle_url('http://vimeo.com/1176321');
'hour' => '10',
'minutes' => '00',
'seconds' => '00',
- 'timezone' => '0.0', //no dst offset
- 'applydst' => false,
- 'expectedoutput' => '1309528800'
+ 'timezone' => '0.0',
+ 'applydst' => false, //no dst offset
+ 'expectedoutput' => '1309514400' // 6pm at UTC+0
),
array(
'usertimezone' => 'America/Moncton',
private $_server;
private $_protocol = 'HTTP/1.1';
private $_port = 80;
+ private $_socket = '';
private $_path ='/';
private $_auth = false;
private $_user;
private $_req;
private $_resp_status;
private $_parser;
+ private $_parserid;
private $_xmltree;
private $_tree;
private $_ls = array();
private $_body='';
private $_connection_closed = false;
private $_maxheaderlenth = 1000;
+ private $_digestchallenge = null;
+ private $_cnonce = '';
+ private $_nc = 0;
/**#@-*/
/**
* Constructor - Initialise class variables
*/
- function __construct($server = '', $user = '', $pass = '', $auth = false) {
+ function __construct($server = '', $user = '', $pass = '', $auth = false, $socket = '') {
if (!empty($server)) {
$this->_server = $server;
}
$this->pass = $pass;
}
$this->_auth = $auth;
+ $this->_socket = $socket;
}
public function __set($key, $value) {
$property = '_' . $key;
function open() {
// let's try to open a socket
$this->_error_log('open a socket connection');
- $this->sock = fsockopen($this->_server, $this->_port, $this->_errno, $this->_errstr, $this->_socket_timeout);
+ $this->sock = fsockopen($this->_socket . $this->_server, $this->_port, $this->_errno, $this->_errstr, $this->_socket_timeout);
set_time_limit(30);
if (is_resource($this->sock)) {
socket_set_blocking($this->sock, true);
if (strcmp($response['header']['Content-Type'], 'text/xml; charset="utf-8"') == 0) {
// ok let's get the content of the xml stuff
$this->_parser = xml_parser_create_ns();
+ $this->_parserid = (int) $this->_parser;
// forget old data...
- unset($this->_lock[$this->_parser]);
- unset($this->_xmltree[$this->_parser]);
+ unset($this->_lock[$this->_parserid]);
+ unset($this->_xmltree[$this->_parserid]);
xml_parser_set_option($this->_parser,XML_OPTION_SKIP_WHITE,0);
xml_parser_set_option($this->_parser,XML_OPTION_CASE_FOLDING,0);
xml_set_object($this->_parser, $this);
// Free resources
xml_parser_free($this->_parser);
// add status code to array
- $this->_lock[$this->_parser]['status'] = 200;
- return $this->_lock[$this->_parser];
+ $this->_lock[$this->_parserid]['status'] = 200;
+ return $this->_lock[$this->_parserid];
} else {
print 'Missing Content-Type: text/xml header in response.<br>';
if (strcmp($response['header']['Content-Type'], 'text/xml; charset="utf-8"') == 0) {
// ok let's get the content of the xml stuff
$this->_parser = xml_parser_create_ns();
+ $this->_parserid = (int) $this->_parser;
// forget old data...
- unset($this->_delete[$this->_parser]);
- unset($this->_xmltree[$this->_parser]);
+ unset($this->_delete[$this->_parserid]);
+ unset($this->_xmltree[$this->_parserid]);
xml_parser_set_option($this->_parser,XML_OPTION_SKIP_WHITE,0);
xml_parser_set_option($this->_parser,XML_OPTION_CASE_FOLDING,0);
xml_set_object($this->_parser, $this);
// Free resources
xml_parser_free($this->_parser);
- $this->_delete[$this->_parser]['status'] = $response['status']['status-code'];
- return $this->_delete[$this->_parser];
+ $this->_delete[$this->_parserid]['status'] = $response['status']['status-code'];
+ return $this->_delete[$this->_parserid];
} else {
print 'Missing Content-Type: text/xml header in response.<br>';
if (preg_match('#(application|text)/xml;\s?charset=[\'\"]?utf-8[\'\"]?#i', $response['header']['Content-Type'])) {
// ok let's get the content of the xml stuff
$this->_parser = xml_parser_create_ns('UTF-8');
+ $this->_parserid = (int) $this->_parser;
// forget old data...
- unset($this->_ls[$this->_parser]);
- unset($this->_xmltree[$this->_parser]);
+ unset($this->_ls[$this->_parserid]);
+ unset($this->_xmltree[$this->_parserid]);
xml_parser_set_option($this->_parser,XML_OPTION_SKIP_WHITE,0);
xml_parser_set_option($this->_parser,XML_OPTION_CASE_FOLDING,0);
// xml_parser_set_option($this->_parser,XML_OPTION_TARGET_ENCODING,'UTF-8');
// Free resources
xml_parser_free($this->_parser);
- $arr = $this->_ls[$this->_parser];
+ $arr = $this->_ls[$this->_parserid];
return $arr;
} else {
$this->_error_log('Missing Content-Type: text/xml header in response!!');
private function _endElement($parser, $name) {
// end tag was found...
- $this->_xmltree[$parser] = substr($this->_xmltree[$parser],0, strlen($this->_xmltree[$parser]) - (strlen($name) + 1));
+ $parserid = (int) $parser;
+ $this->_xmltree[$parserid] = substr($this->_xmltree[$parserid],0, strlen($this->_xmltree[$parserid]) - (strlen($name) + 1));
}
/**
*/
private function _propfind_startElement($parser, $name, $attrs) {
// lower XML Names... maybe break a RFC, don't know ...
+ $parserid = (int) $parser;
$propname = strtolower($name);
- if (!empty($this->_xmltree[$parser])) {
- $this->_xmltree[$parser] .= $propname . '_';
+ if (!empty($this->_xmltree[$parserid])) {
+ $this->_xmltree[$parserid] .= $propname . '_';
} else {
- $this->_xmltree[$parser] = $propname . '_';
+ $this->_xmltree[$parserid] = $propname . '_';
}
// translate xml tree to a flat array ...
- switch($this->_xmltree[$parser]) {
+ switch($this->_xmltree[$parserid]) {
case 'dav::multistatus_dav::response_':
// new element in mu
- $this->_ls_ref =& $this->_ls[$parser][];
+ $this->_ls_ref =& $this->_ls[$parserid][];
break;
case 'dav::multistatus_dav::response_dav::href_':
$this->_ls_ref_cdata = &$this->_ls_ref['href'];
default:
// handle unknown xml elements...
- $this->_ls_ref_cdata = &$this->_ls_ref[$this->_xmltree[$parser]];
+ $this->_ls_ref_cdata = &$this->_ls_ref[$this->_xmltree[$parserid]];
}
}
*/
private function _delete_startElement($parser, $name, $attrs) {
// lower XML Names... maybe break a RFC, don't know ...
+ $parserid = (int) $parser;
$propname = strtolower($name);
- $this->_xmltree[$parser] .= $propname . '_';
+ $this->_xmltree[$parserid] .= $propname . '_';
// translate xml tree to a flat array ...
- switch($this->_xmltree[$parser]) {
+ switch($this->_xmltree[$parserid]) {
case 'dav::multistatus_dav::response_':
// new element in mu
- $this->_delete_ref =& $this->_delete[$parser][];
+ $this->_delete_ref =& $this->_delete[$parserid][];
break;
case 'dav::multistatus_dav::response_dav::href_':
$this->_delete_ref_cdata = &$this->_ls_ref['href'];
default:
// handle unknown xml elements...
- $this->_delete_cdata = &$this->_delete_ref[$this->_xmltree[$parser]];
+ $this->_delete_cdata = &$this->_delete_ref[$this->_xmltree[$parserid]];
}
}
*/
private function _lock_startElement($parser, $name, $attrs) {
// lower XML Names... maybe break a RFC, don't know ...
+ $parserid = (int) $parser;
$propname = strtolower($name);
- $this->_xmltree[$parser] .= $propname . '_';
+ $this->_xmltree[$parserid] .= $propname . '_';
// translate xml tree to a flat array ...
/*
dav::prop_dav::lockdiscovery_dav::activelock_dav::timeout_=
dav::prop_dav::lockdiscovery_dav::activelock_dav::locktoken_dav::href_=
*/
- switch($this->_xmltree[$parser]) {
+ switch($this->_xmltree[$parserid]) {
case 'dav::prop_dav::lockdiscovery_dav::activelock_':
// new element
- $this->_lock_ref =& $this->_lock[$parser][];
+ $this->_lock_ref =& $this->_lock[$parserid][];
break;
case 'dav::prop_dav::lockdiscovery_dav::activelock_dav::locktype_dav::write_':
$this->_lock_ref_cdata = &$this->_lock_ref['locktype'];
break;
default:
// handle unknown xml elements...
- $this->_lock_cdata = &$this->_lock_ref[$this->_xmltree[$parser]];
+ $this->_lock_cdata = &$this->_lock_ref[$this->_xmltree[$parserid]];
}
}
* @access private
*/
private function _lock_cData($parser, $cdata) {
+ $parserid = (int) $parser;
if (trim($cdata) <> '') {
- // $this->_error_log(($this->_xmltree[$parser]) . '='. htmlentities($cdata));
+ // $this->_error_log(($this->_xmltree[$parserid]) . '='. htmlentities($cdata));
$this->_lock_ref_cdata .= $cdata;
} else {
// do nothing
* @access private
*/
private function create_basic_request($method) {
- $request = '';
$this->header_add(sprintf('%s %s %s', $method, $this->_path, $this->_protocol));
$this->header_add(sprintf('Host: %s:%s', $this->_server, $this->_port));
//$request .= sprintf('Connection: Keep-Alive');
$this->header_add('TE: Trailers');
if ($this->_auth == 'basic') {
$this->header_add(sprintf('Authorization: Basic %s', base64_encode("$this->_user:$this->_pass")));
+ } else if ($this->_auth == 'digest') {
+ if ($signature = $this->digest_signature($method)){
+ $this->header_add($signature);
+ }
+ }
+ }
+
+ /**
+ * Reads the header, stores the challenge information
+ *
+ * @return void
+ */
+ private function digest_auth() {
+
+ $headers = array();
+ $headers[] = sprintf('%s %s %s', 'HEAD', $this->_path, $this->_protocol);
+ $headers[] = sprintf('Host: %s:%s', $this->_server, $this->_port);
+ $headers[] = sprintf('User-Agent: %s', $this->_user_agent);
+ $headers = implode("\r\n", $headers);
+ $headers .= "\r\n\r\n";
+ fputs($this->sock, $headers);
+
+ // Reads the headers.
+ $i = 0;
+ $header = '';
+ do {
+ $header .= fread($this->sock, 1);
+ $i++;
+ } while (!preg_match('/\\r\\n\\r\\n$/', $header, $matches) && $i < $this->_maxheaderlenth);
+
+ // Analyse the headers.
+ $digest = array();
+ $splitheaders = explode("\r\n", $header);
+ foreach ($splitheaders as $line) {
+ if (!preg_match('/^WWW-Authenticate: Digest/', $line)) {
+ continue;
+ }
+ $line = substr($line, strlen('WWW-Authenticate: Digest '));
+ $params = explode(',', $line);
+ foreach ($params as $param) {
+ list($key, $value) = explode('=', trim($param), 2);
+ $digest[$key] = trim($value, '"');
+ }
+ break;
+ }
+
+ $this->_digestchallenge = $digest;
+ }
+
+ /**
+ * Generates the digest signature
+ *
+ * @return string signature to add to the headers
+ * @access private
+ */
+ private function digest_signature($method) {
+ if (!$this->_digestchallenge) {
+ $this->digest_auth();
}
+
+ $signature = array();
+ $signature['username'] = '"' . $this->_user . '"';
+ $signature['realm'] = '"' . $this->_digestchallenge['realm'] . '"';
+ $signature['nonce'] = '"' . $this->_digestchallenge['nonce'] . '"';
+ $signature['uri'] = '"' . $this->_path . '"';
+
+ if (isset($this->_digestchallenge['algorithm']) && $this->_digestchallenge['algorithm'] != 'MD5') {
+ $this->_error_log('Algorithm other than MD5 are not supported');
+ return false;
+ }
+
+ $a1 = $this->_user . ':' . $this->_digestchallenge['realm'] . ':' . $this->_pass;
+ $a2 = $method . ':' . $this->_path;
+
+ if (!isset($this->_digestchallenge['qop'])) {
+ $signature['response'] = '"' . md5(md5($a1) . ':' . $this->_digestchallenge['nonce'] . ':' . md5($a2)) . '"';
+ } else {
+ // Assume QOP is auth
+ if (empty($this->_cnonce)) {
+ $this->_cnonce = random_string();
+ $this->_nc = 0;
+ }
+ $this->_nc++;
+ $nc = sprintf('%08d', $this->_nc);
+ $signature['cnonce'] = '"' . $this->_cnonce . '"';
+ $signature['nc'] = '"' . $nc . '"';
+ $signature['qop'] = '"' . $this->_digestchallenge['qop'] . '"';
+ $signature['response'] = '"' . md5(md5($a1) . ':' . $this->_digestchallenge['nonce'] . ':' .
+ $nc . ':' . $this->_cnonce . ':' . $this->_digestchallenge['qop'] . ':' . md5($a2)) . '"';
+ }
+
+ $response = array();
+ foreach ($signature as $key => $value) {
+ $response[] = "$key=$value";
+ }
+ return 'Authorization: Digest ' . implode(', ', $response);
}
/**
// Therefore we need to reopen the socket, before are sending the next request...
$this->_error_log('Connection: close found');
$this->_connection_closed = true;
+ } else if (preg_match('@^HTTP/1\.(1|0) 401 @', $header)) {
+ $this->_error_log('The server requires an authentication');
}
+
// check how to get the data on socket stream
// chunked or content-length (HTTP/1.1) or
// one block until feof is received (HTTP/1.0)
fread($this->sock, 1); // also drop off the Line Feed
$chunk_size=hexdec($chunk_size); // convert to a number in decimal system
if ($chunk_size > 0) {
- $buffer .= fread($this->sock,$chunk_size);
+ $read = 0;
+ // Reading the chunk in one bite is not secure, we read it byte by byte.
+ while ($read < $chunk_size) {
+ $buffer .= fread($this->sock, 1);
+ $read++;
+ }
}
fread($this->sock, 2); // ditch the CRLF that trails the chunk
} while ($chunk_size); // till we reach the 0 length chunk (end marker)
// $this->_buffer = $header . "\r\n\r\n" . $buffer;
$this->_error_log($this->_header);
$this->_error_log($this->_body);
+
}
}
echo html_writer::start_tag('form', array('id' => 'usergroupform','method' => 'get','action' => ''));
- echo html_writer::start_tag('fieldset');
- echo html_writer::select($options, 'viewing', $viewing, false, array('id' => 'viewing','onchange' => 'this.form.submit()'));
- echo html_writer::end_tag('fieldset');
+ echo html_writer::start_tag('fieldset');
+ echo html_writer::label(get_string('messagenavigation', 'message'), 'viewing');
+ echo html_writer::select($options, 'viewing', $viewing, false, array('id' => 'viewing','onchange' => 'this.form.submit()'));
+ echo html_writer::end_tag('fieldset');
echo html_writer::end_tag('form');
}
<tr>
<td colspan="3" class="message_heading mdl-left">
<input type="hidden" name="sesskey" value="<?php p(sesskey()); ?>" />
+ <label for="combinedsearch" class="accesshide"><?php print_string('searchcombined', 'message'); ?></label>
<input type="text" name="combinedsearch" size="40" id="combinedsearch" value="<?php p($combinedsearchstring); ?>" />
<input type="submit" name="combinedsubmit" value="<?php print_string('searchcombined','message') ?>" />
<a href="index.php?usergroup=<?php echo MESSAGE_VIEW_SEARCH ?>&advanced=1" id="advancedcontactsearchlink"><?php print_string('advanced') ?></a>
*/
public function can_upgrade($type, $version) {
- if (($type == 'upload' || $type == 'uploadsingle') && $version >= 2011112900) {
+ if (($type == 'upload' || $type == 'uploadsingle' ||
+ $type == 'online' || $type == 'offline') && $version >= 2011112900) {
return true;
}
return false;
}
/**
- * Format a user record for display (don't link to profile)
+ * Format a user record for display (link to profile)
*
* @param stdClass $row
* @return string
*/
function col_fullname($row) {
- return fullname($row);
+ $courseid = $this->assignment->get_course()->id;
+ $link= new moodle_url('/user/view.php', array('id' =>$row->id, 'course'=>$courseid));
+ return $this->output->action_link($link, fullname($row));
}
/**
$cm = get_coursemodule_from_instance('assign', $assignment->id, 0, false, MUST_EXIST);
$link = html_writer::link(new moodle_url('/mod/assign/view.php', array('id' => $cm->id)), $assignment->name);
- $date = userdate($assignment->duedate);
- $submissions = $DB->count_records('assign_submission', array('assignment'=>$cm->instance));
+ $date = '-';
+ if (!empty($assignment->duedate)) {
+ $date = userdate($assignment->duedate);
+ }
+
+ $params = array('assignment'=>$cm->instance, 'status'=>ASSIGN_SUBMISSION_STATUS_SUBMITTED);
+ $submissions = $DB->count_records('assign_submission', $params);
$row = array($link, $date, $submissions);
$table->data[] = $row;
$string['batchoperationlock'] = 'lock submissions';
$string['batchoperationunlock'] = 'unlock submissions';
$string['batchoperationreverttodraft'] = 'revert submissions to draft';
+$string['changegradewarning'] = 'This assignment has graded submissions and changing the grade will not automatically re-calculate existing submission grades. You must re-grade all existing submissions, if you wish to change the grade.';
$string['comment'] = 'Comment';
$string['conversionexception'] = 'Could not convert assignment. Exception was: {$a}.';
$string['configshowrecentsubmissions'] = 'Everyone can see notifications of submissions in recent activity reports.';
// Do assignment_base::isopen() here without loading the whole thing for speed
foreach ($assignments as $key => $assignment) {
$time = time();
- $isopen = $assignment->allowsubmissionsfromdate <= $time;
+ $isopen = false;
if ($assignment->duedate) {
+ $isopen = $assignment->allowsubmissionsfromdate <= $time;
if ($assignment->preventlatesubmissions) {
$isopen = ($isopen && $time <= $assignment->duedate);
}
}
if (has_all_capabilities(array('gradereport/grader:view', 'moodle/grade:viewall'), $this->get_course_context())) {
- $grade = $this->output->action_link(new moodle_url('/grade/report/grader/index.php',
+ $gradestring = $this->output->action_link(new moodle_url('/grade/report/grader/index.php',
array('id'=>$this->get_course()->id)),
$gradinginfo->items[0]->grades[$userid]->str_grade);
} else {
- $grade = $gradinginfo->items[0]->grades[$userid]->str_grade;
+ $gradestring = $gradinginfo->items[0]->grades[$userid]->str_grade;
}
- $mform->addElement('static', 'finalgrade', get_string('currentgrade', 'assign').':' ,$grade);
+ $mform->addElement('static', 'finalgrade', get_string('currentgrade', 'assign').':', $gradestring);
$mform->addElement('static', 'progress', '', get_string('gradingstudentprogress', 'assign', array('index'=>$rownum+1, 'count'=>count($useridlist))));
* @return void
*/
function definition() {
- global $CFG, $DB;
+ global $CFG, $DB, $PAGE;
$mform = $this->_form;
$mform->addElement('header', 'general', get_string('general', 'form'));
$this->standard_coursemodule_elements();
$this->add_action_buttons();
+
+ // Add warning popup/noscript tag, if grades are changed by user.
+ if ($mform->elementExists('grade') && !empty($this->_instance) && $DB->record_exists_select('assign_grades', 'assignment = ? AND grade <> -1', array($this->_instance))) {
+ $module = array(
+ 'name' => 'mod_assign',
+ 'fullpath' => '/mod/assign/module.js',
+ 'requires' => array('node', 'event'),
+ 'strings' => array(array('changegradewarning', 'mod_assign'))
+ );
+ $PAGE->requires->js_init_call('M.mod_assign.init_grade_change', null, false, $module);
+
+ // Add noscript tag in case
+ $noscriptwarning = $mform->createElement('static', 'warning', null, html_writer::tag('noscript', get_string('changegradewarning', 'mod_assign')));
+ $mform->insertElementBefore($noscriptwarning, 'grade');
+ }
}
/**
});
}
});
+};
+
+M.mod_assign.init_grade_change = function(Y) {
+ var gradenode = Y.one('#id_grade');
+ if (gradenode) {
+ var originalvalue = gradenode.get('value');
+ gradenode.on('change', function() {
+ if (gradenode.get('value') != originalvalue) {
+ alert(M.str.mod_assign.changegradewarning);
+ }
+ });
+ }
};
\ No newline at end of file