Merge branch 'MDL-56041-custom-error-pages' of https://github.com/brendanheywood...
authorJake Dallimore <jake@moodle.com>
Wed, 8 Jul 2020 01:33:46 +0000 (09:33 +0800)
committerJake Dallimore <jake@moodle.com>
Wed, 8 Jul 2020 01:33:46 +0000 (09:33 +0800)
40 files changed:
admin/settings/security.php
admin/tasklogs.php
admin/tool/log/store/legacy/tests/store_test.php
auth/oauth2/classes/auth.php
blocks/blog_menu/block_blog_menu.php
cache/upgrade.txt
enrol/manual/ajax.php
lang/en/admin.php
lib/behat/behat_base.php
lib/classes/lock/db_record_lock_factory.php
lib/classes/lock/file_lock_factory.php
lib/classes/lock/installation_lock_factory.php
lib/classes/lock/lock.php
lib/classes/lock/lock_factory.php
lib/classes/lock/mysql_lock_factory.php
lib/classes/lock/postgres_lock_factory.php
lib/classes/output/icon_system.php
lib/classes/output/icon_system_fontawesome.php
lib/deprecatedlib.php
lib/setuplib.php
lib/tablelib.php
lib/tests/behat/behat_deprecated.php
lib/tests/behat/behat_navigation.php
lib/tests/event_test.php
lib/tests/lock_test.php
lib/tests/setuplib_test.php
lib/upgrade.txt
lib/weblib.php
message/externallib.php
message/tests/externallib_test.php
message/tests/messagelib_test.php
mod/assign/feedback/editpdf/classes/task/convert_submissions.php
mod/lti/templates/tool_card.mustache
mod/scorm/report/basic/classes/report.php
mod/scorm/report/graphs/classes/report.php
mod/scorm/report/interactions/classes/report.php
mod/scorm/report/objectives/classes/report.php
theme/boost/amd/build/pending.min.js
theme/boost/amd/build/pending.min.js.map
theme/boost/amd/src/pending.js

index d8dc48a..77dfb42 100644 (file)
@@ -160,6 +160,23 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $temp->add(new admin_setting_configportlist('curlsecurityallowedport',
                new lang_string('curlsecurityallowedport', 'admin'),
                new lang_string('curlsecurityallowedportsyntax', 'admin'), ""));
+
+    // HTTP Header referrer policy settings.
+    $referreroptions = [
+        'default' => get_string('referrernone', 'admin'),
+        'no-referrer' => 'no-referrer',
+        'no-referrer-when-downgrade' => 'no-referrer-when-downgrade',
+        'origin' => 'origin',
+        'origin-when-cross-origin' => 'origin-when-cross-origin',
+        'same-origin' => 'same-origin',
+        'strict-origin' => 'strict-origin',
+        'strict-origin-when-cross-origin' => 'strict-origin-when-cross-origin',
+        'unsafe-url' => 'unsafe-url',
+    ];
+    $temp->add(new admin_setting_configselect('referrerpolicy',
+            new lang_string('referrerpolicy', 'admin'),
+            new lang_string('referrerpolicydesc', 'admin'), 'default', $referreroptions));
+
     $ADMIN->add('security', $temp);
 
     // "notifications" settingpage
