Merge branch 'm23_MDL-34755' of git://github.com/danmarsden/moodle into MOODLE_23_STABLE
authorSam Hemelryk <sam@moodle.com>
Tue, 11 Sep 2012 03:02:26 +0000 (15:02 +1200)
committerSam Hemelryk <sam@moodle.com>
Tue, 11 Sep 2012 03:02:26 +0000 (15:02 +1200)
101 files changed:
admin/environment.xml
backup/moodle2/backup_custom_fields.php
backup/upgrade.txt [new file with mode: 0644]
backup/util/dbops/backup_plan_dbops.class.php
backup/util/dbops/restore_dbops.class.php
backup/util/helper/backup_cron_helper.class.php
backup/util/plan/backup_structure_step.class.php
backup/util/plan/restore_structure_step.class.php
backup/util/structure/backup_nested_element.class.php
backup/util/ui/backup_ui_stage.class.php
backup/util/ui/restore_ui_stage.class.php
blocks/completionstatus/block_completionstatus.php
blocks/completionstatus/details.php
blocks/completionstatus/lang/en/block_completionstatus.php
blog/external_blogs.php
blog/locallib.php
course/format/weeks/format.js
enrol/cohort/locallib.php
enrol/manual/yui/quickenrolment/quickenrolment.js
enrol/paypal/ipn.php
filter/mediaplugin/tests/filter_test.php
grade/edit/tree/category_form.php
grade/grading/form/guide/lib.php
grade/grading/form/guide/preview.php
install/lang/ko/install.php
install/lang/pl/install.php
install/lang/ru/install.php
lang/en/admin.php
lang/en/backup.php
lang/en/block.php
lang/en/calendar.php
lang/en/moodle.php
lib/accesslib.php
lib/blocklib.php
lib/conditionlib.php
lib/datalib.php
lib/db/upgrade.php
lib/db/upgradelib.php
lib/editor/tinymce/lang/en/editor_tinymce.php
lib/formslib.php
lib/googleapi.php
lib/medialib.php
lib/moodlelib.php
lib/pluginlib.php
lib/questionlib.php
lib/tests/moodlelib_test.php
lib/tests/pluginlib_test.php
message/lib.php
mod/assign/lib.php
mod/assign/locallib.php
mod/book/backup/moodle2/restore_book_activity_task.class.php
mod/book/lib.php
mod/book/version.php
mod/book/view.php
mod/chat/chatd.php
mod/chat/gui_sockets/chatinput.php
mod/choice/backup/moodle2/backup_choice_stepslib.php
mod/data/field/checkbox/mod.html
mod/data/field/latlong/field.class.php
mod/data/field/menu/mod.html
mod/data/field/multimenu/mod.html
mod/data/field/picture/field.class.php
mod/data/field/picture/mod.html
mod/data/field/radiobutton/mod.html
mod/data/field/textarea/mod.html
mod/data/lib.php
mod/data/styles.css
mod/data/templates.php
mod/folder/renderer.php
mod/quiz/lib.php
mod/quiz/styles.css
mod/scorm/locallib.php
mod/workshop/form/comments/backup/moodle1/lib.php
mod/workshop/form/numerrors/backup/moodle1/lib.php
mod/workshop/form/rubric/backup/moodle1/lib.php
question/category_class.php
question/format/blackboard_six/lang/en/qformat_blackboard_six.php
question/type/calculatedmulti/styles.css
question/type/match/styles.css
question/type/multianswer/styles.css
question/type/multichoice/styles.css
report/backups/index.php
report/stats/lib.php
report/stats/settings.php
repository/flickr/lib.php
repository/flickr_public/lib.php
repository/googledocs/lib.php
repository/lib.php
repository/manage_instances.php
theme/afterburner/style/afterburner_styles.css
theme/anomaly/style/general.css
theme/base/style/admin.css
theme/formal_white/layout/frontpage.php
theme/formal_white/layout/general.php
theme/formal_white/layout/report.php
theme/formal_white/settings.php
theme/yui_combo.php
user/editadvanced_form.php
user/profile.php
user/selector/module.js
version.php

