Merge branch 'MDL-61022-master' of git://github.com/damyon/moodle
authorDavid Monllao <davidm@moodle.com>
Mon, 18 Dec 2017 09:21:26 +0000 (10:21 +0100)
committerDavid Monllao <davidm@moodle.com>
Mon, 18 Dec 2017 09:21:26 +0000 (10:21 +0100)
243 files changed:
.gitattributes
.travis.yml
admin/auth_config.php
admin/environment.xml
admin/registration/confirmregistration.php
admin/registration/renewregistration.php
admin/tool/analytics/classes/output/models_list.php
admin/tool/analytics/lang/en/tool_analytics.php
admin/tool/analytics/templates/models_list.mustache
admin/tool/behat/cli/util.php
admin/tool/customlang/db/upgrade.php
admin/tool/httpsreplace/tests/httpsreplace_test.php
admin/tool/log/db/upgrade.php
admin/tool/log/store/database/db/upgrade.php
admin/tool/log/store/standard/db/upgrade.php
admin/tool/lp/templates/manage_competencies_page.mustache
admin/tool/monitor/db/upgrade.php
admin/tool/uploaduser/index.php
admin/tool/uploaduser/tests/behat/upload_users.feature
admin/user.php
analytics/classes/model.php
analytics/tests/model_test.php
auth/cas/db/upgrade.php
auth/ldap/db/upgrade.php
auth/ldap/lang/en/auth_ldap.php
auth/ldap/settings.php
auth/manual/db/upgrade.php
auth/mnet/auth.php
auth/mnet/db/upgrade.php
backup/cc/entity11.resource.class.php
badges/classes/observer.php
badges/criteria/award_criteria.php
badges/criteria/award_criteria_badge.php [new file with mode: 0644]
badges/tests/behat/award_badge.feature
blocks/badges/db/upgrade.php
blocks/calendar_month/db/upgrade.php
blocks/calendar_upcoming/db/upgrade.php
blocks/community/db/upgrade.php
blocks/completionstatus/db/upgrade.php
blocks/course_list/block_course_list.php
blocks/course_summary/db/upgrade.php
blocks/globalsearch/block_globalsearch.php
blocks/html/db/upgrade.php
blocks/lp/classes/output/summary.php
blocks/myoverview/classes/output/main.php
blocks/navigation/db/upgrade.php
blocks/quiz_results/db/upgrade.php
blocks/recent_activity/db/upgrade.php
blocks/rss_client/db/upgrade.php
blocks/section_links/db/upgrade.php
blocks/selfcompletion/db/upgrade.php
blocks/settings/db/upgrade.php
calendar/externallib.php
calendar/lib.php
cohort/classes/external/cohort_summary_exporter.php
competency/classes/api.php
competency/classes/competency.php
competency/classes/template_competency.php
competency/classes/user_competency_course.php
competency/classes/user_competency_plan.php
competency/tests/external_test.php
completion/classes/external.php
completion/criteria/completion_criteria_activity.php
course/edit_form.php
course/renderer.php
enrol/database/db/upgrade.php
enrol/flatfile/db/upgrade.php
enrol/guest/db/upgrade.php
enrol/imsenterprise/db/upgrade.php
enrol/imsenterprise/tests/imsenterprise_test.php
enrol/manual/db/upgrade.php
enrol/mnet/db/upgrade.php
enrol/paypal/db/upgrade.php
enrol/self/db/upgrade.php
enrol/tests/enrollib_test.php
enrol/upgrade.txt
files/classes/converter.php
files/tests/converter_test.php
filter/mathjaxloader/db/upgrade.php
filter/mediaplugin/db/upgrade.php
filter/tex/db/upgrade.php
grade/grading/form/guide/db/upgrade.php
grade/grading/form/rubric/db/upgrade.php
grade/report/user/db/upgrade.php
grade/tests/edittreelib_test.php
grade/tests/importlib_test.php
grade/tests/querylib_test.php
grade/tests/report_graderlib_test.php
grade/tests/reportlib_test.php
grade/tests/reportuserlib_test.php
install/lang/eu/admin.php
install/lang/ig/langconfig.php [new file with mode: 0644]
install/lang/pcm/langconfig.php [new file with mode: 0644]
lang/en/auth.php
lang/en/badges.php
lang/en/form.php
lang/en/search.php
lib/accesslib.php
lib/antivirus/clamav/db/upgrade.php
lib/authlib.php
lib/badgeslib.php
lib/classes/access/get_user_capability_course_helper.php
lib/classes/hub/api.php
lib/classes/hub/registration.php
lib/classes/plugininfo/gradingform.php
lib/classes/session/redis.php
lib/classes/task/delete_unconfirmed_users_task.php
lib/completionlib.php
lib/dataformatlib.php
lib/db/events.php
lib/db/install.xml
lib/db/upgrade.php
lib/dml/moodle_database.php
lib/dml/oci_native_moodle_package.sql
lib/editor/atto/db/upgrade.php
lib/editor/atto/plugins/equation/db/upgrade.php
lib/editor/tinymce/db/upgrade.php
lib/editor/tinymce/plugins/spellchecker/db/upgrade.php
lib/enrollib.php
lib/filelib.php
lib/filestorage/stored_file.php
lib/form/passwordunmask.php
lib/form/tags.php
lib/moodlelib.php
lib/myprofilelib.php
lib/navigationlib.php
lib/outputlib.php
lib/outputrenderers.php
lib/tests/accesslib_test.php
lib/tests/filelib_test.php
lib/tests/gradelib_test.php
message/output/email/db/upgrade.php
message/output/jabber/db/upgrade.php
message/output/popup/db/upgrade.php
mod/assign/db/upgrade.php
mod/assign/feedback/comments/db/upgrade.php
mod/assign/feedback/editpdf/db/upgrade.php
mod/assign/feedback/editpdf/lang/en/assignfeedback_editpdf.php
mod/assign/feedback/editpdf/locallib.php
mod/assign/feedback/editpdf/settings.php
mod/assign/feedback/file/db/upgrade.php
mod/assign/locallib.php
mod/assign/submission/comments/db/upgrade.php
mod/assign/submission/file/db/upgrade.php
mod/assign/submission/file/locallib.php
mod/assign/submission/onlinetext/db/upgrade.php
mod/assign/submission/onlinetext/locallib.php
mod/assign/tests/locallib_test.php
mod/assignment/db/upgrade.php
mod/book/db/upgrade.php
mod/chat/db/upgrade.php
mod/choice/db/upgrade.php
mod/data/db/upgrade.php
mod/data/lang/en/data.php
mod/data/lib.php
mod/data/tests/lib_test.php
mod/feedback/db/upgrade.php
mod/feedback/db/upgradelib.php [deleted file]
mod/feedback/tests/upgradelib_test.php [deleted file]
mod/feedback/upgrade.txt
mod/folder/db/upgrade.php
mod/forum/db/upgrade.php
mod/glossary/db/upgrade.php
mod/imscp/db/upgrade.php
mod/label/db/upgrade.php
mod/lesson/db/upgrade.php
mod/lesson/lang/en/lesson.php
mod/lesson/lib.php
mod/lesson/locallib.php
mod/lesson/tests/lib_test.php
mod/lti/backup/moodle2/backup_lti_stepslib.php
mod/lti/backup/moodle2/restore_lti_stepslib.php
mod/lti/db/upgrade.php
mod/lti/tests/behat/addtype.feature
mod/lti/tests/behat/backup_restore.feature [new file with mode: 0644]
mod/lti/view.php
mod/page/db/upgrade.php
mod/quiz/classes/output/edit_renderer.php
mod/quiz/db/upgrade.php
mod/quiz/index.php
mod/quiz/report/overview/db/upgrade.php
mod/quiz/report/statistics/db/upgrade.php
mod/quiz/styles.css
mod/quiz/yui/build/moodle-mod_quiz-toolboxes/moodle-mod_quiz-toolboxes-debug.js
mod/quiz/yui/build/moodle-mod_quiz-toolboxes/moodle-mod_quiz-toolboxes-min.js
mod/quiz/yui/build/moodle-mod_quiz-toolboxes/moodle-mod_quiz-toolboxes.js
mod/quiz/yui/src/toolboxes/js/toolbox.js
mod/resource/db/upgrade.php
mod/scorm/db/upgrade.php
mod/scorm/lang/en/scorm.php
mod/scorm/lib.php
mod/scorm/locallib.php
mod/scorm/tests/lib_test.php
mod/survey/db/upgrade.php
mod/url/db/upgrade.php
mod/wiki/db/upgrade.php
mod/workshop/db/upgrade.php
mod/workshop/form/accumulative/db/upgrade.php
mod/workshop/form/comments/db/upgrade.php
mod/workshop/form/numerrors/db/upgrade.php
mod/workshop/form/rubric/db/upgrade.php
portfolio/boxnet/db/upgrade.php
portfolio/googledocs/db/upgrade.php
portfolio/picasa/db/upgrade.php
question/behaviour/manualgraded/db/upgrade.php
question/type/calculated/db/upgrade.php
question/type/ddmarker/db/upgrade.php
question/type/essay/db/upgrade.php
question/type/match/db/upgrade.php
question/type/multianswer/db/upgrade.php
question/type/multianswer/questiontype.php
question/type/multichoice/db/upgrade.php
question/type/numerical/db/upgrade.php
question/type/random/db/upgrade.php
question/type/randomsamatch/db/upgrade.php
question/type/shortanswer/db/upgrade.php
repository/boxnet/db/upgrade.php
repository/dropbox/db/upgrade.php
repository/googledocs/db/upgrade.php
repository/lib.php
repository/picasa/db/upgrade.php
search/classes/engine.php
search/classes/manager.php
search/classes/output/form/search.php
search/engine/solr/classes/engine.php
search/engine/solr/classes/schema.php
search/engine/solr/tests/engine_test.php
search/engine/solr/version.php
search/index.php
search/tests/base_test.php
search/tests/behat/behat_search.php
search/tests/behat/search_query.feature
search/tests/fixtures/mock_search_area.php
search/tests/fixtures/testable_core_search.php
search/tests/generator/lib.php
search/tests/manager_test.php
theme/boost/scss/moodle/modules.scss
theme/boost/templates/core_form/element-tags-inline.mustache
theme/boost/templates/core_form/element-tags.mustache
theme/bootstrapbase/less/moodle/modules.less
theme/bootstrapbase/style/moodle.css
theme/more/db/upgrade.php
version.php

