Merge branch 'get_users_by_capability_fix_m23' of http://github.com/timgus/moodle...
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Mon, 1 Jul 2013 22:47:00 +0000 (00:47 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Mon, 1 Jul 2013 22:47:00 +0000 (00:47 +0200)
61 files changed:
admin/environment.xml
admin/tool/customlang/edit.php
backup/converter/moodle1/lib.php
backup/moodle2/restore_final_task.class.php
backup/util/dbops/tests/backup_dbops_test.php [moved from backup/util/dbops/tests/dbops_test.php with 59% similarity]
backup/util/dbops/tests/restore_dbops_test.php [new file with mode: 0644]
blocks/navigation/yui/navigation/navigation.js
cohort/index.php
course/format/weeks/format.js
course/lib.php
files/tests/externallib_test.php [new file with mode: 0644]
filter/urltolink/filter.php
filter/urltolink/tests/filter_test.php
grade/edit/tree/grade.php
grade/report/grader/ajax_callbacks.php
grade/report/grader/lib.php
install/lang/pan/langconfig.php [new file with mode: 0644]
lang/en/hub.php
lib/adminlib.php
lib/csslib.php
lib/db/upgrade.php
lib/filelib.php
lib/formslib.php
lib/jslib.php
lib/moodlelib.php
lib/navigationlib.php
lib/outputlib.php
lib/rsslib.php
lib/tests/formslib_test.php
lib/tests/rsslib_test.php
mod/assign/locallib.php
mod/assign/submissionplugin.php
mod/book/edit.php
mod/feedback/edit_form.php
mod/forum/lib.php
mod/imscp/locallib.php
mod/lesson/pagetypes/matching.php
mod/lti/mod_form.php
mod/quiz/startattempt.php
mod/scorm/mod_form.php
notes/edit_form.php
phpunit.xml.dist
question/behaviour/manualgraded/db/install.php [new file with mode: 0644]
question/behaviour/manualgraded/db/upgrade.php [new file with mode: 0644]
question/behaviour/manualgraded/version.php
question/type/essay/question.php
question/type/essay/tests/question_test.php
repository/lib.php
theme/base/style/core.css
theme/boxxie/layout/frontpage.php
theme/boxxie/layout/general.php
theme/formfactor/layout/frontpage.php
theme/formfactor/layout/general.php
theme/image.php
theme/sky_high/style/admin.css
theme/yui_combo.php
theme/yui_image.php
user/index.php
user/profile.php
user/selector/module.js
version.php

index 61af243..19997a4 100644 (file)
       </PHP_SETTING>
     </PHP_SETTINGS>
   </MOODLE>
+  <MOODLE version="2.6" 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="oracle" version="10.2" />
+    </DATABASE>
+    <PHP version="5.3.3" level="required">
+    </PHP>
+    <PCREUNICODE level="optional">
+      <FEEDBACK>
+        <ON_CHECK message="pcreunicodewarning" />
+      </FEEDBACK>
+    </PCREUNICODE>
+    <PHP_EXTENSIONS>
+      <PHP_EXTENSION name="iconv" level="required">
+        <FEEDBACK>
+          <ON_ERROR 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_ERROR 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="required">
+        <FEEDBACK>
+          <ON_ERROR message="gdrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="simplexml" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="simplexmlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="spl" level="required">
+        <FEEDBACK>
+          <ON_ERROR 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="64M" 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 f34e139..57d3859 100644 (file)
@@ -32,7 +32,7 @@ $lng                    = required_param('lng', PARAM_LANG);
 $currentpage            = optional_param('p', 0, PARAM_INT);
 $translatorsubmitted    = optional_param('translatorsubmitted', 0, PARAM_BOOL);
 
-$PAGE->set_pagelayout('standard');
+$PAGE->set_pagelayout('report'); // Allows for wide page contents.
 $PAGE->set_url('/admin/tool/customlang/edit.php', array('lng' => $lng));
 navigation_node::override_active_url(new moodle_url('/admin/tool/customlang/index.php'));
 $PAGE->set_title(get_string('pluginname', 'tool_customlang'));
index da6a4ec..8940251 100644 (file)
@@ -1209,12 +1209,16 @@ class moodle1_file_manager implements loggable {
      */
     public function migrate_file($sourcepath, $filepath = '/', $filename = null, $sortorder = 0, $timecreated = null, $timemodified = null) {
 
-        $sourcefullpath = $this->basepath.'/'.$sourcepath;
+        // Normalise Windows paths a bit.
+        $sourcepath = str_replace('\\', '/', $sourcepath);
 
-        if ($sourcefullpath !== clean_param($sourcefullpath, PARAM_PATH)) {
-            throw new moodle1_convert_exception('file_invalid_path', $sourcefullpath);
+        // PARAM_PATH must not be used on full OS path!
+        if ($sourcepath !== clean_param($sourcepath, PARAM_PATH)) {
+            throw new moodle1_convert_exception('file_invalid_path', $sourcepath);
         }
 
+        $sourcefullpath = $this->basepath.'/'.$sourcepath;
+
         if (!is_readable($sourcefullpath)) {
             throw new moodle1_convert_exception('file_not_readable', $sourcefullpath);
         }
index d336631..f4a2d46 100644 (file)
@@ -143,6 +143,9 @@ class restore_final_task extends restore_task {
         $rules[] = new restore_log_rule('course', 'report stats', 'report/stats/index.php?id={course}', '{course}');
         $rules[] = new restore_log_rule('course', 'view section', 'view.php?id={course}&sectionid={course_section}', '{course_section}');
 
+        // module 'grade' rules
+        $rules[] = new restore_log_rule('grade', 'update', 'report/grader/index.php?id={course}', null);
+
         // module 'user' rules
         $rules[] = new restore_log_rule('user', 'view', 'view.php?id={user}&course={course}', '{user}');
         $rules[] = new restore_log_rule('user', 'change password', 'view.php?id={user}&course={course}', '{user}');
similarity index 59%
rename from backup/util/dbops/tests/dbops_test.php
rename to backup/util/dbops/tests/backup_dbops_test.php
index e088084..8caf629 100644 (file)
@@ -26,101 +26,6 @@ defined('MOODLE_INTERNAL') || die();
 // Include all the needed stuff
 global $CFG;
 require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
-require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
-
-/**
- * Restore dbops tests (all).
- */
-class restore_dbops_testcase extends advanced_testcase {
-
-    /**
-     * Verify the xxx_ids_cached (in-memory backup_ids cache) stuff works as expected.
-     *
-     * Note that those private implementations are tested here by using the public
-     * backup_ids API and later performing low-level tests.
-     */
-    public function test_backup_ids_cached() {
-        global $DB;
-        $dbman = $DB->get_manager(); // We are going to use database_manager services.
-
-        $this->resetAfterTest(true); // Playing with temp tables, better reset once finished.
-
-        // Some variables and objects for testing.
-        $restoreid = 'testrestoreid';
-
-        $mapping = new stdClass();
-        $mapping->itemname = 'user';
-        $mapping->itemid = 1;
-        $mapping->newitemid = 2;
-        $mapping->parentitemid = 3;
-        $mapping->info = 'info';
-
-        // Create the backup_ids temp tables used by restore.
-        restore_controller_dbops::create_restore_temp_tables($restoreid);
-
-        // Send one mapping using the public api with defaults.
-        restore_dbops::set_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
-        // Get that mapping and verify everything is returned as expected.
-        $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
-        $this->assertSame($mapping->itemname, $result->itemname);
-        $this->assertSame($mapping->itemid, $result->itemid);
-        $this->assertSame(0, $result->newitemid);
-        $this->assertSame(null, $result->parentitemid);
-        $this->assertSame(null, $result->info);
-
-        // Drop the backup_xxx_temp temptables manually, so memory cache won't be invalidated.
-        $dbman->drop_table(new xmldb_table('backup_ids_temp'));
-        $dbman->drop_table(new xmldb_table('backup_files_temp'));
-
-        // Verify the mapping continues returning the same info,
-        // now from cache (the table does not exist).
-        $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
-        $this->assertSame($mapping->itemname, $result->itemname);
-        $this->assertSame($mapping->itemid, $result->itemid);
-        $this->assertSame(0, $result->newitemid);
-        $this->assertSame(null, $result->parentitemid);
-        $this->assertSame(null, $result->info);
-
-        // Recreate the temp table, just to drop it using the restore API in
-        // order to check that, then, the cache becomes invalid for the same request.
-        restore_controller_dbops::create_restore_temp_tables($restoreid);
-        restore_controller_dbops::drop_restore_temp_tables($restoreid);
-
-        // No cached info anymore, so the mapping request will arrive to
-        // DB leading to error (temp table does not exist).
-        try {
-            $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
-            $this->fail('Expecting an exception, none occurred');
-        } catch (Exception $e) {
-            $this->assertTrue($e instanceof dml_exception);
-            $this->assertSame('Table "backup_ids_temp" does not exist', $e->getMessage());
-        }
-
-        // Create the backup_ids temp tables once more.
-        restore_controller_dbops::create_restore_temp_tables($restoreid);
-
-        // Send one mapping using the public api with complete values.
-        restore_dbops::set_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid,
-                $mapping->newitemid, $mapping->parentitemid, $mapping->info);
-        // Get that mapping and verify everything is returned as expected.
-        $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
-        $this->assertSame($mapping->itemname, $result->itemname);
-        $this->assertSame($mapping->itemid, $result->itemid);
-        $this->assertSame($mapping->newitemid, $result->newitemid);
-        $this->assertSame($mapping->parentitemid, $result->parentitemid);
-        $this->assertSame($mapping->info, $result->info);
-
-        // Finally, drop the temp tables properly and get the DB error again (memory caches empty).
-        restore_controller_dbops::drop_restore_temp_tables($restoreid);
-        try {
-            $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
-            $this->fail('Expecting an exception, none occurred');
-        } catch (Exception $e) {
-            $this->assertTrue($e instanceof dml_exception);
-            $this->assertSame('Table "backup_ids_temp" does not exist', $e->getMessage());
-        }
-    }
-}
 
 /**
  * Backup dbops tests (all).
diff --git a/backup/util/dbops/tests/restore_dbops_test.php b/backup/util/dbops/tests/restore_dbops_test.php
new file mode 100644 (file)
index 0000000..d0fd2cc
--- /dev/null
@@ -0,0 +1,122 @@
+<?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/>.
+
+/**
+ * @package    core_backup
+ * @category   phpunit
+ * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+// Include all the needed stuff
+global $CFG;
+require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
+
+/**
+ * Restore dbops tests (all).
+ */
+class restore_dbops_testcase extends advanced_testcase {
+
+    /**
+     * Verify the xxx_ids_cached (in-memory backup_ids cache) stuff works as expected.
+     *
+     * Note that those private implementations are tested here by using the public
+     * backup_ids API and later performing low-level tests.
+     */
+    public function test_backup_ids_cached() {
+        global $DB;
+        $dbman = $DB->get_manager(); // We are going to use database_manager services.
+
+        $this->resetAfterTest(true); // Playing with temp tables, better reset once finished.
+
+        // Some variables and objects for testing.
+        $restoreid = 'testrestoreid';
+
+        $mapping = new stdClass();
+        $mapping->itemname = 'user';
+        $mapping->itemid = 1;
+        $mapping->newitemid = 2;
+        $mapping->parentitemid = 3;
+        $mapping->info = 'info';
+
+        // Create the backup_ids temp tables used by restore.
+        restore_controller_dbops::create_restore_temp_tables($restoreid);
+
+        // Send one mapping using the public api with defaults.
+        restore_dbops::set_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
+        // Get that mapping and verify everything is returned as expected.
+        $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
+        $this->assertSame($mapping->itemname, $result->itemname);
+        $this->assertSame($mapping->itemid, $result->itemid);
+        $this->assertSame(0, $result->newitemid);
+        $this->assertSame(null, $result->parentitemid);
+        $this->assertSame(null, $result->info);
+
+        // Drop the backup_xxx_temp temptables manually, so memory cache won't be invalidated.
+        $dbman->drop_table(new xmldb_table('backup_ids_temp'));
+        $dbman->drop_table(new xmldb_table('backup_files_temp'));
+
+        // Verify the mapping continues returning the same info,
+        // now from cache (the table does not exist).
+        $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
+        $this->assertSame($mapping->itemname, $result->itemname);
+        $this->assertSame($mapping->itemid, $result->itemid);
+        $this->assertSame(0, $result->newitemid);
+        $this->assertSame(null, $result->parentitemid);
+        $this->assertSame(null, $result->info);
+
+        // Recreate the temp table, just to drop it using the restore API in
+        // order to check that, then, the cache becomes invalid for the same request.
+        restore_controller_dbops::create_restore_temp_tables($restoreid);
+        restore_controller_dbops::drop_restore_temp_tables($restoreid);
+
+        // No cached info anymore, so the mapping request will arrive to
+        // DB leading to error (temp table does not exist).
+        try {
+            $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
+            $this->fail('Expecting an exception, none occurred');
+        } catch (Exception $e) {
+            $this->assertTrue($e instanceof dml_exception);
+            $this->assertSame('Table "backup_ids_temp" does not exist', $e->getMessage());
+        }
+
+        // Create the backup_ids temp tables once more.
+        restore_controller_dbops::create_restore_temp_tables($restoreid);
+
+        // Send one mapping using the public api with complete values.
+        restore_dbops::set_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid,
+                $mapping->newitemid, $mapping->parentitemid, $mapping->info);
+        // Get that mapping and verify everything is returned as expected.
+        $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
+        $this->assertSame($mapping->itemname, $result->itemname);
+        $this->assertSame($mapping->itemid, $result->itemid);
+        $this->assertSame($mapping->newitemid, $result->newitemid);
+        $this->assertSame($mapping->parentitemid, $result->parentitemid);
+        $this->assertSame($mapping->info, $result->info);
+
+        // Finally, drop the temp tables properly and get the DB error again (memory caches empty).
+        restore_controller_dbops::drop_restore_temp_tables($restoreid);
+        try {
+            $result = restore_dbops::get_backup_ids_record($restoreid, $mapping->itemname, $mapping->itemid);
+            $this->fail('Expecting an exception, none occurred');
+        } catch (Exception $e) {
+            $this->assertTrue($e instanceof dml_exception);
+            $this->assertSame('Table "backup_ids_temp" does not exist', $e->getMessage());
+        }
+    }
+}
index 2189d51..a987317 100644 (file)
@@ -340,11 +340,15 @@ BRANCH.prototype = {
     },
     /**
      * Attaches required events to the branch structure.
+     *
+     * @chainable
+     * @method wire
+     * @return {BRANCH} This function is chainable, it always returns itself.
      */
     wire : function() {
         this.node = this.node || Y.one('#'+this.get('id'));
         if (!this.node) {
-            return false;
+            return this;
         }
         if (this.get('expandable')) {
             this.event_ajaxload = this.node.on('ajaxload|click', this.ajaxLoad, this);
index 9c18bb7..cba516a 100644 (file)
@@ -77,6 +77,7 @@ $search .= html_writer::start_tag('div');
 $search .= html_writer::label(get_string('searchcohort', 'cohort').':', 'cohort_search_q');
 $search .= html_writer::empty_tag('input', array('id'=>'cohort_search_q', 'type'=>'text', 'name'=>'search', 'value'=>$searchquery));
 $search .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('search', 'cohort')));
+$search .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'contextid', 'value'=>$contextid));
 $search .= html_writer::end_tag('div');
 $search .= html_writer::end_tag('form');
 echo $search;
@@ -137,4 +138,4 @@ if ($manager) {
     echo $OUTPUT->single_button(new moodle_url('/cohort/edit.php', array('contextid'=>$context->id)), get_string('add'));
 }
 
-echo $OUTPUT->footer();
\ No newline at end of file
+echo $OUTPUT->footer();
index 1c36994..69a287d 100644 (file)
@@ -42,6 +42,14 @@ M.course.format.swap_sections = function(Y, node1, node2) {
     var sectionlist = Y.Node.all('.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y));
     // Swap menus.
     sectionlist.item(node1).one('.'+CSS.SECTIONADDMENUS).swap(sectionlist.item(node2).one('.'+CSS.SECTIONADDMENUS));
+
+    if (sectionlist.item(node1).hasClass('current')) {
+        sectionlist.item(node1).removeClass('current');
+        sectionlist.item(node2).addClass('current');
+    } else if (sectionlist.item(node2).hasClass('current')) {
+        sectionlist.item(node2).removeClass('current');
+        sectionlist.item(node1).addClass('current');
+    }
 }
 
 /**
index 045c9e5..057b179 100644 (file)
@@ -94,6 +94,9 @@ function make_log_url($module, $url) {
         case 'role':
             $url = '/'.$url;
             break;
+        case 'grade':
+            $url = "/grade/$url";
+            break;
         default:
             $url = "/mod/$module/$url";
             break;
diff --git a/files/tests/externallib_test.php b/files/tests/externallib_test.php
new file mode 100644 (file)
index 0000000..385aa14
--- /dev/null
@@ -0,0 +1,127 @@
+<?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/>.
+
+
+/**
+ * PHPunit tests for external files API.
+ *
+ * @package    core_files
+ * @category   external
+ * @copyright  2013 Ankit Agarwal
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 2.6
+ */
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+require_once($CFG->dirroot . '/files/externallib.php');
+
+class test_external_files extends advanced_testcase {
+
+    /*
+     * Test core_files_external::upload().
+     */
+
+    public function test_upload() {
+        global $USER;
+
+        $this->resetAfterTest();
+        $this->setAdminUser();
+        $context = context_user::instance($USER->id);
+        $contextid = $context->id;
+        $component = "user";
+        $filearea = "private";
+        $itemid = 0;
+        $filepath = "/";
+        $filename = "Simple.txt";
+        $filecontent = base64_encode("Let us create a nice simple file");
+        $browser = get_file_browser();
+
+        // Make sure no file exists.
+        $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
+        $this->assertEmpty($file);
+
+        // Call the api to create a file.
+        core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, $filename, $filecontent);
+
+        // Make sure the file was created.
+        $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
+        $this->assertNotEmpty($file);
+
+        // Make sure no file exists.
+        $itemid = 2;
+        $filename = "Simple2.txt";
+        $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
+        $this->assertEmpty($file);
+
+        // Call the api to create a file.
+        $fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, $filename, $filecontent);
+
+        // Make sure itemid is always set to 0.
+        $this->assertEquals(0, $fileinfo['itemid']);
+
+        // Make sure the same file cannot be created again.
+        $this->setExpectedException("moodle_exception");
+        core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, $filename, $filecontent);
+    }
+
+    /*
+     * Make sure only user component is allowed in  core_files_external::upload().
+     */
+    public function test_upload_param_component() {
+        global $USER;
+
+        $this->resetAfterTest();
+        $this->setAdminUser();
+        $context = context_user::instance($USER->id);
+        $contextid = $context->id;
+        $component = "backup";
+        $filearea = "private";
+        $itemid = 0;
+        $filepath = "/";
+        $filename = "Simple3.txt";
+        $filecontent = base64_encode("Let us create a nice simple file");
+
+        // Make sure exception is thrown.
+        $this->setExpectedException("coding_exception");
+        core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, $filename, $filecontent);
+    }
+
+    /*
+     * Make sure only private area is allowed in  core_files_external::upload().
+     */
+    public function test_upload_param_area() {
+        global $USER;
+
+        $this->resetAfterTest();
+        $this->setAdminUser();
+        $context = context_user::instance($USER->id);
+        $contextid = $context->id;
+        $component = "user";
+        $filearea = "draft";
+        $itemid = 0;
+        $filepath = "/";
+        $filename = "Simple4.txt";
+        $filecontent = base64_encode("Let us create a nice simple file");
+
+        // Make sure exception is thrown.
+        $this->setExpectedException("coding_exception");
+        core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, $filename, $filecontent);
+    }
+
+}
\ No newline at end of file
index d7ca920..9d01e8d 100644 (file)
@@ -122,19 +122,25 @@ class filter_urltolink extends moodle_text_filter {
             $unicoderegexp = @preg_match('/\pL/u', 'a'); // This will fail silently, returning false,
         }
 
