Merge branch 'wip-MDL-29487-master' of git://github.com/samhemelryk/moodle
authorAparup Banerjee <aparup@moodle.com>
Mon, 26 Sep 2011 08:00:04 +0000 (16:00 +0800)
committerAparup Banerjee <aparup@moodle.com>
Mon, 26 Sep 2011 08:00:04 +0000 (16:00 +0800)
31 files changed:
admin/tool/unittest/styles.css [new file with mode: 0644]
admin/tool/xmldb/actions/check_oracle_semantics/check_oracle_semantics.class.php [new file with mode: 0644]
admin/tool/xmldb/actions/main_view/main_view.class.php
admin/tool/xmldb/lang/en/tool_xmldb.php
blog/lib.php
blog/simpletest/testbloglib.php
grade/import/xml/grade_import_form.php
lib/form/filemanager.js
lib/form/filemanager.php
lib/form/filepicker.js
lib/form/filepicker.php
lib/form/recaptcha.php
lib/formslib.php
lib/simpletest/testpagelib_moodlepage.php
mod/feedback/delete_template.php
mod/feedback/import.php
mod/feedback/show_entries.php
mod/feedback/show_entries_anonym.php
mod/feedback/show_nonrespondents.php
mod/quiz/addrandom.php
mod/quiz/lang/en/quiz.php
mod/workshop/form/numerrors/lib.php
question/format/xml/simpletest/testxmlformat.php
question/previewlib.php
question/type/edit_question_form.php
rating/lib.php
rating/module.js
rating/simpletest/testrating.php
theme/base/style/admin.css
theme/standard/style/admin.css
version.php