index fb39fe0..8afacce 100644 (file)
@@ -1,4 +1,5 @@
 **/yui/build/** -diff
 **/amd/build/** -diff
+lib/dml/oci_native_moodle_package.sql text eol=lf
 theme/bootstrapbase/style/editor.css -diff
 theme/bootstrapbase/style/moodle.css -diff
index 5139a7c..9e436f5 100644 (file)
@@ -23,8 +23,9 @@ addons:
     - mysql-client-core-5.6
     - mysql-client-5.6
 
-services:
-    - redis-server
+# Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
+# services:
+#     - redis-server
 
 env:
     # Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
@@ -99,8 +100,9 @@ install:
             fi
 
             # Enable Redis.
-            echo 'extension="redis.so"' > /tmp/redis.ini
-            phpenv config-add /tmp/redis.ini
+            # Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
+            # echo 'extension="redis.so"' > /tmp/redis.ini
+            # phpenv config-add /tmp/redis.ini
 
             # Install composer dependencies.
             # We need --no-interaction in case we hit API limits for composer. This causes it to fall back to a standard clone.
@@ -171,10 +173,11 @@ before_script:
         mkdir -p "$HOME"/roots/phpunit
 
         # The phpunit dataroot and prefix..
+        # Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
+        # -e "/require_once/i \\define('TEST_SESSION_REDIS_HOST', '127.0.0.1');" \
         sed -i \
           -e "/require_once/i \\\$CFG->phpunit_dataroot = '\/home\/travis\/roots\/phpunit';" \
           -e "/require_once/i \\\$CFG->phpunit_prefix = 'p_';" \
-          -e "/require_once/i \\define('TEST_SESSION_REDIS_HOST', '127.0.0.1');" \
           config.php ;
 
         # Initialise PHPUnit for Moodle.
index 6c3e315..3ee8ebc 100644 (file)
@@ -165,6 +165,12 @@ function print_auth_lock_options($auth, $user_fields, $helptext, $retrieveopts,
             // If custom field then pick name from database.
             $fieldshortname = str_replace('profile_field_', '', $fieldname);
             $fieldname = $customfieldname[$fieldshortname]->name;
+            if (core_text::strlen($fieldshortname) > 67) {
+                // If custom profile field name is longer than 67 characters we will not be able to store the setting
+                // such as 'field_updateremote_profile_field_NOTSOSHORTSHORTNAME' in the database because the character
+                // limit for the setting name is 100.
+                continue;
+            }
         } elseif ($fieldname == 'url') {
             $fieldname = get_string('webpage');
         } else {
index 1f2f001..2b8d4ef 100644 (file)
       </CUSTOM_CHECK>
     </CUSTOM_CHECKS>
   </MOODLE>
+  <MOODLE version="3.5" requires="3.1">
+    <UNICODE level="required">
+      <FEEDBACK>
+        <ON_ERROR message="unicoderequired" />
+      </FEEDBACK>
+    </UNICODE>
+    <DATABASE level="required">
+      <VENDOR name="mariadb" version="5.5.31" />
+      <VENDOR name="mysql" version="5.5.31" />
+      <VENDOR name="postgres" version="9.3" />
+      <VENDOR name="mssql" version="10.0" />
+      <VENDOR name="oracle" version="10.2" />
+    </DATABASE>
+    <PHP version="7.0.0" level="required">
+    </PHP>
+    <PCREUNICODE level="optional">
+      <FEEDBACK>
+        <ON_CHECK message="pcreunicodewarning" />
+      </FEEDBACK>
+    </PCREUNICODE>
+    <PHP_EXTENSIONS>
+      <PHP_EXTENSION name="iconv" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="iconvrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="mbstring" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="mbstringrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="curl" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="curlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="openssl" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="opensslrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="tokenizer" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="tokenizerrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xmlrpc" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="xmlrpcrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="soap" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="soaprecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="ctype" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="ctyperequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="zip" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="ziprequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="zlib" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="gd" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="gdrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="simplexml" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="simplexmlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="spl" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="splrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="pcre" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="dom" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xml" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xmlreader" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="intl" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="intlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="json" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="hash" level="required"/>
+      <PHP_EXTENSION name="fileinfo" level="required"/>
+    </PHP_EXTENSIONS>
+    <PHP_SETTINGS>
+      <PHP_SETTING name="memory_limit" value="96M" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="settingmemorylimit" />
+        </FEEDBACK>
+      </PHP_SETTING>
+      <PHP_SETTING name="file_uploads" value="1" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="settingfileuploads" />
+        </FEEDBACK>
+      </PHP_SETTING>
+      <PHP_SETTING name="opcache.enable" value="1" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="opcacherecommended" />
+        </FEEDBACK>
+      </PHP_SETTING>
+    </PHP_SETTINGS>
+    <CUSTOM_CHECKS>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="unsupporteddbstorageengine" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="quizattemptsupgradedmessage" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="slashargumentswarning" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="unsupporteddbtablerowformat" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="unoconvwarning" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="libcurlwarning" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="unsupporteddbfileformat" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="unsupporteddbfilepertable" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="unsupporteddblargeprefix" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="ishttpswarning" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="incompleteunicodesupport" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+    </CUSTOM_CHECKS>
+  </MOODLE>
 </COMPATIBILITY_MATRIX>
index 6b20e8d..7c9d422 100644 (file)
@@ -46,6 +46,14 @@ $error = optional_param('error', '', PARAM_ALPHANUM);
 admin_externalpage_setup('registrationmoodleorg');
 
 if ($url !== HUB_MOODLEORGHUBURL) {
+    // Allow other plugins to confirm registration on hubs other than moodle.net . Plugins implementing this
+    // callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
+    $callbacks = get_plugins_with_function('hub_registration');
+    foreach ($callbacks as $plugintype => $plugins) {
+        foreach ($plugins as $plugin => $callback) {
+            $callback('confirm');
+        }
+    }
     throw new moodle_exception('errorotherhubsnotsupported', 'hub');
 }
 
index 7926e0f..84e727b 100644 (file)
@@ -40,6 +40,14 @@ $token = optional_param('token', '', PARAM_TEXT);
 admin_externalpage_setup('registrationmoodleorg');
 
 if ($url !== HUB_MOODLEORGHUBURL) {
+    // Allow other plugins to renew registration on hubs other than moodle.net . Plugins implementing this
+    // callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
+    $callbacks = get_plugins_with_function('hub_registration');
+    foreach ($callbacks as $plugintype => $plugins) {
+        foreach ($plugins as $plugin => $callback) {
+            $callback('renew');
+        }
+    }
     throw new moodle_exception('errorotherhubsnotsupported', 'hub');
 }
 
index 0e8d4e8..cbd0a60 100644 (file)
@@ -119,6 +119,9 @@ class models_list implements \renderable, \templatable {
                     debugging("The time splitting method '{$modeldata->timesplitting}' should include a '{$identifier}_help'
                         string to describe its purpose.", DEBUG_DEVELOPER);
                 }
+            } else {
+                $helpicon = new \help_icon('timesplittingnotdefined', 'tool_analytics');
+                $modeldata->timesplittinghelp = $helpicon->export_for_template($output);
             }
 
             // Has this model generated predictions?.
@@ -207,19 +210,22 @@ class models_list implements \renderable, \templatable {
             }
 
             // Enable / disable.
-            if ($model->is_enabled()) {
-                $action = 'disable';
-                $text = get_string('disable');
-                $icontype = 't/block';
-            } else {
-                $action = 'enable';
-                $text = get_string('enable');
-                $icontype = 'i/checked';
+            if ($model->is_enabled() || !empty($modeldata->timesplitting)) {
+                // If there is no timesplitting method set, the model can not be enabled.
+                if ($model->is_enabled()) {
+                    $action = 'disable';
+                    $text = get_string('disable');
+                    $icontype = 't/block';
+                } else {
+                    $action = 'enable';
+                    $text = get_string('enable');
+                    $icontype = 'i/checked';
+                }
+                $urlparams['action'] = $action;
+                $url = new \moodle_url('model.php', $urlparams);
+                $icon = new \action_menu_link_secondary($url, new \pix_icon($icontype, $text), $text);
+                $actionsmenu->add($icon);
             }
-            $urlparams['action'] = $action;
-            $url = new \moodle_url('model.php', $urlparams);
-            $icon = new \action_menu_link_secondary($url, new \pix_icon($icontype, $text), $text);
-            $actionsmenu->add($icon);
 
             // Export training data.
             if (!$model->is_static() && $model->is_trained()) {
index 68ca347..47def2b 100644 (file)
@@ -85,6 +85,8 @@ $string['previouspage'] = 'Previous page';
 $string['samestartdate'] = 'Current start date is good';
 $string['sameenddate'] = 'Current end date is good';
 $string['target'] = 'Target';
+$string['timesplittingnotdefined'] = 'Time splitting is not defined.';
+$string['timesplittingnotdefined_help'] = 'You need to select a time-splitting method before enabling the model.';
 $string['trainandpredictmodel'] = 'Training model and calculating predictions';
 $string['trainingprocessfinished'] = 'Training process finished';
 $string['trainingresults'] = 'Training results';
index 8eb6211..efdc4ca 100644 (file)
                     {{/timesplitting}}
                     {{^timesplitting}}
                         {{#str}}notdefined, tool_analytics{{/str}}
+                        {{#timesplittinghelp}}
+                            {{>core/help_icon}}
+                        {{/timesplittinghelp}}
                     {{/timesplitting}}
                 </td>
                 <td>
index 8efa4ed..e88125b 100644 (file)
@@ -398,7 +398,7 @@ function print_combined_install_output($processes) {
     // Show process name in first row.
     foreach ($processes as $name => $process) {
         // If we don't have enough space to show full run name then show runX.
-        if ($lengthofprocessline < strlen($name + 2)) {
+        if ($lengthofprocessline < strlen($name) + 2) {
             $name = substr($name, -5);
         }
         // One extra padding as we are adding | separator for rest of the data.
index 1c04587..a7ff6a3 100644 (file)
@@ -29,9 +29,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_tool_customlang_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index c10ea2f..e3599c6 100644 (file)
@@ -47,12 +47,12 @@ class httpsreplace_test extends \advanced_testcase {
             "Test image from another site should be replaced" => [
                 "content" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', false) . '">',
                 "outputregex" => '/UPDATE/',
-                "expectedcontent" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', true) . '">',
+                "expectedcontent" => '<img src="' . $this->get_converted_http_link('/test.jpg') . '">',
             ],
             "Test object from another site should be replaced" => [
                 "content" => '<object data="' . $this->getExternalTestFileUrl('/test.swf', false) . '">',
                 "outputregex" => '/UPDATE/',
-                "expectedcontent" => '<object data="' . $this->getExternalTestFileUrl('/test.swf', true) . '">',
+                "expectedcontent" => '<object data="' . $this->get_converted_http_link('/test.swf') . '">',
             ],
             "Test image from a site with international name should be replaced" => [
                 "content" => '<img src="http://中国互联网络信息中心.中国/logosy/201706/W01.png">',
@@ -82,7 +82,7 @@ class httpsreplace_test extends \advanced_testcase {
             "Search for params should be case insensitive" => [
                 "content" => '<object DATA="' . $this->getExternalTestFileUrl('/test.swf', false) . '">',
                 "outputregex" => '/UPDATE/',
-                "expectedcontent" => '<object DATA="' . $this->getExternalTestFileUrl('/test.swf', true) . '">',
+                "expectedcontent" => '<object DATA="' . $this->get_converted_http_link('/test.swf') . '">',
             ],
             "URL should be case insensitive" => [
                 "content" => '<object data="HTTP://some.site/path?query">',
@@ -93,7 +93,7 @@ class httpsreplace_test extends \advanced_testcase {
                 "content" => '<img alt="A picture" src="' . $this->getExternalTestFileUrl('/test.png', false) .
                     '" width="1”><p style="font-size: \'20px\'"></p>',
                 "outputregex" => '/UPDATE/',
-                "expectedcontent" => '<img alt="A picture" src="' . $this->getExternalTestFileUrl('/test.png', true) .
+                "expectedcontent" => '<img alt="A picture" src="' . $this->get_converted_http_link('/test.png') .
                     '" width="1”><p style="font-size: \'20px\'"></p>',
             ],
             "Broken URL should not be changed" => [
@@ -113,11 +113,25 @@ class httpsreplace_test extends \advanced_testcase {
                     $this->getExternalTestFileUrl('/test.jpg', false) . '"></a>',
                 "outputregex" => '/UPDATE/',
                 "expectedcontent" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '"><img src="' .
-                    $this->getExternalTestFileUrl('/test.jpg', true) . '"></a>',
+                    $this->get_converted_http_link('/test.jpg') . '"></a>',
             ],
         ];
     }
 
+    /**
+     * Convert the HTTP external test file URL to use HTTPS.
+     *
+     * Note: We *must not* use getExternalTestFileUrl with the True option
+     * here, becase it is reasonable to have only one of these set due to
+     * issues with SSL certificates.
+     *
+     * @param   string  $path Path to be rewritten
+     * @return  string
+     */
+    protected function get_converted_http_link($path) {
+        return preg_replace('/^http:/', 'https:', $this->getExternalTestFileUrl($path, false));
+    }
+
     /**
      * Test upgrade_http_links
      * @param string $content Example content that we'll attempt to replace.
@@ -152,7 +166,7 @@ class httpsreplace_test extends \advanced_testcase {
         // Get the http url, since the default test wwwroot is https.
         $wwwrootdomain = 'www.example.com';
         $wwwroothttp = preg_replace('/^https:/', 'http:', $CFG->wwwroot);
-        $testdomain = 'download.moodle.org';
+        $testdomain = $this->get_converted_http_link('');
         return [
             "Test image from an available site so shouldn't be reported" => [
                 "content" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', false) . '">',
index fc1e3d1..06d7441 100644 (file)
@@ -33,9 +33,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_tool_log_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 8f014cf..f9c8a8b 100644 (file)
@@ -27,9 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_logstore_database_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 8880f59..610b61c 100644 (file)
@@ -27,9 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_logstore_standard_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index bf43b5d..e99f7c5 100644 (file)
@@ -64,6 +64,7 @@
                                 <li>
                                     <a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
                                     <ul class="dropdown dropdown-menu">
+                                    {{#canmanage}}
                                     <li class="dropdown-item">
                                         <a href="#" data-action="edit">
                                             {{#pix}}t/edit{{/pix}} {{#str}}edit{{/str}}
                                             {{#pix}}t/down{{/pix}} {{#str}}movedown{{/str}}
                                         </a>
                                     </li>
+                                    {{/canmanage}}
                                     <li class="dropdown-item">
                                         <a href="#" data-action="linkedcourses">
                                             {{#pix}}t/viewdetails{{/pix}} {{#str}}linkedcourses, tool_lp{{/str}}
                                         </a>
                                     </li>
+                                    {{#canmanage}}
                                     <li class="dropdown-item">
                                         <a href="#" data-action="relatedcompetencies">
                                             {{#pix}}t/add{{/pix}} {{#str}}addcrossreferencedcompetency, tool_lp{{/str}}
                                             {{#pix}}t/edit{{/pix}} {{#str}}competencyrule, tool_lp{{/str}}
                                         </a>
                                     </li>
+                                    {{/canmanage}}
                                 </ul>
                             </li>
                         </ul>
                 <p data-region="competencyinfo">
                     {{#str}}nocompetencyselected, tool_lp{{/str}}
                 </p>
-                {{#canmanage}}
                 <div data-region="competencyactions">
+                    {{#canmanage}}
                     <button class="btn btn-secondary" data-action="add">{{#pix}}t/add{{/pix}} <span data-region="term"></span></button>
+                    {{/canmanage}}
                 </div>
-                {{/canmanage}}
             </div>
         </div>
     </div>
index 6fbca49..1358647 100644 (file)
@@ -35,9 +35,6 @@ function xmldb_tool_monitor_upgrade($oldversion) {
 
     $dbman = $DB->get_manager();
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     if ($oldversion < 2016052305) {
 
         // Define field inactivedate to be added to tool_monitor_subscriptions.
index d11332b..496b52d 100644 (file)
@@ -358,7 +358,7 @@ if ($formdata = $mform2->is_cancelled()) {
 
         // add default values for remaining fields
         $formdefaults = array();
-        if ($updatetype != UU_UPDATE_FILEOVERRIDE && $updatetype != UU_UPDATE_NOCHANGES) {
+        if (!$existinguser || ($updatetype != UU_UPDATE_FILEOVERRIDE && $updatetype != UU_UPDATE_NOCHANGES)) {
             foreach ($STD_FIELDS as $field) {
                 if (isset($user->$field)) {
                     continue;
index e217cf1..1ee26f4 100644 (file)
@@ -38,6 +38,31 @@ Feature: Upload users
     And I set the field "groups" to "Section 1 (1)"
     And the "members" select box should contain "Tom Jones"
 
+  @javascript
+  Scenario: Upload users enrolling them on courses and groups applying defaults
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Maths | math102 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Section 1 | math102 | S1 |
+      | Section 3 | math102 | S3 |
+    And I log in as "admin"
+    And I navigate to "Upload users" node in "Site administration > Users > Accounts"
+    When I upload "lib/tests/fixtures/upload_users.csv" file to "File" filemanager
+    And I press "Upload users"
+    And I set the following fields to these values:
+      | City/town  | Brighton   |
+      | Department | Purchasing |
+    And I press "Upload users"
+    And I press "Continue"
+    And I navigate to "Users > Accounts > Browse list of users" in site administration
+    And I should see "Tom Jones"
+    And I follow "Tom Jones"
+    And I follow "Edit profile"
+    And the field "City/town" matches value "Brighton"
+    And the field "Department" matches value "Purchasing"
+
   @javascript
   Scenario: Upload users with custom profile fields
     # Create user profile field.
index 65bf4e6..ac0f5f9 100644 (file)
                 $users[$key]->country = $countries[$user->country];
             }
         }
-        if ($sort == "country") {  // Need to resort by full country name, not code
+        if ($sort == "country") {
+            // Need to resort by full country name, not code.
             foreach ($users as $user) {
                 $susers[$user->id] = $user->country;
             }
-            asort($susers);
+            // Sort by country name, according to $dir.
+            if ($dir === 'DESC') {
+                arsort($susers);
+            } else {
+                asort($susers);
+            }
             foreach ($susers as $key => $value) {
                 $nusers[] = $users[$key];
             }
index d881645..0bee650 100644 (file)
@@ -1013,6 +1013,10 @@ class model {
             if (!$this->is_static()) {
                 $this->model->trained = 0;
             }
+        } else if (empty($this->model->timesplitting)) {
+            // A valid timesplitting method needs to be supplied before a model can be enabled.
+            throw new \moodle_exception('invalidtimesplitting', 'analytics', '', $this->model->id);
+
         }
 
         // Purge pages with insights as this may change things.
index 2685b64..d5d0153 100644 (file)
@@ -226,7 +226,7 @@ class analytics_model_testcase extends advanced_testcase {
         $this->model->mark_as_trained();
         $this->assertEquals($originaluniqueid, $this->model->get_unique_id());
 
-        $this->model->enable();
+        $this->model->enable('\core\analytics\time_splitting\deciles');
         $this->assertEquals($originaluniqueid, $this->model->get_unique_id());
 
         // Wait 1 sec so the timestamp changes.
index 167c76b..f3999b3 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_auth_cas_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 6811fd7..02f1323 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_auth_ldap_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index fdb9541..843e1b0 100644 (file)
@@ -41,7 +41,7 @@ $string['auth_ldapdescription'] = 'This method provides authentication against a
                                   entry in its database. This module can read user attributes from LDAP and prefill
                                   wanted fields in Moodle.  For following logins only the username and
                                   password are checked.';
-$string['auth_ldap_expiration_desc'] = 'Select No to disable expired password checking or LDAP to read passwordexpiration time directly from LDAP';
+$string['auth_ldap_expiration_desc'] = 'Select \'{$a->no}\' to disable expired password checking or \'{$a->ldapserver}\' to read the password expiration time directly from the LDAP server';
 $string['auth_ldap_expiration_key'] = 'Expiration';
 $string['auth_ldap_expiration_warning_desc'] = 'Number of days before password expiration warning is issued.';
 $string['auth_ldap_expiration_warning_key'] = 'Expiration warning';
index af1ddf7..43fb8eb 100644 (file)
@@ -185,12 +185,24 @@ if ($ADMIN->fulltree) {
                 new lang_string('auth_ldap_passwdexpire_settings', 'auth_ldap'), ''));
 
         // Password Expiration.
+
+        // Create the description lang_string object.
+        $strno = get_string('no');
+        $strldapserver = get_string('pluginname', 'auth_ldap');
+        $langobject = new stdClass();
+        $langobject->no = $strno;
+        $langobject->ldapserver = $strldapserver;
+        $description = new lang_string('auth_ldap_expiration_desc', 'auth_ldap', $langobject);
+
+        // Now create the options.
         $expiration = array();
-        $expiration['0'] = 'no';
-        $expiration['1'] = 'LDAP';
+        $expiration['0'] = $strno;
+        $expiration['1'] = $strldapserver;
+
+        // Add the setting.
         $settings->add(new admin_setting_configselect('auth_ldap/expiration',
                 new lang_string('auth_ldap_expiration_key', 'auth_ldap'),
-                new lang_string('auth_ldap_expiration_desc', 'auth_ldap'), 0 , $expiration));
+                $description, 0 , $expiration));
 
         // Password Expiration warning.
         $settings->add(new admin_setting_configtext('auth_ldap/expiration_warning',
index 50a5266..03dbdb2 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_auth_manual_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 1f269f7..b3b22f5 100644 (file)
@@ -382,7 +382,7 @@ class auth_plugin_mnet extends auth_plugin_base {
             // with info so that the IDP can maintain mnetservice_enrol_enrolments
             $mnetrequest->add_param($remoteuser->username);
             $fields = 'id, category, sortorder, fullname, shortname, idnumber, summary, startdate, visible';
-            $courses = enrol_get_users_courses($localuser->id, false, $fields, 'visible DESC,sortorder ASC');
+            $courses = enrol_get_users_courses($localuser->id, false, $fields);
             if (is_array($courses) && !empty($courses)) {
                 // Second request to do the JOINs that we'd have done
                 // inside enrol_get_users_courses() if we had been allowed
index 925124e..9db6da9 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_auth_mnet_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
     if ($oldversion < 2017020700) {
index bc5bb5a..7bb6da7 100644 (file)
@@ -99,7 +99,7 @@ class cc11_resource extends entities11 {
                                 $link = 'http://invalidurldetected/';
                             }
                         } else {
-                            $link = $rawlink;
+                            $link = htmlspecialchars(trim($rawlink), ENT_COMPAT, 'UTF-8', false);
                         }
                     }
                 }
index 34cf105..31be94e 100644 (file)
@@ -106,6 +106,37 @@ class core_badges_observer {
         }
     }
 
+    /**
+     * Triggered when 'badge_awarded' event happens.
+     *
+     * @param \core\event\badge_awarded $event event generated when a badge is awarded.
+     */
+    public static function badge_criteria_review(\core\event\badge_awarded $event) {
+        global $DB, $CFG;
+
+        if (!empty($CFG->enablebadges)) {
+            require_once($CFG->dirroot.'/lib/badgeslib.php');
+            $userid = $event->relateduserid;
+
+            if ($rs = $DB->get_records('badge_criteria', array('criteriatype' => BADGE_CRITERIA_TYPE_BADGE))) {
+                foreach ($rs as $r) {
+                    $badge = new badge($r->badgeid);
+                    if (!$badge->is_active() || $badge->is_issued($userid)) {
+                        continue;
+                    }
+
+                    if ($badge->criteria[BADGE_CRITERIA_TYPE_BADGE]->review($userid)) {
+                        $badge->criteria[BADGE_CRITERIA_TYPE_BADGE]->mark_complete($userid);
+
+                        if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
+                            $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
+                            $badge->issue($userid);
+                        }
+                    }
+                }
+            }
+        }
+    }
     /**
      * Triggered when 'user_updated' event happens.
      *
index ee13151..5427783 100644 (file)
@@ -68,6 +68,12 @@ define('BADGE_CRITERIA_TYPE_COURSESET', 5);
  */
 define('BADGE_CRITERIA_TYPE_PROFILE', 6);
 
+/*
+ * Badge completion criteria type
+ * Criteria type constant, primarily for storing criteria type in the database.
+ */
+define('BADGE_CRITERIA_TYPE_BADGE', 7);
+
 /*
  * Criteria type constant to class name mapping
  */