-        //todo: MDL-21296 - use of unicode modifiers may cause a timeout
-        if ($unicoderegexp) { //We can use unicode modifiers
-            $text = preg_replace('#(?<!=["\'])(((http(s?))://)(((([\pLl0-9]([\pLl0-9]|-)*[\pLl0-9]|[\pLl0-9])\.)+([\pLl]([\pLl0-9]|-)*[\pLl0-9]|[\pLl]))|(([0-9]{1,3}\.){3}[0-9]{1,3}))(:[\pL0-9]*)?(/([\pLl0-9\.!$&\'\(\)*+,;=_~:@-]|%[a-fA-F0-9]{2})*)*(\?([\pLl0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)?(\#[\pLl0-9\.!$&\'\(\)*+,;=_~:@/?-]*)?)(?<![,.;])#iu',
-                                 '<a href="\\1" class="_blanktarget">\\1</a>', $text);
-            $text = preg_replace('#(?<!=["\']|//)((www\.([\pLl0-9]([\pLl0-9]|-)*[\pLl0-9]|[\pLl0-9])\.)+([\pLl]([\pLl0-9]|-)*[\pLl0-9]|[\pLl])(:[\pL0-9]*)?(/([\pLl0-9\.!$&\'\(\)*+,;=_~:@-]|%[a-fA-F0-9]{2})*)*(\?([\pLl0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)?(\#[\pLl0-9\.!$&\'\(\)*+,;=_~:@/?-]*)?)(?<![,.;])#iu',
-                                 '<a href="http://\\1" class="_blanktarget">\\1</a>', $text);
-        } else { //We cannot use unicode modifiers
-            $text = preg_replace('#(?<!=["\'])(((http(s?))://)(((([a-z0-9]([a-z0-9]|-)*[a-z0-9]|[a-z0-9])\.)+([a-z]([a-z0-9]|-)*[a-z0-9]|[a-z]))|(([0-9]{1,3}\.){3}[0-9]{1,3}))(:[a-zA-Z0-9]*)?(/([a-z0-9\.!$&\'\(\)*+,;=_~:@-]|%[a-f0-9]{2})*)*(\?([a-z0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)?(\#[a-z0-9\.!$&\'\(\)*+,;=_~:@/?-]*)?)(?<![,.;])#i',
-                                 '<a href="\\1" class="_blanktarget">\\1</a>', $text);
-            $text = preg_replace('#(?<!=["\']|//)((www\.([a-z0-9]([a-z0-9]|-)*[a-z0-9]|[a-z0-9])\.)+([a-z]([a-z0-9]|-)*[a-z0-9]|[a-z])(:[a-zA-Z0-9]*)?(/([a-z0-9\.!$&\'\(\)*+,;=_~:@-]|%[a-f0-9]{2})*)*(\?([a-z0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)?(\#[a-z0-9\.!$&\'\(\)*+,;=_~:@/?-]*)?)(?<![,.;])#i',
-                                 '<a href="http://\\1" class="_blanktarget">\\1</a>', $text);
+        // TODO MDL-21296 - use of unicode modifiers may cause a timeout
+        $domainsegment = '(?:[\pLl0-9][\pLl0-9-]*[\pLl0-9]|[\pLl0-9])';
+        $numericip = '(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})';
+        $port = '(?::\d*)';
+        $pathchar = '(?:[\pL0-9\.!$&\'\(\)*+,;=_~:@-]|%[a-f0-9]{2})';
+        $path = "(?:/$pathchar*)*";
+        $querystring = '(?:\?(?:[\pL0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)';
+        $fragment = '(?:\#(?:[\pL0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)';
+
+        $regex = "(?<!=[\"'])(?:http(s)?://|(www\.))((?:$domainsegment\.)+$domainsegment|$numericip)" .
+                "($port?$path$querystring?$fragment?)(?<![]),.;])";
+        if ($unicoderegexp) {
+            $regex = '#' . $regex . '#ui';
+        } else {
+            $regex = '#' . preg_replace(array('\pLl', '\PL'), 'a-z', $regex) . '#i';
         }
 
+        $text = preg_replace($regex, '<a href="http$1://$2$3$4" class="_blanktarget">$0</a>', $text);
+
         if (!empty($ignoretags)) {
             $ignoretags = array_reverse($ignoretags); /// Reversed so "progressive" str_replace() will solve some nesting problems.
             $text = str_replace(array_keys($ignoretags),$ignoretags,$text);
index 95109d1..70fb3f1 100644 (file)
@@ -44,7 +44,7 @@ class filter_urltolink_testcase extends basic_testcase {
             '$1<a href="http://www.$2$3" target="_blank">www.$2$3</a>', $text);
     }
 
-    function test_convert_urls_into_links() {
+    function get_convert_urls_into_links_test_cases() {
         $texts = array (
             //just a url
             'http://moodle.org - URL' => '<a href="http://moodle.org" class="_blanktarget">http://moodle.org</a> - URL',
@@ -57,13 +57,26 @@ class filter_urltolink_testcase extends basic_testcase {
             'URL: https://moodle.org/s/i=1&j=2' => 'URL: <a href="https://moodle.org/s/i=1&j=2" class="_blanktarget">https://moodle.org/s/i=1&j=2</a>',
             //url with port and params
             'URL: http://moodle.org:8080/s/i=1' => 'URL: <a href="http://moodle.org:8080/s/i=1" class="_blanktarget">http://moodle.org:8080/s/i=1</a>',
-            //url in brackets
+            // URL with complex fragment.
+            'Most voted issues: https://tracker.moodle.org/browse/MDL#selectedTab=com.atlassian.jira.plugin.system.project%3Apopularissues-panel' => 'Most voted issues: <a href="https://tracker.moodle.org/browse/MDL#selectedTab=com.atlassian.jira.plugin.system.project%3Apopularissues-panel" class="_blanktarget">https://tracker.moodle.org/browse/MDL#selectedTab=com.atlassian.jira.plugin.system.project%3Apopularissues-panel</a>',
+            // Domain with more parts
+            'URL: www.bbc.co.uk.' => 'URL: <a href="http://www.bbc.co.uk" class="_blanktarget">www.bbc.co.uk</a>.',
+            // URL in brackets.
             '(http://moodle.org) - URL' => '(<a href="http://moodle.org" class="_blanktarget">http://moodle.org</a>) - URL',
             '(www.moodle.org) - URL' => '(<a href="http://www.moodle.org" class="_blanktarget">www.moodle.org</a>) - URL',
-            //url in square brackets
+            // URL in brackets with a path.
+            '(http://example.com/index.html) - URL' => '(<a href="http://example.com/index.html" class="_blanktarget">http://example.com/index.html</a>) - URL',
+            '(www.example.com/index.html) - URL' => '(<a href="http://www.example.com/index.html" class="_blanktarget">www.example.com/index.html</a>) - URL',
+            // URL in brackets with anchor.
+            '(http://moodle.org/main#anchor) - URL' => '(<a href="http://moodle.org/main#anchor" class="_blanktarget">http://moodle.org/main#anchor</a>) - URL',
+            '(www.moodle.org/main#anchor) - URL' => '(<a href="http://www.moodle.org/main#anchor" class="_blanktarget">www.moodle.org/main#anchor</a>) - URL',
+            // URL in square brackets.
             '[http://moodle.org] - URL' => '[<a href="http://moodle.org" class="_blanktarget">http://moodle.org</a>] - URL',
             '[www.moodle.org] - URL' => '[<a href="http://www.moodle.org" class="_blanktarget">www.moodle.org</a>] - URL',
-            //url in brackets with anchor
+            // URL in square brackets with a path.
+            '[http://example.com/index.html] - URL' => '[<a href="http://example.com/index.html" class="_blanktarget">http://example.com/index.html</a>] - URL',
+            '[www.example.com/index.html] - URL' => '[<a href="http://www.example.com/index.html" class="_blanktarget">www.example.com/index.html</a>] - URL',
+            // URL in square brackets with anchor.
             '[http://moodle.org/main#anchor] - URL' => '[<a href="http://moodle.org/main#anchor" class="_blanktarget">http://moodle.org/main#anchor</a>] - URL',
             '[www.moodle.org/main#anchor] - URL' => '[<a href="http://www.moodle.org/main#anchor" class="_blanktarget">www.moodle.org/main#anchor</a>] - URL',
             //brackets within the url
@@ -71,7 +84,8 @@ class filter_urltolink_testcase extends basic_testcase {
             'URL: www.cc.org/url_(withpar)_go/?i=2' => 'URL: <a href="http://www.cc.org/url_(withpar)_go/?i=2" class="_blanktarget">www.cc.org/url_(withpar)_go/?i=2</a>',
             'URL: http://cc.org/url_(with)_(par)_go/?i=2' => 'URL: <a href="http://cc.org/url_(with)_(par)_go/?i=2" class="_blanktarget">http://cc.org/url_(with)_(par)_go/?i=2</a>',
             'URL: www.cc.org/url_(with)_(par)_go/?i=2' => 'URL: <a href="http://www.cc.org/url_(with)_(par)_go/?i=2" class="_blanktarget">www.cc.org/url_(with)_(par)_go/?i=2</a>',
-            'http://en.wikipedia.org/wiki/Slash_(punctuation)'=>'<a href="http://en.wikipedia.org/wiki/Slash_(punctuation)" class="_blanktarget">http://en.wikipedia.org/wiki/Slash_(punctuation)</a>',
+            // URL legitimately ending in a bracket. Commented out as part of MDL-22390. See next tests for work-arounds.
+            // 'http://en.wikipedia.org/wiki/Slash_(punctuation)'=>'<a href="http://en.wikipedia.org/wiki/Slash_(punctuation)" class="_blanktarget">http://en.wikipedia.org/wiki/Slash_(punctuation)</a>',
             'http://en.wikipedia.org/wiki/%28#Parentheses_.28_.29 - URL' => '<a href="http://en.wikipedia.org/wiki/%28#Parentheses_.28_.29" class="_blanktarget">http://en.wikipedia.org/wiki/%28#Parentheses_.28_.29</a> - URL',
             'http://en.wikipedia.org/wiki/(#Parentheses_.28_.29 - URL' => '<a href="http://en.wikipedia.org/wiki/(#Parentheses_.28_.29" class="_blanktarget">http://en.wikipedia.org/wiki/(#Parentheses_.28_.29</a> - URL',
             //escaped brackets in url
@@ -94,8 +108,6 @@ class filter_urltolink_testcase extends basic_testcase {
             'URL: www.moodle.org?u=1.23' => 'URL: <a href="http://www.moodle.org?u=1.23" class="_blanktarget">www.moodle.org?u=1.23</a>',
             //escaped space in url
             'URL: www.moodle.org?u=test+param&' => 'URL: <a href="http://www.moodle.org?u=test+param&" class="_blanktarget">www.moodle.org?u=test+param&</a>',
-            //odd characters in url param
-            'URL: www.moodle.org?param=:)' => 'URL: <a href="http://www.moodle.org?param=:)" class="_blanktarget">www.moodle.org?param=:)</a>',
             //multiple urls
             'URL: http://moodle.org www.moodle.org'
             => 'URL: <a href="http://moodle.org" class="_blanktarget">http://moodle.org</a> <a href="http://www.moodle.org" class="_blanktarget">www.moodle.org</a>',
@@ -151,17 +163,25 @@ class filter_urltolink_testcase extends basic_testcase {
             //'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN http://www.w3.org/TR/html4/strict.dtd">'=>'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN http://www.w3.org/TR/html4/strict.dtd">'
         );
 
-        $testablefilter = new testable_filter_urltolink();
-
+        $data = array();
         foreach ($texts as $text => $correctresult) {
-            $msg = "Testing text: ". str_replace('%', '%%', $text) . ": %s"; // Escape original '%' so sprintf() wont get confused
+            $data[] = array($text, $correctresult);
+        }
+        return $data;
+    }
 
-            $testablefilter->convert_urls_into_links($text);
+    /**
+     * @dataProvider get_convert_urls_into_links_test_cases
+     */
+    function test_convert_urls_into_links($text, $correctresult) {
+        $testablefilter = new testable_filter_urltolink();
+        $testablefilter->convert_urls_into_links($text);
+        $this->assertEquals($correctresult, $text);
+    }
 
-            $this->assertEquals($text, $correctresult, $msg);
-        }
+    function test_convert_urls_into_links_performance() {
+        $testablefilter = new testable_filter_urltolink();
 
-        //performance testing
         $reps = 1000;
         $text = file_get_contents(__DIR__ . '/fixtures/sample.txt');
         $time_start = microtime(true);
index 2d61e68..14de14b 100644 (file)
@@ -200,6 +200,18 @@ if ($mform->is_cancelled()) {
         $data->feedback       = $old_grade_grade->feedback;
         $data->feedbackformat = $old_grade_grade->feedbackformat;
     }
+
+    // Only log a grade override if they actually changed the student grade.
+    if ($data->finalgrade != $old_grade_grade->finalgrade) {
+        $url = '/report/grader/index.php?id=' . $course->id;
+
+        $user = $DB->get_record('user', array('id'=>$data->userid), '*', MUST_EXIST);
+        $fullname = fullname($user);
+
+        $info = "{$grade_item->itemname}: $fullname";
+        add_to_log($course->id, 'grade', 'update', $url, $info);
+    }
+
     // update final grade or feedback
     // when we set override grade the first time, it happens here
     $grade_item->update_final_grade($data->userid, $data->finalgrade, 'editgrade', $data->feedback, $data->feedbackformat);
@@ -213,6 +225,19 @@ if ($mform->is_cancelled()) {
             $data->overridden = 0; // checkbox unticked
         }
         $grade_grade->set_overridden($data->overridden);
+
+        if ($data->overridden == 0 && $data->overridden != $old_grade_grade->overridden) {
+            // Log removing an override.
+            // The addition of an override is logged above.
+            // One or the other will happen but never both.
+            $url = '/report/grader/index.php?id=' . $course->id;
+
+            $user = $DB->get_record('user', array('id'=>$data->userid), '*', MUST_EXIST);
+            $fullname = fullname($user);
+
+            $info = "{$grade_item->itemname}: $fullname";
+            add_to_log($course->id, 'grade', 'update', $url, $info);
+        }
     }
 
     if (has_capability('moodle/grade:manage', $context) or has_capability('moodle/grade:hide', $context)) {
index 6c12063..c84e2be 100644 (file)
@@ -118,6 +118,14 @@ switch ($action) {
                 echo json_encode($json_object);
                 die();
             } else {
+                $url = '/report/grader/index.php?id=' . $course->id;
+
+                $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
+                $fullname = fullname($user);
+
+                $info = "{$grade_item->itemname}: $fullname";
+                add_to_log($course->id, 'grade', 'update', $url, $info);
+
                 $json_object->gradevalue = $finalvalue;
 
                 if ($grade_item->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE)) {
index 2c653a8..7b09cde 100644 (file)
@@ -297,6 +297,12 @@ class grade_report_grader extends grade_report {
                         }
                     }
 
+                    $url = '/report/grader/index.php?id=' . $this->course->id;
+                    $fullname = fullname($this->users[$userid]);
+
+                    $info = "{$gradeitem->itemname}: $fullname";
+                    add_to_log($this->course->id, 'grade', 'update', $url, $info);
+
                     $gradeitem->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE);
 
                     // We can update feedback without reloading the grade item as it doesn't affect grade calculations
diff --git a/install/lang/pan/langconfig.php b/install/lang/pan/langconfig.php
new file mode 100644 (file)
index 0000000..9c9c136
--- /dev/null
@@ -0,0 +1,33 @@
+<?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/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'ਪੰਜਾਬੀ';
index 81e0c1e..9578f10 100644 (file)
@@ -152,7 +152,6 @@ $string['publisheremail_help'] = 'The publisher email address allows the hub adm
 $string['publishername'] = 'Publisher';
 $string['publishername_help'] = 'The publisher is the person or organisation that is the official publisher of the course.  Unless you are publishing it on behalf of someone else, it will usually be you.';
 $string['publishon'] = 'Publish on';
-$string['publishonmoodleorg'] = 'Publish on MOOCH';
 $string['publishonspecifichub'] = 'Publish on another Hub';
 $string['questionsnumber'] = 'Number of questions ({$a})';
 $string['registeredcourses'] = 'Registered courses';
@@ -190,7 +189,6 @@ $string['share'] = 'Share this course for people to download';
 $string['shared'] = 'Shared';
 $string['shareon'] = 'Upload this course to {$a}';
 $string['shareonhub'] = 'Upload this course to a hub';
-$string['shareonmoodleorg'] = 'Upload this course to MOOCH';
 $string['sharepublication_help'] = 'Uploading this course to a community hub server will enable people to download it and install it on their own Moodle sites.';
 $string['siteadmin'] = 'Administrator';
 $string['siteadmin_help'] = 'The full name of the site administrator.';
index fa7adbe..cdfca8f 100644 (file)
@@ -3842,7 +3842,7 @@ class admin_setting_question_behaviour extends admin_setting_configselect {
     public function load_choices() {
         global $CFG;
         require_once($CFG->dirroot . '/question/engine/lib.php');
-        $this->choices = question_engine::get_archetypal_behaviours();
+        $this->choices = question_engine::get_behaviour_options('');
         return true;
     }
 }
index 79f10f6..8d6de0f 100644 (file)
@@ -124,7 +124,7 @@ function css_send_ie_css($themename, $rev, $etag, $slasharguments) {
         $css .= "\n@import url($relroot/styles.php?theme=$themename&rev=$rev&type=theme);";
     }
 
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     header('Content-Disposition: inline; filename="styles.php"');
     header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT');
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
@@ -150,7 +150,7 @@ function css_send_ie_css($themename, $rev, $etag, $slasharguments) {
 function css_send_cached_css($csspath, $etag) {
     $lifetime = 60*60*24*60; // 60 days only - the revision may get incremented quite often
 
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     header('Content-Disposition: inline; filename="styles.php"');
     header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($csspath)) .' GMT');
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
@@ -208,7 +208,7 @@ function css_send_unmodified($lastmodified, $etag) {
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
     header('Cache-Control: public, max-age='.$lifetime);
     header('Content-Type: text/css; charset=utf-8');
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     if ($lastmodified) {
         header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastmodified) .' GMT');
     }
index cc0cc36..73d48f8 100644 (file)
@@ -1187,5 +1187,14 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062507.01);
     }
 
+    if ($oldversion < 2012062507.06) {
+        // Clean up old tokens which haven't been deleted.
+        $DB->execute("DELETE FROM {user_private_key} WHERE NOT EXISTS
+                         (SELECT 'x' FROM {user} WHERE deleted = 0 AND id = userid)");
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2012062507.06);
+    }
+
     return true;
 }
index 2d9b2b3..47eebc9 100644 (file)
@@ -1880,7 +1880,7 @@ function file_get_typegroup($element, $groups) {
         }
         $result = array_merge($result, $cached[$element][$group]);
     }
