Merge branch 'MDL-62944' of https://github.com/NeillM/moodle
authorDavid Monllao <davidm@moodle.com>
Tue, 4 Sep 2018 10:15:36 +0000 (12:15 +0200)
committerDavid Monllao <davidm@moodle.com>
Tue, 4 Sep 2018 10:15:36 +0000 (12:15 +0200)
27 files changed:
admin/environment.xml
blog/lib.php
course/lib.php
course/tests/courselib_test.php
filter/algebra/algebradebug.php
filter/tex/lib.php
filter/tex/texdebug.php
lang/en/admin.php
lang/en/error.php
lib/amd/build/form-autocomplete.min.js
lib/amd/src/form-autocomplete.js
lib/db/upgrade.php
lib/editor/atto/lib.php
lib/messagelib.php
lib/phpunit/tests/advanced_test.php
lib/templates/form_autocomplete_input.mustache
lib/tests/messagelib_test.php
lib/upgradelib.php
message/tests/externallib_test.php
mod/assign/lang/en/assign.php
mod/assign/locallib.php
mod/assign/mod_form.php
theme/boost/scss/moodle/core.scss
theme/boost/style/moodle.css
theme/boost/templates/core/form_autocomplete_input.mustache
user/lib.php
version.php

index 2b8d4ef..fbda3f3 100644 (file)
       </CUSTOM_CHECK>
     </CUSTOM_CHECKS>
   </MOODLE>
+  <MOODLE version="3.6" 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.6" />
+      <VENDOR name="postgres" version="9.4" />
+      <VENDOR name="mssql" version="10.0" />
+      <VENDOR name="oracle" version="11.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_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="sixtyfourbitswarning" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+    </CUSTOM_CHECKS>
+  </MOODLE>
 </COMPATIBILITY_MATRIX>
index 2e53d97..b81c645 100644 (file)
@@ -135,6 +135,25 @@ function blog_remove_associations_for_course($courseid) {
     $DB->delete_records('blog_association', array('contextid' => $context->id));
 }
 
+/**
+ * Remove module associated blogs and blog tag instances.
+ *
+ * @param  int $modcontextid Module context ID.
+ */
+function blog_remove_associations_for_module($modcontextid) {
+    global $DB;
+
+    if (!empty($assocblogids = $DB->get_fieldset_select('blog_association', 'blogid',
+        'contextid = :contextid', ['contextid' => $modcontextid]))) {
+        list($sql, $params) = $DB->get_in_or_equal($assocblogids, SQL_PARAMS_NAMED);
+
+        $DB->delete_records_select('tag_instance', "itemid $sql", $params);
+        $DB->delete_records_select('post', "id $sql AND module = :module",
+            array_merge($params, ['module' => 'blog']));
+        $DB->delete_records('blog_association', ['contextid' => $modcontextid]);
+    }
+}
+
 /**
  * Given a record in the {blog_external} table, checks the blog's URL
  * for new entries not yet copied into Moodle.
index bf54e66..aba5bdc 100644 (file)
@@ -1169,6 +1169,9 @@ function course_delete_module($cmid, $async = false) {
         }
     }
 
+    // Delete associated blogs and blog tag instances.
+    blog_remove_associations_for_module($modcontext->id);
+
     // Delete completion and availability data; it is better to do this even if the
     // features are not turned on, in case they were turned on previously (these will be
     // very quick on an empty table).
index 249948d..ce18504 100644 (file)
@@ -303,6 +303,50 @@ class core_course_courselib_testcase extends advanced_testcase {
         return $moduleinfo;
     }
 
+    /**
+     * Create module associated blog and tags.
+     *
+     * @param object $course Course.
+     * @param object $modulecontext The context of the module.
+     */
+    private function create_module_asscociated_blog($course, $modulecontext) {
+        global $DB, $CFG;
+
+        // Create default group.
+        $group = new stdClass();
+        $group->courseid = $course->id;
+        $group->name = 'Group';
+        $group->id = $DB->insert_record('groups', $group);
+
+        // Create default user.
+        $user = $this->getDataGenerator()->create_user(array(
+            'username' => 'testuser',
+            'firstname' => 'Firsname',
+            'lastname' => 'Lastname'
+        ));
+
+        // Create default post.
+        $post = new stdClass();
+        $post->userid = $user->id;
+        $post->groupid = $group->id;
+        $post->content = 'test post content text';
+        $post->module = 'blog';
+        $post->id = $DB->insert_record('post', $post);
+
+        // Create default tag.
+        $tag = $this->getDataGenerator()->create_tag(array('userid' => $user->id,
+            'rawname' => 'Testtagname', 'isstandard' => 1));
+        // Apply the tag to the blog.
+        $DB->insert_record('tag_instance', array('tagid' => $tag->id, 'itemtype' => 'user',
+            'component' => 'core', 'itemid' => $post->id, 'ordering' => 0));
+
+        require_once($CFG->dirroot . '/blog/locallib.php');
+        $blog = new blog_entry($post->id);
+        $blog->add_association($modulecontext->id);
+
+        return $blog;
+    }
+
     /**
      * Test create_module() for multiple modules defined in the $modules array (first declaration of the function).
      */
