Merge branch 'MDL-29440-master' of git://github.com/danpoltawski/moodle
authorSam Hemelryk <sam@moodle.com>
Tue, 13 Mar 2012 22:29:52 +0000 (11:29 +1300)
committerSam Hemelryk <sam@moodle.com>
Tue, 13 Mar 2012 22:29:52 +0000 (11:29 +1300)
136 files changed:
admin/settings/appearance.php
admin/tool/xmldb/actions/edit_field/edit_field.js
admin/tool/xmldb/actions/edit_field_save/edit_field_save.class.php
admin/tool/xmldb/actions/main_view/main_view.class.php
admin/tool/xmldb/actions/view_table_php/view_table_php.class.php
admin/tool/xmldb/lang/en/tool_xmldb.php
auth/db/lang/en/auth_db.php
backup/util/settings/base_setting.class.php
backup/util/settings/simpletest/testsettings.php
blocks/rss_client/db/install.xml
config-dist.php
course/completion.js
course/lib.php
course/recent.php
course/search.php
enrol/authorize/localfuncs.php
enrol/database/lang/en/enrol_database.php
enrol/database/lib.php
enrol/database/settings.php
enrol/database/version.php
enrol/locallib.php
enrol/manual/version.php
enrol/manual/yui/quickenrolment/quickenrolment.js
enrol/otherusers.php
enrol/paypal/ipn.php
enrol/users.php
grade/report/user/lib.php
grade/report/user/styles.css
index.php
lang/en/admin.php
lang/en/completion.php
lib/datalib.php
lib/db/install.xml
lib/db/upgrade.php
lib/db/upgradelib.php
lib/ddl/database_manager.php
lib/ddl/mssql_sql_generator.php
lib/ddl/mysql_sql_generator.php
lib/ddl/oracle_sql_generator.php
lib/ddl/postgres_sql_generator.php
lib/ddl/simpletest/testddl.php
lib/ddl/sql_generator.php
lib/ddl/sqlite_sql_generator.php
lib/deprecatedlib.php
lib/dml/database_column_info.php
lib/dml/mysqli_native_moodle_database.php
lib/dml/oci_native_moodle_database.php
lib/dml/pdo_moodle_database.php
lib/dml/sqlite3_pdo_moodle_database.php
lib/enrollib.php
lib/grade/constants.php
lib/gradelib.php
lib/html2text.php
lib/html2text_readme.txt
lib/moodlelib.php
lib/navigationlib.php
lib/outputrequirementslib.php
lib/pluginlib.php
lib/simpletest/testhtml2text.php [new file with mode: 0644]
lib/simpletest/testmoodlelib.php
lib/simpletest/testweblib.php
lib/xmldb/xmldb.dtd
lib/xmldb/xmldb.xsd
lib/xmldb/xmldb_field.php
lib/xmldb/xmldb_table.php
login/signup_form.php
message/index.php
message/lib.php
mnet/service/enrol/db/install.xml
mod/assignment/db/install.xml
mod/assignment/lib.php
mod/assignment/type/upload/assignment.class.php
mod/chat/db/install.xml
mod/choice/db/install.xml
mod/choice/lib.php
mod/data/db/install.xml
mod/data/edit.php
mod/data/lib.php
mod/feedback/db/install.xml
mod/folder/db/install.xml
mod/forum/db/install.xml
mod/forum/lib.php
mod/glossary/db/install.xml
mod/imscp/db/install.xml
mod/label/db/install.xml
mod/lesson/db/install.xml
mod/lesson/essay.php
mod/lesson/pagetypes/essay.php
mod/lti/db/install.xml
mod/lti/servicelib.php
mod/page/db/install.xml
mod/quiz/db/install.xml
mod/quiz/lang/en/quiz.php
mod/quiz/locallib.php
mod/quiz/report/grading/report.php
mod/quiz/report/statistics/db/install.xml
mod/resource/db/install.xml
mod/scorm/db/install.xml
mod/scorm/report/graphs/graph.php [new file with mode: 0644]
mod/scorm/report/graphs/lang/en/scormreport_graphs.php [new file with mode: 0644]
mod/scorm/report/graphs/report.php [new file with mode: 0644]
mod/scorm/report/graphs/version.php [new file with mode: 0644]
mod/scorm/styles.css
mod/survey/db/install.xml
mod/url/db/install.xml
mod/wiki/db/install.xml
mod/wiki/pagelib.php
mod/workshop/db/install.xml
question/type/calculated/db/install.xml
question/type/essay/db/install.xml
question/type/match/db/install.xml
question/type/multianswer/db/install.xml
question/type/multichoice/db/install.xml
question/type/numerical/db/simpletest/testupgradelibnewqe.php
question/type/random/db/simpletest/testupgradelibnewqe.php
question/type/shortanswer/question.php
question/type/shortanswer/renderer.php
question/type/shortanswer/simpletest/helper.php
question/type/shortanswer/simpletest/testquestion.php
report/completion/index.php
report/progress/index.php
repository/filepicker.js
repository/filepicker.php
repository/upload/lib.php
repository/wikimedia/lib.php
repository/wikimedia/wikimedia.php
repository/youtube/lib.php
tag/index.php
theme/base/layout/frontpage.php
theme/base/layout/general.php
theme/base/layout/report.php
theme/base/style/core.css
theme/binarius/style/pagelayout.css
theme/formal_white/style/core.css
theme/index.php
version.php

index 9c86f4f..c791205 100644 (file)
@@ -97,6 +97,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     );
     $temp->add(new admin_setting_configselect('defaulthomepage', new lang_string('defaulthomepage', 'admin'), new lang_string('configdefaulthomepage', 'admin'), HOMEPAGE_SITE, $choices));
     $temp->add(new admin_setting_configcheckbox('navshowcategories', new lang_string('navshowcategories', 'admin'), new lang_string('confignavshowcategories', 'admin'), 1));
+    $temp->add(new admin_setting_configcheckbox('navshowmycoursecategories', new lang_string('navshowmycoursecategories', 'admin'), new lang_string('navshowmycoursecategories_help', 'admin'), 0));
     $temp->add(new admin_setting_configcheckbox('navshowallcourses', new lang_string('navshowallcourses', 'admin'), new lang_string('confignavshowallcourses', 'admin'), 0));
     $temp->add(new admin_setting_configtext('navcourselimit',new lang_string('navcourselimit','admin'),new lang_string('confignavcourselimit', 'admin'),20,PARAM_INT));
     $temp->add(new admin_setting_configcheckbox('navlinkcoursesections', new lang_string('navlinkcoursesections', 'admin'), new lang_string('navlinkcoursesections_help', 'admin'), 0));