-    return array_unique($result);
+    return array_values(array_unique($result));
 }
 
 /**
index 9d46fe6..e99ba0a 100644 (file)
@@ -1079,11 +1079,9 @@ abstract class moodleform {
                             $params = array_merge(array($realelementname), $params);
                             call_user_func_array(array(&$mform, 'addRule'), $params);
                             break;
-                        case 'type' :
-                            //Type should be set only once
-                            if (!isset($mform->_types[$elementname])) {
-                                $mform->setType($elementname, $params);
-                            }
+
+                        case 'type':
+                            $mform->setType($realelementname, $params);
                             break;
                     }
                 }
index ee905f1..cef5c98 100644 (file)
@@ -36,7 +36,7 @@ function js_send_cached($jspath, $etag, $filename = 'javascript.php') {
 
     $lifetime = 60*60*24*60; // 60 days only - the revision may get incremented quite often
 
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     header('Content-Disposition: inline; filename="'.$filename.'"');
     header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($jspath)) .' GMT');
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
@@ -86,7 +86,7 @@ function js_send_unmodified($lastmodified, $etag) {
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
     header('Cache-Control: public, max-age='.$lifetime);
     header('Content-Type: application/javascript; charset=utf-8');
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     if ($lastmodified) {
         header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastmodified) .' GMT');
     }
index 277b496..a1f8a0a 100644 (file)
@@ -4031,6 +4031,9 @@ function delete_user(stdClass $user) {
     // unauthorise the user for all services
     $DB->delete_records('external_services_users', array('userid'=>$user->id));
 
+    // Remove users private keys.
+    $DB->delete_records('user_private_key', array('userid' => $user->id));
+
     // force logout - may fail if file based sessions used, sorry
     session_kill_user($user->id);
 
index 07eea13..c574db7 100644 (file)
@@ -579,7 +579,7 @@ class navigation_node implements renderable {
     public function find_expandable(array &$expandable) {
         foreach ($this->children as &$child) {
             if ($child->nodetype == self::NODETYPE_BRANCH && $child->children->count() == 0 && $child->display) {
-                $child->id = 'expandable_branch_'.(count($expandable)+1);
+                $child->id = 'expandable_branch_'.$child->type.'_'.clean_param($child->key, PARAM_ALPHANUMEXT);
                 $this->add_class('canexpand');
                 $expandable[] = array('id' => $child->id, 'key' => $child->key, 'type' => $child->type);
             }
@@ -3604,12 +3604,11 @@ class settings_navigation extends navigation_node {
                 $editstring = get_string('turneditingon');
             }
             $coursenode->add($editstring, $editurl, self::TYPE_SETTING, null, null, new pix_icon('i/edit', ''));
-        }
 
-        if (has_capability('moodle/course:manageactivities', $coursecontext)) {
             // Add the module chooser toggle
-            $modchoosertoggleurl = clone($baseurl);
-            if ($this->page->user_is_editing() && course_ajax_enabled($course)) {
+            if ($this->page->user_is_editing() && has_capability('moodle/course:manageactivities', $coursecontext)
+                    && course_ajax_enabled($course)) {
+                $modchoosertoggleurl = clone($baseurl);
                 if ($usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault)) {
                     $modchoosertogglestring = get_string('modchooserdisable', 'moodle');
                     $modchoosertoggleurl->param('modchooser', 'off');
index 8246b2c..d26cb78 100644 (file)
@@ -483,7 +483,10 @@ class theme_config {
                 $this->rarrow = '&#x25B6;';
                 $this->larrow = '&#x25C0;';
             }
-            elseif (false !== strpos($uagent, 'Konqueror')) {
+            elseif ((false !== strpos($uagent, 'Konqueror'))
+                || (false !== strpos($uagent, 'Android')))  {
+                // The fonts on Android don't include the characters required for this to work as expected.
+                // So we use the same ones Konqueror uses.
                 $this->rarrow = '&rarr;';
                 $this->larrow = '&larr;';
             }
index 6046e66..17157bb 100644 (file)
@@ -269,7 +269,7 @@ function rss_standard_header($title = NULL, $link = NULL, $description = NULL) {
             $result .= rss_full_tag('language', 2, false, substr($USER->lang,0,2));
         }
         $today = getdate();
-        $result .= rss_full_tag('copyright', 2, false, '&#169; '. $today['year'] .' '. format_string($site->fullname));
+        $result .= rss_full_tag('copyright', 2, false, '(c) '. $today['year'] .' '. format_string($site->fullname));
         /*
        if (!empty($USER->email)) {
             $result .= rss_full_tag('managingEditor', 2, false, fullname($USER));
index eab98a3..a4495da 100644 (file)
@@ -226,6 +226,24 @@ class formslib_testcase extends basic_testcase {
                     'xyz' => PARAM_RAW
                 ),
                 1 => PARAM_INT
+            ),
+            'repeatgroupel1' => array(
+                0 => PARAM_INT,
+                1 => PARAM_INT
+            ),
+            'repeatgroupel2' => array(
+                0 => PARAM_INT,
+                1 => PARAM_INT
+            ),
+            'repeatnamedgroup' => array(
+                0 => array(
+                    'repeatnamedgroupel1' => PARAM_INT,
+                    'repeatnamedgroupel2' => PARAM_INT
+                ),
+                1 => array(
+                    'repeatnamedgroupel1' => PARAM_INT,
+                    'repeatnamedgroupel2' => PARAM_INT
+                )
             )
         );
         $valuessubmitted = array(
@@ -262,6 +280,24 @@ class formslib_testcase extends basic_testcase {
                     'xyz' => '11.01'
                 ),
                 1 => '11.01'
+            ),
+            'repeatgroupel1' => array(
+                0 => '11.01',
+                1 => '11.01'
+            ),
+            'repeatgroupel2' => array(
+                0 => '11.01',
+                1 => '11.01'
+            ),
+            'repeatnamedgroup' => array(
+                0 => array(
+                    'repeatnamedgroupel1' => '11.01',
+                    'repeatnamedgroupel2' => '11.01'
+                ),
+                1 => array(
+                    'repeatnamedgroupel1' => '11.01',
+                    'repeatnamedgroupel2' => '11.01'
+                )
             )
         );
         $expectedvalues = array(
@@ -300,6 +336,26 @@ class formslib_testcase extends basic_testcase {
                     'xyz' => '11.01'
                 ),
                 1 => 11
+            ),
+            'repeatablegroup' => 2,
+            'repeatgroupel1' => array(
+                0 => 11,
+                1 => 11
+            ),
+            'repeatgroupel2' => array(
+                0 => 11,
+                1 => 11
+            ),
+            'repeatablenamedgroup' => 2,
+            'repeatnamedgroup' => array(
+                0 => array(
+                    'repeatnamedgroupel1' => 11,
+                    'repeatnamedgroupel2' => 11
+                ),
+                1 => array(
+                    'repeatnamedgroupel1' => 11,
+                    'repeatnamedgroupel2' => 11
+                )
             )
         );
 
@@ -342,6 +398,7 @@ class formslib_test_form extends moodleform {
     }
 }
 
+// Used to check value cleaning.
 class formslib_clean_value extends moodleform {
     public function get_form() {
         return $this->_form;
@@ -407,5 +464,23 @@ class formslib_clean_value extends moodleform {
         $mform->addElement('text', 'nested[1]', 'nested[1]');
         $mform->addElement('text', 'nested[0][xyz]', 'nested[0][xyz]');
         $mform->addElement('text', 'nested[0][bob][foo]', 'nested[0][bob][foo]');
+
+        // Add group in repeated element (with extra inheritance).
+        $groupelements = array(
+            $mform->createElement('text', 'repeatgroupel1', 'repeatgroupel1'),
+            $mform->createElement('text', 'repeatgroupel2', 'repeatgroupel2')
+        );
+        $group = $mform->createElement('group', 'repeatgroup', 'repeatgroup', $groupelements, null, false);
+        $this->repeat_elements(array($group), 2, array('repeatgroupel1' => array('type' => PARAM_INT),
+            'repeatgroupel2' => array('type' => PARAM_INT)), 'repeatablegroup', 'add', 0);
+
+        // Add named group in repeated element.
+        $groupelements = array(
+            $mform->createElement('text', 'repeatnamedgroupel1', 'repeatnamedgroupel1'),
+            $mform->createElement('text', 'repeatnamedgroupel2', 'repeatnamedgroupel2')
+        );
+        $group = $mform->createElement('group', 'repeatnamedgroup', 'repeatnamedgroup', $groupelements, null, true);
+        $this->repeat_elements(array($group), 2, array('repeatnamedgroup[repeatnamedgroupel1]' => array('type' => PARAM_INT),
+            'repeatnamedgroup[repeatnamedgroupel2]' => array('type' => PARAM_INT)), 'repeatablenamedgroup', 'add', 0);
     }
 }
index 8e9d1a3..7225220 100644 (file)
@@ -43,14 +43,18 @@ class moodlesimplepie_testcase extends basic_testcase {
     const INVALIDURL = 'http://download.moodle.org/unittest/rsstest-which-doesnt-exist.xml';
     # This tinyurl redirects to th rsstest.xml file
     const REDIRECTURL = 'http://tinyurl.com/lvyslv';
+    # The number of seconds tests should wait for the server to respond (high to prevent false positives).
+    const TIMEOUT = 10;
 
     function setUp() {
         moodle_simplepie::reset_cache();
     }
 
     function test_getfeed() {
-        $feed = new moodle_simplepie(self::VALIDURL);
-
+        $feed = new moodle_simplepie();
+        $feed->set_timeout(self::TIMEOUT);
+        $feed->set_feed_url(self::VALIDURL);
+        $feed->init();
         $this->assertInstanceOf('moodle_simplepie', $feed);
 
         $this->assertNull($feed->error(), "Failed to load the sample RSS file. Please check your proxy settings in Moodle. %s");
@@ -108,7 +112,10 @@ EOD;
      * Test retrieving a url which doesn't exist
      */
     function test_failurl() {
-        $feed = @new moodle_simplepie(self::INVALIDURL); // we do not want this in php error log
+        $feed = new moodle_simplepie();
+        $feed->set_timeout(self::TIMEOUT);
+        $feed->set_feed_url(self::INVALIDURL);
+        @$feed->init(); // We do not want this in php error log.
 
         $this->assertNotEmpty($feed->error());
     }