index 004cab0..584a9b0 100644 (file)
         </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>
index e0ceb33..12929de 100644 (file)
@@ -96,14 +96,19 @@ class file_nested_element extends backup_nested_element {
         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);
+        }
     }
 }
 
diff --git a/backup/upgrade.txt b/backup/upgrade.txt
new file mode 100644 (file)
index 0000000..cb02095
--- /dev/null
@@ -0,0 +1,17 @@
+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
index 30714ed..0752f0d 100644 (file)
@@ -197,19 +197,19 @@ abstract class backup_plan_dbops extends backup_dbops {
     * @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:
@@ -231,7 +231,11 @@ abstract class backup_plan_dbops extends backup_dbops {
             $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'));
index 2e73e8f..fb7beb3 100644 (file)
@@ -819,10 +819,13 @@ abstract class restore_dbops {
      * @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
@@ -902,8 +905,14 @@ abstract class restore_dbops {
                 // 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
@@ -960,6 +969,7 @@ abstract class restore_dbops {
             }
         }
         $rs->close();
+        return $results;
     }
 
     /**
index b6d81ab..f7c6bc1 100644 (file)
@@ -46,6 +46,8 @@ abstract class backup_cron_automated_helper {
     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;
@@ -139,7 +141,7 @@ abstract class backup_cron_automated_helper {
                     $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);
@@ -160,7 +162,7 @@ abstract class backup_cron_automated_helper {
                         $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);
@@ -169,7 +171,7 @@ abstract class backup_cron_automated_helper {
 
                         $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);
@@ -188,17 +190,18 @@ abstract class backup_cron_automated_helper {
             $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) {
@@ -261,6 +264,7 @@ abstract class backup_cron_automated_helper {
             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');
@@ -334,7 +338,7 @@ abstract class backup_cron_automated_helper {
      */
     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);
 
@@ -369,6 +373,7 @@ abstract class backup_cron_automated_helper {
 
             $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;
@@ -377,8 +382,10 @@ abstract class backup_cron_automated_helper {
             }
             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();
                 }
             }