diff --git a/admin/tool/unittest/styles.css b/admin/tool/unittest/styles.css
new file mode 100644 (file)
index 0000000..8e51d71
--- /dev/null
@@ -0,0 +1,9 @@
+#page-admin-tool-unittest-index .exception pre {padding: 8px;}
+#page-admin-tool-unittest-index .unittestsummary {padding: 8px;margin-top: 1em;}
+#page-admin-tool-unittest-index span.notice {color: teal;}
+#page-admin-tool-unittest-index b.pass {color: green;}
+#page-admin-tool-unittest-index b.fail, b.exception {color: red;}
+#page-admin-tool-unittest-index .exception, .exception pre {background-color: #FDD;}
+#page-admin-tool-unittest-index .unittestsummary {color: white;}
+#page-admin-tool-unittest-index .unittestsummary.failed {background-color: red;}
+#page-admin-tool-unittest-index .unittestsummary.passed {background-color: green;}
diff --git a/admin/tool/xmldb/actions/check_oracle_semantics/check_oracle_semantics.class.php b/admin/tool/xmldb/actions/check_oracle_semantics/check_oracle_semantics.class.php
new file mode 100644 (file)
index 0000000..97248cd
--- /dev/null
@@ -0,0 +1,153 @@
+<?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   xmldb-editor
+ * @copyright 2011 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * This class will check all the varchar2() columns
+ * in the Moodle installed DB, looking for incorrect (INT)
+ * length semanticas providing one SQL script to fix all
+ * them by changing to cross-db (CHAR) length semantics.
+ * See MDL-29322 for more details.
+ *
+ * @package   xmldb-editor
+ * @copyright 2011 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class check_oracle_semantics extends XMLDBCheckAction {
+
+    /**
+     * Init method, every subclass will have its own
+     */
+    function init() {
+        $this->introstr = 'confirmcheckoraclesemantics';
+        parent::init();
+
+        // Set own core attributes
+
+        // Set own custom attributes
+
+        // Get needed strings
+        $this->loadStrings(array(
+            'wrongoraclesemantics' => 'tool_xmldb',
+            'nowrongoraclesemanticsfound' => 'tool_xmldb',
+            'yeswrongoraclesemanticsfound' => 'tool_xmldb',
+            'expected' => 'tool_xmldb',
+            'actual' => 'tool_xmldb',
+        ));
+    }
+
+    protected function check_table(xmldb_table $xmldb_table, array $metacolumns) {
+        global $DB;
+        $o = '';
+        $wrong_fields = array();
+
+        // Get and process XMLDB fields
+        if ($xmldb_fields = $xmldb_table->getFields()) {
+            $o .= '<ul>';
+            foreach ($xmldb_fields as $xmldb_field) {
+
+                // Get the type of the column, we only will process CHAR (VARCHAR2) ones
+                if ($xmldb_field->getType() != XMLDB_TYPE_CHAR) {
+                    continue;
+                }
+
+                $o.='<li>' . $this->str['field'] . ': ' . $xmldb_field->getName() . ' ';
+
+                // Get current semantic from dictionary, we only will process B (BYTE) ones
+                // suplying the SQL code to change them to C (CHAR) semantic
+                $params = array(
+                    'table_name' => textlib::strtoupper($DB->get_prefix() . $xmldb_table->getName()),
+                    'column_name' => textlib::strtoupper($xmldb_field->getName()),
+                    'data_type' => 'VARCHAR2');
+                $currentsemantic = $DB->get_field_sql('
+                    SELECT char_used
+                      FROM user_tab_columns
+                     WHERE table_name = :table_name
+                       AND column_name = :column_name
+                       AND data_type = :data_type', $params);
+
+                // If using byte semantics, we'll need to change them to char semantics
+                if ($currentsemantic == 'B') {
+                    $info = '(' . $this->str['expected'] . " 'CHAR', " . $this->str['actual'] . " 'BYTE')";
+                    $o .= '<font color="red">' . $this->str['wrong'] . " $info</font>";
+                    // Add the wrong field to the list
+                    $obj = new stdClass();
+                    $obj->table = $xmldb_table;
+                    $obj->field = $xmldb_field;
+                    $wrong_fields[] = $obj;
+                } else {
+                    $o .= '<font color="green">' . $this->str['ok'] . '</font>';
+                }
+                $o .= '</li>';
+            }
+            $o .= '</ul>';
+        }
+
+        return array($o, $wrong_fields);
+    }
+
+    protected function display_results(array $wrong_fields) {
+        global $DB;
+        $dbman = $DB->get_manager();
+
+        $s = '';
+        $r = '<table class="generalbox boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
+        $r.= '  <tr><td class="generalboxcontent">';
+        $r.= '    <h2 class="main">' . $this->str['searchresults'] . '</h2>';
+        $r.= '    <p class="centerpara">' . $this->str['wrongoraclesemantics'] . ': ' . count($wrong_fields) . '</p>';
+        $r.= '  </td></tr>';
+        $r.= '  <tr><td class="generalboxcontent">';
+
+        // If we have found wrong defaults inform about them
+        if (count($wrong_fields)) {
+            $r.= '    <p class="centerpara">' . $this->str['yeswrongoraclesemanticsfound'] . '</p>';
+            $r.= '        <ul>';
+            foreach ($wrong_fields as $obj) {
+                $xmldb_table = $obj->table;
+                $xmldb_field = $obj->field;
+
+                $r.= '            <li>' . $this->str['table'] . ': ' . $xmldb_table->getName() . '. ' .
+                                          $this->str['field'] . ': ' . $xmldb_field->getName() . ', ' .
+                                          $this->str['expected'] . ' ' . "'CHAR'" . ' ' .
+                                          $this->str['actual'] . ' ' . "'BYTE'" . '</li>';
+
+                $sql = 'ALTER TABLE ' . $DB->get_prefix() . $xmldb_table->getName() . ' MODIFY ' .
+                       $xmldb_field->getName() . ' VARCHAR2(' . $xmldb_field->getLength() . ' CHAR)';
+                $sql = $dbman->generator->getEndedStatements($sql);
+                $s.= '<code>' . str_replace("\n", '<br />', $sql) . '</code><br />';
+            }
+            $r.= '        </ul>';
+            // Add the SQL statements (all together)
+            $r.= '<hr />' . $s;
+        } else {
+            $r.= '    <p class="centerpara">' . $this->str['nowrongoraclesemanticsfound'] . '</p>';
+        }
+        $r.= '  </td></tr>';
+        $r.= '  <tr><td class="generalboxcontent">';
+        // Add the complete log message
+        $r.= '    <p class="centerpara">' . $this->str['completelogbelow'] . '</p>';
+        $r.= '  </td></tr>';
+        $r.= '</table>';
+
+        return $r;
+    }
+}
index 833cea1..73d6b9f 100644 (file)
@@ -58,6 +58,7 @@ class main_view extends XMLDBAction {
             'checkdefaults' => 'tool_xmldb',
             'checkforeignkeys' => 'tool_xmldb',
             'checkbigints' => 'tool_xmldb',
+            'checkoraclesemantics' => 'tool_xmldb',
             'doc' => 'tool_xmldb',
             'viewxml' => 'tool_xmldb',
             'pendingchangescannotbesavedreload' => 'tool_xmldb'
@@ -105,6 +106,10 @@ class main_view extends XMLDBAction {
         if ($DB->get_dbfamily() == 'mysql' || $DB->get_dbfamily() == 'postgres') {
             $b .= '&nbsp;<a href="index.php?action=check_bigints&amp;sesskey=' . sesskey() . '">[' . $this->str['checkbigints'] . ']</a>';
         }
+    /// The check semantics button (only for Oracle) MDL-29416
+        if ($DB->get_dbfamily() == 'oracle') {
+            $b .= '&nbsp;<a href="index.php?action=check_oracle_semantics&amp;sesskey=' . sesskey() . '">[' . $this->str['checkoraclesemantics'] . ']</a>';
+        }
         $b .= '&nbsp;<a href="index.php?action=check_foreign_keys&amp;sesskey=' . sesskey() . '">[' . $this->str['checkforeignkeys'] . ']</a>';
         $b .= '</p>';
     /// Send buttons to output
index d95ca7c..1c2a350 100644 (file)
@@ -50,6 +50,10 @@ $string['confirmcheckindexes'] = 'This functionality will search for potential m
 Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).<br /><br />
 It\'s highly recommended to be running the latest (+ version) available of your Moodle release (1.8, 1.9, 2.x ...) before executing the search of missing indexes.<br /><br />
 This functionality doesn\'t perform any action against the DB (just reads from it), so can be safely executed at any moment.';
+$string['confirmcheckoraclesemantics'] = 'This functionality will search for <a href="http://tracker.moodle.org/browse/MDL-29322">Oracle varchar2 columns using BYTE semantics</a> in your Moodle server, generating (but not executing!) automatically the needed SQL statements to have all the columns converted to use CHAR semantics instead (better for cross-db compatibility and increased contents max. length).<br /><br />
+Once generated you can copy such statements and execute them safely with your favourite SQL interface (don\'t forget to backup your data before doing that).<br /><br />
+It\'s highly recommended to be running the latest (+ version) available of your Moodle release (2.2, 2.3, 2.x ...) before executing the search of BYTE semantics.<br /><br />
+This functionality doesn\'t perform any action against the DB (just reads from it), so can be safely executed at any moment.';
 $string['confirmrevertchanges'] = 'Are you absolutely sure that you want to revert changes performed over:';
 $string['create'] = 'Create';
 $string['createtable'] = 'Create table:';
@@ -103,6 +107,8 @@ $string['checkforeignkeys'] = 'Check foreign keys';
 $string['check_foreign_keys'] = 'Look for foreign key violations';
 $string['checkindexes'] = 'Check indexes';
 $string['check_indexes'] = 'Look for missing DB indexes';
+$string['checkoraclesemantics'] = 'Check semantics';
+$string['check_oracle_semantics'] = 'Look for incorrect length semantics';
 $string['incorrectfieldname'] = 'Incorrect name';
 $string['index'] = 'Index';
 $string['indexes'] = 'Indexes';
@@ -130,6 +136,7 @@ $string['nomissingindexesfound'] = 'No missing indexes have been found, your DB
 $string['noviolatedforeignkeysfound'] = 'No violated foreign keys found';
 $string['nowrongdefaultsfound'] = 'No inconsistent default values have been found, your DB does not need further actions.';
 $string['nowrongintsfound'] = 'No wrong integers have been found, your DB doesn\'t need further actions.';
+$string['nowrongoraclesemanticsfound'] = 'No Oracle columns using BYTE semantics have been found, your DB doesn\'t need further actions.';
 $string['numberincorrectdecimals'] = 'Incorrect number of decimals for number field';
 $string['numberincorrectlength'] = 'Incorrect length for number field';
 $string['pendingchanges'] = 'Note: You have performed changes to this file. They can be saved at any moment.';
@@ -172,6 +179,8 @@ $string['wrongdefaults'] = 'Wrong defaults found';
 $string['wrongints'] = 'Wrong integers found';
 $string['wronglengthforenum'] = 'Incorrect length for enum field';
 $string['wrongreservedwords'] = 'Currently used reserved words<br />(note that table names aren\'t important if using $CFG->prefix)';
+$string['wrongoraclesemantics'] = 'Wrong Oracle BYTE semantics found';
 $string['yesmissingindexesfound'] = 'Some missing indexes have been found in your DB. Here are their details and the needed SQL statements to be executed with your favourite SQL interface to create all them (don\'t forget to backup your data before doing that).<br /><br />After doing that, it\'s highly recommended to execute this utility again to check that no more missing indexes are found.';
 $string['yeswrongdefaultsfound'] = 'Some inconsistent defaults have been found in your DB. Here are their details and the needed SQL statements to be executed with your favourite SQL interface to fix them all (don\'t forget to backup your data before doing that).<br /><br />After doing that, it\'s highly recommended to execute this utility again to check that no more inconsistent defaults are found.';
 $string['yeswrongintsfound'] = 'Some wrong integers have been found in your DB. Here are their details and the needed SQL statements to be executed with your favourite SQL interface to create all them (don\'t forget to backup your data before doing that).<br /><br />After doing that, it\'s highly recommended to execute this utility again to check that no more wrong integers are found.';
+$string['yeswrongoraclesemanticsfound'] = 'Some Oracle columns using BYTE semantics have been found in your DB. Here are their details and the needed SQL statements to be executed with your favourite SQL interface to create all them (don\'t forget to backup your data before doing that).<br /><br />After doing that, it\'s highly recommended to execute this utility again to check that no more wrong semantics are found.';
index e247e4d..49ccdc6 100644 (file)
@@ -844,7 +844,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
 
         $a = new stdClass();
         $a->user = fullname($user);
-        $a->course = format_string($course->fullname, true, array('context' => get_context_instance(CONTEXT_COURSE, $courseid)));
+        $a->course = format_string($course->fullname, true, array('context' => get_context_instance(CONTEXT_COURSE, $course->id)));
         $a->type = get_string('course');
         $headers['heading'] = get_string('blogentriesbyuseraboutcourse', 'blog', $a);
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
@@ -870,7 +870,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
 
         $a = new stdClass();
         $a->group = $group->name;
-        $a->course = format_string($course->fullname, true, array('context' => get_context_instance(CONTEXT_COURSE, $courseid)));
+        $a->course = format_string($course->fullname, true, array('context' => get_context_instance(CONTEXT_COURSE, $course->id)));
         $a->type = get_string('course');
         $headers['heading'] = get_string('blogentriesbygroupaboutcourse', 'blog', $a);
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
@@ -927,7 +927,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $PAGE->set_heading("$siteshortname: $courseshortname: " . get_string('blogentries', 'blog'));
         $a = new stdClass();
         $a->type = get_string('course');
-        $headers['heading'] = get_string('blogentriesabout', 'blog', format_string($course->fullname, true, array('context' => get_context_instance(CONTEXT_COURSE, $courseid))));
+        $headers['heading'] = get_string('blogentriesabout', 'blog', format_string($course->fullname, true, array('context' => get_context_instance(CONTEXT_COURSE, $course->id))));
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewblogentries', 'blog', $a);
         $blogurl->remove_params(array('userid'));
index 4d552cc..fdc379e 100644 (file)
  */
 
 require_once($CFG->dirroot . '/blog/locallib.php');
+require_once($CFG->dirroot . '/blog/lib.php');
 
 /**
  * Test functions that rely on the DB tables
  */
 class bloglib_test extends UnitTestCaseUsingDatabase {
 
-    public static $includecoverage = array('blog/locallib.php');
+    public static $includecoverage = array('blog/locallib.php', 'blog/lib.php');
 
     private $courseid; // To store important ids to be used in tests
     private $groupid;
index 1984916..70e69f8 100644 (file)
@@ -32,6 +32,7 @@ class grade_import_form extends moodleform {
         $mform->setType('id', PARAM_INT);
 
         $mform->addElement('header', 'general', get_string('importfile', 'grades'));
+        $mform->disabledIf('url', 'userfile', 'noteq', '');
 
         $mform->addElement('advcheckbox', 'feedback', get_string('importfeedback', 'grades'));
         $mform->setDefault('feedback', 0);
@@ -41,7 +42,6 @@ class grade_import_form extends moodleform {
         $mform->disabledIf('userfile', 'url', 'noteq', '');
 
         $mform->addElement('text', 'url', get_string('fileurl', 'gradeimport_xml'), 'size="80"');
-        $mform->disabledIf('url', 'userfile', 'noteq', '');
 
         if (!empty($CFG->gradepublishing)) {
             $mform->addElement('header', 'publishing', get_string('publishing', 'grades'));
index bedf3a4..cf6837b 100644 (file)
@@ -53,9 +53,6 @@ M.form_filemanager.init = function(Y, options) {
         api: M.cfg.wwwroot+'/repository/draftfiles_ajax.php',
         menus: {},
         initializer: function(options) {
-            //For client side validation, remove hidden draft_id
-            Y.one('#id_'+options.elementname).set('value', '');
-
             this.options = options;
             if (options.mainfile) {
                 this.enablemainfile = options.mainfile;
@@ -72,7 +69,6 @@ M.form_filemanager.init = function(Y, options) {
             this.filepicker_options.maxbytes = this.maxbytes;
             this.filepicker_options.env = 'filemanager';
             this.filepicker_options.itemid = options.itemid;
-            this.filepicker_options.elementname = options.elementname;
 
             if (options.filecount) {
                 this.filecount = options.filecount;
@@ -154,12 +150,6 @@ M.form_filemanager.init = function(Y, options) {
                 button_addfile.setStyle('display', 'none');
             }
             this.refresh(this.currentpath);
-            //When file is added then set draftid for validation
-            var elementname = M.core_filepicker.instances[this.client_id].options.elementname;
-            var itemid = M.core_filepicker.instances[this.client_id].options.itemid;
-            Y.one('#id_'+elementname).set('value', itemid);
-            //generate event to indicate changes which will be used by disable if code.
-            Y.one('#id_'+elementname).simulate('change');
         },
         refresh: function(filepath) {
             var scope = this;
index 7bb93c7..89922a0 100644 (file)
@@ -45,7 +45,6 @@ class MoodleQuickForm_filemanager extends HTML_QuickForm_element {
         if (!empty($options['maxbytes'])) {
             $this->_options['maxbytes'] = get_max_upload_file_size($CFG->maxbytes, $options['maxbytes']);
         }
-        $this->_type = 'filemanager';
         parent::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
     }
 
@@ -147,12 +146,14 @@ class MoodleQuickForm_filemanager extends HTML_QuickForm_element {
         $options->accepted_types = $accepted_types;
         $options->return_types = FILE_INTERNAL;
         $options->context = $PAGE->context;
-        $options->elementname = $elname;
 
         $html = $this->_getTabs();
         $html .= form_filemanager_render($options);
 
-        $html .= '<input id="id_'.$elname.'" value="'.$draftitemid.'" name="'.$elname.'" type="hidden" class="filemanagerhidden"/>';
+        $html .= '<input value="'.$draftitemid.'" name="'.$elname.'" type="hidden" />';
+        // label element needs 'for' attribute work
+        $html .= '<input value="" id="id_'.$elname.'" type="hidden" />';
+
         return $html;
     }
 }
@@ -302,7 +303,7 @@ FMHTML;
     $module = array(
         'name'=>'form_filemanager',
         'fullpath'=>'/lib/form/filemanager.js',
-        'requires' => array('core_filepicker', 'base', 'io-base', 'node', 'node-event-simulate', 'json', 'yui2-button', 'yui2-container', 'yui2-layout', 'yui2-menu', 'yui2-treeview'),
+        'requires' => array('core_filepicker', 'base', 'io-base', 'node', 'json', 'yui2-button', 'yui2-container', 'yui2-layout', 'yui2-menu', 'yui2-treeview'),
         'strings' => array(array('loading', 'repository'), array('nomorefiles', 'repository'), array('confirmdeletefile', 'repository'),
              array('add', 'repository'), array('accessiblefilepicker', 'repository'), array('move', 'moodle'),
              array('cancel', 'moodle'), array('download', 'moodle'), array('ok', 'moodle'),
index 186dc0b..2a84f03 100644 (file)
@@ -5,21 +5,12 @@ M.form_filepicker = {};
 M.form_filepicker.callback = function(params) {
     var html = '<a href="'+params['url']+'">'+params['file']+'</a>';
     document.getElementById('file_info_'+params['client_id']).innerHTML = html;
-    //When file is added then set draftid for validation
-    var elementname = M.core_filepicker.instances[params['client_id']].options.elementname;
-    var itemid = M.core_filepicker.instances[params['client_id']].options.itemid;
-    M.form_filepicker.YUI.one('#id_'+elementname).set('value', itemid);
-    //generate event to indicate changes which will be used by disable if code.
-    M.form_filepicker.YUI.one('#id_'+elementname).simulate('change');
 };
 
 /**
  * This fucntion is called for each file picker on page.
  */
 M.form_filepicker.init = function(Y, options) {
-    //For client side validation, remove hidden draft_id
-    M.form_filepicker.YUI = Y;
-    Y.one('#id_'+options.elementname).set('value', '');
     options.formcallback = M.form_filepicker.callback;
     if (!M.core_filepicker.instances[options.client_id]) {
         M.core_filepicker.init(Y, options); 
index 31a5329..039ab76 100644 (file)
@@ -29,7 +29,6 @@ class MoodleQuickForm_filepicker extends HTML_QuickForm_input {
         if (!empty($options['maxbytes'])) {
             $this->_options['maxbytes'] = get_max_upload_file_size($CFG->maxbytes, $options['maxbytes']);
         }
-        $this->_type = 'filepicker';
         parent::HTML_QuickForm_input($elementName, $elementLabel, $attributes);
     }
 
@@ -79,17 +78,15 @@ class MoodleQuickForm_filepicker extends HTML_QuickForm_input {
         $args->maxbytes = $this->_options['maxbytes'];
         $args->context = $PAGE->context;
         $args->buttonname = $elname.'choose';
-        $args->elementname = $elname;
 
         $html = $this->_getTabs();
         $fp = new file_picker($args);
         $options = $fp->options;
         $options->context = $PAGE->context;
-        $fp->options->elementname = $elname;
         $html .= $OUTPUT->render($fp);
         $html .= '<input type="hidden" name="'.$elname.'" id="'.$id.'" value="'.$draftitemid.'" class="filepickerhidden"/>';
 
-        $module = array('name'=>'form_filepicker', 'fullpath'=>'/lib/form/filepicker.js', 'requires'=>array('core_filepicker', 'node', 'node-event-simulate'));
+        $module = array('name'=>'form_filepicker', 'fullpath'=>'/lib/form/filepicker.js', 'requires'=>array('core_filepicker'));
         $PAGE->requires->js_init_call('M.form_filepicker.init', array($fp->options), true, $module);
 
         $nonjsfilepicker = new moodle_url('/repository/draftfiles_manager.php', array(
index d4f467e..79b2cb1 100644 (file)
@@ -1,4 +1,6 @@
 <?php
+require_once('HTML/QuickForm/input.php');
+
 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
 /**
index 45e01a2..d579b87 100644 (file)
@@ -339,43 +339,6 @@ abstract class moodleform {
         }
     }
 
-    /**
-     * Internal method. Validates filepicker and filemanager files if they are
-     * set as required fields. Also, sets the error message if encountered one.
-     *
-     * @return bool/array with errors
-     */
-    protected function validate_draft_files() {
-        global $USER;
-        $mform =& $this->_form;
-
-        $errors = array();
-        //Go through all the required elements and make sure you hit filepicker or
-        //filemanager element.
-        foreach ($mform->_rules as $elementname => $rules) {
-            $elementtype = $mform->getElementType($elementname);
-            //If element is of type filepicker then do validation
-            if (($elementtype == 'filepicker') || ($elementtype == 'filemanager')){
-                //Check if rule defined is required rule
-                foreach ($rules as $rule) {
-                    if ($rule['type'] == 'required') {
-                        $draftid = (int)$mform->getSubmitValue($elementname);
-                        $fs = get_file_storage();
-                        $context = get_context_instance(CONTEXT_USER, $USER->id);
-                        if (!$files = $fs->get_area_files($context->id, 'user', 'draft', $draftid, 'id DESC', false)) {
-                            $errors[$elementname] = $rule['message'];
-                        }
-                    }
-                }
-            }
-        }
-        if (empty($errors)) {
-            return true;
-        } else {
-            return $errors;
-        }
-    }
-
     /**
      * Load in existing data as form defaults. Usually new entry defaults are stored directly in
      * form definition (new entry form); this function is used to load in data where values
@@ -476,16 +439,6 @@ abstract class moodleform {
 
             $files = array();
             $file_val = $this->_validate_files($files);
-            //check draft files for validation and flag them if required files
-            //are not in draft area.
-            $draftfilevalue = $this->validate_draft_files();
-
-            if ($file_val !== true && $draftfilevalue !== true) {
-                $file_val = array_merge($file_val, $draftfilevalue);
-            } else if ($draftfilevalue !== true) {
-                $file_val = $draftfilevalue;
-            } //default is file_val, so no need to assign.
-
             if ($file_val !== true) {
                 if (!empty($file_val)) {
                     foreach ($file_val as $element=>$msg) {
@@ -2347,7 +2300,7 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
         if (!$form->isFrozen()) {
             $args = $form->getLockOptionObject();
             if (count($args[1]) > 0) {
-                $PAGE->requires->js_init_call('M.form.initFormDependencies', $args, true, moodleform::get_js_module());
+                $PAGE->requires->js_init_call('M.form.initFormDependencies', $args, false, moodleform::get_js_module());
             }
         }
     }
index 8f699b0..2c66b45 100644 (file)
@@ -225,7 +225,7 @@ class moodle_page_test extends UnitTestCase {
 
     public function test_pagetype_defaults_to_script() {
         // Exercise SUT and validate
-        $this->assertEqual('admin-report-unittest-index', $this->testpage->pagetype);
+        $this->assertEqual('admin-tool-unittest-index', $this->testpage->pagetype);
     }
 
     public function test_set_pagetype() {
@@ -239,7 +239,7 @@ class moodle_page_test extends UnitTestCase {
         // Exercise SUT
         $this->testpage->initialise_default_pagetype('admin/tool/unittest/index.php');
         // Validate
-        $this->assertEqual('admin-report-unittest-index', $this->testpage->pagetype);
+        $this->assertEqual('admin-tool-unittest-index', $this->testpage->pagetype);
     }
 
     public function test_initialise_default_pagetype_fp() {
index ae76782..e866a62 100644 (file)
@@ -138,4 +138,3 @@ if($shoulddelete == 1) {
 
 echo $OUTPUT->footer();
 
-?>
\ No newline at end of file
index f065bda..73cd145 100644 (file)
             return $textlib->convert($text, $enc);
         }
     }
-?>
\ No newline at end of file
index 3a4edd7..8916ca7 100644 (file)
@@ -305,4 +305,3 @@ if($do_show == 'showoneentry') {
 
 echo $OUTPUT->footer();
 
-?>
\ No newline at end of file
index 70d4251..63688b0 100644 (file)
@@ -226,4 +226,3 @@ if($showcompleted) {
 
 echo $OUTPUT->footer();
 
-?>
\ No newline at end of file
index 92a3d82..4fb3ff8 100644 (file)
         }
         if(has_capability('moodle/course:bulkmessaging', $coursecontext)) {
             $usehtmleditor = can_use_html_editor();
-            echo '<br /><div class="buttons">';
+            echo '<div class="buttons"><br />';
             echo '<input type="button" id="checkall" value="'.get_string('selectall').'" /> ';
             echo '<input type="button" id="checknone" value="'.get_string('deselectall').'" /> ';
-            echo '</div';
+            echo '</div>';
             echo '<fieldset class="clearfix">';
             echo '<legend class="ftoggler">'.get_string('send_message', 'feedback').'</legend>';
             echo '<div><label for="feedback_subject">'.get_string('subject', 'feedback').'&nbsp;</label><input type="text" id="feedback_subject" size="50" maxlength="255" name="subject" value="'.$subject.'" /></div>';
             echo '<br /><div class="buttons">';
             echo '<input type="submit" name="send_message" value="'.get_string('send', 'feedback').'" />';
             echo '</div>';
-            echo '</fieldset>';
             echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
             echo '<input type="hidden" name="action" value="sendmessage" />';
             echo '<input type="hidden" name="id" value="'.$id.'" />';
+            echo '</fieldset>';
             echo '</form>';
             //include the needed js
             $module = array('name'=>'mod_feedback', 'fullpath'=>'/mod/feedback/feedback.js');
 
     echo $OUTPUT->footer();
 
-?>
\ No newline at end of file
index 9950735..c7f832c 100644 (file)
@@ -96,6 +96,8 @@ if ($data = $mform->get_data()) {
     }
 
     quiz_add_random_questions($quiz, $addonpage, $categoryid, 1, $includesubcategories);
+    quiz_delete_previews($quiz);
+    quiz_update_sumgrades($quiz);
     redirect($returnurl);
 }
 
index 3feae77..d55044b 100644 (file)
@@ -462,7 +462,7 @@ $string['numerical'] = 'Numerical';
 $string['numquestionsx'] = 'Questions: {$a}';
 $string['onlyteachersexport'] = 'Only teachers can export questions';
 $string['onlyteachersimport'] = 'Only teachers with editing rights can import questions';
-$string['onthispage'] = 'On this page';
+$string['onthispage'] = 'This page';
 $string['open'] = 'Not answered';
 $string['openclosedatesupdated'] = 'Quiz open and close dates updated';
 $string['optional'] = 'optional';
index 9fae313..f1acce2 100644 (file)
@@ -164,6 +164,7 @@ class workshop_numerrors_strategy implements workshop_strategy {
         $records    = $data->numerrors; // data to be saved into {workshopform_numerrors}
         $mappings   = $data->mappings;  // data to be saved into {workshopform_numerrors_map}
         $todelete   = array();          // dimension ids to be deleted
+        $maxnonegative = 0;             // maximum number of (weighted) negative responses
 
         for ($i=0; $i < $norepeats; $i++) {
             $record = $records[$i];
@@ -181,6 +182,7 @@ class workshop_numerrors_strategy implements workshop_strategy {
                 // exiting field
                 $DB->update_record('workshopform_numerrors', $record);
             }
+            $maxnonegative += $record->weight;
             // re-save with correct path to embeded media files
             $record = file_postupdate_standard_editor($record, 'description', $this->descriptionopts, $PAGE->context,
                                                       'workshopform_numerrors', 'description', $record->id);
@@ -212,8 +214,8 @@ class workshop_numerrors_strategy implements workshop_strategy {
             $insql = '';
         }
         $sql = "DELETE FROM {workshopform_numerrors_map}
-                      WHERE (($insql nonegative > :nodimensions) AND (workshopid = :workshopid))";
-        $params['nodimensions'] = $norepeats;
+                      WHERE (($insql nonegative > :maxnonegative) AND (workshopid = :workshopid))";
+        $params['maxnonegative'] = $maxnonegative;
         $params['workshopid']   = $this->workshop->id;
         $DB->execute($sql, $params);
     }
index 9ab295f..c82027b 100644 (file)
@@ -306,6 +306,7 @@ END;
         $expectedq->attachments = 0;
         $expectedq->graderinfo['text'] = '';
         $expectedq->graderinfo['format'] = FORMAT_MOODLE;
+        $expectedq->graderinfo['files'] = array();
 
         $this->assert(new CheckSpecifiedFieldsExpectation($expectedq), $q);
     }
@@ -350,6 +351,7 @@ END;
         $expectedq->attachments = -1;
         $expectedq->graderinfo['text'] = '<p>Grade <b>generously</b>!</p>';
         $expectedq->graderinfo['format'] = FORMAT_HTML;
+        $expectedq->graderinfo['files'] = array();
 
         $this->assert(new CheckSpecifiedFieldsExpectation($expectedq), $q);
     }
index 0978e87..6af8f58 100644 (file)
@@ -54,14 +54,14 @@ class preview_options_form extends moodleform {
 
         $mform->addElement('text', 'maxmark', get_string('markedoutof', 'question'),
                 array('size' => '5'));
-        $mform->setType('maxmark', PARAM_NUMBER);
+        $mform->setType('maxmark', PARAM_FLOAT);
 
         if ($this->_customdata['maxvariant'] > 1) {
             $variants = range(1, $this->_customdata['maxvariant']);
             $mform->addElement('select', 'variant', get_string('questionvariant', 'question'),
                     array_combine($variants, $variants));
         }
-        $mform->setType('maxmark', PARAM_INT);
+        $mform->setType('variant', PARAM_INT);
 
         $mform->addElement('select', 'correctness', get_string('whethercorrect', 'question'),
                 $hiddenofvisible);
index 757099b..34f52a8 100644 (file)
@@ -152,7 +152,7 @@ abstract class question_edit_form extends moodleform {
 
         $mform->addElement('text', 'defaultmark', get_string('defaultmark', 'question'),
                 array('size' => 3));
-        $mform->setType('defaultmark', PARAM_INT);
+        $mform->setType('defaultmark', PARAM_FLOAT);
         $mform->setDefault('defaultmark', 1);
         $mform->addRule('defaultmark', null, 'required', null, 'client');
 
index f75a548..cb12428 100644 (file)
@@ -396,13 +396,6 @@ class rating_manager {
      */
     protected $scales = array();
 
-    /**
-     * Gets set to true when the JavaScript that controls AJAX rating has been
-     * initialised (so that it only gets initialised once.
-     * @var int
-     */
-    protected $javascriptinitialised = false;
-
     /**
      * Delete one or more ratings. Specify either a rating id, an item id or just the context id.
      *
@@ -1019,15 +1012,17 @@ class rating_manager {
     public function initialise_rating_javascript(moodle_page $page) {
         global $CFG;
 
-        if ($this->javascriptinitialised) {
+        //only needs to be initialized once
+        static $done = false;
+        if ($done) {
             return true;
         }
 
         if (!empty($CFG->enableajax)) {
             $page->requires->js_init_call('M.core_rating.init');
         }
+        $done = true;
 
-        $this->javascriptinitialised = true;
         return true;
     }
 
index 295f2d6..f577f9e 100644 (file)
@@ -1,7 +1,7 @@
 M.core_rating={
 
     Y : null,
-    transaction : [],
+    api: M.cfg.wwwroot+'/rating/rate_ajax.php',
 
     init : function(Y){
         this.Y = Y;
@@ -27,11 +27,10 @@ M.core_rating={
             }
         }
 
-        this.Y.io.queue.stop();
-        this.transaction.push({transaction:this.Y.io.queue(M.cfg.wwwroot+'/rating/rate_ajax.php', {
-            method : 'POST',
-            data : build_querystring(thedata),
-            on : {
+        var scope = this;
+        var cfg = {
+            method: 'POST',
+            on: {
                 complete : function(tid, outcome, args) {
                     try {
                         if (!outcome) {
@@ -39,17 +38,17 @@ M.core_rating={
                             return false;
                         }
 
-                        var data = this.Y.JSON.parse(outcome.responseText);
+                        var data = scope.Y.JSON.parse(outcome.responseText);
                         if (data.success){
                             //if the user has access to the aggregate then update it
                             if (data.itemid) { //do not test data.aggregate or data.count otherwise it doesn't refresh value=0 or no value
                                 var itemid = data.itemid;
 
-                                var node = this.Y.one('#ratingaggregate'+itemid);
+                                var node = scope.Y.one('#ratingaggregate'+itemid);
                                 node.set('innerHTML',data.aggregate);
 
                                 //empty the count value if no ratings
-                                var node = this.Y.one('#ratingcount'+itemid);
+                                var node = scope.Y.one('#ratingcount'+itemid);
                                 if (data.count > 0) {
                                     node.set('innerHTML',"("+data.count+")");
                                 } else {
@@ -67,11 +66,14 @@ M.core_rating={
                     return false;
                 }
             },
-            context : this,
-            arguments : {
-                //query : this.query.get('value')
-            }
-        }),complete:false,outcome:null});
-        this.Y.io.queue.start();
+            arguments: {
+                scope: scope
+            },
+            headers: {
+            },
+            data: build_querystring(thedata)
+        };
+        this.Y.io(this.api, cfg);
+
     }
 };
\ No newline at end of file
index 910544c..d903496 100644 (file)
@@ -39,16 +39,51 @@ class rating_db_test extends UnitTestCaseUsingDatabase {
 
     protected $testtables = array(
             'lib' => array(
-                'rating', 'scale'));
+                'rating', 'scale', 'context', 'capabilities', 'role_assignments', 'role_capabilities', 'course'));
+
+    protected $syscontext;
+    protected $neededcaps = array('view', 'viewall', 'viewany', 'rate');
+    protected $originaldefaultfrontpageroleid;
 
     public function setUp() {
+        global $CFG;
         parent::setUp();
 
-        $this->switch_to_test_db(); // Switch to test DB for all the execution
+        // Make sure accesslib has cached a sensible system context object
+        // before we switch to the test DB.
+        $this->syscontext = get_context_instance(CONTEXT_SYSTEM);
 
         foreach ($this->testtables as $dir => $tables) {
             $this->create_test_tables($tables, $dir); // Create tables
         }
+
+        $this->switch_to_test_db(); // Switch to test DB for all the execution
+
+        $this->fill_records();
+
+        // Ignore any frontpageroleid, that would require to crete more contexts
+        $this->originaldefaultfrontpageroleid = $CFG->defaultfrontpageroleid;
+        $CFG->defaultfrontpageroleid = null;
+    }
+
+    public function tearDown() {
+        global $CFG;
+        // Recover original frontpageroleid
+        $CFG->defaultfrontpageroleid = $this->originaldefaultfrontpageroleid;
+        parent::tearDown();
+    }
+
+    private function fill_records() {
+        global $DB;
+
+        // Set up systcontext in the test database.
+        $this->syscontext->id = $this->testdb->insert_record('context', $this->syscontext);
+
+        // Add the capabilities used by ratings
+        foreach ($this->neededcaps as $neededcap) {
+            $this->testdb->insert_record('capabilities', (object)array('name' => 'moodle/rating:' . $neededcap,
+                                                                 'contextlevel' => CONTEXT_COURSE));
+        }
     }
 
     /**
@@ -57,7 +92,7 @@ class rating_db_test extends UnitTestCaseUsingDatabase {
     function test_get_ratings_sql() {
 
         // We load 3 items. Each is rated twice. For simplicity itemid == user id of the item owner
-        $ctxid = SYSCONTEXTID;
+        $ctxid = $this->syscontext->id;
         $this->load_test_data('rating',
                 array('contextid', 'component', 'ratingarea', 'itemid', 'scaleid', 'rating', 'userid', 'timecreated', 'timemodified'), array(
 
@@ -86,13 +121,13 @@ class rating_db_test extends UnitTestCaseUsingDatabase {
 
         // Prepare the default options
         $defaultoptions = array (
-                'context'    => get_context_instance(CONTEXT_SYSTEM),
+                'context'    => $this->syscontext,
                 'component'  => 'mod_forum',
                 'ratingarea' => 'post',
                 'scaleid'    => 10,
                 'aggregate'  => RATING_AGGREGATE_AVERAGE);
 
-        $rm = new rating_manager();
+        $rm = new mockup_rating_manager();
 
         // STEP 1: Retreive ratings using the current user
 
@@ -223,3 +258,21 @@ class rating_db_test extends UnitTestCaseUsingDatabase {
         $this->assertEqual($result[0]->rating->aggregate, 3);//should still get the aggregate
     }
 }
+
+/**
+ * rating_manager subclass for unit testing without requiring capabilities to be loaded
+ */
+class mockup_rating_manager extends rating_manager {
+
+    /**
+     * Overwrite get_plugin_permissions_array() so it always return granted perms for unit testing
+     */
+    public function get_plugin_permissions_array($contextid, $component, $ratingarea) {
+        return array(
+            'rate' => true,
+            'view' => true,
+            'viewany' => true,
+            'viewall' => true);
+    }
+
+}
index 19c6286..4037bb8 100644 (file)
 #page-admin-course-index .editcourse td {padding-left:10px;padding-right:10px;}
 #page-admin-course-index .editcourse .count {text-align:right;}
 
-#page-admin-report-unittest-index .exception pre {padding: 8px;}
-#page-admin-report-unittest-index .unittestsummary {padding: 8px;margin-top: 1em;}
-#page-admin-report-unittest-index span.notice {color: teal;}
-#page-admin-report-unittest-index b.pass {color: green;}
-#page-admin-report-unittest-index b.fail, b.exception {color: red;}
-#page-admin-report-unittest-index .exception, .exception pre {background-color: #FDD;}
-#page-admin-report-unittest-index .unittestsummary {color: white;}
-#page-admin-report-unittest-index .unittestsummary.failed {background-color: red;}
-#page-admin-report-unittest-index .unittestsummary.passed {background-color: green;}
-
 #page-admin-report-security-index .timewarninghidden {display:none;}
 #page-admin-report-security-index .statuswarning {background-color: #f0e000;}
 #page-admin-report-security-index .statusserious {background-color: #f07000;}
index ef2afd1..b621573 100644 (file)
@@ -51,7 +51,7 @@
 .course-report-outline td.lastaccess {font-size: 0.8em;}
 #page-admin-uploaduser table#uuresults {font-size: 0.9em;}
 #page-admin-auth_config .required {background-color:#DDDDDD;}
-#page-admin-report-unittest-index .sep {color:#AAAAAA;}
+#page-admin-tool-unittest-index .sep {color:#AAAAAA;}
 .path-admin-roles .capabilitysearchui {text-align:center;margin:0.5em;}
 
 .path-admin .rolecap .cap-name,
index 97a4fb6..78a0051 100644 (file)
@@ -35,6 +35,6 @@ $version  = 2011092100.00;              // YYYYMMDD      = weekly release date o
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.2dev (Build: 20110921)'; // Human-friendly version name
+$release  = '2.2dev (Build: 20110925)'; // Human-friendly version name
 
 $maturity = MATURITY_ALPHA;             // this version's maturity level