@@ -79,7 +85,8 @@ $BADGE_CRITERIA_TYPES = array(
     BADGE_CRITERIA_TYPE_SOCIAL    => 'social',
     BADGE_CRITERIA_TYPE_COURSE    => 'course',
     BADGE_CRITERIA_TYPE_COURSESET => 'courseset',
-    BADGE_CRITERIA_TYPE_PROFILE   => 'profile'
+    BADGE_CRITERIA_TYPE_PROFILE   => 'profile',
+    BADGE_CRITERIA_TYPE_BADGE     => 'badge',
 );
 
 /**
diff --git a/badges/criteria/award_criteria_badge.php b/badges/criteria/award_criteria_badge.php
new file mode 100644 (file)
index 0000000..d9bd795
--- /dev/null
@@ -0,0 +1,271 @@
+<?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/>.
+
+/**
+ * This file contains the badge earned badge award criteria type class
+ *
+ * @package    core
+ * @subpackage badges
+ * @copyright  2017 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Badge award criteria -- award on badge completion
+ *
+ * @package    core
+ * @subpackage badges
+ * @copyright  2017 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class award_criteria_badge extends award_criteria {
+
+    /* @var int Criteria [BADGE_CRITERIA_TYPE_BADGE] */
+    public $criteriatype = BADGE_CRITERIA_TYPE_BADGE;
+
+    public $required_param = 'badge';
+    public $optional_params = array();
+
+    /**
+     * Get criteria details for displaying to users
+     * @param string $short Print short version of criteria
+     * @return string
+     */
+    public function get_details($short = '') {
+        global $DB, $OUTPUT;
+        $output = array();
+        foreach ($this->params as $p) {
+            $badgename = $DB->get_field('badge', 'name', array('id' => $p['badge']));
+            if (!$badgename) {
+                $str = $OUTPUT->error_text(get_string('error:nosuchbadge', 'badges'));
+            } else {
+                $str = html_writer::tag('b', '"' . $badgename . '"');
+            }
+            $output[] = $str;
+        }
+
+        if ($short) {
+            return implode(', ', $output);
+        } else {
+            return html_writer::alist($output, array(), 'ul');
+        }
+    }
+
+    /**
+     * Add appropriate new criteria options to the form
+     * @param object $mform moodle form
+     */
+    public function get_options(&$mform) {
+        global $DB;
+        $none = false;
+        $availablebadges = null;
+
+        $mform->addElement('header', 'first_header', $this->get_title());
+        $mform->addHelpButton('first_header', 'criteria_' . $this->criteriatype, 'badges');
+
+        // Determine if this badge is a course badge or a site badge.
+        $thisbadge = $DB->get_record('badge', array('id' => $this->badgeid));
+
+        if ($thisbadge->type == BADGE_TYPE_SITE) {
+            // Only list site badges that are enabled.
+            $select = " type = :site AND (status = :status1 OR status = :status2)";
+            $params = array('site' => BADGE_TYPE_SITE,
+                            'status1' => BADGE_STATUS_ACTIVE,
+                            'status2' => BADGE_STATUS_ACTIVE_LOCKED);
+            $availablebadges = $DB->get_records_select_menu('badge', $select, $params, 'name ASC', 'id, name');
+
+        } else if ($thisbadge->type == BADGE_TYPE_COURSE) {
+            // List both site badges and course badges belonging to this course.
+            $select = " (type = :site OR (type = :course AND courseid = :courseid)) AND (status = :status1 OR status = :status2)";
+            $params = array('site' => BADGE_TYPE_SITE,
+                            'course' => BADGE_TYPE_COURSE,
+                            'courseid' => $thisbadge->courseid,
+                            'status1' => BADGE_STATUS_ACTIVE,
+                            'status2' => BADGE_STATUS_ACTIVE_LOCKED);
+            $availablebadges = $DB->get_records_select_menu('badge', $select, $params, 'name ASC', 'id, name');
+        }
+        if (!empty($availablebadges)) {
+            $select = array();
+            $selected = array();
+            foreach ($availablebadges as $bid => $badgename) {
+                if ($bid != $this->badgeid) {
+                    // Do not let it use itself as criteria.
+                    $select[$bid] = format_string($badgename, true);
+                }
+            }
+
+            if ($this->id !== 0) {
+                $selected = array_keys($this->params);
+            }
+            $settings = array('multiple' => 'multiple', 'size' => 20, 'class' => 'selectbadge');
+            $mform->addElement('select', 'badge_badges', get_string('addbadge', 'badges'), $select, $settings);
+            $mform->addRule('badge_badges', get_string('requiredbadge', 'badges'), 'required');
+            $mform->addHelpButton('badge_badges', 'addbadge', 'badges');
+
+            if ($this->id !== 0) {
+                $mform->setDefault('badge_badges', $selected);
+            }
+        } else {
+            $mform->addElement('static', 'nobadges', '', get_string('error:nobadges', 'badges'));
+            $none = true;
+        }
+
+        // Add aggregation.
+        if (!$none) {
+            $mform->addElement('header', 'aggregation', get_string('method', 'badges'));
+            $agg = array();
+            $agg[] =& $mform->createElement('radio', 'agg', '', get_string('allmethodbadges', 'badges'), 1);
+            $agg[] =& $mform->createElement('radio', 'agg', '', get_string('anymethodbadges', 'badges'), 2);
+            $mform->addGroup($agg, 'methodgr', '', array('<br/>'), false);
+            if ($this->id !== 0) {
+                $mform->setDefault('agg', $this->method);
+            } else {
+                $mform->setDefault('agg', BADGE_CRITERIA_AGGREGATION_ANY);
+            }
+        }
+
+        return array($none, get_string('noparamstoadd', 'badges'));
+    }
+
+    /**
+     * Save criteria records
+     *
+     * @param array $params Values from the form or any other array.
+     */
+    public function save($params = array()) {
+        $badges = $params['badge_badges'];
+        unset($params['badge_badges']);
+        foreach ($badges as $badgeid) {
+            $params["badge_{$badgeid}"] = $badgeid;
+        }
+
+        parent::save($params);
+    }
+
+    /**
+     * Review this criteria and decide if it has been completed
+     *
+     * @param int $userid User whose criteria completion needs to be reviewed.
+     * @param bool $filtered An additional parameter indicating that user list
+     *        has been reduced and some expensive checks can be skipped.
+     *
+     * @return bool Whether criteria is complete.
+     */
+    public function review($userid, $filtered = false) {
+
+        global $DB;
+        $overall = false;
+
+        foreach ($this->params as $param) {
+            $badge = $DB->get_record('badge', array('id' => $param['badge']));
+            // See if the user has earned this badge.
+            $awarded = $DB->get_record('badge_issued', array('badgeid' => $param['badge'], 'userid' => $userid));
+
+            // Extra check in case a badge was deleted while this badge is still active.
+            if (!$badge) {
+                if ($this->method == BADGE_CRITERIA_AGGREGATION_ALL) {
+                    return false;
+                } else {
+                    continue;
+                }
+            }
+
+            if ($this->method == BADGE_CRITERIA_AGGREGATION_ALL) {
+
+                if ($awarded) {
+                    $overall = true;
+                    continue;
+                } else {
+                    return false;
+                }
+            } else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
+                if ($awarded) {
+                    return true;
+                } else {
+                    $overall = false;
+                    continue;
+                }
+            }
+        }
+
+        return $overall;
+    }
+
+    /**
+     * Checks criteria for any major problems.
+     *
+     * @return array A list containing status and an error message (if any).
+     */
+    public function validate() {
+        global $DB;
+        $params = array_keys($this->params);
+        $method = ($this->method == BADGE_CRITERIA_AGGREGATION_ALL);
+        $singleparam = (count($params) == 1);
+
+        foreach ($params as $param) {
+            // Perform check if there only one parameter with any type of aggregation,
+            // Or there are more than one parameter with aggregation ALL.
+
+            if (($singleparam || $method) && !$DB->record_exists('badge', array('id' => $param))) {
+                return array(false, get_string('error:invalidparambadge', 'badges'));
+            }
+        }
+
+        return array(true, '');
+    }
+
+    /**
+     * Returns array with sql code and parameters returning all ids
+     * of users who meet this particular criterion.
+     *
+     * @return array list($join, $where, $params)
+     */
+    public function get_completed_criteria_sql() {
+        $join = '';
+        $where = '';
+        $params = array();
+
+        if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
+            // User has received ANY of the required badges.
+            $join = " LEFT JOIN {badge_issued} bi2 ON bi2.userid = u.id";
+            $where = "AND (";
+            $i = 0;
+            foreach ($this->params as $param) {
+                if ($i == 0) {
+                    $where .= ' bi2.badgeid = :badgeid'.$i;
+                } else {
+                    $where .= ' OR bi2.badgeid = :badgeid'.$i;
+                }
+                $params['badgeid'.$i] = $param['badge'];
+                $i++;
+            }
+            $where .= ") ";
+            return array($join, $where, $params);
+        } else {
+            // User has received ALL of the required badges.
+            $join = " LEFT JOIN {badge_issued} bi2 ON bi2.userid = u.id";
+            $i = 0;
+            foreach ($this->params as $param) {
+                $i++;
+                $where = ' AND bi2.badgeid = :badgeid'.$i;
+                $params['badgeid'.$i] = $param['badge'];
+            }
+            return array($join, $where, $params);
+        }
+    }
+}
index 13c040a..cd64b32 100644 (file)
@@ -4,6 +4,71 @@ Feature: Award badges
   As an admin
   I need to add criteria to badges in the system
 
+  @javascript
+  Scenario: Award badge on other badges as criteria
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+      | student1 | Student | 1 | student1@example.com |
+    And the following "courses" exist:
+      | fullname | shortname | category | groupmode |
+      | Course 1 | C1 | 0 | 1 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    # Create course badge 1.
+    And I navigate to "Add a new badge" node in "Course administration > Badges"
+    And I follow "Add a new badge"
+    And I set the following fields to these values:
+      | Name | Course Badge 1 |
+      | Description | Course badge 1 description |
+      | issuername | Tester of course badge |
+    And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
+    And I press "Create badge"
+    And I set the field "type" to "Manual issue by role"
+    And I expand all fieldsets
+    # Set to ANY of the roles awards badge.
+    And I set the field "Teacher" to "1"
+    And I set the field "Any of the selected roles awards the badge" to "1"
+    And I press "Save"
+    And I press "Enable access"
+    And I press "Continue"
+    # Badge #2
+    And I navigate to "Add a new badge" node in "Course administration > Badges"
+    And I follow "Add a new badge"
+    And I set the following fields to these values:
+      | Name | Course Badge 2 |
+      | Description | Course badge 2 description |
+      | issuername | Tester of course badge |
+    And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
+    And I press "Create badge"
+    # Set "course badge 1" as criteria
+    And I set the field "type" to "Awarded badges"
+    And I set the field "id_badge_badges" to "Course Badge 1"
+    And I press "Save"
+    And I press "Enable access"
+    And I press "Continue"
+    And I follow "Manage badges"
+    And I follow "Course Badge 1"
+    And I follow "Recipients (0)"
+    And I press "Award badge"
+    # Award course badge 1 to student 1.
+    And I set the field "potentialrecipients[]" to "Student 1 (student1@example.com)"
+    When I press "Award badge"
+    And I follow "Course Badge 1"
+    And I follow "Recipients (1)"
+    Then I should see "Recipients (1)"
+    And I log out
+    # Student 1 should have both badges.
+    And I log in as "student1"
+    And I follow "Profile" in the user menu
+    When I click on "Course 1" "link" in the "region-main" "region"
+    Then I should see "Course Badge 1"
+    And I should see "Course Badge 2"
+
   @javascript
   Scenario: Award profile badge
     Given I log in as "admin"
index 980e5f9..bb9b3cf 100644 (file)
@@ -45,9 +45,6 @@
 function xmldb_block_badges_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 397cb90..4403a77 100644 (file)
@@ -45,9 +45,6 @@
 function xmldb_block_calendar_month_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index e7aa7fe..dbe19a5 100644 (file)
@@ -45,9 +45,6 @@
 function xmldb_block_calendar_upcoming_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index f5f0ae3..d01face 100644 (file)