@@ -387,7 +394,7 @@ abstract class backup_cron_automated_helper {
             $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();
@@ -396,6 +403,30 @@ abstract class backup_cron_automated_helper {
         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.
@@ -530,18 +561,7 @@ abstract class backup_cron_automated_helper {
         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
index f62fee9..964dd3f 100644 (file)
@@ -94,11 +94,22 @@ abstract class backup_structure_step extends backup_step {
         // 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;
     }
 
     /**
index 4b0ff58..b6c0ead 100644 (file)
@@ -218,8 +218,14 @@ abstract class restore_structure_step extends restore_step {
      */
     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);
     }
 
     /**
index 9a47901..8557ec8 100644 (file)
@@ -37,6 +37,8 @@ class backup_nested_element extends base_nested_element implements processable {
     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.
@@ -55,8 +57,16 @@ class backup_nested_element extends base_nested_element implements processable {
         $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');
@@ -113,6 +123,69 @@ class backup_nested_element extends base_nested_element implements processable {
         $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;
index 7995561..0b90e15 100644 (file)
@@ -487,6 +487,9 @@ class backup_ui_stage_complete extends backup_ui_stage_final {
         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();
index 7e92069..34bff92 100644 (file)
@@ -772,6 +772,9 @@ class restore_ui_stage_complete extends restore_ui_stage_process {
             $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');
index 0daec7c..449e632 100644 (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
@@ -36,25 +35,27 @@ require_once($CFG->libdir.'/completionlib.php');
 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()) {
@@ -84,9 +85,9 @@ class block_completionstatus extends block_base {
         // 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;
             }
 
@@ -187,7 +188,7 @@ class block_completionstatus extends block_base {
         // Load course completion
         $params = array(
             'userid' => $USER->id,
-            'course' => $COURSE->id
+            'course' => $course->id
         );
         $ccompletion = new completion_completion($params);
 
@@ -221,7 +222,8 @@ class block_completionstatus extends block_base {
         $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;
     }
index a1ac771..84406e3 100644 (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
  */
 
-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) {
@@ -76,21 +72,13 @@ if (!$can_view) {
 // 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) {
@@ -104,6 +92,7 @@ if (!$info->is_tracked_user($user->id)) {
 ///
 /// Display page
 ///
+$PAGE->set_context(context_course::instance($course->id));
 
 // Print header
 $page = get_string('completionprogressdetails', 'block_completionstatus');
@@ -111,7 +100,7 @@ $title = format_string($course->fullname) . ': ' . $page;
 
 $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();
@@ -135,122 +124,148 @@ $coursecomplete = $info->is_course_complete($user->id);
 // 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();
index fcc965a..6658c17 100644 (file)
@@ -5,3 +5,4 @@ $string['criteriagroup'] = 'Criteria group';
 $string['firstofsecond'] = '{$a->first} of {$a->second}';
 $string['pluginname'] = 'Course completion status';
 $string['requirement'] = 'Requirement';
+$string['returntocourse'] = 'Return to course';
index 70404c2..8b1d902 100644 (file)
@@ -44,7 +44,16 @@ $message = null;
 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');
     }
 }
index 6ac8944..a0d394e 100644 (file)
@@ -405,11 +405,10 @@ class blog_entry {
      * @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());
index f410e07..28ec82a 100644 (file)
@@ -36,7 +36,7 @@ M.course.format.get_config = function() {
 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));
index 5ca237a..fb41a62 100644 (file)
@@ -51,8 +51,8 @@ class enrol_cohort_handler {
         $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;
         }
index 88c09ea..5f4efe6 100644 (file)
@@ -339,7 +339,7 @@ YUI.add('moodle-enrol_manual-quickenrolment', function(Y) {
                 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)))
index b4a6bf4..e5ec7dd 100644 (file)
@@ -34,6 +34,7 @@ require("../../config.php");
 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