index b5a45c1..57dcfca 100644 (file)
@@ -75,20 +75,24 @@ function transformForm(event) {
     switch (typeField.value) {
         case '1':  // XMLDB_TYPE_INTEGER
             lengthTip.innerHTML = ' 1...20';
+            lengthField.disabled = false;
             decimalsTip.innerHTML = '';
             decimalsField.disabled = true;
             decimalsField.value = '';
             break;
         case '2':  // XMLDB_TYPE_NUMBER
             lengthTip.innerHTML = ' 1...20';
+            lengthField.disabled = false;
             decimalsTip.innerHTML = ' 0...length or empty';
             break;
         case '3':  // XMLDB_TYPE_FLOAT
             lengthTip.innerHTML = ' 1...20 or empty';
+            lengthField.disabled = false;
             decimalsTip.innerHTML = ' 0...length or empty';
             break;
         case '4':  // XMLDB_TYPE_CHAR
             lengthTip.innerHTML = ' 1...1333'; // Hardcoded, yes!
+            lengthField.disabled = false;
             decimalsTip.innerHTML = '';
             decimalsField.disabled = true;
             decimalsField.value = '';
@@ -96,7 +100,8 @@ function transformForm(event) {
             sequenceField.value = '0';
             break;
         case '5':  // XMLDB_TYPE_TEXT
-            lengthTip.innerHTML = ' small, medium, big';
+            lengthTip.innerHTML = '';
+            lengthField.disabled = true;
             decimalsTip.innerHTML = '';
             decimalsField.disabled = true;
             decimalsField.value = '';
@@ -106,7 +111,8 @@ function transformForm(event) {
             defaultField.value = '';
             break;
         case '6':  // XMLDB_TYPE_BINARY
-            lengthTip.innerHTML = ' small, medium, big';
+            lengthTip.innerHTML = '';
+            lengthField.disabled = true;
             decimalsTip.innerHTML = '';
             decimalsField.disabled = true;
             decimalsField.value = '';
index a1b4a80..90b1433 100644 (file)
@@ -49,8 +49,6 @@ class edit_field_save extends XMLDBAction {
             'numberincorrectlength' => 'tool_xmldb',
             'floatincorrectlength' => 'tool_xmldb',
             'charincorrectlength' => 'tool_xmldb',
-            'textincorrectlength' => 'tool_xmldb',
-            'binaryincorrectlength' => 'tool_xmldb',
             'numberincorrectdecimals' => 'tool_xmldb',
             'floatincorrectdecimals' => 'tool_xmldb',
             'defaultincorrect' => 'tool_xmldb',
@@ -201,28 +199,8 @@ class edit_field_save extends XMLDBAction {
                 }
             }
         }
-        // Text checks
-        if ($type == XMLDB_TYPE_TEXT) {
-            if ($length != 'small' &&
-                $length != 'medium' &&
-                $length != 'big') {
-                $errors[] = $this->str['textincorrectlength'];
-            }
-            if ($default !== NULL && $default !== '') {
-                if (substr($default, 0, 1) == "'" ||
-                    substr($default, -1, 1) == "'") {
-                    $errors[] = $this->str['defaultincorrect'];
-                }
-            }
-        }
-        // Binary checks
-        if ($type == XMLDB_TYPE_BINARY) {
-            if ($length != 'small' &&
-                $length != 'medium' &&
-                $length != 'big') {
-                $errors[] = $this->str['binaryincorrectlength'];
-            }
-        }
+        // No text checks
+        // No binary checks
 
         if (!empty($errors)) {
             $tempfield = new xmldb_field($name);
index c8feb61..30af587 100644 (file)
@@ -277,40 +277,6 @@ class main_view extends XMLDBAction {
                         }
                     }
                 }
-                // TODO: Drop this check in Moodle 2.1
-                // Intercept loaded structure here and look for ENUM fields
-                if (isset($dbdir->xml_file)) {
-                    if ($structure =& $dbdir->xml_file->getStructure()) {
-                        if ($tables = $structure->getTables()) {
-                            foreach ($tables as $table) {
-                                if ($fields = $table->getFields()) {
-                                    foreach ($fields as $field) {
-                                        if (!empty($field->hasenums)) {
-                                            if ($hithis) {
-                                                $o .= '<tr class="highlight"><td class="error cell" colspan="10">';
-                                            } else {
-                                                $o .= '<tr class="r' . $row . '"><td class="error cell" colspan="10">';
-                                            }
-                                            $o .= 'Table ' . $table->getName() . ', field ' . $field->getName() . ' has ENUM info';
-                                            if (!empty($field->hasenumsenabled)) {
-                                                $o .= ' that seems to be active (true). ENUMs support has been dropped in Moodle 2.0, '  .
-                                                      ' the XMLDB Editor will delete any ENUM reference next time you save this file' .
-                                                      ' and you MUST provide  one upgrade block in your code to drop them from DB. See' .
-                                                      ' <a href="http://docs.moodle.org/dev/DB_layer_2.0_migration_docs#The_changes">' .
-                                                      ' Moodle Docs</a> for more info and examples.';
-                                            } else {
-                                                $o .= ' that seem to be inactive (false). ENUMs support has been dropped in Moodle 2.0,' .
-                                                      ' the XMLDB Editor will, simply, delete any ENUM reference next time you save this file.' .
-                                                      ' No further action is necessary.';
-                                            }
-                                            $o .= '</td></tr>';
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
                 // If there are changes pending to be saved, but the file cannot be written... inform here
                 if ($dbdir->path_exists &&
                     file_exists($key . '/install.xml') &&
index 57c0bd3..7ce2157 100644 (file)
@@ -127,7 +127,6 @@ class view_table_php extends XMLDBAction {
                          $optionspacer . 'change_field_precision',
                          $optionspacer . 'change_field_notnull',
                          $optionspacer . 'change_field_default',
-                         $optionspacer . 'drop_enum_from_field', // TODO: Moodle 2.1 - Drop drop_enum_from_field
                          'Keys',
                          $optionspacer . 'add_key',
                          $optionspacer . 'drop_key',
@@ -224,13 +223,6 @@ class view_table_php extends XMLDBAction {
                         $o.= $this->str['mustselectonefield'];
                     }
                     break;
-                case 'drop_enum_from_field': // TODO: Moodle 2.1 - Drop drop_enum_from_field
-                    if ($fieldkeyindexinitial == 'f') { // Only if we have got one field
-                        $o.= s($this->drop_enum_from_field_php($structure, $tableparam, $fieldkeyindexparam));
-                    } else {
-                        $o.= $this->str['mustselectonefield'];
-                    }
-                    break;
                 case 'change_field_default':
                     if ($fieldkeyindexinitial == 'f') { // Only if we have got one field
                         $o.= s($this->change_field_default_php($structure, $tableparam, $fieldkeyindexparam));
@@ -593,57 +585,6 @@ class view_table_php extends XMLDBAction {
         return $result;
     }
 
-    /**
-     * This function will generate all the PHP code needed to
-     * drop the enum values (check constraint) of one field
-     * using XMLDB objects and functions
-     *
-     * Note this function is here as part of the process of
-     * dropping enums completely from Moodle 2.0: MDL-18577
-     * and will be out in Moodle 2.1
-     * TODO: Moodle 2.1 - Drop drop_enum_from_field_php
-     *
-     * @param xmldb_structure structure object containing all the info
-     * @param string table table name
-     * @param string field field name to change its enum
-     */
-    function drop_enum_from_field_php($structure, $table, $field) {
-
-        $result = '';
-        // Validate if we can do it
-        if (!$table = $structure->getTable($table)) {
-            return false;
-        }
-        if (!$field = $table->getField($field)) {
-            return false;
-        }
-        if ($table->getAllErrors()) {
-            return false;
-        }
-
-        // Add the standard PHP header
-        $result .= XMLDB_PHP_HEADER;
-
-        // Add contents
-        $result .= XMLDB_LINEFEED;
-        $result .= '        // Drop list of values (enum) from field ' . $field->getName() . ' on table ' . $table->getName() . XMLDB_LINEFEED;
-        $result .= '        $table = new xmldb_table(' . "'" . $table->getName() . "'" . ');' . XMLDB_LINEFEED;
-        $result .= '        $field = new xmldb_field(' . "'" . $field->getName() . "', " . $field->getPHP(true) . ');' . XMLDB_LINEFEED;
-
-        // Launch the proper DDL
-        $result .= XMLDB_LINEFEED;
-        $result .= '        // Launch drop of list of values from field ' . $field->getName() . XMLDB_LINEFEED;
-        $result .= '        $dbman->drop_enum_from_field($table, $field);' . XMLDB_LINEFEED;
-
-        // Add the proper upgrade_xxxx_savepoint call
-        $result .= $this->upgrade_savepoint_php ($structure);
-
-        // Add standard PHP footer
-        $result .= XMLDB_PHP_FOOTER;
-
-        return $result;
-    }
-
     /**
      * This function will generate all the PHP code needed to
      * change the default of one field using XMLDB objects and functions
index ebb4878..a378c26 100644 (file)
@@ -27,7 +27,6 @@ $string['actual'] = 'Actual';
 $string['aftertable'] = 'After table:';
 $string['back'] = 'Back';
 $string['backtomainview'] = 'Back to main';
-$string['binaryincorrectlength'] = 'Incorrect length for binary field';
 $string['cannotuseidfield'] = 'Cannot insert the "id" field. It is an autonumeric column';
 $string['completelogbelow'] = '(see the complete log of the search below)';
 $string['confirmdeletefield'] = 'Are you absolutely sure that you want to delete the field:';
@@ -159,7 +158,6 @@ $string['selecttable'] = 'Select table:';
 $string['table'] = 'Table';
 $string['tablenameempty'] = 'The table name cannot be empty';
 $string['tables'] = 'Tables';
-$string['textincorrectlength'] = 'Incorrect length for text field';
 $string['unload'] = 'Unload';
 $string['up'] = 'Up';
 $string['view'] = 'View';
index 2443235..6f42064 100644 (file)
@@ -57,7 +57,7 @@ $string['auth_dbsybasequoting'] = 'Use sybase quotes';
 $string['auth_dbsybasequotinghelp'] = 'Sybase style single quote escaping - needed for Oracle, MS SQL and some other databases. Do not use for MySQL!';
 $string['auth_dbtable'] = 'Name of the table in the database';
 $string['auth_dbtable_key'] = 'Table';
-$string['auth_dbtype'] = 'The database type (See the <a href="../lib/adodb/readme.htm#drivers">ADOdb documentation</a> for details)';
+$string['auth_dbtype'] = 'The database type (See the <a href="http://phplens.com/adodb/supported.databases.html" target="_blank">ADOdb documentation</a> for details)';
 $string['auth_dbtype_key'] = 'Database';
 $string['auth_dbupdatinguser'] = 'Updating user {$a->name} id {$a->id}';
 $string['auth_dbuser'] = 'Username with read access to the database';
index 558b0c2..765c6ac 100644 (file)
@@ -303,7 +303,7 @@ abstract class base_setting {
         if ($this->is_circular_reference($dependency->get_dependent_setting())) {
             $a = new stdclass();
             $a->alreadydependent = $this->name;
-            $a->main = $dependentsetting->get_name();
+            $a->main = $dependency->get_dependent_setting()->get_name();
             throw new base_setting_exception('setting_circular_reference', $a);
         }
         $this->dependencies[$dependency->get_dependent_setting()->get_name()] = $dependency;
index fd079cc..7d0d8a7 100644 (file)
@@ -32,10 +32,12 @@ require_once($CFG->dirroot . '/backup/util/interfaces/checksumable.class.php');
 require_once($CFG->dirroot . '/backup/backup.class.php');
 require_once($CFG->dirroot . '/backup/util/settings/base_setting.class.php');
 require_once($CFG->dirroot . '/backup/util/settings/backup_setting.class.php');
+require_once($CFG->dirroot . '/backup/util/settings/setting_dependency.class.php');
 require_once($CFG->dirroot . '/backup/util/settings/root/root_backup_setting.class.php');
 require_once($CFG->dirroot . '/backup/util/settings/activity/activity_backup_setting.class.php');
 require_once($CFG->dirroot . '/backup/util/settings/section/section_backup_setting.class.php');
 require_once($CFG->dirroot . '/backup/util/settings/course/course_backup_setting.class.php');
+require_once($CFG->dirroot . '/backup/util/ui/backup_ui_setting.class.php');
 
 /*
  * setting tests (all)
@@ -209,6 +211,21 @@ class setting_test extends UnitTestCase {
             $this->assertEqual($e->a->alreadydependent, 'test4');
         }
 
+        $bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null);
+        $bs2 = new mock_base_setting('test2', base_setting::IS_INTEGER, null);
+        $bs1->register_dependency(new setting_dependency_disabledif_empty($bs1, $bs2));
+        try {
+            // $bs1 is already dependent on $bs2 so this should fail.
+            $bs2->register_dependency(new setting_dependency_disabledif_empty($bs2, $bs1));
+            $this->assertTrue(false, 'base_setting_exception expected');
+        } catch (exception $e) {
+            $this->assertTrue($e instanceof base_setting_exception);
+            $this->assertEqual($e->errorcode, 'setting_circular_reference');
+            $this->assertTrue($e->a instanceof stdclass);
+            $this->assertEqual($e->a->main, 'test1');
+            $this->assertEqual($e->a->alreadydependent, 'test2');
+        }
+
         // Create 3 settings and observe between them, last one must
         // automatically inherit all the settings defined in the main one
         $bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null);
index dbd1f14..90096d3 100644 (file)
@@ -8,9 +8,9 @@
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="title"/>
-        <FIELD NAME="title" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid" NEXT="preferredtitle"/>
+        <FIELD NAME="title" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid" NEXT="preferredtitle"/>
         <FIELD NAME="preferredtitle" TYPE="char" LENGTH="64" NOTNULL="true" SEQUENCE="false" PREVIOUS="title" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="preferredtitle" NEXT="shared"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="preferredtitle" NEXT="shared"/>
         <FIELD NAME="shared" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="url"/>
         <FIELD NAME="url" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="shared"/>
       </FIELDS>
index dbc732c..abc8da1 100644 (file)
@@ -383,7 +383,7 @@ $CFG->admin = 'admin';
 // memory limit to something higher.
 // The value for the settings should be a valid PHP memory value. e.g. 512M, 1G
 //
-//     $CFG->extramemorylimit = 1G;
+//     $CFG->extramemorylimit = '1G';
 //
 // The CSS files the Moodle produces can be extremely large and complex, especially
 // if you are using a custom theme that builds upon several other themes.
index 3be2c38..4d9542a 100644 (file)
@@ -18,17 +18,21 @@ M.core_completion.init = function(Y) {
 
         } else {
             var current = args.state.get('value');
-
+            var modulename = args.modulename.get('value');
             if (current == 1) {
+                var altstr = M.str.completion['completion-alt-manual-y'].replace('{$a}', modulename);
+                var titlestr = M.str.completion['completion-title-manual-y'].replace('{$a}', modulename);
                 args.state.set('value', 0);
                 args.image.set('src', M.util.image_url('i/completion-manual-y', 'moodle'));
-                args.image.set('alt', M.str.completion['completion-alt-manual-y']);
-                args.image.set('title', M.str.completion['completion-title-manual-y']);
+                args.image.set('alt', altstr);
+                args.image.set('title', titlestr);
             } else {
+                var altstr = M.str.completion['completion-alt-manual-n'].replace('{$a}', modulename);
+                var titlestr = M.str.completion['completion-title-manual-n'].replace('{$a}', modulename);
                 args.state.set('value', 1);
                 args.image.set('src', M.util.image_url('i/completion-manual-n', 'moodle'));
-                args.image.set('alt', M.str.completion['completion-alt-manual-n']);
-                args.image.set('title', M.str.completion['completion-title-manual-n']);
+                args.image.set('alt', altstr);
+                args.image.set('title', titlestr);
             }
         }
 
@@ -48,6 +52,7 @@ M.core_completion.init = function(Y) {
         var completionstate = 0;
         var state = null;
         var image = null;
+        var modulename = null;
 
         var inputs = Y.Node.getDOMNode(form).getElementsByTagName('input');
         for (var i=0; i<inputs.length; i++) {
@@ -59,6 +64,9 @@ M.core_completion.init = function(Y) {
                      completionstate = inputs[i].value;
                      state = Y.one(inputs[i]);
                      break;
+                  case 'modulename':
+                     modulename = Y.one(inputs[i]);
+                     break;
             }
             if (inputs[i].type == 'image') {
                 image = Y.one(inputs[i]);
@@ -76,7 +84,7 @@ M.core_completion.init = function(Y) {
                 success: handle_success,
                 failure: handle_failure
             },
-            arguments: {state: state, image: image, ajax: ajax}
+            arguments: {state: state, image: image, ajax: ajax, modulename: modulename}
         };
 
         Y.use('io-base', function(Y) {
index f35bbfa..542b3cc 100644 (file)
@@ -1730,9 +1730,9 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                 }
                 if ($completionicon) {
                     $imgsrc = $OUTPUT->pix_url('i/completion-'.$completionicon);
-                    $imgalt = s(get_string('completion-alt-'.$completionicon, 'completion'));
+                    $imgalt = s(get_string('completion-alt-'.$completionicon, 'completion', $mod->name));
                     if ($completion == COMPLETION_TRACKING_MANUAL && !$isediting) {
-                        $imgtitle = s(get_string('completion-title-'.$completionicon, 'completion'));
+                        $imgtitle = s(get_string('completion-title-'.$completionicon, 'completion', $mod->name));
                         $newstate =
                             $completiondata->completionstate==COMPLETION_COMPLETE
                             ? COMPLETION_INCOMPLETE
@@ -1751,6 +1751,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                         echo "
 <form class='togglecompletion$extraclass' method='post' action='".$CFG->wwwroot."/course/togglecompletion.php'><div>
 <input type='hidden' name='id' value='{$mod->id}' />
+<input type='hidden' name='modulename' value='".s($mod->name)."' />
 <input type='hidden' name='sesskey' value='".sesskey()."' />
 <input type='hidden' name='completionstate' value='$newstate' />
 <input type='image' src='$imgsrc' alt='$imgalt' title='$imgtitle' />
index 134cce0..fcf09fd 100644 (file)
@@ -78,7 +78,7 @@ $PAGE->navbar->add($userinfo);
 $PAGE->set_title("$course->shortname: $strrecentactivity");
 $PAGE->set_heading($course->fullname);
 echo $OUTPUT->header();
-echo $OUTPUT->heading(format_string($course->fullname) . ": $userinfo", 3);
+echo $OUTPUT->heading(format_string($course->fullname) . ": $userinfo", 2);
 
 $mform->display();
 
@@ -238,8 +238,8 @@ if (!empty($activities)) {
                 $modfullname = $modnames[$cm->modname];
 
                 $image = "<img src=\"" . $OUTPUT->pix_url('icon', $cm->modname) . "\" class=\"icon\" alt=\"$modfullname\" />";
-                echo "<h4>$image $modfullname".
-                     " <a href=\"$CFG->wwwroot/mod/$cm->modname/view.php?id=$cm->id\" $linkformat>$name</a></h4>";
+                echo "<h3>$image $modfullname".
+                     " <a href=\"$CFG->wwwroot/mod/$cm->modname/view.php?id=$cm->id\" $linkformat>$name</a></h3>";
            }
 
         } else {
@@ -269,7 +269,7 @@ if (!empty($activities)) {
 
 } else {
 
-    echo '<h4><center>' . get_string('norecentactivity') . '</center></h2>';
+    echo '<h3><center>' . get_string('norecentactivity') . '</center></h3>';
 
 }
 
index 1e191a3..b3be912 100644 (file)
 
                 // checks whether user can do site backup
                 if (has_capability('moodle/backup:backupcourse', $coursecontext)) {
-                    echo "<a title=\"".get_string("backup")."\" href=\"../backup/backup.php?id=$course->id\">\n<img".
+                    $backupurl = new moodle_url('/backup/backup.php', array('id' => $course->id));
+                    echo "<a title=\"".get_string("backup")."\" href=\"".$backupurl."\">\n<img".
                         " src=\"" . $OUTPUT->pix_url('t/backup') . "\" class=\"iconsmall\" alt=\"".get_string("backup")."\" /></a>\n ";
                 }
 
                 // checks whether user can do restore
                 if (has_capability('moodle/restore:restorecourse', $coursecontext)) {
-                    echo "<a title=\"".get_string("restore")."\" href=\"../files/index.php?id=$course->id&amp;wdir=/backupdata\">\n<img".
+                    $restoreurl = new moodle_url('/backup/restorefile.php', array('contextid' => $coursecontext->id));
+                    echo "<a title=\"".get_string("restore")."\" href=\"".$restoreurl."\">\n<img".
                         " src=\"" . $OUTPUT->pix_url('t/restore') . "\" class=\"iconsmall\" alt=\"".get_string("restore")."\" /></a>\n ";
                 }
 
index 98634ed..6a5a1e5 100644 (file)
@@ -233,7 +233,7 @@ function send_welcome_messages($orderdata) {
                 $a->profileurl = "$CFG->wwwroot/user/view.php?id=$lastuserid";
                 $a->paymenturl = "$CFG->wwwroot/enrol/authorize/index.php?user=$lastuserid";
                 $emailmessage = get_string('welcometocoursesemail', 'enrol_authorize', $a);
-                $subject = get_string("enrolmentnew", '', format_string($SITE->shortname, true, array('context' => get_context_instance(CONTEXT_COURSE, SITEID))));
+                $subject = get_string("enrolmentnew", 'enrol', format_string($SITE->shortname, true, array('context' => get_context_instance(CONTEXT_COURSE, SITEID))));
 
                 $eventdata = new stdClass();
                 $eventdata->modulename        = 'moodle';
index 18f6420..b423c7b 100644 (file)
@@ -44,12 +44,13 @@ $string['defaultrole'] = 'Default role';
 $string['defaultrole_desc'] = 'The role that will be assigned by default if no other role is specified in external table.';
 $string['ignorehiddencourses'] = 'Ignore hidden courses';
 $string['ignorehiddencourses_desc'] = 'If enabled users will not be enrolled on courses that are set to be unavailable to students.';
+$string['localcategoryfield'] = 'Local category field';
 $string['localcoursefield'] = 'Local course field';
 $string['localrolefield'] = 'Local role field';
 $string['localuserfield'] = 'Local user field';
 $string['newcoursetable'] = 'Remote new courses table';
 $string['newcoursetable_desc'] = 'Specify of the name of the table that contains list of courses that should be created automatically. Empty means no courses are created.';
-$string['newcoursecategory'] = 'New course category id field';
+$string['newcoursecategory'] = 'New course category field';
 $string['newcoursefullname'] = 'New course full name field';
 $string['newcourseidnumber'] = 'New course ID number field';
 $string['newcourseshortname'] = 'New course short name field';
index f0aa364..ce8d6d2 100644 (file)
@@ -81,7 +81,7 @@ class enrol_database_plugin extends enrol_plugin {
         $instance = $ue->enrolmentinstance;
         $params = $manager->get_moodlepage()->url->params();
         $params['ue'] = $ue->id;
-        if ($this->allow_unenrol_user($instance, $ue) && has_capability('enrol/meta:unenrol', $context)) {
+        if ($this->allow_unenrol_user($instance, $ue) && has_capability('enrol/database:unenrol', $context)) {
             $url = new moodle_url('/enrol/unenroluser.php', $params);
             $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, array('class'=>'unenrollink', 'rel'=>$ue->id));
         }
@@ -622,6 +622,8 @@ class enrol_database_plugin extends enrol_plugin {
         $idnumber  = strtolower($this->get_config('newcourseidnumber'));
         $category  = strtolower($this->get_config('newcoursecategory'));
 
+        $localcategoryfield = $this->get_config('localcategoryfield', 'id');
+
         $sqlfields = array($fullname, $shortname);
         if ($category) {
             $sqlfields[] = $category;
@@ -653,17 +655,17 @@ class enrol_database_plugin extends enrol_plugin {
                         }
                         continue;
                     }
-                    if ($category and !$DB->record_exists('course_categories', array('id'=>$fields[$category]))) {
+                    if ($category and !$coursecategory = $DB->get_record('course_categories', array($localcategoryfield=>$fields[$category]), 'id')) {
                         if ($verbose) {
-                            mtrace('  error: invalid category id, can not create course: '.$fields[$shortname]);
+                            mtrace('  error: invalid category '.$localcategoryfield.', can not create course: '.$fields[$shortname]);
                         }
                         continue;
                     }
                     $course = new stdClass();
                     $course->fullname  = $fields[$fullname];
                     $course->shortname = $fields[$shortname];
-                    $course->idnumber  = $idnumber ? $fields[$idnumber] : NULL;
-                    $course->category  = $category ? $fields[$category] : NULL;
+                    $course->idnumber  = $idnumber ? $fields[$idnumber] : '';
+                    $course->category  = $category ? $coursecategory->id : NULL;
                     $createcourses[] = $course;
                 }
             }
index f75afe6..369bd39 100644 (file)
@@ -66,6 +66,8 @@ if ($ADMIN->fulltree) {
     $options = array('id'=>'id', 'shortname'=>'shortname', 'fullname'=>'fullname');
     $settings->add(new admin_setting_configselect('enrol_database/localrolefield', get_string('localrolefield', 'enrol_database'), '', 'shortname', $options));
 
+    $options = array('id'=>'id', 'idnumber'=>'idnumber');
+    $settings->add(new admin_setting_configselect('enrol_database/localcategoryfield', get_string('localcategoryfield', 'enrol_database'), '', 'id', $options));
 
 
     $settings->add(new admin_setting_heading('enrol_database_remoteheader', get_string('settingsheaderremote', 'enrol_database'), ''));
index c1a2820..6f085ff 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012022700;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012031000;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012022300;        // Requires this Moodle version
 $plugin->component = 'enrol_database';  // Full name of the plugin (used for diagnostics)
 //TODO: should we add cron sync?
\ No newline at end of file
index e7cdf29..f7d5030 100644 (file)
@@ -764,20 +764,14 @@ class course_enrolment_manager {
         $userroles = $this->get_other_users($sort, $direction, $page, $perpage);
         $roles = $this->get_all_roles();
 
-        $courseid   = $this->get_course()->id;
         $context    = $this->get_context();
+        $now = time();
+        $extrafields = get_extra_user_fields($context);
 
         $users = array();
         foreach ($userroles as $userrole) {
             if (!array_key_exists($userrole->id, $users)) {
-                $users[$userrole->id] = array(
-                    'userid'     => $userrole->id,
-                    'courseid'   => $courseid,
-                    'picture'    => new user_picture($userrole),
-                    'firstname'  => fullname($userrole, true),
-                    'email'      => $userrole->email,
-                    'roles'      => array()
-                );
+                $users[$userrole->id] = $this->prepare_user_for_display($userrole, $extrafields, $now);
             }
             $a = new stdClass;
             $a->role = $roles[$userrole->roleid]->localname;
@@ -800,6 +794,7 @@ class course_enrolment_manager {
                         break;
                 }
             }
+            $users[$userrole->id]['roles'] = array();
             $users[$userrole->id]['roles'][$userrole->roleid] = array(
                 'text' => $roletext,
                 'unchangeable' => !$changeable
@@ -825,7 +820,6 @@ class course_enrolment_manager {
         $users = $this->get_users($sort, $direction, $page, $perpage);
 
         $now = time();
-        $strnever = get_string('never');
         $straddgroup = get_string('addgroup', 'group');
         $strunenrol = get_string('unenrol', 'enrol');
         $stredit = get_string('edit');
@@ -833,7 +827,6 @@ class course_enrolment_manager {
         $allroles   = $this->get_all_roles();
         $assignable = $this->get_assignable_roles();
         $allgroups  = $this->get_all_groups();
-        $courseid   = $this->get_course()->id;
         $context    = $this->get_context();
         $canmanagegroups = has_capability('moodle/course:managegroups', $context);
 
@@ -842,36 +835,23 @@ class course_enrolment_manager {
 
         $userdetails = array();
         foreach ($users as $user) {
-            $details = array(
-                'userid'     => $user->id,
-                'courseid'   => $courseid,
-                'picture'    => new user_picture($user),
-                'firstname'  => fullname($user, true),
-                'lastseen'   => $strnever,
-                'roles'      => array(),
-                'groups'     => array(),
-                'enrolments' => array()
-            );
-            foreach ($extrafields as $field) {
-                $details[$field] = $user->{$field};
-            }
-
-            if ($user->lastaccess) {
-                $details['lastseen'] = format_time($now - $user->lastaccess);
-            }
+            $details = $this->prepare_user_for_display($user, $extrafields, $now);
 
             // Roles
+            $details['roles'] = array();
             foreach ($this->get_user_roles($user->id) as $rid=>$rassignable) {
                 $details['roles'][$rid] = array('text'=>$allroles[$rid]->localname, 'unchangeable'=>(!$rassignable || !isset($assignable[$rid])));
             }
 
             // Users
             $usergroups = $this->get_user_groups($user->id);
+            $details['groups'] = array();
             foreach($usergroups as $gid=>$unused) {
                 $details['groups'][$gid] = $allgroups[$gid]->name;
             }
 
             // Enrolments
+            $details['enrolments'] = array();
             foreach ($this->get_user_enrolments($user->id) as $ue) {
                 if ($ue->timestart and $ue->timeend) {
                     $period = get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend)));
@@ -898,6 +878,39 @@ class course_enrolment_manager {
         return $userdetails;
     }
 
+    /**
+     * Prepare a user record for display
+     *
+     * This function is called by both {@link get_users_for_display} and {@link get_other_users_for_display} to correctly
+     * prepare user fields for display
+     *
+     * Please note that this function does not check capability for moodle/coures:viewhiddenuserfields
+     *
+     * @param object $user The user record
+     * @param array $extrafields The list of fields as returned from get_extra_user_fields used to determine which
+     * additional fields may be displayed
+     * @param int $now The time used for lastaccess calculation
+     * @return array The fields to be displayed including userid, courseid, picture, firstname, lastseen and any
+     * additional fields from $extrafields
+     */
+    private function prepare_user_for_display($user, $extrafields, $now) {
+        $details = array(
+            'userid'    => $user->id,
+            'courseid'  => $this->get_course()->id,
+            'picture'   => new user_picture($user),
+            'firstname' => fullname($user, has_capability('moodle/site:viewfullnames', $this->get_context())),
+            'lastseen'  => get_string('never'),
+        );
+        foreach ($extrafields as $field) {
+            $details[$field] = $user->{$field};
+        }
+
+        if ($user->lastaccess) {
+            $details['lastseen'] = format_time($now - $user->lastaccess);
+        }
+        return $details;
+    }
+
     public function get_manual_enrol_buttons() {
         $plugins = $this->get_enrolment_plugins();
         $buttons = array();
index 5ed2012..4a7b760 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2011112900;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2011112901;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2011112900;        // Requires this Moodle version
 $plugin->component = 'enrol_manual';    // Full name of the plugin (used for diagnostics)
index d5658b4..88c09ea 100644 (file)
@@ -380,7 +380,11 @@ YUI.add('moodle-enrol_manual-quickenrolment', function(Y) {
             params['role'] = this.get(UEP.BASE).one('.'+CSS.ENROLMENTOPTION+'.'+CSS.ROLE+' select').get('value');
             params['startdate'] = this.get(UEP.BASE).one('.'+CSS.ENROLMENTOPTION+'.'+CSS.STARTDATE+' select').get('value');
             params['duration'] = this.get(UEP.BASE).one('.'+CSS.ENROLMENTOPTION+'.'+CSS.DURATION+' select').get('value');
-            params['recovergrades'] = this.get(UEP.BASE).one('#'+CSS.RECOVERGRADES).get('checked')?1:0;
+            if (this.get(UEP.DISABLEGRADEHISTORY) != true) {
+                params['recovergrades'] = this.get(UEP.BASE).one('#'+CSS.RECOVERGRADES).get('checked')?1:0;
+            } else {
+                params['recovergrades'] = 0;
+            }
 
             Y.io(M.cfg.wwwroot+this.get(UEP.AJAXURL), {
                 method:'POST',
index 8769fc4..52b34bf 100644 (file)
@@ -48,33 +48,30 @@ $manager = new course_enrolment_manager($PAGE, $course, $filter);
 $table = new course_enrolment_other_users_table($manager, $PAGE);
 $PAGE->set_url('/enrol/otherusers.php', $manager->get_url_params()+$table->get_url_params());
 
-/***
- * Actions will go here
- */
+$userdetails = array (
+    'picture' => false,
+    'firstname' => get_string('firstname'),
+    'lastname' => get_string('lastname'),
+);
+$extrafields = get_extra_user_fields($context);
+foreach ($extrafields as $field) {
+    $userdetails[$field] = get_user_field_name($field);
+}
 
-/*$fields = array(
-    'userdetails' => array (
-        'picture' => false,
-        'firstname' => get_string('firstname'),
-        'lastname' => get_string('lastname'),
-        'email' => get_string('email')
-    ),
-    'lastseen' => get_string('lastaccess'),
-    'role' => array(
-        'roles' => get_string('roles', 'role'),
-        'context' => get_string('context')
-    )
-);*/
 $fields = array(
-    'userdetails' => array (
-        'picture' => false,
-        'firstname' => get_string('firstname'),
-        'lastname' => get_string('lastname'),
-        'email' => get_string('email')
-    ),
+    'userdetails' => $userdetails,
     'lastseen' => get_string('lastaccess'),
     'role' => get_string('roles', 'role')
 );
+
+// Remove hidden fields if the user has no access
+if (!has_capability('moodle/course:viewhiddenuserfields', $context)) {
+    $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
+    if (isset($hiddenfields['lastaccess'])) {
+        unset($fields['lastseen']);
+    }
+}
+
 $table->set_fields($fields, $OUTPUT);
 
 //$users = $manager->get_other_users($table->sort, $table->sortdirection, $table->page, $table->perpage);
index 8c5f014..b4a6bf4 100644 (file)
@@ -243,7 +243,7 @@ while (!feof($fp)) {
             $eventdata->name              = 'paypal_enrolment';
             $eventdata->userfrom          = $teacher;
             $eventdata->userto            = $user;
-            $eventdata->subject           = get_string("enrolmentnew", '', $shortname);
+            $eventdata->subject           = get_string("enrolmentnew", 'enrol', $shortname);
             $eventdata->fullmessage       = get_string('welcometocoursetext', '', $a);
             $eventdata->fullmessageformat = FORMAT_PLAIN;
             $eventdata->fullmessagehtml   = '';
@@ -262,8 +262,8 @@ while (!feof($fp)) {
             $eventdata->name              = 'paypal_enrolment';
             $eventdata->userfrom          = $user;
             $eventdata->userto            = $teacher;
-            $eventdata->subject           = get_string("enrolmentnew", '', $shortname);
-            $eventdata->fullmessage       = get_string('enrolmentnewuser', '', $a);
+            $eventdata->subject           = get_string("enrolmentnew", 'enrol', $shortname);
+            $eventdata->fullmessage       = get_string('enrolmentnewuser', 'enrol', $a);
             $eventdata->fullmessageformat = FORMAT_PLAIN;
             $eventdata->fullmessagehtml   = '';
             $eventdata->smallmessage      = '';
@@ -281,8 +281,8 @@ while (!feof($fp)) {
                 $eventdata->name              = 'paypal_enrolment';
                 $eventdata->userfrom          = $user;
                 $eventdata->userto            = $admin;
-                $eventdata->subject           = get_string("enrolmentnew", '', $shortname);
-                $eventdata->fullmessage       = get_string('enrolmentnewuser', '', $a);
+                $eventdata->subject           = get_string("enrolmentnew", 'enrol', $shortname);
+                $eventdata->fullmessage       = get_string('enrolmentnewuser', 'enrol', $a);
                 $eventdata->fullmessageformat = FORMAT_PLAIN;
                 $eventdata->fullmessagehtml   = '';
                 $eventdata->smallmessage      = '';
index 8ff9c26..2ebbab5 100644 (file)
@@ -183,6 +183,18 @@ $fields = array(
     'group' => get_string('groups', 'group'),
     'enrol' => get_string('enrolmentinstances', 'enrol')
 );
+
+// Remove hidden fields if the user has no access
+if (!has_capability('moodle/course:viewhiddenuserfields', $context)) {
+    $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
+    if (isset($hiddenfields['lastaccess'])) {
+        unset($fields['lastseen']);
+    }
+    if (isset($hiddenfields['groups'])) {
+        unset($fields['group']);
+    }
+}
+
 $table->set_fields($fields, $renderer);
 
 $canassign = has_capability('moodle/role:assign', $manager->get_context());
@@ -202,4 +214,4 @@ $PAGE->set_heading($PAGE->title);
 echo $OUTPUT->header();
 echo $OUTPUT->heading(get_string('enrolledusers', 'enrol'));
 echo $renderer->render($table);
-echo $OUTPUT->footer();
\ No newline at end of file
+echo $OUTPUT->footer();
index 9e823cf..b57e8a1 100644 (file)
@@ -312,6 +312,7 @@ class grade_report_user extends grade_report {
         $hidden = '';
         $excluded = '';
         $class = '';
+        $classfeedback = '';
 
         // If this is a hidden grade category, hide it completely from the user
         if ($type == 'category' && $grade_object->is_hidden() && !$this->canviewhidden && (
@@ -368,6 +369,10 @@ class grade_report_user extends grade_report {
                 /// Actual Grade
                 $gradeval = $grade_grade->finalgrade;
 
+                if ($this->showfeedback) {
+                    // Copy $class before appending itemcenter as feedback should not be centered
+                    $classfeedback = $class;
+                }
                 $class .= " itemcenter ";
                 if ($this->showweight) {
                     $data['weight']['class'] = $class;
@@ -477,13 +482,13 @@ class grade_report_user extends grade_report {
                 // Feedback
                 if ($this->showfeedback) {
                     if ($grade_grade->overridden > 0 AND ($type == 'categoryitem' OR $type == 'courseitem')) {
-                    $data['feedback']['class'] = $class.' feedbacktext';
+                    $data['feedback']['class'] = $classfeedback.' feedbacktext';
                         $data['feedback']['content'] = get_string('overridden', 'grades').': ' . format_text($grade_grade->feedback, $grade_grade->feedbackformat);
                     } else if (empty($grade_grade->feedback) or (!$this->canviewhidden and $grade_grade->is_hidden())) {
-                        $data['feedback']['class'] = $class.' feedbacktext';
+                        $data['feedback']['class'] = $classfeedback.' feedbacktext';
                         $data['feedback']['content'] = '&nbsp;';
                     } else {
-                        $data['feedback']['class'] = $class.' feedbacktext';
+                        $data['feedback']['class'] = $classfeedback.' feedbacktext';
                         $data['feedback']['content'] = format_text($grade_grade->feedback, $grade_grade->feedbackformat);
                     }
                 }
index b7751e1..f0e5a3c 100644 (file)
@@ -33,8 +33,8 @@
 .user-grade td.item {border-left: 1px solid gray;border-right: 1px solid gray;}
 .user-grade td.excluded {background-color: #666;}
 .user-grade td.hidden {color: #aaa;}
-.user-grade td.feedbacktext {max-width:600px;padding:0;}
+.user-grade td.feedbacktext {max-width:600px;padding:2px 2px;}
 .pagelayout-report .user-grade .feedbacktext .no-overflow {overflow:auto;padding:0.25em;}
 
 table.user-grade td.feedbacktext {text-align:left;width: 40%;font-size: 0.8em;white-space:normal;}
-table.user-grade td.itemcenter {text-align:center;}
\ No newline at end of file
+table.user-grade td.itemcenter {text-align:center;}
index a778724..946332d 100644 (file)
--- a/index.php
+++ b/index.php
 
     redirect_if_major_upgrade_required();
 
+    $urlparams = array();
+    if ($CFG->defaulthomepage == HOMEPAGE_MY && optional_param('redirect', 1, PARAM_BOOL) === 0) {
+        $urlparams['redirect'] = 0;
+    }
+    $PAGE->set_url('/', $urlparams);
+    $PAGE->set_course($SITE);
+
     if ($CFG->forcelogin) {
         require_login();
     } else {
 
     $hassiteconfig = has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
 
-    $urlparams = array();
-    if ($CFG->defaulthomepage == HOMEPAGE_MY && optional_param('redirect', 1, PARAM_BOOL) === 0) {
-        $urlparams['redirect'] = 0;
-    }
-    $PAGE->set_url('/', $urlparams);
-    $PAGE->set_course($SITE);
-
 /// If the site is currently under maintenance, then print a message
     if (!empty($CFG->maintenance_enabled) and !$hassiteconfig) {
         print_maintenance_message();
index f9597da..6b6c8df 100644 (file)
@@ -378,6 +378,7 @@ $string['curlrecommended'] = 'Installing the optional cURL library is highly rec
 $string['curlrequired'] = 'The cURL PHP extension is now required by Moodle, in order to communicate with Moodle repositories.';
 $string['curltimeoutkbitrate'] = 'Bitrate to use when calculating cURL timeouts (Kbps)';
 $string['curltimeoutkbitrate_help'] = 'This setting is used to calculate an appropriate timeout during large cURL requests. As part of this calculation an HTTP HEAD request is made to determine the size of the content. Setting this to 0 disables this request from being made.';
+$string['currenttheme'] = 'Current theme';
 $string['customcheck'] = 'Other checks';
 $string['custommenu'] = 'Custom menu';
 $string['custommenuitems'] = 'Custom menu items';
@@ -702,6 +703,8 @@ $string['navshowfrontpagemods'] = 'Show front page activities in the navigation'
 $string['navshowfrontpagemods_help'] = 'If enabled, front page activities will be shown on the navigation under site pages.';
 $string['navshowallcourses'] = 'Show all courses';
 $string['navshowcategories'] = 'Show course categories';
+$string['navshowmycoursecategories'] = 'Show my course categories';
+$string['navshowmycoursecategories_help'] = 'If enabled courses in the users my courses branch will be shown in categories.';
 $string['neverdeleteruns'] = 'Never delete runs';
 $string['nobookmarksforuser'] = 'You do not have any bookmarks.';
 $string['nodatabase'] = 'No database';
@@ -884,6 +887,8 @@ $string['searchresults'] = 'Search results';
 $string['sectionerror'] = 'Section error!';
 $string['secureforms'] = 'Use additional form security';
 $string['security'] = 'Security';
+$string['selectdevice'] = 'Select device';
+$string['selecttheme'] = 'Select theme for {$a} device';
 $string['server'] = 'Server';
 $string['serverchecks'] = 'Server checks';
 $string['serverlimit'] = 'Server limit';
@@ -947,7 +952,7 @@ $string['themedesignermode'] = 'Theme designer mode';
 $string['themelist'] = 'Theme list';
 $string['themenoselected'] = 'No theme selected';
 $string['themeresetcaches'] = 'Clear theme caches';
-$string['themeselect'] = 'Select theme';
+$string['themeselect'] = 'Change theme';
 $string['themeselector'] = 'Theme selector';
 $string['themesettings'] = 'Theme settings';
 $string['therewereerrors'] = 'There were errors in your data';
@@ -964,6 +969,7 @@ $string['unbookmarkthispage'] = 'Unbookmark this page';
 $string['unicoderecommended'] = 'Storing all your data in Unicode (UTF-8) is recommended. New installations should be performed into databases that have their default character set as Unicode.  If you are upgrading, you should perform the UTF-8 migration process (see the Admin page).';
 $string['unicoderequired'] = 'It is required that you store all your data in Unicode format (UTF-8). New installations must be performed into databases that have their default character set as Unicode.  If you are upgrading, you should perform the UTF-8 migration process (see the Admin page).';
 $string['uninstallplugin'] = 'Uninstall';
+$string['unsettheme'] = 'Unset theme';
 $string['unsupported'] = 'Unsupported';
 $string['unsuspenduser'] = 'Activate user account';
 $string['updateaccounts'] = 'Update existing accounts';
index 66fc44d..c55779e 100644 (file)
@@ -36,12 +36,12 @@ A tick next to the activity name on the course page indicates when the activity
 $string['completion_link'] = 'activity/completion';
 $string['completion-alt-auto-enabled'] = 'The system marks this item complete according to conditions';
 $string['completion-alt-auto-fail'] = 'Completed (did not achieve pass grade)';
-$string['completion-alt-auto-n'] = 'Not completed';
+$string['completion-alt-auto-n'] = 'Not completed: {$a}';
 $string['completion-alt-auto-pass'] = 'Completed (achieved pass grade)';
-$string['completion-alt-auto-y'] = 'Completed';
+$string['completion-alt-auto-y'] = 'Completed: {$a}';
 $string['completion-alt-manual-enabled'] = 'Students can manually mark this item complete';
-$string['completion-alt-manual-n'] = 'Not completed; select to mark as complete';
-$string['completion-alt-manual-y'] = 'Completed; select to mark as not complete';
+$string['completion-alt-manual-n'] = 'Not completed: {$a}. Select to mark as complete.';
+$string['completion-alt-manual-y'] = 'Completed: {$a}. Select to mark as not complete.';
 $string['completion_automatic'] = 'Show activity as complete when conditions are met';
 $string['completiondisabled'] = 'Disabled, not shown in activity settings';
 $string['completionexpected'] = 'Expect completed on';
@@ -54,8 +54,8 @@ If a dotted tick is shown, you can click it to tick the box when you think you h
 If a blank tick box is shown, a tick will appear automatically when you have completed the activity according to conditions set by the teacher.';
 $string['completion_manual'] = 'Students can manually mark the activity as completed';
 $string['completion_none'] = 'Do not indicate activity completion';
-$string['completion-title-manual-n'] = 'Mark as complete';
-$string['completion-title-manual-y'] = 'Mark as not complete';
+$string['completion-title-manual-n'] = 'Mark as complete: {$a}';
+$string['completion-title-manual-y'] = 'Mark as not complete: {$a}';
 $string['completionnotenabled'] = 'Completion is not enabled';
 $string['completionnotenabledforcourse'] = 'Completion is not enabled for this course';
 $string['completionnotenabledforsite'] = 'Completion is not enabled for this site';
index 1eaaa54..99f6b91 100644 (file)
@@ -222,7 +222,7 @@ function get_users($get=true, $search='', $confirmed=false, array $exceptions=nu
     if ($exceptions) {
         list($exceptions, $eparams) = $DB->get_in_or_equal($exceptions, SQL_PARAMS_NAMED, 'ex', false);
         $params = $params + $eparams;
-        $except = " AND id $exceptions";
+        $select .= " AND id $exceptions";
     }
 
     if ($firstinitial) {
index 8c25f21..eeac75d 100644 (file)
@@ -8,7 +8,7 @@
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="value"/>
-        <FIELD NAME="value" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name"/>
+        <FIELD NAME="value" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="name"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="name"/>
@@ -20,7 +20,7 @@
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="plugin"/>
         <FIELD NAME="plugin" TYPE="char" LENGTH="100" NOTNULL="true" DEFAULT="core" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="plugin" NEXT="value"/>
-        <FIELD NAME="value" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name"/>
+        <FIELD NAME="value" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="name"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="plugin_name"/>
@@ -34,8 +34,8 @@
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid" NEXT="plugin"/>
         <FIELD NAME="plugin" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" PREVIOUS="timemodified" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="plugin" NEXT="value"/>
-        <FIELD NAME="value" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="oldvalue"/>
-        <FIELD NAME="oldvalue" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="value"/>
+        <FIELD NAME="value" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="oldvalue"/>
+        <FIELD NAME="oldvalue" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="value"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="userid"/>
@@ -53,8 +53,8 @@
         <FIELD NAME="version" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" COMMENT="plugin or main version if known" PREVIOUS="plugin" NEXT="targetversion"/>
         <FIELD NAME="targetversion" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" COMMENT="version of plugin or core specified in version.php at the time of upgrade loggging" PREVIOUS="version" NEXT="info"/>
         <FIELD NAME="info" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="targetversion" NEXT="details"/>
-        <FIELD NAME="details" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="info" NEXT="backtrace"/>
-        <FIELD NAME="backtrace" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="details" NEXT="userid"/>
+        <FIELD NAME="details" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="info" NEXT="backtrace"/>
+        <FIELD NAME="backtrace" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="details" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="backtrace" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid"/>
       </FIELDS>
         <FIELD NAME="fullname" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false" PREVIOUS="sortorder" NEXT="shortname"/>
         <FIELD NAME="shortname" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="fullname" NEXT="idnumber"/>
         <FIELD NAME="idnumber" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="shortname" NEXT="summary"/>
-        <FIELD NAME="summary" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="idnumber" NEXT="summaryformat"/>
+        <FIELD NAME="summary" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="idnumber" NEXT="summaryformat"/>
         <FIELD NAME="summaryformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="summary" NEXT="format"/>
         <FIELD NAME="format" TYPE="char" LENGTH="10" NOTNULL="true" DEFAULT="topics" SEQUENCE="false" PREVIOUS="summaryformat" NEXT="showgrades"/>
         <FIELD NAME="showgrades" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="format" NEXT="modinfo"/>
-        <FIELD NAME="modinfo" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" PREVIOUS="showgrades" NEXT="newsitems"/>
+        <FIELD NAME="modinfo" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="showgrades" NEXT="newsitems"/>
         <FIELD NAME="newsitems" TYPE="int" LENGTH="5" NOTNULL="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="modinfo" NEXT="startdate"/>
         <FIELD NAME="startdate" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="newsitems" NEXT="numsections"/>
         <FIELD NAME="numsections" TYPE="int" LENGTH="5" NOTNULL="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="startdate" NEXT="marker"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="idnumber"/>
         <FIELD NAME="idnumber" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="idnumber" NEXT="descriptionformat"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="idnumber" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="parent"/>
         <FIELD NAME="parent" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="descriptionformat" NEXT="sortorder"/>
         <FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="parent" NEXT="coursecount"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="course"/>
         <FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="role"/>
         <FIELD NAME="role" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="ID of the role to receive this notification message when a course has been completed" PREVIOUS="course" NEXT="message"/>
-        <FIELD NAME="message" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="HTML formatted message to be sent" PREVIOUS="role" NEXT="timesent"/>
+        <FIELD NAME="message" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="HTML formatted message to be sent" PREVIOUS="role" NEXT="timesent"/>
         <FIELD NAME="timesent" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="message"/>
       </FIELDS>
       <KEYS>
         <FIELD NAME="customchar2" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Custom - general short name" PREVIOUS="customchar1" NEXT="customdec1"/>
         <FIELD NAME="customdec1" TYPE="number" LENGTH="12" NOTNULL="false" SEQUENCE="false" DECIMALS="7" COMMENT="Custom - general decimal" PREVIOUS="customchar2" NEXT="customdec2"/>
         <FIELD NAME="customdec2" TYPE="number" LENGTH="12" NOTNULL="false" SEQUENCE="false" DECIMALS="7" COMMENT="Custom - general decimal" PREVIOUS="customdec1" NEXT="customtext1"/>
-        <FIELD NAME="customtext1" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="Custom - general text" PREVIOUS="customdec2" NEXT="customtext2"/>
-        <FIELD NAME="customtext2" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="Custom - general text" PREVIOUS="customtext1" NEXT="timecreated"/>
+        <FIELD NAME="customtext1" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Custom - general text" PREVIOUS="customdec2" NEXT="customtext2"/>
+        <FIELD NAME="customtext2" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Custom - general text" PREVIOUS="customtext1" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="customtext2" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timecreated"/>
       </FIELDS>
         <FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="section"/>
         <FIELD NAME="section" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="course" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" PREVIOUS="section" NEXT="summary"/>
-        <FIELD NAME="summary" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="summaryformat"/>
+        <FIELD NAME="summary" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="summaryformat"/>
         <FIELD NAME="summaryformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="summary" NEXT="sequence"/>
-        <FIELD NAME="sequence" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="summaryformat" NEXT="visible"/>
+        <FIELD NAME="sequence" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="summaryformat" NEXT="visible"/>
         <FIELD NAME="visible" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="sequence"/>
       </FIELDS>
       <KEYS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="fullname"/>
         <FIELD NAME="fullname" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="shortname"/>
         <FIELD NAME="shortname" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="fullname" NEXT="summary"/>
-        <FIELD NAME="summary" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="shortname" NEXT="summaryformat"/>
+        <FIELD NAME="summary" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="shortname" NEXT="summaryformat"/>
         <FIELD NAME="summaryformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="summary" NEXT="reason"/>
-        <FIELD NAME="reason" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="summaryformat" NEXT="requester"/>
+        <FIELD NAME="reason" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="summaryformat" NEXT="requester"/>
         <FIELD NAME="requester" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="reason" NEXT="password"/>
         <FIELD NAME="password" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false" PREVIOUS="requester"/>
       </FIELDS>
         <FIELD NAME="filter" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="The filter internal name, like 'filter/tex' or 'mod/glossary'." PREVIOUS="id" NEXT="contextid"/>
         <FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="References context.id." PREVIOUS="filter" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The config variable name." PREVIOUS="contextid" NEXT="value"/>
-        <FIELD NAME="value" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="The correspoding config variable value." PREVIOUS="name"/>
+        <FIELD NAME="value" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="The correspoding config variable value." PREVIOUS="name"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="contextid"/>
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="format"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="format"/>
         <FIELD NAME="format" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="courseid"/>
         <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="format" NEXT="groupid"/>
         <FIELD NAME="groupid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="courseid" NEXT="userid"/>
         <FIELD NAME="filter" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="version"/>
         <FIELD NAME="version" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="filter" NEXT="md5key"/>
         <FIELD NAME="md5key" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" PREVIOUS="version" NEXT="rawtext"/>
-        <FIELD NAME="rawtext" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="md5key" NEXT="timemodified"/>
+        <FIELD NAME="rawtext" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="md5key" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="rawtext"/>
       </FIELDS>
       <KEYS>
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="md5key"/>
         <FIELD NAME="md5key" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="formattedtext"/>
-        <FIELD NAME="formattedtext" TYPE="text" LENGTH="big" NOTNULL="true" SEQUENCE="false" PREVIOUS="md5key" NEXT="timemodified"/>
+        <FIELD NAME="formattedtext" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="md5key" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="formattedtext"/>
       </FIELDS>
       <KEYS>
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="qtype"/>
         <FIELD NAME="qtype" TYPE="int" LENGTH="5" NOTNULL="true" SEQUENCE="false" COMMENT="query type constant" PREVIOUS="id" NEXT="sqltext"/>
-        <FIELD NAME="sqltext" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" COMMENT="query sql" PREVIOUS="qtype" NEXT="sqlparams"/>
-        <FIELD NAME="sqlparams" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="query parameters" PREVIOUS="sqltext" NEXT="error"/>
+        <FIELD NAME="sqltext" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="query sql" PREVIOUS="qtype" NEXT="sqlparams"/>
+        <FIELD NAME="sqlparams" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="query parameters" PREVIOUS="sqltext" NEXT="error"/>
         <FIELD NAME="error" TYPE="int" LENGTH="5" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="is error" PREVIOUS="sqlparams" NEXT="info"/>
-        <FIELD NAME="info" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="detailed info such as error text" PREVIOUS="error" NEXT="backtrace"/>
-        <FIELD NAME="backtrace" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="php execution trace" PREVIOUS="info" NEXT="exectime"/>
+        <FIELD NAME="info" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="detailed info such as error text" PREVIOUS="error" NEXT="backtrace"/>
+        <FIELD NAME="backtrace" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="php execution trace" PREVIOUS="info" NEXT="exectime"/>
         <FIELD NAME="exectime" TYPE="number" LENGTH="10" NOTNULL="true" SEQUENCE="false" DECIMALS="5" COMMENT="query execution time in seconds as float" PREVIOUS="backtrace" NEXT="timelogged"/>
         <FIELD NAME="timelogged" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="timestamp when log info stored into db" PREVIOUS="exectime"/>
       </FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="useridfrom"/>
         <FIELD NAME="useridfrom" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="useridto"/>
         <FIELD NAME="useridto" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="useridfrom" NEXT="subject"/>
-        <FIELD NAME="subject" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="The message subject" PREVIOUS="useridto" NEXT="fullmessage"/>
-        <FIELD NAME="fullmessage" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="subject" NEXT="fullmessageformat"/>
+        <FIELD NAME="subject" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="The message subject" PREVIOUS="useridto" NEXT="fullmessage"/>
+        <FIELD NAME="fullmessage" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="subject" NEXT="fullmessageformat"/>
         <FIELD NAME="fullmessageformat" TYPE="int" LENGTH="4" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="The format of the full message" PREVIOUS="fullmessage" NEXT="fullmessagehtml"/>
-        <FIELD NAME="fullmessagehtml" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="html format of message" PREVIOUS="fullmessageformat" NEXT="smallmessage"/>
-        <FIELD NAME="smallmessage" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Smal version of message (eg sms)" PREVIOUS="fullmessagehtml" NEXT="notification"/>
+        <FIELD NAME="fullmessagehtml" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="html format of message" PREVIOUS="fullmessageformat" NEXT="smallmessage"/>
+        <FIELD NAME="smallmessage" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Smal version of message (eg sms)" PREVIOUS="fullmessagehtml" NEXT="notification"/>
         <FIELD NAME="notification" TYPE="int" LENGTH="1" NOTNULL="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="smallmessage" NEXT="contexturl"/>
-        <FIELD NAME="contexturl" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="If this message is a notification of an event contexturl should contain a link to view this event. For example if its a notification of a forum post contexturl should contain a link to the forum post." PREVIOUS="notification" NEXT="contexturlname"/>
-        <FIELD NAME="contexturlname" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Display text for the contexturl" PREVIOUS="contexturl" NEXT="timecreated"/>
+        <FIELD NAME="contexturl" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="If this message is a notification of an event contexturl should contain a link to view this event. For example if its a notification of a forum post contexturl should contain a link to the forum post." PREVIOUS="notification" NEXT="contexturlname"/>
+        <FIELD NAME="contexturlname" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Display text for the contexturl" PREVIOUS="contexturl" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="contexturlname"/>
       </FIELDS>
       <KEYS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="useridfrom"/>
         <FIELD NAME="useridfrom" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="useridto"/>
         <FIELD NAME="useridto" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="useridfrom" NEXT="subject"/>
-        <FIELD NAME="subject" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="The message subject" PREVIOUS="useridto" NEXT="fullmessage"/>
-        <FIELD NAME="fullmessage" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="subject" NEXT="fullmessageformat"/>
+        <FIELD NAME="subject" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="The message subject" PREVIOUS="useridto" NEXT="fullmessage"/>
+        <FIELD NAME="fullmessage" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="subject" NEXT="fullmessageformat"/>
         <FIELD NAME="fullmessageformat" TYPE="int" LENGTH="4" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="The format of the full message" PREVIOUS="fullmessage" NEXT="fullmessagehtml"/>
-        <FIELD NAME="fullmessagehtml" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="html format of message" PREVIOUS="fullmessageformat" NEXT="smallmessage"/>
-        <FIELD NAME="smallmessage" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Smal version of message (eg sms)" PREVIOUS="fullmessagehtml" NEXT="notification"/>
+        <FIELD NAME="fullmessagehtml" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="html format of message" PREVIOUS="fullmessageformat" NEXT="smallmessage"/>
+        <FIELD NAME="smallmessage" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Smal version of message (eg sms)" PREVIOUS="fullmessagehtml" NEXT="notification"/>
         <FIELD NAME="notification" TYPE="int" LENGTH="1" NOTNULL="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="smallmessage" NEXT="contexturl"/>
-        <FIELD NAME="contexturl" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="If this message is a notification of an event contexturl should contain a link to view this event. For example if its a notification of a forum post contexturl should contain a link to the forum post." PREVIOUS="notification" NEXT="contexturlname"/>
-        <FIELD NAME="contexturlname" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Display text for the contexturl" PREVIOUS="contexturl" NEXT="timecreated"/>
+        <FIELD NAME="contexturl" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="If this message is a notification of an event contexturl should contain a link to view this event. For example if its a notification of a forum post contexturl should contain a link to the forum post." PREVIOUS="notification" NEXT="contexturlname"/>
+        <FIELD NAME="contexturlname" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Display text for the contexturl" PREVIOUS="contexturl" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="contexturlname" NEXT="timeread"/>
         <FIELD NAME="timeread" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timecreated"/>
       </FIELDS>
         <FIELD NAME="state" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="0 means normal session" PREVIOUS="id" NEXT="sid"/>
         <FIELD NAME="sid" TYPE="char" LENGTH="128" NOTNULL="true" SEQUENCE="false" COMMENT="Session id" PREVIOUS="state" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="sid" NEXT="sessdata"/>
-        <FIELD NAME="sessdata" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="session content" PREVIOUS="userid" NEXT="timecreated"/>
+        <FIELD NAME="sessdata" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="session content" PREVIOUS="userid" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="sessdata" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="timecreated" NEXT="firstip"/>
         <FIELD NAME="firstip" TYPE="char" LENGTH="45" NOTNULL="false" SEQUENCE="false" PREVIOUS="timemodified" NEXT="lastip"/>
         <FIELD NAME="secret" TYPE="char" LENGTH="15" NOTNULL="true" SEQUENCE="false" PREVIOUS="lastip" NEXT="picture"/>
         <FIELD NAME="picture" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="secret" NEXT="url"/>
         <FIELD NAME="url" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="picture" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" PREVIOUS="url" NEXT="descriptionformat"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="url" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="mailformat"/>
         <FIELD NAME="mailformat" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="descriptionformat" NEXT="maildigest"/>
         <FIELD NAME="maildigest" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="mailformat" NEXT="maildisplay"/>
         <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="courseid" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid" NEXT="scale"/>
-        <FIELD NAME="scale" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="scale" NEXT="descriptionformat"/>
+        <FIELD NAME="scale" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="description"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="scale" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="descriptionformat"/>
       </FIELDS>
         <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="loggeduser" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="courseid" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid" NEXT="scale"/>
-        <FIELD NAME="scale" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="scale"/>
+        <FIELD NAME="scale" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="description"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="scale"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="oldid"/>
         <FIELD NAME="moduleid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="groupid" NEXT="coursemoduleid"/>
         <FIELD NAME="coursemoduleid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="moduleid" NEXT="subject"/>
         <FIELD NAME="subject" TYPE="char" LENGTH="128" NOTNULL="true" SEQUENCE="false" PREVIOUS="coursemoduleid" NEXT="summary"/>
-        <FIELD NAME="summary" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" PREVIOUS="subject" NEXT="content"/>
-        <FIELD NAME="content" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" PREVIOUS="summary" NEXT="uniquehash"/>
+        <FIELD NAME="summary" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="subject" NEXT="content"/>
+        <FIELD NAME="content" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="summary" NEXT="uniquehash"/>
         <FIELD NAME="uniquehash" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="content" NEXT="rating"/>
         <FIELD NAME="rating" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="uniquehash" NEXT="format"/>
         <FIELD NAME="format" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="rating" NEXT="summaryformat"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="shortname"/>
         <FIELD NAME="shortname" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="shortname" NEXT="sortorder"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="shortname" NEXT="sortorder"/>
         <FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="archetype"/>
         <FIELD NAME="archetype" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" COMMENT="Role archetype is used during install and role reset, marks admin role and helps in site settings" PREVIOUS="sortorder"/>
       </FIELDS>
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="shortname"/>
         <FIELD NAME="shortname" TYPE="char" LENGTH="255" NOTNULL="true" DEFAULT="shortname" SEQUENCE="false" COMMENT="short name for each field" PREVIOUS="id" NEXT="name"/>
-        <FIELD NAME="name" TYPE="text" LENGTH="big" NOTNULL="true" SEQUENCE="false" COMMENT="field name" PREVIOUS="shortname" NEXT="datatype"/>
+        <FIELD NAME="name" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="field name" PREVIOUS="shortname" NEXT="datatype"/>
         <FIELD NAME="datatype" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="Type of data held in this field" PREVIOUS="name" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="Description of field" PREVIOUS="datatype" NEXT="descriptionformat"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Description of field" PREVIOUS="datatype" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="categoryid"/>
         <FIELD NAME="categoryid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="id from category table" PREVIOUS="descriptionformat" NEXT="sortorder"/>
         <FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="order within the category" PREVIOUS="categoryid" NEXT="required"/>
         <FIELD NAME="visible" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Visibility: private, public, hidden" PREVIOUS="locked" NEXT="forceunique"/>
         <FIELD NAME="forceunique" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="should the field contain unique data" PREVIOUS="visible" NEXT="signup"/>
         <FIELD NAME="signup" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="display field on signup page" PREVIOUS="forceunique" NEXT="defaultdata"/>
-        <FIELD NAME="defaultdata" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="Default value for this field" PREVIOUS="signup" NEXT="defaultdataformat"/>
+        <FIELD NAME="defaultdata" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Default value for this field" PREVIOUS="signup" NEXT="defaultdataformat"/>
         <FIELD NAME="defaultdataformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="defaultdata" NEXT="param1"/>
-        <FIELD NAME="param1" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="General parameter field" PREVIOUS="defaultdataformat" NEXT="param2"/>
-        <FIELD NAME="param2" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="General parameter field" PREVIOUS="param1" NEXT="param3"/>
-        <FIELD NAME="param3" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="General parameter field" PREVIOUS="param2" NEXT="param4"/>
-        <FIELD NAME="param4" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="General parameter field" PREVIOUS="param3" NEXT="param5"/>
-        <FIELD NAME="param5" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="General parameter field" PREVIOUS="param4"/>
+        <FIELD NAME="param1" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="General parameter field" PREVIOUS="defaultdataformat" NEXT="param2"/>
+        <FIELD NAME="param2" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="General parameter field" PREVIOUS="param1" NEXT="param3"/>
+        <FIELD NAME="param3" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="General parameter field" PREVIOUS="param2" NEXT="param4"/>
+        <FIELD NAME="param4" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="General parameter field" PREVIOUS="param3" NEXT="param5"/>
+        <FIELD NAME="param5" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="General parameter field" PREVIOUS="param4"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="id from the user table" PREVIOUS="id" NEXT="fieldid"/>
         <FIELD NAME="fieldid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="id from the field table" PREVIOUS="userid" NEXT="data"/>
-        <FIELD NAME="data" TYPE="text" LENGTH="big" NOTNULL="true" SEQUENCE="false" COMMENT="Field data" PREVIOUS="fieldid" NEXT="dataformat"/>
+        <FIELD NAME="data" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Field data" PREVIOUS="fieldid" NEXT="dataformat"/>
         <FIELD NAME="dataformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="data"/>
       </FIELDS>
       <KEYS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="contextid"/>
         <FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="context that this category is shared in" PREVIOUS="name" NEXT="info"/>
-        <FIELD NAME="info" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="contextid" NEXT="infoformat"/>
+        <FIELD NAME="info" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="contextid" NEXT="infoformat"/>
         <FIELD NAME="infoformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="info" NEXT="stamp"/>
         <FIELD NAME="stamp" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="infoformat" NEXT="parent"/>
         <FIELD NAME="parent" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="stamp" NEXT="sortorder"/>
         <FIELD NAME="category" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="parent"/>
         <FIELD NAME="parent" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="category" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="parent" NEXT="questiontext"/>
-        <FIELD NAME="questiontext" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="questiontextformat"/>
+        <FIELD NAME="questiontext" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="questiontextformat"/>
         <FIELD NAME="questiontextformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="questiontext" NEXT="generalfeedback"/>
-        <FIELD NAME="generalfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="to store the question feedback" PREVIOUS="questiontextformat" NEXT="generalfeedbackformat"/>
+        <FIELD NAME="generalfeedback" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="to store the question feedback" PREVIOUS="questiontextformat" NEXT="generalfeedbackformat"/>
         <FIELD NAME="generalfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="generalfeedback" NEXT="defaultmark"/>
         <FIELD NAME="defaultmark" TYPE="number" LENGTH="12" NOTNULL="true" DEFAULT="1" SEQUENCE="false" DECIMALS="7" PREVIOUS="generalfeedbackformat" NEXT="penalty"/>
         <FIELD NAME="penalty" TYPE="number" LENGTH="12" NOTNULL="true" DEFAULT="0.3333333" SEQUENCE="false" DECIMALS="7" PREVIOUS="defaultmark" NEXT="qtype"/>
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="question"/>
         <FIELD NAME="question" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="answer"/>
-        <FIELD NAME="answer" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="question" NEXT="answerformat"/>
+        <FIELD NAME="answer" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="question" NEXT="answerformat"/>
         <FIELD NAME="answerformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="answer" NEXT="fraction"/>
         <FIELD NAME="fraction" TYPE="number" LENGTH="12" NOTNULL="true" DEFAULT="0" SEQUENCE="false" DECIMALS="7" PREVIOUS="answerformat" NEXT="feedback"/>
-        <FIELD NAME="feedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="fraction" NEXT="feedbackformat"/>
+        <FIELD NAME="feedback" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="fraction" NEXT="feedbackformat"/>
         <FIELD NAME="feedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="feedback"/>
       </FIELDS>
       <KEYS>
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="questionid"/>
         <FIELD NAME="questionid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="hint"/>
-        <FIELD NAME="hint" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="The text of the feedback to be given." PREVIOUS="questionid" NEXT="hintformat"/>
+        <FIELD NAME="hint" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="The text of the feedback to be given." PREVIOUS="questionid" NEXT="hintformat"/>
         <FIELD NAME="hintformat" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The format of the hint." PREVIOUS="hint" NEXT="shownumcorrect"/>
         <FIELD NAME="shownumcorrect" TYPE="int" LENGTH="1" NOTNULL="false" SEQUENCE="false" COMMENT="Whether the feedback should include a message about how many things the student got right. This is only applicable to certain question types (for example matching or multiple choice multiple-response)." PREVIOUS="hintformat" NEXT="clearwrong"/>
         <FIELD NAME="clearwrong" TYPE="int" LENGTH="1" NOTNULL="false" SEQUENCE="false" COMMENT="Whether any wrong choices should be cleared before the next try. Whether this is applicable, and what it means, depends on the question type, as with the shownumright option." PREVIOUS="shownumcorrect" NEXT="options"/>
         <FIELD NAME="maxmark" TYPE="number" LENGTH="12" NOTNULL="true" SEQUENCE="false" DECIMALS="7" COMMENT="The grade this question is marked out of in this attempt." PREVIOUS="variant" NEXT="minfraction"/>
         <FIELD NAME="minfraction" TYPE="number" LENGTH="12" NOTNULL="true" SEQUENCE="false" DECIMALS="7" COMMENT="Some questions can award negative marks. This indicates the most negative mark that can be awarded, on the faction scale where the maximum positive mark is 1." PREVIOUS="maxmark" NEXT="flagged"/>
         <FIELD NAME="flagged" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether this question has been flagged within the attempt." PREVIOUS="minfraction" NEXT="questionsummary"/>
-        <FIELD NAME="questionsummary" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="If this question uses randomisation, it should set this field to summarise what random version the student actually saw. This is a human-readable textual summary of the student's response which might, for example, be used in a report." PREVIOUS="flagged" NEXT="rightanswer"/>
-        <FIELD NAME="rightanswer" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="This is a human-readable textual summary of the right answer to this question. Might be used, for example on the quiz preview, to help people who are testing the question. Or might be used in reports." PREVIOUS="questionsummary" NEXT="responsesummary"/>
-        <FIELD NAME="responsesummary" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="This is a textual summary of the student's response (basically what you would expect to in the Quiz responses report)." PREVIOUS="rightanswer" NEXT="timemodified"/>
+        <FIELD NAME="questionsummary" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="If this question uses randomisation, it should set this field to summarise what random version the student actually saw. This is a human-readable textual summary of the student's response which might, for example, be used in a report." PREVIOUS="flagged" NEXT="rightanswer"/>
+        <FIELD NAME="rightanswer" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="This is a human-readable textual summary of the right answer to this question. Might be used, for example on the quiz preview, to help people who are testing the question. Or might be used in reports." PREVIOUS="questionsummary" NEXT="responsesummary"/>
+        <FIELD NAME="responsesummary" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="This is a textual summary of the student's response (basically what you would expect to in the Quiz responses report)." PREVIOUS="rightanswer" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The time this record was last changed." PREVIOUS="responsesummary"/>
       </FIELDS>
       <KEYS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="attemptstepid"/>
         <FIELD NAME="attemptstepid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Foreign key, references question_attempt_steps.id" PREVIOUS="id" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="The name of this bit of data." PREVIOUS="attemptstepid" NEXT="value"/>
-        <FIELD NAME="value" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="The corresponding value" PREVIOUS="name"/>
+        <FIELD NAME="value" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="The corresponding value" PREVIOUS="name"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="attemptstepid"/>
         <FIELD NAME="attempt" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="question"/>
         <FIELD NAME="question" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="attempt" NEXT="seq_number"/>
         <FIELD NAME="seq_number" TYPE="int" LENGTH="6" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="question" NEXT="answer"/>
-        <FIELD NAME="answer" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="seq_number" NEXT="timestamp"/>
+        <FIELD NAME="answer" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="seq_number" NEXT="timestamp"/>
         <FIELD NAME="timestamp" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="answer" NEXT="event"/>
         <FIELD NAME="event" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timestamp" NEXT="grade"/>
         <FIELD NAME="grade" TYPE="number" LENGTH="12" NOTNULL="true" DEFAULT="0" SEQUENCE="false" DECIMALS="7" PREVIOUS="event" NEXT="raw_grade"/>
         <FIELD NAME="newest" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="questionid" NEXT="newgraded"/>
         <FIELD NAME="newgraded" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="newest" NEXT="sumpenalty"/>
         <FIELD NAME="sumpenalty" TYPE="number" LENGTH="12" NOTNULL="true" DEFAULT="0" SEQUENCE="false" DECIMALS="7" PREVIOUS="newgraded" NEXT="manualcomment"/>
-        <FIELD NAME="manualcomment" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="sumpenalty" NEXT="manualcommentformat"/>
+        <FIELD NAME="manualcomment" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="sumpenalty" NEXT="manualcommentformat"/>
         <FIELD NAME="manualcommentformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="manualcomment" NEXT="flagged"/>
         <FIELD NAME="flagged" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The person attempting the question may mark certain questions within their question_attempt if the module that owns the attempt allow it. This field stores the status of that flag." PREVIOUS="manualcommentformat"/>
       </FIELDS>
         <FIELD NAME="wwwroot" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="deleted" NEXT="ip_address"/>
         <FIELD NAME="ip_address" TYPE="char" LENGTH="45" NOTNULL="true" SEQUENCE="false" PREVIOUS="wwwroot" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="80" NOTNULL="true" SEQUENCE="false" PREVIOUS="ip_address" NEXT="public_key"/>
-        <FIELD NAME="public_key" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="public_key_expires"/>
+        <FIELD NAME="public_key" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="public_key_expires"/>
         <FIELD NAME="public_key_expires" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="public_key" NEXT="transport"/>
         <FIELD NAME="transport" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="public_key_expires" NEXT="portno"/>
         <FIELD NAME="portno" TYPE="int" LENGTH="5" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="transport" NEXT="last_connect_time"/>
         <FIELD NAME="plugintype" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" PREVIOUS="xmlrpcpath" NEXT="pluginname"/>
         <FIELD NAME="pluginname" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" PREVIOUS="plugintype" NEXT="enabled"/>
         <FIELD NAME="enabled" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="pluginname" NEXT="help"/>
-        <FIELD NAME="help" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" PREVIOUS="enabled" NEXT="profile"/>
-        <FIELD NAME="profile" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" COMMENT="Method signature" PREVIOUS="help" NEXT="filename"/>
+        <FIELD NAME="help" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="enabled" NEXT="profile"/>
+        <FIELD NAME="profile" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Method signature" PREVIOUS="help" NEXT="filename"/>
         <FIELD NAME="filename" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="profile" NEXT="classname"/>
         <FIELD NAME="classname" TYPE="char" LENGTH="150" NOTNULL="false" SEQUENCE="false" PREVIOUS="filename" NEXT="static"/>
         <FIELD NAME="static" TYPE="int" LENGTH="1" NOTNULL="false" SEQUENCE="false" PREVIOUS="classname"/>
     <TABLE NAME="events_queue" COMMENT="This table is for storing queued events. It stores only one copy of the eventdata here, and entries from this table are being references by the event_queue_handlers table." PREVIOUS="mnet_sso_access_control" NEXT="events_handlers">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="eventdata"/>
-        <FIELD NAME="eventdata" TYPE="text" LENGTH="big" NOTNULL="true" SEQUENCE="false" COMMENT="serialized version of the data object passed to the event handler." PREVIOUS="id" NEXT="stackdump"/>
-        <FIELD NAME="stackdump" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="serialized debug_backtrace showing where the event was fired from" PREVIOUS="eventdata" NEXT="userid"/>
+        <FIELD NAME="eventdata" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="serialized version of the data object passed to the event handler." PREVIOUS="id" NEXT="stackdump"/>
+        <FIELD NAME="stackdump" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="serialized debug_backtrace showing where the event was fired from" PREVIOUS="eventdata" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="$USER-&amp;gt;id when the event was fired" PREVIOUS="stackdump" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="time stamp of the first time this was added" PREVIOUS="userid"/>
       </FIELDS>
         <FIELD NAME="eventname" TYPE="char" LENGTH="166" NOTNULL="true" SEQUENCE="false" COMMENT="name of the event, e.g. 'grade_updated'" PREVIOUS="id" NEXT="component"/>
         <FIELD NAME="component" TYPE="char" LENGTH="166" NOTNULL="true" SEQUENCE="false" COMMENT="e.g. moodle, mod_forum, block_rss_client" PREVIOUS="eventname" NEXT="handlerfile"/>
         <FIELD NAME="handlerfile" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="path to the file of the function, eg /grade/export/lib.php" PREVIOUS="component" NEXT="handlerfunction"/>
-        <FIELD NAME="handlerfunction" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="serialized string or array describing function, suitable to be passed to call_user_func()" PREVIOUS="handlerfile" NEXT="schedule"/>
+        <FIELD NAME="handlerfunction" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="serialized string or array describing function, suitable to be passed to call_user_func()" PREVIOUS="handlerfile" NEXT="schedule"/>
         <FIELD NAME="schedule" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="'cron' or 'instant'." PREVIOUS="handlerfunction" NEXT="status"/>
         <FIELD NAME="status" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="number of failed attempts to process this handler" PREVIOUS="schedule" NEXT="internal"/>
         <FIELD NAME="internal" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="1 means standard plugin handler, 0 indicates if event handler sends data to external systems, this is used for example to prevent immediate sending of events from pending db transactions" PREVIOUS="status"/>
         <FIELD NAME="queuedeventid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="foreign key id corresponding to the id of the event_queues table" PREVIOUS="id" NEXT="handlerid"/>
         <FIELD NAME="handlerid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="foreign key id corresponding to the id of the event_handlers table" PREVIOUS="queuedeventid" NEXT="status"/>
         <FIELD NAME="status" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="number of failed attempts to process this handler" PREVIOUS="handlerid" NEXT="errormessage"/>
-        <FIELD NAME="errormessage" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="if an error happened last time we tried to process this event, record it here." PREVIOUS="status" NEXT="timemodified"/>
+        <FIELD NAME="errormessage" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="if an error happened last time we tried to process this event, record it here." PREVIOUS="status" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="time stamp of the last attempt to run this from the queue" PREVIOUS="errormessage"/>
       </FIELDS>
       <KEYS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" COMMENT="id of the table" NEXT="courseid"/>
         <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Mostly these are defined site wide ie NULL" PREVIOUS="id" NEXT="shortname"/>
         <FIELD NAME="shortname" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The short name or code for this outcome statement" PREVIOUS="courseid" NEXT="fullname"/>
-        <FIELD NAME="fullname" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="The full description of the outcome (usually 1 sentence)" PREVIOUS="shortname" NEXT="scaleid"/>
+        <FIELD NAME="fullname" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="The full description of the outcome (usually 1 sentence)" PREVIOUS="shortname" NEXT="scaleid"/>
         <FIELD NAME="scaleid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The recommended scale for this outcome." PREVIOUS="fullname" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="outcome description" PREVIOUS="scaleid" NEXT="descriptionformat"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="outcome description" PREVIOUS="scaleid" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="the time this outcome was first created" PREVIOUS="descriptionformat" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="the time this outcome was last updated" PREVIOUS="timecreated" NEXT="usermodified"/>
         <FIELD NAME="itemmodule" TYPE="char" LENGTH="30" NOTNULL="false" SEQUENCE="false" COMMENT="'forum', 'quiz', 'csv', etc" PREVIOUS="itemtype" NEXT="iteminstance"/>
         <FIELD NAME="iteminstance" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="id of the item module" PREVIOUS="itemmodule" NEXT="itemnumber"/>
         <FIELD NAME="itemnumber" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Can be used to distinguish multiple grades for an activity" PREVIOUS="iteminstance" NEXT="iteminfo"/>
-        <FIELD NAME="iteminfo" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="Info and notes about this item XXX" PREVIOUS="itemnumber" NEXT="idnumber"/>
+        <FIELD NAME="iteminfo" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Info and notes about this item XXX" PREVIOUS="itemnumber" NEXT="idnumber"/>
         <FIELD NAME="idnumber" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Arbitrary idnumber provided by the module responsible" PREVIOUS="iteminfo" NEXT="calculation"/>
-        <FIELD NAME="calculation" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="Formula describing how to derive this grade from other items, referring to them using giXXX where XXX is grade item id ... eg something like: =sin(square([#gi20#])) + [#gi30#]" PREVIOUS="idnumber" NEXT="gradetype"/>
+        <FIELD NAME="calculation" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Formula describing how to derive this grade from other items, referring to them using giXXX where XXX is grade item id ... eg something like: =sin(square([#gi20#])) + [#gi30#]" PREVIOUS="idnumber" NEXT="gradetype"/>
         <FIELD NAME="gradetype" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="0 = none, 1 = value, 2 = scale, 3 = text" PREVIOUS="calculation" NEXT="grademax"/>
         <FIELD NAME="grademax" TYPE="number" LENGTH="10" NOTNULL="true" DEFAULT="100" SEQUENCE="false" DECIMALS="5" COMMENT="What is the maximum allowable grade?" PREVIOUS="gradetype" NEXT="grademin"/>
         <FIELD NAME="grademin" TYPE="number" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" DECIMALS="5" COMMENT="What is the minimum allowable grade?" PREVIOUS="grademax" NEXT="scaleid"/>
         <FIELD NAME="exported" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="date of last grade export, 0 if none" PREVIOUS="locktime" NEXT="overridden"/>
         <FIELD NAME="overridden" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="indicates grade overridden from gradebook, 0 means none, date means overridden" PREVIOUS="exported" NEXT="excluded"/>
         <FIELD NAME="excluded" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="grade excluded from aggregation functions, date means when excluded" PREVIOUS="overridden" NEXT="feedback"/>
-        <FIELD NAME="feedback" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="grading feedback" PREVIOUS="excluded" NEXT="feedbackformat"/>
+        <FIELD NAME="feedback" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="grading feedback" PREVIOUS="excluded" NEXT="feedbackformat"/>
         <FIELD NAME="feedbackformat" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="format of feedback text" PREVIOUS="feedback" NEXT="information"/>
-        <FIELD NAME="information" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="optiona information" PREVIOUS="feedbackformat" NEXT="informationformat"/>
+        <FIELD NAME="information" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="optiona information" PREVIOUS="feedbackformat" NEXT="informationformat"/>
         <FIELD NAME="informationformat" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="format of information text" PREVIOUS="information" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="the time this grade was first created" PREVIOUS="informationformat" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="the time this grade was last modified" PREVIOUS="timecreated"/>
         <FIELD NAME="loggeduser" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="the userid of the person who last modified this outcome" PREVIOUS="timemodified" NEXT="courseid"/>
         <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Mostly these are defined site wide ie NULL" PREVIOUS="loggeduser" NEXT="shortname"/>
         <FIELD NAME="shortname" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The short name or code for this outcome statement" PREVIOUS="courseid" NEXT="fullname"/>
-        <FIELD NAME="fullname" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="The full description of the outcome (usually 1 sentence)" PREVIOUS="shortname" NEXT="scaleid"/>
+        <FIELD NAME="fullname" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="The full description of the outcome (usually 1 sentence)" PREVIOUS="shortname" NEXT="scaleid"/>
         <FIELD NAME="scaleid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The recommended scale for this outcome." PREVIOUS="fullname" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Outcome description" PREVIOUS="scaleid" NEXT="descriptionformat"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Outcome description" PREVIOUS="scaleid" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description"/>
       </FIELDS>
       <KEYS>
         <FIELD NAME="itemmodule" TYPE="char" LENGTH="30" NOTNULL="false" SEQUENCE="false" COMMENT="'forum', 'quiz', 'csv', etc" PREVIOUS="itemtype" NEXT="iteminstance"/>
         <FIELD NAME="iteminstance" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="id of the item module" PREVIOUS="itemmodule" NEXT="itemnumber"/>
         <FIELD NAME="itemnumber" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Can be used to distinguish multiple grades for an activity" PREVIOUS="iteminstance" NEXT="iteminfo"/>
-        <FIELD NAME="iteminfo" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="Info and notes about this item XXX" PREVIOUS="itemnumber" NEXT="idnumber"/>
+        <FIELD NAME="iteminfo" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Info and notes about this item XXX" PREVIOUS="itemnumber" NEXT="idnumber"/>
         <FIELD NAME="idnumber" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Arbitrary idnumber provided by the module responsible" PREVIOUS="iteminfo" NEXT="calculation"/>
-        <FIELD NAME="calculation" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="Formula describing how to derive this grade from other items, referring to them using giXXX where XXX is grade item id ... eg something like: =sin(square([#gi20#])) + [#gi30#]" PREVIOUS="idnumber" NEXT="gradetype"/>
+        <FIELD NAME="calculation" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Formula describing how to derive this grade from other items, referring to them using giXXX where XXX is grade item id ... eg something like: =sin(square([#gi20#])) + [#gi30#]" PREVIOUS="idnumber" NEXT="gradetype"/>
         <FIELD NAME="gradetype" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="0 = none, 1 = value, 2 = scale, 3 = text" PREVIOUS="calculation" NEXT="grademax"/>
         <FIELD NAME="grademax" TYPE="number" LENGTH="10" NOTNULL="true" DEFAULT="100" SEQUENCE="false" DECIMALS="5" COMMENT="What is the maximum allowable grade?" PREVIOUS="gradetype" NEXT="grademin"/>
         <FIELD NAME="grademin" TYPE="number" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" DECIMALS="5" COMMENT="What is the minimum allowable grade?" PREVIOUS="grademax" NEXT="scaleid"/>
         <FIELD NAME="exported" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="date of last grade export, 0 if none" PREVIOUS="locktime" NEXT="overridden"/>
         <FIELD NAME="overridden" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="indicates grade overridden from gradebook, 0 means none, date means overridden" PREVIOUS="exported" NEXT="excluded"/>
         <FIELD NAME="excluded" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="grade excluded from aggregation functions, date means when excluded" PREVIOUS="overridden" NEXT="feedback"/>
-        <FIELD NAME="feedback" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="grading feedback" PREVIOUS="excluded" NEXT="feedbackformat"/>
+        <FIELD NAME="feedback" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="grading feedback" PREVIOUS="excluded" NEXT="feedbackformat"/>
         <FIELD NAME="feedbackformat" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="format of feedback text" PREVIOUS="feedback" NEXT="information"/>
-        <FIELD NAME="information" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="optiona information" PREVIOUS="feedbackformat" NEXT="informationformat"/>
+        <FIELD NAME="information" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="optiona information" PREVIOUS="feedbackformat" NEXT="informationformat"/>
         <FIELD NAME="informationformat" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="format of information text" PREVIOUS="information"/>
       </FIELDS>
       <KEYS>
         <FIELD NAME="newgradeitem" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="if set, points to the id of grade_import_newitem" PREVIOUS="itemid" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="newgradeitem" NEXT="finalgrade"/>
         <FIELD NAME="finalgrade" TYPE="number" LENGTH="10" NOTNULL="false" SEQUENCE="false" DECIMALS="5" COMMENT="raw grade value" PREVIOUS="userid" NEXT="feedback"/>
-        <FIELD NAME="feedback" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" PREVIOUS="finalgrade" NEXT="importcode"/>
+        <FIELD NAME="feedback" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="finalgrade" NEXT="importcode"/>
         <FIELD NAME="importcode" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="similar to backup_code, a unique batch code for identifying one batch of imports" PREVIOUS="feedback" NEXT="importer"/>
         <FIELD NAME="importer" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" PREVIOUS="importcode"/>
       </FIELDS>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid" NEXT="rawname"/>
         <FIELD NAME="rawname" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The raw, unnormalised name for the tag as entered by users" PREVIOUS="name" NEXT="tagtype"/>
         <FIELD NAME="tagtype" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" PREVIOUS="rawname" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="tagtype" NEXT="descriptionformat"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="tagtype" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="flag"/>
         <FIELD NAME="flag" TYPE="int" LENGTH="4" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="a tag can be 'flagged' as inappropriate" PREVIOUS="descriptionformat" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" PREVIOUS="flag"/>
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="tagid"/>
         <FIELD NAME="tagid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="correlatedtags"/>
-        <FIELD NAME="correlatedtags" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="tagid"/>
+        <FIELD NAME="correlatedtags" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="tagid"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="tagid"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="courseid"/>
         <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false" COMMENT="Short human readable unique name for the group." PREVIOUS="courseid" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="descriptionformat"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="enrolmentkey"/>
         <FIELD NAME="enrolmentkey" TYPE="char" LENGTH="50" NOTNULL="false" SEQUENCE="false" PREVIOUS="descriptionformat" NEXT="picture"/>
         <FIELD NAME="picture" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="enrolmentkey" NEXT="hidepicture"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="courseid"/>
         <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="Short human readable unique name for group." PREVIOUS="courseid" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="descriptionformat"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="description" NEXT="configdata"/>
-        <FIELD NAME="configdata" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="extra configuration data - may be used by group IU tools" PREVIOUS="descriptionformat" NEXT="timecreated"/>
+        <FIELD NAME="configdata" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="extra configuration data - may be used by group IU tools" PREVIOUS="descriptionformat" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="configdata" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timecreated"/>
       </FIELDS>
         <FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Context is usually ignored in sync operations so that the cohorts may be moved freely around in the context tree without any side affects." PREVIOUS="id" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false" COMMENT="Short human readable name for the cohort, does not have to be unique" PREVIOUS="contextid" NEXT="idnumber"/>
         <FIELD NAME="idnumber" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" COMMENT="Unique identifier of a cohort, useful especially for mapping to external entities" PREVIOUS="name" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="Standard description text box" PREVIOUS="idnumber" NEXT="descriptionformat"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Standard description text box" PREVIOUS="idnumber" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" SEQUENCE="false" PREVIOUS="description" NEXT="component"/>
         <FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" COMMENT="Component (plugintype_pluignname) that manages the cohort, manual modifications are allowed only when set to NULL" PREVIOUS="descriptionformat" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="component" NEXT="timemodified"/>
         <FIELD NAME="flagtype" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="flagtype" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="name" NEXT="value"/>
-        <FIELD NAME="value" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" PREVIOUS="timemodified" NEXT="expiry"/>
+        <FIELD NAME="value" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="timemodified" NEXT="expiry"/>
         <FIELD NAME="expiry" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="value"/>
       </FIELDS>
       <KEYS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="courseid"/>
         <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="courseid" NEXT="value"/>
-        <FIELD NAME="value" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="name"/>
+        <FIELD NAME="value" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="name"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="courseid"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="instance"/>
         <FIELD NAME="instance" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="instance of plugin we're configurating" PREVIOUS="id" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="config field" PREVIOUS="instance" NEXT="value"/>
-        <FIELD NAME="value" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="config value" PREVIOUS="name"/>
+        <FIELD NAME="value" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="config value" PREVIOUS="name"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="instancefk"/>
         <FIELD NAME="instance" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="fk to instance table" PREVIOUS="id" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="fk to user table" PREVIOUS="instance" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="name of config item" PREVIOUS="userid" NEXT="value"/>
-        <FIELD NAME="value" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="value of config item" PREVIOUS="name"/>
+        <FIELD NAME="value" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="value of config item" PREVIOUS="name"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="instancefk"/>
     <TABLE NAME="portfolio_tempdata" COMMENT="stores temporary data for portfolio exports. the id of this table is used for the itemid for the temporary files area.  cron can clean up stale records (and associated file data) after expirytime." PREVIOUS="portfolio_log" NEXT="message_providers">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="data"/>
-        <FIELD NAME="data" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="dumping ground for portfolio callers to store their data in." PREVIOUS="id" NEXT="expirytime"/>
+        <FIELD NAME="data" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="dumping ground for portfolio callers to store their data in." PREVIOUS="id" NEXT="expirytime"/>
         <FIELD NAME="expirytime" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="time this record will expire (used for cron cleanups) - the start of export + 24 hours" PREVIOUS="data" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="psuedo fk to user.  this is stored in the serialised data structure in the data field, but added here for ease of lookups." PREVIOUS="expirytime" NEXT="instance"/>
         <FIELD NAME="instance" TYPE="int" LENGTH="10" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="which portfolio plugin instance is being used" PREVIOUS="userid"/>
         <FIELD NAME="filesize" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid" NEXT="mimetype"/>
         <FIELD NAME="mimetype" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" COMMENT="type of file - jpeg image, open document spreadsheet" PREVIOUS="filesize" NEXT="status"/>
         <FIELD NAME="status" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="number greater than 0 means something is wrong with this file (virus, missing, etc.)" PREVIOUS="mimetype" NEXT="source"/>
-        <FIELD NAME="source" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="contains the reference if the file is imported from external sites" PREVIOUS="status" NEXT="author"/>
+        <FIELD NAME="source" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="contains the reference if the file is imported from external sites" PREVIOUS="status" NEXT="author"/>
         <FIELD NAME="author" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="The original author of the file" PREVIOUS="source" NEXT="license"/>
         <FIELD NAME="license" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="license of the file to guide reuse" PREVIOUS="author" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="license" NEXT="timemodified"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="instanceid"/>
         <FIELD NAME="instanceid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="instanceid" NEXT="value"/>
-        <FIELD NAME="value" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" PREVIOUS="name"/>
+        <FIELD NAME="value" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="name"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
         <FIELD NAME="table_name" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" PREVIOUS="backup_code" NEXT="old_id"/>
         <FIELD NAME="old_id" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="table_name" NEXT="new_id"/>
         <FIELD NAME="new_id" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="old_id" NEXT="info"/>
-        <FIELD NAME="info" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" PREVIOUS="new_id"/>
+        <FIELD NAME="info" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="new_id"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="backup_code-table_name-old_id"/>
         <FIELD NAME="subpagepattern" TYPE="char" LENGTH="16" NOTNULL="false" SEQUENCE="false" COMMENT="Further restrictions on where this block appears. In some places, e.g. during a quiz or lesson attempt, different pages have different subpage ids. If this field is not null, the block only appears on that particular subpage." PREVIOUS="pagetypepattern" NEXT="defaultregion"/>
         <FIELD NAME="defaultregion" TYPE="char" LENGTH="16" NOTNULL="true" SEQUENCE="false" COMMENT="Which block region this block should appear in on each page, in the absence of a specific position in the block_positions table." PREVIOUS="subpagepattern" NEXT="defaultweight"/>
         <FIELD NAME="defaultweight" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Used to order the blocks within a block region. Again, may be overridden by the block_positions table for a specific page where this block appears." PREVIOUS="defaultregion" NEXT="configdata"/>
-        <FIELD NAME="configdata" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="A serialized blob of configuration data for this block instance." PREVIOUS="defaultweight"/>
+        <FIELD NAME="configdata" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="A serialized blob of configuration data for this block instance." PREVIOUS="defaultweight"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="parentcontextid"/>
         <FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="commentarea"/>
         <FIELD NAME="commentarea" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="contextid" NEXT="itemid"/>
         <FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="commentarea" NEXT="content"/>
-        <FIELD NAME="content" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="itemid" NEXT="format"/>
+        <FIELD NAME="content" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="itemid" NEXT="format"/>
         <FIELD NAME="format" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="content" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="format" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="userid"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="url"/>
-        <FIELD NAME="url" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="description" NEXT="filtertags"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="url"/>
+        <FIELD NAME="url" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="description" NEXT="filtertags"/>
         <FIELD NAME="filtertags" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Comma-separated list of tags that will be used to filter which entries are copied over from the external blog. They refer to existing tags in the external blog." PREVIOUS="url" NEXT="failedlastsync"/>
         <FIELD NAME="failedlastsync" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether or not the last sync failed for some reason" PREVIOUS="filtertags" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" PREVIOUS="failedlastsync" NEXT="timefetched"/>
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="shortname"/>
         <FIELD NAME="shortname" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" PREVIOUS="id" NEXT="fullname"/>
-        <FIELD NAME="fullname" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="shortname" NEXT="source"/>
+        <FIELD NAME="fullname" TYPE="text" NOTNULL="false" SEQUENCE="false" PREVIOUS="shortname" NEXT="source"/>
         <FIELD NAME="source" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" PREVIOUS="fullname" NEXT="enabled"/>
         <FIELD NAME="enabled" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="source" NEXT="version"/>
         <FIELD NAME="version" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="enabled"/>
         <FIELD NAME="checksum" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="checksum of the backup_controller object" PREVIOUS="executiontime" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="time the controller was created" PREVIOUS="checksum" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="last time the controller was modified" PREVIOUS="timecreated" NEXT="controller"/>
-        <FIELD NAME="controller" TYPE="text" LENGTH="big" NOTNULL="true" SEQUENCE="false" COMMENT="serialised backup_controller object" PREVIOUS="timemodified"/>
+        <FIELD NAME="controller" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="serialised backup_controller object" PREVIOUS="timemodified"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="backupid_uk"/>
         <FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="id of the component (usually table-&amp;gt;id values)" PREVIOUS="itemname" NEXT="newitemid"/>
         <FIELD NAME="newitemid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="new id of the component after restore" PREVIOUS="itemid" NEXT="parentitemid"/>
         <FIELD NAME="parentitemid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="other id that can be useful to represent parent-child relations" PREVIOUS="newitemid" NEXT="info"/>
-        <FIELD NAME="info" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="to store information related with the item, base64(serialize())" PREVIOUS="parentitemid"/>
+        <FIELD NAME="info" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="to store information related with the item, base64(serialize())" PREVIOUS="parentitemid"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="backupid_itemname_itemid_uk"/>
         <FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="contextid" NEXT="filearea"/>
         <FIELD NAME="filearea" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false" PREVIOUS="component" NEXT="itemid"/>
         <FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="filearea" NEXT="info"/>
-        <FIELD NAME="info" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" COMMENT="to store the complete file record (serialized)" PREVIOUS="itemid"/>
+        <FIELD NAME="info" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="to store the complete file record (serialized)" PREVIOUS="itemid"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="runid"/>
         <FIELD NAME="runid" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="the unique id for this run (as generated by xhprof)" PREVIOUS="id" NEXT="url"/>
         <FIELD NAME="url" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="the url this profiling record is about (without wwwroot nor query params)" PREVIOUS="runid" NEXT="data"/>
-        <FIELD NAME="data" TYPE="text" LENGTH="big" NOTNULL="true" SEQUENCE="false" COMMENT="the raw data gathered by xhprof" PREVIOUS="url" NEXT="totalexecutiontime"/>
+        <FIELD NAME="data" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="the raw data gathered by xhprof" PREVIOUS="url" NEXT="totalexecutiontime"/>
         <FIELD NAME="totalexecutiontime" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="time (in microseconds) spent by the run" PREVIOUS="data" NEXT="totalcputime"/>
         <FIELD NAME="totalcputime" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="time (in microseconds) spent by the CPU in this run" PREVIOUS="totalexecutiontime" NEXT="totalcalls"/>
         <FIELD NAME="totalcalls" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Total number of calls performed by the run" PREVIOUS="totalcputime" NEXT="totalmemory"/>
         <FIELD NAME="areaid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="method"/>
         <FIELD NAME="method" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" COMMENT="The name of the plugin providing this grading form" PREVIOUS="areaid" NEXT="name"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The title of the form that helps users to identify it" PREVIOUS="method" NEXT="description"/>
-        <FIELD NAME="description" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="More detailed description of the form" PREVIOUS="name" NEXT="descriptionformat"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="More detailed description of the form" PREVIOUS="name" NEXT="descriptionformat"/>
         <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="false" SEQUENCE="false" COMMENT="Format of the description field" PREVIOUS="description" NEXT="status"/>
         <FIELD NAME="status" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Status of the form definition, by default in the under-construction state" PREVIOUS="descriptionformat" NEXT="copiedfromid"/>
         <FIELD NAME="copiedfromid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The id of the original definition that this was initially copied from or null if it was from scratch" PREVIOUS="status" NEXT="timecreated"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The time stamp of when the form definition was modified recently" PREVIOUS="usercreated" NEXT="usermodified"/>
         <FIELD NAME="usermodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The ID of the user who did the most recent modification" PREVIOUS="timemodified" NEXT="timecopied"/>
         <FIELD NAME="timecopied" TYPE="int" LENGTH="10" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="The timestamp of when this form was most recently copied into another area" PREVIOUS="usermodified" NEXT="options"/>
-        <FIELD NAME="options" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="General field to be used by plugins as a general storage place for their own settings" PREVIOUS="timecopied"/>
+        <FIELD NAME="options" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="General field to be used by plugins as a general storage place for their own settings" PREVIOUS="timecopied"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="fk_areaid"/>
         <FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="This identifies the graded item within the grabable area" PREVIOUS="raterid" NEXT="rawgrade"/>
         <FIELD NAME="rawgrade" TYPE="number" LENGTH="10" NOTNULL="false" SEQUENCE="false" DECIMALS="5" COMMENT="The raw normalized grade 0.00000 - 100.00000 as a result of the most recent assessment" PREVIOUS="itemid" NEXT="status"/>
         <FIELD NAME="status" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The status of the assessment. By default the instance is under-assessment state" PREVIOUS="rawgrade" NEXT="feedback"/>
-        <FIELD NAME="feedback" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" COMMENT="Overall feedback from the rater for the author of the graded item" PREVIOUS="status" NEXT="feedbackformat"/>
+        <FIELD NAME="feedback" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Overall feedback from the rater for the author of the graded item" PREVIOUS="status" NEXT="feedbackformat"/>
         <FIELD NAME="feedbackformat" TYPE="int" LENGTH="2" NOTNULL="false" SEQUENCE="false" COMMENT="The format of the feedback field" PREVIOUS="feedback" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The timestamp of when the assessment was most recently modified" PREVIOUS="feedbackformat"/>
       </FIELDS>
index d335eb4..c42d27c 100644 (file)
@@ -204,6 +204,14 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012030100.02);
     }
 
+    if ($oldversion < 2012030900.01) {
+        // migrate all texts and binaries to big size - it should be safe to interrupt this and continue later
+        upgrade_mysql_fix_lob_columns();
+
+        // Main savepoint reached
+        upgrade_main_savepoint(true, 2012030900.01);
+    }
+
 
     return true;
 }
index d589a5a..7960694 100644 (file)
@@ -83,3 +83,57 @@ function upgrade_mysql_fix_unsigned_columns() {
         $pbar->update($i, $tablecount, "Converted unsigned columns in MySQL database - $i/$tablecount.");
     }
 }
+
+/**
+ * Migrate all text and binary columns to big size - mysql only.
+ */
+function upgrade_mysql_fix_lob_columns() {
+    // we are not using standard API for changes of column intentionally
+
+    global $DB;
+
+    if ($DB->get_dbfamily() !== 'mysql') {
+        return;
+    }
+
+    $pbar = new progress_bar('mysqlconvertlobs', 500, true);
+
+    $prefix = $DB->get_prefix();
+    $tables = $DB->get_tables();
+    asort($tables);
+
+    $tablecount = count($tables);
+    $i = 0;
+    foreach ($tables as $table) {
+        $i++;
+        // set appropriate timeout - 1 minute per thousand of records should be enough, min 60 minutes just in case
+        $count = $DB->count_records($table, array());
+        $timeout = ($count/1000)*60;
+        $timeout = ($timeout < 60*60) ? 60*60 : (int)$timeout;
+
+        $sql = "SHOW COLUMNS FROM `{{$table}}`";
+        $rs = $DB->get_recordset_sql($sql);
+        foreach ($rs as $column) {
+            upgrade_set_timeout($timeout);
+
+            $column = (object)array_change_key_case((array)$column, CASE_LOWER);
+            if ($column->type === 'tinytext' or $column->type === 'mediumtext' or $column->type === 'text') {
+                $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
+                $default = !is_null($column->default) ? "DEFAULT '$column->default'" : '';
+                // primary, unique and inc are not supported for texts
+                $sql = "ALTER TABLE `{$prefix}$table` MODIFY COLUMN `$column->field` LONGTEXT $notnull $default";
+                $DB->change_database_structure($sql);
+            }
+            if ($column->type === 'tinyblob' or $column->type === 'mediumblob' or $column->type === 'blob') {
+                $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
+                $default = !is_null($column->default) ? "DEFAULT '$column->default'" : '';
+                // primary, unique and inc are not supported for blobs
+                $sql = "ALTER TABLE `{$prefix}$table` MODIFY COLUMN `$column->field` LONGBLOB $notnull $default";
+                $DB->change_database_structure($sql);
+            }
+        }
+        $rs->close();
+
+        $pbar->update($i, $tablecount, "Converted LOB columns in MySQL database - $i/$tablecount.");
+    }
+}
index e1b9453..22d24e4 100644 (file)
@@ -221,57 +221,6 @@ class database_manager {
         return ($this->find_index_name($xmldb_table, $xmldb_index) !== false);
     }
 
-    /**
-     * Given one xmldb_field, the function returns the name of the check constraint in DB (if exists)
-     * of false if it doesn't exist. Note that XMLDB limits the number of check constraints per field
-     * to 1 "enum-like" constraint. So, if more than one is returned, only the first one will be
-     * retrieved by this function.
-     *
-     * @todo MDL-31147 Moodle 2.1 - Drop find_check_constraint_name()
-     *
-     * @param xmldb_table $xmldb_table The table to be searched.
-     * @param xmldb_field $xmldb_field The field to be searched.
-     * @return string|bool check constraint name or false
-     */
-    public function find_check_constraint_name(xmldb_table $xmldb_table, xmldb_field $xmldb_field) {
-
-    /// Check the table exists
-        if (!$this->table_exists($xmldb_table)) {
-            throw new ddl_table_missing_exception($xmldb_table->getName());
-        }
-
-    /// Check the field exists
-        if (!$this->field_exists($xmldb_table, $xmldb_field)) {
-            throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName());
-        }
-
-    /// Get list of check_constraints in table/field
-        $checks = false;
-        if ($objchecks = $this->generator->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
-        /// Get only the 1st element. Shouldn't be more than 1 under XMLDB
-            $objcheck = array_shift($objchecks);
-            if ($objcheck) {
-                $checks = strtolower($objcheck->name);
-            }
-        }
-
-    /// Arriving here, check not found
-        return $checks;
-    }
-
-    /**
-     * Given one xmldb_field, check if it has a check constraint in DB
-     *
-     * TODO: Moodle 2.1 - Drop check_constraint_exists()
-     *
-     * @param xmldb_table $xmldb_table The table.
-     * @param xmldb_field $xmldb_field The field to be searched for any existing constraint.
-     * @return boolean true/false
-     */
-    public function check_constraint_exists(xmldb_table $xmldb_table, xmldb_field $xmldb_field) {
-        return ($this->find_check_constraint_name($xmldb_table, $xmldb_field) !== false);
-    }
-
     /**
      * This function IS NOT IMPLEMENTED. ONCE WE'LL BE USING RELATIONAL
      * INTEGRITY IT WILL BECOME MORE USEFUL. FOR NOW, JUST CALCULATE "OFFICIAL"
@@ -707,37 +656,6 @@ class database_manager {
         $this->execute_sql_arr($sqlarr);
     }
 
-    /**
-     * This function will drop the existing enum of the field in the table passed as arguments
-     *
-     * TODO: Moodle 2.1 - Drop drop_enum_from_field()
-     *
-     * @param xmldb_table $xmldb_table Table object (just the name is mandatory).
-     * @param xmldb_field $xmldb_field Index object (full specs are required).
-     * @return void
-     */
-    public function drop_enum_from_field(xmldb_table $xmldb_table, xmldb_field $xmldb_field) {
-        if (!$this->table_exists($xmldb_table)) {
-            throw new ddl_table_missing_exception($xmldb_table->getName());
-        }
-    /// Check the field exists
-        if (!$this->field_exists($xmldb_table, $xmldb_field)) {
-            throw new ddl_field_missing_exception($xmldb_field->getName(), $xmldb_table->getName());
-        }
-
-        if (!$this->check_constraint_exists($xmldb_table, $xmldb_field)) {
-            debugging('Enum for ' . $xmldb_table->getName() . '->' . $xmldb_field->getName() .
-                      ' does not exist. Delete skipped', DEBUG_DEVELOPER);
-            return; //Enum does not exist, nothing to delete
-        }
-
-        if (!$sqlarr = $this->generator->getDropEnumSQL($xmldb_table, $xmldb_field)) {
-            return; //Empty array = nothing to do = no error
-        }
-
-        $this->execute_sql_arr($sqlarr);
-    }
-
     /**
      * This function will rename the field in the table passed as arguments
      * Before renaming the field, the function will check it exists
index e11176f..b24ab45 100644 (file)
@@ -51,8 +51,6 @@ class mssql_sql_generator extends sql_generator {
     public $sequence_name = 'IDENTITY(1,1)'; //Particular name for inline sequences in this generator
     public $sequence_only = false; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name variable
 
-    public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
-
     public $add_table_comments  = false;  // Does the generator need to add code for table comments
 
     public $concat_character = '+'; //Characters to be used as concatenation operator. If not defined
@@ -214,11 +212,6 @@ class mssql_sql_generator extends sql_generator {
             $results[] = 'ALTER TABLE ' . $tablename . ' DROP CONSTRAINT ' . $defaultname;
         }
 
-    /// Look for any check constraint in this field and drop it
-        if ($drop_check = $this->getDropEnumSQL($xmldb_table, $xmldb_field)) {
-            $results = array_merge($results, $drop_check);
-        }
-
     /// Build the standard alter table drop column
         $results[] = 'ALTER TABLE ' . $tablename . ' DROP COLUMN ' . $fieldname;
 
@@ -259,22 +252,6 @@ class mssql_sql_generator extends sql_generator {
 
         $results = array();
 
-        $newt = new xmldb_table($newname); //Temporal table for name calculations
-
-        $oldtablename = $this->getTableName($xmldb_table);
-        $newtablename = $this->getTableName($newt);
-
-    /// Rename all the check constraints in the table
-        $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
-        $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
-
-        if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
-            foreach ($constraints as $constraint) {
-            /// Drop the old constraint
-                $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
-            }
-        }
-
         return $results;
     }
 
@@ -435,25 +412,6 @@ class mssql_sql_generator extends sql_generator {
         return $results;
     }
 
-    /**
-     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its enum
-     * (usually invoked from getModifyEnumSQL()
-     *
-     * TODO: Moodle 2.1 - drop in Moodle 2.1
-     */
-    public function getDropEnumSQL($xmldb_table, $xmldb_field) {
-    /// Let's introspect to know the real name of the check constraint
-        if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
-            $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
-            $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
-        /// All we have to do is to drop the check constraint
-            return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
-                     ' DROP CONSTRAINT ' . $constraint_name);
-        } else { /// Constraint not found. Nothing to do
-            return array();
-        }
-    }
-
     /**
      * Given one xmldb_table and one xmldb_field, return the SQL statements needed to create its default
      * (usually invoked from getModifyDefaultSQL()
@@ -521,55 +479,6 @@ class mssql_sql_generator extends sql_generator {
         }
     }
 
-    /**
-     * Given one xmldb_table returns one array with all the check constraints
-     * in the table (fetched from DB)
-     * Optionally the function allows one xmldb_field to be specified in
-     * order to return only the check constraints belonging to one field.
-     * Each element contains the name of the constraint and its description
-     * If no check constraints are found, returns an empty array
-     *
-     * TODO: Moodle 2.1 - drop in Moodle 2.1
-     */
-    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
-
-
-        $results = array();
-
-        $tablename = $this->getTableName($xmldb_table);
-
-        if ($constraints = $this->mdb->get_records_sql("SELECT o.name, c.text AS description
-                                                          FROM sysobjects o,
-                                                               sysobjects p,
-                                                               syscomments c
-                                                         WHERE p.id = o.parent_obj
-                                                               AND o.id = c.id
-                                                               AND o.xtype = 'C'
-                                                               AND p.name = ?", array($tablename))) {
-            foreach ($constraints as $constraint) {
-                $results[$constraint->name] = $constraint;
-            }
-        }
-
-    /// Filter by the required field if specified
-        if ($xmldb_field) {
-            $filtered_results = array();
-            $filter = $xmldb_field->getName();
-        /// Lets clean a bit each constraint description, looking for the filtered field
-            foreach ($results as $key => $result) {
-                $description = trim(preg_replace('/[\(\)]/', '',  $result->description));   // Parenthesis out & trim
-                /// description starts by [$filter] assume it's a constraint belonging to the field
-                if (preg_match("/^\[{$filter}\]/i", $description)) {
-                    $filtered_results[$key] = $result;
-                }
-            }
-        /// Assign filtered results to the final results array
-            $results =  $filtered_results;
-        }
-
-        return $results;
-    }
-
     /**
      * Given three strings (table name, list of fields (comma separated) and suffix),
      * create the proper object name quoting it if necessary.
index 5f89363..11e241a 100644 (file)
@@ -59,8 +59,6 @@ class mysql_sql_generator extends sql_generator {
     public $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields
     public $sequence_name = 'auto_increment'; //Particular name for inline sequences in this generator
 
-    public $enum_extra_code = false; //Does the generator need to add extra code to generate code for the enums in the table
-
     public $add_after_clause = true; // Does the generator need to add the after clause for fields
 
     public $concat_character = null; //Characters to be used as concatenation operator. If not defined
@@ -204,28 +202,10 @@ class mysql_sql_generator extends sql_generator {
                 $dbtype .= '(' . $xmldb_length . ')';
                 break;
             case XMLDB_TYPE_TEXT:
-                if (empty($xmldb_length)) {
-                    $xmldb_length = 'small';
-                }
-                if ($xmldb_length == 'small') {
-                    $dbtype = 'TEXT';
-                } else if ($xmldb_length == 'medium') {
-                    $dbtype = 'MEDIUMTEXT';
-                } else {
-                    $dbtype = 'LONGTEXT';
-                }
+                $dbtype = 'LONGTEXT';
                 break;
             case XMLDB_TYPE_BINARY:
-                if (empty($xmldb_length)) {
-                    $xmldb_length = 'small';
-                }
-                if ($xmldb_length == 'small') {
-                    $dbtype = 'BLOB';
-                } else if ($xmldb_length == 'medium') {
-                    $dbtype = 'MEDIUMBLOB';
-                } else {
-                    $dbtype = 'LONGBLOB';
-                }
+                $dbtype = 'LONGBLOB';
                 break;
             case XMLDB_TYPE_DATETIME:
                 $dbtype = 'DATETIME';
@@ -233,31 +213,6 @@ class mysql_sql_generator extends sql_generator {
         return $dbtype;
     }
 
-    /**
-     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to create its enum
-     * (usually invoked from getModifyEnumSQL()
-     */
-    public function getCreateEnumSQL($xmldb_table, $xmldb_field) {
-    /// For MySQL, just alter the field
-        return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
-    }
-
-    /**
-     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its enum
-     * (usually invoked from getModifyEnumSQL()
-     *
-     * TODO: Moodle 2.1 - drop in Moodle 2.1
-     */
-    public function getDropEnumSQL($xmldb_table, $xmldb_field) {
-    /// Let's introspect to know if there is one enum
-        if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
-        /// For MySQL, just alter the field
-            return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
-        } else {
-            return array(); /// Enum not found. Nothing to do
-        }
-    }
-
     /**
      * Given one xmldb_table and one xmldb_field, return the SQL statements needed to create its default
      * (usually invoked from getModifyDefaultSQL()
@@ -311,59 +266,6 @@ class mysql_sql_generator extends sql_generator {
         return array($comment);
     }
 
-    /**
-     * Given one xmldb_table returns one array with all the check constraints
-     * in the table (fetched from DB)
-     * Optionally the function allows one xmldb_field to be specified in
-     * order to return only the check constraints belonging to one field.
-     * Each element contains the name of the constraint and its description
-     * If no check constraints are found, returns an empty array
-     * MySQL doesn't have check constraints in this implementation, but
-     * we return them based on the enum fields in the table
-     *
-     * TODO: Moodle 2.1 - drop in Moodle 2.1
-     */
-    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
-
-        $tablename = $xmldb_table->getName($xmldb_table);
-
-    /// Fetch all the columns in the table
-        if (!$columns = $this->mdb->get_columns($tablename)) {
-            return array();
-        }
-
-    /// Filter by the required field if specified
-        if ($xmldb_field) {
-            $filter = $xmldb_field->getName();
-            if (!isset($columns[$filter])) {
-                return array();
-            }
-            $column = ($columns[$filter]);
-            if (!empty($column->enums)) {
-                $result = new stdClass();
-                $result->name = $filter;
-                $result->description = implode(', ', $column->enums);
-                return array($result);
-            } else {
-                return array();
-            }
-
-        } else {
-            $results = array();
-        /// Iterate over columns searching for enums
-            foreach ($columns as $key => $column) {
-            /// Enum found, let's add it to the constraints list
-                if (!empty($column->enums)) {
-                    $result = new stdClass();
-                    $result->name = $key;
-                    $result->description = implode(', ', $column->enums);
-                    $results[$key] = $result;
-                }
-            }
-            return $results;
-        }
-    }
-
     /**
      * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
      * return if such name is currently in use (true) or no (false)
index 133b4ba..a2cf1ad 100644 (file)
@@ -55,8 +55,6 @@ class oracle_sql_generator extends sql_generator {
     public $sequence_name = ''; //Particular name for inline sequences in this generator
     public $sequence_cache_size = 20; //Size of the sequences values cache (20 = Oracle Default)
 
-    public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
-
     public $alter_column_sql = 'ALTER TABLE TABLENAME MODIFY (COLUMNSPECS)'; //The SQL template to alter columns
 
     /**
@@ -288,20 +286,6 @@ class oracle_sql_generator extends sql_generator {
         $newt = new xmldb_table($newname); /// Temp table for trigger code generation
         $results = array_merge($results, $this->getCreateTriggerSQL($newt, $xmldb_field, $newseqname));
 
-    /// Rename all the check constraints in the table
-        $oldtablename = $this->getTableName($xmldb_table);
-        $newtablename = $this->getTableName($newt);
-
-        $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
-        $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
-
-        if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
-            foreach ($constraints as $constraint) {
-            /// Drop the old constraint
-                $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
-            }
-        }
-
         return $results;
     }
 
@@ -484,25 +468,6 @@ class oracle_sql_generator extends sql_generator {
         return $results;
     }
 
-    /**
-     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its enum
-     * (usually invoked from getModifyEnumSQL()
-     *
-     * TODO: Moodle 2.1 - drop in Moodle 2.1
-     */
-    public function getDropEnumSQL($xmldb_table, $xmldb_field) {
-    /// Let's introspect to know the real name of the check constraint
-        if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
-            $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
-            $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
-        /// All we have to do is to drop the check constraint
-            return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
-                     ' DROP CONSTRAINT ' . $constraint_name);
-        } else { /// Constraint not found. Nothing to do
-            return array();
-        }
-    }
-
     /**
      * Given one xmldb_table and one xmldb_field, return the SQL statements needed to create its default
      * (usually invoked from getModifyDefaultSQL()
@@ -523,51 +488,6 @@ class oracle_sql_generator extends sql_generator {
         return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
     }
 
-    /**
-     * Given one xmldb_table returns one array with all the check constraints
-     * in the table (fetched from DB)
-     * Optionally the function allows one xmldb_field to be specified in
-     * order to return only the check constraints belonging to one field.
-     * Each element contains the name of the constraint and its description
-     * If no check constraints are found, returns an empty array
-     *
-     * TODO: Moodle 2.1 - drop in Moodle 2.1
-     */
-    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
-
-        $results = array();
-
-        $tablename = strtoupper($this->getTableName($xmldb_table));
-
-        if ($constraints = $this->mdb->get_records_sql("SELECT lower(c.constraint_name) AS name, c.search_condition AS description
-                                                          FROM user_constraints c
-                                                         WHERE c.table_name = ?
-                                                               AND c.constraint_type = 'C'
-                                                               AND c.constraint_name not like 'SYS%'",
-                                                        array($tablename))) {
-            foreach ($constraints as $constraint) {
-                $results[$constraint->name] = $constraint;
-            }
-        }
-
-    /// Filter by the required field if specified
-        if ($xmldb_field) {
-            $filtered_results = array();
-            $filter = $xmldb_field->getName();
-        /// Lets clean a bit each constraint description, looking for the filtered field
-            foreach ($results as $key => $result) {
-            /// description starts by "$filter IN" assume it's a constraint belonging to the field
-                if (preg_match("/^{$filter} IN/i", $result->description)) {
-                    $filtered_results[$key] = $result;
-                }
-            }
-        /// Assign filtered results to the final results array
-            $results =  $filtered_results;
-        }
-
-        return $results;
-    }
-
     /**
      * Given one xmldb_table returns one string with the sequence of the table
      * in the table (fetched from DB)
index 5dc170e..cf57825 100644 (file)
@@ -47,8 +47,6 @@ class postgres_sql_generator extends sql_generator {
     public $sequence_name_small = 'SERIAL'; //Particular name for inline sequences in this generator
     public $sequence_only = true; //To avoid to output the rest of the field specs, leaving only the name and the sequence_name variable
 
-    public $enum_inline_code = false; //Does the generator need to add inline code in the column definition
-
     public $rename_index_sql = 'ALTER TABLE OLDINDEXNAME RENAME TO NEWINDEXNAME'; //SQL sentence to rename one index
                                       //TABLENAME, OLDINDEXNAME, NEWINDEXNAME are dynamically replaced
 
@@ -181,20 +179,6 @@ class postgres_sql_generator extends sql_generator {
     /// Rename de sequence
         $results[] = 'ALTER TABLE ' . $oldseqname . ' RENAME TO ' . $newseqname;
 
-    /// Rename all the check constraints in the table
-        $oldtablename = $this->getTableName($xmldb_table);
-        $newtablename = $this->getTableName($newt);
-
-        $oldconstraintprefix = $this->getNameForObject($xmldb_table->getName(), '');
-        $newconstraintprefix = $this->getNameForObject($newt->getName(), '', '');
-
-        if ($constraints = $this->getCheckConstraintsFromDB($xmldb_table)) {
-            foreach ($constraints as $constraint) {
-            /// Drop the old constraint
-                $results[] = 'ALTER TABLE ' . $newtablename . ' DROP CONSTRAINT ' . $constraint->name;
-            }
-         }
-
         return $results;
     }
 
@@ -317,25 +301,6 @@ class postgres_sql_generator extends sql_generator {
         return $results;
     }
 
-    /**
-     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its enum
-     * (usually invoked from getModifyEnumSQL()
-     *
-     * TODO: Moodle 2.1 - drop in Moodle 2.1
-     */
-    public function getDropEnumSQL($xmldb_table, $xmldb_field) {
-    /// Let's introspect to know the real name of the check constraint
-        if ($check_constraints = $this->getCheckConstraintsFromDB($xmldb_table, $xmldb_field)) {
-            $check_constraint = array_shift($check_constraints); /// Get the 1st (should be only one)
-            $constraint_name = strtolower($check_constraint->name); /// Extract the REAL name
-        /// All we have to do is to drop the check constraint
-            return array('ALTER TABLE ' . $this->getTableName($xmldb_table) .
-                     ' DROP CONSTRAINT ' . $constraint_name);
-        } else { /// Constraint not found. Nothing to do
-            return array();
-        }
-    }
-
     /**
      * Given one xmldb_table and one xmldb_field, return the SQL statements needed to create its default
      * (usually invoked from getModifyDefaultSQL()
@@ -356,55 +321,6 @@ class postgres_sql_generator extends sql_generator {
         return $this->getAlterFieldSQL($xmldb_table, $xmldb_field);
     }
 
-    /**
-     * Given one xmldb_table returns one array with all the check constraints
-     * in the table (fetched from DB)
-     * Optionally the function allows one xmldb_field to be specified in
-     * order to return only the check constraints belonging to one field.
-     * Each element contains the name of the constraint and its description
-     * If no check constraints are found, returns an empty array
-     *
-     * TODO: Moodle 2.1 - drop in Moodle 2.1
-     */
-    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
-
-        $results = array();
-
-        $tablename = $this->getTableName($xmldb_table);
-
-        if ($constraints = $this->mdb->get_records_sql("SELECT co.conname AS name, co.consrc AS description
-                                                          FROM pg_constraint co, pg_class cl
-                                                         WHERE co.conrelid = cl.oid
-                                                               AND co.contype = 'c' AND cl.relname = ?",
-                                                       array($tablename))) {
-            foreach ($constraints as $constraint) {
-                $results[$constraint->name] = $constraint;
-            }
-        }
-
-    /// Filter by the required field if specified
-        if ($xmldb_field) {
-            $filtered_results = array();
-            $filter = $xmldb_field->getName();
-        /// Lets clean a bit each constraint description, looking for the filtered field
-            foreach ($results as $key => $result) {
-                $description = preg_replace('/\("(.*?)"\)/', '($1)', $result->description);// Double quotes out
-                $description = preg_replace('/[\(\)]/', '', $description);                 // Parenthesis out
-                $description = preg_replace('/::[a-z]+/i', '', $description);              // Casts out
-                $description = preg_replace("/({$filter})/i", '@$1@', $description);
-                $description = trim(preg_replace('/ or /i', ' OR ', $description));        // Uppercase or & trim
-            /// description starts by @$filter@ assume it's a constraint belonging to the field
-                if (preg_match("/^@{$filter}@/i", $description)) {
-                    $filtered_results[$key] = $result;
-                }
-            }
-        /// Assign filtered results to the final results array
-            $results =  $filtered_results;
-        }
-
-        return $results;
-    }
-
     public function addslashes($s) {
         // Postgres is gradually switching to ANSI quotes, we need to check what is expected
         if (!isset($this->std_strings)) {
index 7f95086..4a27f80 100644 (file)
@@ -544,14 +544,14 @@ class ddl_test extends UnitTestCase {
         $this->assertEqual($columns['onechar']->meta_type    ,'C');
         $this->assertEqual($DB->get_field('test_table1', 'onechar', array(), IGNORE_MULTIPLE), 'Nice dflt!'); //check default has been applied
 
-        /// add one text field and check it
+        /// add one big text field and check it
         $field = new xmldb_field('onetext');
-        $field->set_attributes(XMLDB_TYPE_TEXT);
+        $field->set_attributes(XMLDB_TYPE_TEXT, 'big');
         $dbman->add_field($table, $field);
         $this->assertTrue($dbman->field_exists($table, 'onetext'));
         $columns = $DB->get_columns('test_table1');
         $this->assertEqual($columns['onetext']->name         ,'onetext');
-        $this->assertEqual($columns['onetext']->max_length   , -1);
+        $this->assertEqual($columns['onetext']->max_length   , -1); // -1 means unknown or big
         $this->assertEqual($columns['onetext']->scale        , null);
         $this->assertEqual($columns['onetext']->not_null     , false);
         $this->assertEqual($columns['onetext']->primary_key  , false);
@@ -560,6 +560,20 @@ class ddl_test extends UnitTestCase {
         $this->assertEqual($columns['onetext']->default_value, null);
         $this->assertEqual($columns['onetext']->meta_type    ,'X');
 
+        /// add one medium text field and check it
+        $field = new xmldb_field('mediumtext');
+        $field->set_attributes(XMLDB_TYPE_TEXT, 'medium');
+        $dbman->add_field($table, $field);
+        $columns = $DB->get_columns('test_table1');
+        $this->assertTrue(($columns['mediumtext']->max_length == -1) or ($columns['mediumtext']->max_length >= 16777215)); // -1 means unknown or big
+
+        /// add one small text field and check it
+        $field = new xmldb_field('smalltext');
+        $field->set_attributes(XMLDB_TYPE_TEXT, 'small');
+        $dbman->add_field($table, $field);
+        $columns = $DB->get_columns('test_table1');
+        $this->assertTrue(($columns['smalltext']->max_length == -1) or ($columns['smalltext']->max_length >= 65535)); // -1 means unknown or big
+
         /// add one binary field and check it
         $field = new xmldb_field('onebinary');
         $field->set_attributes(XMLDB_TYPE_BINARY);
@@ -1132,73 +1146,6 @@ class ddl_test extends UnitTestCase {
         $dbman->drop_key($table, $key);
     }
 
-    /**
-     * Test behaviour of drop_enum_from_field() and related functions (find_check_constraint_name
-     * and check_constraint_exists). Needed to be able to drop existing "enum" fields in the upgrade
-     * from 1.9 to 2.0, will be completely deleted for Moodle 2.1
-     *
-     * Because we already have dropped support for creation of enum fields in 2.0, we are going to
-     * create them here "manually" (hardcoded DB-dependent SQL). Just to be able to test the
-     * find and drop functions properly.
-     *
-     * TODO: Drop this tests completely from Moodle 2.1
-     */
-    public function test_drop_enum_from_field() {
-        $DB = $this->tdb; // do not use global $DB!
-        $dbman = $this->tdb->get_manager();
-
-        // Create normal table, no enums.
-        $table = new xmldb_table('test_table_cust0');
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
-        $field = new xmldb_field('type');
-        $field->set_attributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, 'general');
-        $table->addField($field);
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-        $dbman->create_table($table);
-
-        $this->assertTrue($dbman->table_exists($table));
-        $this->assertTrue($dbman->field_exists($table, $field));
-
-        // Check table hasn't enums at all
-        $this->assertFalse($dbman->check_constraint_exists($table, $field));
-        $this->assertFalse($dbman->find_check_constraint_name($table, $field));
-        ob_start();
-        $this->assertFalse($dbman->drop_enum_from_field($table, $field)); // This just outputs debug warning if field hasn't enums
-        ob_end_clean();
-
-        // Insert some info
-        $record = new stdClass();
-        $record->course = 666;
-        $record->type = 'qanda';
-        $this->assertTrue($DB->insert_record('test_table_cust0', $record, false));
-
-        // Hackery starts here, depending of the db family we are testing... execute
-        // the needed SQL statements to get the "type" field defined as enum
-        $stmt = '';
-        switch ($DB->get_dbfamily()) {
-            case 'mysql': // It's ENUM field for mysql
-                $stmt = "ALTER TABLE {$DB->get_prefix()}test_table_cust0 MODIFY type ENUM ('general', 'qanda', 'moodle') NOT NULL DEFAULT 'general'";
-                break;
-            default: // It's check constraint for "normal" DBs
-                $stmt = "ALTER TABLE {$DB->get_prefix()}test_table_cust0 ADD CONSTRAINT ttcu0_ck CHECK (type IN ('general', 'qanda', 'moodle'))";
-        }
-        $DB->change_database_structure($stmt);
-
-        // Check table has enums now
-        $this->assertTrue($dbman->check_constraint_exists($table, $field));
-        $this->assertTrue($dbman->find_check_constraint_name($table, $field));
-
-        // Removing an enum value
-        $dbman->drop_enum_from_field($table, $field);
-
-        // Chech table hasn't enum anymore
-        $this->assertFalse($dbman->check_constraint_exists($table, $field));
-        $this->assertFalse($dbman->find_check_constraint_name($table, $field));
-
-        $dbman->drop_table($table);
-    }
-
     public function testRenameField() {
         $DB = $this->tdb; // do not use global $DB!
         $dbman = $this->tdb->get_manager();
index dfa8d1c..6103931 100644 (file)
@@ -1358,19 +1358,6 @@ abstract class sql_generator {
         return array();
     }
 
-    /**
-     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its enum
-     * (usually invoked from getModifyEnumSQL()
-     *
-     * Note that this method may be dropped in future.
-     *
-     * @param xmldb_table $xmldb_table The xmldb_table object instance.
-     * @param xmldb_field $xmldb_field The xmldb_field object instance.
-     *
-     * @todo MDL-31147 Moodle 2.1 - Drop getDropEnumSQL()
-     */
-    public abstract function getDropEnumSQL($xmldb_table, $xmldb_field);
-
     /**
      * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its default
      * (usually invoked from getModifyDefaultSQL()
@@ -1384,20 +1371,6 @@ abstract class sql_generator {
      */
     public abstract function getDropDefaultSQL($xmldb_table, $xmldb_field);
 
-    /**
-     * Given one xmldb_table and one optional xmldb_field, return one array with all the check
-     * constrainst found for that table (or field). Must exist for each DB supported.
-     * (usually invoked from find_check_constraint_name)
-     *
-     * Note that this method may be dropped in future.
-     *
-     * @param xmldb_table $xmldb_table The xmldb_table object instance.
-     * @param xmldb_field $xmldb_field The xmldb_field object instance.
-     *
-     * @todo MDL-31147 Moodle 2.1 - Drop getCheckConstraintsFromDB
-     */
-    public abstract function getCheckConstraintsFromDB($xmldb_table, $xmldb_field=null);
-
     /**
      * Given one xmldb_table and one xmldb_field, return the SQL statements needed to add its default
      * (usually invoked from getModifyDefaultSQL()
index 3977b95..e10b24a 100644 (file)
@@ -54,9 +54,6 @@ class sqlite_sql_generator extends sql_generator {
     public $sequence_extra_code = false; //Does the generator need to add extra code to generate the sequence fields
     public $sequence_name = 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL'; //Particular name for inline sequences in this generator
 
-    public $enum_inline_code = true; //Does the generator need to add inline code in the column definition
-    public $enum_extra_code = false; //Does the generator need to add extra code to generate code for the enums in the table
-
     public $drop_index_sql = 'ALTER TABLE TABLENAME DROP INDEX INDEXNAME'; //SQL sentence to drop one index
                                                                //TABLENAME, INDEXNAME are dynamically replaced
 
@@ -281,22 +278,6 @@ class sqlite_sql_generator extends sql_generator {
         return $this->getAlterTableSchema($xmldb_table);
     }
 
-    /**
-     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to create its enum
-     * (usually invoked from getModifyEnumSQL()
-     */
-    public function getCreateEnumSQL($xmldb_table, $xmldb_field) {
-        return $this->getAlterTableSchema($xmldb_table, $xmldb_field, $xmldb_field);
-    }
-
-    /**
-     * Given one xmldb_table and one xmldb_field, return the SQL statements needed to drop its enum
-     * (usually invoked from getModifyEnumSQL()
-     */
-    public function getDropEnumSQL($xmldb_table, $xmldb_field) {
-        return $this->getAlterTableSchema($xmldb_table, $xmldb_field, $xmldb_field);
-    }
-
     /**
      * Given one xmldb_table and one xmldb_field, return the SQL statements needed to create its default
      * (usually invoked from getModifyDefaultSQL()
@@ -377,37 +358,6 @@ class sqlite_sql_generator extends sql_generator {
         return array();
     }
 
-    /**
-     * Given one xmldb_table returns one array with all the check constraints
-     * in the table (fetched from DB)
-     * Optionally the function allows one xmldb_field to be specified in
-     * order to return only the check constraints belonging to one field.
-     * Each element contains the name of the constraint and its description
-     * If no check constraints are found, returns an empty array.
-     *
-     * TODO: Moodle 2.1 - drop in Moodle 2.1
-     */
-    public function getCheckConstraintsFromDB($xmldb_table, $xmldb_field = null) {
-        $tablename = $xmldb_table->getName($xmldb_table);
-        // Fetch all the columns in the table
-        if (!$columns = $this->mdb->get_columns($tablename, false)) {
-            return array();
-        }
-        $results = array();
-        $filter = $xmldb_field ? $xmldb_field->getName() : NULL;
-        // Iterate over columns searching for enums
-        foreach ($columns as $key => $column) {
-            // Enum found, let's add it to the constraints list
-            if (!empty($column->enums) && (!$filter || $column->name == $filter)) {
-                    $result = new stdClass();
-                    $result->name = $key;
-                    $result->description = implode(', ', $column->enums);
-                    $results[$key] = $result;
-            }
-        }
-        return $results;
-    }
-
     /**
      * Given one object name and it's type (pk, uk, fk, ck, ix, uix, seq, trg)
      * return if such name is currently in use (true) or no (false)
index 06448e1..eed77e9 100644 (file)
@@ -884,29 +884,6 @@ function index_exists($table, $index) {
     return $DB->get_manager()->index_exists($table, $index);
 }
 
-/**
- * @deprecated
- * @global object
- * @param string $table
- * @param string $field
- * @return bool
- */
-function find_check_constraint_name($table, $field) {
-    global $DB;
-    debugging('Deprecated ddllib function used!');
-    return $DB->get_manager()->find_check_constraint_name($table, $field);
-}
-
-/**
- * @deprecated
- * @global object
- */
-function check_constraint_exists($table, $field) {
-    global $DB;
-    debugging('Deprecated ddllib function used!');
-    return $DB->get_manager()->check_constraint_exists($table, $field);
-}
-
 /**
  * @deprecated
  * @global object
@@ -1070,20 +1047,6 @@ function change_field_notnull($table, $field) {
     return true;
 }
 
-/**
- * @deprecated
- * @global object
- * @param string $table
- * @param string $field
- * @return bool
- */
-function change_field_enum($table, $field) {
-    global $DB;
-    debugging('Deprecated ddllib function used! Only dropping of enums is allowed.');
-    $DB->get_manager()->drop_enum_from_field($table, $field);
-    return true;
-}
-
 /**
  * @deprecated
  * @global object
index 0e8a093..a31d362 100644 (file)
@@ -60,7 +60,6 @@ class database_column_info {
      *  integer - number of digits
      *  float - digits left from floating point
      *  boolean - 1
-     *  enums - null
      * @var int
      */
     public $max_length;
@@ -73,16 +72,6 @@ class database_column_info {
      */
     public $scale;
 
-    /**
-     * Enumerated field options,
-     * null if not enum type
-     *
-     * For performance reasons this field is optional!
-     * You can use DDL sql_generator::getCheckConstraintsFromDB() if needed.
-     * @var string
-     */
-    public $enums;
-
     /**
      * True if not null, false otherwise
      * @var bool
index f56c89c..242c5c4 100644 (file)
@@ -439,7 +439,12 @@ class mysqli_native_moodle_database extends moodle_database {
 
         $this->columns[$table] = array();
 
-        $sql = "SHOW COLUMNS FROM {$this->prefix}$table";
+        $sql = "SELECT column_name, data_type, character_maximum_length, numeric_precision,
+                       numeric_scale, is_nullable, column_type, column_default, column_key, extra
+                  FROM information_schema.columns
+                 WHERE table_name = '" . $this->prefix.$table . "'
+                       AND table_schema = '" . $this->dbname . "'
+              ORDER BY ordinal_position";
         $this->query_start($sql, null, SQL_QUERY_AUX);
         $result = $this->mysqli->query($sql);
         $this->query_end(true); // Don't want to throw anything here ever. MDL-30147
@@ -448,140 +453,194 @@ class mysqli_native_moodle_database extends moodle_database {
             return array();
         }
 
-        while ($rawcolumn = $result->fetch_assoc()) {
-            $rawcolumn = (object)array_change_key_case($rawcolumn, CASE_LOWER);
-
-            $info = new stdClass();
-            $info->name = $rawcolumn->field;
-            $matches = null;
-
-            if (preg_match('/varchar\((\d+)\)/i', $rawcolumn->type, $matches)) {
-                $info->type          = 'varchar';
-                $info->meta_type     = 'C';
-                $info->max_length    = $matches[1];
-                $info->scale         = null;
-                $info->not_null      = ($rawcolumn->null === 'NO');
-                $info->default_value = $rawcolumn->default;
-                $info->has_default   = is_null($info->default_value) ? false : true;
-                $info->primary_key   = ($rawcolumn->key === 'PRI');
-                $info->binary        = false;
-                $info->unsigned      = null;
-                $info->auto_increment= false;
-                $info->unique        = null;
-
-            } else if (preg_match('/([a-z]*int[a-z]*)\((\d+)\)/i', $rawcolumn->type, $matches)) {
-                $info->type = $matches[1];
-                $info->primary_key       = ($rawcolumn->key === 'PRI');
-                if ($info->primary_key) {
-                    $info->meta_type     = 'R';
-                    $info->max_length    = $matches[2];
-                    $info->scale         = null;
-                    $info->not_null      = ($rawcolumn->null === 'NO');
-                    $info->default_value = $rawcolumn->default;
-                    $info->has_default   = is_null($info->default_value) ? false : true;
-                    $info->binary        = false;
-                    $info->unsigned      = (stripos($rawcolumn->type, 'unsigned') !== false);
-                    $info->auto_increment= true;
-                    $info->unique        = true;
+        if ($result->num_rows > 0) {
+            // standard table exists
+            while ($rawcolumn = $result->fetch_assoc()) {
+                $info = (object)$this->get_column_info((object)$rawcolumn);
+                $this->columns[$table][$info->name] = new database_column_info($info);
+            }
+            $result->close();
+
+        } else {
+            // temporary tables are not in information schema, let's try it the old way
+            $result->close();
+            $sql = "SHOW COLUMNS FROM {$this->prefix}$table";
+            $this->query_start($sql, null, SQL_QUERY_AUX);
+            $result = $this->mysqli->query($sql);
+            $this->query_end(true);
+            if ($result === false) {
+                return array();
+            }
+            while ($rawcolumn = $result->fetch_assoc()) {
+                $rawcolumn = (object)array_change_key_case($rawcolumn, CASE_LOWER);
+                $rawcolumn->column_name              = $rawcolumn->field; unset($rawcolumn->field);
+                $rawcolumn->column_type              = $rawcolumn->type; unset($rawcolumn->type);
+                $rawcolumn->character_maximum_length = null;
+                $rawcolumn->numeric_precision        = null;
+                $rawcolumn->numeric_scale            = null;
+                $rawcolumn->is_nullable              = $rawcolumn->null; unset($rawcolumn->null);
+                $rawcolumn->column_default           = $rawcolumn->default; unset($rawcolumn->default);
+                $rawcolumn->column_key               = $rawcolumn->key; unset($rawcolumn->default);
+                $rawcolumn->extra                    = ($rawcolumn->column_name === 'id') ? 'auto_increment' : '';
+
+                if (preg_match('/(enum|varchar)\((\d+)\)/i', $rawcolumn->column_type, $matches)) {
+                    $rawcolumn->data_type = $matches[1];
+                    $rawcolumn->character_maximum_length = $matches[2];
+
+                } else if (preg_match('/([a-z]*int[a-z]*)\((\d+)\)/i', $rawcolumn->column_type, $matches)) {
+                    $rawcolumn->data_type = $matches[1];
+                    $rawcolumn->character_maximum_length = $matches[2];
+
+                } else if (preg_match('/(decimal)\((\d+),(\d+)\)/i', $rawcolumn->column_type, $matches)) {
+                    $rawcolumn->data_type = $matches[1];
+                    $rawcolumn->numeric_precision = $matches[2];
+                    $rawcolumn->numeric_scale = $matches[3];
+
+                } else if (preg_match('/(double|float)(\((\d+),(\d+)\))?/i', $rawcolumn->column_type, $matches)) {
+                    $rawcolumn->data_type = $matches[1];
+                    $rawcolumn->numeric_precision = isset($matches[3]) ? $matches[3] : null;
+                    $rawcolumn->numeric_scale = isset($matches[4]) ? $matches[4] : null;
+
+                } else if (preg_match('/([a-z]*text)/i', $rawcolumn->column_type, $matches)) {
+                    $rawcolumn->data_type = $matches[1];
+                    $rawcolumn->character_maximum_length = -1; // unknown
+
+                } else if (preg_match('/([a-z]*blob)/i', $rawcolumn->column_type, $matches)) {
+                    $rawcolumn->data_type = $matches[1];
+
                 } else {
-                    $info->meta_type     = 'I';
-                    $info->max_length    = $matches[2];
-                    $info->scale         = null;
-                    $info->not_null      = ($rawcolumn->null === 'NO');
-                    $info->default_value = $rawcolumn->default;
-                    $info->has_default   = is_null($info->default_value) ? false : true;
-                    $info->binary        = false;
-                    $info->unsigned      = (stripos($rawcolumn->type, 'unsigned') !== false);
-                    $info->auto_increment= false;
-                    $info->unique        = null;
+                    $rawcolumn->data_type = $rawcolumn->column_type;
                 }
 
-            } else if (preg_match('/(decimal)\((\d+),(\d+)\)/i', $rawcolumn->type, $matches)) {
-                $info->type          = $matches[1];
-                $info->meta_type     = 'N';
-                $info->max_length    = $matches[2];
-                $info->scale         = $matches[3];
-                $info->not_null      = ($rawcolumn->null === 'NO');
-                $info->default_value = $rawcolumn->default;
-                $info->has_default   = is_null($info->default_value) ? false : true;
-                $info->primary_key   = ($rawcolumn->key === 'PRI');
-                $info->binary        = false;
-                $info->unsigned      = (stripos($rawcolumn->type, 'unsigned') !== false);
-                $info->auto_increment= false;
-                $info->unique        = null;
-
-            } else if (preg_match('/(double|float)(\((\d+),(\d+)\))?/i', $rawcolumn->type, $matches)) {
-                $info->type          = $matches[1];
-                $info->meta_type     = 'N';
-                $info->max_length    = isset($matches[3]) ? $matches[3] : null;
-                $info->scale         = isset($matches[4]) ? $matches[4] : null;
-                $info->not_null      = ($rawcolumn->null === 'NO');
-                $info->default_value = $rawcolumn->default;
-                $info->has_default   = is_null($info->default_value) ? false : true;
-                $info->primary_key   = ($rawcolumn->key === 'PRI');
-                $info->binary        = false;
-                $info->unsigned      = (stripos($rawcolumn->type, 'unsigned') !== false);
-                $info->auto_increment= false;
-                $info->unique        = null;
-
-            } else if (preg_match('/([a-z]*text)/i', $rawcolumn->type, $matches)) {
-                $info->type          = $matches[1];
-                $info->meta_type     = 'X';
-                $info->max_length    = -1;
-                $info->scale         = null;
-                $info->not_null      = ($rawcolumn->null === 'NO');
-                $info->default_value = $rawcolumn->default;
-                $info->has_default   = is_null($info->default_value) ? false : true;
-                $info->primary_key   = ($rawcolumn->key === 'PRI');
-                $info->binary        = false;
-                $info->unsigned      = null;
-                $info->auto_increment= false;
-                $info->unique        = null;
-
-            } else if (preg_match('/([a-z]*blob)/i', $rawcolumn->type, $matches)) {
-                $info->type          = $matches[1];
-                $info->meta_type     = 'B';
-                $info->max_length    = -1;
-                $info->scale         = null;
-                $info->not_null      = ($rawcolumn->null === 'NO');
-                $info->default_value = $rawcolumn->default;
-                $info->has_default   = is_null($info->default_value) ? false : true;
-                $info->primary_key   = false;
-                $info->binary        = true;
-                $info->unsigned      = null;
-                $info->auto_increment= false;
-                $info->unique        = null;
-
-            } else if (preg_match('/enum\((.*)\)/i', $rawcolumn->type, $matches)) {
-                $info->type          = 'enum';
-                $info->meta_type     = 'C';
-                $info->enums         = array();
-                $info->max_length    = 0;
-                $values = $matches[1];
-                $values = explode(',', $values);
-                foreach ($values as $val) {
-                    $val = trim($val, "'");
-                    $length = textlib::strlen($val);
-                    $info->enums[] = $val;
-                    $info->max_length = ($info->max_length < $length) ? $length : $info->max_length;
-                }
-                $info->scale         = null;
-                $info->not_null      = ($rawcolumn->null === 'NO');
-                $info->default_value = $rawcolumn->default;
-                $info->has_default   = is_null($info->default_value) ? false : true;
-                $info->primary_key   = ($rawcolumn->key === 'PRI');
-                $info->binary        = false;
-                $info->unsigned      = null;
-                $info->auto_increment= false;
-                $info->unique        = null;
+                $info = $this->get_column_info($rawcolumn);
+                $this->columns[$table][$info->name] = new database_column_info($info);
+            }
+            $result->close();
+        }
+
+        return $this->columns[$table];
+    }
+
+    /**
+     * Returns moodle column info for raw column from information schema.
+     * @param stdClass $rawcolumn
+     * @return stdClass standardised colum info
+     */
+    private function get_column_info(stdClass $rawcolumn) {
+        $rawcolumn = (object)$rawcolumn;
+        $info = new stdClass();
+        $info->name           = $rawcolumn->column_name;
+        $info->type           = $rawcolumn->data_type;
+        $info->meta_type      = $this->mysqltype2moodletype($rawcolumn->data_type);
+        $info->default_value  = $rawcolumn->column_default;
+        $info->has_default    = !is_null($rawcolumn->column_default);
+        $info->not_null       = ($rawcolumn->is_nullable === 'NO');
+        $info->primary_key    = ($rawcolumn->column_key === 'PRI');
+        $info->binary         = false;
+        $info->unsigned       = null;
+        $info->auto_increment = false;
+        $info->unique         = null;
+        $info->scale          = null;
+
+        if ($info->meta_type === 'C') {
+            $info->max_length = $rawcolumn->character_maximum_length;
+
+        } else if ($info->meta_type === 'I') {
+            if ($info->primary_key) {
+                $info->meta_type = 'R';
+                $info->unique    = true;
+            }
+            $info->max_length    = $rawcolumn->numeric_precision;
+            $info->unsigned      = (stripos($rawcolumn->column_type, 'unsigned') !== false);
+            $info->auto_increment= (strpos($rawcolumn->extra, 'auto_increment') !== false);
+
+        } else if ($info->meta_type === 'N') {
+            $info->max_length    = $rawcolumn->numeric_precision;
+            $info->scale         = $rawcolumn->numeric_scale;
+            $info->unsigned      = (stripos($rawcolumn->column_type, 'unsigned') !== false);
+
+        } else if ($info->meta_type === 'X') {
+            if ("$rawcolumn->character_maximum_length" === '4294967295') { // watch out for PHP max int limits!
+                // means maximum moodle size for text column, in other drivers it may also mean unknown size
+                $info->max_length = -1;
+            } else {
+                $info->max_length = $rawcolumn->character_maximum_length;
             }
+            $info->primary_key   = false;
 
-            $this->columns[$table][$info->name] = new database_column_info($info);
+        } else if ($info->meta_type === 'B') {
+            $info->max_length    = -1;
+            $info->primary_key   = false;
+            $info->binary        = true;
         }
 
-        $result->close();
+        return $info;
+    }
 
-        return $this->columns[$table];
+    /**
+     * Normalise column type.
+     * @param string $mysql_type
+     * @return string one character
+     * @throws dml_exception
+     */
+    private function mysqltype2moodletype($mysql_type) {
+        $type = null;
+
+        switch(strtoupper($mysql_type)) {
+            case 'BIT':
+                $type = 'L';
+                break;
+
+            case 'TINYINT':
+            case 'SMALLINT':
+            case 'MEDIUMINT':
+            case 'INT':
+            case 'BIGINT':
+                $type = 'I';
+                break;
+
+            case 'FLOAT':
+            case 'DOUBLE':
+            case 'DECIMAL':
+                $type = 'N';
+                break;
+
+            case 'CHAR':
+            case 'ENUM':
+            case 'SET':
+            case 'VARCHAR':
+                $type = 'C';
+                break;
+
+            case 'TINYTEXT':
+            case 'TEXT':
+            case 'MEDIUMTEXT':
+            case 'LONGTEXT':
+                $type = 'X';
+                break;
+
+            case 'BINARY':
+            case 'VARBINARY':
+            case 'BLOB':
+            case 'TINYBLOB':
+            case 'MEDIUMBLOB':
+            case 'LONGBLOB':
+                $type = 'B';
+                break;
+
+            case 'DATE':
+            case 'TIME':
+            case 'DATETIME':
+            case 'TIMESTAMP':
+            case 'YEAR':
+                $type = 'D';
+                break;
+        }
+
+        if (!$type) {
+            throw new dml_exception('invalidmysqlnativetype', $mysql_type);
+        }
+        return $type;
     }
 
     /**
@@ -604,16 +663,6 @@ class mysqli_native_moodle_database extends moodle_database {
         } else if (is_float($value) and ($column->meta_type == 'C' or $column->meta_type == 'X')) {
             $value = "$value";
         }
-        // workaround for problem with wrong enums in mysql - TODO: Out in Moodle 2.1
-        if (!empty($column->enums)) {
-            if (is_null($value) and !$column->not_null) {
-                // ok - nulls allowed
-            } else {
-                if (!in_array((string)$value, $column->enums)) {
-                    throw new dml_write_exception('Enum value '.s($value).' not allowed in field '.$field.' table '.$table.'.');
-                }
-            }
-        }
         return $value;
     }
 
index 3983dd1..b780bd4 100644 (file)
@@ -523,7 +523,6 @@ class oci_native_moodle_database extends moodle_database {
              or $rawcolumn->COLTYPE === 'NVARCHAR'
              or $rawcolumn->COLTYPE === 'CHAR'
              or $rawcolumn->COLTYPE === 'NCHAR') {
-                //TODO add some basic enum support here
                 $info->type          = $rawcolumn->COLTYPE;
                 $info->meta_type     = 'C';
                 $info->max_length    = $rawcolumn->WIDTH;
index eced736..8b090a4 100644 (file)
@@ -411,17 +411,6 @@ abstract class pdo_moodle_database extends moodle_database {
             if (is_bool($value)) {
                 $value = (int)$value; // prevent "false" problems
             }
-            if (!empty($column->enums)) {
-                // workaround for problem with wrong enums
-                if (is_null($value) and !$column->not_null) {
-                    // ok - nulls allowed
-                } else {
-                    if (!in_array((string)$value, $column->enums)) {
-                        debugging('Enum value '.s($value).' not allowed in field '.$field.' table '.$table.'.');
-                        return false;
-                    }
-                }
-            }
             $cleaned[$field] = $value;
         }
 
index b28334c..01731fc 100644 (file)
@@ -260,13 +260,6 @@ class sqlite3_pdo_moodle_database extends pdo_moodle_database {
                     $columninfo['meta_type'] = 'C';
                     break;
                 case 'enu': // enums
-                    if (preg_match('|'.$columninfo['name'].'\W+in\W+\(/\*liststart\*/(.*?)/\*listend\*/\)|im', $createsql, $tmp)) {
-                        $tmp = explode(',', $tmp[1]);
-                        foreach($tmp as $value) {
-                            $columninfo['enums'][] = trim($value, '\'"');
-                        }
-                        unset($tmp);
-                    }
                     $columninfo['meta_type'] = 'C';
                     break;
                 case 'tex': // text
index 62e791a..7fd29e6 100644 (file)
@@ -476,8 +476,10 @@ function enrol_add_course_navigation(navigation_node $coursenode, $course) {
     $usersnode->trim_if_empty();
 
     if ($course->id != SITEID) {
-        // Unenrol link
-        if (is_enrolled($coursecontext)) {
+        if (isguestuser() or !isloggedin()) {
+            // guest account can not be enrolled - no links for them
+        } else if (is_enrolled($coursecontext)) {
+            // unenrol link if possible
             foreach ($instances as $instance) {
                 if (!isset($plugins[$instance->enrol])) {
                     continue;
@@ -491,6 +493,7 @@ function enrol_add_course_navigation(navigation_node $coursenode, $course) {
                 }
             }
         } else {
+            // enrol link if possible
             if (is_viewing($coursecontext)) {
                 // better not show any enrol link, this is intended for managers and inspectors
             } else {
index 6c20f56..ba9fd82 100644 (file)
@@ -112,11 +112,6 @@ define('GRADE_UPDATE_FAILED', 1);
  */
 define('GRADE_UPDATE_MULTIPLE', 2);
 
-/**
- * GRADE_UPDATE_DELETED - Grade item deleted (MDL-31362)
- */
-define('GRADE_UPDATE_ITEM_DELETED', 3);
-
 /**
  * GRADE_UPDATE_DELETED - Grade item cannot be updated as it is locked
  */
index b63464f..8de67cf 100644 (file)
@@ -56,7 +56,7 @@ require_once($CFG->libdir . '/grade/grade_outcome.php');
  * @param int    $itemnumber Most probably 0. Modules can use other numbers when having more than one grade for each user
  * @param mixed  $grades Grade (object, array) or several grades (arrays of arrays or objects), NULL if updating grade_item definition only
  * @param mixed  $itemdetails Object or array describing the grading item, NULL if no change
- * @return int Returns GRADE_UPDATE_OK, GRADE_UPDATE_FAILED, GRADE_UPDATE_MULTIPLE, GRADE_UPDATE_ITEM_DELETED (MDL-31362) or GRADE_UPDATE_ITEM_LOCKED
+ * @return int Returns GRADE_UPDATE_OK, GRADE_UPDATE_FAILED, GRADE_UPDATE_MULTIPLE or GRADE_UPDATE_ITEM_LOCKED
  */
 function grade_update($source, $courseid, $itemtype, $itemmodule, $iteminstance, $itemnumber, $grades=NULL, $itemdetails=NULL) {
     global $USER, $CFG, $DB;
index 8337f98..afedac5 100644 (file)
@@ -1,22 +1,38 @@
 <?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/>.
-//
-// Author(s): Jon Abernathy <jon@chuggnutt.com>
-// Copyright (c) 2005-2007 Jon Abernathy <jon@chuggnutt.com>
+/*************************************************************************
+ *                                                                       *
+ * class.html2text.inc                                                   *
+ *                                                                       *
+ *************************************************************************
+ *                                                                       *
+ * Converts HTML to formatted plain text                                 *
+ *                                                                       *
+ * Copyright (c) 2005-2007 Jon Abernathy <jon@chuggnutt.com>             *
+ * All rights reserved.                                                  *
+ *                                                                       *
+ * This script 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 2 of the License, or     *
+ * (at your option) any later version.                                   *
+ *                                                                       *
+ * The GNU General Public License can be found at                        *
+ * http://www.gnu.org/copyleft/gpl.html.                                 *
+ *                                                                       *
+ * This script 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.                          *
+ *                                                                       *
+ * Author(s): Jon Abernathy <jon@chuggnutt.com>                          *
+ *                                                                       *
+ * Last modified: 08/08/07                                               *
+ *                                                                       *
+ *************************************************************************/
+
+if (!defined('RCMAIL_CHARSET')) {
+    define('RCMAIL_CHARSET', 'UTF-8');
+}
 
 /**
  *  Takes HTML and converts it to formatted, plain text.
  *
  *  *** End of the housecleaning updates. Updated 08/08/07.
  *
- * @package   moodlecore
- * @copyright Jon Abernathy <jon@chuggnutt.com>
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-/**
- * @package   moodlecore
- * @copyright Jon Abernathy <jon@chuggnutt.com>
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ *  @author Jon Abernathy <jon@chuggnutt.com>
+ *  @version 1.0.0
+ *  @since PHP 4.0.2
  */
 class html2text
 {
@@ -138,10 +148,8 @@ class html2text
     var $search = array(
         "/\r/",                                  // Non-legal carriage return
         "/[\n\t]+/",                             // Newlines and tabs
-        '/[ ]{2,}/',                             // Runs of spaces, pre-handling
         '/<script[^>]*>.*?<\/script>/i',         // <script>s -- which strip_tags supposedly has problems with
         '/<style[^>]*>.*?<\/style>/i',           // <style>s -- which strip_tags supposedly has problems with
-        //'/<!-- .* -->/',                         // Comments -- which strip_tags might have problem a with
         '/<p[^>]*>/i',                           // <P>
         '/<br[^>]*>/i',                          // <br>
         '/<i[^>]*>(.*?)<\/i>/i',                 // <i>
@@ -151,26 +159,10 @@ class html2text
         '/<li[^>]*>(.*?)<\/li>/i',               // <li> and </li>
         '/<li[^>]*>/i',                          // <li>
         '/<hr[^>]*>/i',                          // <hr>
+        '/<div[^>]*>/i',                         // <div>
         '/(<table[^>]*>|<\/table>)/i',           // <table> and </table>
         '/(<tr[^>]*>|<\/tr>)/i',                 // <tr> and </tr>
         '/<td[^>]*>(.*?)<\/td>/i',               // <td> and </td>
-        '/&(nbsp|#160);/i',                      // Non-breaking space
-        '/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i',
-                                                        // Double quotes
-        '/&(apos|rsquo|lsquo|#8216|#8217);/i',   // Single quotes
-        '/&gt;/i',                               // Greater-than
-        '/&lt;/i',                               // Less-than
-        '/&(amp|#38);/i',                        // Ampersand
-        '/&(copy|#169);/i',                      // Copyright
-        '/&(trade|#8482|#153);/i',               // Trademark
-        '/&(reg|#174);/i',                       // Registered
-        '/&(mdash|#151|#8212);/i',               // mdash
-        '/&(ndash|minus|#8211|#8722);/i',        // ndash
-        '/&(bull|#149|#8226);/i',                // Bullet
-        '/&(pound|#163);/i',                     // Pound sign
-        '/&(euro|#8364);/i',                     // Euro sign
-        '/[ ]+([\n\t])/',                        // Trailing spaces before newline or tab
-        '/[ ]{2,}/'                              // Runs of spaces, post-handling
     );
 
     /**
@@ -183,11 +175,9 @@ class html2text
     var $replace = array(
         '',                                     // Non-legal carriage return
         ' ',                                    // Newlines and tabs
-        ' ',                                    // Runs of spaces, pre-handling
         '',                                     // <script>s -- which strip_tags supposedly has problems with
         '',                                     // <style>s -- which strip_tags supposedly has problems with
-        //'',                                     // Comments -- which strip_tags might have problem a with
-        "\n\n",                               // <P>
+        "\n\n",                                 // <P>
         "\n",                                   // <br>
         '_\\1_',                                // <i>
         '_\\1_',                                // <em>
@@ -196,15 +186,52 @@ class html2text
         "\t* \\1\n",                            // <li> and </li>
         "\n\t* ",                               // <li>
         "\n-------------------------\n",        // <hr>
+        "<div>\n",                              // <div>
         "\n\n",                                 // <table> and </table>
         "\n",                                   // <tr> and </tr>
         "\t\t\\1\n",                            // <td> and </td>
+    );
+
+    /**
+     *  List of preg* regular expression patterns to search for,
+     *  used in conjunction with $ent_replace.
+     *
+     *  @var array $ent_search
+     *  @access public
+     *  @see $ent_replace
+     */
+    var $ent_search = array(
+        '/&(nbsp|#160);/i',                      // Non-breaking space
+        '/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i',
+        // Double quotes
+        '/&(apos|rsquo|lsquo|#8216|#8217);/i',   // Single quotes
+        '/&gt;/i',                               // Greater-than
+        '/&lt;/i',                               // Less-than
+        '/&(copy|#169);/i',                      // Copyright
+        '/&(trade|#8482|#153);/i',               // Trademark
+        '/&(reg|#174);/i',                       // Registered
+        '/&(mdash|#151|#8212);/i',               // mdash
+        '/&(ndash|minus|#8211|#8722);/i',        // ndash
+        '/&(bull|#149|#8226);/i',                // Bullet
+        '/&(pound|#163);/i',                     // Pound sign
+        '/&(euro|#8364);/i',                     // Euro sign
+        '/&(amp|#38);/i',                        // Ampersand: see _converter()
+        '/[ ]{2,}/',                             // Runs of spaces, post-handling
+    );
+
+    /**
+     *  List of pattern replacements corresponding to patterns searched.
+     *
+     *  @var array $ent_replace
+     *  @access public
+     *  @see $ent_search
+     */
+    var $ent_replace = array(
         ' ',                                    // Non-breaking space
         '"',                                    // Double quotes
         "'",                                    // Single quotes
         '>',
         '<',
-        '&',
         '(c)',
         '(tm)',
         '(R)',
@@ -213,8 +240,8 @@ class html2text
         '*',
         '£',
         'EUR',                                  // Euro sign. € ?
-        '\\1',                                  // Trailing spaces before newline or tab
-        ' '                                     // Runs of spaces, post-handling
+        '|+|amp|+|',                            // Ampersand: see _converter()
+        ' ',                                    // Runs of spaces, post-handling
     );
 
     /**
@@ -225,23 +252,23 @@ class html2text
      *  @access public
      */
     var $callback_search = array(
+        '/<(a) [^>]*href=("|\')([^"\']+)\2[^>]*>(.*?)<\/a>/i',
+        // <a href="">
         '/<(h)[123456][^>]*>(.*?)<\/h[123456]>/i', // H1 - H3
         '/<(b)[^>]*>(.*?)<\/b>/i',                 // <b>
         '/<(strong)[^>]*>(.*?)<\/strong>/i',       // <strong>
-        '/<(a) [^>]*href=("|\')([^"\']+)\2[^>]*>(.*?)<\/a>/i',
-                                                   // <a href="">
         '/<(th)[^>]*>(.*?)<\/th>/i',               // <th> and </th>
         '/<(img)[^>]*alt=\"([^>"]+)\"[^>]*>/i',    // <img> with alt
     );
 
-   /**
-    *  List of preg* regular expression patterns to search for in PRE body,
-    *  used in conjunction with $pre_replace.
-    *
-    *  @var array $pre_search
-    *  @access public
-    *  @see $pre_replace
-    */
+    /**
+     *  List of preg* regular expression patterns to search for in PRE body,
+     *  used in conjunction with $pre_replace.
+     *
+     *  @var array $pre_search
+     *  @access public
+     *  @see $pre_replace
+     */
     var $pre_search = array(
         "/\n/",
         "/\t/",
@@ -294,21 +321,11 @@ class html2text
     /**
      *  Contains URL addresses from links to be rendered in plain text.
      *
-     *  @var string $_link_list
+     *  @var array $_link_list
      *  @access private
      *  @see _build_link_list()
      */
-    var $_link_list = '';
-
-    /**
-     *  Number of valid links detected in the text, used for plain text
-     *  display (rendered similar to footnotes).
-     *
-     *  @var integer $_link_count
-     *  @access private
-     *  @see _build_link_list()
-     */
-    var $_link_count = 0;
+    var $_link_list = array();
 
     /**
      * Boolean flag, true if a table of link URLs should be listed after the text.
@@ -335,7 +352,7 @@ class html2text
      */
     function html2text( $source = '', $from_file = false, $do_links = true, $width = 75 )
     {
-        if ($source !== '') {
+        if ( $source !== '' ) {
             $this->set_html($source, $from_file);
         }
 
@@ -425,11 +442,11 @@ class html2text
     function set_base_url( $url = '' )
     {
         if ( empty($url) ) {
-               if ( !empty($_SERVER['HTTP_HOST']) ) {
-                   $this->url = 'http://' . $_SERVER['HTTP_HOST'];
-               } else {
-                   $this->url = '';
-               }
+            if ( !empty($_SERVER['HTTP_HOST']) ) {
+                $this->url = 'http://' . $_SERVER['HTTP_HOST'];
+            } else {
+                $this->url = '';
+            }
         } else {
             // Strip any trailing slashes for consistency (relative
             // URLs may already start with a slash like "/file.html")
@@ -440,6 +457,35 @@ class html2text
         }
     }
 
+    /**
+     *  Workhorse function that does actual conversion (calls _converter() method).
+     *
+     *  @access private
+     *  @return void
+     */
+    function _convert()
+    {
+        // Variables used for building the link list
+        $this->_link_list = array();
+
+        $text = trim($this->html);
+
+        // Convert HTML to TXT
+        $this->_converter($text);
+
+        // Add link list
+        if (!empty($this->_link_list)) {
+            $text .= "\n\nLinks:\n------\n";
+            foreach ($this->_link_list as $idx => $url) {
+                $text .= '[' . ($idx+1) . '] ' . $url . "\n";
+            }
+        }
+
+        $this->text = $text;
+
+        $this->_converted = true;
+    }
+
     /**
      *  Workhorse function that does actual conversion.
      *
@@ -448,52 +494,54 @@ class html2text
      *  and newlines to a readable format, and word wraps the text to
      *  $width characters.
      *
+     *  @param string Reference to HTML content string
+     *
      *  @access private
      *  @return void
      */
-    function _convert()
+    function _converter(&$text)
     {
-        // Variables used for building the link list
-        $this->_link_count = 0;
-        $this->_link_list = '';
-
-        $text = trim($this->html);
+        // Convert <BLOCKQUOTE> (before PRE!)
+        $this->_convert_blockquotes($text);
 
         // Convert <PRE>
         $this->_convert_pre($text);
 
-        // Run our defined search-and-replace
+        // Run our defined tags search-and-replace
         $text = preg_replace($this->search, $this->replace, $text);
+
+        // Run our defined tags search-and-replace with callback
         $text = preg_replace_callback($this->callback_search, array('html2text', '_preg_callback'), $text);
 
+        // Strip any other HTML tags
+        $text = strip_tags($text, $this->allowed_tags);
+
+        // Run our defined entities/characters search-and-replace
+        $text = preg_replace($this->ent_search, $this->ent_replace, $text);
+
         // Replace known html entities
         $text = html_entity_decode($text, ENT_COMPAT, 'UTF-8');
 
         // Remove unknown/unhandled entities (this cannot be done in search-and-replace block)
         $text = preg_replace('/&([a-zA-Z0-9]{2,6}|#[0-9]{2,4});/', '', $text);
 
-        // Strip any other HTML tags
-        $text = strip_tags($text, $this->allowed_tags);
+        // Convert "|+|amp|+|" into "&", need to be done after handling of unknown entities
+        // This properly handles situation of "&amp;quot;" in input string
+        $text = str_replace('|+|amp|+|', '&', $text);
 
         // Bring down number of empty lines to 2 max
         $text = preg_replace("/\n\s+\n/", "\n\n", $text);
         $text = preg_replace("/[\n]{3,}/", "\n\n", $text);
 
-        // Add link list
-        if ( !empty($this->_link_list) ) {
-            $text .= "\n\nLinks:\n------\n" . $this->_link_list;
-        }
+        // remove leading empty lines (can be produced by eg. P tag on the beginning)
+        $text = ltrim($text, "\n");
 
         // Wrap the text to a readable format
         // for PHP versions >= 4.0.2. Default width is 75
         // If width is 0 or less, don't wrap the text.
         if ( $this->width > 0 ) {
-               $text = wordwrap($text, $this->width);
+            $text = wordwrap($text, $this->width);
         }
-
-        $this->text = $text;
-
-        $this->_converted = true;
     }
 
     /**
@@ -511,39 +559,44 @@ class html2text
      */
     function _build_link_list( $link, $display )
     {
-       if ( !$this->_do_links ) return $display;
-
-       if ( substr($link, 0, 7) == 'http://' || substr($link, 0, 8) == 'https://' ||
-             substr($link, 0, 7) == 'mailto:' ) {
-            $this->_link_count++;
-            $this->_link_list .= "[" . $this->_link_count . "] $link\n";
-            $additional = ' [' . $this->_link_count . ']';
-       } elseif ( substr($link, 0, 11) == 'javascript:' ) {
-               // Don't count the link; ignore it
-               $additional = '';
-               // what about href="#anchor" ?
-        } else {
-            $this->_link_count++;
-            $this->_link_list .= "[" . $this->_link_count . "] " . $this->url;
-            if ( substr($link, 0, 1) != '/' ) {
-                $this->_link_list .= '/';
+        if (!$this->_do_links || empty($link)) {
+            return $display;
+        }
+
+        // Ignored link types
+        if (preg_match('!^(javascript|mailto|#):!i', $link)) {
+            return $display;
+        }
+
+        if (preg_match('!^(https?://)!i', $link)) {
+            $url = $link;
+        }
+        else {
+            $url = $this->url;
+            if (substr($link, 0, 1) != '/') {
+                $url .= '/';
             }
-            $this->_link_list .= "$link\n";
-            $additional = ' [' . $this->_link_count . ']';
+            $url .= "$link";
+        }
+
+        if (($index = array_search($url, $this->_link_list)) === false) {
+            $this->_link_list[] = $url;
+            $index = count($this->_link_list);
         }
 
-        return $display . $additional;
+        return $display . ' [' . ($index+1) . ']';
     }
 
     /**
      *  Helper function for PRE body conversion.
      *
-     *  @param string $text HTML content
+     *  @param string HTML content
      *  @access private
      */
     function _convert_pre(&$text)
     {
-         while (preg_match('/<pre[^>]*>(.*)<\/pre>/ismU', $text, $matches)) {
+        // get the content of PRE element
+        while (preg_match('/<pre[^>]*>(.*)<\/pre>/ismU', $text, $matches)) {
             // convert the content
             $this->pre_content = sprintf('<div><br>%s<br></div>',
                 preg_replace($this->pre_search, $this->pre_replace, $matches[1]));
@@ -555,27 +608,84 @@ class html2text
         }
     }
 
+    /**
+     *  Helper function for BLOCKQUOTE body conversion.
+     *
+     *  @param string HTML content
+     *  @access private
+     */
+    function _convert_blockquotes(&$text)
+    {
+        if (preg_match_all('/<\/*blockquote[^>]*>/i', $text, $matches, PREG_OFFSET_CAPTURE)) {
+            $level = 0;
+            $diff = 0;
+            foreach ($matches[0] as $m) {
+                if ($m[0][0] == '<' && $m[0][1] == '/') {
+                    $level--;
+                    if ($level < 0) {
+                        $level = 0; // malformed HTML: go to next blockquote
+                    }
+                    else if ($level > 0) {
+                        // skip inner blockquote
+                    }
+                    else {
+                        $end  = $m[1];
+                        $len  = $end - $taglen - $start;
+                        // Get blockquote content
+                        $body = substr($text, $start + $taglen - $diff, $len);
+
+                        // Set text width
+                        $p_width = $this->width;
+                        if ($this->width > 0) $this->width -= 2;
+                        // Convert blockquote content
+                        $body = trim($body);
+                        $this->_converter($body);
+                        // Add citation markers and create PRE block
+                        $body = preg_replace('/((^|\n)>*)/', '\\1> ', trim($body));
+                        $body = '<pre>' . htmlspecialchars($body) . '</pre>';
+                        // Re-set text width
+                        $this->width = $p_width;
+                        // Replace content
+                        $text = substr($text, 0, $start - $diff)
+                            . $body . substr($text, $end + strlen($m[0]) - $diff);
+
+                        $diff = $len + $taglen + strlen($m[0]) - strlen($body);
+                        unset($body);
+                    }
+                }
+                else {
+                    if ($level == 0) {
+                        $start = $m[1];
+                        $taglen = strlen($m[0]);
+                    }
+                    $level ++;
+                }
+            }
+        }
+    }
+
     /**
      *  Callback function for preg_replace_callback use.
      *
-     *  @param  array $matches PREG matches
+     *  @param  array PREG matches
      *  @return string
-     *  @access private
      */
-    function _preg_callback($matches)
+    private function _preg_callback($matches)
     {
         switch($matches[1]) {
-        case 'b':
-        case 'strong':
-            return $this->_strtoupper($matches[2]);
-        case 'hr':
-            return $this->_strtoupper("\t\t". $matches[2] ."\n");
-        case 'h':
-            return $this->_strtoupper("\n\n". $matches[2] ."\n\n");
-        case 'a':
-            return $this->_build_link_list($matches[3], $matches[4]);
-        case 'img':
-            return '[' . $matches[2] . ']';
+            case 'b':
+            case 'strong':
+                return $this->_toupper($matches[2]);
+            case 'th':
+                return $this->_toupper("\t\t". $matches[2] ."\n");
+            case 'h':
+                return $this->_toupper("\n\n". $matches[2] ."\n\n");
+            case 'a':
+                // Remove spaces in URL (#1487805)
+                $url = str_replace(' ', '', $matches[3]);
+                return $this->_build_link_list($url, $matches[4]);
+            case 'img':
+                return '[' . $matches[2] . ']';
         }
     }
 
@@ -591,14 +701,45 @@ class html2text
     }
 
     /**
-     *  Strtoupper multibyte wrapper function
+     * Strtoupper function with HTML tags and entities handling.
      *
-     *  @param  string $str
-     *  @return string
-     *  @access private
+     * @param string $str Text to convert
+     * @return string Converted text
+     */
+    private function _toupper($str)
+    {
+        // string can containg HTML tags
+        $chunks = preg_split('/(<[^>]*>)/', $str, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
+
+        // convert toupper only the text between HTML tags
+        foreach ($chunks as $idx => $chunk) {
+            if ($chunk[0] != '<') {
+                $chunks[$idx] = $this->_strtoupper($chunk);
+            }
+        }
+
+        return implode($chunks);
+    }
+
+    /**
+     * Strtoupper multibyte wrapper function with HTML entities handling.
+     *
+     * @param string $str Text to convert
+     * @return string Converted text
      */
-    function _strtoupper($str)
+    private function _strtoupper($str)
     {
-        return textlib::strtoupper($str);
+        $str = html_entity_decode($str, ENT_COMPAT, RCMAIL_CHARSET);
+
+        if (class_exists('textlib'))
+            $str = textlib::strtoupper($str);
+        else if (function_exists('mb_strtoupper'))
+            $str = mb_strtoupper($str);
+        else
+            $str = strtoupper($str);
+
+        $str = htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
+
+        return $str;
     }
 }
index 65b5f32..75ddfbe 100644 (file)
@@ -1,69 +1,17 @@
-html2text.php is an unmodified copy of a file shipped with the RoundCube project:
+Customised html2text.php from the RoundCube project:
 
   http://trac.roundcube.net/log/trunk/roundcubemail/program/lib/html2text.php
 
  -- Francois Marier <francois@catalyst.net.nz>  2009-05-22
 
-
 Modifications
 --------------
 
-1- Don't just strip images, replace them with their alt text.
-
-index b7e3e3e..96ef508 100644
---- a/lib/html2text.php
-+++ b/lib/html2text.php
-@@ -237,6 +237,7 @@ class html2text
-         '/<(a) [^>]*href=("|\')([^"\']+)\2[^>]*>(.*?)<\/a>/i',
-                                                    // <a href="">
-         '/<(th)[^>]*>(.*?)<\/th>/i',               // <th> and </th>
-+        '/<(img)[^>]*alt=\"([^>"]+)\"[^>]*>/i',    // <img> with alt
-     );
-
-    /**
-@@ -574,6 +575,8 @@ class html2text
-             return $this->_strtoupper("\n\n". $matches[2] ."\n\n");
-         case 'a':
-             return $this->_build_link_list($matches[3], $matches[4]);
-+        case 'img':
-+            return '[' . $matches[2] . ']';
-         }
-     }
-
--- Tim Hunt 2010-08-04
-
-2- No strip slashes, we do not use magic quotes any more in Moodle 2.0 or later
-
-3- Use textlib, not crappy functions that break UTF-8, in the _strtoupper method.
-
-Index: lib/html2text.php
---- lib/html2text.php   2 Sep 2010 12:49:29 -0000   1.16
-+++ lib/html2text.php   2 Nov 2010 19:57:09 -0000
-@@ -580,9 +580,7 @@
-      */
-     function _strtoupper($str)
-     {
--        if (function_exists('mb_strtoupper'))
--            return mb_strtoupper($str);
--        else
--            return strtoupper($str);
-+        return textlib::strtoupper($str);
-     }
- }
-
--- Tim Hunt 2010-11-02
-
-4 - Make sure html2text does not destroy '0'.
+1. Don't just strip images, replace them with their alt text. (Tim Hunt 2010-08-04)
+2. No strip slashes, we do not use magic quotes any more in Moodle 2.0 or later
+3. Use textlib, not crappy functions that break UTF-8, in the _strtoupper method. (Tim Hunt 2010-11-02)
+4. Make sure html2text does not destroy '0'. (Tim Hunt 2011-09-21)
+5. define missing mail charset
 
-index e2d0dff..9cc213d 100644
---- a/lib/html2text.php
-+++ b/lib/html2text.php
-@@ -335,7 +335,7 @@ class html2text
-      */
-     function html2text( $source = '', $from_file = false, $do_links = true, $wi     {
--        if ( !empty($source) ) {
-+        if ($source !== '') {
-             $this->set_html($source, $from_file);
-         }
 
--- Tim Hunt 2011-09-21
+Imported from: https://github.com/moodle/custom-html2text/tree/MOODLE_5886_1
index 580cb1b..0099f60 100644 (file)
@@ -4546,7 +4546,7 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
     // Remove all roles and enrolments by default
     if (empty($options['keep_roles_and_enrolments'])) {
         // this hack is used in restore when deleting contents of existing course
-        role_unassign_all(array('contextid'=>$coursecontext->id), true);
+        role_unassign_all(array('contextid'=>$coursecontext->id, 'component'=>''), true);
         enrol_course_delete($course);
         if ($showfeedback) {
             echo $OUTPUT->notification($strdeleted.get_string('type_enrol_plural', 'plugin'), 'notifysuccess');
@@ -4772,14 +4772,10 @@ function reset_course_userdata($data) {
                 unset($instances[$key]);
                 continue;
             }
-            if (!$plugins[$instance->enrol]->allow_unenrol($instance)) {
-                unset($instances[$key]);
-            }
         }
 
-        $sqlempty = $DB->sql_empty();
         foreach($data->unenrol_users as $withroleid) {
-            $sql = "SELECT DISTINCT ue.userid, ue.enrolid
+            $sql = "SELECT ue.*
                       FROM {user_enrolments} ue
                       JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)
                       JOIN {context} c ON (c.contextlevel = :courselevel AND c.instanceid = e.courseid)
@@ -4791,9 +4787,16 @@ function reset_course_userdata($data) {
                 if (!isset($instances[$ue->enrolid])) {
                     continue;
                 }
-                $plugins[$instances[$ue->enrolid]->enrol]->unenrol_user($instances[$ue->enrolid], $ue->userid);
+                $instance = $instances[$ue->enrolid];
+                $plugin = $plugins[$instance->enrol];
+                if (!$plugin->allow_unenrol($instance) and !$plugin->allow_unenrol_user($instance, $ue)) {
+                    continue;
+                }
+
+                $plugin->unenrol_user($instance, $ue->userid);
                 $data->unenrolled[$ue->userid] = $ue->userid;
             }
+            $rs->close();
         }
     }
     if (!empty($data->unenrolled)) {
@@ -5441,7 +5444,9 @@ function reset_password_and_mail($user) {
 
     $subject = get_string('emailconfirmationsubject', '', format_string($site->fullname));
 
-    $data->link  = $CFG->wwwroot .'/login/confirm.php?data='. $user->secret .'/'. urlencode($user->username);
+    $username = urlencode($user->username);
+    $username = str_replace('.', '%2E', $username); // prevent problems with trailing dots
+    $data->link  = $CFG->wwwroot .'/login/confirm.php?data='. $user->secret .'/'. $username;
     $message     = get_string('emailconfirmation', '', $data);
     $messagehtml = text_to_html(get_string('emailconfirmation', '', $data), false, false, true);
 
@@ -8848,7 +8853,7 @@ function shorten_text($text, $ideal=30, $exact = false, $ending='...') {
     global $CFG;
 
     // if the plain text is shorter than the maximum length, return the whole text
-    if (strlen(preg_replace('/<.*?>/', '', $text)) <= $ideal) {
+    if (textlib::strlen(preg_replace('/<.*?>/', '', $text)) <= $ideal) {
         return $text;
     }
 
@@ -8856,7 +8861,7 @@ function shorten_text($text, $ideal=30, $exact = false, $ending='...') {
     // and only tag in its 'line'
     preg_match_all('/(<.+?>)?([^<>]*)/s', $text, $lines, PREG_SET_ORDER);
 
-    $total_length = strlen($ending);
+    $total_length = textlib::strlen($ending);
     $truncate = '';
 
     // This array stores information about open and close tags and their position
@@ -8875,19 +8880,19 @@ function shorten_text($text, $ideal=30, $exact = false, $ending='...') {
             } else if (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) {
                 // record closing tag
                 $tagdetails[] = (object)array('open'=>false,
-                    'tag'=>strtolower($tag_matchings[1]), 'pos'=>strlen($truncate));
+                    'tag'=>textlib::strtolower($tag_matchings[1]), 'pos'=>textlib::strlen($truncate));
             // if tag is an opening tag (f.e. <b>)
             } else if (preg_match('/^<\s*([^\s>!]+).*?>$/s', $line_matchings[1], $tag_matchings)) {
                 // record opening tag
                 $tagdetails[] = (object)array('open'=>true,
-                    'tag'=>strtolower($tag_matchings[1]), 'pos'=>strlen($truncate));
+                    'tag'=>textlib::strtolower($tag_matchings[1]), 'pos'=>textlib::strlen($truncate));
             }
             // add html-tag to $truncate'd text
             $truncate .= $line_matchings[1];
         }
 
         // calculate the length of the plain text part of the line; handle entities as one character
-        $content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
+        $content_length = textlib::strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
         if ($total_length+$content_length > $ideal) {
             // the number of characters which are left
             $left = $ideal - $total_length;
@@ -8898,14 +8903,14 @@ function shorten_text($text, $ideal=30, $exact = false, $ending='...') {
                 foreach ($entities[0] as $entity) {
                     if ($entity[1]+1-$entities_length <= $left) {
                         $left--;
-                        $entities_length += strlen($entity[0]);
+                        $entities_length += textlib::strlen($entity[0]);
                     } else {
                         // no more characters left
                         break;
                     }
                 }
             }
-            $truncate .= substr($line_matchings[2], 0, $left+$entities_length);
+            $truncate .= textlib::substr($line_matchings[2], 0, $left+$entities_length);
             // maximum length is reached, so get off the loop
             break;
         } else {
@@ -8922,21 +8927,21 @@ function shorten_text($text, $ideal=30, $exact = false, $ending='...') {
     // if the words shouldn't be cut in the middle...
     if (!$exact) {
         // ...search the last occurence of a space...
-        for ($k=strlen($truncate);$k>0;$k--) {
-            if (!empty($truncate[$k]) && ($char = $truncate[$k])) {
-                if ($char == '.' or $char == ' ') {
+        for ($k=textlib::strlen($truncate);$k>0;$k--) {
+            if ($char = textlib::substr($truncate, $k, 1)) {
+                if ($char === '.' or $char === ' ') {
                     $breakpos = $k+1;
                     break;
-                } else if (ord($char) >= 0xE0) {  // Chinese/Japanese/Korean text
-                    $breakpos = $k;               // can be truncated at any UTF-8
-                    break;                        // character boundary.
+                } else if (strlen($char) > 2) {  // Chinese/Japanese/Korean text
+                    $breakpos = $k+1;            // can be truncated at any UTF-8
+                    break;                       // character boundary.
                 }
             }
         }
 
         if (isset($breakpos)) {
             // ...and cut the text in this position
-            $truncate = substr($truncate, 0, $breakpos);
+            $truncate = textlib::substr($truncate, 0, $breakpos);
         }
     }
 
index 19ef2f5..f807b7d 100644 (file)
@@ -1055,7 +1055,7 @@ class global_navigation extends navigation_node {
             $limit = $CFG->navcourselimit;
         }
 
-        $mycourses = enrol_get_my_courses(NULL, 'visible DESC,sortorder ASC', $limit);
+        $mycourses = enrol_get_my_courses(NULL, 'visible DESC,sortorder ASC');
         $showallcourses = (count($mycourses) == 0 || !empty($CFG->navshowallcourses));
         $showcategories = ($showallcourses && $this->show_categories());
         $issite = ($this->page->course->id == SITEID);
@@ -1063,7 +1063,77 @@ class global_navigation extends navigation_node {
 
         // Check if any courses were returned.
         if (count($mycourses) > 0) {
-            // Add all of the users courses to the navigation
+
+            // Check if categories should be displayed within the my courses branch
+            if (!empty($CFG->navshowmycoursecategories)) {
+
+                // Find the category of each mycourse
+                $categories = array();
+                foreach ($mycourses as $course) {
+                    $categories[] = $course->category;
+                }
+
+                // Do a single DB query to get the categories immediately associated with
+                // courses the user is enrolled in.
+                $categories = $DB->get_records_list('course_categories', 'id', array_unique($categories), 'depth ASC, sortorder ASC');
+                // Work out the parent categories that we need to load that we havn't
+                // already got.
+                $categoryids = array();
+                foreach ($categories as $category) {
+                    $categoryids = array_merge($categoryids, explode('/', trim($category->path, '/')));
+                }
+                $categoryids = array_unique($categoryids);
+                $categoryids = array_diff($categoryids, array_keys($categories));
+
+                if (count($categoryids)) {
+                    // Fetch any other categories we need.
+                    $allcategories = $DB->get_records_list('course_categories', 'id', $categoryids, 'depth ASC, sortorder ASC');
+                    if (is_array($allcategories) && count($allcategories) > 0) {
+                        $categories = array_merge($categories, $allcategories);
+                    }
+                }
+
+                // We ONLY want the categories, we need to get rid of the keys
+                $categories = array_values($categories);
+                $addedcategories = array();
+                while (($category = array_shift($categories)) !== null) {
+                    if ($category->parent == '0') {
+                        $categoryparent = $this->rootnodes['mycourses'];
+                    } else if (array_key_exists($category->parent, $addedcategories)) {
+                        $categoryparent = $addedcategories[$category->parent];
+                    } else {
+                        // Prepare to count iterations. We don't want to loop forever
+                        // accidentally if for some reason a category can't be placed.
+                        if (!isset($category->loopcount)) {
+                            $category->loopcount = 0;
+                        }
+                        $category->loopcount++;
+                        if ($category->loopcount > 5) {
+                            // This is a pretty serious problem and this should never happen.
+                            // If it does then for some reason a category has been loaded but
+                            // its parents have now. It could be data corruption.
+                            debugging('Category '.$category->id.' could not be placed within the navigation', DEBUG_DEVELOPER);
+                        } else {
+                            // Add it back to the end of the categories array
+                            array_push($categories, $category);
+                        }
+                        continue;
+                    }
+
+                    $url = new moodle_url('/course/category.php', array('id' => $category->id));
+                    $addedcategories[$category->id] = $categoryparent->add($category->name, $url, self::TYPE_CATEGORY, $category->name, $category->id);
+
+                    if (!$category->visible) {
+                        if (!has_capability('moodle/category:viewhiddencategories', get_context_instance(CONTEXT_COURSECAT, $category->parent))) {
+                            $addedcategories[$category->id]->display = false;
+                        } else {
+                            $addedcategories[$category->id]->hidden = true;
+                        }
+                    }
+                }
+            }
+
+            // Add all of the users courses to the navigation.
             foreach ($mycourses as $course) {
                 $course->coursenode = $this->add_course($course, false, true);
             }
@@ -2196,7 +2266,11 @@ class global_navigation extends navigation_node {
                 $shortname = get_string('sitepages');
             }
         } else if ($ismycourse) {
-            $parent = $this->rootnodes['mycourses'];
+            if (!empty($CFG->navshowmycoursecategories) && ($parent = $this->rootnodes['mycourses']->find($course->category, self::TYPE_CATEGORY))) {
+                // Nothing to do here the above statement set $parent to the category within mycourses.
+            } else {
+                $parent = $this->rootnodes['mycourses'];
+            }
             $url = new moodle_url('/course/view.php', array('id'=>$course->id));
         } else {
             $parent = $this->rootnodes['courses'];
@@ -3301,6 +3375,7 @@ class settings_navigation extends navigation_node {
             // hidden in new courses and courses where legacy files were turned off
             $url = new moodle_url('/files/index.php', array('contextid'=>$coursecontext->id));
             $coursenode->add(get_string('courselegacyfiles'), $url, self::TYPE_SETTING, null, 'coursefiles', new pix_icon('i/files', ''));
+
         }
 
         // Switch roles
index e351b93..7806b74 100644 (file)
@@ -441,7 +441,7 @@ class page_requirements_manager {
                                                         array('saving', 'repository'), array('search', 'repository'), array('searching', 'repository'), array('size', 'repository'),
                                                         array('submit', 'repository'), array('sync', 'repository'), array('title', 'repository'), array('upload', 'repository'),
                                                         array('uploading', 'repository'), array('xhtmlerror', 'repository'),
-                                                        array('cancel'), array('chooselicense', 'repository'), array('author', 'repository'),
+                                                        array('cancel'), array('chooselicense', 'repository'), array('author', 'repository'),array('next', 'moodle'),
                                                         array('ok', 'moodle'), array('error', 'moodle'), array('info', 'moodle'), array('norepositoriesavailable', 'repository'), array('norepositoriesexternalavailable', 'repository'),
                                                         array('nofilesattached', 'repository'), array('filepicker', 'repository'),
                                                         array('nofilesavailable', 'repository'), array('overwrite', 'repository'),
index 9d788a7..06fa73e 100644 (file)
@@ -465,7 +465,8 @@ class plugin_manager {
 
             'scormreport' => array(
                 'basic',
-                'interactions'
+                'interactions',
+                'graphs'
             ),
 
             'theme' => array(
diff --git a/lib/simpletest/testhtml2text.php b/lib/simpletest/testhtml2text.php
new file mode 100644 (file)
index 0000000..5ac56ed
--- /dev/null
@@ -0,0 +1,147 @@
+<?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/>.
+
+/**
+ * Tests our html2text hacks
+ *
+ * Note: includes original tests from testweblib.php
+ *
+ * @package    core
+ * @subpackage lib
+ * @copyright  2012 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+class html2text_test extends UnitTestCase {
+
+    public static $includecoverage = array('lib/html2text.php');
+
+    /**
+     * ALT as image replacements
+     */
+    public function test_images() {
+        $this->assertEqual('[edit]', html_to_text('<img src="edit.png" alt="edit" />'));
+
+        $text = 'xx<img src="gif.gif" alt="some gif" />xx';
+        $result = html_to_text($text, null, false, false);
+        $this->assertIdentical($result, 'xx[some gif]xx');
+    }
+
+    /**
+     * No magic quotes messing
+     */
+    public function test_no_strip_slashes() {
+        $this->assertEqual('[\edit]', html_to_text('<img src="edit.png" alt="\edit" />'));
+
+        $text = '\\magic\\quotes\\are\\\\horrible';
+        $result = html_to_text($text, null, false, false);
+        $this->assertIdentical($result, $text);
+    }
+
+    /**
+     * Textlib integration
+     */
+    public function test_textlib() {
+        $text = '<strong>Žluťoučký koníček</strong>';
+        $result = html_to_text($text, null, false, false);
+        $this->assertIdentical($result, 'ŽLUŤOUČKÝ KONÍČEK');
+    }
+
+    /**
+     * Protect 0
+     */
+    public function test_zero() {
+        $text = '0';
+        $result = html_to_text($text, null, false, false);
+        $this->assertIdentical($result, $text);
+
+        $this->assertIdentical('0', html_to_text('0'));
+    }
+
+    // ======= Standard html2text conversion features =======
+
+    /**
+     * Various invalid HTML typed by users that ignore html strict
+     **/
+    public function test_invalid_html() {
+        $text = 'Gin & Tonic';
+        $result = html_to_text($text, null, false, false);
+        $this->assertIdentical($result, $text);
+
+        $text = 'Gin > Tonic';
+        $result = html_to_text($text, null, false, false);
+        $this->assertIdentical($result, $text);
+
+        $text = 'Gin < Tonic';
+        $result = html_to_text($text, null, false, false);
+        $this->assertIdentical($result, $text);
+    }
+
+    /**
+     * Basic text formatting.
+     */
+    public function test_simple() {
+        $this->assertEqual("_Hello_ WORLD!", html_to_text('<p><i>Hello</i> <b>world</b>!</p>'));
+        $this->assertEqual("All the WORLD’S a stage.\n\n-- William Shakespeare", html_to_text('<p>All the <strong>world’s</strong> a stage.</p><p>-- William Shakespeare</p>'));
+        $this->assertEqual("HELLO WORLD!\n\n", html_to_text('<h1>Hello world!</h1>'));
+        $this->assertEqual("Hello\nworld!", html_to_text('Hello<br />world!'));
+    }
+
+    /**
+     * Test line wrapping
+     */
+    public function test_text_nowrap() {
+        $long = "Here is a long string, more than 75 characters long, since by default html_to_text wraps text at 75 chars.";
+        $wrapped = "Here is a long string, more than 75 characters long, since by default\nhtml_to_text wraps text at 75 chars.";
+        $this->assertEqual($long, html_to_text($long, 0));
+        $this->assertEqual($wrapped, html_to_text($long));
+    }
+
+    /**
+     * Whitespace removal
+     */
+    public function test_trailing_whitespace() {
+        $this->assertEqual('With trailing whitespace and some more text', html_to_text("With trailing whitespace   \nand some   more text", 0));
+    }
+
+    /**
+     * PRE parsing
+     */
+    public function test_html_to_text_pre_parsing_problem() {
+        $strorig = 'Consider the following function:<br /><pre><span style="color: rgb(153, 51, 102);">void FillMeUp(char* in_string) {'.
+            '<br />  int i = 0;<br />  while (in_string[i] != \'\0\') {<br />    in_string[i] = \'X\';<br />    i++;<br />  }<br />'.
+            '}</span></pre>What would happen if a non-terminated string were input to this function?<br /><br />';
+
+        $strconv = 'Consider the following function:
+
+void FillMeUp(char* in_string) {
+ int i = 0;
+ while (in_string[i] != \'\0\') {
+ in_string[i] = \'X\';
+ i++;
+ }
+}
+What would happen if a non-terminated string were input to this function?
+
+';
+
+        $this->assertIdentical($strconv, html_to_text($strorig));
+    }
+}
+
index 575238f..0142a66 100644 (file)
@@ -953,6 +953,48 @@ class moodlelib_test extends UnitTestCase {
         $text = "<h1>123456789</h1>";//a string with no convenient breaks
         $this->assertEqual("<h1>12345...</h1>",
             shorten_text($text, 8));
+
+        // ==== this must work with UTF-8 too! ======
+
+        // text without tags
+        $text = "Žluťoučký koníček přeskočil";
+        $this->assertEqual($text, shorten_text($text)); // 30 chars by default
+        $this->assertEqual("Žluťoučký koníče...", shorten_text($text, 19, true));
+        $this->assertEqual("Žluťoučký ...", shorten_text($text, 19, false));
+        // And try it with 2-less (that are, in bytes, the middle of a sequence)
+        $this->assertEqual("Žluťoučký koní...", shorten_text($text, 17, true));
+        $this->assertEqual("Žluťoučký ...", shorten_text($text, 17, false));
+
+        $text = "<p>Žluťoučký koníček <b>přeskočil</b> potůček</p>";
+        $this->assertEqual($text, shorten_text($text, 60));
+        $this->assertEqual("<p>Žluťoučký koníček ...</p>", shorten_text($text, 21));
+        $this->assertEqual("<p>Žluťoučký koníče...</p>", shorten_text($text, 19, true));
+        $this->assertEqual("<p>Žluťoučký ...</p>", shorten_text($text, 19, false));
+        // And try it with 2-less (that are, in bytes, the middle of a sequence)
+        $this->assertEqual("<p>Žluťoučký koní...</p>", shorten_text($text, 17, true));
+        $this->assertEqual("<p>Žluťoučký ...</p>", shorten_text($text, 17, false));
+        // And try over one tag (start/end), it does proper text len
+        $this->assertEqual("<p>Žluťoučký koníček <b>př...</b></p>", shorten_text($text, 23, true));
+        $this->assertEqual("<p>Žluťoučký koníček <b>přeskočil</b> pot...</p>", shorten_text($text, 34, true));
+        // And in the middle of one tag
+        $this->assertEqual("<p>Žluťoučký koníček <b>přeskočil...</b></p>", shorten_text($text, 30, true));
+
+        // Japanese
+        $text = '言語設定言語設定abcdefghijkl';
+        $this->assertEqual($text, shorten_text($text)); // 30 chars by default
+        $this->assertEqual("言語設定言語...", shorten_text($text, 9, true));
+        $this->assertEqual("言語設定言語...", shorten_text($text, 9, false));
+        $this->assertEqual("言語設定言語設定ab...", shorten_text($text, 13, true));
+        $this->assertEqual("言語設定言語設定...", shorten_text($text, 13, false));
+
+        // Chinese
+        $text = '简体中文简体中文abcdefghijkl';
+        $this->assertEqual($text, shorten_text($text)); // 30 chars by default
+        $this->assertEqual("简体中文简体...", shorten_text($text, 9, true));
+        $this->assertEqual("简体中文简体...", shorten_text($text, 9, false));
+        $this->assertEqual("简体中文简体中文ab...", shorten_text($text, 13, true));
+        $this->assertEqual("简体中文简体中文...", shorten_text($text, 13, false));
+
     }
 
     function test_usergetdate() {
@@ -1753,4 +1795,4 @@ class moodlelib_test extends UnitTestCase {
         // Reset the language
         $COURSE->lang = $originallang;
     }
-}
\ No newline at end of file
+}
index c1a313d..a1d985e 100644 (file)
@@ -62,9 +62,9 @@ class web_test extends UnitTestCase {
     }
 
     function test_format_text_email() {
-        $this->assertEqual("\n\nThis is a TEST",
+        $this->assertEqual("This is a TEST",
             format_text_email('<p>This is a <strong>test</strong></p>',FORMAT_HTML));
-        $this->assertEqual("\n\nThis is a TEST",
+        $this->assertEqual("This is a TEST",
             format_text_email('<p class="frogs">This is a <strong class=\'fishes\'>test</strong></p>',FORMAT_HTML));
         $this->assertEqual('& so is this',
             format_text_email('&amp; so is this',FORMAT_HTML));
@@ -159,56 +159,6 @@ class web_test extends UnitTestCase {
         $url2->out_as_local_url();
     }
 
-    public function test_html_to_text_simple() {
-        $this->assertEqual("\n\n_Hello_ WORLD!", html_to_text('<p><i>Hello</i> <b>world</b>!</p>'));
-    }
-
-    public function test_html_to_text_image() {
-        $this->assertEqual('[edit]', html_to_text('<img src="edit.png" alt="edit" />'));
-    }
-
-    public function test_html_to_text_image_with_backslash() {
-        $this->assertEqual('[\edit]', html_to_text('<img src="edit.png" alt="\edit" />'));
-    }
-
-    public function test_html_to_text_nowrap() {
-        $long = "Here is a long string, more than 75 characters long, since by default html_to_text wraps text at 75 chars.";
-        $this->assertEqual($long, html_to_text($long, 0));
-    }
-
-    public function test_html_to_text_dont_screw_up_utf8() {
-        $this->assertEqual("\n\nAll the WORLD’S a stage.", html_to_text('<p>All the <strong>world’s</strong> a stage.</p>'));
-    }
-
-    public function test_html_to_text_trailing_whitespace() {
-        $this->assertEqual('With trailing whitespace and some more text', html_to_text("With trailing whitespace   \nand some   more text", 0));
-    }
-
-    public function test_html_to_text_0() {
-        $this->assertIdentical('0', html_to_text('0'));
-    }
-
-    public function test_html_to_text_pre_parsing_problem() {
-        $strorig = 'Consider the following function:<br /><pre><span style="color: rgb(153, 51, 102);">void FillMeUp(char* in_string) {'.
-                   '<br />  int i = 0;<br />  while (in_string[i] != \'\0\') {<br />    in_string[i] = \'X\';<br />    i++;<br />  }<br />'.
-                   '}</span></pre>What would happen if a non-terminated string were input to this function?<br /><br />';
-
-        $strconv = 'Consider the following function:
-
-void FillMeUp(char* in_string) {
- int i = 0;
- while (in_string[i] != \'\0\') {
- in_string[i] = \'X\';
- i++;
- }
-}
-What would happen if a non-terminated string were input to this function?
-
-';
-
-        $this->assertIdentical($strconv, html_to_text($strorig));
-    }
-
     public function test_clean_text() {
         $text = "lala <applet>xx</applet>";
         $this->assertEqual($text, clean_text($text, FORMAT_PLAIN));
index 0d20746..20bad53 100644 (file)
@@ -1,9 +1,6 @@
 <!ELEMENT FIELD EMPTY >
 <!ATTLIST FIELD DECIMALS NMTOKEN #IMPLIED >
 <!ATTLIST FIELD DEFAULT NMTOKEN #IMPLIED >
-<!-- TODO: Moodle 2.1 - Drop ENUM and ENUMVALUES attributes -->
-<!ATTLIST FIELD ENUM ( false | true ) #IMPLIED >
-<!ATTLIST FIELD ENUMVALUES CDATA #IMPLIED >
 <!ATTLIST FIELD LENGTH NMTOKEN #REQUIRED >
 <!ATTLIST FIELD NAME NMTOKEN #REQUIRED >
 <!ATTLIST FIELD NEXT NMTOKEN #IMPLIED >
index e795423..d30597e 100644 (file)
@@ -34,6 +34,7 @@
 
   <xs:simpleType name="fieldLength" >
     <xs:restriction base="xs:string" >
+    <!-- TODO: Moodle 2.5 - Drop LOB sizes, keep only numbers -->
      <xs:pattern value='(\d+)|(small|medium|big)'/>
     </xs:restriction >
   </xs:simpleType >
@@ -64,9 +65,6 @@
       <xs:attribute name="DECIMALS"   type="xs:positiveInteger" use="optional" />
       <!-- TODO: Moodle 2.4 - Drop ignored UNSIGNED attribute -->
       <xs:attribute name="UNSIGNED"   type="trueFalse"   use="optional" />
-      <!-- TODO: Moodle 2.1 - Drop ENUM and ENUMVALUES attributes -->
-      <xs:attribute name="ENUM"       type="trueFalse"   use="optional" />
-      <xs:attribute name="ENUMVALUES" type="xs:string"   use="optional" />
       <xs:attribute name="DEFAULT"    type="xs:string"   use="optional" />
       <xs:attribute name="COMMENT"    type="xs:string"   use="optional" />
       <xs:attribute name="PREVIOUS"   type="fieldName"   use="optional" />
index bcede35..cec73df 100644 (file)
@@ -66,9 +66,6 @@ class xmldb_field extends xmldb_object {
     function setAttributes($type, $precision=null, $unsigned=null, $notnull=null, $sequence=null, $enum=null, $enumvalues=null, $default=null, $previous=null) {
 
         debugging('XMLDBField->setAttributes() has been deprecated in Moodle 2.0. Will be out in Moodle 2.1. Please use xmldb_field->set_attributes() instead.', DEBUG_DEVELOPER);
-        if ($enum) {
-            debugging('Also, ENUMs support has been dropped in Moodle 2.0. Your fields specs are incorrect because you are trying to introduce one new ENUM. Created DB estructures will ignore that.');
-        }
 
         return $this->set_attributes($type, $precision, $unsigned, $notnull, $sequence, $default, $previous);
     }
@@ -78,7 +75,7 @@ class xmldb_field extends xmldb_object {
      * Set all the attributes of one xmldb_field
      *
      * @param string type XMLDB_TYPE_INTEGER, XMLDB_TYPE_NUMBER, XMLDB_TYPE_CHAR, XMLDB_TYPE_TEXT, XMLDB_TYPE_BINARY
-     * @param string precision length for integers and chars, two-comma separated numbers for numbers and 'small', 'medium', 'big' for texts and binaries
+     * @param string precision length for integers and chars, two-comma separated numbers for numbers
      * @param string unsigned XMLDB_UNSIGNED or null (or false)
      * @param string notnull XMLDB_NOTNULL or null (or false)
      * @param string sequence XMLDB_SEQUENCE or null (or false)
@@ -100,6 +97,11 @@ class xmldb_field extends xmldb_object {
         $this->sequence = !empty($sequence) ? true : false;
         $this->setDefault($default);
 
+        if ($this->type == XMLDB_TYPE_BINARY || $this->type == XMLDB_TYPE_TEXT) {
+            $this->length = null;
+            $this->decimals = null;
+        }
+
         $this->previous = $previous;
     }
 
@@ -269,19 +271,10 @@ class xmldb_field extends xmldb_object {
                     $result = false;
                 }
             }
-        /// Check for big, medium, small to be applied to text and binary
+        /// Remove length from text and binary
             if ($this->type == XMLDB_TYPE_TEXT ||
                 $this->type == XMLDB_TYPE_BINARY) {
-                if (!$length) {
-                    $length == 'big';
-                }
-                if ($length != 'big' &&
-                    $length != 'medium' &&
-                    $length != 'small') {
-                    $this->errormsg = 'Incorrect LENGTH attribute for text and binary fields (only big, medium and small allowed)';
-                    $this->debug($this->errormsg);
-                    $result = false;
-                }
+                $length = null;
             }
         /// Finally, set the length
             $this->length = $length;