index 796f323..a91faa3 100644 (file)
@@ -66,7 +66,7 @@ echo $OUTPUT->header();
 // Output the search form.
 echo $OUTPUT->render_from_template('core_admin/tasklogs', (object) [
     'action' => $pageurl->out(),
-    'filter' => $filter,
+    'filter' => htmlentities($filter),
     'resultfilteroptions' => [
         (object) [
             'value' => -1,
index a2aeb98..f0a95a3 100644 (file)
@@ -34,11 +34,9 @@ class logstore_legacy_store_testcase extends advanced_testcase {
 
         $this->setAdminUser();
         $user1 = $this->getDataGenerator()->create_user();
-        $user2 = $this->getDataGenerator()->create_user();
         $course1 = $this->getDataGenerator()->create_course();
         $module1 = $this->getDataGenerator()->create_module('resource', array('course' => $course1));
         $course2 = $this->getDataGenerator()->create_course();
-        $module2 = $this->getDataGenerator()->create_module('resource', array('course' => $course2));
 
         // Enable legacy logging plugin.
         set_config('enabled_stores', 'logstore_legacy', 'tool_log');
@@ -68,15 +66,8 @@ class logstore_legacy_store_testcase extends advanced_testcase {
             array('context' => context_course::instance($course2->id), 'other' => array('sample' => 6, 'xx' => 11)));
         $event2->trigger();
 
-        $this->setUser($user2);
-        add_to_log($course1->id, 'xxxx', 'yyyy', '', '7', 0, 0);
-        $this->assertDebuggingCalled();
-
-        add_to_log($course2->id, 'aaa', 'bbb', 'info.php', '666', $module2->cmid, $user1->id);
-        $this->assertDebuggingCalled();
-
         $logs = $DB->get_records('log', array(), 'id ASC');
-        $this->assertCount(4, $logs);
+        $this->assertCount(2, $logs);
 
         $log = array_shift($logs);
         $this->assertNotEmpty($log->id);
@@ -104,34 +95,6 @@ class logstore_legacy_store_testcase extends advanced_testcase {
         $this->assertSame('unittest.php?id=6', $log->url);
         $this->assertSame('bbb', $log->info);
 
-        $oldlogid = $log->id;
-        $log = array_shift($logs);
-        $this->assertGreaterThan($oldlogid, $log->id);
-        $this->assertNotEmpty($log->id);
-        $this->assertTimeCurrent($log->time);
-        $this->assertEquals($user2->id, $log->userid);
-        $this->assertSame('0.0.0.0', $log->ip);
-        $this->assertEquals($course1->id, $log->course);
-        $this->assertSame('xxxx', $log->module);
-        $this->assertEquals(0, $log->cmid);
-        $this->assertSame('yyyy', $log->action);
-        $this->assertSame('', $log->url);
-        $this->assertSame('7', $log->info);
-
-        $oldlogid = $log->id;
-        $log = array_shift($logs);
-        $this->assertGreaterThan($oldlogid, $log->id);
-        $this->assertNotEmpty($log->id);
-        $this->assertTimeCurrent($log->time);
-        $this->assertEquals($user1->id, $log->userid);
-        $this->assertSame('0.0.0.0', $log->ip);
-        $this->assertEquals($course2->id, $log->course);
-        $this->assertSame('aaa', $log->module);
-        $this->assertEquals($module2->cmid, $log->cmid);
-        $this->assertSame('bbb', $log->action);
-        $this->assertSame('info.php', $log->url);
-        $this->assertSame('666', $log->info);
-
         // Test if disabling works.
         set_config('enabled_stores', 'logstore_legacy', 'tool_log');
         set_config('loglegacy', 0, 'logstore_legacy');
@@ -142,9 +105,7 @@ class logstore_legacy_store_testcase extends advanced_testcase {
 
         \logstore_legacy\event\unittest_executed::create(
             array('context' => \context_system::instance(), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
-        add_to_log($course1->id, 'xxxx', 'yyyy', '', '7', 0, 0);
-        $this->assertDebuggingCalled();
-        $this->assertEquals(4, $DB->count_records('log'));
+        $this->assertEquals(2, $DB->count_records('log'));
 
         // Another way to disable legacy completely.
         set_config('enabled_stores', 'logstore_standard', 'tool_log');
@@ -153,9 +114,7 @@ class logstore_legacy_store_testcase extends advanced_testcase {
 
         \logstore_legacy\event\unittest_executed::create(
             array('context' => \context_system::instance(), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
-        add_to_log($course1->id, 'xxxx', 'yyyy', '', '7', 0, 0);
-        $this->assertDebuggingCalled();
-        $this->assertEquals(4, $DB->count_records('log'));
+        $this->assertEquals(2, $DB->count_records('log'));
         // Set everything back.
         set_config('enabled_stores', '', 'tool_log');
         set_config('loglegacy', 0, 'logstore_legacy');
index 1d1ff6f..cf6fcfd 100644 (file)
@@ -455,8 +455,9 @@ class auth extends \auth_plugin_base {
             }
         }
 
+        $issuer = $client->get_issuer();
         // First we try and find a defined mapping.
-        $linkedlogin = api::match_username_to_user($userinfo['username'], $client->get_issuer());
+        $linkedlogin = api::match_username_to_user($userinfo['username'], $issuer);
 
         if (!empty($linkedlogin) && empty($linkedlogin->get('confirmtoken'))) {
             $mappeduser = get_complete_user_data('id', $linkedlogin->get('userid'));
@@ -474,7 +475,7 @@ class auth extends \auth_plugin_base {
                 $SESSION->loginerrormsg = get_string('invalidlogin');
                 $client->log_out();
                 redirect(new moodle_url('/login/index.php'));
-            } else if ($mappeduser && $mappeduser->confirmed) {
+            } else if ($mappeduser && ($mappeduser->confirmed || !$issuer->get('requireconfirmation'))) {
                 // Update user fields.
                 $userinfo = $this->update_user($userinfo, $mappeduser);
                 $userwasmapped = true;
@@ -503,7 +504,7 @@ class auth extends \auth_plugin_base {
             redirect(new moodle_url('/login/index.php'));
         }
 
-        $issuer = $client->get_issuer();
+
         if (!$issuer->is_valid_login_domain($oauthemail)) {
             // Trigger login failed event.
             $failurereason = AUTH_LOGIN_UNAUTHORISED;
index 71fd422..7bc53b1 100644 (file)
@@ -99,10 +99,14 @@ class block_blog_menu extends block_base {
         // Prepare the footer for this block
         if (has_capability('moodle/blog:search', context_system::instance())) {
             // Full-text search field
-            $form  = html_writer::tag('label', get_string('search', 'admin'), array('for'=>'blogsearchquery', 'class'=>'accesshide'));
-            $form .= html_writer::empty_tag('input', array('id'=>'blogsearchquery', 'type'=>'text', 'name'=>'search'));
-            $form .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('search')));
-            $this->content->footer = html_writer::tag('form', html_writer::tag('div', $form), array('class'=>'blogsearchform', 'method'=>'get', 'action'=>new moodle_url('/blog/index.php')));
+            $form  = html_writer::tag('label', get_string('search', 'admin'), array('for' => 'blogsearchquery',
+                'class' => 'accesshide'));
+            $form .= html_writer::empty_tag('input', array('id' => 'blogsearchquery', 'class' => 'form-control mr-1',
+                'type' => 'text', 'name' => 'search'));
+            $form .= html_writer::empty_tag('input', array('type' => 'submit', 'class' => 'btn btn-secondary',
+                'value' => get_string('search')));
+            $this->content->footer = html_writer::tag('form', html_writer::tag('div', $form), array(
+                'class' => 'blogsearchform form-inline', 'method' => 'get', 'action' => new moodle_url('/blog/index.php')));
         } else {
             // No footer to display
             $this->content->footer = '';
index 076bd53..7563077 100644 (file)
@@ -1,6 +1,12 @@
 This files describes API changes in /cache/stores/* - cache store plugins.
 Information provided here is intended especially for developers.
 
+=== 4.0 ===
+* The function supports_recursion() from the lock_factory interface has been deprecated including the related implementations.
+* The function extend_lock() from the lock_factory interface has been deprecated without replacement including the related
+  implementations.
+* The function extend() from the lock class has been deprecated without replacement.
+
 === 3.9 ===
 * The record_cache_hit/miss/set methods now take a cache_store instead of a cache_definition object
 
index 29cb40e..22ccef2 100644 (file)
@@ -100,6 +100,13 @@ switch ($action) {
 
         if (empty($roleid)) {
             $roleid = null;
+        } else {
+            if (!has_capability('moodle/role:assign', $context)) {
+                throw new enrol_ajax_exception('assignnotpermitted');
+            }
+            if (!array_key_exists($roleid, get_assignable_roles($context, ROLENAME_ALIAS, false))) {
+                throw new enrol_ajax_exception('invalidrole');
+            }
         }
 
         if (empty($startdate)) {
index 31c4acb..9ee6a8b 100644 (file)
@@ -1070,6 +1070,9 @@ $string['purgeselectedcaches'] = 'Purge selected caches';
 $string['purgeselectedcachesfinished'] = 'The selected caches were purged.';
 $string['purgetemplates'] = 'Templates';
 $string['purgethemecache'] = 'Themes';
+$string['referrernone'] = 'Browser default';
+$string['referrerpolicy'] = 'Referrer policy';
+$string['referrerpolicydesc'] = 'Set the referrer policy header to be included with responses from your site.';
 $string['restorecourse'] = 'Restore course';
 $string['restorernewroleid'] = 'Restorers\' role in courses';
 $string['restorernewroleid_help'] = 'If the user does not already have the permission to manage the newly restored course, the user is automatically assigned this role and enrolled if necessary. Select "None" if you do not want restorers to be able to manage every restored course.';
index 729ac1e..c97f492 100644 (file)
@@ -119,6 +119,11 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
      * @return NodeElement
      */
     protected function find($selector, $locator, $exception = false, $node = false, $timeout = false) {
+        if ($selector === 'NodeElement' && is_a($locator, NodeElement::class)) {
+            // Support a NodeElement being passed in for use in step chaining.
+            return $locator;
+        }
+
         // Returns the first match.
         $items = $this->find_all($selector, $locator, $exception, $node, $timeout);
         return count($items) ? reset($items) : null;
index e430bc5..4dfec49 100644 (file)
@@ -91,9 +91,13 @@ class db_record_lock_factory implements lock_factory {
 
     /**
      * Multiple locks for the same resource can be held by a single process.
+     *
+     * @deprecated since Moodle 4.0.
      * @return boolean - False - not process specific.
      */
     public function supports_recursion() {
+        debugging('The function supports_recursion() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
         return false;
     }
 
@@ -187,11 +191,16 @@ class db_record_lock_factory implements lock_factory {
 
     /**
      * Extend a lock that was previously obtained with @lock.
+     *
+     * @deprecated since Moodle 4.0.
      * @param lock $lock - a lock obtained from this factory.
      * @param int $maxlifetime - the new lifetime for the lock (in seconds).
      * @return boolean - true if the lock was extended.
      */
     public function extend_lock(lock $lock, $maxlifetime = 86400) {
+        debugging('The function extend_lock() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
+
         $now = time();
         $expires = $now + $maxlifetime;
         $params = array('expires' => $expires,
index dd20e9b..b771639 100644 (file)
@@ -108,9 +108,13 @@ class file_lock_factory implements lock_factory {
 
     /**
      * Multiple locks for the same resource cannot be held from a single process.
+     *
+     * @deprecated since Moodle 4.0.
      * @return boolean - False
      */
     public function supports_recursion() {
+        debugging('The function supports_recursion() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
         return false;
     }
 
@@ -188,11 +192,15 @@ class file_lock_factory implements lock_factory {
 
     /**
      * Extend a lock that was previously obtained with @lock.
+     *
+     * @deprecated since Moodle 4.0.
      * @param lock $lock - not used
      * @param int $maxlifetime - not used
      * @return boolean - true if the lock was extended.
      */
     public function extend_lock(lock $lock, $maxlifetime = 86400) {
+        debugging('The function extend_lock() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
         // Not supported by this factory.
         return false;
     }
index 5200cab..0874ced 100644 (file)
@@ -76,9 +76,12 @@ class installation_lock_factory implements lock_factory {
     /**
      * Multiple locks for the same resource cannot be held from a single process.
      *
+     * @deprecated since Moodle 4.0.
      * @return boolean - False
      */
     public function supports_recursion() {
+        debugging('The function supports_recursion() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
         return false;
     }
 
@@ -115,11 +118,14 @@ class installation_lock_factory implements lock_factory {
     /**
      * Extend a lock that was previously obtained with @lock.
      *
+     * @deprecated since Moodle 4.0.
      * @param lock $lock - not used
      * @param int $maxlifetime - not used
      * @return boolean - true if the lock was extended.
      */
     public function extend_lock(lock $lock, $maxlifetime = 86400) {
+        debugging('The function extend_lock() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
         // Not supported by this factory.
         return false;
     }
index 7b117c3..f67083c 100644 (file)
@@ -80,10 +80,15 @@ class lock {
 
     /**
      * Extend the lifetime of this lock. Not supported by all factories.
+     *
+     * @deprecated since Moodle 4.0.
      * @param int $maxlifetime - the new lifetime for the lock (in seconds).
      * @return bool
      */
     public function extend($maxlifetime = 86400) {
+        debugging('The function extend() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
+
         if ($this->factory) {
             return $this->factory->extend_lock($this, $maxlifetime);
         }
index b03e774..c0d32b0 100644 (file)
@@ -63,6 +63,7 @@ interface lock_factory {
     /**
      * Supports recursion.
      *
+     * @deprecated since Moodle 4.0.
      * @return boolean - True if attempting to get 2 locks on the same resource will "stack"
      */
     public function supports_recursion();
@@ -98,6 +99,7 @@ interface lock_factory {
     /**
      * Extend the timeout on a held lock.
      *
+     * @deprecated since Moodle 4.0.
      * @param lock $lock - lock obtained from this factory
      * @param int $maxlifetime - new max time to hold the lock
      * @return boolean - True if the lock was extended.
index 6f05924..753741b 100644 (file)
@@ -106,9 +106,12 @@ class mysql_lock_factory implements lock_factory {
      * Hard coded to false and workaround inconsistent support in different
      * versions of MySQL / MariaDB.
      *
+     * @deprecated since Moodle 4.0.
      * @return boolean - false
      */
     public function supports_recursion() {
+        debugging('The function supports_recursion() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
         return false;
     }
 
@@ -165,11 +168,15 @@ class mysql_lock_factory implements lock_factory {
 
     /**
      * Extend a lock that was previously obtained with @lock.
+     *
+     * @deprecated since Moodle 4.0.
      * @param lock $lock - a lock obtained from this factory.
      * @param int $maxlifetime - the new lifetime for the lock (in seconds).
      * @return boolean - true if the lock was extended.
      */
     public function extend_lock(lock $lock, $maxlifetime = 86400) {
+        debugging('The function extend_lock() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
         // Not supported by this factory.
         return false;
     }
index 0d48eaa..1d18967 100644 (file)
@@ -118,11 +118,15 @@ class postgres_lock_factory implements lock_factory {
     }
 
     /**
-     * Multiple locks for the same resource can be held by a single process.
-     * @return boolean - Defer to the DB driver.
+     * Multiple locks for the same resource can NOT be held by a single process.
+     *
+     * @deprecated since Moodle 4.0.
+     * @return boolean - false.
      */
     public function supports_recursion() {
-        return true;
+        debugging('The function supports_recursion() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
+        return false;
     }
 
     /**
@@ -145,6 +149,7 @@ class postgres_lock_factory implements lock_factory {
 
     /**
      * Create and get a lock
+     *
      * @param string $resource - The identifier for the lock. Should use frankenstyle prefix.
      * @param int $timeout - The number of seconds to wait for a lock before giving up.
      * @param int $maxlifetime - Unused by this lock type.
@@ -155,8 +160,14 @@ class postgres_lock_factory implements lock_factory {
 
         $token = $this->get_index_from_key($this->type . '_' . $resource);
 
-        $params = array('locktype' => $this->dblockid,
-                        'token' => $token);
+        if (isset($this->openlocks[$token])) {
+            return false;
+        }
+
+        $params = [
+            'locktype' => $this->dblockid,
+            'token' => $token
+        ];
 
         $locked = false;
 
@@ -194,11 +205,15 @@ class postgres_lock_factory implements lock_factory {
 
     /**
      * Extend a lock that was previously obtained with @lock.
+     *
+     * @deprecated since Moodle 4.0.
      * @param lock $lock - a lock obtained from this factory.
      * @param int $maxlifetime - the new lifetime for the lock (in seconds).
      * @return boolean - true if the lock was extended.
      */
     public function extend_lock(lock $lock, $maxlifetime = 86400) {
+        debugging('The function extend_lock() is deprecated, please do not use it anymore.',
+            DEBUG_DEVELOPER);
         // Not supported by this factory.
         return false;
     }
index 08e88b5..14e1075 100644 (file)
@@ -72,22 +72,22 @@ abstract class icon_system {
     /**
      * Factory method
      *
-     * @param $type Either a specific type, or null to get the default type.
+     * @param string $type Either a specific type, or null to get the default type.
      * @return \core\output\icon_system
      */
     public final static function instance($type = null) {
         global $PAGE;
 
-        if ($type == null) {
-            if (!empty(self::$instance)) {
-                return self::$instance;
-            }
-            $type = $PAGE->theme->get_icon_system();
-            self::$instance = new $type();
-            // Default one is a singleton.
+        if (empty(self::$instance)) {
+            $icontype = $PAGE->theme->get_icon_system();
+            self::$instance = new $icontype();
+        }
+
+        // If $type is specified we need to make sure that the theme icon system supports this type,
+        // if not, we will return a generic new instance of the $type.
+        if ($type === null || is_a(self::$instance, $type)) {
             return self::$instance;
         } else {
-            // Not a singleton.
             return new $type();
         }
     }
index ba4ccdb..38ad233 100644 (file)
@@ -440,7 +440,10 @@ class icon_system_fontawesome extends icon_system_font {
         if ($this->map === []) {
             $cache = \cache::make('core', 'fontawesomeiconmapping');
 
-            $this->map = $cache->get('mapping');
+            // Create different mapping keys for different icon system classes, there may be several different
+            // themes on the same site.
+            $mapkey = 'mapping_'.preg_replace('/[^a-zA-Z0-9_]/', '_', get_class($this));
+            $this->map = $cache->get($mapkey);
 
             if (empty($this->map)) {
                 $this->map = $this->get_core_icon_map();
@@ -454,7 +457,7 @@ class icon_system_fontawesome extends icon_system_font {
                         }
                     }
                 }
-                $cache->set('mapping', $this->map);
+                $cache->set($mapkey, $this->map);
             }
 
         }
index 1327d93..c28996f 100644 (file)
@@ -33,28 +33,10 @@ defined('MOODLE_INTERNAL') || die();
 /* === Functions that needs to be kept longer in deprecated lib than normal time period === */
 
 /**
- * Add an entry to the legacy log table.
- *
  * @deprecated since 2.7 use new events instead
- *
- * @param    int     $courseid  The course id
- * @param    string  $module  The module name  e.g. forum, journal, resource, course, user etc
- * @param    string  $action  'view', 'update', 'add' or 'delete', possibly followed by another word to clarify.
- * @param    string  $url     The file and parameters used to see the results of the action
- * @param    string  $info    Additional description information
- * @param    int     $cm      The course_module->id if there is one
- * @param    int|stdClass $user If log regards $user other than $USER
- * @return void
- */
-function add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user=0) {
-    debugging('add_to_log() has been deprecated, please rewrite your code to the new events API', DEBUG_DEVELOPER);
-
-    // This is a nasty hack that allows us to put all the legacy stuff into legacy storage,
-    // this way we may move all the legacy settings there too.
-    $manager = get_log_manager();
-    if (method_exists($manager, 'legacy_add_to_log')) {
-        $manager->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user);
-    }
+ */
+function add_to_log() {
+    throw new coding_exception('add_to_log() has been removed, please rewrite your code to the new events API');
 }
 
 /**
@@ -766,57 +748,12 @@ function print_side_block() {
 }
 
 /**
- * Prints a basic textarea field.
- *
- * This was 'deprecated' in 2.0, but not properly (there was no alternative) so the
- * debugging message was commented out.
- *
  * @deprecated since Moodle 3.6
- *
- * When using this function, you should
- *
- * @global object
- * @param bool $unused No longer used.
- * @param int $rows Number of rows to display  (minimum of 10 when $height is non-null)
- * @param int $cols Number of columns to display (minimum of 65 when $width is non-null)
- * @param null $width (Deprecated) Width of the element; if a value is passed, the minimum value for $cols will be 65. Value is otherwise ignored.
- * @param null $height (Deprecated) Height of the element; if a value is passe, the minimum value for $rows will be 10. Value is otherwise ignored.
- * @param string $name Name to use for the textarea element.
- * @param string $value Initial content to display in the textarea.
- * @param int $obsolete deprecated
- * @param bool $return If false, will output string. If true, will return string value.
- * @param string $id CSS ID to add to the textarea element.
- * @return string|void depending on the value of $return
- */
-function print_textarea($unused, $rows, $cols, $width, $height, $name, $value='', $obsolete=0, $return=false, $id='') {
-    /// $width and height are legacy fields and no longer used as pixels like they used to be.
-    /// However, you can set them to zero to override the mincols and minrows values below.
-
-    // Disabling because there is not yet a viable $OUTPUT option for cases when mforms can't be used
-    debugging('print_textarea() is deprecated. Please use $OUTPUT->print_textarea() instead.', DEBUG_DEVELOPER);
-
-    global $OUTPUT;
-
-    $mincols = 65;
-    $minrows = 10;
-
-    if ($id === '') {
-        $id = 'edit-'.$name;
-    }
-
-    if ($height && ($rows < $minrows)) {
-        $rows = $minrows;
-    }
-    if ($width && ($cols < $mincols)) {
-        $cols = $mincols;
-    }
-
-    $textarea = $OUTPUT->print_textarea($name, $id, $value, $rows, $cols);
-    if ($return) {
-        return $textarea;
-    }
-
-    echo $textarea;
+ */
+function print_textarea() {
+    throw new coding_exception(
+        'print_textarea() has been removed. Please use $OUTPUT->print_textarea() instead.'
+    );
 }
 
 /**
@@ -2686,542 +2623,133 @@ function message_delete_message() {
 }
 
 /**
- * Get all of the allowed types for all of the courses and groups
- * the logged in user belongs to.
- *
- * The returned array will optionally have 5 keys:
- *      'user' : true if the logged in user can create user events
- *      'site' : true if the logged in user can create site events
- *      'category' : array of course categories that the user can create events for
- *      'course' : array of courses that the user can create events for
- *      'group': array of groups that the user can create events for
- *      'groupcourses' : array of courses that the groups belong to (can
- *                       be different from the list in 'course'.
  * @deprecated since 3.6
- * @return array The array of allowed types.
  */
 function calendar_get_all_allowed_types() {
-    debugging('calendar_get_all_allowed_types() is deprecated. Please use calendar_get_allowed_types() instead.',
-        DEBUG_DEVELOPER);
-
-    global $CFG, $USER, $DB;
-
-    require_once($CFG->libdir . '/enrollib.php');
-
-    $types = [];
-
-    $allowed = new stdClass();
-
-    calendar_get_allowed_types($allowed);
-
-    if ($allowed->user) {
-        $types['user'] = true;
-    }
-
-    if ($allowed->site) {
-        $types['site'] = true;
-    }
-
-    if (core_course_category::has_manage_capability_on_any()) {
-        $types['category'] = core_course_category::make_categories_list('moodle/category:manage');
-    }
-
-    // This function warms the context cache for the course so the calls
-    // to load the course context in calendar_get_allowed_types don't result
-    // in additional DB queries.
-    $courses = calendar_get_default_courses(null, 'id, groupmode, groupmodeforce', true);
-
-    // We want to pre-fetch all of the groups for each course in a single
-    // query to avoid calendar_get_allowed_types from hitting the DB for
-    // each separate course.
-    $groups = groups_get_all_groups_for_courses($courses);
-
-    foreach ($courses as $course) {
-        $coursegroups = isset($groups[$course->id]) ? $groups[$course->id] : null;
-        calendar_get_allowed_types($allowed, $course, $coursegroups);
-
-        if (!empty($allowed->courses)) {
-            $types['course'][$course->id] = $course;
-        }
-
-        if (!empty($allowed->groups)) {
-            $types['groupcourses'][$course->id] = $course;
-
-            if (!isset($types['group'])) {
-                $types['group'] = array_values($allowed->groups);
-            } else {
-                $types['group'] = array_merge($types['group'], array_values($allowed->groups));
-            }
-        }
-    }
+    throw new coding_exception(
+        'calendar_get_all_allowed_types() has been removed. Please use calendar_get_allowed_types() instead.'
+    );
 
-    return $types;
 }
 
 /**
- * Gets array of all groups in a set of course.
- *
- * @category group
- * @param array $courses Array of course objects or course ids.
- * @return array Array of groups indexed by course id.
+ * @deprecated since Moodle 3.6.
  */
-function groups_get_all_groups_for_courses($courses) {
-    global $DB;
-
-    if (empty($courses)) {
-        return [];
-    }
-
-    $groups = [];
-    $courseids = [];
-
-    foreach ($courses as $course) {
-        $courseid = is_object($course) ? $course->id : $course;
-        $groups[$courseid] = [];
-        $courseids[] = $courseid;
-    }
-
-    $groupfields = [
-        'g.id as gid',
-        'g.courseid',
-        'g.idnumber',
-        'g.name',
-        'g.description',
-        'g.descriptionformat',
-        'g.enrolmentkey',
-        'g.picture',
-        'g.hidepicture',
-        'g.timecreated',
-        'g.timemodified'
-    ];
-
-    $groupsmembersfields = [
-        'gm.id as gmid',
-        'gm.groupid',
-        'gm.userid',
-        'gm.timeadded',
-        'gm.component',
-        'gm.itemid'
-    ];
-
-    $concatidsql = $DB->sql_concat_join("'-'", ['g.id', 'COALESCE(gm.id, 0)']) . ' AS uniqid';
-    list($courseidsql, $params) = $DB->get_in_or_equal($courseids);
-    $groupfieldssql = implode(',', $groupfields);
-    $groupmembersfieldssql = implode(',', $groupsmembersfields);
-    $sql = "SELECT {$concatidsql}, {$groupfieldssql}, {$groupmembersfieldssql}
-              FROM {groups} g
-         LEFT JOIN {groups_members} gm
-                ON gm.groupid = g.id
-             WHERE g.courseid {$courseidsql}";
-
-    $results = $DB->get_records_sql($sql, $params);
-
-    // The results will come back as a flat dataset thanks to the left
-    // join so we will need to do some post processing to blow it out
-    // into a more usable data structure.
-    //
-    // This loop will extract the distinct groups from the result set
-    // and add it's list of members to the object as a property called
-    // 'members'. Then each group will be added to the result set indexed
-    // by it's course id.
-    //
-    // The resulting data structure for $groups should be:
-    // $groups = [
-    //      '1' = [
-    //          '1' => (object) [
-    //              'id' => 1,
-    //              <rest of group properties>
-    //              'members' => [
-    //                  '1' => (object) [
-    //                      <group member properties>
-    //                  ],
-    //                  '2' => (object) [
-    //                      <group member properties>
-    //                  ]
-    //              ]
-    //          ],
-    //          '2' => (object) [
-    //              'id' => 2,
-    //              <rest of group properties>
-    //              'members' => [
-    //                  '1' => (object) [
-    //                      <group member properties>
-    //                  ],
-    //                  '3' => (object) [
-    //                      <group member properties>
-    //                  ]
-    //              ]
-    //          ]
-    //      ]
-    // ]
-    //
-    foreach ($results as $key => $result) {
-        $groupid = $result->gid;
-        $courseid = $result->courseid;
-        $coursegroups = $groups[$courseid];
-        $groupsmembersid = $result->gmid;
-        $reducefunc = function($carry, $field) use ($result) {
-            // Iterate over the groups properties and pull
-            // them out into a separate object.
-            list($prefix, $field) = explode('.', $field);
-
-            if (property_exists($result, $field)) {
-                $carry[$field] = $result->{$field};
-            }
-
-            return $carry;
-        };
-
-        if (isset($coursegroups[$groupid])) {
-            $group = $coursegroups[$groupid];
-        } else {
-            $initial = [
-                'id' => $groupid,
-                'members' => []
-            ];
-            $group = (object) array_reduce(
-                $groupfields,
-                $reducefunc,
-                $initial
-            );
-        }
-
-        if (!empty($groupsmembersid)) {
-            $initial = ['id' => $groupsmembersid];
-            $groupsmembers = (object) array_reduce(
-                $groupsmembersfields,
-                $reducefunc,
-                $initial
-            );
-
-            $group->members[$groupsmembers->userid] = $groupsmembers;
-        }
-
-        $coursegroups[$groupid] = $group;
-        $groups[$courseid] = $coursegroups;
-    }
-
-    return $groups;
+function groups_get_all_groups_for_courses() {
+    throw new coding_exception(
+        'groups_get_all_groups_for_courses() has been removed and can not be used anymore.'
+    );
 }
 
 /**
- * Gets the capabilities that have been cached in the database for this
- * component.
  * @deprecated since Moodle 3.6. Please use the Events 2 API.
- * @todo final deprecation. To be removed in Moodle 4.0
- *
- * @access protected To be used from eventslib only
- *
- * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
- * @return array of events
  */
-function events_get_cached($component) {
-    global $DB;
-
-    debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.',
-            DEBUG_DEVELOPER);
-
-    $cachedhandlers = array();
-
-    if ($storedhandlers = $DB->get_records('events_handlers', array('component'=>$component))) {
-        foreach ($storedhandlers as $handler) {
-            $cachedhandlers[$handler->eventname] = array (
-                'id'              => $handler->id,
-                'handlerfile'     => $handler->handlerfile,
-                'handlerfunction' => $handler->handlerfunction,
-                'schedule'        => $handler->schedule,
-                'internal'        => $handler->internal);
-        }
-    }
-
-    return $cachedhandlers;
+function events_get_cached() {
+    throw new coding_exception(
+        'Events API using $handlers array has been removed in favour of Events 2 API, please use it instead.'
+    );
 }
 
 /**
- * Remove all event handlers and queued events
  * @deprecated since Moodle 3.6. Please use the Events 2 API.
- * @todo final deprecation. To be removed in Moodle 4.0
- *
- * @category event
- * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
  */
-function events_uninstall($component) {
-    debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.',
-            DEBUG_DEVELOPER);
-    $cachedhandlers = events_get_cached($component);
-    events_cleanup($component, $cachedhandlers);
-
-    events_get_handlers('reset');
+function events_uninstall() {
+    throw new coding_exception(
+        'Events API using $handlers array has been removed in favour of Events 2 API, please use it instead.'
+    );
 }
 
 /**
- * Deletes cached events that are no longer needed by the component.
  * @deprecated since Moodle 3.6. Please use the Events 2 API.
- * @todo final deprecation. To be removed in Moodle 4.0
- *
- * @access protected To be used from eventslib only
- *
- * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
- * @param array $cachedhandlers array of the cached events definitions that will be
- * @return int number of unused handlers that have been removed
  */
-function events_cleanup($component, $cachedhandlers) {
-    global $DB;
-    debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.',
-            DEBUG_DEVELOPER);
-    $deletecount = 0;
-    foreach ($cachedhandlers as $eventname => $cachedhandler) {
-        if ($qhandlers = $DB->get_records('events_queue_handlers', array('handlerid'=>$cachedhandler['id']))) {
-            //debugging("Removing pending events from queue before deleting of event handler: $component - $eventname");
-            foreach ($qhandlers as $qhandler) {
-                events_dequeue($qhandler);
-            }
-        }
-        $DB->delete_records('events_handlers', array('eventname'=>$eventname, 'component'=>$component));
-        $deletecount++;
-    }
-
-    return $deletecount;
+function events_cleanup() {
+    throw new coding_exception(
+        'Events API using $handlers array has been removed in favour of Events 2 API, please use it instead.'
+    );
 }
 
 /**
- * Removes this queued handler from the events_queued_handler table
- *
- * Removes events_queue record from events_queue if no more references to this event object exists
  * @deprecated since Moodle 3.6. Please use the Events 2 API.
- * @todo final deprecation. To be removed in Moodle 4.0
- *
- * @access protected To be used from eventslib only
- *
- * @param stdClass $qhandler A row from the events_queued_handler table
  */
-function events_dequeue($qhandler) {
-    global $DB;
-    debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.',
-            DEBUG_DEVELOPER);
-    // first delete the queue handler
-    $DB->delete_records('events_queue_handlers', array('id'=>$qhandler->id));
-
-    // if no more queued handler is pointing to the same event - delete the event too
-    if (!$DB->record_exists('events_queue_handlers', array('queuedeventid'=>$qhandler->queuedeventid))) {
-        $DB->delete_records('events_queue', array('id'=>$qhandler->queuedeventid));
-    }
+function events_dequeue() {
+    throw new coding_exception(
+        'Events API using $handlers array has been removed in favour of Events 2 API, please use it instead.'
+    );
 }
 
 /**
- * Returns handlers for given event. Uses caching for better perf.
  * @deprecated since Moodle 3.6. Please use the Events 2 API.
- * @todo final deprecation. To be removed in Moodle 4.0
- *
- * @access protected To be used from eventslib only
- *
- * @staticvar array $handlers
- * @param string $eventname name of event or 'reset'
- * @return array|false array of handlers or false otherwise
  */
-function events_get_handlers($eventname) {
-    global $DB;
-    static $handlers = array();
-    debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.',
-            DEBUG_DEVELOPER);
-
-    if ($eventname === 'reset') {
-        $handlers = array();
-        return false;
-    }
-
-    if (!array_key_exists($eventname, $handlers)) {
-        $handlers[$eventname] = $DB->get_records('events_handlers', array('eventname'=>$eventname));
-    }
-
-    return $handlers[$eventname];
+function events_get_handlers() {
+    throw new coding_exception(
+        'Events API using $handlers array has been removed in favour of Events 2 API, please use it instead.'
+    );
 }
 
 /**
- * This function finds the roles assigned directly to this context only
- * i.e. no roles in parent contexts
- *
  * @deprecated since Moodle 3.6. Please use the get_roles_used_in_context().
- * @todo final deprecation. To be removed in Moodle 4.0
- * @param context $context
- * @return array
  */
-function get_roles_on_exact_context(context $context) {
-    debugging('get_roles_on_exact_context() is deprecated, please use get_roles_used_in_context() instead.',
-        DEBUG_DEVELOPER);
-
-    return get_roles_used_in_context($context, false);
+function get_roles_on_exact_context() {
+    throw new coding_exception(
+        'get_roles_on_exact_context() has been removed, please use get_roles_used_in_context() instead.'
+    );
 }
 
 /**
- * Find out which roles has assignment on this context
- *
  * @deprecated since Moodle 3.6. Please use the get_roles_used_in_context().
- * @todo final deprecation. To be removed in Moodle 4.0
- * @param context $context
- * @return array
  */
-function get_roles_with_assignment_on_context(context $context) {
-    debugging('get_roles_with_assignment_on_context() is deprecated, please use get_roles_used_in_context() instead.',
-        DEBUG_DEVELOPER);
-
-    return get_roles_used_in_context($context, false);
+function get_roles_with_assignment_on_context() {
+    throw new coding_exception(
+        'get_roles_with_assignment_on_context() has been removed, please use get_roles_used_in_context() instead.'
+    );
 }
 
 /**
- * Add the selected user as a contact for the current user
- *
  * @deprecated since Moodle 3.6
- * @param int $contactid the ID of the user to add as a contact
- * @param int $blocked 1 if you wish to block the contact
- * @param int $userid the user ID of the user we want to add the contact for, defaults to current user if not specified.
- * @return bool/int false if the $contactid isnt a valid user id. True if no changes made.
- *                  Otherwise returns the result of update_record() or insert_record()
- */
-function message_add_contact($contactid, $blocked = 0, $userid = 0) {
-    debugging('message_add_contact() is deprecated. Please use \core_message\api::create_contact_request() instead. ' .
+ */
+function message_add_contact() {
+    throw new coding_exception(
+        'message_add_contact() has been removed. Please use \core_message\api::create_contact_request() instead. ' .
         'If you wish to block or unblock a user please use \core_message\api::is_blocked() and ' .
-        '\core_message\api::block_user() or \core_message\api::unblock_user() respectively.', DEBUG_DEVELOPER);
-
-    global $USER, $DB;
-
-    if (!$DB->record_exists('user', array('id' => $contactid))) {
-        return false;
-    }
-
-    if (empty($userid)) {
-        $userid = $USER->id;
-    }
-
-    // Check if a record already exists as we may be changing blocking status.
-    if (\core_message\api::is_contact($userid, $contactid)) {
-        $isblocked = \core_message\api::is_blocked($userid, $contactid);
-        // Check if blocking status has been changed.
-        if ($isblocked != $blocked) {
-            if ($blocked == 1) {
-                if (!$isblocked) {
-                    \core_message\api::block_user($userid, $contactid);
-                }
-            } else {
-                \core_message\api::unblock_user($userid, $contactid);
-            }
-
-            return true;
-        } else {
-            // No change to blocking status.
-            return true;
-        }
-    } else {
-        if ($blocked == 1) {
-            if (!\core_message\api::is_blocked($userid, $contactid)) {
-                \core_message\api::block_user($userid, $contactid);
-            }
-        } else {
-            \core_message\api::unblock_user($userid, $contactid);
-            if (!\core_message\api::does_contact_request_exist($userid, $contactid)) {
-                \core_message\api::create_contact_request($userid, $contactid);
-            }
-        }
-
-        return true;
-    }
+        '\core_message\api::block_user() or \core_message\api::unblock_user() respectively.'
+    );
 }
 
 /**
- * Remove a contact.
- *
  * @deprecated since Moodle 3.6
- * @param int $contactid the user ID of the contact to remove
- * @param int $userid the user ID of the user we want to remove the contacts for, defaults to current user if not specified.
- * @return bool returns the result of delete_records()
  */
-function message_remove_contact($contactid, $userid = 0) {
-    debugging('message_remove_contact() is deprecated. Please use \core_message\api::remove_contact() instead.',
-        DEBUG_DEVELOPER);
-
-    global $USER;
-
-    if (empty($userid)) {
-        $userid = $USER->id;
-    }
-
-    \core_message\api::remove_contact($userid, $contactid);
-
-    return true;
+function message_remove_contact() {
+    throw new coding_exception(
+        'message_remove_contact() has been removed. Please use \core_message\api::remove_contact() instead.'
+    );
 }
 
 /**
- * Unblock a contact.
- *
  * @deprecated since Moodle 3.6
- * @param int $contactid the user ID of the contact to unblock
- * @param int $userid the user ID of the user we want to unblock the contact for, defaults to current user
- *  if not specified.
- * @return bool returns the result of delete_records()
  */
-function message_unblock_contact($contactid, $userid = 0) {
-    debugging('message_unblock_contact() is deprecated. Please use \core_message\api::unblock_user() instead.',
-        DEBUG_DEVELOPER);
-
-    global $DB, $USER;
-
-    if (!$DB->record_exists('user', array('id' => $contactid))) {
-        return false;
-    }
-
-    if (empty($userid)) {
-        $userid = $USER->id;
-    }
-
-    \core_message\api::unblock_user($userid, $contactid);
-
-    return true;
+function message_unblock_contact() {
+    throw new coding_exception(
+        'message_unblock_contact() has been removed. Please use \core_message\api::unblock_user() instead.'
+    );
 }
 
 /**
- * Block a user.
- *
  * @deprecated since Moodle 3.6
- * @param int $contactid the user ID of the user to block
- * @param int $userid the user ID of the user we want to unblock the contact for, defaults to current user
- *  if not specified.
- * @return bool
  */
-function message_block_contact($contactid, $userid = 0) {
-    debugging('message_block_contact() is deprecated. Please use \core_message\api::is_blocked() and ' .
-        '\core_message\api::block_user() instead.', DEBUG_DEVELOPER);
-
-    global $DB, $USER;
-
-    if (!$DB->record_exists('user', array('id' => $contactid))) {
-        return false;
-    }
-
-    if (empty($userid)) {
-        $userid = $USER->id;
-    }
-
-    if (!\core_message\api::is_blocked($userid, $contactid)) {
-        \core_message\api::block_user($userid, $contactid);
-    }
-
-    return true;
+function message_block_contact() {
+    throw new coding_exception(
+        'message_block_contact() has been removed. Please use \core_message\api::is_blocked() and ' .
+        '\core_message\api::block_user() instead.'
+    );
 }
 
 /**
- * Load a user's contact record
- *
  * @deprecated since Moodle 3.6
- * @param int $contactid the user ID of the user whose contact record you want
- * @return array message contacts
  */
-function message_get_contact($contactid) {
-    debugging('message_get_contact() is deprecated. Please use \core_message\api::get_contact() instead.',
-        DEBUG_DEVELOPER);
-
-    global $USER;
-
-    return \core_message\api::get_contact($USER->id, $contactid);
+function message_get_contact() {
+    throw new coding_exception(
+        'message_get_contact() has been removed. Please use \core_message\api::get_contact() instead.'
+    );
 }
 
 /**
index 941b344..5a2b1ef 100644 (file)
@@ -551,7 +551,7 @@ function get_exception_info($ex) {
     // Remove some absolute paths from message and debugging info.
     $searches = array();
     $replaces = array();
-    $cfgnames = array('tempdir', 'cachedir', 'localcachedir', 'themedir', 'dataroot', 'dirroot');
+    $cfgnames = array('backuptempdir', 'tempdir', 'cachedir', 'localcachedir', 'themedir', 'dataroot', 'dirroot');
     foreach ($cfgnames as $cfgname) {
         if (property_exists($CFG, $cfgname)) {
             $searches[] = $CFG->$cfgname;
index 8e28ab4..78bade9 100644 (file)
@@ -1306,8 +1306,7 @@ class flexible_table {
 
             if (array_key_exists($sortby, $sortdata)) {
                 // This key already exists somewhere. Change its sortorder and bring it to the top.
-                //$sortorder = $sortdata[$sortby] = $sortorder;
-                unset($sortdata['sortby'][$sortby]);
+                unset($sortdata[$sortby]);
             }
             $sortdata = array_merge([$sortby => $sortorder], $sortdata);
         }
index e9284f7..8906527 100644 (file)
@@ -41,59 +41,6 @@ use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException,
  */
 class behat_deprecated extends behat_base {
 
-    /**
-     * Click link in navigation tree that matches the text in parentnode/s (seperated using greater-than character if more than one)
-     *
-     * @throws ExpectationException
-     * @param string $nodetext navigation node to click.
-     * @param string $parentnodes comma seperated list of parent nodes.
-     * @return void
-     * @deprecated since Moodle 3.6 MDL-57281 - please do not use this definition step any more.
-     * @todo MDL-63004 This will be deleted in Moodle 4.0.
-     */
-    public function i_navigate_to_node_in($nodetext, $parentnodes) {
-        $alternative[] = 'I navigate to "PATH" in current page administration';
-        $alternative[] = 'I navigate to "PATH" in site administration';
-        $alternative[] = 'I navigate to "TAB1 > TAB2" in the course gradebook';
-        $alternative[] = 'I navigate to course participants';
-        $alternative[] = 'If some items are not available without Navigation block at all, one can use combination of:
-                              I add the "Navigation" block if not present
-                              I click on "LINK" "link" in the "Navigation" "block"';
-
-        $this->deprecated_message($alternative);
-
-        $parentnodes = array_map('trim', explode('>', $parentnodes));
-        $nodelist = array_merge($parentnodes, [$nodetext]);
-        $firstnode = array_shift($nodelist);
-
-        if ($firstnode === get_string('administrationsite')) {
-            $this->execute('behat_theme_boost_behat_navigation::i_select_from_flat_navigation_drawer',
-                    array(get_string('administrationsite')));
-            $this->execute('behat_theme_boost_behat_navigation::select_on_administration_page', array($nodelist));
-            return;
-        }
-
-        if ($firstnode === get_string('sitepages')) {
-            if ($nodetext === get_string('calendar', 'calendar')) {
-                $this->execute('behat_theme_boost_behat_navigation::i_select_from_flat_navigation_drawer',
-                        array(($nodetext)));
-            } else {
-                // TODO MDL-57120 other links under "Site pages" are not accessible without navigation block.
-                $this->execute('behat_theme_boost_behat_navigation::select_node_in_navigation',
-                        array($nodetext, $parentnodes));
-            }
-            return;
-        }
-
-        if ($firstnode === get_string('courseadministration')) {
-            // Administration menu is available only on the main course page where settings in Administration
-            // block (original purpose of the step) are available on every course page.
-            $this->execute('behat_theme_boost_behat_navigation::go_to_main_course_page', array());
-        }
-
-        $this->execute('behat_theme_boost_behat_navigation::select_from_administration_menu', array($nodelist));
-    }
-
     /**
      * Docks a block. Editing mode should be previously enabled.
      * @throws ExpectationException
index 3eed52f..052fe30 100644 (file)
@@ -194,7 +194,7 @@ class behat_navigation extends behat_base {
             // We just want to expand the node, we don't want to follow it.
             $node = $node->getParent();
         }
-        $node->click();
+        $this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
     }
 
     /**
@@ -218,7 +218,7 @@ class behat_navigation extends behat_base {
             // We just want to expand the node, we don't want to follow it.
             $node = $node->getParent();
         }
-        $node->click();
+        $this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
     }
 
     /**
@@ -245,7 +245,7 @@ class behat_navigation extends behat_base {
                 // don't wait, it is non-JS and we already waited for the DOM.
                 $siteadminlink = $this->getSession()->getPage()->find('named_exact', array('link', "'" . $siteadminstr . "'"));
                 if ($siteadminlink) {
-                    $siteadminlink->click();
+                    $this->execute('behat_general::i_click_on', [$siteadminlink, 'NodeElement']);
                 }
             }
         }
@@ -302,7 +302,7 @@ class behat_navigation extends behat_base {
             throw new ExpectationException('Navigation node "' . $nodetext . '" not found under "' .
                 implode(' > ', $parentnodes) . '"', $this->getSession());
         }
-        $nodetoclick->click();
+        $this->execute('behat_general::i_click_on', [$nodetoclick, 'NodeElement']);
     }
 
     /**
@@ -791,9 +791,8 @@ class behat_navigation extends behat_base {
         $node = $this->find('xpath', $xpath);
         $expanded = $node->getAttribute('aria-expanded');
         if ($expanded === 'false') {
-            $node->click();
+            $this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
             $this->ensure_node_attribute_is_set($node, 'aria-expanded', 'true');
-            $this->wait_for_pending_js();
         }
     }
 
@@ -812,8 +811,7 @@ class behat_navigation extends behat_base {
         $node = $this->find('xpath', $xpath);
         $expanded = $node->getAttribute('aria-expanded');
         if ($expanded === 'true') {
-            $node->click();
-            $this->wait_for_pending_js();
+            $this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
         }
     }
 
@@ -835,8 +833,8 @@ class behat_navigation extends behat_base {
     protected function go_to_main_course_page() {
         $url = $this->getSession()->getCurrentUrl();
         if (!preg_match('|/course/view.php\?id=[\d]+$|', $url)) {
-            $this->find('xpath', '//header//div[@id=\'page-navbar\']//a[contains(@href,\'/course/view.php?id=\')]')->click();
-            $this->execute('behat_general::wait_until_the_page_is_ready');
+            $node = $this->find('xpath', '//header//div[@id=\'page-navbar\']//a[contains(@href,\'/course/view.php?id=\')]');
+            $this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
         }
     }
 
@@ -856,8 +854,8 @@ class behat_navigation extends behat_base {
             $tabxpath = '//ul[@role=\'tablist\']/li/a[contains(normalize-space(.), ' . $tabname . ')]';
             if ($node = $this->getSession()->getPage()->find('xpath', $tabxpath)) {
                 if ($this->running_javascript()) {
+                    $this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
                     // Click on the tab and add 'active' tab to the xpath.
-                    $node->click();
                     $xpath .= '//div[contains(@class,\'active\')]';
                 } else {
                     // Add the tab content selector to the xpath.
@@ -881,8 +879,7 @@ class behat_navigation extends behat_base {
         if (!$node = $this->getSession()->getPage()->find('xpath', $xpath)) {
             throw new ElementNotFoundException($this->getSession(), 'Link "' . join(' > ', $nodelist) . '"');
         }
-        $node->click();
-        $this->wait_for_pending_js();
+        $this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
     }
 
     /**
@@ -929,8 +926,8 @@ class behat_navigation extends behat_base {
             $menuxpath = $this->find_header_administration_menu() ?: $this->find_page_administration_menu();
         }
         if ($menuxpath && $this->running_javascript()) {
-            $this->find('xpath', $menuxpath . '//a[@data-toggle=\'dropdown\']')->click();
-            $this->wait_for_pending_js();
+            $node = $this->find('xpath', $menuxpath . '//a[@data-toggle=\'dropdown\']');
+            $this->execute('behat_general::i_click_on', [$node, 'NodeElement']);
         }
     }
 
@@ -952,15 +949,14 @@ class behat_navigation extends behat_base {
             $isheader = false;
         }
 
-        $this->toggle_page_administration_menu($menuxpath);
+        $this->execute('behat_navigation::toggle_page_administration_menu', [$menuxpath]);
 
         if (!$isheader || count($nodelist) == 1) {
             $lastnode = end($nodelist);
             $linkname = behat_context_helper::escape($lastnode);
             $link = $this->getSession()->getPage()->find('xpath', $menuxpath . '//a[contains(normalize-space(.), ' . $linkname . ')]');
             if ($link) {
-                $link->click();
-                $this->wait_for_pending_js();
+                $this->execute('behat_general::i_click_on', [$link, 'NodeElement']);
                 return;
             }
         }
@@ -970,8 +966,7 @@ class behat_navigation extends behat_base {
             $linkname = behat_context_helper::escape(get_string('morenavigationlinks'));
             $link = $this->getSession()->getPage()->find('xpath', $menuxpath . '//a[contains(normalize-space(.), ' . $linkname . ')]');
             if ($link) {
-                $link->click();
-                $this->execute('behat_general::wait_until_the_page_is_ready');
+                $this->execute('behat_general::i_click_on', [$link, 'NodeElement']);
                 $this->select_on_administration_page($nodelist);
                 return;
             }
index 8c094f3..9e71470 100644 (file)
@@ -596,7 +596,7 @@ class core_event_testcase extends advanced_testcase {
         events_update_definition('unittest');
 
         $DB->delete_records_select('events_handlers', "component <> 'unittest'");
-        events_get_handlers('reset');
+
         $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
         $this->assertEquals(3, $DB->count_records('events_handlers'));
         set_config('loglifetime', 60*60*24*5);
index 47a9fec..2064621 100644 (file)
@@ -70,35 +70,35 @@ class lock_testcase extends advanced_testcase {
             $this->assertNotEmpty($lock1, 'Get a lock');
 
             if ($lockfactory->supports_timeout()) {
-                if ($lockfactory->supports_recursion()) {
-                    $lock2 = $lockfactory->get_lock('abc', 2);
+                // Attempt to obtain a lock within a 2 sec timeout.
+                $durationlock2 = -microtime(true);
+                $lock2 = $lockfactory->get_lock('abc', 2);
+                $durationlock2 += microtime(true);
+
+                if (!$lock2) { // If the lock was not obtained.
+                    $this->assertFalse($lock2, 'Cannot get a stacked lock');
+                    // This should timeout after 2 seconds.
+                    $this->assertTrue($durationlock2 < 2.5, 'Lock should timeout after no more than 2 seconds');
+                } else {
                     $this->assertNotEmpty($lock2, 'Get a stacked lock');
                     $this->assertTrue($lock2->release(), 'Release a stacked lock');
+                }
+
+                // Attempt to obtain a lock within a 0 sec timeout.
+                $durationlock2 = -microtime(true);
+                $lock2 = $lockfactory->get_lock('abc', 0);
+                $durationlock2 += microtime(true);
 
+                if (!$lock2) { // If the lock was not obtained.
+                    // This should timeout almost instantly.
+                    $this->assertTrue($durationlock2 < 0.100, 'Lock should timeout almost instantly < 100ms');
+                } else {
                     // This stacked lock should be gained almost instantly.
-                    $duration = -microtime(true);
-                    $lock3 = $lockfactory->get_lock('abc', 0);
-                    $duration += microtime(true);
-                    $lock3->release();
-                    $this->assertTrue($duration < 0.100, 'Lock should be gained almost instantly');
+                    $this->assertTrue($durationlock2 < 0.100, 'Lock should be gained almost instantly');
+                    $lock2->release();
 
                     // We should also assert that locks fail instantly if locked
                     // from another process but this is hard to unit test.
-
-                } else {
-                    // This should timeout after 2 seconds.
-                    $duration = -microtime(true);
-                    $lock2 = $lockfactory->get_lock('abc', 2);
-                    $duration += microtime(true);
-                    $this->assertFalse($lock2, 'Cannot get a stacked lock');
-                    $this->assertTrue($duration < 2.5, 'Lock should timeout after no more than 2 seconds');
-
-                    // This should timeout almost instantly.
-                    $duration = -microtime(true);
-                    $lock2 = $lockfactory->get_lock('abc', 0);
-                    $duration += microtime(true);
-                    $this->assertFalse($lock2, 'Cannot get a stacked lock');
-                    $this->assertTrue($duration < 0.100, 'Lock should timeout almost instantly < 100ms');
                 }
             }
             // Release the lock.
index 6e3ce5b..1e6c3b3 100644 (file)
@@ -79,7 +79,7 @@ class core_setuplib_testcase extends advanced_testcase {
         global $CFG;
 
         // This doesn't test them all possible ones, but these are set for unit tests.
-        $cfgnames = array('dataroot', 'dirroot', 'tempdir', 'cachedir', 'localcachedir');
+        $cfgnames = array('dataroot', 'dirroot', 'tempdir', 'backuptempdir', 'cachedir', 'localcachedir');
 
         $fixture  = '';
         $expected = '';
index fd1f97d..8ddc5de 100644 (file)
@@ -8,6 +8,23 @@ information provided here is intended especially for developers.
   of 'scrollable' is true.
 * The `$CFG->behat_retart_browser_after` configuration setting has been removed.
   The browser session is now restarted between all tests.
+* add_to_log() has been through final deprecation, please rewrite your code to the new events API.
+* The following functions have been finally deprecated and can not be used anymore:
+  - print_textarea
+  - calendar_get_all_allowed_types
+  - groups_get_all_groups_for_courses
+  - events_get_cached
+  - events_uninstall
+  - events_cleanup
+  - events_dequeue
+  - events_get_handlers
+  - get_roles_on_exact_context
+  - get_roles_with_assignment_on_context
+  - message_add_contact
+  - message_remove_contact
+  - message_unblock_contact
+  - message_block_contact
+  - message_get_contact
 
 === 3.9 ===
 * Following function has been deprecated, please use \core\task\manager::run_from_cli().
index c7d3d2b..29ef0e7 100644 (file)
@@ -2285,6 +2285,11 @@ function send_headers($contenttype, $cacheable = true) {
     if (empty($CFG->allowframembedding) && !core_useragent::is_moodle_app()) {
         @header('X-Frame-Options: sameorigin');
     }
+
+    // If referrer policy is set, add a referrer header.
+    if (!empty($CFG->referrerpolicy) && ($CFG->referrerpolicy !== 'default')) {
+        @header('Referrer-Policy: ' . $CFG->referrerpolicy);
+    }
 }
 
 /**
index 3e101d5..d942821 100644 (file)
@@ -292,6 +292,7 @@ class core_message_external extends external_api {
      * Create contacts.
      *
      * @deprecated since Moodle 3.6
+     * TODO: MDL-63261
      * @param array $userids array of user IDs.
      * @param int $userid The id of the user we are creating the contacts for
      * @return external_description
@@ -323,7 +324,7 @@ class core_message_external extends external_api {
 
         $warnings = array();
         foreach ($params['userids'] as $id) {
-            if (!message_add_contact($id, 0, $params['userid'])) {
+            if (!\core_message\api::create_contact_request($params['userid'], $id)) {
                 $warnings[] = array(
                     'item' => 'user',
                     'itemid' => $id,
@@ -682,6 +683,7 @@ class core_message_external extends external_api {
      * Block contacts.
      *
      * @deprecated since Moodle 3.6
+     * TODO: MDL-63261
      * @param array $userids array of user IDs.
      * @param int $userid The id of the user we are blocking the contacts for
      * @return external_description
@@ -713,7 +715,7 @@ class core_message_external extends external_api {
 
         $warnings = array();
         foreach ($params['userids'] as $id) {
-            if (!message_block_contact($id, $params['userid'])) {
+            if (!\core_message\api::block_user($params['userid'], $id)) {
                 $warnings[] = array(
                     'item' => 'user',
                     'itemid' => $id,
@@ -798,7 +800,7 @@ class core_message_external extends external_api {
         }
 
         foreach ($params['userids'] as $id) {
-            message_unblock_contact($id, $params['userid']);
+            core_message\api::unblock_user($params['userid'], $id);
         }
 
         return null;
index 1f14399..9a61444 100644 (file)
@@ -340,6 +340,8 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
 
     /**
      * Test create_contacts.
+     *
+     * TODO: MDL-63261
      */
     public function test_create_contacts() {
         $this->resetAfterTest(true);
@@ -351,41 +353,17 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
         $user5 = self::getDataGenerator()->create_user();
         $this->setUser($user1);
 
-        // Adding a contact.
-        $return = core_message_external::create_contacts(array($user2->id));
-        $this->assertDebuggingCalled();
-        $return = external_api::clean_returnvalue(core_message_external::create_contacts_returns(), $return);
-        $this->assertEquals(array(), $return);
-
         // Adding a contact who is already a contact.
         $return = core_message_external::create_contacts(array($user2->id));
-        $this->assertDebuggingCalled();
         $return = external_api::clean_returnvalue(core_message_external::create_contacts_returns(), $return);
         $this->assertEquals(array(), $return);
 
         // Adding multiple contacts.
         $return = core_message_external::create_contacts(array($user3->id, $user4->id));
-        $this->assertDebuggingCalledCount(2);
         $return = external_api::clean_returnvalue(core_message_external::create_contacts_returns(), $return);
         $this->assertEquals(array(), $return);
 
-        // Adding a non-existing user.
-        $return = core_message_external::create_contacts(array(99999));
-        $this->assertDebuggingCalled();
-        $return = external_api::clean_returnvalue(core_message_external::create_contacts_returns(), $return);
-        $this->assertCount(1, $return);
-        $return = array_pop($return);
-        $this->assertEquals($return['warningcode'], 'contactnotcreated');
-        $this->assertEquals($return['itemid'], 99999);
-
-        // Adding contacts with valid and invalid parameters.
-        $return = core_message_external::create_contacts(array($user5->id, 99999));
-        $this->assertDebuggingCalledCount(2);
-        $return = external_api::clean_returnvalue(core_message_external::create_contacts_returns(), $return);
-        $this->assertCount(1, $return);
-        $return = array_pop($return);
-        $this->assertEquals($return['warningcode'], 'contactnotcreated');
-        $this->assertEquals($return['itemid'], 99999);
+        // Note: We should add real user checks in api L:2656.
 
         // Try to add a contact to another user, should throw an exception.
         // All assertions must be added before this point.
@@ -455,36 +433,36 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
         \core_message\api::add_contact($user1->id, $user4->id);
         \core_message\api::add_contact($user1->id, $user5->id);
 
-        // Blocking a contact.
-        $return = core_message_external::block_contacts(array($user2->id));
-        $this->assertDebuggingCalled();
-        $return = external_api::clean_returnvalue(core_message_external::block_contacts_returns(), $return);
-        $this->assertEquals(array(), $return);
-
         // Blocking a contact who is already a contact.
         $return = core_message_external::block_contacts(array($user2->id));
-        $this->assertDebuggingCalled();
         $return = external_api::clean_returnvalue(core_message_external::block_contacts_returns(), $return);
-        $this->assertEquals(array(), $return);
+        $this->assertEquals(array(array(
+            'item' => 'user',
+            'itemid' => $user2->id,
+            'warningcode' => 'contactnotblocked',
+            'message' => 'The contact could not be blocked'
+        )), $return);
 
         // Blocking multiple contacts.
         $return = core_message_external::block_contacts(array($user3->id, $user4->id));
-        $this->assertDebuggingCalledCount(2);
         $return = external_api::clean_returnvalue(core_message_external::block_contacts_returns(), $return);
-        $this->assertEquals(array(), $return);
+        $this->assertEquals(array(
+            array(
+                'item' => 'user',
+                'itemid' => $user3->id,
+                'warningcode' => 'contactnotblocked',
+                'message' => 'The contact could not be blocked'
+            ),
+            array(
+                'item' => 'user',
+                'itemid' => $user4->id,
+                'warningcode' => 'contactnotblocked',
+                'message' => 'The contact could not be blocked'
+            )
+        ), $return);
 
         // Blocking a non-existing user.
         $return = core_message_external::block_contacts(array(99999));
-        $this->assertDebuggingCalled();
-        $return = external_api::clean_returnvalue(core_message_external::block_contacts_returns(), $return);
-        $this->assertCount(1, $return);
-        $return = array_pop($return);
-        $this->assertEquals($return['warningcode'], 'contactnotblocked');
-        $this->assertEquals($return['itemid'], 99999);
-
-        // Blocking contacts with valid and invalid parameters.
-        $return = core_message_external::block_contacts(array($user5->id, 99999));
-        $this->assertDebuggingCalledCount(2);
         $return = external_api::clean_returnvalue(core_message_external::block_contacts_returns(), $return);
         $this->assertCount(1, $return);
         $return = array_pop($return);
@@ -518,34 +496,28 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
 
         // Removing a non-contact.
         $return = core_message_external::unblock_contacts(array($user2->id));
-        $this->assertDebuggingCalled();
         $this->assertNull($return);
 
         // Removing one contact.
         $return = core_message_external::unblock_contacts(array($user3->id));
-        $this->assertDebuggingCalled();
         $this->assertNull($return);
 
         // Removing multiple contacts.
         $return = core_message_external::unblock_contacts(array($user4->id, $user5->id));
-        $this->assertDebuggingCalledCount(2);
         $this->assertNull($return);
 
         // Removing contact from unexisting user.
         $return = core_message_external::unblock_contacts(array(99999));
-        $this->assertDebuggingCalled();
         $this->assertNull($return);
 
         // Removing mixed valid and invalid data.
         $return = core_message_external::unblock_contacts(array($user6->id, 99999));
-        $this->assertDebuggingCalledCount(2);
         $this->assertNull($return);
 
         // Try to unblock a contact of another user contact list, should throw an exception.
         // All assertions must be added before this point.
         $this->expectException('required_capability_exception');
         core_message_external::unblock_contacts(array($user2->id), $user3->id);
-        $this->assertDebuggingCalled();
     }
 
     /**
@@ -1392,7 +1364,6 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
         $this->assertCount(1, $contacts['online']);
         $this->assertCount(3, $contacts['strangers']);
         core_message_external::block_contacts(array($user_blocked->id));
-        $this->assertDebuggingCalled();
         $contacts = core_message_external::get_contacts();
         $contacts = external_api::clean_returnvalue(core_message_external::get_contacts_returns(), $contacts);
         $this->assertCount(3, $contacts['offline']);
@@ -1822,7 +1793,6 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
 
         // Block the $userblocked and retrieve again the list.
         core_message_external::block_contacts(array($userblocked->id));
-        $this->assertDebuggingCalled();
         $blockedusers = core_message_external::get_blocked_users($user1->id);
         $blockedusers = external_api::clean_returnvalue(core_message_external::get_blocked_users_returns(), $blockedusers);
         $this->assertCount(1, $blockedusers['users']);
index 8b0e8fd..c02a610 100644 (file)
@@ -223,102 +223,6 @@ class core_message_messagelib_testcase extends advanced_testcase {
         $this->assertEquals(0, message_count_unread_messages($userfrom));
     }
 
-    /**
-     * Test message_add_contact.
-     */
-    public function test_message_add_contact() {
-        global $DB, $USER;
-
-        // Set this user as the admin.
-        $this->setAdminUser();
-
-        // Create a user to add to the admin's contact list.
-        $user1 = $this->getDataGenerator()->create_user();
-        $user2 = $this->getDataGenerator()->create_user();
-
-        message_add_contact($user1->id);
-        $this->assertDebuggingCalled();
-        $this->assertEquals(1, $DB->count_records('message_contact_requests'));
-
-        message_add_contact($user2->id, 1);
-        $this->assertDebuggingCalled();
-        $this->assertEquals(1, $DB->count_records('message_users_blocked'));
-
-        message_add_contact($user2->id, 0);
-        $this->assertDebuggingCalled();
-        $this->assertEquals(0, $DB->count_records('message_users_blocked'));
-    }
-
-    /**
-     * Test message_remove_contact.
-     */
-    public function test_message_remove_contact() {
-        global $USER;
-
-        // Set this user as the admin.
-        $this->setAdminUser();
-
-        // Create a user to add to the admin's contact list.
-        $user = $this->getDataGenerator()->create_user();
-
-        // Add the user to the admin's contact list.
-        \core_message\api::add_contact($USER->id, $user->id);
-
-        // Remove user from admin's contact list.
-        message_remove_contact($user->id);
-        $this->assertDebuggingCalled();
-        $this->assertEquals(false, message_get_contact($user->id));
-        $this->assertDebuggingCalled();
-    }
-
-    /**
-     * Test message_block_contact.
-     */
-    public function test_message_block_contact() {
-        global $USER;
-
-        // Set this user as the admin.
-        $this->setAdminUser();
-
-        // Create a user to add to the admin's contact list.
-        $user1 = $this->getDataGenerator()->create_user();
-        $user2 = $this->getDataGenerator()->create_user();
-
-        // Add users to the admin's contact list.
-        \core_message\api::add_contact($USER->id, $user1->id);
-        \core_message\api::add_contact($USER->id, $user2->id);
-
-        $this->assertEquals(0, \core_message\api::count_blocked_users());
-
-        // Block 1 user.
-        message_block_contact($user2->id);
-        $this->assertDebuggingCalled();
-        $this->assertEquals(1, \core_message\api::count_blocked_users());
-
-    }
-
-    /**
-     * Test message_unblock_contact.
-     */
-    public function test_message_unblock_contact() {
-        global $USER;
-
-        // Set this user as the admin.
-        $this->setAdminUser();
-
-        // Create a user to add to the admin's contact list.
-        $user1 = $this->getDataGenerator()->create_user();
-
-        // Add users to the admin's blocked list.
-        \core_message\api::block_user($USER->id, $user1->id);
-        $this->assertEquals(1, \core_message\api::count_blocked_users());
-
-        // Unblock user.
-        message_unblock_contact($user1->id);
-        $this->assertDebuggingCalled();
-        $this->assertEquals(0, \core_message\api::count_blocked_users());
-    }
-
     /**
      * Test message_search_users.
      */
index be6b0a1..86b4151 100644 (file)
@@ -98,6 +98,7 @@ class convert_submissions extends scheduled_task {
             }
 
             mtrace('Convert ' . count($users) . ' submission attempt(s) for assignment ' . $assignmentid);
+            $conversionrequirespolling = false;
 
             foreach ($users as $userid) {
                 try {
@@ -107,6 +108,7 @@ class convert_submissions extends scheduled_task {
                         case combined_document::STATUS_READY_PARTIAL:
                         case combined_document::STATUS_PENDING_INPUT:
                             // The document has not been converted yet or is somehow still ready.
+                            $conversionrequirespolling = true;
                             continue 2;
                     }
                     document_services::get_page_images_for_attempt(
@@ -127,7 +129,9 @@ class convert_submissions extends scheduled_task {
             }
 
             // Remove from queue.
-            $DB->delete_records('assignfeedback_editpdf_queue', array('id' => $record->id));
+            if (!$conversionrequirespolling) {
+                $DB->delete_records('assignfeedback_editpdf_queue', array('id' => $record->id));
+            }
 
         }
     }
index 56b2dbc..8676816 100644 (file)
     * none
 
     Context variables required for this template:
+    * id
     * hascapabilitygroups
     * state
     ** pending|configured|rejected|unknown
     ** text
     * courseid
     * urls
-    ** course
+    ** course - optional, required if courseid > 0
     ** icon
+    ** edit
     ** publickeyset
     ** accesstoken
     ** authrequest
     * deploymentid
     * instancecount
 
+    Example context (json):
+    {
+        "id": 1,
+        "name": "Example Tool",
+        "description": "This is an example tool",
+        "platformid": "https:\/\/moodle.example.com",
+        "courseid": 0,
+        "hascapabilitygroups": false,
+        "state": {
+            "text": "Active",
+            "pending": false,
+            "configured": true,
+            "rejected": false,
+            "unknown": false
+        },
+        "urls": {
+            "icon": "https://www.example.com/icon1.png",
+            "edit": "https://www.example.com/mod/lti/typessettings.php",
+            "publickeyset": "https:\/\/moodle.example.com\/mod\/lti\/certs.php",
+            "accesstoken": "https:\/\/moodle.example.com\/mod\/lti\/token.php",
+            "authrequest": "https:\/\/moodle.example.com\/mod\/lti\/auth.php"
+        },
+        "clientid": null,
+        "deploymentid": 1,
+        "instancecount": 0
+    }
+
 }}
 <div class="tool-card" data-type-id="{{id}}" data-uniqid="{{uniqid}}"
     data-modaltitle="{{#str}} tooldetailsmodaltitle, mod_lti {{/str}}"
                     <a class="delete" href="#" title="{{#str}} delete {{/str}}">{{#pix}} t/delete, core, {{#str}} delete {{/str}}{{/pix}}</a>
                 </div>
             </div>
-            <img class="tool-card-icon" src="{{{urls.icon}}}" alt="{{name}}"></img>
+            <img class="tool-card-icon" src="{{{urls.icon}}}" alt="{{name}}">
             <div class="contenteditable-container">
                 <h4 class="name" contenteditable="true">{{name}}</h4>
                 <div class="overlay-container">{{> mod_lti/loader }}</div>
index 5c1cfb3..d5f1285 100644 (file)
@@ -81,27 +81,19 @@ class report extends \mod_scorm\report {
                         && ($attemptsmode != SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO);
         // Select the students.
         $nostudents = false;
-
+        list($allowedlistsql, $params) = get_enrolled_sql($contextmodule, 'mod/scorm:savetrack', (int) $currentgroup);
         if (empty($currentgroup)) {
             // All users who can attempt scoes.
-            if (!$students = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', 'u.id', '', '', '', '', '', false)) {
+            if (!$DB->record_exists_sql($allowedlistsql, $params)) {
                 echo $OUTPUT->notification(get_string('nostudentsyet'));
                 $nostudents = true;
-                $allowedlist = '';
-            } else {
-                $allowedlist = array_keys($students);
             }
-            unset($students);
         } else {
             // All users who can attempt scoes and who are in the currently selected group.
-            if (!$groupstudents = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', 'u.id', '', '', '',
-                                                            $currentgroup, '', false)) {
+            if (!$DB->record_exists_sql($allowedlistsql, $params)) {
                 echo $OUTPUT->notification(get_string('nostudentsingroup'));
                 $nostudents = true;
-                $groupstudents = array();
             }
-            $allowedlist = array_keys($groupstudents);
-            unset($groupstudents);
         }
 
         if ( !$nostudents ) {
@@ -273,8 +265,6 @@ class report extends \mod_scorm\report {
                 $csvexport->set_filename($filename, ".txt");
                 $csvexport->add_data($headers);
             }
-            $params = array();
-            list($usql, $params) = $DB->get_in_or_equal($allowedlist, SQL_PARAMS_NAMED);
             // Construct the SQL.
             $select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, ';
             $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' .
@@ -287,15 +277,15 @@ class report extends \mod_scorm\report {
             switch ($attemptsmode) {
                 case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH:
                     // Show only students with attempts.
-                    $where = ' WHERE u.id ' .$usql. ' AND st.userid IS NOT NULL';
+                    $where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NOT NULL";
                     break;
                 case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO:
                     // Show only students without attempts.
-                    $where = ' WHERE u.id ' .$usql. ' AND st.userid IS NULL';
+                    $where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NULL";
                     break;
                 case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS:
                     // Show all students with or without attempts.
-                    $where = ' WHERE u.id ' .$usql. ' AND (st.userid IS NOT NULL OR st.userid IS NULL)';
+                    $where = " WHERE u.id IN ({$allowedlistsql}) AND (st.userid IS NOT NULL OR st.userid IS NULL)";
                     break;
             }
 
index 4971d5c..6fa46f7 100644 (file)
@@ -50,18 +50,15 @@ class report extends \mod_scorm\report {
      * Get the data for the report.
      *
      * @param int $scoid The sco ID.
-     * @param array $allowedlist The list of user IDs allowed to be displayed.
+     * @param array $allowedlist The SQL and params to get the userlist.
      * @return array of data indexed per bar.
      */
-    protected function get_data($scoid, $allowedlist = []) {
+    protected function get_data($scoid, $allowedlistsql) {
         global $DB;
         $data = array_fill(0, self::BANDS, 0);
-        if (empty($allowedlist)) {
-            return $data;
-        }
 
-        list($usql, $params) = $DB->get_in_or_equal($allowedlist);
-        $params[] = $scoid;
+        list($allowedlist, $params) = $allowedlistsql;
+        $params = array_merge($params, ['scoid' => $scoid]);
 
         // Construct the SQL.
         $sql = "SELECT DISTINCT " . $DB->sql_concat('st.userid', '\'#\'', 'COALESCE(st.attempt, 0)') . " AS uniqueid,
@@ -70,7 +67,7 @@ class report extends \mod_scorm\report {
                        st.attempt AS attempt,
                        st.scoid AS scoid
                   FROM {scorm_scoes_track} st
-                 WHERE st.userid $usql AND st.scoid = ?";
+                 WHERE st.userid IN ({$allowedlistsql}) AND st.scoid = :scoid";
         $attempts = $DB->get_records_sql($sql, $params);
 
         $usergrades = [];
@@ -144,15 +141,7 @@ class report extends \mod_scorm\report {
 
         // Find out current restriction.
         $group = groups_get_activity_group($cm, true);
-        if (empty($group)) {
-            // All users who can attempt scoes.
-            $students = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', 'u.id' , '', '', '', '', '', false);
-            $allowedlist = empty($students) ? array() : array_keys($students);
-        } else {
-            // All users who can attempt scoes and who are in the currently selected group.
-            $groupstudents = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', 'u.id', '', '', '', $group, '', false);
-            $allowedlist = empty($groupstudents) ? array() : array_keys($groupstudents);
-        }
+        $allowedlistsql = get_enrolled_sql($contextmodule, 'mod/scorm:savetrack', (int) $group);
 
         // Labels.
         $labels = [get_string('invaliddata', 'scormreport_graphs')];
@@ -164,7 +153,7 @@ class report extends \mod_scorm\report {
             foreach ($scoes as $sco) {
                 if ($sco->launch != '') {
 
-                    $data = $this->get_data($sco->id, $allowedlist);
+                    $data = $this->get_data($sco->id, $allowedlistsql);
                     $series = new chart_series($sco->title, $data);
 
                     $chart = new chart_bar();
index 1deef30..1bc5afb 100644 (file)
@@ -98,28 +98,19 @@ class report extends \mod_scorm\report {
                 && ($attemptsmode != SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO);
         // Select the students.
         $nostudents = false;
-
+        list($allowedlistsql, $params) = get_enrolled_sql($contextmodule, 'mod/scorm:savetrack', (int) $currentgroup);
         if (empty($currentgroup)) {
             // All users who can attempt scoes.
-            if (!$students = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', 'u.id', '', '', '', '', '', false)) {
+            if (!$DB->record_exists_sql($allowedlistsql, $params)) {
                 echo $OUTPUT->notification(get_string('nostudentsyet'));
                 $nostudents = true;
-                $allowedlist = '';
-            } else {
-                $allowedlist = array_keys($students);
             }
-            unset($students);
         } else {
             // All users who can attempt scoes and who are in the currently selected group.
-            if (!$groupstudents = get_users_by_capability($contextmodule,
-                                                            'mod/scorm:savetrack', 'u.id', '', '', '',
-                                                            $currentgroup, '', false)) {
+            if (!$DB->record_exists_sql($allowedlistsql, $params)) {
                 echo $OUTPUT->notification(get_string('nostudentsingroup'));
                 $nostudents = true;
-                $groupstudents = array();
             }
-            $allowedlist = array_keys($groupstudents);
-            unset($groupstudents);
         }
         if ( !$nostudents ) {
             // Now check if asked download of data.
@@ -163,8 +154,6 @@ class report extends \mod_scorm\report {
                 }
             }
 
-            $params = array();
-            list($usql, $params) = $DB->get_in_or_equal($allowedlist, SQL_PARAMS_NAMED);
             // Construct the SQL.
             $select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, ';
             $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' .
@@ -177,15 +166,15 @@ class report extends \mod_scorm\report {
             switch ($attemptsmode) {
                 case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH:
                     // Show only students with attempts.
-                    $where = ' WHERE u.id ' .$usql. ' AND st.userid IS NOT NULL';
+                    $where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NOT NULL";
                     break;
                 case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO:
                     // Show only students without attempts.
-                    $where = ' WHERE u.id ' .$usql. ' AND st.userid IS NULL';
+                    $where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NULL";
                     break;
                 case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS:
                     // Show all students with or without attempts.
-                    $where = ' WHERE u.id ' .$usql. ' AND (st.userid IS NOT NULL OR st.userid IS NULL)';
+                    $where = " WHERE u.id IN ({$allowedlistsql}) AND (st.userid IS NOT NULL OR st.userid IS NULL)";
                     break;
             }
 
index 85488c7..4e2ad62 100644 (file)
@@ -92,28 +92,19 @@ class report extends \mod_scorm\report {
                 && ($attemptsmode != SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO);
         // Select the students.
         $nostudents = false;
-
+        list($allowedlistsql, $params) = get_enrolled_sql($contextmodule, 'mod/scorm:savetrack', (int) $currentgroup);
         if (empty($currentgroup)) {
             // All users who can attempt scoes.
-            if (!$students = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', 'u.id', '', '', '', '', '', false)) {
+            if (!$DB->record_exists_sql($allowedlistsql, $params)) {
                 echo $OUTPUT->notification(get_string('nostudentsyet'));
                 $nostudents = true;
-                $allowedlist = '';
-            } else {
-                $allowedlist = array_keys($students);
             }
-            unset($students);
         } else {
             // All users who can attempt scoes and who are in the currently selected group.
-            $groupstudents = get_users_by_capability($contextmodule, 'mod/scorm:savetrack',
-                                                     'u.id', '', '', '', $currentgroup, '', false);
-            if (!$groupstudents) {
+            if (!$DB->record_exists_sql($allowedlistsql, $params)) {
                 echo $OUTPUT->notification(get_string('nostudentsingroup'));
                 $nostudents = true;
-                $groupstudents = array();
             }
-            $allowedlist = array_keys($groupstudents);
-            unset($groupstudents);
         }
         if ( !$nostudents ) {
             // Now check if asked download of data.
@@ -157,8 +148,6 @@ class report extends \mod_scorm\report {
                 }
             }
 
-            $params = array();
-            list($usql, $params) = $DB->get_in_or_equal($allowedlist, SQL_PARAMS_NAMED);
             // Construct the SQL.
             $select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, ';
             $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' .
@@ -171,15 +160,15 @@ class report extends \mod_scorm\report {
             switch ($attemptsmode) {
                 case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH:
                     // Show only students with attempts.
-                    $where = ' WHERE u.id ' .$usql. ' AND st.userid IS NOT NULL';
+                    $where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NOT NULL";
                     break;
                 case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO:
                     // Show only students without attempts.
-                    $where = ' WHERE u.id ' .$usql. ' AND st.userid IS NULL';
+                    $where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NULL";
                     break;
                 case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS:
                     // Show all students with or without attempts.
-                    $where = ' WHERE u.id ' .$usql. ' AND (st.userid IS NOT NULL OR st.userid IS NULL)';
+                    $where = " WHERE u.id IN ({$allowedlistsql}) AND (st.userid IS NOT NULL OR st.userid IS NULL)";
                     break;
             }
 
index 3630be6..8aff844 100644 (file)
Binary files a/theme/boost/amd/build/pending.min.js and b/theme/boost/amd/build/pending.min.js differ
index 09b04e7..1d1b9b9 100644 (file)
Binary files a/theme/boost/amd/build/pending.min.js.map and b/theme/boost/amd/build/pending.min.js.map differ
index 4b3a548..ad036d4 100644 (file)
@@ -121,13 +121,13 @@ export default () => {
         pairs.forEach(pair => {
             const eventStart = `${pair.start}.bs.${key}`;
             const eventEnd = `${pair.end}.bs.${key}`;
-            jQuery(document.body).on(eventStart, () => {
+            jQuery(document.body).on(eventStart, e => {
                 M.util.js_pending(eventEnd);
+                jQuery(e.target).one(eventEnd, () => {
+                    M.util.js_complete(eventEnd);
+                });
             });
 
-            jQuery(document.body).on(eventEnd, () => {
-                M.util.js_complete(eventEnd);
-            });
         });
     });
 };