@@ -135,7 +142,10 @@ EOD;
     function test_redirect() {
         global $CFG;
 
-        $feed = new moodle_simplepie(self::REDIRECTURL);
+        $feed = new moodle_simplepie();
+        $feed->set_timeout(self::TIMEOUT);
+        $feed->set_feed_url(self::REDIRECTURL);
+        $feed->init();
 
         $this->assertNull($feed->error());
         $this->assertEquals($feed->get_title(), 'Moodle News');
index d6e7c41..791734e 100644 (file)
@@ -2662,7 +2662,9 @@ class assign {
             // Give each submission plugin a chance to process the submission
             $plugins = $this->get_submission_plugins();
             foreach ($plugins as $plugin) {
-                $plugin->submit_for_grading();
+                if ($plugin->is_enabled() && $plugin->is_visible()) {
+                    $plugin->submit_for_grading($submission);
+                }
             }
 
             $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
@@ -2943,7 +2945,7 @@ class assign {
             $allempty = true;
             $pluginerror = false;
             foreach ($this->submissionplugins as $plugin) {
-                if ($plugin->is_enabled()) {
+                if ($plugin->is_enabled() && $plugin->is_visible()) {
                     if (!$plugin->save($submission, $data)) {
                         $notices[] = $plugin->get_error();
                         $pluginerror = true;
@@ -3286,6 +3288,13 @@ class assign {
         $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
         $this->update_submission($submission, false);
 
+        // Give each submission plugin a chance to process the reverting to draft.
+        $plugins = $this->get_submission_plugins();
+        foreach ($plugins as $plugin) {
+            if ($plugin->is_enabled() && $plugin->is_visible()) {
+                $plugin->revert_to_draft($submission);
+            }
+        }
         // update the modified time on the grade (grader modified)
         $grade = $this->get_user_grade($userid, true);
         $this->update_grade($grade);
@@ -3313,6 +3322,15 @@ class assign {
             $userid = required_param('userid', PARAM_INT);
         }
 
+        // Give each submission plugin a chance to process the locking.
+        $plugins = $this->get_submission_plugins();
+        $submission = $this->get_user_submission($userid, false);
+        foreach ($plugins as $plugin) {
+            if ($plugin->is_enabled() && $plugin->is_visible()) {
+                $plugin->lock($submission);
+            }
+        }
+
         $grade = $this->get_user_grade($userid, true);
         $grade->locked = 1;
         $grade->grader = $USER->id;
@@ -3340,6 +3358,15 @@ class assign {
             $userid = required_param('userid', PARAM_INT);
         }
 
+        // Give each submission plugin a chance to process the locking.
+        $plugins = $this->get_submission_plugins();
+        $submission = $this->get_user_submission($userid, false);
+        foreach ($plugins as $plugin) {
+            if ($plugin->is_enabled() && $plugin->is_visible()) {
+                $plugin->unlock($submission);
+            }
+        }
+
         $grade = $this->get_user_grade($userid, true);
         $grade->locked = 0;
         $grade->grader = $USER->id;
index 29462c9..3257be0 100644 (file)
@@ -69,9 +69,38 @@ abstract class assign_submission_plugin extends assign_plugin {
 
     /**
      * Carry out any extra processing required when the work is submitted for grading
+     *
+     * @param stdClass $submission - assign_submission data
+     * @return void
+     */
+    public function submit_for_grading(stdClass $submission) {
+    }
+
+    /**
+     * Carry out any extra processing required when the work is locked.
+     *
+     * @param stdClass $submission - assign_submission data
+     * @return void
+     */
+    public function lock(stdClass $submission) {
+    }
+
+    /**
+     * Carry out any extra processing required when the work is unlocked.
+     *
+     * @param stdClass $submission - assign_submission data
+     * @return void
+     */
+    public function unlock(stdClass $submission) {
+    }
+
+    /**
+     * Carry out any extra processing required when the work reverted to draft.
+     *
+     * @param stdClass $submission - assign_submission data
      * @return void
      */
-    public function submit_for_grading() {
+    public function revert_to_draft(stdClass $submission) {
     }
 
 }
index 541233d..e0f7003 100644 (file)
@@ -72,6 +72,7 @@ if ($mform->is_cancelled()) {
         // store the files
         $data = file_postupdate_standard_editor($data, 'content', $options, $context, 'mod_book', 'chapter', $data->id);
         $DB->update_record('book_chapters', $data);
+        $DB->set_field('book', 'revision', $book->revision+1, array('id'=>$book->id));
 
         add_to_log($course->id, 'course', 'update mod', '../mod/book/view.php?id='.$cm->id, 'book '.$book->id);
         add_to_log($course->id, 'book', 'update', 'view.php?id='.$cm->id.'&chapterid='.$data->id, $book->id, $cm->id);
index 84ec317..1769bb5 100644 (file)
@@ -48,7 +48,7 @@ class feedback_edit_add_question_form extends moodleform {
         $mform->setType('position', PARAM_INT);
 
         // buttons
-        $mform->addElement('submit', 'add_item', get_string('add_item', 'feedback'));
+        $mform->addElement('submit', 'add_item', get_string('add_item', 'feedback'), array('class' => 'hiddenifjs'));
     }
 }
 
index d9f28be..f1c07ef 100644 (file)
@@ -6717,7 +6717,11 @@ function forum_tp_count_forum_unread_posts($cm, $course) {
         $modinfo->groups = groups_get_user_groups($course->id, $USER->id);
     }
 
-    $mygroups = $modinfo->groups[$cm->groupingid];
+    if (array_key_exists($cm->groupingid, $modinfo->groups)) {
+        $mygroups = $modinfo->groups[$cm->groupingid];
+    } else {
+        $mygroups = false; // Will be set below
+    }
 
     // add all groups posts
     if (empty($mygroups)) {
index 04b16fb..71a1813 100644 (file)
@@ -61,10 +61,14 @@ function imscp_print_content($imscp, $cm, $course) {
 function imscp_htmllize_item($item, $imscp, $cm) {
     global $CFG;
 
-    $context = get_context_instance(CONTEXT_MODULE, $cm->id);
-    $urlbase = "$CFG->wwwroot/pluginfile.php";
-    $path = '/'.$context->id.'/mod_imscp/content/'.$imscp->revision.'/'.$item['href'];
-    $url = file_encode_url($urlbase, $path, false);
+    if (preg_match('|^https?://|', $item['href'])) {
+        $url = $item['href'];
+    } else {
+        $context = context_module::instance($cm->id);
+        $urlbase = "$CFG->wwwroot/pluginfile.php";
+        $path = '/'.$context->id.'/mod_imscp/content/'.$imscp->revision.'/'.$item['href'];
+        $url = file_encode_url($urlbase, $path, false);
+    }
     $result = "<li><a href=\"$url\">".$item['title'].'</a>';
     if ($item['subitems']) {
         $result .= '<ul>';
index 3c77e53..9082c9f 100644 (file)
@@ -71,18 +71,16 @@ class lesson_page_type_matching extends lesson_page {
         $responses = array();
         foreach ($answers as $answer) {
             // get all the response
-            if ($answer->response != NULL) {
-                $responses[$answer->id] = trim($answer->response);
+            if ($answer->response != null) {
+                $responses[] = trim($answer->response);
             }
         }
 
         $responseoptions = array(''=>get_string('choosedots'));
         if (!empty($responses)) {
-            $shuffleresponses = $responses;
-            shuffle($shuffleresponses);
-            foreach ($shuffleresponses as  $response) {
-                $key = array_search($response, $responses);
-                $responseoptions[$key] = $response;
+            shuffle($responses);
+            foreach ($responses as  $response) {
+                $responseoptions[htmlspecialchars($response)] = $response;
             }
         }
         if (isset($USER->modattempts[$this->lesson->id]) && !empty($attempt->useranswer)) {
@@ -167,12 +165,12 @@ class lesson_page_type_matching extends lesson_page {
         $wrong   = array_shift($getanswers);
 
         $answers = array();
-        foreach ($getanswers as $key=>$answer) {
+        foreach ($getanswers as $key => $answer) {
             if ($answer->answer !== '' or $answer->response !== '') {
                 $answers[$answer->id] = $answer;
             }
-            unset($getanswers[$key]);
         }
+
         // get the user's exact responses for record keeping
         $hits = 0;
         $userresponse = array();
@@ -181,12 +179,13 @@ class lesson_page_type_matching extends lesson_page {
                 $result->noanswer = true;
                 return $result;
             }
+            $value = htmlspecialchars_decode($value);
             $userresponse[] = $value;
             // Make sure the user's answer exists in question's answer
             if (array_key_exists($id, $answers)) {
                 $answer = $answers[$id];
-                $result->studentanswer .= '<br />'.format_text($answer->answer, $answer->answerformat, $formattextdefoptions).' = '.$answers[$value]->response;
-                if ($id == $value) {
+                $result->studentanswer .= '<br />'.format_text($answer->answer, $answer->answerformat, $formattextdefoptions).' = '.$value;
+                if (trim($answer->response) == trim($value)) {
                     $hits++;
                 }
             }
@@ -401,13 +400,13 @@ class lesson_page_type_matching extends lesson_page {
                 }
             } elseif ($n > 1) {
                 $data = '<label class="accesshide" for="answer_' . $n . '">' . get_string('answer', 'lesson') . '</label>';
-                $data .= "<select id=\"answer_". $n ."\" disabled=\"disabled\"><option selected=\"selected\">".strip_tags(format_string($answer->answer))."</option></select>";
-                if ($useranswer != NULL) {
+                $data .= strip_tags(format_string($answer->answer)) . ' ';
+                if ($useranswer != null) {
                     $userresponse = explode(",", $useranswer->useranswer);
                     $data .= '<label class="accesshide" for="stu_answer_response_' . $n . '">' . get_string('matchesanswer', 'lesson') . '</label>';
                     $data .= "<select id=\"stu_answer_response_" . $n . "\" disabled=\"disabled\"><option selected=\"selected\">";
                     if (array_key_exists($i, $userresponse)) {
-                        $data .= strip_tags(format_string($answers[$userresponse[$i]]->response));
+                        $data .= $userresponse[$i];
                     }
                     $data .= "</option></select>";
                 } else {
@@ -518,19 +517,20 @@ class lesson_display_answer_form_matching extends moodleform {
         $mform->setType('pageid', PARAM_INT);
 
         $i = 0;
+
         foreach ($answers as $answer) {
             $mform->addElement('html', '<div class="answeroption">');
-            if ($answer->response != NULL) {
+            if ($answer->response != null) {
                 $responseid = 'response['.$answer->id.']';
                 if ($hasattempt) {
                     $responseid = 'response_'.$answer->id;
-                    $mform->addElement('hidden', 'response['.$answer->id.']', htmlspecialchars(trim($answers[$useranswers[$i]]->response)));
+                    $mform->addElement('hidden', 'response['.$answer->id.']', htmlspecialchars($useranswers[$i]));
                     $mform->setType('response['.$answer->id.']', PARAM_TEXT);
                 }
                 $mform->addElement('select', $responseid, format_text($answer->answer,$answer->answerformat,$options), $responseoptions, $disabled);
                 $mform->setType($responseid, PARAM_TEXT);
                 if ($hasattempt) {
-                    $mform->setDefault($responseid, htmlspecialchars(trim($answers[$useranswers[$i]]->response))); //TODO: this is suspicious
+                    $mform->setDefault($responseid, htmlspecialchars(trim($useranswers[$i])));
                 } else {
                     $mform->setDefault($responseid, 'answeroption');
                 }
index 425c518..d269817 100644 (file)
@@ -153,15 +153,15 @@ class mod_lti_mod_form extends moodleform_mod {
         // Add privacy preferences fieldset where users choose whether to send their data
         $mform->addElement('header', 'privacy', get_string('privacy', 'lti'));
 
-        $mform->addElement('checkbox', 'instructorchoicesendname', '&nbsp;', ' ' . get_string('share_name', 'lti'));
+        $mform->addElement('advcheckbox', 'instructorchoicesendname', '&nbsp;', ' ' . get_string('share_name', 'lti'));
         $mform->setDefault('instructorchoicesendname', '1');
         $mform->addHelpButton('instructorchoicesendname', 'share_name', 'lti');
 
-        $mform->addElement('checkbox', 'instructorchoicesendemailaddr', '&nbsp;', ' ' . get_string('share_email', 'lti'));
+        $mform->addElement('advcheckbox', 'instructorchoicesendemailaddr', '&nbsp;', ' ' . get_string('share_email', 'lti'));
         $mform->setDefault('instructorchoicesendemailaddr', '1');
         $mform->addHelpButton('instructorchoicesendemailaddr', 'share_email', 'lti');
 
-        $mform->addElement('checkbox', 'instructorchoiceacceptgrades', '&nbsp;', ' ' . get_string('accept_grades', 'lti'));
+        $mform->addElement('advcheckbox', 'instructorchoiceacceptgrades', '&nbsp;', ' ' . get_string('accept_grades', 'lti'));
         $mform->setDefault('instructorchoiceacceptgrades', '1');
         $mform->addHelpButton('instructorchoiceacceptgrades', 'accept_grades', 'lti');
 
index f1f08ca..4a47194 100644 (file)
@@ -93,7 +93,7 @@ if ($lastattempt && ($lastattempt->state == quiz_attempt::IN_PROGRESS ||
 
     // And, if the attempt is now no longer in progress, redirect to the appropriate place.
     if ($lastattempt->state == quiz_attempt::OVERDUE) {
-         redirect($quizobj->summary_url($lastattempt->id));
+        redirect($quizobj->summary_url($lastattempt->id));
     } else if ($lastattempt->state != quiz_attempt::IN_PROGRESS) {
         redirect($quizobj->review_url($lastattempt->id));
     }
@@ -104,6 +104,10 @@ if ($lastattempt && ($lastattempt->state == quiz_attempt::IN_PROGRESS ||
     }
 
 } else {
+    while ($lastattempt && $lastattempt->preview) {
+        $lastattempt = array_pop($attempts);
+    }
+
     // Get number for the next or unfinished attempt.
     if ($lastattempt) {
         $attemptnumber = $lastattempt->attempt + 1;
index e3ffb34..a57f2dd 100644 (file)
@@ -35,7 +35,7 @@ class mod_scorm_mod_form extends moodleform_mod {
         //-------------------------------------------------------------------------------
         $mform->addElement('header', 'general', get_string('general', 'form'));
 
-        // Name
+        // Name.
         $mform->addElement('text', 'name', get_string('name'));
         if (!empty($CFG->formatstringstriptags)) {
             $mform->setType('name', PARAM_TEXT);
@@ -45,10 +45,10 @@ class mod_scorm_mod_form extends moodleform_mod {
         $mform->addRule('name', null, 'required', null, 'client');
         $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
-        // Summary
+        // Summary.
         $this->add_intro_editor(true);
 
-        // Scorm types
+        // Scorm types.
         $scormtypes = array(SCORM_TYPE_LOCAL => get_string('typelocal', 'scorm'));
 
         if ($cfg_scorm->allowtypeexternal) {
@@ -67,7 +67,7 @@ class mod_scorm_mod_form extends moodleform_mod {
             $scormtypes[SCORM_TYPE_AICCURL] = get_string('typeaiccurl', 'scorm');
         }
 
-        // Reference
+        // Reference.
         if (count($scormtypes) > 1) {
             $mform->addElement('select', 'scormtype', get_string('scormtype', 'scorm'), $scormtypes);
             $mform->addHelpButton('scormtype', 'scormtype', 'scorm');
@@ -79,7 +79,7 @@ class mod_scorm_mod_form extends moodleform_mod {
             $mform->addElement('hidden', 'scormtype', SCORM_TYPE_LOCAL);
         }
 
-        // New local package upload
+        // New local package upload.
         $maxbytes = get_max_upload_file_size($CFG->maxbytes, $COURSE->maxbytes);
         $mform->setMaxFileSize($maxbytes);
         $mform->addElement('filepicker', 'packagefile', get_string('package', 'scorm'));
@@ -87,34 +87,34 @@ class mod_scorm_mod_form extends moodleform_mod {
         $mform->disabledIf('packagefile', 'scormtype', 'noteq', SCORM_TYPE_LOCAL);
 
         //-------------------------------------------------------------------------------
-        // Time restrictions
+        // Time restrictions.
         $mform->addElement('header', 'timerestricthdr', get_string('timerestrict', 'scorm'));
 
         $mform->addElement('date_time_selector', 'timeopen', get_string("scormopen", "scorm"), array('optional' => true));
         $mform->addElement('date_time_selector', 'timeclose', get_string("scormclose", "scorm"), array('optional' => true));
         //-------------------------------------------------------------------------------
-        // display Settings
+        // Display Settings.
         $mform->addElement('header', 'displaysettings', get_string('displaysettings', 'scorm'));
-        // Framed / Popup Window
+        // Framed / Popup Window.
         $mform->addElement('select', 'popup', get_string('display', 'scorm'), scorm_get_popup_display_array());
         $mform->setDefault('popup', $cfg_scorm->popup);
         $mform->setAdvanced('popup', $cfg_scorm->popup_adv);
 
-        // Width
+        // Width.
         $mform->addElement('text', 'width', get_string('width', 'scorm'), 'maxlength="5" size="5"');
         $mform->setDefault('width', $cfg_scorm->framewidth);
         $mform->setType('width', PARAM_INT);
         $mform->setAdvanced('width', $cfg_scorm->framewidth_adv);
         $mform->disabledIf('width', 'popup', 'eq', 0);
 
-        // Height
+        // Height.
         $mform->addElement('text', 'height', get_string('height', 'scorm'), 'maxlength="5" size="5"');
         $mform->setDefault('height', $cfg_scorm->frameheight);
         $mform->setType('height', PARAM_INT);
         $mform->setAdvanced('height', $cfg_scorm->frameheight_adv);
         $mform->disabledIf('height', 'popup', 'eq', 0);
 
-        // Window Options
+        // Window Options.
         $winoptgrp = array();
         foreach (scorm_get_popup_options_array() as $key => $value) {
             $winoptgrp[] = &$mform->createElement('checkbox', $key, '', get_string($key, 'scorm'));
@@ -124,7 +124,7 @@ class mod_scorm_mod_form extends moodleform_mod {
         $mform->disabledIf('winoptgrp', 'popup', 'eq', 0);
         $mform->setAdvanced('winoptgrp', $cfg_scorm->winoptgrp_adv);
 
-        // Skip view page
+        // Skip view page.
         $skipviewoptions = scorm_get_skip_view_array();
         if ($COURSE->format == 'scorm') { // Remove option that would cause a constant redirect.
             unset($skipviewoptions[SCORM_SKIPVIEW_ALWAYS]);
@@ -137,41 +137,41 @@ class mod_scorm_mod_form extends moodleform_mod {
         $mform->setDefault('skipview', $cfg_scorm->skipview);
         $mform->setAdvanced('skipview', $cfg_scorm->skipview_adv);
 
-        // Hide Browse
+        // Hide Browse.
         $mform->addElement('selectyesno', 'hidebrowse', get_string('hidebrowse', 'scorm'));
         $mform->addHelpButton('hidebrowse', 'hidebrowse', 'scorm');
         $mform->setDefault('hidebrowse', $cfg_scorm->hidebrowse);
         $mform->setAdvanced('hidebrowse', $cfg_scorm->hidebrowse_adv);
 
-        // Display course structure
+        // Display course structure.
         $mform->addElement('selectyesno', 'displaycoursestructure', get_string('displaycoursestructure', 'scorm'));
         $mform->addHelpButton('displaycoursestructure', 'displaycoursestructure', 'scorm');
         $mform->setDefault('displaycoursestructure', $cfg_scorm->displaycoursestructure);
         $mform->setAdvanced('displaycoursestructure', $cfg_scorm->displaycoursestructure_adv);
 
-        // Toc display
+        // Toc display.
         $mform->addElement('select', 'hidetoc', get_string('hidetoc', 'scorm'), scorm_get_hidetoc_array());
         $mform->addHelpButton('hidetoc', 'hidetoc', 'scorm');
         $mform->setDefault('hidetoc', $cfg_scorm->hidetoc);
         $mform->setAdvanced('hidetoc', $cfg_scorm->hidetoc_adv);
 
-        // Hide Navigation panel
+        // Hide Navigation panel.
         $mform->addElement('selectyesno', 'hidenav', get_string('hidenav', 'scorm'));
         $mform->setDefault('hidenav', $cfg_scorm->hidenav);
         $mform->setAdvanced('hidenav', $cfg_scorm->hidenav_adv);
         $mform->disabledIf('hidenav', 'hidetoc', 'noteq', 0);
 
         //-------------------------------------------------------------------------------
-        // grade Settings
+        // Grade Settings.
         $mform->addElement('header', 'gradesettings', get_string('gradesettings', 'scorm'));
 
-        // Grade Method
+        // Grade Method.
         $mform->addElement('select', 'grademethod', get_string('grademethod', 'scorm'), scorm_get_grade_method_array());
         $mform->addHelpButton('grademethod', 'grademethod', 'scorm');
         $mform->setDefault('grademethod', $cfg_scorm->grademethod);
         $mform->setAdvanced('grademethod', $cfg_scorm->grademethod_adv);
 
-        // Maximum Grade
+        // Maximum Grade.
         for ($i=0; $i<=100; $i++) {
             $grades[$i] = "$i";
         }
@@ -182,20 +182,20 @@ class mod_scorm_mod_form extends moodleform_mod {
 
         $mform->addElement('header', 'othersettings', get_string('othersettings', 'scorm'));
 
-        // Max Attempts
+        // Max Attempts.
         $mform->addElement('select', 'maxattempt', get_string('maximumattempts', 'scorm'), scorm_get_attempts_array());
         $mform->addHelpButton('maxattempt', 'maximumattempts', 'scorm');
         $mform->setDefault('maxattempt', $cfg_scorm->maxattempt);
         $mform->setAdvanced('maxattempt', $cfg_scorm->maxattempt_adv);
 
-        // What Grade
+        // What Grade.
         $mform->addElement('select', 'whatgrade', get_string('whatgrade', 'scorm'),  scorm_get_what_grade_array());
         $mform->disabledIf('whatgrade', 'maxattempt', 'eq', 1);
         $mform->addHelpButton('whatgrade', 'whatgrade', 'scorm');
         $mform->setDefault('whatgrade', $cfg_scorm->whatgrade);
         $mform->setAdvanced('whatgrade', $cfg_scorm->whatgrade_adv);
 
-        // Display attempt status
+        // Display attempt status.
         $mform->addElement('selectyesno', 'displayattemptstatus', get_string('displayattemptstatus', 'scorm'));
         $mform->addHelpButton('displayattemptstatus', 'displayattemptstatus', 'scorm');
         $mform->setDefault('displayattemptstatus', $cfg_scorm->displayattemptstatus);
@@ -207,19 +207,19 @@ class mod_scorm_mod_form extends moodleform_mod {
         $mform->setDefault('forcecompleted', $cfg_scorm->forcecompleted);
         $mform->setAdvanced('forcecompleted', $cfg_scorm->forcecompleted_adv);
 
-        // Force new attempt
+        // Force new attempt.
         $mform->addElement('selectyesno', 'forcenewattempt', get_string('forcenewattempt', 'scorm'));
         $mform->addHelpButton('forcenewattempt', 'forcenewattempt', 'scorm');
         $mform->setDefault('forcenewattempt', $cfg_scorm->forcenewattempt);
         $mform->setAdvanced('forcenewattempt', $cfg_scorm->forcenewattempt_adv);
 
-        // Last attempt lock - lock the enter button after the last available attempt has been made
+        // Last attempt lock - lock the enter button after the last available attempt has been made.
         $mform->addElement('selectyesno', 'lastattemptlock', get_string('lastattemptlock', 'scorm'));
         $mform->addHelpButton('lastattemptlock', 'lastattemptlock', 'scorm');
         $mform->setDefault('lastattemptlock', $cfg_scorm->lastattemptlock);
         $mform->setAdvanced('lastattemptlock', $cfg_scorm->lastattemptlock_adv);
 
-        // Activation period
+        // Activation period.
 /*        $mform->addElement('static', '', '' ,'<hr />');
         $mform->addElement('static', 'activation', get_string('activation','scorm'));
         $datestartgrp = array();
@@ -239,14 +239,14 @@ class mod_scorm_mod_form extends moodleform_mod {
         $mform->disabledIf('dateendgrp', 'enddisabled', 'checked');
 */
 
-        // Autocontinue
+        // Autocontinue.
         $mform->addElement('selectyesno', 'auto', get_string('autocontinue', 'scorm'));
         $mform->addHelpButton('auto', 'autocontinue', 'scorm');
         $mform->setDefault('auto', $cfg_scorm->auto);
         $mform->setAdvanced('auto', $cfg_scorm->auto_adv);
 
         if (count($scormtypes) > 1) {
-            // Update packages timing
+            // Update packages timing.
             $mform->addElement('select', 'updatefreq', get_string('updatefreq', 'scorm'), scorm_get_updatefreq_array());
             $mform->setDefault('updatefreq', $cfg_scorm->updatefreq);
             $mform->setAdvanced('updatefreq', $cfg_scorm->updatefreq_adv);
@@ -256,7 +256,7 @@ class mod_scorm_mod_form extends moodleform_mod {
             $mform->addElement('hidden', 'updatefreq', 0);
         }
         //-------------------------------------------------------------------------------
-        // Hidden Settings
+        // Hidden Settings.
         $mform->addElement('hidden', 'datadir', null);
         $mform->setType('datadir', PARAM_RAW);
         $mform->addElement('hidden', 'pkgtype', null);
@@ -271,7 +271,7 @@ class mod_scorm_mod_form extends moodleform_mod {
         //-------------------------------------------------------------------------------
         $this->standard_coursemodule_elements();
         //-------------------------------------------------------------------------------
-        // buttons
+        // Buttons.
         $this->add_action_buttons();
     }
 
@@ -324,7 +324,7 @@ class mod_scorm_mod_form extends moodleform_mod {
             $default_values['timeclose'] = 0;
         }
 
-        // Set some completion default data
+        // Set some completion default data.
         if (!empty($default_values['completionstatusrequired']) && !is_array($default_values['completionstatusrequired'])) {
             // Unpack values
             $cvalues = array();
@@ -351,7 +351,7 @@ class mod_scorm_mod_form extends moodleform_mod {
 
         if ($type === SCORM_TYPE_LOCAL) {
             if (!empty($data['update'])) {
-                //ok, not required
+                // OK, not required.
 
             } else if (empty($data['packagefile'])) {
                 $errors['packagefile'] = get_string('required');
@@ -419,7 +419,7 @@ class mod_scorm_mod_form extends moodleform_mod {
         return $errors;
     }
 
-    //need to translate the "options" and "reference" field.
+    // Need to translate the "options" and "reference" field.
     function set_data($default_values) {
         $default_values = (array)$default_values;
 
@@ -452,7 +452,7 @@ class mod_scorm_mod_form extends moodleform_mod {
         $mform =& $this->_form;
         $items = array();
 
-        // Require score
+        // Require score.
         $group = array();
         $group[] =& $mform->createElement('text', 'completionscorerequired', '', array('size' => 5));
         $group[] =& $mform->createElement('checkbox', 'completionscoredisabled', null, get_string('disable'));
@@ -465,7 +465,7 @@ class mod_scorm_mod_form extends moodleform_mod {
         $items[] = 'completionscoregroup';
 
 
-        // Require status
+        // Require status.
         $first = true;
         $firstkey = null;
         foreach (scorm_status_options(true) as $key => $value) {
@@ -499,18 +499,22 @@ class mod_scorm_mod_form extends moodleform_mod {
             return false;
         }
 
+        // Convert completionstatusrequired to a proper integer, if any.
+        $total = 0;
+        if (isset($data->completionstatusrequired) && is_array($data->completionstatusrequired)) {
+            foreach (array_keys($data->completionstatusrequired) as $state) {
+                $total |= $state;
+            }
+            $data->completionstatusrequired = $total;
+        }
+
         if (!empty($data->completionunlocked)) {
-            // Turn off completion settings if the checkboxes aren't ticked
+            // Turn off completion settings if the checkboxes aren't ticked.
             $autocompletion = isset($data->completion) && $data->completion == COMPLETION_TRACKING_AUTOMATIC;
 
-            if (isset($data->completionstatusrequired) &&
-                    is_array($data->completionstatusrequired) && $autocompletion) {
-                $total = 0;
-                foreach (array_keys($data->completionstatusrequired) as $state) {
-                    $total |= $state;
-                }
-
-                $data->completionstatusrequired = $total;
+            if (isset($data->completionstatusrequired) && $autocompletion) {
+                // Do nothing: completionstatusrequired has been already converted
+                //             into a correct integer representation.
             } else {
                 $data->completionstatusrequired = null;
             }
index 979b432..e66c434 100644 (file)
@@ -24,10 +24,10 @@ class note_edit_form extends moodleform {
         $this->add_action_buttons();
 
         $mform->addElement('hidden', 'courseid');
-        $mform->setType('course', PARAM_INT);
+        $mform->setType('courseid', PARAM_INT);
 
         $mform->addElement('hidden', 'userid');
-        $mform->setType('user', PARAM_INT);
+        $mform->setType('userid', PARAM_INT);
 
         $mform->addElement('hidden', 'id');
         $mform->setType('id', PARAM_INT);
index 6071430..16f8f30 100644 (file)
@@ -38,6 +38,7 @@
         </testsuite>
         <testsuite name="core_files">
             <directory suffix="_test.php">lib/filestorage/tests</directory>
+            <directory suffix="_test.php">files/tests</directory>
         </testsuite>
         <testsuite name="core_grade">
             <directory suffix="_test.php">lib/grade/tests</directory>
diff --git a/question/behaviour/manualgraded/db/install.php b/question/behaviour/manualgraded/db/install.php
new file mode 100644 (file)
index 0000000..7818769
--- /dev/null
@@ -0,0 +1,49 @@
+<?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/>.
+
+/**
+ * Post-install script for manual graded question behaviour.
+ * @package   qbehaviour_manualgraded
+ * @copyright 2013 The Open Universtiy
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Post-install script
+ */
+function xmldb_qbehaviour_manualgraded_install() {
+
+    // Hide the manualgraded behaviour from the list of behaviours that users
+    // can select in the user-interface. If a user accidentally chooses manual
+    // graded behaviour for a quiz, there is no way to get the questions automatically
+    // graded after the student has answered them. If teachers really want to do
+    // this they can ask their admin to enable it on the manage behaviours
+    // screen in the UI.
+    $disabledbehaviours = get_config('question', 'disabledbehaviours');
+    if (!empty($disabledbehaviours)) {
+        $disabledbehaviours = explode(',', $disabledbehaviours);
+    } else {
+        $disabledbehaviours = array();
+    }
+    if (array_search('manualgraded', $disabledbehaviours) === false) {
+        $disabledbehaviours[] = 'manualgraded';
+        set_config('disabledbehaviours', implode(',', $disabledbehaviours), 'question');
+    }
+}
diff --git a/question/behaviour/manualgraded/db/upgrade.php b/question/behaviour/manualgraded/db/upgrade.php
new file mode 100644 (file)
index 0000000..635a8e7
--- /dev/null
@@ -0,0 +1,91 @@
+<?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/>.
+
+/**
+ * Post-install script for the manual graded question behaviour.
+ *
+ * @package   qbehaviour_manualgraded
+ * @copyright 2013 The Open Universtiy
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Manual graded question behaviour upgrade code.
+ */
+function xmldb_qbehaviour_manualgraded_upgrade($oldversion) {
+    global $CFG, $DB;
+
+    $dbman = $DB->get_manager();
+
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+    if ($oldversion < 2012061701) {
+        // Hide the manualgraded behaviour from the list of behaviours that users
+        // can select in the user-interface. If a user accidentally chooses manual
+        // graded behaviour for a quiz, there is no way to get the questions automatically
+        // graded after the student has answered them. If teachers really want to do
+        // this they can ask their admin to enable it on the manage behaviours
+        // screen in the UI.
+        $disabledbehaviours = get_config('question', 'disabledbehaviours');
+        if (!empty($disabledbehaviours)) {
+            $disabledbehaviours = explode(',', $disabledbehaviours);
+        } else {
+            $disabledbehaviours = array();
+        }
+        if (array_search('manualgraded', $disabledbehaviours) === false) {
+            $disabledbehaviours[] = 'manualgraded';
+            set_config('disabledbehaviours', implode(',', $disabledbehaviours), 'question');
+        }
+
+        // Manual graded question behaviour savepoint reached.
+        upgrade_plugin_savepoint(true, 2012061701, 'qbehaviour', 'manualgraded');
+    }
+
+    if ($oldversion < 2012061702) {
+        // Also, fix any other admin settings that currently select manualgraded behaviour.
+
+        // Work out a sensible default alternative to manualgraded.
+        require_once($CFG->libdir . '/questionlib.php');
+        $behaviours = question_engine::get_behaviour_options('');
+        if (array_key_exists('deferredfeedback', $behaviours)) {
+             $defaultbehaviour = 'deferredfeedback';
+        } else {
+            reset($behaviours);
+            $defaultbehaviour = key($behaviours);
+        }
+
+        // Fix the question preview default.
+        if (get_config('question_preview', 'behaviour') == 'manualgraded') {
+            set_config('behaviour', $defaultbehaviour, 'question_preview');
+        }
+
+        // Fix the quiz settings default.
+        if (get_config('quiz', 'preferredbehaviour') == 'manualgraded') {
+            set_config('preferredbehaviour', $defaultbehaviour, 'quiz');
+        }
+
+        // Manual graded question behaviour savepoint reached.
+        upgrade_plugin_savepoint(true, 2012061702, 'qbehaviour', 'manualgraded');
+    }
+
+    return true;
+}
+
index 897af13..4c8ffc4 100644 (file)
@@ -26,7 +26,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 $plugin->component = 'qbehaviour_manualgraded';
-$plugin->version   = 2012061700;
+$plugin->version   = 2012061702;
 
 $plugin->requires  = 2012061700;
 
index 19ad588..f85eff6 100644 (file)
@@ -82,7 +82,7 @@ class qtype_essay_question extends question_with_responses {
     }
 
     public function is_complete_response(array $response) {
-        return !empty($response['answer']);
+        return array_key_exists('answer', $response) && ($response['answer'] !== '');
     }
 
     public function is_same_response(array $prevresponse, array $newresponse) {
index 6381a6d..24a2231 100644 (file)
@@ -49,4 +49,19 @@ class qtype_essay_question_test extends advanced_testcase {
         $this->assertEquals($longstring,
                 $essay->summarise_response(array('answer' => $longstring)));
     }
+
+    public function test_is_complete_response() {
+
+        $essay = test_question_maker::make_an_essay_question();
+        $essay->start_attempt(new question_attempt_step(), 1);
+
+        // The empty string should be considered an empty response, as should a lack of a response.
+        $this->assertFalse($essay->is_complete_response(array('answer' => '')));
+        $this->assertFalse($essay->is_complete_response(array()));
+
+        // Any nonempty string should be considered a complete response.
+        $this->assertTrue($essay->is_complete_response(array('answer' => 'A student response.')));
+        $this->assertTrue($essay->is_complete_response(array('answer' => '0 times.')));
+        $this->assertTrue($essay->is_complete_response(array('answer' => '0')));
+    }
 }
index c98e0ec..0a151a0 100644 (file)
@@ -2796,6 +2796,7 @@ final class repository_instance_form extends moodleform {
         $instance = (isset($this->_customdata['instance'])
                 && is_subclass_of($this->_customdata['instance'], 'repository'))
             ? $this->_customdata['instance'] : null;
+
         if (!$instance) {
             $errors = repository::static_function($plugin, 'instance_form_validation', $this, $data, $errors);
         } else {
@@ -2806,6 +2807,10 @@ final class repository_instance_form extends moodleform {
                   FROM {repository_instances} i, {repository} r
                  WHERE r.type=:plugin AND r.id=i.typeid AND i.name=:name AND i.contextid=:contextid";
         $params = array('name' => $data['name'], 'plugin' => $this->plugin, 'contextid' => $this->contextid);
+        if ($instance) {
+            $sql .= ' AND i.id != :instanceid';
+            $params['instanceid'] = $instance->id;
+        }
         if ($DB->count_records_sql($sql, $params) > 0) {
             $errors['name'] = get_string('erroruniquename', 'repository');
         }
index 50ccadb..72fac5d 100644 (file)
@@ -231,11 +231,6 @@ a.skip:active {position: static;display: block;}
 .mform .ftags select {margin-bottom: 0.7em;min-width: 22em;}
 
 input#id_externalurl {direction:ltr;}
-
-/** Browser corrections for mforms **/
-.ie .mform .fitem .felement {margin-left:0;text-align:left;float:left;}
-/** Fix IE double margin + float bugs **/
-.ie .mform .fitem .fitemtitle {padding-right:1em;}
 #portfolio-add-button {display:inline;}
 
 /**
@@ -629,11 +624,6 @@ body.tag .managelink {padding: 5px;}
 .corelightbox {background-color:#CCC;position:absolute;top:0;left:0;width:100%;height:100%;text-align:center;}
 .corelightbox img {position:fixed;top:50%;}
 
-/**
- * IE - Overide for RTL layout
- */
-.ie.dir-rtl .mform .fitem .felement {margin-right:0;text-align:right;float:right;}
-
 .mod-indent-1 {margin-left:20px;}
 .mod-indent-2 {margin-left:40px;}
 .mod-indent-3 {margin-left:60px;}
index e12091f..2cde03a 100644 (file)
@@ -70,7 +70,7 @@ echo $OUTPUT->doctype() ?>
                 </div>
 
                 <?php if ($hassidepre) { ?>
-                <div id="region-pre">
+                <div id="region-pre" class="block-region">
                     <div class="region-content">
                         <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
                     </div>
@@ -78,7 +78,7 @@ echo $OUTPUT->doctype() ?>
                 <?php } ?>
 
                 <?php if ($hassidepost) { ?>
-                <div id="region-post">
+                <div id="region-post" class="block-region">
                     <div class="region-content">
                         <?php echo $OUTPUT->blocks_for_region('side-post') ?>
                     </div>
@@ -102,7 +102,7 @@ echo $OUTPUT->doctype() ?>
 
 if ($hasheading || $hasnavbar) { ?>
 
-       <div class="myclear"></div>
+    <div class="myclear"></div>
   </div> <!-- END #page -->
 
 </div> <!-- END #page-wrapper -->
index 7d63694..8abc8fc 100644 (file)
@@ -79,7 +79,7 @@ echo $OUTPUT->doctype() ?>
                 </div>
 
                 <?php if ($hassidepre) { ?>
-                <div id="region-pre">
+                <div id="region-pre" class="block-region">
                     <div class="region-content">
                         <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
                     </div>
@@ -87,7 +87,7 @@ echo $OUTPUT->doctype() ?>
                 <?php } ?>
 
                 <?php if ($hassidepost) { ?>
-                <div id="region-post">
+                <div id="region-post" class="block-region">
                     <div class="region-content">
                         <?php echo $OUTPUT->blocks_for_region('side-post') ?>
                     </div>
index 76d88ae..ca4db09 100644 (file)
@@ -31,16 +31,16 @@ echo $OUTPUT->doctype() ?>
 <!-- START OF HEADER -->
 
     <div id="page-header" class="clearfix">
-               <div id="page-header-wrapper">
-               <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
-           <div class="headermenu">
-                       <?php
-                           echo $OUTPUT->login_info();
-                       echo $OUTPUT->lang_menu();
-                           echo $PAGE->headingmenu;
-                       ?>
-               </div>
-           </div>
+        <div id="page-header-wrapper">
+            <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
+            <div class="headermenu">
+                <?php
+                    echo $OUTPUT->login_info();
+                    echo $OUTPUT->lang_menu();
+                    echo $PAGE->headingmenu;
+                ?>
+            </div>
+        </div>
     </div>
 
     <?php if ($hascustommenu) { ?>
@@ -49,7 +49,7 @@ echo $OUTPUT->doctype() ?>
       <ul id="page-navigation" class="clearfix">
         <li>&nbsp;</li>
       </ul>
-       <?php } ?>
+    <?php } ?>
 
 <!-- END OF HEADER -->
 
@@ -69,7 +69,7 @@ echo $OUTPUT->doctype() ?>
                 </div>
 
                 <?php if ($hassidepre) { ?>
-                <div id="region-pre">
+                <div id="region-pre" class="block-region">
                     <div class="region-content">
                         <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
                     </div>
@@ -77,7 +77,7 @@ echo $OUTPUT->doctype() ?>
                 <?php } ?>
 
                 <?php if ($hassidepost) { ?>
-                <div id="region-post">
+                <div id="region-post" class="block-region">
                     <div class="region-content">
                         <?php echo $OUTPUT->blocks_for_region('side-post') ?>
                     </div>
index 7d4b519..5910315 100644 (file)
@@ -33,22 +33,22 @@ echo $OUTPUT->doctype() ?>
 <?php if ($hasheading || $hasnavbar) { ?>
 
     <div id="page-header" class="clearfix">
-               <div id="page-header-wrapper">
-
-               <?php if ($hasheading) { ?>
-                       <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
-                   <div class="headermenu">
-                               <?php
-                               echo $OUTPUT->login_info();
-                                       if (!empty($PAGE->layout_options['langmenu'])) {
-                                       echo $OUTPUT->lang_menu();
-                                   }
-                               echo $PAGE->headingmenu
-                               ?>
-                       </div>
-               <?php } ?>
-
-           </div>
+        <div id="page-header-wrapper">
+
+            <?php if ($hasheading) { ?>
+                <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
+                <div class="headermenu">
+                    <?php
+                        echo $OUTPUT->login_info();
+                        if (!empty($PAGE->layout_options['langmenu'])) {
+                            echo $OUTPUT->lang_menu();
+                        }
+                        echo $PAGE->headingmenu
+                    ?>
+                </div>
+            <?php } ?>
+
+        </div>
     </div>
 
     <?php if ($hasheading) { ?>
@@ -59,11 +59,11 @@ echo $OUTPUT->doctype() ?>
           <li>&nbsp;</li>
         </ul>
       <?php } ?>
-       <?php } ?>
+    <?php } ?>
 
     <?php if ($hasnavbar) { ?>
-           <div class="navbar clearfix">
-           <div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
+        <div class="navbar clearfix">
+            <div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
             <div class="navbutton"> <?php echo $PAGE->button; ?></div>
         </div>
     <?php } ?>
@@ -85,7 +85,7 @@ echo $OUTPUT->doctype() ?>
                 </div>
 
                 <?php if ($hassidepre) { ?>
-                <div id="region-pre">
+                <div id="region-pre" class="block-region">
                     <div class="region-content">
                         <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
                     </div>
@@ -93,7 +93,7 @@ echo $OUTPUT->doctype() ?>
                 <?php } ?>
 
                 <?php if ($hassidepost) { ?>
-                <div id="region-post">
+                <div id="region-post" class="block-region">
                     <div class="region-content">
                         <?php echo $OUTPUT->blocks_for_region('side-post') ?>
                     </div>
index 1ddeb26..e9baecf 100644 (file)
@@ -103,7 +103,7 @@ if ($rev > -1) {
             header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
             header('Cache-Control: public, max-age='.$lifetime);
             header('Content-Type: '.$mimetype);
-            header('Etag: '.$etag);
+            header('Etag: "'.$etag.'"');
             die;
         }
         send_cached_image($cacheimage, $etag);
@@ -184,7 +184,7 @@ function send_cached_image($imagepath, $etag) {
 
     $mimetype = get_contenttype_from_ext($pathinfo['extension']);
 
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     header('Content-Disposition: inline; filename="'.$imagename.'"');
     header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($imagepath)) .' GMT');
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
index 253d320..92264ae 100644 (file)
@@ -11,7 +11,6 @@ body.pagelayout-admin.has_dock {
 }
 .pagelayout-admin #page-footer {
     float: none;
-    background: #f3f3f3 none;
     width: 100%;
     margin: 0;
     padding: 0;
index 6f4f49e..60971e9 100644 (file)
@@ -61,7 +61,7 @@ if (strpos($parts, '/-1/') === false and (!empty($_SERVER['HTTP_IF_NONE_MATCH'])
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
     header('Cache-Control: public, max-age='.$lifetime);
     header('Content-Type: '.$mimetype);
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     die;
 }
 
@@ -170,7 +170,7 @@ function combo_send_cached($content, $mimetype, $etag, $lastmodified) {
     header('Cache-Control: public, max-age='.$lifetime);
     header('Accept-Ranges: none');
     header('Content-Type: '.$mimetype);
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     if (!min_enable_zlib_compression()) {
         header('Content-Length: '.strlen($content));
     }
index dd092d6..4955936 100644 (file)
@@ -92,7 +92,7 @@ if (strpos($path, '/-1/') === false and (!empty($_SERVER['HTTP_IF_NONE_MATCH'])
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
     header('Cache-Control: public, max-age='.$lifetime);
     header('Content-Type: '.$mimetype);
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     die;
 }
 
@@ -113,7 +113,7 @@ function yui_image_cached($imagepath, $imagename, $mimetype, $etag) {
     header('Accept-Ranges: none');
     header('Content-Type: '.$mimetype);
     header('Content-Length: '.filesize($imagepath));
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
 
     if (xsendfile($imagepath)) {
         die;
index bfa603d..7aa5e2d 100644 (file)
         $PAGE->requires->js_init_call('M.core_user.init_participation', null, false, $module);
     }
 
-    if (has_capability('moodle/site:viewparticipants', $context) && $totalcount > ($perpage*3)) {
+    // Show a search box if all participants don't fit on a single screen
+    if ($totalcount > $perpage) {
         echo '<form action="index.php" class="searchform"><div><input type="hidden" name="id" value="'.$course->id.'" />';
         echo '<label for="search">' . get_string('search', 'search') . ' </label>';
         echo '<input type="text" id="search" name="search" value="'.s($search).'" />&nbsp;<input type="submit" value="'.get_string('search').'" /></div></form>'."\n";
index d6f502f..3e35951 100644 (file)
@@ -56,12 +56,14 @@ if (!empty($CFG->forceloginforprofiles)) {
 }
 
 $userid = $userid ? $userid : $USER->id;       // Owner of the page
-$user = $DB->get_record('user', array('id' => $userid));
-
-if ($user->deleted) {
-    $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
+if ((!$user = $DB->get_record('user', array('id' => $userid))) || ($user->deleted)) {
+    $PAGE->set_context(context_system::instance());
     echo $OUTPUT->header();
-    echo $OUTPUT->notification(get_string('userdeleted'));
+    if (!$user) {
+        echo $OUTPUT->notification(get_string('invaliduser', 'error'));
+    } else {
+        echo $OUTPUT->notification(get_string('userdeleted'));
+    }
     echo $OUTPUT->footer();
     die;
 }
@@ -97,7 +99,7 @@ if (!$currentpage->userid) {
 }
 
 $PAGE->set_context($context);
-$PAGE->set_pagelayout('mydashboard');
+$PAGE->set_pagelayout('mypublic');
 $PAGE->set_pagetype('user-profile');
 
 // Set up block editing capabilities
index 120fb78..f1bd9d3 100644 (file)
@@ -270,6 +270,7 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
                     option.set('selected', true);
                 }
             } else {
+                optgroup.set('label', groupname);
                 optgroup.append(Y.Node.create('<option disabled="disabled">\u00A0</option>'));
             }
             this.listbox.append(optgroup);
@@ -374,4 +375,4 @@ M.core_user.init_user_selector_options_tracker = function(Y) {
     user_selector_options_tracker.init();
     // Return it just incase it is ever wanted
     return user_selector_options_tracker;
-};
\ No newline at end of file
+};
index fc714a2..da0bb86 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
-
-$version  = 2012062507.04;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062507.08;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.7+ (Build: 20130606)';  // Human-friendly version name
+$release  = '2.3.7+ (Build: 20130627)';  // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level