@@ -46,9 +46,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_block_community_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index c74148a..f0837fc 100644 (file)
@@ -48,9 +48,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_block_completionstatus_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 36003f7..10cbf23 100644 (file)
@@ -57,14 +57,7 @@ class block_course_list extends block_list {
 
         if (empty($CFG->disablemycourses) and isloggedin() and !isguestuser() and
           !(has_capability('moodle/course:update', context_system::instance()) and $adminseesall)) {    // Just print My Courses
-            // As this is producing navigation sort order should default to $CFG->navsortmycoursessort instead
-            // of using the default.
-            if (!empty($CFG->navsortmycoursessort)) {
-                $sortorder = 'visible DESC, ' . $CFG->navsortmycoursessort . ' ASC';
-            } else {
-                $sortorder = 'visible DESC, sortorder ASC';
-            }
-            if ($courses = enrol_get_my_courses(NULL, $sortorder)) {
+            if ($courses = enrol_get_my_courses()) {
                 foreach ($courses as $course) {
                     $coursecontext = context_course::instance($course->id);
                     $linkcss = $course->visible ? "" : " class=\"dimmed\" ";
index 9186a40..763a538 100644 (file)
@@ -48,9 +48,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_block_course_summary_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 7dd3057..d3d96b2 100644 (file)
@@ -78,6 +78,12 @@ class block_globalsearch extends block_base {
             'type' => 'text', 'size' => '15');
         $this->content->text .= html_writer::empty_tag('input', $inputoptions);
 
+        // Context id.
+        if ($this->page->context && $this->page->context->contextlevel !== CONTEXT_SYSTEM) {
+            $this->content->text .= html_writer::empty_tag('input', ['type' => 'hidden',
+                    'name' => 'context', 'value' => $this->page->context->id]);
+        }
+
         // Search button.
         $this->content->text .= html_writer::tag('button', get_string('search', 'search'),
             array('id' => 'searchform_button', 'type' => 'submit', 'title' => 'globalsearch', 'class' => 'btn btn-secondary'));
index e386f20..5ad7f22 100644 (file)
@@ -33,9 +33,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_block_html_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index e5cee22..995f6d4 100644 (file)
@@ -35,6 +35,7 @@ use core_competency\url;
 use renderable;
 use renderer_base;
 use templatable;
+use required_capability_exception;
 
 /**
  * Summary renderable class.
@@ -68,7 +69,11 @@ class summary implements renderable, templatable {
         $this->user = $user;
 
         // Get the plans.
-        $this->plans = api::list_user_plans($this->user->id);
+        try {
+            $this->plans = api::list_user_plans($this->user->id);
+        } catch (required_capability_exception $e) {
+            $this->plans = [];
+        }
 
         // Get the competencies to review.
         $this->compstoreview = api::list_user_competencies_to_review(0, 3);
index 2435f54..2850637 100644 (file)
@@ -63,7 +63,7 @@ class main implements renderable, templatable {
     public function export_for_template(renderer_base $output) {
         global $USER;
 
-        $courses = enrol_get_my_courses('*', 'fullname ASC');
+        $courses = enrol_get_my_courses('*');
         $coursesprogress = [];
 
         foreach ($courses as $course) {
index 04dc110..07b4381 100644 (file)
@@ -55,9 +55,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_block_navigation_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 0bf77eb..18ee857 100644 (file)
@@ -45,9 +45,6 @@
 function xmldb_block_quiz_results_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 4a9f5fb..d9bf407 100644 (file)
@@ -47,9 +47,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_block_recent_activity_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 518fffa..d968dda 100644 (file)
@@ -33,9 +33,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_block_rss_client_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index f0d5534..0200032 100644 (file)
@@ -49,9 +49,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_block_section_links_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 1f0f0a7..7e5e56a 100644 (file)
@@ -48,9 +48,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_block_selfcompletion_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index ba37266..2a9dceb 100644 (file)
@@ -55,9 +55,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_block_settings_upgrade($oldversion, $block) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 049f13d..7592536 100644 (file)
@@ -503,7 +503,7 @@ class core_calendar_external extends external_api {
             $params['aftereventid'] = null;
         }
 
-        $courses = enrol_get_my_courses('*', 'visible DESC,sortorder ASC', 0, [$courseid]);
+        $courses = enrol_get_my_courses('*', null, 0, [$courseid]);
         $courses = array_values($courses);
 
         if (empty($courses)) {
@@ -588,7 +588,7 @@ class core_calendar_external extends external_api {
         }
 
         $renderer = $PAGE->get_renderer('core_calendar');
-        $courses = enrol_get_my_courses('*', 'visible DESC,sortorder ASC', 0, $params['courseids']);
+        $courses = enrol_get_my_courses('*', null, 0, $params['courseids']);
         $courses = array_values($courses);
 
         if (empty($courses)) {
index 45c1785..0a8408f 100644 (file)
@@ -249,10 +249,6 @@ class calendar_event {
         }
 
         $this->properties = $data;
-
-        if (empty($data->context)) {
-            $this->properties->context = $this->calculate_context();
-        }
     }
 
     /**
@@ -343,6 +339,24 @@ class calendar_event {
         return $context;
     }
 
+    /**
+     * Returns the context for this event. The context is calculated
+     * the first time is is requested and then stored in a member
+     * variable to be returned each subsequent time.
+     *
+     * This is a magical getter function that will be called when
+     * ever the context property is accessed, e.g. $event->context.
+     *
+     * @return context
+     */
+    protected function get_context() {
+        if (!isset($this->properties->context)) {
+            $this->properties->context = $this->calculate_context();
+        }
+
+        return $this->properties->context;
+    }
+
     /**
      * Returns an array of editoroptions for this event.
      *
@@ -367,7 +381,7 @@ class calendar_event {
             // Check if we have already resolved the context for this event.
             if ($this->editorcontext === null) {
                 // Switch on the event type to decide upon the appropriate context to use for this event.
-                $this->editorcontext = $this->properties->context;
+                $this->editorcontext = $this->get_context();
                 if (!calendar_is_valid_eventtype($this->properties->eventtype)) {
                     return clean_text($this->properties->description, $this->properties->format);
                 }
@@ -433,7 +447,7 @@ class calendar_event {
 
         // Prepare event data.
         $eventargs = array(
-            'context' => $this->properties->context,
+            'context' => $this->get_context(),
             'objectid' => $this->properties->id,
             'other' => array(
                 'repeatid' => empty($this->properties->repeatid) ? 0 : $this->properties->repeatid,
@@ -485,7 +499,7 @@ class calendar_event {
                 // were set when calculate_context() was called from the constructor.
                 if ($usingeditor) {
                     $this->properties->context = $this->calculate_context();
-                    $this->editorcontext = $this->properties->context;
+                    $this->editorcontext = $this->get_context();
                 }
 
                 $editor = $this->properties->description;
@@ -512,7 +526,7 @@ class calendar_event {
 
             // Log the event entry.
             $eventargs['objectid'] = $this->properties->id;
-            $eventargs['context'] = $this->properties->context;
+            $eventargs['context'] = $this->get_context();
             $event = \core\event\calendar_event_created::create($eventargs);
             $event->trigger();
 
@@ -681,7 +695,7 @@ class calendar_event {
 
         // Trigger an event for the delete action.
         $eventargs = array(
-            'context' => $this->properties->context,
+            'context' => $this->get_context(),
             'objectid' => $this->properties->id,
             'other' => array(
                 'repeatid' => empty($this->properties->repeatid) ? 0 : $this->properties->repeatid,
@@ -715,7 +729,7 @@ class calendar_event {
 
         // If the editor context hasn't already been set then set it now.
         if ($this->editorcontext === null) {
-            $this->editorcontext = $this->properties->context;
+            $this->editorcontext = $this->get_context();
         }
 
         // If the context has been set delete all associated files.
@@ -774,10 +788,10 @@ class calendar_event {
 
                 if ($properties->eventtype === 'site') {
                     // Site context.
-                    $this->editorcontext = $this->properties->context;
+                    $this->editorcontext = $this->get_context();
                 } else if ($properties->eventtype === 'user') {
                     // User context.
-                    $this->editorcontext = $this->properties->context;
+                    $this->editorcontext = $this->get_context();
                 } else if ($properties->eventtype === 'group' || $properties->eventtype === 'course') {
                     // First check the course is valid.
                     $course = $DB->get_record('course', array('id' => $properties->courseid));
@@ -785,7 +799,7 @@ class calendar_event {
                         print_error('invalidcourse');
                     }
                     // Course context.
-                    $this->editorcontext = $this->properties->context;
+                    $this->editorcontext = $this->get_context();
                     // We have a course and are within the course context so we had
                     // better use the courses max bytes value.
                     $this->editoroptions['maxbytes'] = $course->maxbytes;
@@ -793,7 +807,7 @@ class calendar_event {
                     // First check the course is valid.
                     \coursecat::get($properties->categoryid, MUST_EXIST, true);
                     // Course context.
-                    $this->editorcontext = $this->properties->context;
+                    $this->editorcontext = $this->get_context();
                     // We have a course and are within the course context so we had
                     // better use the courses max bytes value.
                     $this->editoroptions['maxbytes'] = $course->maxbytes;
@@ -869,7 +883,7 @@ class calendar_event {
 
         // Prepare event data.
         $eventargs = array(
-            'context' => $this->properties->context,
+            'context' => $this->get_context(),
             'objectid' => $this->properties->id,
             'other' => array(
                 'repeatid' => empty($this->properties->repeatid) ? 0 : $this->properties->repeatid,
@@ -939,7 +953,7 @@ class calendar_event {
 
         if ($this->editorcontext === null) {
             // Switch on the event type to decide upon the appropriate context to use for this event.
-            $this->editorcontext = $this->properties->context;
+            $this->editorcontext = $this->get_context();
 
             if (!calendar_is_valid_eventtype($this->properties->eventtype)) {
                 // We don't have a context here, do a normal format_text.
index 44d8e25..55e7529 100644 (file)
@@ -52,6 +52,16 @@ class cohort_summary_exporter extends \core\external\exporter {
                 'default' => '',
                 'null' => NULL_ALLOWED
             ),
+            'description' => array(
+                'type' => PARAM_TEXT,
+                'default' => '',
+                'null' => NULL_ALLOWED
+            ),
+            'descriptionformat' => array(
+                'type' => PARAM_INT,
+                'default' => FORMAT_HTML,
+                'null' => NULL_ALLOWED
+            ),
             'visible' => array(
                 'type' => PARAM_BOOL,
             )
index fc16c0c..9d04083 100644 (file)
@@ -165,7 +165,7 @@ class api {
         require_capability('moodle/competency:competencymanage', $competency->get_context());
 
         // Reset the sortorder, use reorder instead.
-        $competency->set('sortorder', null);
+        $competency->set('sortorder', 0);
         $competency->create();
 
         \core\event\competency_created::create_from_competency($competency)->trigger();
index c537508..9e417e9 100644 (file)
@@ -76,7 +76,7 @@ class competency extends persistent {
                 'default' => FORMAT_HTML
             ),
             'sortorder' => array(
-                'default' => null,
+                'default' => 0,
                 'type' => PARAM_INT
             ),
             'parentid' => array(
index 3e0c8f8..8c6df0b 100644 (file)
@@ -53,7 +53,7 @@ class template_competency extends persistent {
             ),
             'sortorder' => array(
                 'type' => PARAM_INT,
-                'default' => null,
+                'default' => 0,
             ),
         );
     }
index 392e1c5..ad97f6c 100644 (file)
@@ -282,7 +282,6 @@ class user_competency_course extends persistent {
               ORDER BY p.timesproficient ASC, c.id DESC';
 
         $results = $DB->get_records_sql($sql, $params, $skip, $limit);
-        $a = $DB->get_records_sql('SELECT * from {' . self::TABLE . '}');
 
         $comps = array();
         foreach ($results as $r) {
index 3880a2a..5b53589 100644 (file)
@@ -66,7 +66,7 @@ class user_competency_plan extends persistent {
             ),
             'sortorder' => array(
                 'type' => PARAM_INT,
-                'default' => null,
+                'default' => 0,
             ),
         );
     }
index f8a09e0..f0b50c8 100644 (file)
@@ -281,8 +281,7 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
             'idnumber' => 'idnumber' . $number,
             'description' => 'description' . $number,
             'descriptionformat' => FORMAT_HTML,
-            'competencyframeworkid' => $frameworkid,
-            'sortorder' => 0
+            'competencyframeworkid' => $frameworkid
         );
         $result = external::create_competency($competency);
         return (object) external_api::clean_returnvalue(external::create_competency_returns(), $result);
@@ -294,8 +293,7 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
             'shortname' => 'shortname' . $number,
             'idnumber' => 'idnumber' . $number,
             'description' => 'description' . $number,
-            'descriptionformat' => FORMAT_HTML,
-            'sortorder' => 0
+            'descriptionformat' => FORMAT_HTML
         );
         $result = external::update_competency($competency);
         return external_api::clean_returnvalue(external::update_competency_returns(), $result);
index b610108..24384e9 100644 (file)
@@ -249,7 +249,7 @@ class core_completion_external extends external_api {
 
         $completion = new completion_info($course);
         $activities = $completion->get_activities();
-        $progresses = $completion->get_progress_all();
+        $progresses = $completion->get_progress_all('u.id = :uid', ['uid' => $params['userid']]);
         $userprogress = $progresses[$user->id];
 
         $results = array();
index 29c570b..592c84e 100644 (file)
@@ -279,7 +279,8 @@ class completion_criteria_activity extends completion_criteria {
             $details['requirement'][] = get_string('markingyourselfcomplete', 'completion');
         } elseif ($cm->completion == COMPLETION_TRACKING_AUTOMATIC) {
             if ($cm->completionview) {
-                $details['requirement'][] = get_string('viewingactivity', 'completion', $this->module);
+                $modulename = core_text::strtolower(get_string('modulename', $this->module));
+                $details['requirement'][] = get_string('viewingactivity', 'completion', $modulename);
             }
 
             if (!is_null($cm->completiongradeitemnumber)) {
index 4c03e2d..47c8c18 100644 (file)
@@ -88,7 +88,7 @@ class course_edit_form extends moodleform {
             }
         } else {
             if (has_capability('moodle/course:changecategory', $coursecontext)) {
-                $displaylist = coursecat::make_categories_list('moodle/course:create');
+                $displaylist = coursecat::make_categories_list('moodle/course:changecategory');
                 if (!isset($displaylist[$course->category])) {
                     //always keep current
                     $displaylist[$course->category] = coursecat::get($course->category, MUST_EXIST, true)->get_formatted_name();
index 64b2575..d759837 100644 (file)
@@ -1988,13 +1988,7 @@ class core_course_renderer extends plugin_renderer_base {
         }
 
         $output = '';
-        if (!empty($CFG->navsortmycoursessort)) {
-            // sort courses the same as in navigation menu
-            $sortorder = 'visible DESC,'. $CFG->navsortmycoursessort.' ASC';
-        } else {
-            $sortorder = 'visible DESC,sortorder ASC';
-        }
-        $courses  = enrol_get_my_courses('summary, summaryformat', $sortorder);
+        $courses  = enrol_get_my_courses('summary, summaryformat');
         $rhosts   = array();
         $rcourses = array();
         if (!empty($CFG->mnet_dispatcher_mode) && $CFG->mnet_dispatcher_mode==='strict') {
index c38575a..351cf66 100644 (file)
@@ -27,9 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_enrol_database_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 91ea55b..59ae42e 100644 (file)
@@ -27,9 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_enrol_flatfile_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 51a3a0b..cb6fb76 100644 (file)
@@ -27,9 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_enrol_guest_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 53366c6..a4e1df7 100644 (file)
@@ -33,9 +33,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_enrol_imsenterprise_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index e3ed112..dd8d9a8 100644 (file)
@@ -206,7 +206,7 @@ class enrol_imsenterprise_testcase extends advanced_testcase {
         $this->set_xml_file(array($imsuser));
 
         $this->imsplugin->cron();
-        $this->assertEquals(1, $DB->get_field('user', 'deleted', array('id' => $user->id), '*', MUST_EXIST));
+        $this->assertEquals(1, $DB->get_field('user', 'deleted', array('id' => $user->id), MUST_EXIST));
     }
 
     /**
@@ -227,7 +227,7 @@ class enrol_imsenterprise_testcase extends advanced_testcase {
         $this->set_xml_file(array($imsuser));
 
         $this->imsplugin->cron();
-        $this->assertEquals(0, $DB->get_field('user', 'deleted', array('id' => $user->id), '*', MUST_EXIST));
+        $this->assertEquals(0, $DB->get_field('user', 'deleted', array('id' => $user->id), MUST_EXIST));
     }
 
     /**
index 0086edf..cec4ea4 100644 (file)
@@ -27,9 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_enrol_manual_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 29f8564..6f22cca 100644 (file)
@@ -27,9 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_enrol_mnet_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 5ed2ae7..bdbbbf6 100644 (file)
@@ -45,9 +45,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_enrol_paypal_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index f9dff59..4965298 100644 (file)
@@ -27,9 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_enrol_self_upgrade($oldversion) {
     global $CFG, $DB;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     if ($oldversion < 2016052301) {
         // Get roles with manager archetype.
         $managerroles = get_archetype_roles('manager');
index d52dc6f..1678462 100644 (file)
@@ -55,10 +55,24 @@ class core_enrollib_testcase extends advanced_testcase {
 
         $category1 = $this->getDataGenerator()->create_category(array('visible'=>0));
         $category2 = $this->getDataGenerator()->create_category();
-        $course1 = $this->getDataGenerator()->create_course(array('category'=>$category1->id));
-        $course2 = $this->getDataGenerator()->create_course(array('category'=>$category2->id));
-        $course3 = $this->getDataGenerator()->create_course(array('category'=>$category2->id, 'visible'=>0));
-        $course4 = $this->getDataGenerator()->create_course(array('category'=>$category2->id));
+
+        $course1 = $this->getDataGenerator()->create_course(array(
+            'shortname' => 'Z',
+            'category' => $category1->id,
+        ));
+        $course2 = $this->getDataGenerator()->create_course(array(
+            'shortname' => 'X',
+            'category' => $category2->id,
+        ));
+        $course3 = $this->getDataGenerator()->create_course(array(
+            'shortname' => 'Y',
+            'category' => $category2->id,
+            'visible' => 0,
+        ));
+        $course4 = $this->getDataGenerator()->create_course(array(
+            'shortname' => 'W',
+            'category' => $category2->id,
+        ));
 
         $maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
         $DB->set_field('enrol', 'status', ENROL_INSTANCE_DISABLED, array('id'=>$maninstance1->id));
@@ -150,6 +164,18 @@ class core_enrollib_testcase extends advanced_testcase {
 
         $courses = enrol_get_all_users_courses($user2->id, false, null, 'id DESC');
         $this->assertEquals(array($course3->id, $course2->id, $course1->id), array_keys($courses));
+
+        // Make sure that implicit sorting defined in navsortmycoursessort is respected.
+
+        $CFG->navsortmycoursessort = 'shortname';
+
+        $courses = enrol_get_all_users_courses($user1->id);
+        $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
+
+        // But still the explicit sorting takes precedence over the implicit one.
+
+        $courses = enrol_get_all_users_courses($user1->id, false, null, 'shortname DESC');
+        $this->assertEquals(array($course1->id, $course3->id, $course2->id), array_keys($courses));
     }
 
     public function test_enrol_user_sees_own_courses() {
@@ -590,15 +616,15 @@ class core_enrollib_testcase extends advanced_testcase {
         // Create test user and 4 courses, two of which have guest access enabled.
         $user = $this->getDataGenerator()->create_user();
         $course1 = $this->getDataGenerator()->create_course(
-                (object)array('shortname' => 'Z',
+                (object)array('shortname' => 'X',
                 'enrol_guest_status_0' => ENROL_INSTANCE_DISABLED,
                 'enrol_guest_password_0' => ''));
         $course2 = $this->getDataGenerator()->create_course(
-                (object)array('shortname' => 'Y',
+                (object)array('shortname' => 'Z',
                 'enrol_guest_status_0' => ENROL_INSTANCE_ENABLED,
                 'enrol_guest_password_0' => ''));
         $course3 = $this->getDataGenerator()->create_course(
-                (object)array('shortname' => 'X',
+                (object)array('shortname' => 'Y',
                 'enrol_guest_status_0' => ENROL_INSTANCE_ENABLED,
                 'enrol_guest_password_0' => 'frog'));
         $course4 = $this->getDataGenerator()->create_course(
@@ -645,10 +671,19 @@ class core_enrollib_testcase extends advanced_testcase {
         $this->assertObjectHasAttribute('summary', $courses[$course3->id]);
         $this->assertObjectHasAttribute('summaryformat', $courses[$course3->id]);
 
-        // Check sort parameter still works.
-        $courses = enrol_get_my_courses(null, 'shortname', 0, [], true);
+        // By default, courses are ordered by sortorder - which by default is most recent first.
+        $courses = enrol_get_my_courses(null, null, 0, [], true);
         $this->assertEquals([$course3->id, $course2->id, $course1->id], array_keys($courses));
 
+        // Make sure that implicit sorting defined in navsortmycoursessort is respected.
+        $CFG->navsortmycoursessort = 'shortname';
+        $courses = enrol_get_my_courses(null, null, 0, [], true);
+        $this->assertEquals([$course1->id, $course3->id, $course2->id], array_keys($courses));
+
+        // But still the explicit sorting takes precedence over the implicit one.
+        $courses = enrol_get_my_courses(null, 'shortname DESC', 0, [], true);
+        $this->assertEquals([$course2->id, $course3->id, $course1->id], array_keys($courses));
+
         // Check filter parameter still works.
         $courses = enrol_get_my_courses(null, 'id', 0, [$course2->id, $course3->id, $course4->id], true);
         $this->assertEquals([$course2->id, $course3->id], array_keys($courses));
index 528fe37..09ff3ba 100644 (file)
@@ -1,6 +1,11 @@
 This files describes API changes in /enrol/* - plugins,
 information provided here is intended especially for developers.
 
+=== 3.5 ===
+
+* Default sorting in enrol_get_my_courses(), enrol_get_all_users_courses() and enrol_get_users_courses() now respects
+  the site setting "navsortmycoursessort" and should be consistently used when displaying the courses in the UI.
+
 === 3.4 ===
 
 * render_course_enrolment_users_table method has been removed from the renderer. The enrolled users page is now
index 32793d3..da8c5ba 100644 (file)
@@ -127,7 +127,7 @@ class converter {
         if ($status === conversion::STATUS_PENDING || $status === conversion::STATUS_FAILED) {
             // The current status is either pending or failed.
             // Attempt to pick up a new converter and convert the document.
-            $from = \core_filetypes::get_file_extension($file->get_mimetype());
+            $from = pathinfo($file->get_filename(), PATHINFO_EXTENSION);
             $converters = $this->get_document_converter_classes($from, $format);
             $currentconverter = $this->get_next_converter($converters, $conversion->get('converter'));
 
@@ -225,9 +225,9 @@ class converter {
             return false;
         }
 
-        $from = \core_filetypes::get_file_extension($file->get_mimetype());
+        $from = pathinfo($file->get_filename(), PATHINFO_EXTENSION);
         if (!$from) {
-            // No mime type could be found. Unable to determine converter.
+            // No file extension could be found. Unable to determine converter.
             return false;
         }
 
index 950d593..e345c1e 100644 (file)
@@ -341,7 +341,7 @@ class core_files_converter_testcase extends advanced_testcase {
     }
 
     /**
-     * Test the can_convert_storedfile_to function with a file with indistinguished mimetype.
+     * Test the can_convert_storedfile_to function with a file with a known mimetype and extension.
      */
     public function test_can_convert_storedfile_to_docx() {
         $returnvalue = (object) [];
@@ -352,8 +352,7 @@ class core_files_converter_testcase extends advanced_testcase {
 
         $types = \core_filetypes::get_types();
 
-        // A file with filename '.' is a directory.
-        $file = $this->get_stored_file('example content', 'example', [
+        $file = $this->get_stored_file('example content', 'example.docx', [
                 'mimetype' => $types['docx']['type'],
             ]);
 
index 7edde8a..5294046 100644 (file)
@@ -33,26 +33,6 @@ function xmldb_filter_mathjaxloader_upgrade($oldversion) {
 
     require_once($CFG->dirroot . '/filter/mathjaxloader/db/upgradelib.php');
 
-    if ($oldversion < 2016032200) {
-
-        $httpurl = get_config('filter_mathjaxloader', 'httpurl');
-        // Don't change the config if it has been manually changed to something besides the default setting value.
-        if ($httpurl === "http://cdn.mathjax.org/mathjax/2.5-latest/MathJax.js") {
-            set_config('httpurl', 'http://cdn.mathjax.org/mathjax/2.6-latest/MathJax.js', 'filter_mathjaxloader');
-        }
-
-        $httpsurl = get_config('filter_mathjaxloader', 'httpsurl');
-        // Don't change the config if it has been manually changed to something besides the default setting value.
-        if ($httpsurl === "https://cdn.mathjax.org/mathjax/2.5-latest/MathJax.js") {
-            set_config('httpsurl', 'https://cdn.mathjax.org/mathjax/2.6-latest/MathJax.js', 'filter_mathjaxloader');
-        }
-
-        upgrade_plugin_savepoint(true, 2016032200, 'filter', 'mathjaxloader');
-    }
-
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     if ($oldversion < 2016080200) {
         // We are consolodating the two settings for http and https url into only the https
         // setting. Since it is preferably to always load the secure resource.
@@ -78,8 +58,10 @@ function xmldb_filter_mathjaxloader_upgrade($oldversion) {
         }
         upgrade_plugin_savepoint(true, 2016102500, 'filter', 'mathjaxloader');
     }
+
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
+    //
     if ($oldversion < 2017040300) {
 
         $httpsurl = get_config('filter_mathjaxloader', 'httpsurl');
@@ -97,6 +79,7 @@ function xmldb_filter_mathjaxloader_upgrade($oldversion) {
 
         upgrade_plugin_savepoint(true, 2017040300, 'filter', 'mathjaxloader');
     }
+
     if ($oldversion < 2017042602) {
 
         $httpsurl = get_config('filter_mathjaxloader', 'httpsurl');
index 8b58139..c89fab9 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_filter_mediaplugin_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 459183d..53cc010 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_filter_tex_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 68f39ad..5677911 100644 (file)
@@ -37,18 +37,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_gradingform_guide_upgrade($oldversion) {
     global $DB;
 
-    if ($oldversion < 2016051100) {
-        // Clean up empty string or null marking guide comments.
-        $sql = $DB->sql_isempty('gradingform_guide_comments', 'description', true, true);
-        $sql .= " OR description IS NULL ";
-        $DB->delete_records_select('gradingform_guide_comments', $sql);
-        // Main savepoint reached.
-        upgrade_plugin_savepoint(true, 2016051100, 'gradingform', 'guide');
-    }
-
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index bab220d..92e65e3 100644 (file)
@@ -33,9 +33,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_gradingform_rubric_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 3e662ba..ea9d000 100644 (file)
@@ -29,9 +29,6 @@
 function xmldb_gradereport_user_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index cb96fa0..b24608d 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Unit tests for grade/edit/tree/lib.php.
  *
- * @pacakge  core_grade
+ * @package  core_grades
  * @category phpunit
  * @author   Andrew Davis
  * @license  http://www.gnu.org/copyleft/gpl.html GNU Public License
index 0acea9e..234e6a4 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Unit tests for grade/import/lib.php.
  *
- * @package   core_grade
+ * @package   core_grades
  * @category  phpunit
  * @copyright 2015 Adrian Greeve <adrian@moodle.com>
  * @license   http://www.gnu.org/copyleft/gpl.html GNU Public License
index c284123..28e6cde 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Unit tests for grade quering
  *
- * @pacakge   core_grade
+ * @package   core_grades
  * @category  phpunit
  * @copyright 2011 Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU Public License
index d65e285..75f52c3 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Unit tests for grade/report/user/lib.php.
  *
- * @package  core_grade
+ * @package  core_grades
  * @category phpunit
  * @copyright 2012 Andrew Davis
  * @license  http://www.gnu.org/copyleft/gpl.html GNU Public License
index bade609..d8928e5 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Unit tests for grade/report/lib.php.
  *
- * @pacakge  core_grade
+ * @package  core_grades
  * @category phpunit
  * @author   Andrew Davis
  * @license  http://www.gnu.org/copyleft/gpl.html GNU Public License
index 7bc3289..94ae292 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Unit tests for grade/report/user/lib.php.
  *
- * @package  core_grade
+ * @package  core_grades
  * @category phpunit
  * @copyright 2012 Andrew Davis
  * @license  http://www.gnu.org/copyleft/gpl.html GNU Public License
index e751fee..a25438e 100644 (file)
@@ -41,3 +41,4 @@ Mesedez, erabili --laguntza aukera.';
 $string['cliyesnoprompt'] = 'idatzi b (bai esateko) edo e (ez esateko)';
 $string['environmentrequireinstall'] = 'derrigorrezkoa da instalatuta eta gaituta izatea';
 $string['environmentrequireversion'] = '{$a->needed} bertsioa beharrezkoa da eta zu {$a->current} ari zara egikaritzen';
+$string['upgradekeyset'] = 'Eguneraketa-kodea (utzi hutsik kodea erabili nahi ez baduzu)';
diff --git a/install/lang/ig/langconfig.php b/install/lang/ig/langconfig.php
new file mode 100644 (file)
index 0000000..41f3b6c
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'Igbo';
diff --git a/install/lang/pcm/langconfig.php b/install/lang/pcm/langconfig.php
new file mode 100644 (file)
index 0000000..5eb603a
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'Pidgin';
index 2dbef7e..d2493b1 100644 (file)
@@ -65,6 +65,7 @@ $string['auth_user_create'] = 'Enable user creation';
 $string['auth_user_creation'] = 'New (anonymous) users can create user accounts on the external authentication source and confirmed via email. If you enable this , remember to also configure module-specific options for user creation.';
 $string['auth_usernameexists'] = 'Selected username already exists. Please choose a new one.';
 $string['auto_add_remote_users'] = 'Auto add remote users';
+$string['cannotmapfield'] = 'Field "{$a->fieldname}" can not be mapped because its short name "{$a->shortname}" is too long. To enable mapping reduce the profile field short name down to {$a->charlimit} characters. <a href="{$a->link}">Edit user profile fields</a>';
 $string['createpassword'] = 'Generate password and notify user';
 $string['createpasswordifneeded'] = 'Create password if needed and send via email';
 $string['emailchangecancel'] = 'Cancel email change';
index 59833af..2364312 100644 (file)
@@ -27,6 +27,8 @@
 $string['actions'] = 'Actions';
 $string['activate'] = 'Enable access';
 $string['activatesuccess'] = 'Access to the badges was successfully enabled.';
+$string['addbadge'] = 'Add a badge as criteria';
+$string['addbadge_help'] = 'Select all badges that should be added to this badge requirement. Hold CTRL key to select multiple items.';
 $string['addbadgecriteria'] = 'Add badge criteria';
 $string['addcriteria'] = 'Add criteria';
 $string['addcriteriatext'] = 'To start adding criteria, please select one of the options from the drop-down menu.';
@@ -39,6 +41,7 @@ $string['aggregationmethod'] = 'Aggregation method';
 $string['all'] = 'All';
 $string['allmethod'] = 'All of the selected conditions are met';
 $string['allmethodactivity'] = 'All of the selected activities are complete';
+$string['allmethodbadges'] = 'All of the selected badges have been earned';
 $string['allmethodcourseset'] = 'All of the selected courses are complete';
 $string['allmethodmanual'] = 'All of the selected roles award the badge';
 $string['allmethodprofile'] = 'All of the selected profile fields have been completed';
@@ -51,6 +54,7 @@ Note: It is recommended to leave this option disabled if the website cannot be a
 $string['any'] = 'Any';
 $string['anymethod'] = 'Any of the selected conditions is met';
 $string['anymethodactivity'] = 'Any of the selected activities is complete';
+$string['anymethodbadges'] = 'Any of the selected badges have been earned';
 $string['anymethodcourseset'] = 'Any of the selected courses is complete';
 $string['anymethodmanual'] = 'Any of the selected roles awards the badge';
 $string['anymethodprofile'] = 'Any of the selected profile fields has been completed';
@@ -176,22 +180,26 @@ $string['criteria_descr_short2'] = 'Awarded by <strong>{$a}</strong> of: ';
 $string['criteria_descr_short4'] = 'Complete the course ';
 $string['criteria_descr_short5'] = 'Complete <strong>{$a}</strong> of: ';
 $string['criteria_descr_short6'] = 'Complete <strong>{$a}</strong> of: ';
+$string['criteria_descr_short7'] = 'Complete <strong>{$a}</strong> of: ';
 $string['criteria_descr_single_short1'] = 'Complete: ';
 $string['criteria_descr_single_short2'] = 'Awarded by: ';
 $string['criteria_descr_single_short4'] = 'Complete the course ';
 $string['criteria_descr_single_short5'] = 'Complete: ';
 $string['criteria_descr_single_short6'] = 'Complete: ';
+$string['criteria_descr_single_short7'] = 'Complete: ';
 $string['criteria_descr_single_1'] = 'The following activity has to be completed:';
 $string['criteria_descr_single_2'] = 'This badge has to be awarded by a user with the following role:';
 $string['criteria_descr_single_4'] = 'Users must complete the course';
 $string['criteria_descr_single_5'] = 'The following course has to be completed:';
 $string['criteria_descr_single_6'] = 'The following user profile field has to be completed:';
+$string['criteria_descr_single_7'] = 'The following badge has to be earned:';
 $string['criteria_descr_0'] = 'Users are awarded this badge when they complete <strong>{$a}</strong> of the listed requirements.';
 $string['criteria_descr_1'] = '<strong>{$a}</strong> of the following activities are completed:';
 $string['criteria_descr_2'] = 'This badge has to be awarded by the users with <strong>{$a}</strong> of the following roles:';
 $string['criteria_descr_4'] = 'Users must complete the course';
 $string['criteria_descr_5'] = '<strong>{$a}</strong> of the following courses have to be completed:';
 $string['criteria_descr_6'] = '<strong>{$a}</strong> of the following user profile fields have to be completed:';
+$string['criteria_descr_7'] = '<strong>{$a}</strong> of the following badges have to be earned:';
 $string['criteria_0'] = 'This badge is awarded when...';
 $string['criteria_1'] = 'Activity completion';
 $string['criteria_1_help'] = 'Allows a badge to be awarded to users based on the completion of a set of activities within a course.';
@@ -205,6 +213,8 @@ $string['criteria_5'] = 'Completing a set of courses';
 $string['criteria_5_help'] = 'Allows a badge to be awarded to users who have completed a set of courses. Each course can have additional parameters such as minimum grade and date of course completion. ';
 $string['criteria_6'] = 'Profile completion';
 $string['criteria_6_help'] = 'Allows a badge to be awarded to users for completing certain fields in their profile. You can select from default and custom profile fields that are available to users. ';
+$string['criteria_7'] = 'Awarded badges';
+$string['criteria_7_help'] = 'Allows a badge to be awarded to users based on the other badges thay have earned.';
 $string['criterror'] = 'Current parameters issues';
 $string['criterror_help'] = 'This fieldset shows all parameters that were initially added to this badge requirement but are no longer available. It is recommended that you un-check such parameters to make sure that users can earn this badge in the future.';
 $string['currentimage'] = 'Current image';
@@ -248,7 +258,9 @@ $string['error:invalidbadgeurl'] = 'Invalid badge issuer URL format.';
 $string['error:invalidcriteriatype'] = 'Invalid criteria type.';
 $string['error:invalidexpiredate'] = 'Expiry date has to be in the future.';
 $string['error:invalidexpireperiod'] = 'Expiry period cannot be negative or equal 0.';
+$string['error:invalidparambadge'] = 'Badge does not exist. ';
 $string['error:noactivities'] = 'There are no activities with completion criteria enabled in this course.';
+$string['error:nobadges'] = 'There are no course or site badges available to be added as criteria.  Make sure that your other badges are enabled ';
 $string['error:nocourses'] = 'Course completion is not enabled for any of the courses in this site, so none can be displayed. Course completion may be enabled in the course settings.';
 $string['error:nogroups'] = '<p>There are no public collections of badges available in your backpack. </p>
 <p>Only public collections are shown, <a href="http://backpack.openbadges.org">visit your backpack</a> to create some public collections.</p>';
@@ -369,6 +381,7 @@ $string['recipientvalidationproblem'] = 'Current user cannot be verified as a re
 $string['relative'] = 'Relative date';
 $string['revoke'] = 'Revoke badge';
 $string['requiredcourse'] = 'At least one course should be added to the courseset criterion.';
+$string['requiredbadge'] = 'At least one badge should be added to the badge criterion.';
 $string['reviewbadge'] = 'Changes in badge access';
 $string['reviewconfirm'] = '<p>This will make your badge visible to users and allow them to start earning it.</p>
 
index 288c4b6..743a749 100644 (file)
@@ -41,6 +41,7 @@ $string['err_nopunctuation'] = 'You must enter no punctuation characters here.';
 $string['err_numeric'] = 'You must enter a number here.';
 $string['err_rangelength'] = 'You must enter between {$a->format[0]} and {$a->format[1]} characters here.';
 $string['err_required'] = 'You must supply a value here.';
+$string['err_wrappingwhitespace'] = 'The value must not start or end with whitespace.';
 $string['err_wrongfileextension'] = 'Some files ({$a->wrongfiles}) cannot be uploaded. Only file types {$a->whitelist} are allowed.';
 $string['filesofthesetypes'] = 'Accepted file types:';
 $string['filetypesany'] = 'All file types';
index 096722d..552d9b6 100644 (file)
@@ -53,6 +53,7 @@ $string['engineserverstatus'] = 'The search engine is not available. Please cont
 $string['enteryoursearchquery'] = 'Enter your search query';
 $string['errors'] = 'Errors';
 $string['errorareanotavailable'] = '{$a} search area is not available.';
+$string['everywhere'] = 'Everywhere you can access';
 $string['filesinindexdirectory'] = 'Files in index directory';
 $string['filterheader'] = 'Filter';
 $string['fromtime'] = 'Modified after';
@@ -89,6 +90,7 @@ $string['searcharea'] = 'Search area';
 $string['searching'] = 'Searching in ...';
 $string['searchnotpermitted'] = 'You are not allowed to do a search';
 $string['searchsetupdescription'] = 'The following steps help you to set up Moodle global search.';
+$string['searchwithin'] = 'Search within';
 $string['seconds'] = 'seconds';
 $string['solutions'] = 'Solutions';
 $string['statistics'] = 'Statistics';
index bd400e4..856a809 100644 (file)
@@ -319,8 +319,7 @@ function get_role_definitions_uncached(array $roleids) {
     $sql = "SELECT ctx.path, rc.roleid, rc.capability, rc.permission
               FROM {role_capabilities} rc
               JOIN {context} ctx ON rc.contextid = ctx.id
-             WHERE rc.roleid $sql
-          ORDER BY ctx.path, rc.roleid, rc.capability";
+             WHERE rc.roleid $sql";
     $rs = $DB->get_recordset_sql($sql, $params);
 
     foreach ($rs as $rd) {
@@ -334,6 +333,15 @@ function get_role_definitions_uncached(array $roleids) {
     }
 
     $rs->close();
+
+    // Sometimes (e.g. get_user_capability_course_helper::get_capability_info_at_each_context)
+    // we process role definitinons in a way that requires we see parent contexts
+    // before child contexts. This sort ensures that works (and is faster than
+    // sorting in the SQL query).
+    foreach ($rdefs as $roleid => $rdef) {
+        ksort($rdefs[$roleid]);
+    }
+
     return $rdefs;
 }
 
index c35f1ca..e1b678b 100644 (file)
@@ -31,8 +31,6 @@ defined('MOODLE_INTERNAL') || die();
  * @return bool
  */
 function xmldb_antivirus_clamav_upgrade($oldversion) {
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
 
     if ($oldversion < 2016101700) {
         // Remove setting that has been deprecated long time ago at MDL-44260.
index ae72619..e1735fd 100644 (file)
@@ -1016,16 +1016,22 @@ function display_auth_lock_options($settings, $auth, $userfields, $helptext, $ma
     }
 
     foreach ($userfields as $field) {
-
         // Define the fieldname we display to the  user.
         // this includes special handling for some profile fields.
         $fieldname = $field;
+        $fieldnametoolong = false;
         if ($fieldname === 'lang') {
             $fieldname = get_string('language');
         } else if (!empty($customfields) && in_array($field, $customfields)) {
             // If custom field then pick name from database.
             $fieldshortname = str_replace('profile_field_', '', $fieldname);
             $fieldname = $customfieldname[$fieldshortname]->name;
+            if (core_text::strlen($fieldshortname) > 67) {
+                // If custom profile field name is longer than 67 characters we will not be able to store the setting
+                // such as 'field_updateremote_profile_field_NOTSOSHORTSHORTNAME' in the database because the character
+                // limit for the setting name is 100.
+                $fieldnametoolong = true;
+            }
         } else if ($fieldname == 'url') {
             $fieldname = get_string('webpage');
         } else {
@@ -1033,11 +1039,17 @@ function display_auth_lock_options($settings, $auth, $userfields, $helptext, $ma
         }
 
         // Generate the list of fields / mappings.
-        if ($mapremotefields) {
+        if ($fieldnametoolong) {
+            // Display a message that the field can not be mapped because it's too long.
+            $url = new moodle_url('/user/profile/index.php');
+            $a = (object)['fieldname' => s($fieldname), 'shortname' => s($field), 'charlimit' => 67, 'link' => $url->out()];
+            $settings->add(new admin_setting_heading($auth.'/field_not_mapped_'.sha1($field), '',
+                get_string('cannotmapfield', 'auth', $a)));
+        } else if ($mapremotefields) {
             // We are mapping to a remote field here.
             // Mapping.
             $settings->add(new admin_setting_configtext("auth_{$auth}/field_map_{$field}",
-                    get_string('auth_fieldmapping', 'auth', $fieldname), '', '', PARAM_ALPHANUMEXT, 30));
+                    get_string('auth_fieldmapping', 'auth', $fieldname), '', '', PARAM_RAW, 30));
 
             // Update local.
             $settings->add(new admin_setting_configselect("auth_{$auth}/field_updatelocal_{$field}",
index b1adc3f..c9ac3ff 100644 (file)
@@ -191,6 +191,7 @@ class badge {
                     BADGE_CRITERIA_TYPE_OVERALL,
                     BADGE_CRITERIA_TYPE_MANUAL,
                     BADGE_CRITERIA_TYPE_COURSE,
+                    BADGE_CRITERIA_TYPE_BADGE,
                     BADGE_CRITERIA_TYPE_ACTIVITY
             );
         } else if ($this->type == BADGE_TYPE_SITE) {
@@ -198,6 +199,7 @@ class badge {
                     BADGE_CRITERIA_TYPE_OVERALL,
                     BADGE_CRITERIA_TYPE_MANUAL,
                     BADGE_CRITERIA_TYPE_COURSESET,
+                    BADGE_CRITERIA_TYPE_BADGE,
                     BADGE_CRITERIA_TYPE_PROFILE,
             );
         }
index 80b5b45..93dccfa 100644 (file)
@@ -39,7 +39,10 @@ class get_user_capability_course_helper {
      * an array of capability values at each relevant context for the given user and capability.
      *
      * This is organised by the effective context path (the one at which the capability takes
-     * effect) and then by role id.
+     * effect) and then by role id. Note, however, that the resulting array only has
+     * the information that will be needed later. If there are Prohibits present in some
+     * roles, then they cannot be overridden by other roles or role overrides in lower contexts,
+     * therefore, such information, if any, is absent from the results.
      *
      * @param int $userid User id
      * @param string $capability Capability e.g. 'moodle/course:view'
@@ -58,42 +61,101 @@ class get_user_capability_course_helper {
         }
         $rdefs = get_role_definitions(array_keys($roleids));
 
+        // A prohibit in any relevant role prevents the capability
+        // in that context and all subcontexts. We need to track that.
+        // Here, the array keys are the paths where there is a prohibit the values are the role id.
+        $prohibitpaths = [];
+
         // Get data for required capability at each context path where the user has a role that can
         // affect it.
-        $systemcontext = \context_system::instance();
         $pathroleperms = [];
-        foreach ($accessdata['ra'] as $userpath => $roles) {
+        foreach ($accessdata['ra'] as $rapath => $roles) {
+
             foreach ($roles as $roleid) {
                 // Get role definition for that role.
-                foreach ($rdefs[$roleid] as $rolepath => $caps) {
+                foreach ($rdefs[$roleid] as $rdefpath => $caps) {
                     // Ignore if this override/definition doesn't refer to the relevant cap.
                     if (!array_key_exists($capability, $caps)) {
                         continue;
                     }
 
-                    // Check path is /1 or matches a path the user has.
-                    if ($rolepath === '/' . $systemcontext->id) {
-                        // Note /1 is listed first in the array so this entry will be overridden
-                        // if there is an override for the role on this actual level.
-                        $effectivepath = $userpath;
-                    } else if (preg_match('~^' . $userpath . '($|/)~', $rolepath)) {
-                        $effectivepath = $rolepath;
+                    // Check a role definition or override above ra.
+                    if (self::path_is_above($rdefpath, $rapath)) {
+                        // Note that $rdefs is sorted by path, so if a more specific override
+                        // exists, it will be processed later and override this one.
+                        $effectivepath = $rapath;
+                    } else if (self::path_is_above($rapath, $rdefpath)) {
+                        $effectivepath = $rdefpath;
                     } else {
                         // Not inside an area where the user has the role, so ignore.
                         continue;
                     }
 
+                    // Check for already seen prohibits in higher context. Overrides can't change that.
+                    if (self::any_path_is_above($prohibitpaths, $effectivepath)) {
+                        continue;
+                    }
+
+                    // This is a releavant role assignment / permission combination. Save it.
                     if (!array_key_exists($effectivepath, $pathroleperms)) {
                         $pathroleperms[$effectivepath] = [];
                     }
                     $pathroleperms[$effectivepath][$roleid] = $caps[$capability];
+
+                    // Update $prohibitpaths if necessary.
+                    if ($caps[$capability] == CAP_PROHIBIT) {
+                        // First remove any lower-context prohibits that might have come from other roles.
+                        foreach ($prohibitpaths as $otherprohibitpath => $notused) {
+                            if (self::path_is_above($effectivepath, $otherprohibitpath)) {
+                                unset($prohibitpaths[$otherprohibitpath]);
+                            }
+                        }
+                        $prohibitpaths[$effectivepath] = $roleid;
+                    }
                 }
             }
         }
 
+        // Finally, if a later role had a higher-level prohibit that an earlier role,
+        // there may be more bits we can prune - but don't prune the prohibits!
+        foreach ($pathroleperms as $effectivepath => $roleperms) {
+            if ($roleid = self::any_path_is_above($prohibitpaths, $effectivepath)) {
+                unset($pathroleperms[$effectivepath]);
+                $pathroleperms[$effectivepath][$roleid] = CAP_PROHIBIT;
+            }
+        }
+
         return $pathroleperms;
     }
 
+    /**
+     * Test if a context path $otherpath is the same as, or underneath, $parentpath.
+     *
+     * @param string $parentpath the path of the parent context.
+     * @param string $otherpath the path of another context.
+     * @return bool true if $otherpath is underneath (or equal to) $parentpath.
+     */
+    protected static function path_is_above($parentpath, $otherpath) {
+        return preg_match('~^' . $parentpath . '($|/)~', $otherpath);
+    }
+
+    /**
+     * Test if a context path $otherpath is the same as, or underneath, any of $prohibitpaths.
+     *
+     * @param array $prohibitpaths array keys are context paths.
+     * @param string $otherpath the path of another context.
+     * @return int releavant $roleid if $otherpath is underneath (or equal to)
+     *      any of the $prohibitpaths, 0 otherwise (so, can be used as a bool).
+     */
+    protected static function any_path_is_above($prohibitpaths, $otherpath) {
+        foreach ($prohibitpaths as $prohibitpath => $roleid) {
+            if (self::path_is_above($prohibitpath, $otherpath)) {
+                return $roleid;
+            }
+        }
+        return 0;
+    }
+
     /**
      * Calculates a permission tree based on an array of information about role permissions.
      *
index fe6e112..2c66b58 100644 (file)
@@ -67,36 +67,7 @@ class api {
             registration::require_registration();
         }
 
-        if (extension_loaded('xmlrpc')) {
-            // Use XMLRPC protocol.
-            return self::call_xmlrpc($token, $function, $data);
-        } else {
-            // Use REST.
-            return self::call_rest($token, $function, $data);
-        }
-    }
-
-    /**
-     * Performs REST request to moodle.net (using GET method)
-     *
-     * @param string $token
-     * @param string $function
-     * @param array $data
-     * @return mixed
-     * @throws moodle_exception
-     */
-    protected static function call_xmlrpc($token, $function, array $data) {
-        global $CFG;
-        require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
-
-        $serverurl = HUB_MOODLEORGHUBURL . "/local/hub/webservice/webservices.php";
-        $xmlrpcclient = new webservice_xmlrpc_client($serverurl, $token);
-        try {
-            return $xmlrpcclient->call($function, $data);
-        } catch (\Exception $e) {
-            // Function webservice_xmlrpc_client::call() can throw Exception, wrap it into moodle_exception.
-            throw new moodle_exception('errorws', 'hub', '', $e->getMessage());
-        }
+        return self::call_rest($token, $function, $data);
     }
 
     /**
index 7dc8be6..187ab85 100644 (file)
@@ -158,8 +158,8 @@ class registration {
         $cleanhuburl = clean_param(HUB_MOODLEORGHUBURL, PARAM_ALPHANUMEXT);
         foreach (self::FORM_FIELDS as $field) {
             $siteinfo[$field] = get_config('hub', 'site_'.$field.'_' . $cleanhuburl);
-            if ($siteinfo[$field] === false && array_key_exists($field, $defaults)) {
-                $siteinfo[$field] = $defaults[$field];
+            if ($siteinfo[$field] === false) {
+                $siteinfo[$field] = array_key_exists($field, $defaults) ? $defaults[$field] : null;
             }
         }
 
index 77137af..8c01012 100644 (file)
@@ -31,6 +31,30 @@ defined('MOODLE_INTERNAL') || die();
 class gradingform extends base {
 
     public function is_uninstall_allowed() {
-        return false;
+        return true;
+    }
+
+    /**
+     * Pre-uninstall hook.
+     * This is intended for disabling of plugin, some DB table purging, etc.
+     */
+    public function uninstall_cleanup() {
+        global $DB;
+
+        // Find all definitions and templates.
+        $definitions = $DB->get_fieldset_select('grading_definitions', 'id', 'method = ?', [$this->name]);
+        if ($definitions) {
+            // Delete instances and definitions. Deleting instance will not delete grades because they were
+            // already pushed to the module and gradebook.
+            list($sqld, $paramsd) = $DB->get_in_or_equal($definitions);
+            $DB->delete_records_select('grading_instances', 'definitionid ' . $sqld, $paramsd);
+            $DB->delete_records_select('grading_definitions', 'id ' . $sqld, $paramsd);
+        }
+        // Delete templates for this grading method.
+        $DB->delete_records_select('grading_areas', 'component = ? AND activemethod = ?', array('core_grading', $this->name));
+        // Update the remaining grading areas to use simple grading method instead of this grading method.
+        $DB->execute('UPDATE {grading_areas} SET activemethod = NULL WHERE activemethod = ?', [$this->name]);
+
+        parent::uninstall_cleanup();
     }
 }
index 780a3f4..fefab50 100644 (file)
@@ -157,39 +157,61 @@ class redis extends handler {
             throw new exception('redissessionhandlerproblem', 'error');
         }
 
-        try {
-            // One second timeout was chosen as it is long for connection, but short enough for a user to be patient.
-            if (!$this->connection->connect($this->host, $this->port, 1)) {
-                throw new RedisException('Unable to connect to host.');
-            }
+        // MDL-59866: Add retries for connections (up to 5 times) to make sure it goes through.
+        $counter = 1;
+        $maxnumberofretries = 5;
+
+        while ($counter <= $maxnumberofretries) {
+
+            try {
+
+                $delay = rand(100000, 500000);
 
-            if ($this->auth !== '') {
-                if (!$this->connection->auth($this->auth)) {
-                    throw new RedisException('Unable to authenticate.');
+                // One second timeout was chosen as it is long for connection, but short enough for a user to be patient.
+                if (!$this->connection->connect($this->host, $this->port, 1, null, $delay)) {
+                    throw new RedisException('Unable to connect to host.');
                 }
-            }
 
-            if (!$this->connection->setOption(\Redis::OPT_SERIALIZER, $this->serializer)) {
-                throw new RedisException('Unable to set Redis PHP Serializer option.');
-            }
+                if ($this->auth !== '') {
+                    if (!$this->connection->auth($this->auth)) {
+                        throw new RedisException('Unable to authenticate.');
+                    }
+                }
 
-            if ($this->prefix !== '') {
-                // Use custom prefix on sessions.
-                if (!$this->connection->setOption(\Redis::OPT_PREFIX, $this->prefix)) {
-                    throw new RedisException('Unable to set Redis Prefix option.');
+                if (!$this->connection->setOption(\Redis::OPT_SERIALIZER, $this->serializer)) {
+                    throw new RedisException('Unable to set Redis PHP Serializer option.');
                 }
-            }
-            if ($this->database !== 0) {
-                if (!$this->connection->select($this->database)) {
-                    throw new RedisException('Unable to select Redis database '.$this->database.'.');
+
+                if ($this->prefix !== '') {
+                    // Use custom prefix on sessions.
+                    if (!$this->connection->setOption(\Redis::OPT_PREFIX, $this->prefix)) {
+                        throw new RedisException('Unable to set Redis Prefix option.');
+                    }
+                }
+                if ($this->database !== 0) {
+                    if (!$this->connection->select($this->database)) {
+                        throw new RedisException('Unable to select Redis database '.$this->database.'.');
+                    }
                 }
+                $this->connection->ping();
+                return true;
+            } catch (RedisException $e) {
+                $logstring = "Failed to connect (try {$counter} out of {$maxnumberofretries}) to redis ";
+                $logstring .= "at {$this->host}:{$this->port}, error returned was: {$e->getMessage()}";
+
+                // @codingStandardsIgnoreStart
+                error_log($logstring);
+                // @codingStandardsIgnoreEnd
             }
-            $this->connection->ping();
-            return true;
-        } catch (RedisException $e) {
-            error_log('Failed to connect to redis at '.$this->host.':'.$this->port.', error returned was: '.$e->getMessage());
-            return false;
+
+            $counter++;
+
+            // Introduce a random sleep between 100ms and 500ms.
+            usleep(rand(100000, 500000));
         }
+
+        // We have exhausted our retries, time to give up.
+        return false;
     }
 
     /**
index d5c3939..b9aa9a3 100644 (file)
@@ -51,8 +51,8 @@ class delete_unconfirmed_users_task extends scheduled_task {
             $cuttime = $timenow - ($CFG->deleteunconfirmed * 3600);
             $rs = $DB->get_recordset_sql ("SELECT *
                                              FROM {user}
-                                            WHERE confirmed = 0 AND firstaccess > 0
-                                                  AND firstaccess < ? AND deleted = 0", array($cuttime));
+                                            WHERE confirmed = 0 AND timecreated > 0
+                                                  AND timecreated < ? AND deleted = 0", array($cuttime));
             foreach ($rs as $user) {
                 delete_user($user); // We MUST delete user properly first.
                 $DB->delete_records('user', array('id' => $user->id)); // This is a bloody hack, but it might work.
index 89827fb..3d8a5e7 100644 (file)
@@ -356,19 +356,19 @@ class completion_info {
      * @return array
      */
     public function get_completions($user_id, $criteriatype = null) {
-        $criterion = $this->get_criteria($criteriatype);
+        $criteria = $this->get_criteria($criteriatype);
 
         $completions = array();
 
-        foreach ($criterion as $criteria) {
+        foreach ($criteria as $criterion) {
             $params = array(
                 'course'        => $this->course_id,
                 'userid'        => $user_id,
-                'criteriaid'    => $criteria->id
+                'criteriaid'    => $criterion->id
             );
 
             $completion = new completion_criteria_completion($params);
-            $completion->attach_criteria($criteria);
+            $completion->attach_criteria($criterion);
 
             $completions[] = $completion;
         }
index fad18d6..4412e96 100644 (file)
@@ -44,7 +44,7 @@ function download_as_dataformat($filename, $dataformat, $columns, $iterator, $ca
 
     $classname = 'dataformat_' . $dataformat . '\writer';
     if (!class_exists($classname)) {
-        throw new coding_exception("Unable to locate dataformat/$type/classes/writer.php");
+        throw new coding_exception("Unable to locate dataformat/$dataformat/classes/writer.php");
     }
     $format = new $classname;
 
index 8045f8e..de2be51 100644 (file)
@@ -46,6 +46,10 @@ $observers = array(
         'eventname'   => '\core\event\course_module_completion_updated',
         'callback'    => 'core_badges_observer::course_module_criteria_review',
     ),
+    array(
+        'eventname'   => '\core\event\badge_awarded',
+        'callback'    => 'core_badges_observer::badge_criteria_review',
+    ),
     array(
         'eventname'   => '\core\event\course_completed',
         'callback'    => 'core_badges_observer::course_criteria_review',
index c1a4efb..821cf37 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="lib/db" VERSION="20171026" COMMENT="XMLDB file for core Moodle tables"
+<XMLDB PATH="lib/db" VERSION="20171205" COMMENT="XMLDB file for core Moodle tables"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
 >
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
         <KEY NAME="categoryid" TYPE="foreign" FIELDS="categoryid" REFTABLE="course_categories" REFFIELDS="id"/>
+        <KEY NAME="subscriptionid" TYPE="foreign" FIELDS="subscriptionid" REFTABLE="event_subscriptions" REFFIELDS="id"/>
       </KEYS>
       <INDEXES>
         <INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid"/>
         <INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
         <INDEX NAME="timestart" UNIQUE="false" FIELDS="timestart"/>
         <INDEX NAME="timeduration" UNIQUE="false" FIELDS="timeduration"/>
+        <INDEX NAME="uuid" UNIQUE="false" FIELDS="uuid"/>
         <INDEX NAME="type-timesort" UNIQUE="false" FIELDS="type, timesort"/>
         <INDEX NAME="groupid-courseid-categoryid-visible-userid" UNIQUE="false" FIELDS="groupid, courseid, categoryid, visible, userid" COMMENT="used for calendar view"/>
       </INDEXES>
       </KEYS>
     </TABLE>
   </TABLES>
-</XMLDB>
+</XMLDB>
\ No newline at end of file
index 88cdee7..31019f5 100644 (file)
@@ -92,1005 +92,15 @@ function xmldb_main_upgrade($oldversion) {
     $dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes.
 
     // Always keep this upgrade step with version being the minimum
-    // allowed version to upgrade from (v3.0.0 right now).
-    if ($oldversion < 2015111600) {
+    // allowed version to upgrade from (v3.1.0 right now).
+    if ($oldversion < 2016052300) {
         // Just in case somebody hacks upgrade scripts or env, we really can not continue.
-        echo("You need to upgrade to 3.0.x or higher first!\n");
+        echo("You need to upgrade to 3.1.x or higher first!\n");
         exit(1);
         // Note this savepoint is 100% unreachable, but needed to pass the upgrade checks.
-        upgrade_main_savepoint(true, 2015111600);
+        upgrade_main_savepoint(true, 2016052300);
     }
 
-    if ($oldversion < 2016011300.01) {
-
-        // This is a big upgrade script. We create new table tag_coll and the field
-        // tag.tagcollid pointing to it.
-
-        // Define table tag_coll to be created.
-        $table = new xmldb_table('tag_coll');
-
-        // Adding fields to table tagcloud.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
-        $table->add_field('isdefault', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
-        $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null);
-        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '5', null, XMLDB_NOTNULL, null, '0');
-        $table->add_field('searchable', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
-        $table->add_field('customurl', XMLDB_TYPE_CHAR, '255', null, null, null, null);
-
-        // Adding keys to table tagcloud.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Conditionally launch create table for tagcloud.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Table {tag}.
-        // Define index name (unique) to be dropped form tag - we will replace it with index on (tagcollid,name) later.
-        $table = new xmldb_table('tag');
-        $index = new xmldb_index('name', XMLDB_INDEX_UNIQUE, array('name'));
-
-        // Conditionally launch drop index name.
-        if ($dbman->index_exists($table, $index)) {
-            $dbman->drop_index($table, $index);
-        }
-
-        // Define field tagcollid to be added to tag, we create it as null first and will change to notnull later.
-        $table = new xmldb_table('tag');
-        $field = new xmldb_field('tagcollid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'userid');
-
-        // Conditionally launch add field tagcloudid.
-        if (!$dbman->field_exists($table, $field)) {
-            $dbman->add_field($table, $field);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016011300.01);
-    }
-
-    if ($oldversion < 2016011300.02) {
-        // Create a default tag collection if not exists and update the field tag.tagcollid to point to it.
-        if (!$tcid = $DB->get_field_sql('SELECT id FROM {tag_coll} ORDER BY isdefault DESC, sortorder, id', null,
-                IGNORE_MULTIPLE)) {
-            $tcid = $DB->insert_record('tag_coll', array('isdefault' => 1, 'sortorder' => 0));
-        }
-        $DB->execute('UPDATE {tag} SET tagcollid = ? WHERE tagcollid IS NULL', array($tcid));
-
-        // Define index tagcollname (unique) to be added to tag.
-        $table = new xmldb_table('tag');
-        $index = new xmldb_index('tagcollname', XMLDB_INDEX_UNIQUE, array('tagcollid', 'name'));
-        $field = new xmldb_field('tagcollid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid');
-
-        // Conditionally launch add index tagcollname.
-        if (!$dbman->index_exists($table, $index)) {
-            // Launch change of nullability for field tagcollid.
-            $dbman->change_field_notnull($table, $field);
-            $dbman->add_index($table, $index);
-        }
-
-        // Define key tagcollid (foreign) to be added to tag.
-        $table = new xmldb_table('tag');
-        $key = new xmldb_key('tagcollid', XMLDB_KEY_FOREIGN, array('tagcollid'), 'tag_coll', array('id'));
-
-        // Launch add key tagcloudid.
-        $dbman->add_key($table, $key);
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016011300.02);
-    }
-
-    if ($oldversion < 2016011300.03) {
-
-        // Define table tag_area to be created.
-        $table = new xmldb_table('tag_area');
-
-        // Adding fields to table tag_area.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('itemtype', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('enabled', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
-        $table->add_field('tagcollid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('callback', XMLDB_TYPE_CHAR, '100', null, null, null, null);
-        $table->add_field('callbackfile', XMLDB_TYPE_CHAR, '100', null, null, null, null);
-
-        // Adding keys to table tag_area.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-        $table->add_key('tagcollid', XMLDB_KEY_FOREIGN, array('tagcollid'), 'tag_coll', array('id'));
-
-        // Adding indexes to table tag_area.
-        $table->add_index('compitemtype', XMLDB_INDEX_UNIQUE, array('component', 'itemtype'));
-
-        // Conditionally launch create table for tag_area.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016011300.03);
-    }
-
-    if ($oldversion < 2016011300.04) {
-
-        // Define index itemtype-itemid-tagid-tiuserid (unique) to be dropped form tag_instance.
-        $table = new xmldb_table('tag_instance');
-        $index = new xmldb_index('itemtype-itemid-tagid-tiuserid', XMLDB_INDEX_UNIQUE,
-                array('itemtype', 'itemid', 'tagid', 'tiuserid'));
-
-        // Conditionally launch drop index itemtype-itemid-tagid-tiuserid.
-        if ($dbman->index_exists($table, $index)) {
-            $dbman->drop_index($table, $index);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016011300.04);
-    }
-
-    if ($oldversion < 2016011300.05) {
-
-        $DB->execute("UPDATE {tag_instance} SET component = ? WHERE component IS NULL", array(''));
-
-        // Changing nullability of field component on table tag_instance to not null.
-        $table = new xmldb_table('tag_instance');
-        $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'tagid');
-
-        // Launch change of nullability for field component.
-        $dbman->change_field_notnull($table, $field);
-
-        // Changing type of field itemtype on table tag_instance to char.
-        $table = new xmldb_table('tag_instance');
-        $field = new xmldb_field('itemtype', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'component');
-
-        // Launch change of type for field itemtype.
-        $dbman->change_field_type($table, $field);
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016011300.05);
-    }
-
-    if ($oldversion < 2016011300.06) {
-
-        // Define index taggeditem (unique) to be added to tag_instance.
-        $table = new xmldb_table('tag_instance');
-        $index = new xmldb_index('taggeditem', XMLDB_INDEX_UNIQUE, array('component', 'itemtype', 'itemid', 'tiuserid', 'tagid'));
-
-        // Conditionally launch add index taggeditem.
-        if (!$dbman->index_exists($table, $index)) {
-            $dbman->add_index($table, $index);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016011300.06);
-    }
-
-    if ($oldversion < 2016011300.07) {
-
-        // Define index taglookup (not unique) to be added to tag_instance.
-        $table = new xmldb_table('tag_instance');
-        $index = new xmldb_index('taglookup', XMLDB_INDEX_NOTUNIQUE, array('itemtype', 'component', 'tagid', 'contextid'));
-
-        // Conditionally launch add index taglookup.
-        if (!$dbman->index_exists($table, $index)) {
-            $dbman->add_index($table, $index);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016011300.07);
-    }
-
-    if ($oldversion < 2016011301.00) {
-
-        // Force uninstall of deleted tool.
-        if (!file_exists("$CFG->dirroot/webservice/amf")) {
-            // Remove capabilities.
-            capabilities_cleanup('webservice_amf');
-            // Remove all other associated config.
-            unset_all_config_for_plugin('webservice_amf');
-        }
-        upgrade_main_savepoint(true, 2016011301.00);
-    }
-
-    if ($oldversion < 2016011901.00) {
-
-        // Convert calendar_lookahead to nearest new value.
-        $transaction = $DB->start_delegated_transaction();
-
-        // Count all users who curretly have that preference set (for progress bar).
-        $total = $DB->count_records_select('user_preferences', "name = 'calendar_lookahead' AND value != '0'");
-        $pbar = new progress_bar('upgradecalendarlookahead', 500, true);
-
-        // Get all these users, one at a time.
-        $rs = $DB->get_recordset_select('user_preferences', "name = 'calendar_lookahead' AND value != '0'");
-        $i = 0;
-        foreach ($rs as $userpref) {
-
-            // Calculate and set new lookahead value.
-            if ($userpref->value > 90) {
-                $newvalue = 120;
-            } else if ($userpref->value > 60 and $userpref->value < 90) {
-                $newvalue = 90;
-            } else if ($userpref->value > 30 and $userpref->value < 60) {
-                $newvalue = 60;
-            } else if ($userpref->value > 21 and $userpref->value < 30) {
-                $newvalue = 30;
-            } else if ($userpref->value > 14 and $userpref->value < 21) {
-                $newvalue = 21;
-            } else if ($userpref->value > 7 and $userpref->value < 14) {
-                $newvalue = 14;
-            } else {
-                $newvalue = $userpref->value;
-            }
-
-            $DB->set_field('user_preferences', 'value', $newvalue, array('id' => $userpref->id));
-
-            // Update progress.
-            $i++;
-            $pbar->update($i, $total, "Upgrading user preference settings - $i/$total.");
-        }
-        $rs->close();
-        $transaction->allow_commit();
-
-        upgrade_main_savepoint(true, 2016011901.00);
-    }
-
-    if ($oldversion < 2016020200.00) {
-
-        // Define field isstandard to be added to tag.
-        $table = new xmldb_table('tag');
-        $field = new xmldb_field('isstandard', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'rawname');
-
-        // Conditionally launch add field isstandard.
-        if (!$dbman->field_exists($table, $field)) {
-            $dbman->add_field($table, $field);
-        }
-
-        // Define index tagcolltype (not unique) to be dropped form tag.
-        // This index is no longer created however it was present at some point and it's better to be safe and try to drop it.
-        $index = new xmldb_index('tagcolltype', XMLDB_INDEX_NOTUNIQUE, array('tagcollid', 'tagtype'));
-
-        // Conditionally launch drop index tagcolltype.
-        if ($dbman->index_exists($table, $index)) {
-            $dbman->drop_index($table, $index);
-        }
-
-        // Define index tagcolltype (not unique) to be added to tag.
-        $index = new xmldb_index('tagcolltype', XMLDB_INDEX_NOTUNIQUE, array('tagcollid', 'isstandard'));
-
-        // Conditionally launch add index tagcolltype.
-        if (!$dbman->index_exists($table, $index)) {
-            $dbman->add_index($table, $index);
-        }
-
-        // Define field tagtype to be dropped from tag.
-        $field = new xmldb_field('tagtype');
-
-        // Conditionally launch drop field tagtype and update isstandard.
-        if ($dbman->field_exists($table, $field)) {
-            $DB->execute("UPDATE {tag} SET isstandard=(CASE WHEN (tagtype = ?) THEN 1 ELSE 0 END)", array('official'));
-            $dbman->drop_field($table, $field);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016020200.00);
-    }
-
-    if ($oldversion < 2016020201.00) {
-
-        // Define field showstandard to be added to tag_area.
-        $table = new xmldb_table('tag_area');
-        $field = new xmldb_field('showstandard', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'callbackfile');
-
-        // Conditionally launch add field showstandard.
-        if (!$dbman->field_exists($table, $field)) {
-            $dbman->add_field($table, $field);
-        }
-
-        // By default set user area to hide standard tags. 2 = core_tag_tag::HIDE_STANDARD (can not use constant here).
-        $DB->execute("UPDATE {tag_area} SET showstandard = ? WHERE itemtype = ? AND component = ?",
-            array(2, 'user', 'core'));
-
-        // Changing precision of field enabled on table tag_area to (1).
-        $table = new xmldb_table('tag_area');
-        $field = new xmldb_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'itemtype');
-
-        // Launch change of precision for field enabled.
-        $dbman->change_field_precision($table, $field);
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016020201.00);
-    }
-
-    if ($oldversion < 2016021500.00) {
-        $root = $CFG->tempdir . '/download';
-        if (is_dir($root)) {
-            // Fetch each repository type - include all repos, not just enabled.
-            $repositories = $DB->get_records('repository', array(), '', 'type');
-
-            foreach ($repositories as $id => $repository) {
-                $directory = $root . '/repository_' . $repository->type;
-                if (is_dir($directory)) {
-                    fulldelete($directory);
-                }
-            }
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016021500.00);
-    }
-
-    if ($oldversion < 2016021501.00) {
-        // This could take a long time. Unfortunately, no way to know how long, and no way to do progress, so setting for 1 hour.
-        upgrade_set_timeout(3600);
-
-        // Define index userid-itemid (not unique) to be added to grade_grades_history.
-        $table = new xmldb_table('grade_grades_history');
-        $index = new xmldb_index('userid-itemid-timemodified', XMLDB_INDEX_NOTUNIQUE, array('userid', 'itemid', 'timemodified'));
-
-        // Conditionally launch add index userid-itemid.
-        if (!$dbman->index_exists($table, $index)) {
-            $dbman->add_index($table, $index);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016021501.00);
-    }
-
-    if ($oldversion < 2016030103.00) {
-
-        // MDL-50887. Implement plugins infrastructure for antivirus and create ClamAV plugin.
-        // This routine moves core ClamAV configuration to plugin level.
-
-        // If clamav was configured and enabled, enable the plugin.
-        if (!empty($CFG->runclamonupload) && !empty($CFG->pathtoclam)) {
-            set_config('antiviruses', 'clamav');
-        } else {
-            set_config('antiviruses', '');
-        }
-
-        if (isset($CFG->runclamonupload)) {
-            // Just unset global configuration, we have already enabled the plugin
-            // which implies that ClamAV will be used for scanning uploaded files.
-            unset_config('runclamonupload');
-        }
-        // Move core ClamAV configuration settings to plugin.
-        if (isset($CFG->pathtoclam)) {
-            set_config('pathtoclam', $CFG->pathtoclam, 'antivirus_clamav');
-            unset_config('pathtoclam');
-        }
-        if (isset($CFG->quarantinedir)) {
-            set_config('quarantinedir', $CFG->quarantinedir, 'antivirus_clamav');
-            unset_config('quarantinedir');
-        }
-        if (isset($CFG->clamfailureonupload)) {
-            set_config('clamfailureonupload', $CFG->clamfailureonupload, 'antivirus_clamav');
-            unset_config('clamfailureonupload');
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016030103.00);
-    }
-
-    if ($oldversion < 2016030400.01) {
-        // Add the new services field.
-        $table = new xmldb_table('external_functions');
-        $field = new xmldb_field('services', XMLDB_TYPE_CHAR, '1333', null, null, null, null, 'capabilities');
-
-        // Conditionally launch add field services.
-        if (!$dbman->field_exists($table, $field)) {
-            $dbman->add_field($table, $field);
-        }
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016030400.01);
-    }
-
-    if ($oldversion < 2016041500.50) {
-
-        // Define table competency to be created.
-        $table = new xmldb_table('competency');
-
-        // Adding fields to table competency.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('shortname', XMLDB_TYPE_CHAR, '100', null, null, null, null);
-        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
-        $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
-        $table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null);
-        $table->add_field('competencyframeworkid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('parentid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
-        $table->add_field('path', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('ruletype', XMLDB_TYPE_CHAR, '100', null, null, null, null);
-        $table->add_field('ruleoutcome', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
-        $table->add_field('ruleconfig', XMLDB_TYPE_TEXT, null, null, null, null, null);
-        $table->add_field('scaleid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('scaleconfiguration', XMLDB_TYPE_TEXT, null, null, null, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-
-        // Adding keys to table competency.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency.
-        $table->add_index('idnumberframework', XMLDB_INDEX_UNIQUE, array('competencyframeworkid', 'idnumber'));
-        $table->add_index('ruleoutcome', XMLDB_INDEX_NOTUNIQUE, array('ruleoutcome'));
-
-        // Conditionally launch create table for competency.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.50);
-    }
-
-    if ($oldversion < 2016041500.51) {
-
-        // Define table competency_coursecompsetting to be created.
-        $table = new xmldb_table('competency_coursecompsetting');
-
-        // Adding fields to table competency_coursecompsetting.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('pushratingstouserplans', XMLDB_TYPE_INTEGER, '2', null, null, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-
-        // Adding keys to table competency_coursecompsetting.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-        $table->add_key('courseidlink', XMLDB_KEY_FOREIGN_UNIQUE, array('courseid'), 'course', array('id'));
-
-        // Conditionally launch create table for competency_coursecompsetting.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.51);
-    }
-
-    if ($oldversion < 2016041500.52) {
-
-        // Define table competency_framework to be created.
-        $table = new xmldb_table('competency_framework');
-
-        // Adding fields to table competency_framework.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('shortname', XMLDB_TYPE_CHAR, '100', null, null, null, null);
-        $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null);
-        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
-        $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
-        $table->add_field('scaleid', XMLDB_TYPE_INTEGER, '11', null, null, null, null);
-        $table->add_field('scaleconfiguration', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
-        $table->add_field('visible', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
-        $table->add_field('taxonomies', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-
-        // Adding keys to table competency_framework.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency_framework.
-        $table->add_index('idnumber', XMLDB_INDEX_UNIQUE, array('idnumber'));
-
-        // Conditionally launch create table for competency_framework.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.52);
-    }
-
-    if ($oldversion < 2016041500.53) {
-
-        // Define table competency_coursecomp to be created.
-        $table = new xmldb_table('competency_coursecomp');
-
-        // Adding fields to table competency_coursecomp.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('ruleoutcome', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_coursecomp.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-        $table->add_key('courseidlink', XMLDB_KEY_FOREIGN, array('courseid'), 'course', array('id'));
-        $table->add_key('competencyid', XMLDB_KEY_FOREIGN, array('competencyid'), 'competency_competency', array('id'));
-
-        // Adding indexes to table competency_coursecomp.
-        $table->add_index('courseidruleoutcome', XMLDB_INDEX_NOTUNIQUE, array('courseid', 'ruleoutcome'));
-        $table->add_index('courseidcompetencyid', XMLDB_INDEX_UNIQUE, array('courseid', 'competencyid'));
-
-        // Conditionally launch create table for competency_coursecomp.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.53);
-    }
-
-    if ($oldversion < 2016041500.54) {
-
-        // Define table competency_plan to be created.
-        $table = new xmldb_table('competency_plan');
-
-        // Adding fields to table competency_plan.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('name', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
-        $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
-        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('templateid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('origtemplateid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('status', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('duedate', XMLDB_TYPE_INTEGER, '10', null, null, null, '0');
-        $table->add_field('reviewerid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_plan.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency_plan.
-        $table->add_index('useridstatus', XMLDB_INDEX_NOTUNIQUE, array('userid', 'status'));
-        $table->add_index('templateid', XMLDB_INDEX_NOTUNIQUE, array('templateid'));
-        $table->add_index('statusduedate', XMLDB_INDEX_NOTUNIQUE, array('status', 'duedate'));
-
-        // Conditionally launch create table for competency_plan.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.54);
-    }
-
-    if ($oldversion < 2016041500.55) {
-
-        // Define table competency_template to be created.
-        $table = new xmldb_table('competency_template');
-
-        // Adding fields to table competency_template.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('shortname', XMLDB_TYPE_CHAR, '100', null, null, null, null);
-        $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
-        $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
-        $table->add_field('visible', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
-        $table->add_field('duedate', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-
-        // Adding keys to table competency_template.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Conditionally launch create table for competency_template.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.55);
-    }
-
-    if ($oldversion < 2016041500.56) {
-
-        // Define table competency_templatecomp to be created.
-        $table = new xmldb_table('competency_templatecomp');
-
-        // Adding fields to table competency_templatecomp.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('templateid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-
-        // Adding keys to table competency_templatecomp.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-        $table->add_key('templateidlink', XMLDB_KEY_FOREIGN, array('templateid'), 'competency_template', array('id'));
-        $table->add_key('competencyid', XMLDB_KEY_FOREIGN, array('competencyid'), 'competency_competency', array('id'));
-
-        // Conditionally launch create table for competency_templatecomp.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.56);
-    }
-
-    if ($oldversion < 2016041500.57) {
-
-        // Define table competency_templatecohort to be created.
-        $table = new xmldb_table('competency_templatecohort');
-
-        // Adding fields to table competency_templatecohort.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('templateid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('cohortid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_templatecohort.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency_templatecohort.
-        $table->add_index('templateid', XMLDB_INDEX_NOTUNIQUE, array('templateid'));
-        $table->add_index('templatecohortids', XMLDB_INDEX_UNIQUE, array('templateid', 'cohortid'));
-
-        // Conditionally launch create table for competency_templatecohort.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.57);
-    }
-
-    if ($oldversion < 2016041500.58) {
-
-        // Define table competency_relatedcomp to be created.
-        $table = new xmldb_table('competency_relatedcomp');
-
-        // Adding fields to table competency_relatedcomp.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('relatedcompetencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_relatedcomp.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Conditionally launch create table for competency_relatedcomp.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.58);
-    }
-
-    if ($oldversion < 2016041500.59) {
-
-        // Define table competency_usercomp to be created.
-        $table = new xmldb_table('competency_usercomp');
-
-        // Adding fields to table competency_usercomp.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('status', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
-        $table->add_field('reviewerid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('proficiency', XMLDB_TYPE_INTEGER, '2', null, null, null, null);
-        $table->add_field('grade', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_usercomp.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency_usercomp.
-        $table->add_index('useridcompetency', XMLDB_INDEX_UNIQUE, array('userid', 'competencyid'));
-
-        // Conditionally launch create table for competency_usercomp.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.59);
-    }
-
-    if ($oldversion < 2016041500.60) {
-
-        // Define table competency_usercompcourse to be created.
-        $table = new xmldb_table('competency_usercompcourse');
-
-        // Adding fields to table competency_usercompcourse.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('proficiency', XMLDB_TYPE_INTEGER, '2', null, null, null, null);
-        $table->add_field('grade', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_usercompcourse.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency_usercompcourse.
-        $table->add_index('useridcoursecomp', XMLDB_INDEX_UNIQUE, array('userid', 'courseid', 'competencyid'));
-
-        // Conditionally launch create table for competency_usercompcourse.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.60);
-    }
-
-    if ($oldversion < 2016041500.61) {
-
-        // Define table competency_usercompplan to be created.
-        $table = new xmldb_table('competency_usercompplan');
-
-        // Adding fields to table competency_usercompplan.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('planid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('proficiency', XMLDB_TYPE_INTEGER, '2', null, null, null, null);
-        $table->add_field('grade', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_usercompplan.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency_usercompplan.
-        $table->add_index('usercompetencyplan', XMLDB_INDEX_UNIQUE, array('userid', 'competencyid', 'planid'));
-
-        // Conditionally launch create table for competency_usercompplan.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.61);
-    }
-
-    if ($oldversion < 2016041500.62) {
-
-        // Define table competency_plancomp to be created.
-        $table = new xmldb_table('competency_plancomp');
-
-        // Adding fields to table competency_plancomp.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('planid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_plancomp.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency_plancomp.
-        $table->add_index('planidcompetencyid', XMLDB_INDEX_UNIQUE, array('planid', 'competencyid'));
-
-        // Conditionally launch create table for competency_plancomp.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.62);
-    }
-
-    if ($oldversion < 2016041500.63) {
-
-        // Define table competency_evidence to be created.
-        $table = new xmldb_table('competency_evidence');
-
-        // Adding fields to table competency_evidence.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('usercompetencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('action', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('actionuserid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('descidentifier', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('desccomponent', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('desca', XMLDB_TYPE_TEXT, null, null, null, null, null);
-        $table->add_field('url', XMLDB_TYPE_CHAR, '255', null, null, null, null);
-        $table->add_field('grade', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
-        $table->add_field('note', XMLDB_TYPE_TEXT, null, null, null, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_evidence.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency_evidence.
-        $table->add_index('usercompetencyid', XMLDB_INDEX_NOTUNIQUE, array('usercompetencyid'));
-
-        // Conditionally launch create table for competency_evidence.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.63);
-    }
-
-    if ($oldversion < 2016041500.64) {
-
-        // Define table competency_userevidence to be created.
-        $table = new xmldb_table('competency_userevidence');
-
-        // Adding fields to table competency_userevidence.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('name', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
-        $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('url', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_userevidence.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency_userevidence.
-        $table->add_index('userid', XMLDB_INDEX_NOTUNIQUE, array('userid'));
-
-        // Conditionally launch create table for competency_userevidence.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.64);
-    }
-
-    if ($oldversion < 2016041500.65) {
-
-        // Define table competency_userevidencecomp to be created.
-        $table = new xmldb_table('competency_userevidencecomp');
-
-        // Adding fields to table competency_userevidencecomp.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('userevidenceid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_userevidencecomp.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Adding indexes to table competency_userevidencecomp.
-        $table->add_index('userevidenceid', XMLDB_INDEX_NOTUNIQUE, array('userevidenceid'));
-        $table->add_index('userevidencecompids', XMLDB_INDEX_UNIQUE, array('userevidenceid', 'competencyid'));
-
-        // Conditionally launch create table for competency_userevidencecomp.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.65);
-    }
-
-    if ($oldversion < 2016041500.66) {
-
-        // Define table competency_modulecomp to be created.
-        $table = new xmldb_table('competency_modulecomp');
-
-        // Adding fields to table competency_modulecomp.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('cmid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('ruleoutcome', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table competency_modulecomp.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-        $table->add_key('cmidkey', XMLDB_KEY_FOREIGN, array('cmid'), 'course_modules', array('id'));
-        $table->add_key('competencyidkey', XMLDB_KEY_FOREIGN, array('competencyid'), 'competency_competency', array('id'));
-
-        // Adding indexes to table competency_modulecomp.
-        $table->add_index('cmidruleoutcome', XMLDB_INDEX_NOTUNIQUE, array('cmid', 'ruleoutcome'));
-        $table->add_index('cmidcompetencyid', XMLDB_INDEX_UNIQUE, array('cmid', 'competencyid'));
-
-        // Conditionally launch create table for competency_modulecomp.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016041500.66);
-    }
-
-    if ($oldversion < 2016042100.00) {
-        // Update all countries to upper case.
-        $DB->execute("UPDATE {user} SET country = UPPER(country)");
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016042100.00);
-    }
-
-    if ($oldversion < 2016042600.01) {
-        $deprecatedwebservices = [
-            'moodle_course_create_courses',
-            'moodle_course_get_courses',
-            'moodle_enrol_get_enrolled_users',
-            'moodle_enrol_get_users_courses',
-            'moodle_enrol_manual_enrol_users',
-            'moodle_file_get_files',
-            'moodle_file_upload',
-            'moodle_group_add_groupmembers',
-            'moodle_group_create_groups',
-            'moodle_group_delete_groupmembers',
-            'moodle_group_delete_groups',
-            'moodle_group_get_course_groups',
-            'moodle_group_get_groupmembers',
-            'moodle_group_get_groups',
-            'moodle_message_send_instantmessages',
-            'moodle_notes_create_notes',
-            'moodle_role_assign',
-            'moodle_role_unassign',
-            'moodle_user_create_users',
-            'moodle_user_delete_users',
-            'moodle_user_get_course_participants_by_id',
-            'moodle_user_get_users_by_courseid',
-            'moodle_user_get_users_by_id',
-            'moodle_user_update_users',
-            'core_grade_get_definitions',
-            'core_user_get_users_by_id',
-            'moodle_webservice_get_siteinfo',
-            'mod_forum_get_forum_discussions'
-        ];
-
-        list($insql, $params) = $DB->get_in_or_equal($deprecatedwebservices);
-        $DB->delete_records_select('external_functions', "name $insql", $params);
-        $DB->delete_records_select('external_services_functions', "functionname $insql", $params);
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016042600.01);
-    }
-
-    if ($oldversion < 2016051300.00) {
-        // Add a default competency rating scale.
-        make_competence_scale();
-
-        // Savepoint reached.
-        upgrade_main_savepoint(true, 2016051300.00);
-    }
-
-    if ($oldversion < 2016051700.01) {
-        // This script is included in each major version upgrade process (3.0, 3.1) so make sure we don't run it twice.
-        if (empty($CFG->upgrade_letterboundarycourses)) {
-            // MDL-45390. If a grade is being displayed with letters and the grade boundaries are not being adhered to properly
-            // then this course will also be frozen.
-            // If the changes are accepted then the display of some grades may change.
-            // This is here to freeze the gradebook in affected courses.
-            upgrade_course_letter_boundary();
-
-            // To skip running the same script on the upgrade to the next major version release.
-            set_config('upgrade_letterboundarycourses', 1);
-        }
-        // Main savepoint reached.
-        upgrade_main_savepoint(true, 2016051700.01);
-    }
-
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     if ($oldversion < 2016081700.00) {
 
         // If someone is emotionally attached to it let's leave the config (basically the version) there.
@@ -2827,5 +1837,27 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2017111300.02);
     }
 
+    if ($oldversion < 2017121200.00) {
+
+        // Define key subscriptionid (foreign) to be added to event.
+        $table = new xmldb_table('event');
+        $key = new xmldb_key('subscriptionid', XMLDB_KEY_FOREIGN, array('subscriptionid'), 'event_subscriptions', array('id'));
+
+        // Launch add key subscriptionid.
+        $dbman->add_key($table, $key);
+
+        // Define index uuid (not unique) to be added to event.
+        $table = new xmldb_table('event');
+        $index = new xmldb_index('uuid', XMLDB_INDEX_NOTUNIQUE, array('uuid'));
+
+        // Conditionally launch add index uuid.
+        if (!$dbman->index_exists($table, $index)) {
+            $dbman->add_index($table, $index);
+        }
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2017121200.00);
+    }
+
     return true;
 }
index 1b72c00..a16b933 100644 (file)
@@ -2402,21 +2402,25 @@ abstract class moodle_database {
 
         // Enclose the column name by the proper quotes if it's a reserved word.
         $columnname = $this->get_manager()->generator->getEncQuoted($column->name);
+
+        $searchsql = $this->sql_like($columnname, '?');
+        $searchparam = '%'.$this->sql_like_escape($search).'%';
+
         $sql = "UPDATE {".$table."}
                        SET $columnname = REPLACE($columnname, ?, ?)
-                     WHERE $columnname IS NOT NULL";
+                     WHERE $searchsql";
 
         if ($column->meta_type === 'X') {
-            $this->execute($sql, array($search, $replace));
+            $this->execute($sql, array($search, $replace, $searchparam));
 
         } else if ($column->meta_type === 'C') {
             if (core_text::strlen($search) < core_text::strlen($replace)) {
                 $colsize = $column->max_length;
                 $sql = "UPDATE {".$table."}
                        SET $columnname = " . $this->sql_substr("REPLACE(" . $columnname . ", ?, ?)", 1, $colsize) . "
-                     WHERE $columnname IS NOT NULL";
+                     WHERE $searchsql";
             }
-            $this->execute($sql, array($search, $replace));
+            $this->execute($sql, array($search, $replace, $searchparam));
         }
     }
 
index 850fb5f..1d6dec9 100644 (file)
@@ -30,6 +30,8 @@
  *  - bit ops: To provide cross-db bitwise operations to be used by the
  *             sql_bitXXX() helper functions
  *  - one space hacks: One space empty string substitute hacks.
+ *
+ * Moodle will not parse this file correctly if it uses Windows line endings.
  */
 
 CREATE OR REPLACE PACKAGE MOODLELIB AS
index 4483e41..283a09f 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_editor_atto_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index dcab5bb..efe6f10 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_atto_equation_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 9e3b709..6f8f80f 100644 (file)
@@ -27,9 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_editor_tinymce_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 2cf7efe..a56ffb4 100644 (file)
@@ -27,9 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_tinymce_spellchecker_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index d69094b..1a73b2d 100644 (file)
@@ -544,26 +544,32 @@ function enrol_add_course_navigation(navigation_node $coursenode, $course) {
 /**
  * Returns list of courses current $USER is enrolled in and can access
  *
- * - $fields is an array of field names to ADD
- *   so name the fields you really need, which will
- *   be added and uniq'd
+ * The $fields param is a list of field names to ADD so name just the fields you really need,
+ * which will be added and uniq'd.
  *
  * If $allaccessible is true, this will additionally return courses that the current user is not
  * enrolled in, but can access because they are open to the user for other reasons (course view
  * permission, currently viewing course as a guest, or course allows guest access without
  * password).
  *
- * @param string|array $fields
- * @param string $sort
+ * @param string|array $fields Extra fields to be returned (array or comma-separated list).
+ * @param string|null $sort Comma separated list of fields to sort by, defaults to respecting navsortmycoursessort.
  * @param int $limit max number of courses
  * @param array $courseids the list of course ids to filter by
  * @param bool $allaccessible Include courses user is not enrolled in, but can access
  * @return array
  */
-function enrol_get_my_courses($fields = null, $sort = 'visible DESC,sortorder ASC',
-          $limit = 0, $courseids = [], $allaccessible = false) {
+function enrol_get_my_courses($fields = null, $sort = null, $limit = 0, $courseids = [], $allaccessible = false) {
     global $DB, $USER, $CFG;
 
+    if ($sort === null) {
+        if (empty($CFG->navsortmycoursessort)) {
+            $sort = 'visible DESC, sortorder ASC';
+        } else {
+            $sort = 'visible DESC, '.$CFG->navsortmycoursessort.' ASC';
+        }
+    }
+
     // Guest account does not have any enrolled courses.
     if (!$allaccessible && (isguestuser() or !isloggedin())) {
         return array();
@@ -584,7 +590,7 @@ function enrol_get_my_courses($fields = null, $sort = 'visible DESC,sortorder AS
     } else if (is_array($fields)) {
         $fields = array_unique(array_merge($basefields, $fields));
     } else {
-        throw new coding_exception('Invalid $fileds parameter in enrol_get_my_courses()');
+        throw new coding_exception('Invalid $fields parameter in enrol_get_my_courses()');
     }
     if (in_array('*', $fields)) {
         $fields = array('*');
@@ -788,19 +794,19 @@ function enrol_get_course_description_texts($course) {
 
 /**
  * Returns list of courses user is enrolled into.
- * (Note: use enrol_get_all_users_courses if you want to use the list wihtout any cap checks )
  *
- * - $fields is an array of fieldnames to ADD
- *   so name the fields you really need, which will
- *   be added and uniq'd
+ * Note: Use {@link enrol_get_all_users_courses()} if you need the list without any capability checks.
  *
- * @param int $userid
- * @param bool $onlyactive return only active enrolments in courses user may see
- * @param string|array $fields
- * @param string $sort
+ * The $fields param is a list of field names to ADD so name just the fields you really need,
+ * which will be added and uniq'd.
+ *
+ * @param int $userid User whose courses are returned, defaults to the current user.
+ * @param bool $onlyactive Return only active enrolments in courses user may see.
+ * @param string|array $fields Extra fields to be returned (array or comma-separated list).
+ * @param string|null $sort Comma separated list of fields to sort by, defaults to respecting navsortmycoursessort.
  * @return array
  */
-function enrol_get_users_courses($userid, $onlyactive = false, $fields = NULL, $sort = 'visible DESC,sortorder ASC') {
+function enrol_get_users_courses($userid, $onlyactive = false, $fields = null, $sort = null) {
     global $DB;
 
     $courses = enrol_get_all_users_courses($userid, $onlyactive, $fields, $sort);
@@ -877,19 +883,27 @@ function enrol_user_sees_own_courses($user = null) {
 }
 
 /**
- * Returns list of courses user is enrolled into without any capability checks
- * - $fields is an array of fieldnames to ADD
- *   so name the fields you really need, which will
- *   be added and uniq'd
+ * Returns list of courses user is enrolled into without performing any capability checks.
  *
- * @param int $userid
- * @param bool $onlyactive return only active enrolments in courses user may see
- * @param string|array $fields
- * @param string $sort
+ * The $fields param is a list of field names to ADD so name just the fields you really need,
+ * which will be added and uniq'd.
+ *
+ * @param int $userid User whose courses are returned, defaults to the current user.
+ * @param bool $onlyactive Return only active enrolments in courses user may see.
+ * @param string|array $fields Extra fields to be returned (array or comma-separated list).
+ * @param string|null $sort Comma separated list of fields to sort by, defaults to respecting navsortmycoursessort.
  * @return array
  */
-function enrol_get_all_users_courses($userid, $onlyactive = false, $fields = NULL, $sort = 'visible DESC,sortorder ASC') {
-    global $DB;
+function enrol_get_all_users_courses($userid, $onlyactive = false, $fields = null, $sort = null) {
+    global $CFG, $DB;
+
+    if ($sort === null) {
+        if (empty($CFG->navsortmycoursessort)) {
+            $sort = 'visible DESC, sortorder ASC';
+        } else {
+            $sort = 'visible DESC, '.$CFG->navsortmycoursessort.' ASC';
+        }
+    }
 
     // Guest account does not have any courses
     if (isguestuser($userid) or empty($userid)) {
@@ -912,7 +926,7 @@ function enrol_get_all_users_courses($userid, $onlyactive = false, $fields = NUL
     } else if (is_array($fields)) {
         $fields = array_unique(array_merge($basefields, $fields));
     } else {
-        throw new coding_exception('Invalid $fileds parameter in enrol_get_my_courses()');
+        throw new coding_exception('Invalid $fields parameter in enrol_get_all_users_courses()');
     }
     if (in_array('*', $fields)) {
         $fields = array('*');
index 6b4f1dc..4eeab3d 100644 (file)
@@ -904,6 +904,7 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea
 
         $newhashes = array();
         $filecount = 0;
+        $context = context::instance_by_id($contextid, MUST_EXIST);
         foreach ($draftfiles as $file) {
             if (!$options['subdirs'] && $file->get_filepath() !== '/') {
                 continue;
@@ -912,8 +913,11 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea
                 continue;
             }
             if (!$file->is_directory()) {
-                if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) {
-                    // oversized file - should not get here at all
+                // Check to see if this file was uploaded by someone who can ignore the file size limits.
+                $fileusermaxbytes = get_user_max_upload_file_size($context, $options['maxbytes'], 0, 0, $file->get_userid());
+                if ($fileusermaxbytes != USER_CAN_IGNORE_FILE_SIZE_LIMITS
+                        && ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize())) {
+                    // Oversized file.
                     continue;
                 }
                 if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) {
index 36f186f..c1a4254 100644 (file)
@@ -304,7 +304,9 @@ class stored_file {
         $filerecord->filesize = $newfile->get_filesize();
         $filerecord->referencefileid = $newfile->get_referencefileid();
         $filerecord->userid = $newfile->get_userid();
+        $oldcontenthash = $this->get_contenthash();
         $this->update($filerecord);
+        $this->filesystem->remove_file($oldcontenthash);
     }
 
     /**
index db18e88..e90ee4d 100644 (file)
@@ -90,4 +90,21 @@ class MoodleQuickForm_passwordunmask extends MoodleQuickForm_password {
 
         return $context;
     }
+
+    /**
+     * Check that there is no whitespace at the beginning and end of the password.
+     *
+     * It turned out that wrapping whitespace can easily be pasted by accident when copying the text from elsewhere.
+     * Such a mistake is very hard to debug as the whitespace is not displayed.
+     *
+     * @param array $value Submitted value.
+     * @return string|null Validation error message or null.
+     */
+    public function validateSubmitValue($value) {
+        if ($value !== null && $value !== trim($value)) {
+            return get_string('err_wrappingwhitespace', 'core_form');
+        }
+
+        return;
+    }
 }
index b62eaf9..ef3719f 100644 (file)
@@ -244,7 +244,11 @@ class MoodleQuickForm_tags extends MoodleQuickForm_autocomplete {
      */
     public function exportValue(&$submitValues, $assoc = false) {
         if (!$this->is_tagging_enabled()) {
-            return $assoc ? array($this->getName() => array()) : array();
+            return $this->_prepareValue([], $assoc);
+        }
+        if ($this->_findValue($submitValues) === '_qf__force_multiselect_submission') {
+            // Nothing was selected.
+            return $this->_prepareValue([], $assoc);
         }
 
         return parent::exportValue($submitValues, $assoc);
@@ -257,6 +261,7 @@ class MoodleQuickForm_tags extends MoodleQuickForm_autocomplete {
             $url = new moodle_url('/tag/manage.php', array('tc' => $this->get_tag_collection()));
             $context['managestandardtagsurl'] = $url->out(false);
         }
+        $context['nameraw'] = $this->getName();
 
         return $context;
     }
index 774f7d4..9ba9f39 100644 (file)
@@ -2111,7 +2111,7 @@ function make_timestamp($year, $month=1, $day=1, $hour=0, $minute=0, $second=0,
  * Format a date/time (seconds) as weeks, days, hours etc as needed
  *
  * Given an amount of time in seconds, returns string
- * formatted nicely as weeks, days, hours etc as needed
+ * formatted nicely as years, days, hours etc as needed
  *
  * @package core
  * @category time
@@ -3917,11 +3917,11 @@ function update_user_record_by_id($id) {
                 // Unknown or must not be changed.
                 continue;
             }
-            $confval = $userauth->config->{'field_updatelocal_' . $key};
-            $lockval = $userauth->config->{'field_lock_' . $key};
-            if (empty($confval) || empty($lockval)) {
+            if (empty($userauth->config->{'field_updatelocal_' . $key}) || empty($userauth->config->{'field_lock_' . $key})) {
                 continue;
             }
+            $confval = $userauth->config->{'field_updatelocal_' . $key};
+            $lockval = $userauth->config->{'field_lock_' . $key};
             if ($confval === 'onlogin') {
                 // MDL-4207 Don't overwrite modified user profile values with
                 // empty LDAP values when 'unlocked if empty' is set. The purpose
index c873280..5ce9104 100644 (file)
@@ -225,7 +225,7 @@ function core_myprofile_navigation(core_user\output\myprofile\tree $tree, $user,
 
     if (!isset($hiddenfields['mycourses'])) {
         $showallcourses = optional_param('showallcourses', 0, PARAM_INT);
-        if ($mycourses = enrol_get_all_users_courses($user->id, true, null, 'visible DESC, sortorder ASC')) {
+        if ($mycourses = enrol_get_all_users_courses($user->id, true, null)) {
             $shown = 0;
             $courselisting = html_writer::start_tag('ul');
             foreach ($mycourses as $mycourse) {
index 9f22f18..16d7b63 100644 (file)
@@ -2920,14 +2920,7 @@ class global_navigation extends navigation_node {
 
         $limit = (int) $CFG->navcourselimit;
 
-        $sortorder = 'visible DESC';
-        // Prevent undefined $CFG->navsortmycoursessort errors.
-        if (empty($CFG->navsortmycoursessort)) {
-            $CFG->navsortmycoursessort = 'sortorder';
-        }
-        // Append the chosen sortorder.
-        $sortorder = $sortorder . ',' . $CFG->navsortmycoursessort . ' ASC';
-        $courses = enrol_get_my_courses('*', $sortorder);
+        $courses = enrol_get_my_courses('*');
         $flatnavcourses = [];
 
         // Go through the courses and see which ones we want to display in the flatnav.
index 6d101b3..7a8beff 100644 (file)
@@ -201,10 +201,13 @@ function theme_build_css_for_themes($themeconfigs = [], $directions = ['rtl', 'l
 
         // First generate all the new css.
         foreach ($directions as $direction) {
+            // Lock it on. Technically we should build all themes for SVG and no SVG - but ie9 is out of support.
+            $themeconfig->force_svg_use(true);
             $themeconfig->set_rtl_mode(($direction === 'rtl'));
 
             $themecss[$direction] = $themeconfig->get_css_content();
             if ($cache) {
+                $themeconfig->set_css_content_cache($themecss[$direction]);
                 $filename = theme_get_css_filename($themeconfig->name, $themerev, $newrevision, $direction);
                 css_store_css($themeconfig, $filename, $themecss[$direction]);
             }
index 83c74a3..4fbdedc 100644 (file)
@@ -3259,6 +3259,10 @@ EOD;
 
         $contents = html_writer::tag('label', get_string('enteryoursearchquery', 'search'),
             array('for' => 'id_q_' . $id, 'class' => 'accesshide')) . html_writer::tag('input', '', $inputattrs);
+        if ($this->page->context && $this->page->context->contextlevel !== CONTEXT_SYSTEM) {
+            $contents .= html_writer::empty_tag('input', ['type' => 'hidden',
+                    'name' => 'context', 'value' => $this->page->context->id]);
+        }
         $searchinput = html_writer::tag('form', $contents, $formattrs);
 
         return html_writer::tag('div', $searchicon . $searchinput, array('class' => 'search-input-wrapper nav-link', 'id' => $id));
index 9e27b4b..a4d16e5 100644 (file)
@@ -1707,6 +1707,25 @@ class core_accesslib_testcase extends advanced_testcase {
         $generator = $this->getDataGenerator();
         $cap = 'moodle/course:view';
 
+        // The structure being created here is this:
+        //
+        // All tests work with the single capability 'moodle/course:view'.
+        //
+        //             ROLE DEF/OVERRIDE                        ROLE ASSIGNS
+        //    Role:  Allow    Prohib    Empty   Def user      u1  u2  u3  u4   u5  u6  u7  u8
+        // System    ALLOW    PROHIBIT                            A   E   A+E
+        //   cat1                       ALLOW
+        //     C1                               (ALLOW)                            P
+        //     C2             ALLOW                                                    E   P
+        //     cat2                     PREVENT
+        //       C3                     ALLOW                                      E
+        //       C4
+        //   Misc.                                                             A
+        //     C5    PREVENT                                                       A
+        //     C6                       PROHIBIT
+        //
+        // Front-page and guest role stuff from the end of this test not included in the diagram.
+
         // Create a role which allows course:view and one that prohibits it, and one neither.
         $allowroleid = $generator->create_role();
         $prohibitroleid = $generator->create_role();
@@ -1720,6 +1739,7 @@ class core_accesslib_testcase extends advanced_testcase {
         $cat2 = $generator->create_category(['parent' => $cat1->id]);
 
         // Create six courses - two in cat1, two in cat2, and two in default category.
+        // Shortnames are used for a sorting test. Otherwise they are not significant.
         $c1 = $generator->create_course(['category' => $cat1->id, 'shortname' => 'Z']);
         $c2 = $generator->create_course(['category' => $cat1->id, 'shortname' => 'Y']);
         $c3 = $generator->create_course(['category' => $cat2->id, 'shortname' => 'X']);
@@ -1741,6 +1761,8 @@ class core_accesslib_testcase extends advanced_testcase {
                 context_course::instance($c6->id)->id);
         assign_capability($cap, CAP_ALLOW, $emptyroleid,
                 context_course::instance($c3->id)->id);
+        assign_capability($cap, CAP_ALLOW, $prohibitroleid,
+                context_course::instance($c2->id)->id);
 
         // User 1 has no roles except default user role.
         $u1 = $generator->create_user();
@@ -1800,6 +1822,22 @@ class core_accesslib_testcase extends advanced_testcase {
         $courses = get_user_capability_course($cap, $u6->id, true, '', 'id');
         $this->assert_course_ids([$c3->id], $courses);
 
+        // User 7 has empty role in C2.
+        $u7 = $generator->create_user();
+        role_assign($emptyroleid, $u7->id, context_course::instance($c2->id)->id);
+
+        // Should get C1 by the default user role override, and C2 by the cat1 level override.
+        $courses = get_user_capability_course($cap, $u7->id, true, '', 'id');
+        $this->assert_course_ids([$c1->id, $c2->id], $courses);
+
+        // User 8 has prohibit role as system context, to verify that prohibits can't be overridden.
+        $u8 = $generator->create_user();
+        role_assign($prohibitroleid, $u8->id, context_course::instance($c2->id)->id);
+
+        // Should get C1 by the default user role override, no other courses because the prohibit cannot be overridden.
+        $courses = get_user_capability_course($cap, $u8->id, true, '', 'id');
+        $this->assert_course_ids([$c1->id], $courses);
+
         // Admin user gets everything....
         $courses = get_user_capability_course($cap, get_admin()->id, true, '', 'id');
         $this->assert_course_ids([SITEID, $c1->id, $c2->id, $c3->id, $c4->id, $c5->id, $c6->id],
index b6109d9..b6a1b7e 100644 (file)
@@ -1046,7 +1046,6 @@ EOF;
     public static function create_draft_file($filedata = array()) {
         global $USER;
 
-        self::setAdminUser();
         $fs = get_file_storage();
 
         $filerecord = array(
@@ -1208,7 +1207,9 @@ EOF;
         global $USER;
 
         $this->resetAfterTest(true);
-        $this->setAdminUser();
+        // The admin has no restriction for max file uploads, so use a normal user.
+        $user = $this->getDataGenerator()->create_user();
+        $this->setUser($user);
         $fs = get_file_storage();
 
         $file = self::create_draft_file();
index 2b2744a..f178315 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Unit tests for /lib/gradelib.php.
  *
- * @package   core_grade
+ * @package   core_grades
  * @category  phpunit
  * @copyright 2012 Andrew Davis
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 79b3fa9..cf94659 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_message_email_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 6db361a..616e44d 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_message_jabber_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index c82679c..455d89a 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_message_popup_upgrade($oldversion) {
     global $CFG, $DB;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     $dbman = $DB->get_manager();
 
     if ($oldversion < 2016052309) {
index fe87115..013eaa0 100644 (file)
@@ -34,9 +34,6 @@ function xmldb_assign_upgrade($oldversion) {
 
     $dbman = $DB->get_manager();
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     if ($oldversion < 2016100301) {
 
         // Define table assign_overrides to be created.
index 859ac0e..0288554 100644 (file)
@@ -32,9 +32,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_assignfeedback_comments_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 19882e3..18d5c3b 100644 (file)
@@ -34,31 +34,6 @@ function xmldb_assignfeedback_editpdf_upgrade($oldversion) {
 
     $dbman = $DB->get_manager();
 
-    if ($oldversion < 2016021600) {
-
-        // Define table assignfeedback_editpdf_queue to be created.
-        $table = new xmldb_table('assignfeedback_editpdf_queue');
-
-        // Adding fields to table assignfeedback_editpdf_queue.
-        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('submissionid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-        $table->add_field('submissionattempt', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
-
-        // Adding keys to table assignfeedback_editpdf_queue.
-        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
-
-        // Conditionally launch create table for assignfeedback_editpdf_queue.
-        if (!$dbman->table_exists($table)) {
-            $dbman->create_table($table);
-        }
-
-        // Editpdf savepoint reached.
-        upgrade_plugin_savepoint(true, 2016021600, 'assignfeedback', 'editpdf');
-    }
-
-    // Moodle v3.1.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Automatically generated Moodle v3.2.0 release upgrade line.
     // Put any upgrade step following this.
 
index 6aec217..fe6a7ec 100644 (file)
@@ -39,6 +39,8 @@ $string['command'] = 'Command:';
 $string['commentcontextmenu'] = 'Comment context menu';
 $string['couldnotsavepage'] = 'Could not save page {$a}';
 $string['currentstamp'] = 'Stamp';
+$string['default'] = 'Enabled by default';
+$string['default_help'] = 'If set, this feedback method will be enabled by default for all new assignments.';
 $string['deleteannotation'] = 'Delete annotation';
 $string['deletecomment'] = 'Delete comment';
 $string['deletefeedback'] = 'Delete feedback PDF';