@@ -1521,6 +1565,8 @@ class core_course_courselib_testcase extends advanced_testcase {
         // Get the module context.
         $modcontext = context_module::instance($module->cmid);
 
+        $assocblog = $this->create_module_asscociated_blog($course, $modcontext);
+
         // Verify context exists.
         $this->assertInstanceOf('context_module', $modcontext);
 
@@ -1565,6 +1611,18 @@ class core_course_courselib_testcase extends advanced_testcase {
         $cmcount = $DB->count_records('course_modules', array('id' => $module->cmid));
         $this->assertEmpty($cmcount);
 
+        // Verify the blog_association record has been deleted.
+        $this->assertCount(0, $DB->get_records('blog_association',
+                array('contextid' => $modcontext->id)));
+
+        // Verify the blog post record has been deleted.
+        $this->assertCount(0, $DB->get_records('post',
+                array('id' => $assocblog->id)));
+
+        // Verify the tag instance record has been deleted.
+        $this->assertCount(0, $DB->get_records('tag_instance',
+                array('itemid' => $assocblog->id)));
+
         // Test clean up of module specific messes.
         switch ($type) {
             case 'assign':
index 52cf068..cf5bf96 100644 (file)
@@ -338,17 +338,8 @@ Mathematics Tools</a> forum in the Using Moodle course on moodle.org.</li>
 running Unix, a likely cause is that the mimetex binary you are using is
 incompatible with your operating system. You can try compiling it from the
 C sources downloaded from <a href="http://www.forkosh.com/mimetex.zip">
-http://www.forkosh.com/mimetex.zip</a>, or looking for an appropriate
-binary at <a href="http://moodle.org/download/mimetex/">
-http://moodle.org/download/mimetex/</a>. You may then also need to
-edit your moodle/filter/algebra/pix.php file to add
-<br /><?php echo "case &quot;" . PHP_OS . "&quot;:" ;?><br ?> to the list of operating systems
-in the switch (PHP_OS) statement. Windows users may have a problem properly
-unzipping mimetex.exe. Make sure that mimetex.exe is is <b>PRECISELY</b>
-433152 bytes in size. If not, download fresh copy from
-<a href="http://moodle.org/download/mimetex/windows/mimetex.exe">
-http://moodle.org/download/mimetex/windows/mimetex.exe</a>. Lastly check
-the execute permissions on your mimetex binary, as outlined in item 2 above.</li>
+http://www.forkosh.com/mimetex.zip</a>. Lastly check the execute permissions
+on your mimetex binary, as outlined in item 2 above.</li>
 </ol>
 </body>
 </html>
index 4aad3ec..f579fa5 100644 (file)
@@ -29,15 +29,6 @@ defined('MOODLE_INTERNAL') || die();
 function filter_tex_get_executable($debug=false) {
     global $CFG;
 
-    $error_message1 = "Your system is not configured to run mimeTeX. You need to download the appropriate<br />"
-                     ."executable for you ".PHP_OS." platform from <a href=\"http://moodle.org/download/mimetex/\">"
-                     ."http://moodle.org/download/mimetex/</a>, or obtain the C source<br /> "
-                     ."from <a href=\"http://www.forkosh.com/mimetex.zip\">"
-                     ."http://www.forkosh.com/mimetex.zip</a>, compile it and "
-                     ."put the executable into your<br /> moodle/filter/tex/ directory.";
-
-    $error_message2 = "Custom mimetex is not executable!<br /><br />";
-
     if ((PHP_OS == "WINNT") || (PHP_OS == "WIN32") || (PHP_OS == "Windows")) {
         return "$CFG->dirroot/filter/tex/mimetex.exe";
     }
index e713d57..dadbe18 100644 (file)
@@ -377,16 +377,7 @@ If this fails or is not available, the Mimetex executable is tried. If this
 fails a likely cause is that the mimetex binary you are using is
 incompatible with your operating system. You can try compiling it from the
 C sources downloaded from <a href="http://www.forkosh.com/mimetex.zip">
-http://www.forkosh.com/mimetex.zip</a>, or looking for an appropriate
-binary at <a href="http://moodle.org/download/mimetex/">
-http://moodle.org/download/mimetex/</a>. You may then also need to
-edit your moodle/filter/tex/pix.php file to add
-<br /><?php echo "case &quot;" . PHP_OS . "&quot;:" ;?><br ?> to the list of operating systems
-in the switch (PHP_OS) statement. Windows users may have a problem properly
-unzipping mimetex.exe. Make sure that mimetex.exe is is <b>PRECISELY</b>
-433152 bytes in size. If not, download a fresh copy from
-<a href="http://moodle.org/download/mimetex/windows/mimetex.exe">
-http://moodle.org/download/mimetex/windows/mimetex.exe</a>.
+http://www.forkosh.com/mimetex.zip</a>.
 Another possible problem which may affect
 both Unix and Windows servers is that the web server doesn't have execute permission
 on the mimetex binary. In that case change permissions accordingly</li>
index 6c38f65..500b20e 100644 (file)
@@ -1080,6 +1080,7 @@ $string['sitepolicyhandlerplugin'] = '{$a->name} ({$a->component})';
 $string['sitepolicyguest'] = 'Site policy URL for guests';
 $string['sitepolicyguest_help'] = 'The URL of the site policy that all guests must see and agree to before accessing the site. Note that this setting will only have an effect if the site policy handler is set to default (core).';
 $string['sitesectionhelp'] = 'If selected, a topic section will be displayed on the site\'s front page.';
+$string['sixtyfourbitswarning'] = 'It has been detected that your site is not using a 64-bit PHP version. It is recommended that you upgrade your site to ensure future compatibility.';
 $string['slasharguments'] = 'Use slash arguments';
 $string['slashargumentswarning'] = 'It is recommended that the use of slash arguments is enabled. In future it will be required. For more details, see the documentation <a href="https://docs.moodle.org/en/admin/environment/slasharguments">Using slash arguments</a>.';
 $string['smartpix'] = 'Smart pix search';
index f15f401..95b9450 100644 (file)
@@ -383,7 +383,7 @@ $string['loginasonecourse'] = 'You cannot enter this course.<br /> You have to t
 $string['maxbytesfile'] = 'The file {$a->file} is too large. The maximum size you can upload is {$a->size}.';
 $string['maxareabytes'] = 'The file is larger than the space remaining in this area.';
 $string['messagingdisable'] = 'Messaging is disabled on this site';
-$string['mimetexisnotexist'] = 'Your system is not configured to run mimeTeX. You need to download the appropriate executable for you PHP_OS platform from <a href="http://moodle.org/download/mimetex/">http://moodle.org/download/mimetex/</a>, or obtain the C source from <a href="http://www.forkosh.com/mimetex.zip"> http://www.forkosh.com/mimetex.zip</a>, compile it and put the executable into your moodle/filter/tex/ directory.';
+$string['mimetexisnotexist'] = 'Your system is not configured to run mimeTeX. You need to obtain the C source from <a href="http://www.forkosh.com/mimetex.zip">http://www.forkosh.com/mimetex.zip</a>, compile it and put the executable into your moodle/filter/tex/ directory.';
 $string['mimetexnotexecutable'] = 'Custom mimetex is not executable!';
 $string['missingfield'] = 'Field "{$a}" is missing';
 $string['missingkeyinsql'] = 'ERROR: missing param "{$a}" in query';
index 7755fdc..0369c31 100644 (file)
Binary files a/lib/amd/build/form-autocomplete.min.js and b/lib/amd/build/form-autocomplete.min.js differ
index b4c0053..58a7fc2 100644 (file)
@@ -882,9 +882,23 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
             context.options = suggestions;
             context.items = [];
 
-            var renderInput = templates.render('core/form_autocomplete_input', context);
-            var renderDatalist = templates.render('core/form_autocomplete_suggestions', context);
-            var renderSelection = templates.render('core/form_autocomplete_selection', context);
+            // Collect rendered inline JS to be executed once the HTML is shown.
+            var collectedjs = '';
+
+            var renderInput = templates.render('core/form_autocomplete_input', context).then(function(html, js) {
+                collectedjs += js;
+                return html;
+            });
+
+            var renderDatalist = templates.render('core/form_autocomplete_suggestions', context).then(function(html, js) {
+                collectedjs += js;
+                return html;
+            });
+
+            var renderSelection = templates.render('core/form_autocomplete_selection', context).then(function(html, js) {
+                collectedjs += js;
+                return html;
+            });
 
             return $.when(renderInput, renderDatalist, renderSelection).then(function(input, suggestions, selection) {
                 originalSelect.hide();
@@ -892,6 +906,8 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                 originalSelect.after(input);
                 originalSelect.after(selection);
 
+                templates.runTemplateJS(collectedjs);
+
                 // Update the form label to point to the text input.
                 originalLabel.attr('for', state.inputId);
                 // Add the event handlers.
index 8fbb66a..80f33f8 100644 (file)
@@ -2301,5 +2301,32 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2018073000.00);
     }
 
+    if ($oldversion < 2018083100.01) {
+        // Remove module associated blog posts for non-existent (deleted) modules.
+        $sql = "SELECT ba.contextid as modcontextid
+                  FROM {blog_association} ba
+                  JOIN {post} p
+                       ON p.id = ba.blogid
+             LEFT JOIN {context} c
+                       ON c.id = ba.contextid
+                 WHERE p.module = :module
+                       AND c.contextlevel IS NULL
+              GROUP BY ba.contextid";
+        if ($deletedmodules = $DB->get_records_sql($sql, array('module' => 'blog'))) {
+            foreach ($deletedmodules as $module) {
+                $assocblogids = $DB->get_fieldset_select('blog_association', 'blogid',
+                    'contextid = :contextid', ['contextid' => $module->modcontextid]);
+                list($sql, $params) = $DB->get_in_or_equal($assocblogids, SQL_PARAMS_NAMED);
+
+                $DB->delete_records_select('tag_instance', "itemid $sql", $params);
+                $DB->delete_records_select('post', "id $sql AND module = :module",
+                    array_merge($params, ['module' => 'blog']));
+                $DB->delete_records('blog_association', ['contextid' => $module->modcontextid]);
+            }
+        }
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2018083100.01);
+    }
+
     return true;
 }
index 220d1ef..bcd5c38 100644 (file)
@@ -180,8 +180,8 @@ class atto_texteditor extends texteditor {
         }
         $contentcss     = $PAGE->theme->editor_css_url()->out(false);
 
-        // Autosave disabled for guests.
-        if (isguestuser()) {
+        // Autosave disabled for guests and not logged in users.
+        if (isguestuser() OR !isloggedin()) {
             $autosave = false;
         }
         // Note <> is a safe separator, because it will not appear in the output of s().
index 060e508..16ccefe 100644 (file)
@@ -63,7 +63,8 @@ function message_send(\core\message\message $eventdata) {
     // Fetch default (site) preferences
     $defaultpreferences = get_message_output_default_preferences();
     $preferencebase = $eventdata->component.'_'.$eventdata->name;
-    // If message provider is disabled then don't do any processing.
+
+    // If the message provider is disabled via preferences, then don't send the message.
     if (!empty($defaultpreferences->{$preferencebase.'_disable'})) {
         return $messageid;
     }
@@ -88,6 +89,20 @@ function message_send(\core\message\message $eventdata) {
         return false;
     }
 
+    // If the provider's component is disabled or the user can't receive messages from it, don't send the message.
+    $isproviderallowed = false;
+    foreach (message_get_providers_for_user($eventdata->userto->id) as $provider) {
+        if ($provider->component === $eventdata->component && $provider->name === $eventdata->name) {
+            $isproviderallowed = true;
+            break;
+        }
+    }
+    if (!$isproviderallowed) {
+        debugging('Attempt to send msg from a provider '.$eventdata->component.'/'.$eventdata->name.
+            ' that is inactive or not allowed for the user id='.$eventdata->userto->id, DEBUG_NORMAL);
+        return false;
+    }
+
     // Verify all necessary data fields are present.
     if (!isset($eventdata->userto->auth) or !isset($eventdata->userto->suspended)
             or !isset($eventdata->userto->deleted) or !isset($eventdata->userto->emailstop)) {
index 2aaa254..39c7c16 100644 (file)
@@ -516,21 +516,16 @@ class core_phpunit_advanced_testcase extends advanced_testcase {
         $message3->smallmessage      = 'small message';
         $message3->notification      = 0;
 
-        try {
-            message_send($message3);
-            $this->fail('coding expcetion expected if invalid component specified');
-        } catch (moodle_exception $e) {
-            $this->assertInstanceOf('coding_exception', $e);
-        }
+        $this->assertFalse(message_send($message3));
+        $this->assertDebuggingCalled('Attempt to send msg from a provider xxxx_yyyyy/instantmessage '.
+            'that is inactive or not allowed for the user id='.$user1->id);
 
         $message3->component = 'moodle';
         $message3->name      = 'yyyyyy';
-        try {
-            message_send($message3);
-            $this->fail('coding expcetion expected if invalid name specified');
-        } catch (moodle_exception $e) {
-            $this->assertInstanceOf('coding_exception', $e);
-        }
+
+        $this->assertFalse(message_send($message3));
+        $this->assertDebuggingCalled('Attempt to send msg from a provider moodle/yyyyyy '.
+            'that is inactive or not allowed for the user id='.$user1->id);
 
         message_send($message1);
         $this->assertEquals(1, $sink->count());
index ad064f2..7bf5032 100644 (file)
 {{^showSuggestions}}
 <input type="text" id="{{inputId}}" placeholder="{{placeholder}}" role="textbox" aria-owns="{{selectionId}}"/>
 {{/showSuggestions}}
+
+{{#js}}
+require(['jquery'], function($) {
+    // Set the minimum width of the input so that the placeholder is whole displayed.
+    var inputElement = $(document.getElementById('{{inputId}}'));
+    if (inputElement.length) {
+        inputElement.css('min-width', inputElement.attr('placeholder').length + 'ch');
+    }
+});
+{{/js}}
index ed6e8ab..679175c 100644 (file)
@@ -287,6 +287,8 @@ class core_messagelib_testcase extends advanced_testcase {
             $this->assertInstanceOf('coding_exception', $e);
         }
         $this->assertCount(0, $sink->get_messages());
+        $this->assertDebuggingCalled('Attempt to send msg from a provider xxxxx/instantmessage '.
+            'that is inactive or not allowed for the user id='.$user2->id);
 
         $message->component = 'moodle';
         $message->name = 'xxx';
@@ -297,6 +299,8 @@ class core_messagelib_testcase extends advanced_testcase {
             $this->assertInstanceOf('coding_exception', $e);
         }
         $this->assertCount(0, $sink->get_messages());
+        $this->assertDebuggingCalled('Attempt to send msg from a provider moodle/xxx '.
+            'that is inactive or not allowed for the user id='.$user2->id);
         $sink->close();
         $this->assertFalse($DB->record_exists('messages', array()));
 
@@ -430,6 +434,7 @@ class core_messagelib_testcase extends advanced_testcase {
         $this->assertInstanceOf('\core\event\message_sent', $events[0]);
         $eventsink->clear();
 
+        // No messages are sent when the feature is disabled.
         $CFG->messaging = 0;
 
         $message = new \core\message\message();
@@ -446,20 +451,19 @@ class core_messagelib_testcase extends advanced_testcase {
         $message->notification      = '0';
 
         $messageid = message_send($message);
+        $this->assertFalse($messageid);
+        $this->assertDebuggingCalled('Attempt to send msg from a provider moodle/instantmessage '.
+            'that is inactive or not allowed for the user id='.$user2->id);
         $emails = $sink->get_messages();
         $this->assertCount(0, $emails);
-        $savedmessage = $DB->get_record('messages', array('id' => $messageid), '*', MUST_EXIST);
         $sink->clear();
-        $this->assertTrue($DB->record_exists('message_user_actions', array('userid' => $user2->id, 'messageid' => $messageid,
-            'action' => \core_message\api::MESSAGE_ACTION_READ)));
         $DB->delete_records('messages', array());
         $DB->delete_records('message_user_actions', array());
         $events = $eventsink->get_events();
-        $this->assertCount(2, $events);
-        $this->assertInstanceOf('\core\event\message_sent', $events[0]);
-        $this->assertInstanceOf('\core\event\message_viewed', $events[1]);
+        $this->assertCount(0, $events);
         $eventsink->clear();
 
+        // Example of a message that is sent and viewed.
         $CFG->messaging = 1;
 
         $message = new \core\message\message();
index 6f35c36..f83ad6c 100644 (file)
@@ -2338,6 +2338,22 @@ function check_is_https(environment_results $result) {
     return null;
 }
 
+/**
+ * Check if the site is using 64 bits PHP.
+ *
+ * @param  environment_results $result
+ * @return environment_results|null updated results object, or null if the site is using 64 bits PHP.
+ */
+function check_sixtyfour_bits(environment_results $result) {
+
+    if (PHP_INT_SIZE === 4) {
+         $result->setInfo('php not 64 bits');
+         $result->setStatus(false);
+         return $result;
+    }
+    return null;
+}
+
 /**
  * Assert the upgrade key is provided, if it is defined.
  *
index 9ae8b7e..f78cc46 100644 (file)
@@ -534,9 +534,10 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
         // Now, create some notifications...
         // We are creating fake notifications but based on real ones.
 
-        // This one omits notification = 1.
+        // This one comes from a disabled plugin's provider and therefore is not sent.
         $eventdata = new \core\message\message();
         $eventdata->courseid          = $course->id;
+        $eventdata->notification      = 1;
         $eventdata->modulename        = 'moodle';
         $eventdata->component         = 'enrol_paypal';
         $eventdata->name              = 'paypal_enrolment';
@@ -548,6 +549,24 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
         $eventdata->fullmessagehtml   = '';
         $eventdata->smallmessage      = '';
         message_send($eventdata);
+        $this->assertDebuggingCalled('Attempt to send msg from a provider enrol_paypal/paypal_enrolment '.
+            'that is inactive or not allowed for the user id='.$user1->id);
+
+        // This one omits notification = 1.
+        $message = new \core\message\message();
+        $message->courseid          = $course->id;
+        $message->component         = 'enrol_manual';
+        $message->name              = 'expiry_notification';
+        $message->userfrom          = $user2;
+        $message->userto            = $user1;
+        $message->subject           = 'Test: This is not a notification but otherwise is valid';
+        $message->fullmessage       = 'Test: Full message';
+        $message->fullmessageformat = FORMAT_MARKDOWN;
+        $message->fullmessagehtml   = markdown_to_html($message->fullmessage);
+        $message->smallmessage      = $message->subject;
+        $message->contexturlname    = $course->fullname;
+        $message->contexturl        = (string)new moodle_url('/course/view.php', array('id' => $course->id));
+        message_send($message);
 
         $message = new \core\message\message();
         $message->courseid          = $course->id;
index 06775e5..624e4d9 100644 (file)
@@ -134,8 +134,8 @@ $string['currentattemptof'] = 'This is attempt {$a->attemptnumber} ( {$a->maxatt
 $string['cutoffdate'] = 'Cut-off date';
 $string['cutoffdatecolon'] = 'Cut-off date: {$a}';
 $string['cutoffdate_help'] = 'If set, the assignment will not accept submissions after this date without an extension.';
-$string['cutoffdatevalidation'] = 'The cut-off date cannot be earlier than the due date.';
-$string['cutoffdatefromdatevalidation'] = 'Cut-off date must be after the allow submissions from date.';
+$string['cutoffdatevalidation'] = 'Cut-off date cannot be earlier than the due date.';
+$string['cutoffdatefromdatevalidation'] = 'Cut-off date cannot be earlier than the allow submissions from date.';
 $string['defaultlayout'] = 'Restore default layout';
 $string['defaultsettings'] = 'Default assignment settings';
 $string['defaultsettings_help'] = 'These settings define the defaults for all new assignments.';
@@ -157,7 +157,7 @@ $string['submissionempty'] = 'Nothing was submitted';
 $string['submissionmodified'] = 'You have existing submission data. Please leave this page and try again.';
 $string['submissionmodifiedgroup'] = 'The submission has been modified by somebody else. Please leave this page and try again.';
 $string['duedatereached'] = 'The due date for this assignment has now passed';
-$string['duedatevalidation'] = 'Due date must be after the allow submissions from date.';
+$string['duedatevalidation'] = 'Due date cannot be earlier than the allow submissions from date.';
 $string['editattemptfeedback'] = 'Edit the grade and feedback for attempt number {$a}.';
 $string['editonline'] = 'Edit online';
 $string['editingpreviousfeedbackwarning'] = 'You are editing the feedback for a previous attempt. This is attempt {$a->attemptnumber} out of {$a->totalattempts}.';
index 22398d7..a2dd3e4 100644 (file)
@@ -274,7 +274,10 @@ class assign {
     public function get_return_params() {
         global $PAGE;
 
-        $params = $PAGE->url->params();
+        $params = array();
+        if (!WS_SERVER) {
+            $params = $PAGE->url->params();
+        }
         unset($params['id']);
         unset($params['action']);
         return $params;
index ffb9a15..4cfc941 100644 (file)
@@ -223,18 +223,18 @@ class mod_assign_mod_form extends moodleform_mod {
     public function validation($data, $files) {
         $errors = parent::validation($data, $files);
 
-        if ($data['allowsubmissionsfromdate'] && $data['duedate']) {
-            if ($data['allowsubmissionsfromdate'] > $data['duedate']) {
+        if (!empty($data['allowsubmissionsfromdate']) && !empty($data['duedate'])) {
+            if ($data['duedate'] < $data['allowsubmissionsfromdate']) {
                 $errors['duedate'] = get_string('duedatevalidation', 'assign');
             }
         }
-        if ($data['duedate'] && $data['cutoffdate']) {
-            if ($data['duedate'] > $data['cutoffdate']) {
+        if (!empty($data['cutoffdate']) && !empty($data['duedate'])) {
+            if ($data['cutoffdate'] < $data['duedate'] ) {
                 $errors['cutoffdate'] = get_string('cutoffdatevalidation', 'assign');
             }
         }
-        if ($data['allowsubmissionsfromdate'] && $data['cutoffdate']) {
-            if ($data['allowsubmissionsfromdate'] > $data['cutoffdate']) {
+        if (!empty($data['allowsubmissionsfromdate']) && !empty($data['cutoffdate'])) {
+            if ($data['cutoffdate'] < $data['allowsubmissionsfromdate']) {
                 $errors['cutoffdate'] = get_string('cutoffdatefromdatevalidation', 'assign');
             }
         }
index af836a3..02806c6 100644 (file)
@@ -10,6 +10,7 @@ $bg-inverse-link-color: #fff !default;
     overflow-y: visible;
     border: $card-border-width solid $card-border-color;
     padding: $card-spacer-x;
+    background-color: $body-bg;
 }
 
 .context-header-settings-menu,
index 808ef33..f28c297 100644 (file)
@@ -8794,7 +8794,8 @@ input[disabled] {
   overflow-x: auto;
   overflow-y: visible;
   border: 1px solid rgba(0, 0, 0, 0.125);
-  padding: 1.25rem; }
+  padding: 1.25rem;
+  background-color: #fff; }
 
 .context-header-settings-menu,
 .region-main-settings-menu {
index f8d9293..0d2b966 100644 (file)
 {{^showSuggestions}}
 <input type="text" id="{{inputId}}" placeholder="{{placeholder}}" role="textbox" aria-owns="{{selectionId}}"/>
 {{/showSuggestions}}
+
+{{#js}}
+require(['jquery'], function($) {
+    // Set the minimum width of the input so that the placeholder is whole displayed.
+    var inputElement = $(document.getElementById('{{inputId}}'));
+    if (inputElement.length) {
+        inputElement.css('min-width', inputElement.attr('placeholder').length + 'ch');
+    }
+});
+{{/js}}
index f7008b5..e42ae41 100644 (file)
@@ -1505,7 +1505,7 @@ function user_get_course_lastaccess_sql($accesssince = null, $tableprefix = 'ul'
     if ($accesssince == -1) { // Never.
         return $tableprefix . '.timeaccess = 0';
     } else {
-        return $tableprefix . '.timeaccess != 0 AND ul.timeaccess < ' . $accesssince;
+        return $tableprefix . '.timeaccess != 0 AND ' . $tableprefix . '.timeaccess < ' . $accesssince;
     }
 }
 
@@ -1524,7 +1524,7 @@ function user_get_user_lastaccess_sql($accesssince = null, $tableprefix = 'u') {
     if ($accesssince == -1) { // Never.
         return $tableprefix . '.lastaccess = 0';
     } else {
-        return $tableprefix . '.lastaccess != 0 AND u.lastaccess < ' . $accesssince;
+        return $tableprefix . '.lastaccess != 0 AND ' . $tableprefix . '.lastaccess < ' . $accesssince;
     }
 }
 
index 6bfb060..4a22036 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2018083100.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2018083100.01;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.