</FEEDBACK>
</PHP_SETTING>
</PHP_SETTINGS>
-</MOODLE>
+ </MOODLE>
+ <MOODLE version="2.4" requires="2.2">
+ <UNICODE level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unicoderequired" />
+ </FEEDBACK>
+ </UNICODE>
+ <DATABASE level="required">
+ <VENDOR name="mysql" version="5.1.33" />
+ <VENDOR name="postgres" version="8.3" />
+ <VENDOR name="mssql" version="9.0" />
+ <VENDOR name="odbc_mssql" version="9.0" />
+ <VENDOR name="mssql_n" version="9.0" />
+ <VENDOR name="oracle" version="10.2" />
+ <VENDOR name="sqlite" version="2.0" />
+ </DATABASE>
+ <PHP version="5.3.2" level="required">
+ </PHP>
+ <PCREUNICODE level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="pcreunicodewarning" />
+ </FEEDBACK>
+ </PCREUNICODE>
+ <PHP_EXTENSIONS>
+ <PHP_EXTENSION name="iconv" level="required">
+ <FEEDBACK>
+ <ON_CHECK message="iconvrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="mbstring" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="mbstringrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="curl" level="required">
+ <FEEDBACK>
+ <ON_CHECK message="curlrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="openssl" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="opensslrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="tokenizer" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="tokenizerrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="xmlrpc" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="xmlrpcrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="soap" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="soaprecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="ctype" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="ctyperequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="zip" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="ziprequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="gd" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="gdrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="simplexml" level="required">
+ <FEEDBACK>
+ <ON_CHECK message="simplexmlrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="spl" level="required">
+ <FEEDBACK>
+ <ON_CHECK message="splrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="pcre" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="dom" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="xml" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="intl" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="intlrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="json" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="hash" level="required"/>
+ </PHP_EXTENSIONS>
+ <PHP_SETTINGS>
+ <PHP_SETTING name="memory_limit" value="40M" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="settingmemorylimit" />
+ </FEEDBACK>
+ </PHP_SETTING>
+ <PHP_SETTING name="safe_mode" value="0" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="settingsafemode" />
+ </FEEDBACK>
+ </PHP_SETTING>
+ <PHP_SETTING name="file_uploads" value="1" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="settingfileuploads" />
+ </FEEDBACK>
+ </PHP_SETTING>
+ </PHP_SETTINGS>
+ </MOODLE>
</COMPATIBILITY_MATRIX>
if (is_null($this->backupid)) {
$this->backupid = $processor->get_var(backup::VAR_BACKUPID);
}
- parent::process($processor);
+ return parent::process($processor);
}
public function fill_values($values) {
// Fill values
parent::fill_values($values);
// Do our own tasks (copy file from moodle to backup)
- backup_file_manager::copy_file_moodle2backup($this->backupid, $values);
+ try {
+ backup_file_manager::copy_file_moodle2backup($this->backupid, $values);
+ } catch (file_exception $e) {
+ $this->add_result(array('missing_files_in_pool' => true));
+ $this->add_log('missing file in pool: ' . $e->debuginfo, backup::LOG_WARNING);
+ }
}
}
AND ' . $DB->sql_compare_text('answer', 255) . ' = ' . $DB->sql_compare_text('?', 255);
$params = array($newquestionid, $data->answertext);
$newitemid = $DB->get_field_sql($sql, $params);
+
+ // Not able to find the answer, let's try cleaning the answertext
+ // of all the question answers in DB as slower fallback. MDL-30018.
+ if (!$newitemid) {
+ $params = array('question' => $newquestionid);
+ $answers = $DB->get_records('question_answers', $params, '', 'id, answer');
+ foreach ($answers as $answer) {
+ // Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
+ $clean = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is','', $answer->answer); // Clean CTRL chars.
+ $clean = preg_replace("/\r\n|\r/", "\n", $clean); // Normalize line ending.
+ if ($clean === $data->answertext) {
+ $newitemid = $data->id;
+ }
+ }
+ }
+
// If we haven't found the newitemid, something has gone really wrong, question in DB
// is missing answers, exception
if (!$newitemid) {
--- /dev/null
+This files describes API changes in /backup/*,
+information provided here is intended especially for developers.
+
+=== 2.4 ===
+
+* Since 2.3.1+ the backup file name schema has changed. The ID of the course will always be part of
+ the filename regardless of the setting 'backup_shortname'. See MDL-33812.
+
+=== 2.3 ===
+
+* Since 2.3.1+ the backup file name schema has changed. The ID of the course will always be part of
+ the filename regardless of the setting 'backup_shortname'. See MDL-33812.
+
+=== 2.2 ===
+
+* Since 2.2.4+ the backup file name schema has changed. The ID of the course will always be part of
+ the filename regardless of the setting 'backup_shortname'. See MDL-33812.
\ No newline at end of file
* @param int $courseid/$sectionid/$cmid
* @param bool $users Should be true is users were included in the backup
* @param bool $anonymised Should be true is user information was anonymized.
- * @param bool $useidasname true to use id, false to use strings (default)
+ * @param bool $useidonly only use the ID in the file name
* @return string The filename to use
*/
- public static function get_default_backup_filename($format, $type, $id, $users, $anonymised, $useidasname = false) {
+ public static function get_default_backup_filename($format, $type, $id, $users, $anonymised, $useidonly = false) {
global $DB;
// Calculate backup word
$backupword = str_replace(' ', '_', textlib::strtolower(get_string('backupfilename')));
$backupword = trim(clean_filename($backupword), '_');
+ // Not $useidonly, lets fetch the name
$shortname = '';
- // Not $useidasname, lets calculate it, else $id will be used
- if (!$useidasname) {
+ if (!$useidonly) {
// Calculate proper name element (based on type)
switch ($type) {
case backup::TYPE_1COURSE:
$shortname = textlib::strtolower(trim(clean_filename($shortname), '_'));
}
- $name = empty($shortname) ? $id : $shortname;
+ // The name will always contain the ID, but we append the course short name if requested.
+ $name = $id;
+ if (!$useidonly && $shortname != '') {
+ $name .= '-' . $shortname;
+ }
// Calculate date
$backupdateformat = str_replace(' ', '_', get_string('backupnameformat', 'langconfig'));
* @param int|null $olditemid
* @param int|null $forcenewcontextid explicit value for the new contextid (skip mapping)
* @param bool $skipparentitemidctxmatch
+ * @return array of result object
*/
public static function send_files_to_pool($basepath, $restoreid, $component, $filearea, $oldcontextid, $dfltuserid, $itemname = null, $olditemid = null, $forcenewcontextid = null, $skipparentitemidctxmatch = false) {
global $DB;
+ $results = array();
+
if ($forcenewcontextid) {
// Some components can have "forced" new contexts (example: questions can end belonging to non-standard context mappings,
// with questions originally at system/coursecat context in source being restored to course context in target). So we need
// this is a regular file, it must be present in the backup pool
$backuppath = $basepath . backup_file_manager::get_backup_content_file_location($file->contenthash);
+ // The file is not found in the backup.
if (!file_exists($backuppath)) {
- throw new restore_dbops_exception('file_not_found_in_pool', $file);
+ $result = new stdClass();
+ $result->code = 'file_missing_in_backup';
+ $result->message = sprintf('missing file %s%s in backup', $file->filepath, $file->filename);
+ $result->level = backup::LOG_WARNING;
+ $results[] = $result;
+ continue;
}
// create the file in the filepool if it does not exist yet
}
}
$rs->close();
+ return $results;
}
/**
const BACKUP_STATUS_UNFINISHED = 2;
/** Course automated backup was skipped */
const BACKUP_STATUS_SKIPPED = 3;
+ /** Course automated backup had warnings */
+ const BACKUP_STATUS_WARNING = 4;
/** Run if required by the schedule set in config. Default. **/
const RUN_ON_SCHEDULE = 0;
$params = array('courseid' => $course->id, 'time' => $now-31*24*60*60, 'action' => '%view%');
$logexists = $DB->record_exists_select('log', $sqlwhere, $params);
if (!$logexists) {
- $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
+ $backupcourse->laststatus = self::BACKUP_STATUS_SKIPPED;
$backupcourse->nextstarttime = $nextstarttime;
$DB->update_record('backup_courses', $backupcourse);
mtrace('Skipping unchanged course '.$course->fullname);
$starttime = time();
$backupcourse->laststarttime = time();
- $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED;
+ $backupcourse->laststatus = self::BACKUP_STATUS_UNFINISHED;
$DB->update_record('backup_courses', $backupcourse);
$backupcourse->laststatus = backup_cron_automated_helper::launch_automated_backup($course, $backupcourse->laststarttime, $admin->id);
$DB->update_record('backup_courses', $backupcourse);
- if ($backupcourse->laststatus) {
+ if ($backupcourse->laststatus === self::BACKUP_STATUS_OK) {
// Clean up any excess course backups now that we have
// taken a successful backup.
$removedcount = backup_cron_automated_helper::remove_excess_backups($course);
$message = "";
$count = backup_cron_automated_helper::get_backup_status_array();
- $haserrors = ($count[backup_cron_automated_helper::BACKUP_STATUS_ERROR] != 0 || $count[backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED] != 0);
+ $haserrors = ($count[self::BACKUP_STATUS_ERROR] != 0 || $count[self::BACKUP_STATUS_UNFINISHED] != 0);
//Build the message text
//Summary
$message .= get_string('summary')."\n";
$message .= "==================================================\n";
$message .= " ".get_string('courses').": ".array_sum($count)."\n";
- $message .= " ".get_string('ok').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_OK]."\n";
- $message .= " ".get_string('skipped').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_SKIPPED]."\n";
- $message .= " ".get_string('error').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_ERROR]."\n";
- $message .= " ".get_string('unfinished').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED]."\n\n";
+ $message .= " ".get_string('ok').": ".$count[self::BACKUP_STATUS_OK]."\n";
+ $message .= " ".get_string('skipped').": ".$count[self::BACKUP_STATUS_SKIPPED]."\n";
+ $message .= " ".get_string('error').": ".$count[self::BACKUP_STATUS_ERROR]."\n";
+ $message .= " ".get_string('unfinished').": ".$count[self::BACKUP_STATUS_UNFINISHED]."\n";
+ $message .= " ".get_string('warning').": ".$count[self::BACKUP_STATUS_WARNING]."\n\n";
//Reference
if ($haserrors) {
self::BACKUP_STATUS_OK => 0,
self::BACKUP_STATUS_UNFINISHED => 0,
self::BACKUP_STATUS_SKIPPED => 0,
+ self::BACKUP_STATUS_WARNING => 0
);
$statuses = $DB->get_records_sql('SELECT DISTINCT bc.laststatus, COUNT(bc.courseid) AS statuscount FROM {backup_courses} bc GROUP BY bc.laststatus');
*/
public static function launch_automated_backup($course, $starttime, $userid) {
- $outcome = true;
+ $outcome = self::BACKUP_STATUS_OK;
$config = get_config('backup');
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_AUTOMATED, $userid);
$bc->execute_plan();
$results = $bc->get_results();
+ $outcome = self::outcome_from_results($results);
$file = $results['backup_destination']; // may be empty if file already moved to target location
$dir = $config->backup_auto_destination;
$storage = (int)$config->backup_auto_storage;
}
if ($file && !empty($dir) && $storage !== 0) {
$filename = backup_plan_dbops::get_default_backup_filename($format, $type, $course->id, $users, $anonymised, !$config->backup_shortname);
- $outcome = $file->copy_content_to($dir.'/'.$filename);
- if ($outcome && $storage === 1) {
+ if (!$file->copy_content_to($dir.'/'.$filename)) {
+ $outcome = self::BACKUP_STATUS_ERROR;
+ }
+ if ($outcome != self::BACKUP_STATUS_ERROR && $storage === 1) {
$file->delete();
}
}
$bc->log('backup_auto_failed_on_course', backup::LOG_ERROR, $course->shortname); // Log error header.
$bc->log('Exception: ' . $e->errorcode, backup::LOG_ERROR, $e->a, 1); // Log original exception problem.
$bc->log('Debug: ' . $e->debuginfo, backup::LOG_DEBUG, null, 1); // Log original debug information.
- $outcome = false;
+ $outcome = self::BACKUP_STATUS_ERROR;
}
$bc->destroy();
return $outcome;
}
+ /**
+ * Returns the backup outcome by analysing its results.
+ *
+ * @param array $results returned by a backup
+ * @return int {@link self::BACKUP_STATUS_OK} and other constants
+ */
+ public static function outcome_from_results($results) {
+ $outcome = self::BACKUP_STATUS_OK;
+ foreach ($results as $code => $value) {
+ // Each possible error and warning code has to be specified in this switch
+ // which basically analyses the results to return the correct backup status.
+ switch ($code) {
+ case 'missing_files_in_pool':
+ $outcome = self::BACKUP_STATUS_WARNING;
+ break;
+ }
+ // If we found the highest error level, we exit the loop.
+ if ($outcome == self::BACKUP_STATUS_ERROR) {
+ break;
+ }
+ }
+ return $outcome;
+ }
+
/**
* Removes deleted courses fromn the backup_courses table so that we don't
* waste time backing them up.
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
-
-
- // 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 . '-';
+ $filename = $backupword . '-' . backup::FORMAT_MOODLE . '-' . backup::TYPE_1COURSE . '-' .$course->id . '-';
$regex = '#^'.preg_quote($filename, '#').'.*\.mbz$#';
// Store all the matching files into fullpath => timemodified array
// Process structure definition
$structure->process($pr);
+ // Get the results from the nested elements
+ $results = $structure->get_results();
+
+ // Get the log messages to append to the log
+ $logs = $structure->get_logs();
+ foreach ($logs as $log) {
+ $this->log($log->message, $log->level, $log->a, $log->depth, $log->display);
+ }
+
// Close everything
$xw->stop();
// Destroy the structure. It helps PHP 5.2 memory a lot!
$structure->destroy();
+
+ return $results;
}
/**
*/
public function add_related_files($component, $filearea, $mappingitemname, $filesctxid = null, $olditemid = null) {
$filesctxid = is_null($filesctxid) ? $this->task->get_old_contextid() : $filesctxid;
- restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component,
- $filearea, $filesctxid, $this->task->get_userid(), $mappingitemname, $olditemid);
+ $results = restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component,
+ $filearea, $filesctxid, $this->task->get_userid(), $mappingitemname, $olditemid);
+ $resultstoadd = array();
+ foreach ($results as $result) {
+ $this->log($result->message, $result->level);
+ $resultstoadd[$result->code] = true;
+ }
+ $this->task->add_result($resultstoadd);
}
/**
protected $aliases; // Define DB->final element aliases
protected $fileannotations; // array of file areas to be searched by file annotations
protected $counter; // Number of instances of this element that have been processed
+ protected $results; // Logs the results we encounter during the process.
+ protected $logs; // Some log messages that could be retrieved later.
/**
* Constructor - instantiates one backup_nested_element, specifying its basic info.
$this->aliases = array();
$this->fileannotations = array();
$this->counter = 0;
+ $this->results = array();
+ $this->logs = array();
}
+ /**
+ * Process the nested element
+ *
+ * @param object $processor the processor
+ * @return void
+ */
public function process($processor) {
if (!$processor instanceof base_processor) { // No correct processor, throw exception
throw new base_element_struct_exception('incorrect_processor');
$iterator->close();
}
+ /**
+ * Saves a log message to an array
+ *
+ * @see backup_helper::log()
+ * @param string $message to add to the logs
+ * @param int $level level of importance {@link backup::LOG_DEBUG} and other constants
+ * @param mixed $a to be included in $message
+ * @param int $depth of the message
+ * @param display $bool supporting translation via get_string() if true
+ * @return void
+ */
+ protected function add_log($message, $level, $a = null, $depth = null, $display = false) {
+ // Adding the result to the oldest parent.
+ if ($this->get_parent()) {
+ $parent = $this->get_grandparent();
+ $parent->add_log($message, $level, $a, $depth, $display);
+ } else {
+ $log = new stdClass();
+ $log->message = $message;
+ $log->level = $level;
+ $log->a = $a;
+ $log->depth = $depth;
+ $log->display = $display;
+ $this->logs[] = $log;
+ }
+ }
+
+ /**
+ * Saves the results to an array
+ *
+ * @param array $result associative array
+ * @return void
+ */
+ protected function add_result($result) {
+ if (is_array($result)) {
+ // Adding the result to the oldest parent.
+ if ($this->get_parent()) {
+ $parent = $this->get_grandparent();
+ $parent->add_result($result);
+ } else {
+ $this->results = array_merge($this->results, $result);
+ }
+ }
+ }
+
+ /**
+ * Returns the logs
+ *
+ * @return array of log objects
+ */
+ public function get_logs() {
+ return $this->logs;
+ }
+
+ /**
+ * Returns the results
+ *
+ * @return associative array of results
+ */
+ public function get_results() {
+ return $this->results;
+ }
+
public function set_source_array($arr) {
// TODO: Only elements having final elements can set source
$this->var_array = $arr;
if (!empty($this->results['include_file_references_to_external_content'])) {
$output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem');
}
+ if (!empty($this->results['missing_files_in_pool'])) {
+ $output .= $renderer->notification(get_string('missingfilesinpool', 'backup'), 'notifyproblem');
+ }
$output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
$output .= $renderer->continue_button($restorerul);
$output .= $renderer->box_end();
$html .= $renderer->box_end();
}
$html .= $renderer->box_start();
+ if (array_key_exists('file_missing_in_backup', $this->results)) {
+ $html .= $renderer->notification(get_string('restorefileweremissing', 'backup'), 'notifyproblem');
+ }
$html .= $renderer->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess');
$html .= $renderer->continue_button(new moodle_url('/course/view.php', array(
'id' => $this->get_ui()->get_controller()->get_courseid())), 'get');
bodyContent:Y.one('#commentoverlay-'+commentid).get('innerHTML'),
visible: false, //by default it is not displayed
lightbox : false,
- zIndex:100,
- height: '350px'
+ zIndex:100
});
this.overlays[commentid].get('contentBox').one('.commenttitle').remove();
}, '@VERSION@', {
requires:['base','overlay', 'moodle-enrol-notification']
-});
\ No newline at end of file
+});
*
* @package block
* @subpackage completion
- * @copyright 2009 Catalyst IT Ltd
+ * @copyright 2009-2012 Catalyst IT Ltd
* @author Aaron Barnes <aaronb@catalyst.net.nz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
-
-require_once($CFG->libdir.'/completionlib.php');
+require_once("{$CFG->libdir}/completionlib.php");
/**
* Course completion status
class block_completionstatus extends block_base {
public function init() {
- $this->title = get_string('pluginname', 'block_completionstatus');
+ $this->title = get_string('pluginname', 'block_completionstatus');
}
public function get_content() {
- global $USER, $CFG, $DB, $COURSE;
+ global $USER;
// If content is cached
if ($this->content !== NULL) {
return $this->content;
}
+ $course = $this->page->course;
+
// Create empty content
- $this->content = new stdClass;
+ $this->content = new stdClass();
// Can edit settings?
- $can_edit = has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $this->page->course->id));
+ $can_edit = has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $course->id));
// Get course completion data
- $info = new completion_info($this->page->course);
+ $info = new completion_info($course);
// Don't display if completion isn't enabled!
if (!completion_info::is_enabled_for_site()) {
// Check this user is enroled
if (!$info->is_tracked_user($USER->id)) {
// If not enrolled, but are can view the report:
- if (has_capability('report/completion:view', get_context_instance(CONTEXT_COURSE, $COURSE->id))) {
- $this->content->text = '<a href="'.$CFG->wwwroot.'/report/completion/index.php?course='.$COURSE->id.
- '">'.get_string('viewcoursereport', 'completion').'</a>';
+ if (has_capability('report/completion:view', get_context_instance(CONTEXT_COURSE, $course->id))) {
+ $report = new moodle_url('/report/completion/index.php', array('course' => $course->id));
+ $this->content->text = '<a href="'.$report->out().'">'.get_string('viewcoursereport', 'completion').'</a>';
return $this->content;
}
// Load course completion
$params = array(
'userid' => $USER->id,
- 'course' => $COURSE->id
+ 'course' => $course->id
);
$ccompletion = new completion_completion($params);
$this->content->text .= $shtml.'</tbody></table>';
// Display link to detailed view
- $this->content->footer = '<br><a href="'.$CFG->wwwroot.'/blocks/completionstatus/details.php?course='.$COURSE->id.'">'.get_string('moredetails', 'completion').'</a>';
+ $details = new moodle_url('/blocks/completionstatus/details.php', array('course' => $course->id));
+ $this->content->footer = '<br><a href="'.$details->out().'">'.get_string('moredetails', 'completion').'</a>';
return $this->content;
}
*
* @package block
* @subpackage completion
- * @copyright 2009 Catalyst IT Ltd
+ * @copyright 2009-2012 Catalyst IT Ltd
* @author Aaron Barnes <aaronb@catalyst.net.nz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-require_once('../../config.php');
-require_once($CFG->libdir.'/completionlib.php');
-
-
-// TODO: Make this page Moodle 2.0 compliant
+require_once(dirname(__FILE__).'/../../config.php');
+require_once("{$CFG->libdir}/completionlib.php");
///
/// Load data
///
$id = required_param('course', PARAM_INT);
-// User id
$userid = optional_param('user', 0, PARAM_INT);
// Load course
-$course = $DB->get_record('course', array('id' => $id));
+$course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
// Load user
if ($userid) {
// Load completion data
$info = new completion_info($course);
-$returnurl = "{$CFG->wwwroot}/course/view.php?id={$id}";
+$returnurl = new moodle_url('/course/view.php', array('id' => $id));
// Don't display if completion isn't enabled!
if (!$info->is_enabled()) {
print_error('completionnotenabled', 'completion', $returnurl);
}
-// Load criteria to display
-$completions = $info->get_completions($user->id);
-
-// Check if this course has any criteria
-if (empty($completions)) {
- print_error('nocriteriaset', 'completion', $returnurl);
-}
-
// Check this user is enroled
if (!$info->is_tracked_user($user->id)) {
if ($USER->id == $user->id) {
///
/// Display page
///
+$PAGE->set_context(context_course::instance($course->id));
// Print header
$page = get_string('completionprogressdetails', 'block_completionstatus');
$PAGE->navbar->add($page);
$PAGE->set_pagelayout('standard');
-$PAGE->set_url('/blocks/completionstatus/details.php', array('course' => $course->id));
+$PAGE->set_url('/blocks/completionstatus/details.php', array('course' => $course->id, 'user' => $user->id));
$PAGE->set_title(get_string('course') . ': ' . $course->fullname);
$PAGE->set_heading($title);
echo $OUTPUT->header();
// Has this user completed any criteria?
$criteriacomplete = $info->count_course_user_data($user->id);
+// Load course completion
+$params = array(
+ 'userid' => $user->id,
+ 'course' => $course->id,
+);
+$ccompletion = new completion_completion($params);
+
if ($coursecomplete) {
echo get_string('complete');
-} else if (!$criteriacomplete) {
+} else if (!$criteriacomplete && !$ccompletion->timestarted) {
echo '<i>'.get_string('notyetstarted', 'completion').'</i>';
} else {
echo '<i>'.get_string('inprogress','completion').'</i>';
}
echo '</td></tr>';
-echo '<tr><td colspan="2"><b>'.get_string('required').':</b> ';
-// Get overall aggregation method
-$overall = $info->get_aggregation_method();
+// Load criteria to display
+$completions = $info->get_completions($user->id);
-if ($overall == COMPLETION_AGGREGATION_ALL) {
- echo get_string('criteriarequiredall', 'completion');
+// Check if this course has any criteria
+if (empty($completions)) {
+ echo '<tr><td colspan="2"><br />';
+ echo $OUTPUT->box(get_string('err_nocriteria', 'completion'), 'noticebox');
+ echo '</td></tr></tbody></table>';
} else {
- echo get_string('criteriarequiredany', 'completion');
-}
+ echo '<tr><td colspan="2"><b>'.get_string('required').':</b> ';
-echo '</td></tr></tbody></table>';
-
-// Generate markup for criteria statuses
-echo '<table class="generalbox boxaligncenter" cellpadding="3"><tbody>';
-echo '<tr class="ccheader">';
-echo '<th class="c0 header" scope="col">'.get_string('criteriagroup', 'block_completionstatus').'</th>';
-echo '<th class="c1 header" scope="col">'.get_string('criteria', 'completion').'</th>';
-echo '<th class="c2 header" scope="col">'.get_string('requirement', 'block_completionstatus').'</th>';
-echo '<th class="c3 header" scope="col">'.get_string('status').'</th>';
-echo '<th class="c4 header" scope="col">'.get_string('complete').'</th>';
-echo '<th class="c5 header" scope="col">'.get_string('completiondate', 'report_completion').'</th>';
-echo '</tr>';
-
-// Save row data
-$rows = array();
-
-global $COMPLETION_CRITERIA_TYPES;
-
-// Loop through course criteria
-foreach ($completions as $completion) {
- $criteria = $completion->get_criteria();
- $complete = $completion->is_complete();
-
- $row = array();
- $row['type'] = $criteria->criteriatype;
- $row['title'] = $criteria->get_title();
- $row['status'] = $completion->get_status();
- $row['timecompleted'] = $completion->timecompleted;
- $row['details'] = $criteria->get_details($completion);
- $rows[] = $row;
-}
+ // Get overall aggregation method
+ $overall = $info->get_aggregation_method();
-// Print table
-$last_type = '';
-$agg_type = false;
+ if ($overall == COMPLETION_AGGREGATION_ALL) {
+ echo get_string('criteriarequiredall', 'completion');
+ } else {
+ echo get_string('criteriarequiredany', 'completion');
+ }
+
+ echo '</td></tr></tbody></table>';
+
+ // Generate markup for criteria statuses
+ echo '<table class="generalbox logtable boxaligncenter" id="criteriastatus" width="100%"><tbody>';
+ echo '<tr class="ccheader">';
+ echo '<th class="c0 header" scope="col">'.get_string('criteriagroup', 'block_completionstatus').'</th>';
+ echo '<th class="c1 header" scope="col">'.get_string('criteria', 'completion').'</th>';
+ echo '<th class="c2 header" scope="col">'.get_string('requirement', 'block_completionstatus').'</th>';
+ echo '<th class="c3 header" scope="col">'.get_string('status').'</th>';
+ echo '<th class="c4 header" scope="col">'.get_string('complete').'</th>';
+ echo '<th class="c5 header" scope="col">'.get_string('completiondate', 'report_completion').'</th>';
+ echo '</tr>';
-foreach ($rows as $row) {
+ // Save row data
+ $rows = array();
+
+ // Loop through course criteria
+ foreach ($completions as $completion) {
+ $criteria = $completion->get_criteria();
+
+ $row = array();
+ $row['type'] = $criteria->criteriatype;
+ $row['title'] = $criteria->get_title();
+ $row['status'] = $completion->get_status();
+ $row['complete'] = $completion->is_complete();
+ $row['timecompleted'] = $completion->timecompleted;
+ $row['details'] = $criteria->get_details($completion);
+ $rows[] = $row;
+ }
- // Criteria group
- echo '<td class="c0">';
- if ($last_type !== $row['details']['type']) {
- $last_type = $row['details']['type'];
- echo $last_type;
+ // Print table
+ $last_type = '';
+ $agg_type = false;
+ $oddeven = 0;
- // Reset agg type
- $agg_type = true;
- } else {
- // Display aggregation type
- if ($agg_type) {
- $agg = $info->get_aggregation_method($row['type']);
+ foreach ($rows as $row) {
- echo '(<i>';
+ echo '<tr class="r' . $oddeven . '">';
- if ($agg == COMPLETION_AGGREGATION_ALL) {
- echo strtolower(get_string('all', 'completion'));
- } else {
- echo strtolower(get_string('any', 'completion'));
- }
+ // Criteria group
+ echo '<td class="cell c0">';
+ if ($last_type !== $row['details']['type']) {
+ $last_type = $row['details']['type'];
+ echo $last_type;
+
+ // Reset agg type
+ $agg_type = true;
+ } else {
+ // Display aggregation type
+ if ($agg_type) {
+ $agg = $info->get_aggregation_method($row['type']);
- echo '</i> '.strtolower(get_string('required')).')';
- $agg_type = false;
+ echo '(<i>';
+
+ if ($agg == COMPLETION_AGGREGATION_ALL) {
+ echo strtolower(get_string('aggregateall', 'completion'));
+ } else {
+ echo strtolower(get_string('aggregateany', 'completion'));
+ }
+
+ echo '</i> '.strtolower(get_string('required')).')';
+ $agg_type = false;
+ }
}
+ echo '</td>';
+
+ // Criteria title
+ echo '<td class="cell c1">';
+ echo $row['details']['criteria'];
+ echo '</td>';
+
+ // Requirement
+ echo '<td class="cell c2">';
+ echo $row['details']['requirement'];
+ echo '</td>';
+
+ // Status
+ echo '<td class="cell c3">';
+ echo $row['details']['status'];
+ echo '</td>';
+
+ // Is complete
+ echo '<td class="cell c4">';
+ echo $row['complete'] ? get_string('yes') : get_string('no');
+ echo '</td>';
+
+ // Completion data
+ echo '<td class="cell c5">';
+ if ($row['timecompleted']) {
+ echo userdate($row['timecompleted'], get_string('strftimedate', 'langconfig'));
+ } else {
+ echo '-';
+ }
+ echo '</td>';
+ echo '</tr>';
+ // for row striping
+ $oddeven = $oddeven ? 0 : 1;
}
- echo '</td>';
-
- // Criteria title
- echo '<td class="c1">';
- echo $row['details']['criteria'];
- echo '</td>';
-
- // Requirement
- echo '<td class="c2">';
- echo $row['details']['requirement'];
- echo '</td>';
-
- // Status
- echo '<td class="c3">';
- echo $row['details']['status'];
- echo '</td>';
-
- // Is complete
- echo '<td class="c4">';
- echo ($row['status'] === get_string('yes')) ? get_string('yes') : get_string('no');
- echo '</td>';
-
- // Completion data
- echo '<td class="c5">';
- if ($row['timecompleted']) {
- echo userdate($row['timecompleted'], '%e %B %G');
- } else {
- echo '-';
- }
- echo '</td>';
- echo '</tr>';
+
+ echo '</tbody></table>';
}
-echo '</tbody></table>';
+echo '<div class="buttons">';
+$courseurl = new moodle_url("/course/view.php", array('id' => $course->id));
+echo $OUTPUT->single_button($courseurl, get_string('returntocourse', 'block_completionstatus'), 'get');
+echo '</div>';
echo $OUTPUT->footer();
$string['firstofsecond'] = '{$a->first} of {$a->second}';
$string['pluginname'] = 'Course completion status';
$string['requirement'] = 'Requirement';
+$string['returntocourse'] = 'Return to course';
return;
}
+ // Disable the skip anchor when docking
+ var skipanchor = node.previous();
+ if (skipanchor.hasClass('skip-block')) {
+ skipanchor.hide();
+ }
+
var blockclass = (function(classes){
var r = /(^|\s)(block_[a-zA-Z0-9_]+)(\s|$)/;
var m = r.exec(classes);
return_to_block : function(dockitem) {
var placeholder = this.Y.one('#content_placeholder_'+this.id);
+ // Enable the skip anchor when going back to block mode
+ var skipanchor = placeholder.previous();
+ if (skipanchor.hasClass('skip-block')) {
+ skipanchor.show();
+ }
+
if (this.cachedcontentnode.one('.header')) {
this.cachedcontentnode.one('.header').insert(dockitem.contents, 'after');
} else {
if ($delete && confirm_sesskey()) {
$externalbloguserid = $DB->get_field('blog_external', 'userid', array('id' => $delete));
if ($externalbloguserid == $USER->id) {
+ // Delete the external blog
$DB->delete_records('blog_external', array('id' => $delete));
+
+ // Delete the external blog's posts
+ $deletewhere = 'module = :module
+ AND userid = :userid
+ AND ' . $DB->sql_isnotempty('post', 'uniquehash', false, false) . '
+ AND ' . $DB->sql_compare_text('content') . ' = ' . $DB->sql_compare_text(':delete');
+ $DB->delete_records_select('post', $deletewhere, array('module' => 'blog_external', 'userid' => $USER->id, 'delete' => $delete));
+
$message = get_string('externalblogdeleted', 'blog');
}
}
* @return void
*/
public function delete() {
- global $DB, $USER;
-
- $returnurl = '';
+ global $DB;
$this->delete_attachments();
+ $this->remove_associations();
$DB->delete_records('post', array('id' => $this->id));
tag_set('post', $this->id, array());
require_once("../config.php");
require_once($CFG->dirroot.'/course/lib.php');
+require_once($CFG->libdir.'/textlib.class.php');
$id = required_param('id', PARAM_INT); // Category id
$page = optional_param('page', 0, PARAM_INT); // which page to show
// Process any category actions.
if ($canmanage && $resort && $sesskeyprovided) {
// Resort the category if requested
- if ($courses = get_courses($category->id, "fullname ASC", 'c.id,c.fullname,c.sortorder')) {
+ if ($courses = get_courses($category->id, '', 'c.id,c.fullname,c.sortorder')) {
+ collatorlib::asort_objects_by_property($courses, 'fullname', collatorlib::SORT_NATURAL);
$i = 1;
foreach ($courses as $course) {
$DB->set_field('course', 'sortorder', $category->sortorder+$i, array('id'=>$course->id));
M.course.format.swap_sections = function(Y, node1, node2) {
var CSS = {
COURSECONTENT : 'course-content',
- SECTIONADDMENUS : 'section_add_menus',
+ SECTIONADDMENUS : 'section_add_menus'
};
var sectionlist = Y.Node.all('.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y));
global $DB;
$this->resetAfterTest(true);
+
+ $generatedcats = array();
$category1data['idnumber'] = 'idnumbercat1';
$category1data['name'] = 'Category 1 for PHPunit test';
$category1data['description'] = 'Category 1 description';
$category1data['descriptionformat'] = FORMAT_MOODLE;
$category1 = self::getDataGenerator()->create_category($category1data);
+ $generatedcats[$category1->id] = $category1;
$category2 = self::getDataGenerator()->create_category(
array('parent' => $category1->id));
+ $generatedcats[$category2->id] = $category2;
$category6 = self::getDataGenerator()->create_category(
array('parent' => $category1->id, 'visible' => 0));
+ $generatedcats[$category6->id] = $category6;
$category3 = self::getDataGenerator()->create_category();
+ $generatedcats[$category3->id] = $category3;
$category4 = self::getDataGenerator()->create_category(
array('parent' => $category3->id));
+ $generatedcats[$category4->id] = $category4;
$category5 = self::getDataGenerator()->create_category(
array('parent' => $category4->id));
+ $generatedcats[$category5->id] = $category5;
// Set the required capabilities by the external function.
$context = context_system::instance();
$this->assertEquals(2, count($categories));
// Check the return values
- $this->assertEquals($categories[0]['id'], $category1->id);
- $this->assertEquals($categories[0]['idnumber'], $category1->idnumber);
- $this->assertEquals($categories[0]['name'], $category1->name);
- $this->assertEquals($categories[0]['description'], $category1->description);
- $this->assertEquals($categories[0]['descriptionformat'], FORMAT_HTML);
+ foreach ($categories as $category) {
+ $generatedcat = $generatedcats[$category['id']];
+ $this->assertEquals($category['idnumber'], $generatedcat->idnumber);
+ $this->assertEquals($category['name'], $generatedcat->name);
+ $this->assertEquals($category['description'], $generatedcat->description);
+ $this->assertEquals($category['descriptionformat'], FORMAT_HTML);
+ }
// Check different params.
$categories = core_course_external::get_categories(array(
$this->resetAfterTest(true);
+ $generatedcourses = array();
$coursedata['idnumber'] = 'idnumbercourse1';
$coursedata['fullname'] = 'Course 1 for PHPunit test';
$coursedata['summary'] = 'Course 1 description';
$coursedata['summaryformat'] = FORMAT_MOODLE;
$course1 = self::getDataGenerator()->create_course($coursedata);
+ $generatedcourses[$course1->id] = $course1;
$course2 = self::getDataGenerator()->create_course();
+ $generatedcourses[$course2->id] = $course2;
$course3 = self::getDataGenerator()->create_course();
+ $generatedcourses[$course3->id] = $course3;
// Set the required capabilities by the external function.
$context = context_system::instance();
// Check we retrieve the good total number of categories.
$this->assertEquals(2, count($courses));
- // Check the return values for course 1
- $dbcourse = $DB->get_record('course', array('id' => $course1->id));
- $this->assertEquals($courses[0]['id'], $dbcourse->id);
- $this->assertEquals($courses[0]['idnumber'], $coursedata['idnumber']);
- $this->assertEquals($courses[0]['fullname'], $coursedata['fullname']);
- $this->assertEquals($courses[0]['summary'], $coursedata['summary']);
- $this->assertEquals($courses[0]['summaryformat'], FORMAT_HTML);
- $this->assertEquals($courses[0]['shortname'], $dbcourse->shortname);
- $this->assertEquals($courses[0]['categoryid'], $dbcourse->category);
- $this->assertEquals($courses[0]['format'], $dbcourse->format);
- $this->assertEquals($courses[0]['showgrades'], $dbcourse->showgrades);
- $this->assertEquals($courses[0]['newsitems'], $dbcourse->newsitems);
- $this->assertEquals($courses[0]['startdate'], $dbcourse->startdate);
- $this->assertEquals($courses[0]['numsections'], $dbcourse->numsections);
- $this->assertEquals($courses[0]['maxbytes'], $dbcourse->maxbytes);
- $this->assertEquals($courses[0]['showreports'], $dbcourse->showreports);
- $this->assertEquals($courses[0]['visible'], $dbcourse->visible);
- $this->assertEquals($courses[0]['hiddensections'], $dbcourse->hiddensections);
- $this->assertEquals($courses[0]['groupmode'], $dbcourse->groupmode);
- $this->assertEquals($courses[0]['groupmodeforce'], $dbcourse->groupmodeforce);
- $this->assertEquals($courses[0]['defaultgroupingid'], $dbcourse->defaultgroupingid);
- $this->assertEquals($courses[0]['completionnotify'], $dbcourse->completionnotify);
- $this->assertEquals($courses[0]['lang'], $dbcourse->lang);
- $this->assertEquals($courses[0]['forcetheme'], $dbcourse->theme);
- $this->assertEquals($courses[0]['completionstartonenrol'], $dbcourse->completionstartonenrol);
- $this->assertEquals($courses[0]['enablecompletion'], $dbcourse->enablecompletion);
- $this->assertEquals($courses[0]['completionstartonenrol'], $dbcourse->completionstartonenrol);
+ foreach ($courses as $course) {
+ $dbcourse = $generatedcourses[$course['id']];
+ $this->assertEquals($course['idnumber'], $dbcourse->idnumber);
+ $this->assertEquals($course['fullname'], $dbcourse->fullname);
+ $this->assertEquals($course['summary'], $dbcourse->summary);
+ $this->assertEquals($course['summaryformat'], FORMAT_HTML);
+ $this->assertEquals($course['shortname'], $dbcourse->shortname);
+ $this->assertEquals($course['categoryid'], $dbcourse->category);
+ $this->assertEquals($course['format'], $dbcourse->format);
+ $this->assertEquals($course['showgrades'], $dbcourse->showgrades);
+ $this->assertEquals($course['newsitems'], $dbcourse->newsitems);
+ $this->assertEquals($course['startdate'], $dbcourse->startdate);
+ $this->assertEquals($course['numsections'], $dbcourse->numsections);
+ $this->assertEquals($course['maxbytes'], $dbcourse->maxbytes);
+ $this->assertEquals($course['showreports'], $dbcourse->showreports);
+ $this->assertEquals($course['visible'], $dbcourse->visible);
+ $this->assertEquals($course['hiddensections'], $dbcourse->hiddensections);
+ $this->assertEquals($course['groupmode'], $dbcourse->groupmode);
+ $this->assertEquals($course['groupmodeforce'], $dbcourse->groupmodeforce);
+ $this->assertEquals($course['defaultgroupingid'], $dbcourse->defaultgroupingid);
+ $this->assertEquals($course['completionnotify'], $dbcourse->completionnotify);
+ $this->assertEquals($course['lang'], $dbcourse->lang);
+ $this->assertEquals($course['forcetheme'], $dbcourse->theme);
+ $this->assertEquals($course['completionstartonenrol'], $dbcourse->completionstartonenrol);
+ $this->assertEquals($course['enablecompletion'], $dbcourse->enablecompletion);
+ $this->assertEquals($course['completionstartonenrol'], $dbcourse->completionstartonenrol);
+ }
// Get all courses in the DB
$courses = core_course_external::get_courses(array());
$sql = "SELECT e.*, r.id as roleexists
FROM {enrol} e
LEFT JOIN {role} r ON (r.id = e.roleid)
- WHERE customint1 = :cohortid AND enrol = 'cohort'
- ORDER BY id ASC";
+ WHERE e.customint1 = :cohortid AND e.enrol = 'cohort'
+ ORDER BY e.id ASC";
if (!$instances = $DB->get_records_sql($sql, array('cohortid'=>$ca->cohortid))) {
return true;
}
count++;
var user = result.response.users[i];
users.append(create('<div class="'+CSS.USER+' clearfix" rel="'+user.id+'"></div>')
- .addClass((i%2)?CSS.ODD:CSS.EVEN)
+ .addClass((count%2)?CSS.ODD:CSS.EVEN)
.append(create('<div class="'+CSS.COUNT+'">'+count+'</div>'))
.append(create('<div class="'+CSS.PICTURE+'"></div>')
.append(create(user.picture)))
require_once("lib.php");
require_once($CFG->libdir.'/eventslib.php');
require_once($CFG->libdir.'/enrollib.php');
+require_once($CFG->libdir . '/filelib.php');
/// Keep out casual intruders
$plugin = enrol_get_plugin('paypal');
/// Open a connection back to PayPal to validate the data
-$header = '';
-$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
-$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
-$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
+$c = new curl();
+$options = array(
+ 'returntransfer' => true,
+ 'httpheader' => array('application/x-www-form-urlencoded'),
+ 'timeout' => 30,
+);
$paypaladdr = empty($CFG->usepaypalsandbox) ? 'www.paypal.com' : 'www.sandbox.paypal.com';
-$fp = fsockopen ($paypaladdr, 80, $errno, $errstr, 30);
+$location = "https://$paypaladdr/cgi-bin/webscr";
+$result = $c->post($location, $req, $options);
-if (!$fp) { /// Could not open a socket to PayPal - FAIL
+if (!$result) { /// Could not connect to PayPal - FAIL
echo "<p>Error: could not access paypal.com</p>";
message_paypal_error_to_admin("Could not access paypal.com to verify payment", $data);
die;
/// Connection is OK, so now we post the data to validate it
-fputs ($fp, $header.$req);
-
/// Now read the response and check if everything is OK.
-while (!feof($fp)) {
- $result = fgets($fp, 1024);
+if (strlen($result) > 0) {
if (strcmp($result, "VERIFIED") == 0) { // VALID PAYMENT!
}
}
-fclose($fp);
exit;
<div class="{!}fp-tb-logout"><img src="'.$this->pix_url('a/logout').'" /><a href="#"></a></div>
<div class="{!}fp-tb-manage"><a href="#"><img src="'.$this->pix_url('a/setting').'" /> '.get_string('manageurl', 'repository').'</a></div>
<div class="{!}fp-tb-help"><a href="#"><img src="'.$this->pix_url('a/help').'" /> '.get_string('help').'</a></div>
+ <div class="{!}fp-tb-message"></div>
</div>
<div class="{!}fp-viewbar">
<a class="{!}fp-vb-icons" href="#"></a>
'<a id="movie player" class="center" href="http://moodle.org/testfile/test.mpg">test mpg</a>',
'<a href="http://moodle.org/testfile/test.ram">test</a>',
'<a href="http://www.youtube.com/watch?v=JghQgA2HMX8" class="href=css">test file</a>',
+ '<a href="http://www.youtube-nocookie.com/watch?v=JghQgA2HMX8" class="href=css">test file</a>',
'<a class="youtube" href="http://www.youtube.com/watch?v=JghQgA2HMX8">test file</a>',
+ '<a href="http://youtu.be/JghQgA2HMX8" class="href=css">test file</a>',
+ '<a href="http://y2u.be/JghQgA2HMX8" class="href=css">test file</a>',
'<a class="_blanktarget" href="http://moodle.org/testfile/test.flv?d=100x100">test flv</a>',
'<a class="hrefcss" href="http://www.youtube.com/watch?v=JghQgA2HMX8">test file</a>',
'<a class="content" href="http://moodle.org/testfile/test.avi">test mp3</a>',
$mform->addElement('header', 'headerparent', get_string('parentcategory', 'grades'));
$options = array();
- $default = '';
+ $default = -1;
$categories = grade_category::fetch_all(array('courseid'=>$COURSE->id));
foreach ($categories as $cat) {
if (count($categories) > 1) {
$mform->addElement('select', 'parentcategory', get_string('parentcategory', 'grades'), $options);
+ $mform->setDefault('parentcategory', $default);
$mform->addElement('static', 'currentparentaggregation', get_string('currentparentaggregation', 'grades'));
}
$html .= html_writer::tag('div', get_string('restoredfromdraft', 'gradingform_guide'),
array('class' => 'gradingform_guide-restored'));
}
- if (!empty($options['showdescriptionteacher'])) {
- $html .= html_writer::tag('div', $this->get_controller()->get_formatted_description(),
- array('class' => 'gradingform_guide-description'));
- }
+ $html .= html_writer::tag('div', $this->get_controller()->get_formatted_description(),
+ array('class' => 'gradingform_guide-description'));
$html .= $this->get_controller()->get_renderer($page)->display_guide($criteria, $comments, $options, $mode,
$gradingformelement->getName(), $value, $this->validationerrors);
return $html;
echo $OUTPUT->header();
echo $OUTPUT->heading($title);
-if (!empty($options['showdescriptionstudent'])) {
- echo $OUTPUT->box($controller->get_formatted_description(), 'gradingform_guide-description');
-}
+echo $OUTPUT->box($controller->get_formatted_description(), 'gradingform_guide-description');
echo $controller->render_preview($PAGE);
echo $OUTPUT->footer();
break;
case FRONTPAGECOURSELIST:
+ $ncourses = $DB->count_records('course');
if (isloggedin() and !$hassiteconfig and !isguestuser() and empty($CFG->disablemycourses)) {
echo html_writer::tag('a', get_string('skipa', 'access', textlib::strtolower(get_string('mycourses'))), array('href'=>'#skipmycourses', 'class'=>'skip-block'));
echo $OUTPUT->heading(get_string('mycourses'), 2, 'headingblock header');
print_my_moodle();
echo html_writer::tag('span', '', array('class'=>'skip-block-to', 'id'=>'skipmycourses'));
- } else if ((!$hassiteconfig and !isguestuser()) or ($DB->count_records('course') <= FRONTPAGECOURSELIMIT)) {
+ } else if ((!$hassiteconfig and !isguestuser()) or ($ncourses <= FRONTPAGECOURSELIMIT)) {
// admin should not see list of courses when there are too many of them
echo html_writer::tag('a', get_string('skipa', 'access', textlib::strtolower(get_string('availablecourses'))), array('href'=>'#skipavailablecourses', 'class'=>'skip-block'));
echo $OUTPUT->heading(get_string('availablecourses'), 2, 'headingblock header');
print_courses(0);
echo html_writer::tag('span', '', array('class'=>'skip-block-to', 'id'=>'skipavailablecourses'));
+ } else {
+ echo html_writer::tag('div', get_string('therearecourses', '', $ncourses), array('class' => 'notifyproblem'));
+ print_course_search('', false, 'short');
}
break;
$string['availablelangs'] = '가능한 언어 목록';
$string['chooselanguagehead'] = '언어를 선택하시오';
$string['chooselanguagesub'] = '설치 과정에서 사용할 언어를 선택하십시오. 선택한 언어는 사이트의 기본 언어로 사용할 수 있으며, 추후 다른 언어로 바꿀 수도 있습니다.';
-$string['clialreadyinstalled'] = '이미 config.php 파일이 존재함. 사이트를 업데이트하려면 admin/cli/upgrade.php를 사용하십시오';
+$string['clialreadyconfigured'] = '만일 이 사이트를 설치하고 싶은데 이미 config.php파일이 있다면, admin/cli/install_database.php 를 이용하시기 바랍니다.';
+$string['clialreadyinstalled'] = '이미 config.php 파일이 존재함. 사이트를 업그레이드하려면 admin/cli/upgrade.php를 사용하시기 바랍니다.';
$string['cliinstallheader'] = '무들 {$a} 명령 입력 설치 프로그램';
$string['databasehost'] = '데이터베이스 호스트';
$string['databasename'] = '데이터베이스 명칭';
<p>PHP를 업그레이드 하시거나 새버전을 제공하는 웹호스팅 업체로 이전하기를 권합니다!<br />(만일 5.0.x버전을 사용 중이라면 4.4.x 버전으로 다운그레이드 할 수 있습니다)</p>';
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = '당신의 컴퓨터에 <strong>{$a->packname} {$a->packversion}</strong> 패키지를 성공적으로 설치한 것을 축하합니다!';
-$string['welcomep30'] = '<strong>{$a->installername}</strong> 의 이 릴리스는 <strong>무들</strong>이 그 속에서 동작하는 환경을 생성하기 위한 어플리케이션을 포함하고 있습니다.';
+$string['welcomep30'] = '<strong>{$a->installername}</strong> 판본은 <strong>무들</strong>이 동작하는 환경을 생성하기 위한 어플리케이션을 포함하고 있습니다.';
$string['welcomep40'] = '이 패키지는 <strong>무들 {$a->moodlerelease} ({$a->moodleversion})</strong> 을 포함하고 있습니다.';
$string['welcomep50'] = '이 패키지에 있는 모든 어플리케이션을 사용하는 것은 각각의 라이센스에의해 지배받습니다. 완전한<strong>{$a->installername}</strong> 패키지는
<a href="http://www.opensource.org/docs/definition_plain.html">공개 소스이며 </a> <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> 라이선스에 의해 배포됩니다.';
-$string['welcomep60'] = '다음 페이지들은 당신의 컴퓨터에 <strong>무들</strong>을 설정하고 설치하는 길라잡이 역할을 할 것입니다. 기본 설정을 선택하거나 목적에 맞게 선택적으로 수정할 수 있습니다.';
+$string['welcomep60'] = '다음 페이지들은 컴퓨터에 <strong>무들</strong>을 설치하고 설정하는 길라잡이 역할을 할 것입니다. 기본 설정을 선택하거나 목적에 맞게 선택적으로 수정할 수 있습니다.';
$string['welcomep70'] = '<strong>무들</strong> 설정을 계속하기 위해서는 "다음" 버튼을 클릭하세요.';
$string['wwwroot'] = '웹 주소';
$string['dbprefix'] = 'Prefiks tabel';
$string['dirroot'] = 'Katalog Moodle';
$string['environmenthead'] = 'Sprawdzam środowisko (ustawienia) ...';
+$string['environmentsub2'] = 'Każde wydanie Moodle ma pewne minimalne wymagania wersji PHP i pewną liczbę obowiązkowych rozszerzeń PHP. Pełna kontrola środowiska odbywa się przed każdą instalacją i aktualizacją. Prosimy o kontakt z administratorem serwera, jeśli nie wiesz jak zainstalować nową wersję lub włączyć rozszerzenie PHP.';
$string['errorsinenvironment'] = 'Kontrola środowiska zakończona niepowodzeniem!';
$string['installation'] = 'Instalacja';
$string['langdownloaderror'] = 'Niestety język "{$a}" nie może zostać pobrany. Proces instalacji będzie kontynuowany w języku angielskim.';
$string['databasename'] = 'Название базы данных';
$string['databasetypehead'] = 'Выберите драйвер базы данных';
$string['dataroot'] = 'Каталог данных';
+$string['datarootpermission'] = 'Разрешения на каталоги данных';
$string['dbprefix'] = 'Префикс имён таблиц';
$string['dirroot'] = 'Каталог Moodle';
$string['environmenthead'] = 'Проверка среды...';
$string['backgroundcolour'] = 'Transparent colour';
$string['backups'] = 'Backups';
$string['backup_shortname'] = 'Use course name in backup filename';
-$string['backup_shortnamehelp'] = 'Use the course name as part of the backup filename instead of the course id number.';
+$string['backup_shortnamehelp'] = 'Use the course name as part of the backup filename.';
$string['badwordsconfig'] = 'Enter your list of bad words separated by commas.';
$string['badwordsdefault'] = 'If the custom list is empty, a default list from the language pack will be used.';
$string['badwordslist'] = 'Custom bad words list';
$string['lockedbyconfig'] = 'This setting has been locked by the default backup settings';
$string['lockedbyhierarchy'] = 'Locked by dependencies';
$string['managefiles'] = 'Manage backup files';
+$string['missingfilesinpool'] = 'Some files could not be saved during the backup, it won\'t be possible to restore them.';
$string['moodleversion'] = 'Moodle version';
$string['moreresults'] = 'There are too many results, enter a more specific search.';
$string['nomatchingcourses'] = 'There are no courses to display';
$string['restorecourse'] = 'Restore course';
$string['restorecoursesettings'] = 'Course settings';
$string['restoreexecutionsuccess'] = 'The course was restored successfully, clicking the continue button below will take you to view the course you restored.';
+$string['restorefileweremissing'] = 'Some files could not be restored because they were missing in the backup.';
$string['restorenewcoursefullname'] = 'New course name';
$string['restorenewcourseshortname'] = 'New course short name';
$string['restorenewcoursestartdate'] = 'New start date';
$string['defaultregion_help'] = 'Themes may define one or more named block regions where blocks are displayed. This setting defines which of these you want this block to appear in by default. The region may be overridden on specific pages if required.';
$string['defaultweight'] = 'Default weight';
$string['defaultweight_help'] = 'The default weight allows you to choose roughly where you want the block to appear in the chosen region, either at the top or the bottom. The final location is calculated from all the blocks in that region (for example, only one block can actually be at the top). This value can be overridden on specific pages if required.';
+$string['deletecheck'] = 'Delete {$a} block?';
+$string['deleteblockcheck'] = 'Are you sure that you want to delete this block titled {$a}?';
$string['moveblockhere'] = 'Move block here';
$string['movingthisblockcancel'] = 'Moving this block ({$a})';
$string['onthispage'] = 'On this page';
$string['eventendtime'] = 'End time';
$string['eventinstanttime'] = 'Time';
$string['eventkind'] = 'Type of event';
-$string['eventname'] = 'Name';
+$string['eventname'] = 'Event title';
$string['eventnone'] = 'No events';
$string['eventrepeat'] = 'Repeats';
$string['eventsall'] = 'All events';
$string['createcategory'] = 'Create category';
$string['createfolder'] = 'Create a folder in {$a}';
$string['createuserandpass'] = 'Choose your username and password';
+$string['createuser'] = 'Create user';
$string['createziparchive'] = 'Create zip archive';
$string['creatingblocks'] = 'Creating blocks';
$string['creatingblocksroles'] = 'Creating block level role assignments and overrides';
$string['themes'] = 'Themes';
$string['themesaved'] = 'New theme saved';
$string['thereareno'] = 'There are no {$a} in this course';
+$string['therearecourses'] = 'There are {$a} courses';
$string['thiscategorycontains'] = 'This category contains';
$string['time'] = 'Time';
$string['timezone'] = 'Timezone';
$string['virusplaceholder'] = 'This file that has been uploaded was found to contain a virus and has been moved or deleted and the user notified.';
$string['visible'] = 'Visible';
$string['visibletostudents'] = 'Visible to {$a}';
+$string['warning'] = 'Warning';
$string['warningdeleteresource'] = 'Warning: {$a} is referred in a resource. Would you like to update the resource?';
$string['webpage'] = 'Web page';
$string['week'] = 'Week';
if ($withprefix){
$name = get_string('modulename', $cm->modname).': ';
}
- $name .= $mod->name;
+ $name .= format_string($mod->name, true, array('context' => $this));
}
}
return $name;
$str = '
<div class="form-item clearfix" id="admin-'.$setting->name.'">
<div class="form-label">
- <label '.$labelfor.'>'.highlightfast($query, $title).'<span class="form-shortname">'.highlightfast($query, $name).'</span>
- '.$override.$warning.'
- </label>
+ <label '.$labelfor.'>'.highlightfast($query, $title).$override.$warning.'</label>
+ <span class="form-shortname">'.highlightfast($query, $name).'</span>
</div>
<div class="form-setting">'.$form.$defaultinfo.'</div>
<div class="form-description">'.highlight($query, markdown_to_html($description)).'</div>
* @return boolean true if anything was done. False if not.
*/
public function process_url_delete() {
- $blockid = optional_param('bui_deleteid', null, PARAM_INTEGER);
+ global $CFG, $PAGE, $OUTPUT;
+
+ $blockid = optional_param('bui_deleteid', null, PARAM_INT);
+ $confirmdelete = optional_param('bui_confirm', null, PARAM_INT);
+
if (!$blockid) {
return false;
}
require_sesskey();
-
$block = $this->page->blocks->find_instance($blockid);
-
if (!$block->user_can_edit() || !$this->page->user_can_edit_blocks() || !$block->user_can_addto($this->page)) {
throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('deleteablock'));
}
- blocks_delete_instance($block->instance);
-
- // If the page URL was a guess, it will contain the bui_... param, so we must make sure it is not there.
- $this->page->ensure_param_not_in_url('bui_deleteid');
+ if (!$confirmdelete) {
+ $deletepage = new moodle_page();
+ $deletepage->set_pagelayout('admin');
+ $deletepage->set_course($this->page->course);
+ $deletepage->set_context($this->page->context);
+ if ($this->page->cm) {
+ $deletepage->set_cm($this->page->cm);
+ }
- return true;
+ $deleteurlbase = str_replace($CFG->wwwroot . '/', '/', $this->page->url->out_omit_querystring());
+ $deleteurlparams = $this->page->url->params();
+ $deletepage->set_url($deleteurlbase, $deleteurlparams);
+ $deletepage->set_block_actions_done();
+ // At this point we are either going to redirect, or display the form, so
+ // overwrite global $PAGE ready for this. (Formslib refers to it.)
+ $PAGE = $deletepage;
+ //some functions like MoodleQuickForm::addHelpButton use $OUTPUT so we need to replace that too
+ $output = $deletepage->get_renderer('core');
+ $OUTPUT = $output;
+
+ $site = get_site();
+ $blocktitle = $block->get_title();
+ $strdeletecheck = get_string('deletecheck', 'block', $blocktitle);
+ $message = get_string('deleteblockcheck', 'block', $blocktitle);
+
+ $PAGE->navbar->add($strdeletecheck);
+ $PAGE->set_title($blocktitle . ': ' . $strdeletecheck);
+ $PAGE->set_heading($site->fullname);
+ echo $OUTPUT->header();
+ $confirmurl = new moodle_url("$deletepage->url?", array('sesskey' => sesskey(), 'bui_deleteid' => $block->instance->id, 'bui_confirm' => 1));
+ $cancelurl = new moodle_url($deletepage->url);
+ $yesbutton = new single_button($confirmurl, get_string('yes'));
+ $nobutton = new single_button($cancelurl, get_string('no'));
+ echo $OUTPUT->confirm($message, $yesbutton, $nobutton);
+ echo $OUTPUT->footer();
+ // Make sure that nothing else happens after we have displayed this form.
+ exit;
+ } else {
+ blocks_delete_instance($block->instance);
+ // bui_deleteid and bui_confirm should not be in the PAGE url.
+ $this->page->ensure_param_not_in_url('bui_deleteid');
+ $this->page->ensure_param_not_in_url('bui_confirm');
+ return true;
+ }
}
/**
$course = $COURSE;
} else {
$course = $DB->get_record('course', array('id' => $this->item->course),
- 'id, enablecompletion, modinfo', MUST_EXIST);
+ 'id, enablecompletion, modinfo, sectioncache', MUST_EXIST);
}
foreach ($this->item->conditionscompletion as $cmid => $expectedcompletion) {
if (!$modinfo) {
$course = $COURSE;
} else {
$course = $DB->get_record('course', array('id' => $this->item->course),
- 'id, enablecompletion, modinfo', MUST_EXIST);
+ 'id, enablecompletion, modinfo, sectioncache', MUST_EXIST);
}
$completion = new completion_info($course);
return;
}
+ if (isguestuser()) {
+ // Do not update guest access times/ips for performance.
+ return;
+ }
+
if (empty($courseid)) {
$courseid = SITEID;
}
if ($CFG->restrictmodulesfor === 'all') {
$courses = $DB->get_records_menu('course', array(), 'id', 'id, 1');
} else if ($CFG->restrictmodulesfor === 'requested') {
- $courses = $DB->get_records_menu('course', array('retrictmodules' => 1), 'id', 'id, 1');
+ $courses = $DB->get_records_menu('course', array('restrictmodules' => 1), 'id', 'id, 1');
} else {
$courses = array();
}
if ($oldversion < 2012031500.02) {
- // Define field retrictmodules to be dropped from course
+ // Define field restrictmodules to be dropped from course
$table = new xmldb_table('course');
$field = new xmldb_field('restrictmodules');
upgrade_main_savepoint(true, 2012062501.08);
}
+ if ($oldversion < 2012062501.14) {
+ $subquery = 'SELECT b.id FROM {blog_external} b where b.id = ' . $DB->sql_cast_char2int('{post}.content', true);
+ $sql = 'DELETE FROM {post}
+ WHERE {post}.module = \'blog_external\'
+ AND NOT EXISTS (' . $subquery . ')
+ AND ' . $DB->sql_isnotempty('post', 'uniquehash', false, false);
+ $DB->execute($sql);
+ upgrade_main_savepoint(true, 2012062501.14);
+ }
+
return true;
}
defined('MOODLE_INTERNAL') || die();
+/**
+ * Returns all non-view and non-temp tables with sane names.
+ * Prints list of non-supported tables using $OUTPUT->notification()
+ *
+ * @return array
+ */
+function upgrade_mysql_get_supported_tables() {
+ global $OUTPUT, $DB;
+
+ $tables = array();
+ $patprefix = str_replace('_', '\\_', $DB->get_prefix());
+ $pregprefix = preg_quote($DB->get_prefix(), '/');
+
+ $sql = "SHOW FULL TABLES LIKE '$patprefix%'";
+ $rs = $DB->get_recordset_sql($sql);
+ foreach ($rs as $record) {
+ $record = array_change_key_case((array)$record, CASE_LOWER);
+ $type = $record['table_type'];
+ unset($record['table_type']);
+ $fullname = array_shift($record);
+
+ if ($pregprefix === '') {
+ $name = $fullname;
+ } else {
+ $count = null;
+ $name = preg_replace("/^$pregprefix/", '', $fullname, -1, $count);
+ if ($count !== 1) {
+ continue;
+ }
+ }
+
+ if (!preg_match("/^[a-z][a-z0-9_]*$/", $name)) {
+ echo $OUTPUT->notification("Database table with invalid name '$fullname' detected, skipping.", 'notifyproblem');
+ continue;
+ }
+ if ($type === 'VIEW') {
+ echo $OUTPUT->notification("Unsupported database table view '$fullname' detected, skipping.", 'notifyproblem');
+ continue;
+ }
+ $tables[$name] = $name;
+ }
+ $rs->close();
+
+ return $tables;
+}
/**
* Remove all signed numbers from current database - mysql only.
$pbar = new progress_bar('mysqlconvertunsigned', 500, true);
$prefix = $DB->get_prefix();
- $tables = $DB->get_tables();
+ $tables = upgrade_mysql_get_supported_tables();
$tablecount = count($tables);
$i = 0;
$pbar = new progress_bar('mysqlconvertlobs', 500, true);
$prefix = $DB->get_prefix();
- $tables = $DB->get_tables();
+ $tables = upgrade_mysql_get_supported_tables();
asort($tables);
$tablecount = count($tables);
$string['advanced_dlg:anchor_name'] = 'Anchor name';
$string['advanced_dlg:anchor_title'] = 'Insert/edit anchor';
$string['advanced_dlg:charmap_title'] = 'Select custom character';
+$string['advanced_dlg:charmap_usage'] = 'Use left and right arrows to navigate.';
$string['advanced_dlg:code_title'] = 'HTML Source Editor';
$string['advanced_dlg:code_wordwrap'] = 'Word wrap';
$string['advanced_dlg:colorpicker_color'] = 'Color:';
$module = 'moodle-form-dateselector';
$function = 'M.form.dateselector.init_date_selectors';
$config = array(array(
- 'firstdayofweek' => get_string('firstdayofweek', 'langconfig'),
- 'mon' => strftime('%a', strtotime("Monday")), // 5th Jan 1970 at 12pm
+ 'firstdayofweek' => get_string('firstdayofweek', 'langconfig'),
+ 'mon' => strftime('%a', strtotime("Monday")),
'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"))
+ 'january' => strftime('%B', strtotime("January 1")),
+ 'february' => strftime('%B', strtotime("February 1")),
+ 'march' => strftime('%B', strtotime("March 1")),
+ 'april' => strftime('%B', strtotime("April 1")),
+ 'may' => strftime('%B', strtotime("May 1")),
+ 'june' => strftime('%B', strtotime("June 1")),
+ 'july' => strftime('%B', strtotime("July 1")),
+ 'august' => strftime('%B', strtotime("August 1")),
+ 'september' => strftime('%B', strtotime("September 1")),
+ 'october' => strftime('%B', strtotime("October 1")),
+ 'november' => strftime('%B', strtotime("November 1")),
+ 'december' => strftime('%B', strtotime("December 1"))
));
$PAGE->requires->yui_module($module, $function, $config);
$done = true;
$unfiltered = array();
if (null === $elementList) {
// iterate over all elements, calling their exportValue() methods
- $emptyarray = array();
foreach (array_keys($this->_elements) as $key) {
- if ($this->_elements[$key]->isFrozen() && !$this->_elements[$key]->_persistantFreeze){
- $value = $this->_elements[$key]->exportValue($emptyarray, true);
+ if ($this->_elements[$key]->isFrozen() && !$this->_elements[$key]->_persistantFreeze) {
+ $varname = $this->_elements[$key]->_attributes['name'];
+ $value = '';
+ // If we have a default value then export it.
+ if (isset($this->_defaultValues[$varname])) {
+ $value = array($varname => $this->_defaultValues[$varname]);
+ }
} else {
$value = $this->_elements[$key]->exportValue($this->_submitValues, true);
}
if (is_array($this->_constantValues)) {
$unfiltered = HTML_QuickForm::arrayMerge($unfiltered, $this->_constantValues);
}
-
return $unfiltered;
}
$source = 'https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key='.$docid.'&exportFormat=xls';
break;
case 'pdf':
- $title = (string)$gdoc->title;
- $source = (string)$gdoc->content[0]->attributes()->src;
- break;
case 'file':
- $title = (string)$gdoc->title;
- $source = (string)$gdoc->content[0]->attributes()->src;
+ $title = (string)$gdoc->title;
+ // Some files don't have a content probably because the download has been restricted.
+ if (isset($gdoc->content)) {
+ $source = (string)$gdoc->content[0]->attributes()->src;
+ }
break;
}
- if (!empty($source)) {
- $files[] = array( 'title' => $title,
- 'url' => "{$gdoc->link[0]->attributes()->href}",
- 'source' => $source,
- 'date' => usertime(strtotime($gdoc->updated)),
- 'thumbnail' => (string) $OUTPUT->pix_url(file_extension_icon($title, 32))
- );
- }
+ $files[] = array( 'title' => $title,
+ 'url' => "{$gdoc->link[0]->attributes()->href}",
+ 'source' => $source,
+ 'date' => usertime(strtotime($gdoc->updated)),
+ 'thumbnail' => (string) $OUTPUT->pix_url(file_extension_icon($title, 32))
+ );
}
return $files;
protected function embed_external(moodle_url $url, $name, $width, $height, $options) {
global $CFG;
- $site = $this->matches[1];
- $videoid = $this->matches[3];
+ $site = 'www.youtube.com';
+ $videoid = end($this->matches);
$info = trim($name);
if (empty($info) or strpos($info, 'http') === 0) {
}
protected function get_regex() {
+ // Regex for standard youtube link
+ $link = '(youtube(-nocookie)?\.com/(?:watch\?v=|v/))';
+ // Regex for shortened youtube link
+ $shortlink = '((youtu|y2u)\.be/)';
+
// Initial part of link.
- $start = '~^https?://(www\.youtube(-nocookie)?\.com)/';
- // Middle bit: either watch?v= or v/.
- $middle = '(?:watch\?v=|v/)([a-z0-9\-_]+)';
+ $start = '~^https?://(www\.)?(' . $link . '|' . $shortlink . ')';
+ // Middle bit: Video key value
+ $middle = '([a-z0-9\-_]+)';
return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
}
}
public function get_embeddable_markers() {
- return array('youtube');
+ return array('youtube.com', 'youtube-nocookie.com', 'youtu.be', 'y2u.be');
}
}
function update_user_login_times() {
global $USER, $DB;
+ if (isguestuser()) {
+ // Do not update guest access times/ips for performance.
+ return true;
+ }
+
$now = time();
$user = new stdClass();
* Any plugin that needs to purge user data should register the 'user_deleted' event.
*
* @param stdClass $user full user object before delete
- * @return boolean always true
+ * @return boolean success
+ * @throws coding_exception if invalid $user parameter detected
*/
-function delete_user($user) {
+function delete_user(stdClass $user) {
global $CFG, $DB;
require_once($CFG->libdir.'/grouplib.php');
require_once($CFG->libdir.'/gradelib.php');
require_once($CFG->dirroot.'/message/lib.php');
require_once($CFG->dirroot.'/tag/lib.php');
+ // Make sure nobody sends bogus record type as parameter.
+ if (!property_exists($user, 'id') or !property_exists($user, 'username')) {
+ throw new coding_exception('Invalid $user parameter in delete_user() detected');
+ }
+
+ // Better not trust the parameter and fetch the latest info,
+ // this will be very expensive anyway.
+ if (!$user = $DB->get_record('user', array('id'=>$user->id))) {
+ debugging('Attempt to delete unknown user account.');
+ return false;
+ }
+
+ // There must be always exactly one guest record,
+ // originally the guest account was identified by username only,
+ // now we use $CFG->siteguest for performance reasons.
+ if ($user->username === 'guest' or isguestuser($user)) {
+ debugging('Guest user account can not be deleted.');
+ return false;
+ }
+
+ // Admin can be theoretically from different auth plugin,
+ // but we want to prevent deletion of internal accoutns only,
+ // if anything goes wrong ppl may force somebody to be admin via
+ // config.php setting $CFG->siteadmins.
+ if ($user->auth === 'manual' and is_siteadmin($user)) {
+ debugging('Local administrator accounts can not be deleted.');
+ return false;
+ }
+
// delete all grades - backup is kept in grade_grades_history table
grade_user_delete($user->id);
foreach ($fields as $field) {
$updatesql = "UPDATE {".$modname."}
SET $field = $field + ?
- WHERE course=? AND $field<>0 AND $field<>0";
+ WHERE course=? AND $field<>0";
$return = $DB->execute($updatesql, array($timeshift, $courseid)) && $return;
}
return true;
}
- if ($now - $recent > HOURSECS) {
+ if ($now - $recent > 24 * HOURSECS) {
return false;
}
// sort cats out into different contexts
$categoriesarray = array();
- foreach ($pcontexts as $pcontext) {
- $contextstring = print_context_name(
- get_context_instance_by_id($pcontext), true, true);
+ foreach ($pcontexts as $contextid) {
+ $context = context::instance_by_id($contextid);
+ $contextstring = $context->get_context_name(true, true);
foreach ($categories as $category) {
- if ($category->contextid == $pcontext) {
+ if ($category->contextid == $contextid) {
$cid = $category->id;
if ($currentcat != $cid || $currentcat == 0) {
$countstring = !empty($category->questioncount) ?
" ($category->questioncount)" : '';
- $categoriesarray[$contextstring][$cid] = $category->indentedname.$countstring;
+ $categoriesarray[$contextstring][$cid] =
+ format_string($category->indentedname, true,
+ array('context' => $context)) . $countstring;
}
}
}
$this->assertEquals('5.43000', format_float(5.43, 5, false));
$this->assertEquals('5.43', format_float(5.43, 5, false, true));
}
+
+ /**
+ * Test deleting of users.
+ */
+ public function test_delete_user() {
+ global $DB, $CFG;
+
+ $this->resetAfterTest();
+
+ $guest = $DB->get_record('user', array('id'=>$CFG->siteguest), '*', MUST_EXIST);
+ $admin = $DB->get_record('user', array('id'=>$CFG->siteadmins), '*', MUST_EXIST);
+ $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
+
+ $user = $this->getDataGenerator()->create_user(array('idnumber'=>'abc'));
+ $user2 = $this->getDataGenerator()->create_user(array('idnumber'=>'xyz'));
+
+ $result = delete_user($user);
+ $this->assertTrue($result);
+ $deluser = $DB->get_record('user', array('id'=>$user->id), '*', MUST_EXIST);
+ $this->assertEquals(1, $deluser->deleted);
+ $this->assertEquals(0, $deluser->picture);
+ $this->assertSame('', $deluser->idnumber);
+ $this->assertSame(md5($user->username), $deluser->email);
+ $this->assertRegExp('/^'.preg_quote($user->email, '/').'\.\d*$/', $deluser->username);
+
+ $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
+
+ // Try invalid params.
+
+ $record = new stdClass();
+ $record->grrr = 1;
+ try {
+ delete_user($record);
+ $this->fail('Expecting exception for invalid delete_user() $user parameter');
+ } catch (coding_exception $e) {
+ $this->assertTrue(true);
+ }
+ $record->id = 1;
+ try {
+ delete_user($record);
+ $this->fail('Expecting exception for invalid delete_user() $user parameter');
+ } catch (coding_exception $e) {
+ $this->assertTrue(true);
+ }
+
+ $CFG->debug = DEBUG_MINIMAL; // Prevent standard debug warnings.
+
+ $record = new stdClass();
+ $record->id = 666;
+ $record->username = 'xx';
+ $this->assertFalse($DB->record_exists('user', array('id'=>666))); // Any non-existent id is ok.
+ $result = delete_user($record);
+ $this->assertFalse($result);
+
+ $result = delete_user($guest);
+ $this->assertFalse($result);
+
+ $result = delete_user($admin);
+ $this->assertFalse($result);
+ }
}
*/
public function test_cron_has_fresh_fetch() {
$provider = testable_available_update_checker::instance();
- $provider->fakerecentfetch = time() - 59 * MINSECS; // fetched an hour ago
+ $provider->fakerecentfetch = time() - 23 * HOURSECS; // fetched 23 hours ago
$provider->fakecurrenttimestamp = -1;
$provider->cron();
$this->assertTrue(true); // we should get here with no exception thrown
*/
public function test_cron_offset_execution_not_yet() {
$provider = testable_available_update_checker::instance();
- $provider->fakerecentfetch = time() - 24 * HOURSECS;
- $provider->fakecurrenttimestamp = mktime(1, 40, 02); // 01:40:02 AM
+ $provider->fakecurrenttimestamp = mktime(1, 40, 02); // 01:40:02 AM today
+ $provider->fakerecentfetch = $provider->fakecurrenttimestamp - 24 * HOURSECS;
$provider->cron();
$this->assertTrue(true); // we should get here with no exception thrown
}
/**
- * The first cron after 01:42 AM today should fetch the data
+ * The first cron after 01:42 AM today should fetch the data and then
+ * it is supposed to wait next 24 hours.
*
* @see testable_available_update_checker::cron_execution_offset()
*/
public function test_cron_offset_execution() {
$provider = testable_available_update_checker::instance();
- $provider->fakerecentfetch = time() - 24 * HOURSECS;
- $provider->fakecurrenttimestamp = mktime(1, 45, 02); // 01:45:02 AM
- $this->setExpectedException('testable_available_update_checker_cron_executed');
- $provider->cron();
+
+ // the cron at 01:45 should fetch the data
+ $provider->fakecurrenttimestamp = mktime(1, 45, 02); // 01:45:02 AM today
+ $provider->fakerecentfetch = $provider->fakecurrenttimestamp - 24 * HOURSECS - 1;
+ $executed = false;
+ try {
+ $provider->cron();
+ } catch (testable_available_update_checker_cron_executed $e) {
+ $executed = true;
+ }
+ $this->assertTrue($executed, 'Cron should be executed at 01:45:02 but it was not.');
+
+ // another cron at 06:45 should still consider data as fresh enough
+ $provider->fakerecentfetch = $provider->fakecurrenttimestamp;
+ $provider->fakecurrenttimestamp = mktime(6, 45, 03); // 06:45:03 AM
+ $executed = false;
+ try {
+ $provider->cron();
+ } catch (testable_available_update_checker_cron_executed $e) {
+ $executed = true;
+ }
+ $this->assertFalse($executed, 'Cron should not be executed at 06:45:03 but it was.');
+
+ // the next scheduled execution should happen the next day
+ $provider->fakecurrenttimestamp = $provider->fakerecentfetch + 24 * HOURSECS + 1;
+ $executed = false;
+ try {
+ $provider->cron();
+ } catch (testable_available_update_checker_cron_executed $e) {
+ $executed = true;
+ }
+ $this->assertTrue($executed, 'Cron should be executed the next night but it was not.');
}
public function test_compare_responses_both_empty() {
}
protected function cron_execute() {
- throw new testable_available_update_checker_cron_executed('Cron executed but it should not!');
+ throw new testable_available_update_checker_cron_executed('Cron executed!');
}
}
}
}
- //Sort the conversations. This is a bit complicated as we need to sort by $conversation->timecreated
- //and there may be multiple conversations with the same timecreated value.
- //The conversations array contains both read and unread messages (different tables) so sorting by ID won't work
- usort($conversations, "conversationsort");
+ // Sort the conversations by $conversation->timecreated, newest to oldest
+ // There may be multiple conversations with the same timecreated
+ // The conversations array contains both read and unread messages (different tables) so sorting by ID won't work
+ $result = collatorlib::asort_objects_by_property($conversations, 'timecreated', collatorlib::SORT_NUMERIC);
+ $conversations = array_reverse($conversations);
return $conversations;
}
-/**
- * Sort function used to order conversations
- *
- * @param object $a A conversation object
- * @param object $b A conversation object
- * @return integer
- */
-function conversationsort($a, $b)
-{
- if ($a->timecreated == $b->timecreated) {
- return 0;
- }
- return ($a->timecreated > $b->timecreated) ? -1 : 1;
-}
-
/**
* Get the users recent event notifications
*
array($user1->id, $user2->id, $user2->id, $user1->id, $user1->id),
"timecreated $sort", '*', 0, $limitnum)) {
foreach ($messages_read as $message) {
- $messages[$message->timecreated] = $message;
+ $messages[] = $message;
}
}
if ($messages_new = $DB->get_records_select('message', "((useridto = ? AND useridfrom = ?) OR
array($user1->id, $user2->id, $user2->id, $user1->id, $user1->id),
"timecreated $sort", '*', 0, $limitnum)) {
foreach ($messages_new as $message) {
- $messages[$message->timecreated] = $message;
+ $messages[] = $message;
}
}
+ $result = collatorlib::asort_objects_by_property($messages, 'timecreated', collatorlib::SORT_NUMERIC);
+
//if we only want the last $limitnum messages
- ksort($messages);
$messagecount = count($messages);
- if ($limitnum>0 && $messagecount>$limitnum) {
- $messages = array_slice($messages, $messagecount-$limitnum, $limitnum, true);
+ if ($limitnum > 0 && $messagecount > $limitnum) {
+ $messages = array_slice($messages, $messagecount - $limitnum, $limitnum, true);
}
return $messages;
// get all user submissions, indexed by assignment id
- $mysubmissions = $DB->get_records_sql("SELECT a.id AS assignment, a.nosubmissions AS offline, g.timemodified AS timemarked, g.grader AS grader, g.grade AS grade, s.status AS status
+ $mysubmissions = $DB->get_records_sql("SELECT a.id AS assignment, a.nosubmissions AS nosubmissions, g.timemodified AS timemarked, g.grader AS grader, g.grade AS grade, s.status AS status
FROM {assign} a LEFT JOIN {assign_grades} g ON g.assignment = a.id AND g.userid = ? LEFT JOIN {assign_submission} s ON s.assignment = a.id AND s.userid = ?
AND a.id $sqlassignmentids", array_merge(array($USER->id, $USER->id), $assignmentidparams));
$str .= '<div class="details">';
$str .= get_string('mysubmission', 'assign');
$submission = $mysubmissions[$assignment->id];
- if ($submission->offline) {
+ if ($submission->nosubmissions) {
$str .= get_string('offline', 'assign');
} else if(!$submission->status || $submission->status == 'draft'){
$str .= $strnotsubmittedyet;
$gradingoptionsdata->filter = $filter;
$gradingoptionsform->set_data($gradingoptionsdata);
+ $actionformtext = $this->output->render($gradingactions);
+ $o .= $this->output->render(new assign_header($this->get_instance(),
+ $this->get_context(), false, $this->get_course_module()->id, get_string('grading', 'assign'), $actionformtext));
+ $o .= groups_print_activity_menu($this->get_course_module(), $CFG->wwwroot . '/mod/assign/view.php?id=' . $this->get_course_module()->id.'&action=grading', true);
+
// plagiarism update status apearring in the grading book
if (!empty($CFG->enableplagiarism)) {
/** Include plagiarismlib.php */
$o .= plagiarism_update_status($this->get_course(), $this->get_course_module());
}
- $actionformtext = $this->output->render($gradingactions);
- $o .= $this->output->render(new assign_header($this->get_instance(),
- $this->get_context(), false, $this->get_course_module()->id, get_string('grading', 'assign'), $actionformtext));
- $o .= groups_print_activity_menu($this->get_course_module(), $CFG->wwwroot . '/mod/assign/view.php?id=' . $this->get_course_module()->id.'&action=grading', true);
-
-
// load and print the table of submissions
if ($showquickgrading && $quickgrading) {
$table = $this->output->render(new assign_grading_table($this, $perpage, $filter, 0, true));
$rules[] = new restore_decode_rule('BOOKVIEWBYB', '/mod/book/view.php?b=$1', 'book');
$rules[] = new restore_decode_rule('BOOKVIEWBYBCH', '/mod/book/view.php?b=$1&chapterid=$2', array('book', 'book_chapter'));
- // Convert old book links MDL-33362\r
+ // Convert old book links MDL-33362 & MDL-35007
$rules[] = new restore_decode_rule('BOOKSTART', '/mod/book/view.php?id=$1', 'course_module');
+ $rules[] = new restore_decode_rule('BOOKCHAPTER', '/mod/book/view.php?id=$1&chapterid=$2', array('course_module', 'book_chapter'));
return $rules;
}
return false; // True if anything was printed, otherwise false
}
+/**
+ * This function is used by the reset_course_userdata function in moodlelib.
+ * @param $data the data submitted from the reset course.
+ * @return array status array
+ */
+function book_reset_userdata($data) {
+ return array();
+}
+
/**
* No cron in book.
*
defined('MOODLE_INTERNAL') || die;
$module->component = 'mod_book'; // Full name of the plugin (used for diagnostics)
-$module->version = 2012061701; // The current module version (Date: YYYYMMDDXX)
+$module->version = 2012061702; // The current module version (Date: YYYYMMDDXX)
$module->requires = 2012061700; // Requires this Moodle version
$module->cron = 0; // Period for cron to check this module (secs)
$strtoc = get_string('toc', 'mod_book');
// prepare header
-$PAGE->set_title($book->name);
+$pagetitle = $book->name . ": " . $chapter->title;
+$PAGE->set_title($pagetitle);
$PAGE->set_heading($course->fullname);
book_add_fake_block($chapters, $chapter, $book, $cm, $edit);
#!/usr/bin/php -q
<?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/>.
+
+/**
+ * Chat daemon
+ *
+ * @package mod_chat
+ * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('CLI_SCRIPT', true);
+
+require(dirname(dirname(dirname(__FILE__))).'/config.php');
+require_once($CFG->dirroot . '/mod/chat/lib.php');
+
// Browser quirks
define('QUIRK_CHUNK_UPDATE', 0x0001);
$_SERVER['SERVER_NAME'] = 'dummy';
$_SERVER['HTTP_USER_AGENT'] = 'dummy';
-define('NO_MOODLE_COOKIES', true); // session not used here
-
-include('../../config.php');
-include('lib.php');
-
$_SERVER['SERVER_NAME'] = $CFG->chat_serverhost;
$_SERVER['PHP_SELF'] = "http://$CFG->chat_serverhost:$CFG->chat_serverport/mod/chat/chatd.php";
$safemode = ini_get('safe_mode');
-
-if($phpversion < '4.3') {
- die("Error: The Moodle chat daemon requires at least PHP version 4.3 to run.\n Since your version is $phpversion, you have to upgrade.\n\n");
-}
if(!empty($safemode)) {
die("Error: Cannot run with PHP safe_mode = On. Turn off safe_mode in php.ini.\n");
}
-$passref = ini_get('allow_call_time_pass_reference');
-if(empty($passref)) {
- die("Error: Cannot run with PHP allow_call_time_pass_reference = Off. Turn on allow_call_time_pass_reference in php.ini.\n");
-}
-
@set_time_limit (0);
-set_magic_quotes_runtime(0);
error_reporting(E_ALL);
function chat_empty_connection() {
}
function get_user_window($sessionid) {
- global $CFG, $PAGE, $OUTPUT;
+ global $CFG, $OUTPUT;
static $str;
$info = &$this->sets_info[$sessionid];
- $PAGE->set_course($info['course']);
$timenow = time();
// $this->trace('QUIRKS value for this connection is '.$customdata['quirks']);
+ $header = "HTTP/1.1 200 OK\n";
+ $header .= "Connection: close\n";
+ $header .= "Date: ".date('r')."\n";
+ $header .= "Server: Moodle\n";
+ $header .= "Content-Type: text/html; charset=utf-8\n";
+ $header .= "Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT\n";
+ $header .= "Cache-Control: no-cache, must-revalidate\n";
+ $header .= "Expires: Wed, 4 Oct 1978 09:32:45 GMT\n";
+ $header .= "\n";
+
$this->dismiss_half($sessionid, false);
- $this->write_data($this->conn_sets[$sessionid][CHAT_CONNECTION_CHANNEL], $CHAT_HTMLHEAD_JS);
+ $this->write_data($this->conn_sets[$sessionid][CHAT_CONNECTION_CHANNEL], $header . $CHAT_HTMLHEAD_JS);
$this->trace('Connection accepted: '.$this->conn_sets[$sessionid][CHAT_CONNECTION_CHANNEL].', SID: '.$sessionid.' UID: '.$chatuser->userid.' GID: '.$chatuser->groupid, E_USER_WARNING);
// Finally, broadcast the "entered the chat" message
}
function message_broadcast($message, $sender) {
- global $PAGE;
if(empty($this->conn_sets)) {
return true;
{
// Simply give them the message
- $PAGE->set_course($info['course']);
$output = chat_format_message_manually($message, $info['courseid'], $sender, $info['user']);
$this->trace('Delivering message "'.$output->text.'" to '.$this->conn_sets[$sessionid][CHAT_CONNECTION_CHANNEL]);
// [pj]: I really must have a good read on sockets. What exactly does this do?
// http://www.unixguide.net/network/socketfaq/4.5.shtml is still not enlightening enough for me.
- socket_setopt($this->listen_socket, SOL_SOCKET, SO_REUSEADDR, 1);
+ socket_set_option($this->listen_socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_set_nonblock($this->listen_socket);
}
die();
}
-if (!function_exists('socket_setopt')) {
- echo "Error: Function socket_setopt() does not exist.\n";
+if (!function_exists('socket_set_option')) {
+ echo "Error: Function socket_set_option() does not exist.\n";
echo "Possibly PHP has not been compiled with --enable-sockets.\n\n";
die();
}
$USER = $DB->get_record('user', array('id'=>$chatuser->userid));
//Setup course, lang and theme
+$PAGE->set_pagelayout('embedded');
$PAGE->set_course($DB->get_record('course', array('id' => $chatuser->course)));
$PAGE->requires->js('/mod/chat/gui_sockets/chat_gui_sockets.js', true);
$PAGE->requires->js_function_call('setfocus');
</title>
</head>
<frameset cols="*,200" border="5" framespacing="no" frameborder="yes" marginwidth="2" marginheight="1">
- <frameset rows="0,*,50" border="0" framespacing="no" frameborder="no" marginwidth="2" marginheight="1">
+ <frameset rows="0,*,70" border="0" framespacing="no" frameborder="no" marginwidth="2" marginheight="1">
<frame src="../empty.php" name="empty" scrolling="auto" noresize marginwidth="2" marginheight="0">
<frame src="<?php echo "http://$CFG->chat_serverhost:$CFG->chat_serverport?win=chat&$params"; ?>" scrolling="auto" name="msg" noresize marginwidth="2" marginheight="0">
<frame src="chatinput.php?<?php echo $params ?>" name="input" scrolling="no" marginwidth="2" marginheight="1">
$option->set_source_sql('
SELECT *
- FROM {choice_options}
- WHERE choiceid = ?',
+ FROM {choice_options}
+ WHERE choiceid = ?
+ ORDER BY id',
array(backup::VAR_PARENTID));
// All the rest of elements only happen if we are including user info
</tr>
<tr>
<td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
- <td class="c1"><textarea style="width:300px; height:150px;" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
+ <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
</tr>
</table>
} else {
$compasslong = sprintf('%01.4f', $long) . '°E';
}
- $str = '<form style="display:inline;">';
// Now let's create the jump-to-services link
$servicesshown = explode(',', $this->field->param1);
);
if(sizeof($servicesshown)==1 && $servicesshown[0]) {
- $str .= " <a href='"
+ $str = " <a href='"
. str_replace(array_keys($urlreplacements), array_values($urlreplacements), $this->linkoutservices[$servicesshown[0]])
."' title='$servicesshown[0]'>$compasslat, $compasslong</a>";
} elseif (sizeof($servicesshown)>1) {
+ $str = '<form id="latlongfieldbrowse">';
$str .= "$compasslat, $compasslong\n";
$str .= "<label class='accesshide' for='jumpto'>". get_string('jumpto') ."</label>";
$str .= "<select id='jumpto' name='jumpto'>";
// NB! If you are editing this, make sure you don't break the javascript reference "previousSibling"
// which allows the "Go" button to refer to the drop-down selector.
$str .= "\n</select><input type='button' value='" . get_string('go') . "' onclick='if(previousSibling.value){self.location=previousSibling.value}'/>";
+ $str .= '</form>';
} else {
- $str.= "$compasslat, $compasslong";
+ $str = "$compasslat, $compasslong";
}
- $str.= '</form>';
+
return $str;
}
return false;
</tr>
<tr>
<td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
- <td class="c1"><textarea style="width:300px; height:150px;" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
+ <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
</tr>
</table>
</tr>
<tr>
<td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
- <td class="c1"><textarea style="width:300px; height:150px;" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
+ <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
</tr>
</table>
if ($template == 'listtemplate') {
$src = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/mod_data/content/'.$content->id.'/'.'thumb_'.$content->content);
// no need to add width/height, because the thumb is resized properly
- $str = '<a href="view.php?d='.$this->field->dataid.'&rid='.$recordid.'"><img src="'.$src.'" alt="'.s($alt).'" title="'.s($title).'" style="border:0px" /></a>';
+ $str = '<a href="view.php?d='.$this->field->dataid.'&rid='.$recordid.'"><img src="'.$src.'" alt="'.s($alt).'" title="'.s($title).'" class="list_picture"/></a>';
} else {
$src = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/mod_data/content/'.$content->id.'/'.$content->content);
$width = $this->field->param1 ? ' width="'.s($this->field->param1).'" ':' ';
$height = $this->field->param2 ? ' height="'.s($this->field->param2).'" ':' ';
- $str = '<a href="'.$src.'"><img '.$width.$height.' src="'.$src.'" alt="'.s($alt).'" title="'.s($title).'" style="border:0px" /></a>';
+ $str = '<a href="'.$src.'"><img '.$width.$height.' src="'.$src.'" alt="'.s($alt).'" title="'.s($title).'" class="list_picture"/></a>';
}
return $str;
<td class="c0"><label for="param1">
<?php echo get_string('fieldwidthsingleview', 'data');?></label></td>
<td class="c1">
- <input style="width:70px;" type="text" name="param1" id="param1" value="<?php if (!empty($this->field->param1)) p($this->field->param1); ?>" />
+ <input class="picturefieldsize" type="text" name="param1" id="param1" value="<?php if (!empty($this->field->param1)) p($this->field->param1); ?>" />
</td>
</tr>
<tr>
<td class="c0"><label for="param2">
<?php echo get_string('fieldheightsingleview', 'data');?></label></td>
<td class="c1">
- <input style="width:70px;" type="text" name="param2" id="param2" value="<?php if (!empty($this->field->param2)) p($this->field->param2); ?>" />
+ <input class="picturefieldsize" type="text" name="param2" id="param2" value="<?php if (!empty($this->field->param2)) p($this->field->param2); ?>" />
</td>
</tr>
<tr>
<td class="c0"><label for="param4">
<?php echo get_string('fieldwidthlistview', 'data');?></label></td>
- <td class="c1"><input style="width:70px;" type="text" name="param4" id="param4" value="<?php if (!empty($this->field->param4)) p($this->field->param4); ?>" />
+ <td class="c1"><input class="picturefieldsize" type="text" name="param4" id="param4" value="<?php if (!empty($this->field->param4)) p($this->field->param4); ?>" />
</td>
</tr>
<tr>
<td class="c0"><label for="param5">
<?php echo get_string('fieldheightlistview', 'data');?></label></td>
<td class="c1">
- <input style="width:70px;" type="text" name="param5" id="param5" value="<?php if (!empty($this->field->param5)) p($this->field->param5); ?>" />
+ <input class="picturefieldsize" type="text" name="param5" id="param5" value="<?php if (!empty($this->field->param5)) p($this->field->param5); ?>" />
</td>
</tr>
<tr>
</tr>
<tr>
<td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
- <td class="c1"><textarea style="width:300px; height:150px;" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
+ <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
</tr>
</table>
<td class="c0"><label for="param2">
<?php echo get_string('fieldwidth', 'data'); ?></label></td>
<td class="c1">
- <input style="width:50px;" type="text" name="param2" id="param2" value=
+ <input class="textareafieldsize" type="text" name="param2" id="param2" value=
<?php
if (empty($this->field->param2)) {
echo('"60"');
<td class="c0"><label for="param3">
<?php echo get_string('fieldheight', 'data'); ?></label></td>
<td class="c1">
- <input style="width:50px;" type="text" name="param3" id="param3" value=
+ <input class="textareafieldsize" type="text" name="param3" id="param3" value=
<?php
if (empty($this->field->param3)) {
echo('"35"');
$str = '<div title="'.s($this->field->description).'">';
$str .= '<label class="accesshide" for="field_'.$this->field->id.'">'.$this->field->description.'</label>';
- $str .= '<input style="width:300px;" type="text" name="field_'.$this->field->id.'" id="field_'.$this->field->id.'" value="'.s($content).'" />';
+ $str .= '<input class="basefieldinput" type="text" name="field_'.$this->field->id.'" id="field_'.$this->field->id.'" value="'.s($content).'" />';
$str .= '</div>';
return $str;
$pagesizes = array(2=>2,3=>3,4=>4,5=>5,6=>6,7=>7,8=>8,9=>9,10=>10,15=>15,
20=>20,30=>30,40=>40,50=>50,100=>100,200=>200,300=>300,400=>400,500=>500,1000=>1000);
echo html_writer::select($pagesizes, 'perpage', $perpage, false, array('id'=>'pref_perpage'));
- echo '<div id="reg_search" style="display: ';
+
if ($advanced) {
- echo 'none';
- }
- else {
- echo 'inline';
+ $regsearchclass = 'search_none';
+ $advancedsearchclass = 'search_inline';
+ } else {
+ $regsearchclass = 'search_inline';
+ $advancedsearchclass = 'search_none';
}
- echo ';" > <label for="pref_search">'.get_string('search').'</label> <input type="text" size="16" name="search" id= "pref_search" value="'.s($search).'" /></div>';
+ echo '<div id="reg_search" class="' . $regsearchclass . '" > ';
+ echo '<label for="pref_search">'.get_string('search').'</label> <input type="text" size="16" name="search" id= "pref_search" value="'.s($search).'" /></div>';
echo ' <label for="pref_sortby">'.get_string('sortby').'</label> ';
// foreach field, print the option
echo '<select name="sort" id="pref_sortby">';
echo ' <input type="submit" value="'.get_string('savesettings','data').'" />';
echo '<br />';
- echo '<div class="dataadvancedsearch" id="data_adv_form" style="display: ';
-
- if ($advanced) {
- echo 'inline';
- }
- else {
- echo 'none';
- }
- echo ';margin-left:auto;margin-right:auto;" >';
+ echo '<div class="' . $advancedsearchclass . '" id="data_adv_form">';
echo '<table class="boxaligncenter">';
// print ASC or DESC
echo format_text($newtext, FORMAT_HTML, $options);
echo '</td></tr>';
- echo '<tr><td colspan="4" style="text-align: center;"><br/><input type="submit" value="'.get_string('savesettings','data').'" /><input type="submit" name="resetadv" value="'.get_string('resetsettings','data').'" /></td></tr>';
+ echo '<tr><td colspan="4"><br/><input type="submit" value="'.get_string('savesettings','data').'" /><input type="submit" name="resetadv" value="'.get_string('resetsettings','data').'" /></td></tr>';
echo '</table>';
echo '</div>';
echo '</div>';
.path-mod-data-field .c0,
#page-mod-data-view #sortsearch .c0 {text-align: right;}
#page-mod-data-view .approve img.icon {width:34px;height:34px;}
+#page-mod-data-view img.list_picture {
+ border:0px;
+}
+#page-mod-data-view div.search_none {
+ display: none;
+}
+#page-mod-data-view div.search_inline,
+#page-mod-data-view form#latlongfieldbrowse {
+ display: inline;
+}
+#page-mod-data-view div#data_adv_form {
+ margin-left:auto;
+ margin-right:auto;
+}
+
+#page-mod-data-edit .basefieldinput {
+ width:300px;
+}
/** Styles for preset.php **/
#page-mod-data-preset .presetmapping table {text-align: left;margin-left: auto;margin-right: auto;}
.path-mod-data-field .sortdefault select {margin-left: 1em;}
.path-mod-data-field .fieldname,
.path-mod-data-field .fielddescription {width:300px;}
+.path-mod-data-field textarea.optionstextarea {
+ width:300px;
+ height:150px;
+}
+.path-mod-data-field input.textareafieldsize {
+ width:50px;
+}
+.path-mod-data-field input.picturefieldsize {
+ width:70px;
+}
/** UI Usability Hacks **/
#page-mod-data-export #notice span {padding:0 10px;}
.mod-data-default-template .template-token {text-align:left;}
.mod-data-default-template .controls {text-align:center;}
.mod-data-default-template searchcontrols {text-align:right;}
+#page-mod-data-templates td.save_template,
+#page-mod-data-templates .template_heading {
+ text-align:center;
+}
.dir-rtl .mod-data-default-template .template-field {text-align:left;}
.dir-rtl .mod-data-default-template .template-token {text-align:right;}
}
}
} else {
- echo '<div class="littleintro" style="text-align:center">'.get_string('header'.$mode,'data').'</div>';
+ echo '<div class="template_heading">'.get_string('header'.$mode,'data').'</div>';
}
/// If everything is empty then generate some defaults
echo '<tr>';
echo '<td> </td>';
echo '<td>';
- echo '<div style="text-align:center"><label for="edit-listtemplateheader">'.get_string('header','data').'</label></div>';
+ echo '<div class="template_heading"><label for="edit-listtemplateheader">'.get_string('header','data').'</label></div>';
$field = 'listtemplateheader';
$editor->use_editor($field, $options);
echo '<td valign="top">';
if ($mode == 'listtemplate'){
- echo '<div style="text-align:center"><label for="edit-template">'.get_string('multientry','data').'</label></div>';
+ echo '<div class="template_heading"><label for="edit-template">'.get_string('multientry','data').'</label></div>';
} else {
- echo '<div style="text-align:center"><label for="edit-template">'.get_string($mode,'data').'</label></div>';
+ echo '<div class="template_heading"><label for="edit-template">'.get_string($mode,'data').'</label></div>';
}
$field = 'template';
echo '<tr>';
echo '<td> </td>';
echo '<td>';
- echo '<div style="text-align:center"><label for="edit-listtemplatefooter">'.get_string('footer','data').'</label></div>';
+ echo '<div class="template_heading"><label for="edit-listtemplatefooter">'.get_string('footer','data').'</label></div>';
$field = 'listtemplatefooter';
$editor->use_editor($field, $options);
echo '<tr>';
echo '<td> </td>';
echo '<td>';
- echo '<div style="text-align:center"><label for="edit-rsstitletemplate">'.get_string('rsstitletemplate','data').'</label></div>';
+ echo '<div class="template_heading"><label for="edit-rsstitletemplate">'.get_string('rsstitletemplate','data').'</label></div>';
$field = 'rsstitletemplate';
$editor->use_editor($field, $options);
echo '</tr>';
}
-echo '<tr><td style="text-align:center" colspan="2">';
+echo '<tr><td class="save_template" colspan="2">';
echo '<input type="submit" value="'.get_string('savetemplate','data').'" /> ';
echo '</td></tr></table>';
if (empty($dir['subdirs']) and empty($dir['files'])) {
return '';
}
- $browser = get_file_browser();
$result = '<ul>';
foreach ($dir['subdirs'] as $subdir) {
$image = $this->output->pix_icon(file_folder_icon(24), $subdir['dirname'], 'moodle');
- $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')). html_writer::tag('span', s($subdir['dirname']), array('class' => 'fp-filename'));
+ $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')).
+ html_writer::tag('span', s($subdir['dirname']), array('class' => 'fp-filename'));
$filename = html_writer::tag('div', $filename, array('class' => 'fp-filename-icon'));
$result .= html_writer::tag('li', $filename. $this->htmllize_tree($tree, $subdir));
}
foreach ($dir['files'] as $file) {
- $fileinfo = $browser->get_file_info($tree->context, $file->get_component(),
- $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
- $url = $fileinfo->get_url(true);
$filename = $file->get_filename();
- if ($imageinfo = $fileinfo->get_imageinfo()) {
- $fileurl = new moodle_url($fileinfo->get_url());
- $image = $fileurl->out(false, array('preview' => 'tinyicon', 'oid' => $fileinfo->get_timemodified()));
+ $url = moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(),
+ $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $filename, false);
+ if (file_extension_in_typegroup($filename, 'web_image')) {
+ $image = $url->out(false, array('preview' => 'tinyicon', 'oid' => $file->get_timemodified()));
$image = html_writer::empty_tag('img', array('src' => $image));
} else {
$image = $this->output->pix_icon(file_file_icon($file, 24), $filename, 'moodle');
}
- $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')). html_writer::tag('span', $filename, array('class' => 'fp-filename'));
- $filename = html_writer::tag('span', html_writer::link($url, $filename), array('class' => 'fp-filename-icon'));
+ $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')).
+ html_writer::tag('span', $filename, array('class' => 'fp-filename'));
+ $filename = html_writer::tag('span',
+ html_writer::link($url->out(false, array('forcedownload' => 1)), $filename),
+ array('class' => 'fp-filename-icon'));
$result .= html_writer::tag('li', $filename);
}
$result .= '</ul>';
$fs = get_file_storage();
$this->dir = $fs->get_area_tree($this->context->id, 'mod_folder', 'content', 0);
}
-}
\ No newline at end of file
+}
return new forum_file_info_container($browser, $course, $cm, $context, $areas, $filearea);
}
- if (!$post = $DB->get_record('forum_posts', array('id' => $itemid))) {
+ static $cached = array();
+ // $cached will store last retrieved post, discussion and forum. To make sure that the cache
+ // is cleared between unit tests we check if this is the same session
+ if (!isset($cached['sesskey']) || $cached['sesskey'] != sesskey()) {
+ $cached = array('sesskey' => sesskey());
+ }
+
+ if (isset($cached['post']) && $cached['post']->id == $itemid) {
+ $post = $cached['post'];
+ } else if ($post = $DB->get_record('forum_posts', array('id' => $itemid))) {
+ $cached['post'] = $post;
+ } else {
return null;
}
- if (!$discussion = $DB->get_record('forum_discussions', array('id' => $post->discussion))) {
+ if (isset($cached['discussion']) && $cached['discussion']->id == $post->discussion) {
+ $discussion = $cached['discussion'];
+ } else if ($discussion = $DB->get_record('forum_discussions', array('id' => $post->discussion))) {
+ $cached['discussion'] = $discussion;
+ } else {
return null;
}
- if (!$forum = $DB->get_record('forum', array('id' => $cm->instance))) {
+ if (isset($cached['forum']) && $cached['forum']->id == $cm->instance) {
+ $forum = $cached['forum'];
+ } else if ($forum = $DB->get_record('forum', array('id' => $cm->instance))) {
+ $cached['forum'] = $forum;
+ } else {
return null;
}
return null;
}
// Make sure groups allow this user to see this file
- if ($discussion->groupid > 0) {
+ if ($discussion->groupid > 0 && !has_capability('moodle/site:accessallgroups', $context)) {
$groupmode = groups_get_activity_groupmode($cm, $course);
- if ($groupmode == SEPARATEGROUPS) {
- if (!groups_is_member($discussion->groupid) and !has_capability('moodle/site:accessallgroups', $context)) {
- return null;
- }
+ if ($groupmode == SEPARATEGROUPS && !groups_is_member($discussion->groupid)) {
+ return null;
}
}
$addopen = empty($current->id) || !empty($current->timeopen);
$addclose = empty($current->id) || !empty($current->timeclose);
+ if (!empty($quiz->coursemodule)) {
+ $cmid = $quiz->coursemodule;
+ } else {
+ $cmid = get_coursemodule_from_instance('quiz', $quiz->id, $quiz->course)->id;
+ }
+
$event = new stdClass();
- $event->description = format_module_intro('quiz', $quiz, $quiz->coursemodule);
+ $event->description = format_module_intro('quiz', $quiz, $cmid);
// Events module won't show user events when the courseid is nonzero.
$event->courseid = ($userid) ? 0 : $quiz->course;
$event->groupid = $groupid;
// Updating dates - shift may be negative too.
if ($data->timeshift) {
+ $DB->execute("UPDATE {quiz_overrides}
+ SET timeopen = timeopen + ?
+ WHERE quiz IN (SELECT id FROM {quiz} WHERE course = ?)
+ AND timeopen <> 0", array($data->timeshift, $data->courseid));
+ $DB->execute("UPDATE {quiz_overrides}
+ SET timeclose = timeclose + ?
+ WHERE quiz IN (SELECT id FROM {quiz} WHERE course = ?)
+ AND timeclose <> 0", array($data->timeshift, $data->courseid));
+
shift_course_mod_dates('quiz', array('timeopen', 'timeclose'),
$data->timeshift, $data->courseid);
+
$status[] = array(
'component' => $componentstr,
'item' => get_string('openclosedatesupdated', 'quiz'),
#page-mod-quiz-edit h2.main{display:inline;padding-right:1em;clear:left;}
#categoryquestions .r1 {background: #e4e4e4;}
+#categoryquestions .r1.highlight {background-color:#AAFFAA;}
#categoryquestions .header {text-align: center;padding: 0 2px;border: 0 none;}
#categoryquestions th.modifiername .sorters,
#categoryquestions th.creatorname .sorters {font-weight: normal;font-size: 0.8em;}
return $DB->count_records_select('scorm_scoes', "scorm = ? $sqlorganization AND ".$DB->sql_isnotempty('scorm_scoes', 'launch', false, true), $params);
}
+/**
+ * Returns the last attempt used - if no attempts yet, returns 1 for first attempt
+ *
+ * @param int $scormid the id of the scorm.
+ * @param int $userid the id of the user.
+ *
+ * @return int The attempt number to use.
+ */
function scorm_get_last_attempt($scormid, $userid) {
global $DB;
/// Find the last attempt number for the given user id and scorm id
- if ($lastattempt = $DB->get_record('scorm_scoes_track', array('userid'=>$userid, 'scormid'=>$scormid), 'max(attempt) as a')) {
- if (empty($lastattempt->a)) {
- return '1';
- } else {
- return $lastattempt->a;
- }
+ $sql = "SELECT MAX(attempt)
+ FROM {scorm_scoes_track}
+ WHERE userid = ? AND scormid = ?";
+ $lastattempt = $DB->get_field_sql($sql, array($userid, $scormid));
+ if (empty($lastattempt)) {
+ return '1';
} else {
- return false;
+ return $lastattempt;
}
}
+/**
+ * Returns the last completed attempt used - if no completed attempts yet, returns 1 for first attempt
+ *
+ * @param int $scormid the id of the scorm.
+ * @param int $userid the id of the user.
+ *
+ * @return int The attempt number to use.
+ */
function scorm_get_last_completed_attempt($scormid, $userid) {
global $DB;
- /// Find the last attempt number for the given user id and scorm id
- if ($lastattempt = $DB->get_record_select('scorm_scoes_track', "userid = ? AND scormid = ? AND (value='completed' OR value='passed')", array($userid, $scormid), 'max(attempt) as a')) {
- if (empty($lastattempt->a)) {
- return '1';
- } else {
- return $lastattempt->a;
- }
+ /// Find the last completed attempt number for the given user id and scorm id
+ $sql = "SELECT MAX(attempt)
+ FROM {scorm_scoes_track}
+ WHERE userid = ? AND scormid = ?
+ AND (value='completed' OR value='passed')";
+ $lastattempt = $DB->get_field_sql($sql, array($userid, $scormid));
+ if (empty($lastattempt)) {
+ return '1';
} else {
- return false;
+ return $lastattempt;
}
}
M.mod_scormform = {};
M.mod_scormform.init = function(Y) {
- var scormform = Y.one('#scormviewform');
+ var scormform = document.getElementById('scormviewform');
var cwidth = scormplayerdata.cwidth;
var cheight = scormplayerdata.cheight;
var poptions = scormplayerdata.popupoptions;
}
poptions = poptions+',width='+cwidth+',height='+cheight;
}
- scormform.setAttribute('onsubmit', "window.open('','Popup','"+poptions+"'); this.target='Popup';");
+ scormform.onsubmit = function() {window.open('', 'Popup', poptions); this.target='Popup';};
}
/**
* Converts <ELEMENT> into <workshopform_comments_dimension>
+ *
+ * @param array $data legacy element data
+ * @param array $raw raw element data
+ *
+ * @return array converted
*/
- public function process_legacy_element($data, $raw) {
+ public function process_legacy_element(array $data, array $raw) {
// prepare a fake record and re-use the upgrade logic
$fakerecord = (object)$data;
$converted = (array)workshopform_comments_upgrade_element($fakerecord, 12345678);
/**
* Converts <ELEMENT> into <workshopform_numerrors_dimension> and stores it for later writing
*
+ * @param array $data legacy element data
+ * @param array $raw raw element data
+ *
* @return array to be written to workshop.xml
*/
- public function process_legacy_element($data, $raw) {
+ public function process_legacy_element(array $data, array $raw) {
$workshop = $this->parenthandler->get_current_workshop();
/**
* Processes one <ELEMENT>
+ *
+ * @param array $data legacy element data
+ * @param array $raw raw element data
*/
- public function process_legacy_element($data, $raw) {
+ public function process_legacy_element(array $data, array $raw) {
$this->elements[] = $data;
$this->rubrics[$data['id']] = array();
}
/// Each section adds html to be displayed as part of this list item
$questionbankurl = new moodle_url("/question/edit.php", ($this->parentlist->pageurl->params() + array('category'=>"$category->id,$category->contextid")));
$catediturl = $this->parentlist->pageurl->out(true, array('edit' => $this->id));
- $item = "<b><a title=\"{$str->edit}\" href=\"$catediturl\">".$category->name ."</a></b> <a title=\"$editqestions\" href=\"$questionbankurl\">".'('.$category->questioncount.')</a>';
+ $item = "<b><a title=\"{$str->edit}\" href=\"$catediturl\">" .
+ format_string($category->name, true, array('context' => $this->parentlist->context)) .
+ "</a></b> <a title=\"$editqestions\" href=\"$questionbankurl\">".'('.$category->questioncount.')</a>';
- $item .= ' '. $category->info;
+ $item .= ' ' . format_text($category->info, $category->infoformat,
+ array('context' => $this->parentlist->context, 'noclean' => true));
// don't allow delete if this is the last category in this context.
if (count($this->parentlist->records) != 1) {
$string['defaultname'] = 'Imported question {$a}';
$string['errormanifest'] = 'Error while parsing the IMS manifest document';
$string['importnotext'] = 'Missing question text in XML file';
-$string['filenothandled'] = 'This archive contains reference to a file material {$a} wich is not currently handled by import';
+$string['filenothandled'] = 'This archive contains reference to a file material {$a} which is not currently handled by import';
$string['imagenotfound'] = 'Image file with path {$a} was not found in the import.';
$string['notenoughtsubans'] = 'Unable to import matching question \'{$a}\' because a matching question must comprise at least two questions and three answers.';
$string['pluginname'] = 'Blackboard V6+';
$string['pluginname_help'] = 'Blackboard V6+ format enables questions saved in all Blackboard export formats to be imported via a dat or zip file. For zip files, images import is supported.';
-$string['unhandledpresblock'] = 'Unhandled presentation bloc';
+$string['unhandledpresblock'] = 'Unhandled presentation block';
$string['unknownorunhandledtype'] = 'Unknown or unhandled question type: {$a}';
display: inline;
background: #FFF3BF;
}
+.que.calculatedmulti .answer .specificfeedback script {
+ display: none;
+}
.que.calculatedmulti .answer div.r0,
.que.calculatedmulti .answer div.r1 {
padding: 0.3em;
.que.match .feedback .rightanswer * {
display: inline;
}
+.que.match .feedback .rightanswer script {
+ display: none;
+}
display: inline;
background: #FFF3BF;
}
+.que.multianswer .answer .specificfeedback script {
+ display: none;
+}
.que.multianswer .answer div.r0,
.que.multianswer .answer div.r1 {
padding: 0.3em;
display: inline;
background: #FFF3BF;
}
+.que.multichoice .answer .specificfeedback script {
+ display: none;
+}
.que.multichoice .answer div.r0,
.que.multichoice .answer div.r1 {
padding: 0.3em;
}
+.que.multichoice .feedback .rightanswer * {
+ display: inline;
+}
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->dirroot.'/backup/lib.php');
+// Required for constants in backup_cron_automated_helper
+require_once($CFG->dirroot.'/backup/util/helper/backup_cron_helper.class.php');
+
admin_externalpage_setup('reportbackups', '', null, '', array('pagelayout'=>'report'));
$table = new html_table;
$strok = get_string("ok");
$strunfinished = get_string("unfinished");
$strskipped = get_string("skipped");
+$strwarning = get_string("warning");
list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
$sql = "SELECT bc.*, c.fullname $select
context_instance_preload($backuprow);
// Prepare a cell to display the status of the entry
- if ($backuprow->laststatus == 1) {
+ if ($backuprow->laststatus == backup_cron_automated_helper::BACKUP_STATUS_OK) {
$status = $strok;
$statusclass = 'backup-ok'; // Green
- } else if ($backuprow->laststatus == 2) {
+ } else if ($backuprow->laststatus == backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED) {
$status = $strunfinished;
$statusclass = 'backup-unfinished'; // Red
- } else if ($backuprow->laststatus == 3) {
+ } else if ($backuprow->laststatus == backup_cron_automated_helper::BACKUP_STATUS_SKIPPED) {
$status = $strskipped;
$statusclass = 'backup-skipped'; // Green
+ } else if ($backuprow->laststatus == backup_cron_automated_helper::BACKUP_STATUS_WARNING) {
+ $status = $strwarning;
+ $statusclass = 'backup-warning'; // Orange
} else {
$status = $strerror;
$statusclass = 'backup-error'; // Red
*/
function report_stats_extend_navigation_course($navigation, $course, $context) {
global $CFG;
- if (!empty($CFG->enablestats)) {
+ if (empty($CFG->enablestats)) {
return;
}
if (has_capability('report/stats:view', $context)) {
*/
function report_stats_extend_navigation_user($navigation, $user, $course) {
global $CFG;
- if (!empty($CFG->enablestats)) {
+ if (empty($CFG->enablestats)) {
return;
}
if (report_stats_can_access_user_report($user, $course)) {
defined('MOODLE_INTERNAL') || die;
// just a link to course report
-$ADMIN->add('reports', new admin_externalpage('reportstats', get_string('pluginname', 'report_stats'), "$CFG->wwwroot/report/stats/index.php", 'report/stats:view'));
+$ADMIN->add('reports', new admin_externalpage('reportstats', get_string('pluginname', 'report_stats'), "$CFG->wwwroot/report/stats/index.php", 'report/stats:view', empty($CFG->enablestats)));
// no report settings
$settings = null;
$string['cachelimit'] = 'Cache limit';
$string['cachelimit_info'] = 'Enter the maximum size of files (in bytes) to be cached on server for Dropbox aliases/shortcuts. Cached files will be served when the source is no longer available. Empty value or zero mean caching of all files regardless of size.';
$string['dropbox:view'] = 'View a Dropbox folder';
+$string['logoutdesc'] = '(Logout when you finish using Dropbox)';
$list['manage'] = 'https://www.dropbox.com/home';
$list['dynload'] = true;
$list['nosearch'] = true;
+ $list['logouturl'] = 'https://www.dropbox.com/logout';
+ $list['message'] = get_string('logoutdesc', 'repository_dropbox');
// process breadcrumb trail
$list['path'] = array(
array('name'=>get_string('dropbox', 'repository_dropbox'), 'path'=>'/')
this.active_repo.norefresh = (data.login || data.norefresh); // this is either login form or 'norefresh' attribute set
this.active_repo.nologin = (data.login || data.nologin); // this is either login form or 'nologin' attribute is set
this.active_repo.logouttext = data.logouttext?data.logouttext:null;
+ this.active_repo.logouturl = (data.logouturl || '');
+ this.active_repo.message = (data.message || '');
this.active_repo.help = data.help?data.help:null;
this.active_repo.manage = data.manage?data.manage:null;
this.print_header();
callback: this.display_response
}, true);
}
+ if (this.active_repo.logouturl) {
+ window.open(this.active_repo.logouturl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes');
+ }
}, this);
toolbar.one('.fp-tb-refresh').one('a,button').on('click', function(e) {
e.preventDefault();
callback: this.display_response
}, true);
}
- }, this);
+ }, this);
// it does not matter what kind of element is .fp-tb-manage, we create a dummy <a>
// element and use it to open url on click event
// help url
enable_tb_control(toolbar.one('.fp-tb-help'), r.help);
Y.one('#fp-tb-help-'+client_id+'-link').set('href', r.help);
+
+ // message
+ if (toolbar.one('.fp-tb-message')) {
+ enable_tb_control(toolbar.one('.fp-tb-message'), r.message);
+ toolbar.one('.fp-tb-message').setContent(r.message);
+ }
},
print_path: function() {
if (!this.pathbar) {
private $flickr;
public $photos;
+ /**
+ * Stores sizes of images to prevent multiple API call
+ */
+ static private $sizes = array();
+
/**
*
* @param int $repositoryid
* @return string
*/
private function build_photo_url($photoid) {
- $result = $this->flickr->photos_getSizes($photoid);
- $url = '';
- if(!empty($result[4])) {
- $url = $result[4]['source'];
- } elseif(!empty($result[3])) {
- $url = $result[3]['source'];
- } elseif(!empty($result[2])) {
- $url = $result[2]['source'];
+ $bestsize = $this->get_best_size($photoid);
+ if (!isset($bestsize['source'])) {
+ throw new repository_exception('cannotdownload', 'repository');
+ }
+ return $bestsize['source'];
+ }
+
+ /**
+ * Returns the best size for a photo
+ *
+ * @param string $photoid the photo identifier
+ * @return array of information provided by the API
+ */
+ protected function get_best_size($photoid) {
+ if (!isset(self::$sizes[$photoid])) {
+ // Sizes are returned from smallest to greatest.
+ self::$sizes[$photoid] = $this->flickr->photos_getSizes($photoid);
+ }
+ $sizes = self::$sizes[$photoid];
+ $bestsize = array();
+ if (is_array($sizes)) {
+ while ($bestsize = array_pop($sizes)) {
+ // Make sure the source is set. Exit the loop if found.
+ if (isset($bestsize['source'])) {
+ break;
+ }
+ }
}
- return $url;
+ return $bestsize;
}
public function get_link($photoid) {
private $flickr;
public $photos;
+ /**
+ * Stores sizes of images to prevent multiple API call
+ */
+ static private $sizes = array();
+
/**
* constructor method
*
public function license4moodle ($license_id) {
$license = array(
+ '0' => 'allrightsreserved',
'1' => 'cc-nc-sa',
'2' => 'cc-nc',
'3' => 'cc-nc-nd',
'4' => 'cc',
'5' => 'cc-sa',
'6' => 'cc-nd',
- '7' => 'allrightsreserved'
+ '7' => 'other'
);
return $license[$license_id];
}
* @return string
*/
private function build_photo_url($photoid) {
- $result = $this->flickr->photos_getSizes($photoid);
- $url = '';
- if(!empty($result[4])) {
- $url = $result[4]['source'];
- } elseif(!empty($result[3])) {
- $url = $result[3]['source'];
- } elseif(!empty($result[2])) {
- $url = $result[2]['source'];
+ $bestsize = $this->get_best_size($photoid);
+ if (!isset($bestsize['source'])) {
+ throw new repository_exception('cannotdownload', 'repository');
+ }
+ return $bestsize['source'];
+ }
+
+ /**
+ * Returns the best size for a photo
+ *
+ * @param string $photoid the photo identifier
+ * @return array of information provided by the API
+ */
+ protected function get_best_size($photoid) {
+ if (!isset(self::$sizes[$photoid])) {
+ // Sizes are returned from smallest to greatest.
+ self::$sizes[$photoid] = $this->flickr->photos_getSizes($photoid);
+ }
+ $sizes = self::$sizes[$photoid];
+ $bestsize = array();
+ if (is_array($sizes)) {
+ while ($bestsize = array_pop($sizes)) {
+ // Make sure the source is set. Exit the loop if found.
+ if (isset($bestsize['source'])) {
+ break;
+ }
+ }
}
- return $url;
+ return $bestsize;
}
public function get_link($photoid) {
$author = $info['owner']['username'];
}
$copyright = get_string('author', 'repository') . ': ' . $author;
- $result = $this->flickr->photos_getSizes($photoid);
- // download link
- $source = '';
- // flickr photo page
- $url = '';
- if (!empty($result[4])) {
- $source = $result[4]['source'];
- $url = $result[4]['url'];
- } elseif(!empty($result[3])) {
- $source = $result[3]['source'];
- $url = $result[3]['url'];
- } elseif(!empty($result[2])) {
- $source = $result[2]['source'];
- $url = $result[2]['url'];
+
+ // If we can read the original secret, it means that we have access to the original picture.
+ if (isset($info['originalsecret'])) {
+ $source = $this->flickr->buildPhotoURL($info, 'original');
+ } else {
+ $source = $this->build_photo_url($photoid);
}
+
$result = parent::get_file($source, $file);
$path = $result['path'];
+
if (!empty($this->usewatermarks)) {
$img = new moodle_image($path);
$img->watermark($copyright, array(10,10), array('ttf'=>true, 'fontsize'=>12))->saveas($path);
}
- return array('path'=>$path, 'url'=>$url, 'author'=>$info['owner']['realname'], 'license'=>$this->license4moodle($info['license']));
+ return array('path'=>$path, 'author'=>$info['owner']['realname'], 'license'=>$this->license4moodle($info['license']));
}
/**
}
public function get_file($url, $file = '') {
+ if (empty($url)) {
+ throw new repository_exception('cannotdownload', 'repository');
+ }
$gdocs = new google_docs($this->googleoauth);
-
$path = $this->prepare_file($file);
return $gdocs->download_file($url, $path, self::GETFILE_TIMEOUT);
}
$types = repository::get_editable_types($context);
foreach ($types as $type) {
if (!empty($type) && $type->get_visible()) {
+ // If the user does not have the permission to view the repository, it won't be displayed in
+ // the list of instances. Hiding the link to create new instances will prevent the
+ // user from creating them without being able to find them afterwards, which looks like a bug.
+ if (!has_capability('repository/'.$type->get_typename().':view', $context)) {
+ continue;
+ }
$instanceoptionnames = repository::static_function($type->get_typename(), 'get_instance_option_names');
if (!empty($instanceoptionnames)) {
$baseurl->param('new', $type->get_typename());
$type = repository::get_type_by_id($instance->options['typeid']);
}
-if (isset($type) && !$type->get_visible()) {
- print_error('typenotvisible', 'repository', $baseurl);
-}
-
-if (isset($type) && !$type->get_contextvisibility($context)) {
- print_error('usercontextrepositorydisabled', 'repository', $baseurl);
+if (isset($type)) {
+ if (!$type->get_visible()) {
+ print_error('typenotvisible', 'repository', $baseurl);
+ }
+ // Prevents the user from creating/editing an instance if the repository is not visible in
+ // this context OR if the user does not have the capability to view this repository in this context.
+ $canviewrepository = has_capability('repository/'.$type->get_typename().':view', $context);
+ if (!$type->get_contextvisibility($context) || !$canviewrepository) {
+ print_error('usercontextrepositorydisabled', 'repository', $baseurl);
+ }
}
/// Create navigation links
background-color: #34637f;
color: #fff;
}
+.ie7 select { /* fixes compatibility view */
+ background-color: #eee;
+ color: #036;
+}
#loginbtn, input, button, select {
cursor: pointer;
margin-left: 5px;
.file-picker button,
.file-picker textarea {
background-color: #EEE;
-}
\ No newline at end of file
+}
padding-top: 10px;
}
-.forumpost .content .shortenedpost a,
-.forumpost .content p {
+.forumpost .content .shortenedpost a {
margin: 0 10px;
padding: 0;
}
#page-admin-report-backups-index .backup-unfinished {color: #f00000;}
#page-admin-report-backups-index .backup-skipped,
#page-admin-report-backups-index .backup-ok {color: #006400;}
+#page-admin-report-backups-index .backup-warning {color: #ff9900;}
#page-admin-qbehaviours .disabled {color: gray;}
#page-admin-qbehaviours th {white-space: normal;}
} else {
$logourl = $OUTPUT->pix_url('logo', 'theme');
}
+if (strtolower(substr($logourl, 0, 4)) != 'http') {
+ $logourl = $CFG->wwwroot.'/'.$logourl;
+}
$hasframe = !isset($PAGE->theme->settings->noframe) || !$PAGE->theme->settings->noframe;
/************************************************************************************************/
if (!empty($PAGE->theme->settings->customlogourl)) {
$logourl = $PAGE->theme->settings->customlogourl;
+ if (strtolower(substr($logourl, 0, 4)) != 'http') {
+ $logourl = $CFG->wwwroot.'/'.$logourl;
+ }
} else {
$logourl = $OUTPUT->pix_url('logo_small', 'theme');
}
/************************************************************************************************/
if (!empty($PAGE->theme->settings->customlogourl)) {
$logourl = $PAGE->theme->settings->customlogourl;
+ if (strtolower(substr($logourl, 0, 4)) != 'http') {
+ $logourl = $CFG->wwwroot.'/'.$logourl;
+ }
} else {
$logourl = $OUTPUT->pix_url('logo_small', 'theme');
}
$title = get_string('customlogourl','theme_formal_white');
$description = get_string('customlogourldesc', 'theme_formal_white');
$default = '';
- $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_URL);
+ $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_RAW); // we want it accepting ../ at the beginning. Security is not at its top but Moodle trusts admins.
$settings->add($setting);
// Custom front page site logo setting
$title = get_string('frontpagelogourl','theme_formal_white');
$description = get_string('frontpagelogourldesc', 'theme_formal_white');
$default = '';
- $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_URL);
+ $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_RAW); // we want it accepting ../ at the beginning. Security is not at its top but Moodle trusts admins.
$settings->add($setting);
// page header background colour setting
$contentfile = "$CFG->libdir/yui/$part";
}
if (!file_exists($contentfile) or !is_file($contentfile)) {
- $content .= "\n// Combo resource $part ($contentfile) not found!\n";
+ $location = '$CFG->dirroot'.preg_replace('/^'.preg_quote($CFG->dirroot, '/').'/', '', $contentfile);
+ $content .= "\n// Combo resource $part ($location) not found!\n";
continue;
}
$filecontent = file_get_contents($contentfile);
/// Next the customisable profile fields
profile_definition($mform, $userid);
- $this->add_action_buttons(false, get_string('updatemyprofile'));
+ if ($userid == -1) {
+ $btnstring = get_string('createuser');
+ } else {
+ $btnstring = get_string('updatemyprofile');
+ }
+
+ $this->add_action_buttons(false, $btnstring);
}
function definition_after_data() {
$hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
}
+if (has_capability('moodle/site:viewuseridentity', $context)) {
+ $identityfields = array_flip(explode(',', $CFG->showuseridentity));
+} else {
+ $identityfields = array();
+}
+
// Start setting up the page
$strpublicprofile = get_string('publicprofile');
print_row(get_string('city') . ':', $user->city);
}
-if (has_capability('moodle/user:viewhiddendetails', $context)) {
- if ($user->address) {
- print_row(get_string("address").":", "$user->address");
- }
- if ($user->phone1) {
- print_row(get_string("phone").":", "$user->phone1");
- }
- if ($user->phone2) {
- print_row(get_string("phone2").":", "$user->phone2");
- }
+if (isset($identityfields['address']) && $user->address) {
+ print_row(get_string("address").":", "$user->address");
+}
+
+if (isset($identityfields['phone1']) && $user->phone1) {
+ print_row(get_string("phone").":", "$user->phone1");
}
-if ($currentuser
+if (isset($identityfields['phone2']) && $user->phone2) {
+ print_row(get_string("phone2").":", "$user->phone2");
+}
+
+if (isset($identityfields['institution']) && $user->institution) {
+ print_row(get_string("institution").":", "$user->institution");
+}
+
+if (isset($identityfields['department']) && $user->department) {
+ print_row(get_string("department").":", "$user->department");
+}
+
+if (isset($identityfields['idnumber']) && $user->idnumber) {
+ print_row(get_string("idnumber").":", "$user->idnumber");
+}
+
+if (isset($identityfields['email']) and ($currentuser
or $user->maildisplay == 1
or has_capability('moodle/course:useremail', $context)
- or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER))) {
-
+ or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER)))) {
print_row(get_string("email").":", obfuscate_mailto($user->email, ''));
}
var clearbtn = Y.one('#'+this.name + '_clearbutton');
this.clearbutton = Y.Node.create('<input type="button" value="'+clearbtn.get('value')+'" />');
clearbtn.replace(Y.Node.getDOMNode(this.clearbutton));
- this.clearbutton.set('id',+this.name+"_clearbutton");
+ this.clearbutton.set('id', this.name+"_clearbutton");
this.clearbutton.on('click', this.handle_clear, this);
+ this.clearbutton.set('disabled', (this.get_search_text() == ''));
this.send_query(false);
},
defined('MOODLE_INTERNAL') || die();
-$version = 2012062501.12; // YYYYMMDD = weekly release date of this DEV branch
+$version = 2012062502.00; // YYYYMMDD = weekly release date of this DEV branch
// RR = release increments - 00 in DEV branches
// .XX = incremental changes
-$release = '2.3.1+ (Build: 20120831)'; // Human-friendly version name
+$release = '2.3.2 (Build: 20120910)'; // Human-friendly version name
$branch = '23'; // this version's branch
$maturity = MATURITY_STABLE; // this version's maturity level