@@ -89,14 +90,17 @@ if (! $plugin_instance = $DB->get_record("enrol", array("id"=>$data->instanceid,
 $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;
@@ -104,12 +108,9 @@ if (!$fp) {  /// Could not open a socket to PayPal - FAIL
 
 /// 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!
 
 
@@ -296,7 +297,6 @@ while (!feof($fp)) {
     }
 }
 
-fclose($fp);
 exit;
 
 
index 8687610..f2029ca 100644 (file)
@@ -57,7 +57,10 @@ class filter_mediaplugin_testcase extends advanced_testcase {
             '<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>',
index 5a1d8f7..c155565 100644 (file)
@@ -225,7 +225,7 @@ class edit_category_form extends moodleform {
         $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) {
@@ -238,6 +238,7 @@ class edit_category_form extends moodleform {
 
         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'));
         }
 
index 1990064..9e2c832 100644 (file)
@@ -872,10 +872,8 @@ class gradingform_guide_instance extends gradingform_instance {
             $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;
index ba8aa5d..ec2c1e1 100644 (file)
@@ -49,8 +49,6 @@ $PAGE->set_heading($title);
 
 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();
index a395a57..5dfca0c 100644 (file)
@@ -34,7 +34,8 @@ $string['admindirname'] = '관리 디렉토리';
 $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'] = '데이터베이스 명칭';
@@ -83,10 +84,10 @@ $string['phpversionhelp'] = '<p>무들은 적어도 PHP4.3.0 혹은 5.1.0. 이
 <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'] = '웹 주소';
index 28adfbc..22d60fc 100644 (file)
@@ -41,6 +41,7 @@ $string['dataroot'] = 'Katalog z danymi';
 $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.';
index bc06968..e16259e 100644 (file)
@@ -40,6 +40,7 @@ $string['databasehost'] = 'Сервер баз данных';
 $string['databasename'] = 'Название базы данных';
 $string['databasetypehead'] = 'Выберите драйвер базы данных';
 $string['dataroot'] = 'Каталог данных';
+$string['datarootpermission'] = 'Разрешения на каталоги данных';
 $string['dbprefix'] = 'Префикс имён таблиц';
 $string['dirroot'] = 'Каталог Moodle';
 $string['environmenthead'] = 'Проверка среды...';
index 26fbe3b..5d26680 100644 (file)
@@ -68,7 +68,7 @@ $string['availablelicenses'] = 'Available licences';
 $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';
index 5fde19e..e053c96 100644 (file)
@@ -163,6 +163,7 @@ $string['lockedbypermission'] = 'You don\'t have sufficient permissions to chang
 $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';
@@ -177,6 +178,7 @@ $string['restoreactivity'] = 'Restore activity';
 $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';
index c0b8f01..a685f0e 100644 (file)
@@ -37,6 +37,8 @@ $string['defaultregion'] = 'Default region';
 $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';
index dd0b7b4..3f1cc5f 100644 (file)
@@ -59,7 +59,7 @@ $string['eventduration'] = 'Duration';
 $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';
index 377b840..a5dd05a 100644 (file)
@@ -363,6 +363,7 @@ $string['createaccount'] = 'Create my new account';
 $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';
@@ -1803,6 +1804,7 @@ $string['virusfounduser'] = 'The file you have uploaded, {$a->filename}, has bee
 $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';
index c62dae4..50a9ee4 100644 (file)
@@ -6537,7 +6537,7 @@ class context_module extends context {
                     if ($withprefix){
                         $name = get_string('modulename', $cm->modname).': ';
                     }
-                    $name .= $mod->name;
+                    $name .= format_string($mod->name, true, array('context' => $this));
                 }
             }
         return $name;
index b41b67c..1986c09 100644 (file)
@@ -1114,25 +1114,65 @@ class block_manager {
      * @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;
+        }
     }
 
     /**
index 0d8b3cb..550d49a 100644 (file)
@@ -596,7 +596,7 @@ abstract class condition_info_base {
                 $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) {
@@ -747,7 +747,7 @@ abstract class condition_info_base {
                 $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);
index 99f6b91..dde0f20 100644 (file)
@@ -1764,6 +1764,11 @@ function user_accesstime_log($courseid=0) {
         return;
     }
 
+    if (isguestuser()) {
+        // Do not update guest access times/ips for performance.
+        return;
+    }
+
     if (empty($courseid)) {
         $courseid = SITEID;
     }
index dcb9f2d..83c7370 100644 (file)
@@ -949,5 +949,15 @@ function xmldb_main_upgrade($oldversion) {
         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;
 }
index 5103e0b..5247e49 100644 (file)
 
 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.
@@ -50,7 +95,7 @@ function upgrade_mysql_fix_unsigned_columns() {
     $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;
@@ -115,7 +160,7 @@ function upgrade_mysql_fix_lob_columns() {
     $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);
index 587ed66..2209291 100644 (file)
@@ -122,6 +122,7 @@ $string['advanced_dlg:about_version'] = 'Version';
 $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:';
index 31a5419..23f65cb 100644 (file)
@@ -80,26 +80,26 @@ function form_init_date_js() {
         $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;
@@ -1669,10 +1669,14 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
         $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);
                 }
@@ -1699,7 +1703,6 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
         if (is_array($this->_constantValues)) {
             $unfiltered = HTML_QuickForm::arrayMerge($unfiltered, $this->_constantValues);
         }
-
         return $unfiltered;
     }
 
index c2d529f..3ace654 100644 (file)
@@ -109,23 +109,21 @@ class google_docs {
                     $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;
index 2290060..e24f979 100644 (file)
@@ -528,8 +528,8 @@ class core_media_player_youtube extends core_media_player_external {
     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) {
@@ -564,10 +564,15 @@ OET;
     }
 
     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;
     }
 
@@ -578,7 +583,7 @@ OET;
     }
 
     public function get_embeddable_markers() {
-        return array('youtube');
+        return array('youtube.com', 'youtube-nocookie.com', 'youtu.be', 'y2u.be');
     }
 }
 
index 58a6c59..1d10587 100644 (file)
@@ -3289,6 +3289,11 @@ function get_user_key($script, $userid, $instance=null, $iprestriction=null, $va
 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();
@@ -3915,15 +3920,45 @@ function truncate_userinfo($info) {
  * 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);
 
@@ -4767,7 +4802,7 @@ function shift_course_mod_dates($modname, $fields, $timeshift, $courseid) {
     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;
     }
 
index 43de510..65e1c35 100644 (file)
@@ -1064,7 +1064,7 @@ class available_update_checker {
             return true;
         }
 
-        if ($now - $recent > HOURSECS) {
+        if ($now - $recent > 24 * HOURSECS) {
             return false;
         }
 
index a5f8822..c8aeacd 100644 (file)
@@ -1117,16 +1117,18 @@ function question_category_options($contexts, $top = false, $currentcat = 0,
 
     // 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;
                 }
             }
         }
index dd9665a..1abdf80 100644 (file)
@@ -1910,4 +1910,64 @@ class moodlelib_testcase extends advanced_testcase {
         $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);
+    }
 }
index eb29268..2ec4d0d 100644 (file)
@@ -103,7 +103,7 @@ class available_update_checker_test extends advanced_testcase {
      */
     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
@@ -127,23 +127,52 @@ class available_update_checker_test extends advanced_testcase {
      */
     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() {
@@ -503,7 +532,7 @@ class testable_available_update_checker extends available_update_checker {
     }
 
     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!');
     }
 }
 
index 1e759d6..5263217 100644 (file)
@@ -749,29 +749,15 @@ function message_get_recent_conversations($user, $limitfrom=0, $limitto=100) {
         }
     }
 
-    //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
  *
@@ -1804,7 +1790,7 @@ function message_get_history($user1, $user2, $limitnum=0, $viewingnewmessages=fa
                                                     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
@@ -1812,15 +1798,16 @@ function message_get_history($user1, $user2, $limitnum=0, $viewingnewmessages=fa
                                                     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;
index 2da6610..070dc50 100644 (file)
@@ -258,7 +258,7 @@ function assign_print_overview($courses, &$htmlarray) {
 
 
     // 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));
 
@@ -298,7 +298,7 @@ function assign_print_overview($courses, &$htmlarray) {
             $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;
index a933ab5..e1e5104 100644 (file)
@@ -1762,6 +1762,11 @@ class assign {
         $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 */
@@ -1769,12 +1774,6 @@ class assign {
             $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));
index d9ee50e..3755f68 100644 (file)
@@ -82,8 +82,9 @@ class restore_book_activity_task extends restore_activity_task {
         $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&amp;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&amp;chapterid=$2', array('course_module', 'book_chapter'));
 
         return $rules;
     }
index 4c3cde3..b6307f7 100644 (file)
@@ -166,6 +166,15 @@ function book_print_recent_activity($course, $viewfullnames, $timestart) {
     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.
  *
index 84a1638..e187cb3 100644 (file)
@@ -25,6 +25,6 @@
 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)
index 26d5ac0..f5643d3 100644 (file)
@@ -114,7 +114,8 @@ $strbook  = get_string('modulename', 'mod_book');
 $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);
index f255c17..f43bdee 100644 (file)
@@ -1,6 +1,34 @@
 #!/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);
 
@@ -27,30 +55,15 @@ $_SERVER['PHP_SELF']        = 'dummy';
 $_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() {
@@ -225,12 +238,11 @@ class ChatDaemon {
     }
 
     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();
 
@@ -538,8 +550,18 @@ EOD;
 
         // $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
@@ -707,7 +729,6 @@ EOD;
     }
 
     function message_broadcast($message, $sender) {
-        global $PAGE;
 
         if(empty($this->conn_sets)) {
             return true;
@@ -725,7 +746,6 @@ EOD;
             {
 
                 // 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]);
 
index 237f488..d0603c2 100644 (file)
@@ -17,6 +17,7 @@ if (!$chatuser = $DB->get_record('chat_users', array('sid'=>$chat_sid))) {
 $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');
index bd9b0c2..77b2405 100644 (file)
@@ -65,8 +65,9 @@ class backup_choice_activity_structure_step extends backup_activity_structure_st
 
         $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
index 6d8bef3..a881292 100644 (file)
@@ -9,6 +9,6 @@
     </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>
index a6f6889..e941699 100644 (file)
@@ -130,7 +130,6 @@ class data_field_latlong extends data_field_base {
             } 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);
@@ -148,10 +147,11 @@ class data_field_latlong extends data_field_base {
             );
 
             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'>";
@@ -164,10 +164,11 @@ class data_field_latlong extends data_field_base {
                 // 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;
index 58fa709..f92fb13 100644 (file)
@@ -9,6 +9,6 @@
     </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>
index 6d8bef3..a881292 100644 (file)
@@ -9,6 +9,6 @@
     </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>
index 67d80f8..f569f53 100644 (file)
@@ -152,13 +152,13 @@ class data_field_picture extends data_field_base {
         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.'&amp;rid='.$recordid.'"><img src="'.$src.'" alt="'.s($alt).'" title="'.s($title).'" style="border:0px" /></a>';
+            $str = '<a href="view.php?d='.$this->field->dataid.'&amp;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;
index 4b32474..2ea0778 100644 (file)
         <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>
index 6d8bef3..a881292 100644 (file)
@@ -9,6 +9,6 @@
     </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>
index fb68424..e75365a 100644 (file)
@@ -14,7 +14,7 @@
         <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"');
@@ -28,7 +28,7 @@
         <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"');
index 7b139af..fc26f78 100644 (file)
@@ -244,7 +244,7 @@ class data_field_base {     // Base class for Database Field Types (see field/*/
 
         $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;
@@ -1480,14 +1480,16 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
     $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 ';" >&nbsp;&nbsp;&nbsp;<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 . '" >&nbsp;&nbsp;&nbsp;';
+    echo '<label for="pref_search">'.get_string('search').'</label> <input type="text" size="16" name="search" id= "pref_search" value="'.s($search).'" /></div>';
     echo '&nbsp;&nbsp;&nbsp;<label for="pref_sortby">'.get_string('sortby').'</label> ';
     // foreach field, print the option
     echo '<select name="sort" id="pref_sortby">';
@@ -1547,15 +1549,7 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
     echo '&nbsp;<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
@@ -1620,7 +1614,7 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
     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>';
index 4f68465..600c79d 100644 (file)
@@ -7,6 +7,24 @@
 .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;}
index 404f28d..953fc89 100644 (file)
@@ -141,7 +141,7 @@ if (($mytemplate = data_submitted()) && confirm_sesskey()) {
         }
     }
 } 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
@@ -198,7 +198,7 @@ if ($mode == 'listtemplate'){
     echo '<tr>';
     echo '<td>&nbsp;</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);
@@ -290,9 +290,9 @@ echo '</td>';
 
 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';
@@ -305,7 +305,7 @@ if ($mode == 'listtemplate'){
     echo '<tr>';
     echo '<td>&nbsp;</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);
@@ -316,7 +316,7 @@ if ($mode == 'listtemplate'){
     echo '<tr>';
     echo '<td>&nbsp;</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);
@@ -325,7 +325,7 @@ if ($mode == 'listtemplate'){
     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').'" />&nbsp;';
 
 echo '</td></tr></table>';
index 539affe..3cc317d 100644 (file)
@@ -56,28 +56,29 @@ class mod_folder_renderer extends plugin_renderer_base {
         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>';
@@ -102,4 +103,4 @@ class folder_tree implements renderable {
         $fs = get_file_storage();
         $this->dir = $fs->get_area_tree($this->context->id, 'mod_folder', 'content', 0);
     }
-}
\ No newline at end of file
+}
index 993ca98..be061bb 100644 (file)
@@ -1150,8 +1150,14 @@ function quiz_update_events($quiz, $override = 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;
@@ -1341,8 +1347,18 @@ function quiz_reset_userdata($data) {
 
     // 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'),
index 6361024..d07442b 100644 (file)
@@ -178,6 +178,7 @@ table.quizreviewsummary td.cell {padding: 1px 1em 1px 0.5em;text-align: left;bac
 #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;}
index 6021912..19e6061 100644 (file)
@@ -646,33 +646,50 @@ function scorm_count_launchable($scormid, $organization='') {
     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;
     }
 }
 
index 5d557a4..2e9a0c0 100644 (file)
@@ -32,8 +32,13 @@ class moodle1_workshopform_comments_handler extends moodle1_workshopform_handler
 
     /**
      * 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);
index d2c6310..e18a2f2 100644 (file)
@@ -49,9 +49,12 @@ class moodle1_workshopform_numerrors_handler extends moodle1_workshopform_handle
     /**
      * 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();
 
index be0a6c6..fe604f8 100644 (file)
@@ -46,8 +46,11 @@ class moodle1_workshopform_rubric_handler extends moodle1_workshopform_handler {
 
     /**
      * 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();
     }
index fd65dba..8103e96 100644 (file)
@@ -102,9 +102,12 @@ class question_category_list_item extends list_item {
         /// 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 .= '&nbsp;'. $category->info;
+        $item .= '&nbsp;' . 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) {
index 020c7a2..c7c4746 100644 (file)
 $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}';
index 75ce4f9..f751527 100644 (file)
@@ -7,6 +7,9 @@
     display: inline;
     background: #FFF3BF;
 }
+.que.calculatedmulti .answer .specificfeedback script {
+    display: none;
+}
 .que.calculatedmulti .answer div.r0,
 .que.calculatedmulti .answer div.r1 {
     padding: 0.3em;
index 0f79d8c..5320cdf 100644 (file)
@@ -1,3 +1,6 @@
 .que.match .feedback .rightanswer * {
     display: inline;
 }
+.que.match .feedback .rightanswer script {
+    display: none;
+}
index fbeb0fe..aeeaccf 100644 (file)
@@ -14,6 +14,9 @@
     display: inline;
     background: #FFF3BF;
 }
+.que.multianswer .answer .specificfeedback script {
+    display: none;
+}
 .que.multianswer .answer div.r0,
 .que.multianswer .answer div.r1 {
     padding: 0.3em;
index 3cadf62..c179bb8 100644 (file)
@@ -6,7 +6,13 @@
     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;
+}
index 5a70587..7685117 100644 (file)
@@ -27,6 +27,9 @@ require_once('../../config.php');
 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;
@@ -45,6 +48,7 @@ $strerror = get_string("error");
 $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
@@ -58,15 +62,18 @@ foreach ($rs as $backuprow) {
     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
index c185fb3..1c191a4 100644 (file)
@@ -36,7 +36,7 @@ defined('MOODLE_INTERNAL') || die;
  */
 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)) {
@@ -54,7 +54,7 @@ function report_stats_extend_navigation_course($navigation, $course, $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)) {
index c92ec33..0644538 100644 (file)
@@ -26,7 +26,7 @@
 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;
index 478e53b..84bac4b 100644 (file)
@@ -37,6 +37,11 @@ class repository_flickr extends repository {
     private $flickr;
     public $photos;
 
+    /**
+     * Stores sizes of images to prevent multiple API call
+     */
+    static private $sizes = array();
+
     /**
      *
      * @param int $repositoryid
@@ -228,16 +233,35 @@ class repository_flickr extends repository {
      * @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) {
index b31adaf..17cdb57 100644 (file)
@@ -41,6 +41,11 @@ class repository_flickr_public extends repository {
     private $flickr;
     public $photos;
 
+    /**
+     * Stores sizes of images to prevent multiple API call
+     */
+    static private $sizes = array();
+
     /**
      * constructor method
      *
@@ -213,13 +218,14 @@ class repository_flickr_public extends repository {
 
     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];
     }
@@ -402,16 +408,35 @@ class repository_flickr_public extends repository {
      * @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) {
@@ -434,29 +459,23 @@ class repository_flickr_public extends repository {
             $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']));
     }
 
     /**
index 38299de..72ca7bb 100644 (file)
@@ -92,8 +92,10 @@ class repository_googledocs extends repository {
     }
 
     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);
     }
index 10f3081..b416284 100644 (file)
@@ -1515,6 +1515,12 @@ abstract class repository {
             $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());
index 5b5d1c8..e3b0dc9 100644 (file)
@@ -106,12 +106,16 @@ if (!empty($new)){
     $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
index eb9260e..5d78380 100644 (file)
@@ -206,6 +206,10 @@ select, input, button {
     background-color: #34637f;
     color: #fff;
 }
+.ie7 select { /* fixes compatibility view */
+    background-color: #eee;
+    color: #036;
+}
 #loginbtn, input, button, select {
     cursor: pointer;
     margin-left: 5px;
@@ -465,4 +469,4 @@ body#page-course-view-topics.path-course div.moodle-dialogue-base div.yui3-widge
 .file-picker button,
 .file-picker textarea {
     background-color: #EEE;
-}
\ No newline at end of file
+}
index d420e1e..d695186 100644 (file)
@@ -491,8 +491,7 @@ h1.headermain {
     padding-top: 10px;
 }
 
-.forumpost .content .shortenedpost a,
-.forumpost .content p {
+.forumpost .content .shortenedpost a {
     margin: 0 10px;
     padding: 0;
 }
index 8c0ce47..df0e64f 100644 (file)
@@ -42,6 +42,7 @@
 #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;}
index 29644e1..3f577e6 100644 (file)
@@ -36,6 +36,9 @@ if (!empty($PAGE->theme->settings->frontpagelogourl)) {
 } 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;
 
index 3cebe1c..31e373e 100644 (file)
@@ -31,6 +31,9 @@ if ($hascustommenu) {
 /************************************************************************************************/
 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');
 }
index 1c49f65..8919acd 100644 (file)
@@ -26,6 +26,9 @@ if ($hascustommenu) {
 /************************************************************************************************/
 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');
 }
index 81db472..67938d0 100644 (file)
@@ -47,7 +47,7 @@ if ($ADMIN->fulltree) {
     $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
@@ -55,7 +55,7 @@ if ($ADMIN->fulltree) {
     $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
index 2a77538..6f4f49e 100644 (file)
@@ -109,7 +109,8 @@ foreach ($parts as $part) {
         $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);
index dbe6d82..400d9d3 100644 (file)
@@ -72,7 +72,13 @@ class user_editadvanced_form extends moodleform {
         /// 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() {
index b5cb4eb..81e5e0b 100644 (file)
@@ -118,6 +118,12 @@ if (has_capability('moodle/user:viewhiddendetails', $context)) {
     $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');
 
@@ -247,23 +253,34 @@ if (! isset($hiddenfields['city']) && $user->city) {
     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, ''));
 }
 
index e6818c8..68b743d 100644 (file)
@@ -77,8 +77,9 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
             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);
         },
index 13f2855..38c2756 100644 (file)
 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