Merge branch 'MDL-66852-master' of github.com:lucaboesch/moodle
authorSara Arjona <sara@moodle.com>
Wed, 9 Oct 2019 10:58:00 +0000 (12:58 +0200)
committerSara Arjona <sara@moodle.com>
Wed, 9 Oct 2019 10:58:00 +0000 (12:58 +0200)
77 files changed:
admin/registration/confirmregistration.php
admin/registration/forms.php
admin/registration/index.php
admin/registration/renewregistration.php
admin/renderer.php
admin/settings/appearance.php
admin/tool/lp/classes/output/manage_competency_frameworks_page.php
admin/tool/monitor/lib.php
admin/tool/usertours/classes/manager.php
backup/cc/cc2moodle.php
blocks/online_users/block_online_users.php
blocks/online_users/classes/fetcher.php
blocks/online_users/lang/en/block_online_users.php
blocks/online_users/settings.php
blocks/online_users/tests/behat/block_online_users_course.feature
blocks/online_users/tests/behat/block_online_users_dashboard.feature
blocks/online_users/tests/behat/block_online_users_frontpage.feature
blocks/online_users/tests/online_users_test.php
blocks/online_users/version.php
blocks/participants/block_participants.php [deleted file]
blocks/participants/classes/privacy/provider.php [deleted file]
blocks/participants/db/access.php [deleted file]
blocks/participants/lang/en/block_participants.php [deleted file]
blocks/participants/tests/behat/block_participants_course.feature [deleted file]
blocks/participants/tests/behat/block_participants_frontpage.feature [deleted file]
blocks/participants/version.php [deleted file]
blocks/tests/externallib_test.php
blocks/upgrade.txt
cache/stores/redis/addinstanceform.php
cache/stores/redis/lang/en/cachestore_redis.php
cache/stores/redis/lib.php
cache/stores/redis/tests/compressor_test.php [new file with mode: 0644]
cache/upgrade.txt
config-dist.php
enrol/tests/enrollib_test.php
index.php
lang/en/admin.php
lang/en/deprecated.txt
lang/en/hub.php
lib/amd/build/str.min.js
lib/amd/build/str.min.js.map
lib/amd/src/str.js
lib/classes/hub/api.php
lib/classes/hub/registration.php
lib/classes/hub/site_registration_form.php
lib/classes/hub/site_unregistration_form.php [deleted file]
lib/classes/plugin_manager.php
lib/classes/useragent.php
lib/db/upgrade.php
lib/db/upgradelib.php
lib/dml/tests/dml_table_test.php
lib/enrollib.php
lib/filelib.php
lib/filestorage/tests/file_storage_test.php
lib/filestorage/tests/file_system_filedir_test.php
lib/filestorage/tests/file_system_test.php
lib/moodlelib.php
lib/tests/filelib_test.php
lib/tests/upgradelib_test.php
lib/tests/useragent_test.php
mod/forum/tests/behat/forum_export.feature [new file with mode: 0644]
mod/forum/tests/managers_capability_test.php
mod/forum/tests/vaults_forum_test.php
mod/forum/tests/vaults_post_test.php
phpunit.xml.dist
privacy/tests/approved_contextlist_test.php
privacy/tests/approved_userlist_test.php
privacy/tests/collection_test.php
privacy/tests/contextlist_base_test.php
privacy/tests/contextlist_collection_test.php
privacy/tests/contextlist_test.php
privacy/tests/manager_test.php
privacy/tests/moodle_content_writer_test.php
privacy/tests/writer_test.php
theme/boost/lang/en/theme_boost.php
theme/classic/lang/en/theme_classic.php
version.php

index 7c9d422..ff99680 100644 (file)
@@ -46,7 +46,7 @@ $error = optional_param('error', '', PARAM_ALPHANUM);
 admin_externalpage_setup('registrationmoodleorg');
 
 if ($url !== HUB_MOODLEORGHUBURL) {
-    // Allow other plugins to confirm registration on hubs other than moodle.net . Plugins implementing this
+    // Allow other plugins to confirm registration on custom hubs. Plugins implementing this
     // callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
     $callbacks = get_plugins_with_function('hub_registration');
     foreach ($callbacks as $plugintype => $plugins) {
index 6fe9553..af05a7a 100644 (file)
@@ -32,5 +32,4 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-debugging('Support for alternative hubs has been removed from Moodle in 3.4. For communication with moodle.net ' .
-    'see lib/classes/hub/ .', DEBUG_DEVELOPER);
+debugging('Support for alternative hubs has been removed from Moodle in 3.4.', DEBUG_DEVELOPER);
index 62f251a..ede6a67 100644 (file)
@@ -22,7 +22,7 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
  * @copyright  (C) 1999 onwards Martin Dougiamas  http://dougiamas.com
  *
- * This page displays the site registration form for Moodle.net.
+ * This page displays the site registration form.
  * It handles redirection to the hub to continue the registration workflow process.
  * It also handles update operation by web service.
  */
@@ -32,24 +32,25 @@ require_once($CFG->libdir . '/adminlib.php');
 
 admin_externalpage_setup('registrationmoodleorg');
 
-$unregistration = optional_param('unregistration', 0, PARAM_INT);
+$unregistration = optional_param('unregistration', false, PARAM_BOOL);
+$confirm = optional_param('confirm', false, PARAM_BOOL);
 
 if ($unregistration && \core\hub\registration::is_registered()) {
-    $siteunregistrationform = new \core\hub\site_unregistration_form();
+    if ($confirm) {
+        require_sesskey();
+        \core\hub\registration::unregister(false, false);
 
-    if ($siteunregistrationform->is_cancelled()) {
-        redirect(new moodle_url('/admin/registration/index.php'));
-    } else if ($data = $siteunregistrationform->get_data()) {
-        \core\hub\registration::unregister($data->unpublishalladvertisedcourses,
-            $data->unpublishalluploadedcourses);
         if (!\core\hub\registration::is_registered()) {
             redirect(new moodle_url('/admin/registration/index.php'));
         }
     }
 
     echo $OUTPUT->header();
-    echo $OUTPUT->heading(get_string('unregisterfrom', 'hub', 'Moodle.net'), 3, 'main');
-    $siteunregistrationform->display();
+    echo $OUTPUT->confirm(
+        get_string('registerwithmoodleorgremove', 'core_hub'),
+        new moodle_url(new moodle_url('/admin/registration/index.php', ['unregistration' => 1, 'confirm' => 1])),
+        new moodle_url(new moodle_url('/admin/registration/index.php'))
+    );
     echo $OUTPUT->footer();
     exit;
 }
@@ -82,7 +83,7 @@ if ($fromform = $siteregistrationform->get_data()) {
 
 echo $OUTPUT->header();
 
-// Current status of registration on Moodle.net.
+// Current status of registration.
 
 $notificationtype = \core\output\notification::NOTIFY_ERROR;
 if (\core\hub\registration::is_registered()) {
@@ -104,11 +105,11 @@ if (\core\hub\registration::is_registered()) {
 
 // Heading.
 if (\core\hub\registration::is_registered()) {
-    echo $OUTPUT->heading(get_string('updatesite', 'hub', 'Moodle.net'));
+    echo $OUTPUT->heading(get_string('registerwithmoodleorgupdate', 'core_hub'));
 } else if ($isinitialregistration) {
-    echo $OUTPUT->heading(get_string('completeregistration', 'hub'));
+    echo $OUTPUT->heading(get_string('registerwithmoodleorgcomplete', 'core_hub'));
 } else {
-    echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
+    echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'core_hub'));
 }
 
 $renderer = $PAGE->get_renderer('core', 'admin');
@@ -119,8 +120,9 @@ $siteregistrationform->display();
 if (\core\hub\registration::is_registered()) {
     // Unregister link.
     $unregisterhuburl = new moodle_url("/admin/registration/index.php", ['unregistration' => 1]);
-    echo html_writer::div(html_writer::link($unregisterhuburl, get_string('unregister', 'hub')), 'unregister');
+    echo html_writer::div(html_writer::link($unregisterhuburl, get_string('unregister', 'hub')), 'unregister mt-2');
 } else if ($isinitialregistration) {
-    echo html_writer::div(html_writer::link(new moodle_url($returnurl), get_string('skipregistration', 'hub')), 'skipregistration');
+    echo html_writer::div(html_writer::link(new moodle_url($returnurl), get_string('skipregistration', 'hub')),
+        'skipregistration mt-2');
 }
 echo $OUTPUT->footer();
index 84e727b..bc05da6 100644 (file)
@@ -40,7 +40,7 @@ $token = optional_param('token', '', PARAM_TEXT);
 admin_externalpage_setup('registrationmoodleorg');
 
 if ($url !== HUB_MOODLEORGHUBURL) {
-    // Allow other plugins to renew registration on hubs other than moodle.net . Plugins implementing this
+    // Allow other plugins to renew registration on custom hubs. Plugins implementing this
     // callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
     $callbacks = get_plugins_with_function('hub_registration');
     foreach ($callbacks as $plugintype => $plugins) {
@@ -56,7 +56,7 @@ if ($url !== HUB_MOODLEORGHUBURL) {
 
 echo $OUTPUT->header();
 echo $OUTPUT->heading(get_string('renewregistration', 'hub'), 3, 'main');
-$hublink = html_writer::tag('a', 'Moodle.net', array('href' => HUB_MOODLEORGHUBURL));
+$hublink = html_writer::tag('a', HUB_MOODLEORGHUBURL, array('href' => HUB_MOODLEORGHUBURL));
 
 $deletedregmsg = get_string('previousregistrationdeleted', 'hub', $hublink);
 
index 773ba4d..5abd08e 100644 (file)
@@ -2112,6 +2112,27 @@ class core_admin_renderer extends plugin_renderer_base {
      * @return string
      */
     public function moodleorg_registration_message() {
-        return format_text(get_string('registermoodlenet', 'admin'), FORMAT_HTML, ['noclean' => true]);
+
+        $out = format_text(get_string('registerwithmoodleorginfo', 'core_hub'), FORMAT_MARKDOWN);
+
+        $out .= html_writer::link(
+            new moodle_url('/admin/settings.php', ['section' => 'moodleservices']),
+            $this->output->pix_icon('i/info', '').' '.get_string('registerwithmoodleorginfoapp', 'core_hub'),
+            ['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href']
+        );
+
+        $out .= html_writer::link(
+            HUB_MOODLEORGHUBURL,
+            $this->output->pix_icon('i/stats', '').' '.get_string('registerwithmoodleorginfostats', 'core_hub'),
+            ['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href']
+        );
+
+        $out .= html_writer::link(
+            HUB_MOODLEORGHUBURL.'/sites',
+            $this->output->pix_icon('i/location', '').' '.get_string('registerwithmoodleorginfosites', 'core_hub'),
+            ['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href']
+        );
+
+        return $this->output->box($out);
     }
 }
index dc924f7..c9d406a 100644 (file)
@@ -197,6 +197,10 @@ preferences,moodle|/user/preferences.php|t/preferences',
         'idnumber' => new lang_string('sort_idnumber', 'admin'),
     );
     $temp->add(new admin_setting_configselect('navsortmycoursessort', new lang_string('navsortmycoursessort', 'admin'), new lang_string('navsortmycoursessort_help', 'admin'), 'sortorder', $sortoptions));
+    $temp->add(new admin_setting_configcheckbox('navsortmycourseshiddenlast',
+            new lang_string('navsortmycourseshiddenlast', 'admin'),
+            new lang_string('navsortmycourseshiddenlast_help', 'admin'),
+            1));
     $temp->add(new admin_setting_configtext('navcourselimit', new lang_string('navcourselimit', 'admin'),
         new lang_string('confignavcourselimit', 'admin'), 10, PARAM_INT));
     $temp->add(new admin_setting_configcheckbox('usesitenameforsitepages', new lang_string('usesitenameforsitepages', 'admin'), new lang_string('configusesitenameforsitepages', 'admin'), 0));
index 7a2181b..07a6dad 100644 (file)
@@ -75,7 +75,7 @@ class manage_competency_frameworks_page implements renderable, templatable {
             );
             $this->navigation[] = $addpage;
             $competenciesrepository = new single_button(
-                new moodle_url('https://moodle.net/competencies'),
+                new moodle_url('https://archive.moodle.net/competencies'),
                 get_string('competencyframeworksrepository', 'tool_lp'),
                 'get'
             );
index 58078ec..df11ac9 100644 (file)
@@ -119,7 +119,9 @@ function tool_monitor_can_subscribe() {
  * @return array|bool Returns an array of courses or false if the user has no permission to subscribe to rules.
  */
 function tool_monitor_get_user_courses() {
-    $orderby = 'visible DESC, sortorder ASC';
+    // Get the course sorting according to the admin settings.
+    $sort = enrol_get_courses_sortingsql();
+
     $options = array();
     if (has_capability('tool/monitor:subscribe', context_system::instance())) {
         $options[0] = get_string('site');
@@ -134,7 +136,7 @@ function tool_monitor_get_user_courses() {
         );
 
     $fields = implode(', ', $fieldlist);
-    if ($courses = get_user_capability_course('tool/monitor:subscribe', null, true, $fields, $orderby)) {
+    if ($courses = get_user_capability_course('tool/monitor:subscribe', null, true, $fields, $sort)) {
         foreach ($courses as $course) {
             context_helper::preload_from_record($course);
             $coursectx = context_course::instance($course->id);
index 33cd752..40d2595 100644 (file)
@@ -266,7 +266,7 @@ class manager {
                 'title' => get_string('importtour', 'tool_usertours'),
             ],
             (object) [
-                'link'  => new \moodle_url('https://moodle.net/tours'),
+                'link'  => new \moodle_url('https://archive.moodle.net/tours'),
                 'linkproperties' => [
                         'target' => '_blank',
                     ],
index 6ecf6fe..88895a9 100644 (file)
@@ -384,7 +384,7 @@ class cc2moodle {
             if (isset($CFG->defaultblocks)) {
                 $blocknames = $CFG->defaultblocks;
             } else {
-                $blocknames = 'participants,activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
+                $blocknames = 'activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
             }
         }
 
index 01ada95..9d1fc90 100644 (file)
@@ -129,14 +129,16 @@ class block_online_users extends block_base {
                     $this->content->text .= $OUTPUT->user_picture($user, array('size'=>16, 'alttext'=>false, 'link'=>false)) .$user->fullname.'</a></div>';
 
                     if ($USER->id == $user->id) {
-                        $action = ($user->uservisibility != null && $user->uservisibility == 0) ? 'show' : 'hide';
-                        $anchortagcontents = $OUTPUT->pix_icon('t/' . $action,
-                            get_string('online_status:' . $action, 'block_online_users'));
-                        $anchortag = html_writer::link("", $anchortagcontents,
-                            array('title' => get_string('online_status:' . $action, 'block_online_users'),
-                                'data-action' => $action, 'data-userid' => $user->id, 'id' => 'change-user-visibility'));
-
-                        $this->content->text .= '<div class="uservisibility">' . $anchortag . '</div>';
+                        if ($CFG->block_online_users_onlinestatushiding) {
+                            $action = ($user->uservisibility != null && $user->uservisibility == 0) ? 'show' : 'hide';
+                            $anchortagcontents = $OUTPUT->pix_icon('t/' . $action,
+                                get_string('online_status:' . $action, 'block_online_users'));
+                            $anchortag = html_writer::link("", $anchortagcontents,
+                                array('title' => get_string('online_status:' . $action, 'block_online_users'),
+                                    'data-action' => $action, 'data-userid' => $user->id, 'id' => 'change-user-visibility'));
+
+                            $this->content->text .= '<div class="uservisibility">' . $anchortag . '</div>';
+                        }
                     } else {
                         if ($canshowicon) {  // Only when logged in and messaging active etc.
                             $anchortagcontents = $OUTPUT->pix_icon('t/message', get_string('messageselectadd'));
index 20f706f..a18e625 100644 (file)
@@ -67,7 +67,7 @@ class fetcher {
      * @param int $courseid The course id to check
      */
     protected function set_sql($currentgroup, $now, $timetoshowusers, $context, $sitelevel, $courseid) {
-        global $USER, $DB;
+        global $USER, $DB, $CFG;
 
         $timefrom = 100 * floor(($now - $timetoshowusers) / 100); // Round to nearest 100 seconds for better query cache.
 
@@ -76,7 +76,14 @@ class fetcher {
         $groupby       = "";
         $lastaccess    = ", lastaccess";
         $timeaccess    = ", ul.timeaccess AS lastaccess";
-        $uservisibility = ", up.value AS uservisibility";
+        $uservisibility = "";
+        $uservisibilityselect = "";
+        if ($CFG->block_online_users_onlinestatushiding) {
+            $uservisibility = ", up.value AS uservisibility";
+            $uservisibilityselect = "AND (" . $DB->sql_cast_char2int('up.value') . " = 1
+                                    OR up.value IS NULL
+                                    OR u.id = :userid)";
+        }
         $params = array();
 
         $userfields = \user_picture::fields('u', array('username'));
@@ -88,7 +95,9 @@ class fetcher {
             $groupby = "GROUP BY $userfields";
             $lastaccess = ", MAX(u.lastaccess) AS lastaccess";
             $timeaccess = ", MAX(ul.timeaccess) AS lastaccess";
-            $uservisibility = ", MAX(up.value) AS uservisibility";
+            if ($CFG->block_online_users_onlinestatushiding) {
+                $uservisibility = ", MAX(up.value) AS uservisibility";
+            }
             $params['currentgroup'] = $currentgroup;
         }
 
@@ -105,9 +114,7 @@ class fetcher {
                      WHERE u.lastaccess > :timefrom
                            AND u.lastaccess <= :now
                            AND u.deleted = 0
-                           AND (" . $DB->sql_cast_char2int('up.value') . " = 1
-                               OR up.value IS NULL
-                               OR u.id = :userid)
+                           $uservisibilityselect
                            $groupselect $groupby
                   ORDER BY lastaccess DESC ";
 
@@ -118,9 +125,7 @@ class fetcher {
                       WHERE u.lastaccess > :timefrom
                             AND u.lastaccess <= :now
                             AND u.deleted = 0
-                            AND (" . $DB->sql_cast_char2int('up.value') . " = 1
-                                OR up.value IS NULL
-                                OR u.id = :userid)
+                            $uservisibilityselect
                             $groupselect";
         } else {
             // Course level - show only enrolled users for now.
@@ -138,9 +143,7 @@ class fetcher {
                            AND ul.courseid = :courseid
                            AND ul.timeaccess <= :now
                            AND u.deleted = 0
-                           AND (" . $DB->sql_cast_char2int('up.value') . " = 1
-                               OR up.value IS NULL
-                               OR u.id = :userid)
+                           $uservisibilityselect
                            $groupselect $groupby
                   ORDER BY lastaccess DESC";
 
@@ -154,9 +157,7 @@ class fetcher {
                            AND ul.courseid = :courseid
                            AND ul.timeaccess <= :now
                            AND u.deleted = 0
-                           AND (" . $DB->sql_cast_char2int('up.value') . " = 1
-                               OR up.value IS NULL
-                               OR u.id = :userid)
+                           $uservisibilityselect
                            $groupselect";
 
             $params['courseid'] = $courseid;
index c6bc022..f34f5d6 100644 (file)
@@ -23,7 +23,9 @@
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['onlinestatushiding_desc'] = 'If enabled, users have the option to hide their online status from other users.';
 $string['configtimetosee'] = 'Number of minutes determining the period of inactivity after which a user is no longer considered to be online.';
+$string['onlinestatushiding'] = 'Online status hiding';
 $string['nouser'] = 'No online users';
 $string['numuser'] = '{$a} online user';
 $string['numusers'] = '{$a} online users';
index b9d7d81..39d3bf0 100644 (file)
@@ -27,5 +27,9 @@ defined('MOODLE_INTERNAL') || die;
 if ($ADMIN->fulltree) {
     $settings->add(new admin_setting_configtext('block_online_users_timetosee', get_string('timetosee', 'block_online_users'),
                    get_string('configtimetosee', 'block_online_users'), 5, PARAM_INT));
+
+    $settings->add(new admin_setting_configcheckbox('block_online_users_onlinestatushiding',
+            get_string('onlinestatushiding', 'block_online_users'),
+            get_string('onlinestatushiding_desc', 'block_online_users'), 1));
 }
 
index 20b0d95..097cee1 100644 (file)
@@ -42,7 +42,9 @@ Feature: The online users block allow you to see who is currently online
 
   @javascript
   Scenario: Hide/show user's online status from/to other users in the online users block on course page
-    Given I log in as "teacher1"
+    Given the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 1 |
+    And I log in as "teacher1"
     And I am on "Course 1" course homepage with editing mode on
     And I add the "Online users" block
     And I log out
@@ -71,3 +73,45 @@ Feature: The online users block allow you to see who is currently online
     Then I should see "2 online users" in the "Online users" "block"
     And I should see "Teacher 1" in the "Online users" "block"
     And I should see "Student 1" in the "Online users" "block"
+
+  @javascript
+  Scenario: Hide/show icon is not visible in the online users block on course page when the setting is disabled
+    Given the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 1 |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Online users" block
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And "Hide" "icon" should exist in the ".block.block_online_users" "css_element"
+    And I log out
+    And the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 0 |
+    When I log in as "student1"
+    Then I should see "Student 1" in the "Online users" "block"
+    And "Hide" "icon" should not exist in the ".block.block_online_users" "css_element"
+
+  @javascript
+  Scenario: User is displayed in the online users block on course page when visibility setting is disabled,
+            ignoring the previously set visibility state
+    Given the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 1 |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Online users" block
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And "Hide" "icon" should exist in the "#change-user-visibility" "css_element"
+    And I click on "#change-user-visibility" "css_element"
+    And I wait "1" seconds
+    And "Show" "icon" should exist in the "#change-user-visibility" "css_element"
+    And I log out
+    And the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 0 |
+    And I log in as "teacher1"
+    When I am on "Course 1" course homepage
+    Then I should see "2 online users" in the "Online users" "block"
+    And I should see "Teacher 1" in the "Online users" "block"
+    And I should see "Student 1" in the "Online users" "block"
index 0d01207..2d32fc6 100644 (file)
@@ -29,7 +29,9 @@ Feature: The online users block allow you to see who is currently online on dash
 
   @javascript
   Scenario: Hide/show user's online status from/to other users in the online users block on dashboard
-    Given I log in as "student1"
+    Given the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 1 |
+    And I log in as "student1"
     And I should see "1 online user" in the "Online users" "block"
     And I should see "Student 1" in the "Online users" "block"
     And "Hide" "icon" should exist in the "#change-user-visibility" "css_element"
@@ -52,3 +54,44 @@ Feature: The online users block allow you to see who is currently online on dash
     Then I should see "2 online users" in the "Online users" "block"
     And I should see "Student 2" in the "Online users" "block"
     And I should see "Student 1" in the "Online users" "block"
+
+  @javascript
+  Scenario: Hide/show icon is not visible in the online users block when the setting is disabled
+    Given the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 1 |
+    And I log in as "student1"
+    And I should see "1 online user" in the "Online users" "block"
+    And I should see "Student 1" in the "Online users" "block"
+    And "Hide" "icon" should exist in the ".block.block_online_users" "css_element"
+    And I log out
+    And the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 0 |
+    When I log in as "student1"
+    Then I should see "1 online user" in the "Online users" "block"
+    And I should see "Student 1" in the "Online users" "block"
+    And "Hide" "icon" should not exist in the ".block.block_online_users" "css_element"
+
+  @javascript
+  Scenario: User is displayed in the online users block when visibility setting is disabled,
+            ignoring the previously set visibility state
+    Given the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 1 |
+    And I log in as "student1"
+    And I should see "1 online user" in the "Online users" "block"
+    And I should see "Student 1" in the "Online users" "block"
+    And "Hide" "icon" should exist in the "#change-user-visibility" "css_element"
+    And I click on "#change-user-visibility" "css_element"
+    And I wait "1" seconds
+    And "Show" "icon" should exist in the "#change-user-visibility" "css_element"
+    And I log out
+    And I log in as "student2"
+    And I should see "1 online user" in the "Online users" "block"
+    And I should see "Student 2" in the "Online users" "block"
+    And I should not see "Student 1" in the "Online users" "block"
+    And I log out
+    And the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 0 |
+    When I log in as "student2"
+    Then I should see "2 online users" in the "Online users" "block"
+    And I should see "Student 2" in the "Online users" "block"
+    And I should see "Student 1" in the "Online users" "block"
index 097c9e7..ca817e8 100644 (file)
@@ -52,7 +52,9 @@ Feature: The online users block allow you to see who is currently online on fron
 
   @javascript
   Scenario: Hide/show user's online status from/to other users in the online users block on front page
-    Given I log in as "admin"
+    Given the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 1 |
+    And I log in as "admin"
     And I am on site homepage
     And I navigate to "Turn editing on" in current page administration
     And I add the "Online users" block
@@ -84,3 +86,55 @@ Feature: The online users block allow you to see who is currently online on fron
     And I should see "Admin" in the "Online users" "block"
     And I should see "Student 2" in the "Online users" "block"
     And I should see "Student 1" in the "Online users" "block"
+
+  @javascript
+  Scenario: Hide/show icon is not visible in the online users block on front page when the setting is disabled
+    Given the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 1 |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" in current page administration
+    And I add the "Online users" block
+    And I log out
+    And I log in as "student1"
+    And I am on site homepage
+    And "Hide" "icon" should exist in the ".block.block_online_users" "css_element"
+    And I log out
+    And the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 0 |
+    When I log in as "student1"
+    Then I should see "Student 1" in the "Online users" "block"
+    And "Hide" "icon" should not exist in the ".block.block_online_users" "css_element"
+
+  @javascript
+  Scenario: User is displayed in the online users block on front page when visibility setting is disabled,
+            ignoring the previously set visibility state
+    Given the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 1 |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" in current page administration
+    And I add the "Online users" block
+    And I log out
+    And I log in as "student1"
+    And I am on site homepage
+    And "Hide" "icon" should exist in the "#change-user-visibility" "css_element"
+    And I click on "#change-user-visibility" "css_element"
+    And I wait "1" seconds
+    And "Show" "icon" should exist in the "#change-user-visibility" "css_element"
+    And I log out
+    And I log in as "student2"
+    And I am on site homepage
+    And I should see "2 online user" in the "Online users" "block"
+    And I should see "Admin" in the "Online users" "block"
+    And I should see "Student 2" in the "Online users" "block"
+    And I should not see "Student 1" in the "Online users" "block"
+    And I log out
+    And the following config values are set as admin:
+      | block_online_users_onlinestatushiding | 0 |
+    And I log in as "student2"
+    When I am on site homepage
+    Then I should see "3 online users" in the "Online users" "block"
+    And I should see "Admin" in the "Online users" "block"
+    And I should see "Student 2" in the "Online users" "block"
+    And I should see "Student 1" in the "Online users" "block"
index 946e456..da436ac 100644 (file)
@@ -155,6 +155,8 @@ class block_online_users_testcase extends advanced_testcase {
     public function test_user_visibility_course1_group1_members() {
         global $CFG;
 
+        // Enable users to set their visibility to others in the online users block.
+        $CFG->block_online_users_onlinestatushiding = true;
         $groupid = $this->data['group1']->id;
         $now = time();
         $timetoshowusers = $CFG->block_online_users_timetosee * 60;
@@ -190,6 +192,18 @@ class block_online_users_testcase extends advanced_testcase {
         // User1 should not be displayed in the online users block.
         $this->assertEquals(2, $usercount);
         $this->assertFalse(array_key_exists($user1->id, $users));
+
+        // Disable users to set their visibility to others in the online users block.
+        // All users should be displayed now and the visibility status of a users should be ignored,
+        // as the capability of setting the visibility to other user has been disabled.
+        $CFG->block_online_users_onlinestatushiding = false;
+        // Test if the fetcher gets all the users including user1.
+        $onlineusers = new fetcher($groupid, $now, $timetoshowusers, $context, false, $courseid);
+        $users = $onlineusers->get_users();
+        $usercount = $onlineusers->count_users();
+        // User1 should be displayed in the online users block.
+        $this->assertEquals(3, $usercount);
+        $this->assertTrue(array_key_exists($user1->id, $users));
     }
 
     /**
@@ -234,6 +248,18 @@ class block_online_users_testcase extends advanced_testcase {
         // User1 should not be displayed in the online users block.
         $this->assertEquals(8, $usercount);
         $this->assertFalse(array_key_exists($user1->id, $users));
+
+        // Disable users to set their visibility to others in the online users block.
+        // All users should be displayed now and the visibility status of a users should be ignored,
+        // as the capability of setting the visibility to other user has been disabled.
+        $CFG->block_online_users_onlinestatushiding = false;
+        // Test if the fetcher gets all the users including user1.
+        $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, false, $courseid);
+        $users = $onlineusers->get_users();
+        $usercount = $onlineusers->count_users();
+        // User1 should be displayed in the online users block.
+        $this->assertEquals(9, $usercount);
+        $this->assertTrue(array_key_exists($user1->id, $users));
     }
 
     /**
@@ -277,5 +303,17 @@ class block_online_users_testcase extends advanced_testcase {
         // User1 should not be displayed in the online users block.
         $this->assertEquals(11, $usercount);
         $this->assertFalse(array_key_exists($user1->id, $users));
+
+        // Disable users to set their visibility to others in the online users block.
+        // All users should be displayed now and the visibility status of a users should be ignored,
+        // as the capability of setting the visibility to other user has been disabled.
+        $CFG->block_online_users_onlinestatushiding = false;
+        // Test if the fetcher gets all the users including user1.
+        $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, true);
+        $users = $onlineusers->get_users();
+        $usercount = $onlineusers->count_users();
+        // User1 should be displayed in the online users block.
+        $this->assertEquals(12, $usercount);
+        $this->assertTrue(array_key_exists($user1->id, $users));
     }
 }
index eaf8a55..c5806d3 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2019052000;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2019052001;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2019051100;        // Requires this Moodle version
 $plugin->component = 'block_online_users'; // Full name of the plugin (used for diagnostics)
diff --git a/blocks/participants/block_participants.php b/blocks/participants/block_participants.php
deleted file mode 100644 (file)
index b1b433b..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Participants block
- *
- * @package    block_participants
- * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-require_once($CFG->dirroot . '/course/lib.php');
-
-/**
- * Participants block
- *
- * @package    block_participants
- * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class block_participants extends block_list {
-    function init() {
-        $this->title = get_string('pluginname', 'block_participants');
-    }
-
-    function get_content() {
-
-        global $CFG, $OUTPUT;
-
-        if (empty($this->instance)) {
-            $this->content = '';
-            return $this->content;
-        }
-
-        $this->content = new stdClass();
-        $this->content->items = array();
-        $this->content->icons = array();
-        $this->content->footer = '';
-
-        // user/index.php expect course context, so get one if page has module context.
-        $currentcontext = $this->page->context->get_course_context(false);
-
-        if (empty($currentcontext)) {
-            $this->content = '';
-            return $this->content;
-        } else if ($this->page->course->id == SITEID) {
-            if (!course_can_view_participants(context_system::instance())) {
-                $this->content = '';
-                return $this->content;
-            }
-        } else {
-            if (!course_can_view_participants($currentcontext)) {
-                $this->content = '';
-                return $this->content;
-            }
-        }
-
-        $icon = $OUTPUT->pix_icon('i/users', '');
-        $this->content->items[] = '<a title="'.get_string('listofallpeople').'" href="'.
-                                  $CFG->wwwroot.'/user/index.php?contextid='.$currentcontext->id.'">'.$icon.get_string('participants').'</a>';
-
-        return $this->content;
-    }
-
-    // my moodle can only have SITEID and it's redundant here, so take it away
-    function applicable_formats() {
-        return array('all' => true, 'my' => false, 'tag' => false);
-    }
-
-}
diff --git a/blocks/participants/classes/privacy/provider.php b/blocks/participants/classes/privacy/provider.php
deleted file mode 100644 (file)
index efcffd1..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Privacy Subsystem implementation for block_participants.
- *
- * @package    block_participants
- * @copyright  2018 Zig Tan <zig@moodle.com>
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-namespace block_participants\privacy;
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- * Privacy Subsystem for block_participants implementing null_provider.
- *
- * @copyright  2018 Zig Tan <zig@moodle.com>
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class provider implements \core_privacy\local\metadata\null_provider {
-
-    /**
-     * Get the language string identifier with the component's language
-     * file to explain why this plugin stores no data.
-     *
-     * @return  string
-     */
-    public static function get_reason() : string {
-        return 'privacy:metadata';
-    }
-}
diff --git a/blocks/participants/db/access.php b/blocks/participants/db/access.php
deleted file mode 100644 (file)
index 734f8a1..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Participants block caps.
- *
- * @package    block_participants
- * @copyright  Mark Nelson <markn@moodle.com>
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-$capabilities = array(
-
-    'block/participants:addinstance' => array(
-        'riskbitmask' => RISK_SPAM | RISK_XSS,
-
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_BLOCK,
-        'archetypes' => array(
-            'editingteacher' => CAP_ALLOW,
-            'manager' => CAP_ALLOW
-        ),
-
-        'clonepermissionsfrom' => 'moodle/site:manageblocks'
-    ),
-);
diff --git a/blocks/participants/lang/en/block_participants.php b/blocks/participants/lang/en/block_participants.php
deleted file mode 100644 (file)
index 20eb2dd..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Strings for component 'block_participants', language 'en', branch 'MOODLE_20_STABLE'
- *
- * @package   block_participants
- * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-$string['participants:addinstance'] = 'Add a new people block';
-$string['pluginname'] = 'People';
-$string['privacy:metadata'] = 'The People block only shows data stored in other locations.';
diff --git a/blocks/participants/tests/behat/block_participants_course.feature b/blocks/participants/tests/behat/block_participants_course.feature
deleted file mode 100644 (file)
index 5fa4a0b..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-@block @block_participants
-Feature: People Block used in a course
-  In order to view participants in a course
-  As a teacher
-  I can add the people block to a course
-
-  Background:
-    Given the following "courses" exist:
-      | fullname | shortname | category |
-      | Course 1 | C101      | 0        |
-    And the following "users" exist:
-      | username    | firstname | lastname | email            |
-      | student1    | Sam       | Student  | student1@example.com |
-    And the following "course enrolments" exist:
-      | user        | course | role           |
-      | student1    | C101   | student        |
-    And I log in as "admin"
-    And I am on "Course 1" course homepage with editing mode on
-    And I add the "People" block
-    And I log out
-
-  Scenario: Student can view participants link
-    When I log in as "student1"
-    And I am on "Course 1" course homepage
-    Then "People" "block" should exist
-    And I should see "Participants" in the "People" "block"
-
-  Scenario: Student can follow participants link and be directed to the correct page
-    When I log in as "student1"
-    And I am on "Course 1" course homepage
-    And I click on "Participants" "link" in the "People" "block"
-    Then I should see "Participants" in the "#page-content" "css_element"
-
-  Scenario: Student without permission can not view participants link
-    Given the following "permission overrides" exist:
-         | capability | permission | role | contextlevel | reference |
-         | moodle/course:viewparticipants | Prevent | student | Course | C101 |
-    When I log in as "student1"
-    And I am on "Course 1" course homepage
-    Then "People" "block" should not exist
diff --git a/blocks/participants/tests/behat/block_participants_frontpage.feature b/blocks/participants/tests/behat/block_participants_frontpage.feature
deleted file mode 100644 (file)
index 3e47bd2..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-@block @block_participants
-Feature: People Block used on frontpage
-  In order to view participants in a site
-  As a admin
-  I can add the people block to the front page
-
-  Background:
-    Given the following "users" exist:
-      | username    | firstname | lastname | email            |
-      | student1    | Sam       | Student  | student1@example.com |
-    And I log in as "admin"
-    And I am on site homepage
-    And I navigate to "Turn editing on" in current page administration
-    And I add the "People" block
-    And I log out
-
-  Scenario: Admin can view site participants link
-    When I log in as "admin"
-    And I am on site homepage
-    Then "People" "block" should exist
-    And I should see "Participants" in the "People" "block"
-
-  Scenario: Student can not follow participants link on frontpage
-    When I log in as "student1"
-    And I am on site homepage
-    Then "People" "block" should not exist
diff --git a/blocks/participants/version.php b/blocks/participants/version.php
deleted file mode 100644 (file)
index d6ea91b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Version details
- *
- * @package    block_participants
- * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-$plugin->version   = 2019052000;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2019051100;        // Requires this Moodle version
-$plugin->component = 'block_participants'; // Full name of the plugin (used for diagnostics)
index 647e992..1694636 100644 (file)
@@ -112,7 +112,7 @@ class core_block_externallib_testcase extends externallib_advanced_testcase {
 
         $this->resetAfterTest(true);
 
-        $CFG->defaultblocks_override = 'participants,search_forums,course_list:calendar_upcoming,recent_activity';
+        $CFG->defaultblocks_override = 'search_forums,course_list:calendar_upcoming,recent_activity';
 
         $user = $this->getDataGenerator()->create_user();
         $course = $this->getDataGenerator()->create_course();
@@ -126,10 +126,10 @@ class core_block_externallib_testcase extends externallib_advanced_testcase {
         // We need to execute the return values cleaning process to simulate the web service server.
         $result = external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
 
-        // Expect 5 default blocks.
-        $this->assertCount(5, $result['blocks']);
+        // Expect 4 default blocks.
+        $this->assertCount(4, $result['blocks']);
 
-        $expectedblocks = array('navigation', 'settings', 'participants', 'search_forums', 'course_list',
+        $expectedblocks = array('navigation', 'settings', 'search_forums', 'course_list',
                                 'calendar_upcoming', 'recent_activity');
         foreach ($result['blocks'] as $block) {
             if (!in_array($block['name'], $expectedblocks)) {
index 0f370ee..5894b64 100644 (file)
@@ -3,6 +3,7 @@ information provided here is intended especially for developers.
 
 === 3.8 ===
 * Block block_community is no longer a part of core.
+* Block block_participants is no longer a part of core.
 
 === 3.7 ===
 * The block:addinstance capability is no longer required if the block can only be added to a dashboard.
index ad9bc00..1a3faa1 100644 (file)
@@ -58,5 +58,11 @@ class cachestore_redis_addinstance_form extends cachestore_addinstance_form {
         $form->addHelpButton('serializer', 'useserializer', 'cachestore_redis');
         $form->setDefault('serializer', Redis::SERIALIZER_PHP);
         $form->setType('serializer', PARAM_INT);
+
+        $compressoroptions = cachestore_redis::config_get_compressor_options();
+        $form->addElement('select', 'compressor', get_string('usecompressor', 'cachestore_redis'), $compressoroptions);
+        $form->addHelpButton('compressor', 'usecompressor', 'cachestore_redis');
+        $form->setDefault('compressor', cachestore_redis::COMPRESSOR_NONE);
+        $form->setType('compressor', PARAM_INT);
     }
 }
index 0d155be..a52b93f 100644 (file)
@@ -24,6 +24,9 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['compressor_none'] = 'No compression.';
+$string['compressor_php_gzip'] = 'Use gzip compression.';
+$string['compressor_php_zstd'] = 'Use Zstandard compression.';
 $string['pluginname'] = 'Redis';
 $string['prefix'] = 'Key prefix';
 $string['prefix_help'] = 'This prefix is used for all key names on the Redis server.
@@ -48,3 +51,5 @@ $string['useserializer'] = 'Use serializer';
 $string['useserializer_help'] = 'Specifies the serializer to use for serializing.
 The valid serializers are Redis::SERIALIZER_PHP or Redis::SERIALIZER_IGBINARY.
 The latter is supported only when phpredis is configured with --enable-redis-igbinary option and the igbinary extension is loaded.';
+$string['usecompressor'] = 'Use compressor';
+$string['usecompressor_help'] = 'Specifies the compressor to use after serializing. It is done at Moodle Cache API level, not at php-redis level.';
index 3596200..bde6b9e 100644 (file)
@@ -38,6 +38,21 @@ defined('MOODLE_INTERNAL') || die();
  */
 class cachestore_redis extends cache_store implements cache_is_key_aware, cache_is_lockable,
         cache_is_configurable, cache_is_searchable {
+    /**
+     * Compressor: none.
+     */
+    const COMPRESSOR_NONE = 0;
+
+    /**
+     * Compressor: PHP GZip.
+     */
+    const COMPRESSOR_PHP_GZIP = 1;
+
+    /**
+     * Compressor: PHP Zstandard.
+     */
+    const COMPRESSOR_PHP_ZSTD = 2;
+
     /**
      * Name of this store.
      *
@@ -80,6 +95,13 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_
      */
     protected $serializer = Redis::SERIALIZER_PHP;
 
+    /**
+     * Compressor for this store.
+     *
+     * @var int
+     */
+    protected $compressor = self::COMPRESSOR_NONE;
+
     /**
      * Determines if the requirements for this type of store are met.
      *
@@ -134,6 +156,9 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_
         if (array_key_exists('serializer', $configuration)) {
             $this->serializer = (int)$configuration['serializer'];
         }
+        if (array_key_exists('compressor', $configuration)) {
+            $this->compressor = (int)$configuration['compressor'];
+        }
         $password = !empty($configuration['password']) ? $configuration['password'] : '';
         $prefix = !empty($configuration['prefix']) ? $configuration['prefix'] : '';
         $this->redis = $this->new_redis($configuration['server'], $prefix, $password);
@@ -161,7 +186,10 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_
             if (!empty($password)) {
                 $redis->auth($password);
             }
-            $redis->setOption(Redis::OPT_SERIALIZER, $this->serializer);
+            // If using compressor, serialisation will be done at cachestore level, not php-redis.
+            if ($this->compressor == self::COMPRESSOR_NONE) {
+                $redis->setOption(Redis::OPT_SERIALIZER, $this->serializer);
+            }
             if (!empty($prefix)) {
                 $redis->setOption(Redis::OPT_PREFIX, $prefix);
             }
@@ -236,7 +264,13 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_
      * @return mixed The value of the key, or false if there is no value associated with the key.
      */
     public function get($key) {
-        return $this->redis->hGet($this->hash, $key);
+        $value = $this->redis->hGet($this->hash, $key);
+
+        if ($this->compressor == self::COMPRESSOR_NONE) {
+            return $value;
+        }
+
+        return $this->uncompress($value);
     }
 
     /**
@@ -246,7 +280,17 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_
      * @return array An array of the values of the given keys.
      */
     public function get_many($keys) {
-        return $this->redis->hMGet($this->hash, $keys);
+        $values = $this->redis->hMGet($this->hash, $keys);
+
+        if ($this->compressor == self::COMPRESSOR_NONE) {
+            return $values;
+        }
+
+        foreach ($values as &$value) {
+            $value = $this->uncompress($value);
+        }
+
+        return $values;
     }
 
     /**
@@ -257,6 +301,10 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_
      * @return bool True if the operation succeeded, false otherwise.
      */
     public function set($key, $value) {
+        if ($this->compressor != self::COMPRESSOR_NONE) {
+            $value = $this->compress($value);
+        }
+
         return ($this->redis->hSet($this->hash, $key, $value) !== false);
     }
 
@@ -270,7 +318,12 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_
     public function set_many(array $keyvaluearray) {
         $pairs = [];
         foreach ($keyvaluearray as $pair) {
-            $pairs[$pair['key']] = $pair['value'];
+            $key = $pair['key'];
+            if ($this->compressor != self::COMPRESSOR_NONE) {
+                $pairs[$key] = $this->compress($pair['value']);
+            } else {
+                $pairs[$key] = $pair['value'];
+            }
         }
         if ($this->redis->hMSet($this->hash, $pairs)) {
             return count($pairs);
@@ -446,7 +499,8 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_
             'server' => $data->server,
             'prefix' => $data->prefix,
             'password' => $data->password,
-            'serializer' => $data->serializer
+            'serializer' => $data->serializer,
+            'compressor' => $data->compressor,
         );
     }
 
@@ -465,6 +519,9 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_
         if (!empty($config['serializer'])) {
             $data['serializer'] = $config['serializer'];
         }
+        if (!empty($config['compressor'])) {
+            $data['compressor'] = $config['compressor'];
+        }
         $editform->set_data($data);
     }
 
@@ -538,4 +595,115 @@ class cachestore_redis extends cache_store implements cache_is_key_aware, cache_
         }
         return $options;
     }
+
+    /**
+     * Gets an array of options to use as the compressor.
+     *
+     * @return array
+     */
+    public static function config_get_compressor_options() {
+        $arr = [
+            self::COMPRESSOR_NONE     => get_string('compressor_none', 'cachestore_redis'),
+            self::COMPRESSOR_PHP_GZIP => get_string('compressor_php_gzip', 'cachestore_redis'),
+        ];
+
+        // Check if the Zstandard PHP extension is installed.
+        if (extension_loaded('zstd')) {
+            $arr[self::COMPRESSOR_PHP_ZSTD] = get_string('compressor_php_zstd', 'cachestore_redis');
+        }
+
+        return $arr;
+    }
+
+    /**
+     * Compress the given value, serializing it first.
+     *
+     * @param mixed $value
+     * @return string
+     */
+    private function compress($value) {
+        $value = $this->serialize($value);
+
+        switch ($this->compressor) {
+            case self::COMPRESSOR_NONE:
+                return $value;
+
+            case self::COMPRESSOR_PHP_GZIP:
+                return gzencode($value);
+
+            case self::COMPRESSOR_PHP_ZSTD:
+                return zstd_compress($value);
+
+            default:
+                debugging("Invalid compressor: {$this->compressor}");
+                return $value;
+        }
+    }
+
+    /**
+     * Uncompresses (deflates) the data, unserialising it afterwards.
+     *
+     * @param string $value
+     * @return mixed
+     */
+    private function uncompress($value) {
+        if ($value === false) {
+            return false;
+        }
+
+        switch ($this->compressor) {
+            case self::COMPRESSOR_NONE:
+                break;
+            case self::COMPRESSOR_PHP_GZIP:
+                $value = gzdecode($value);
+                break;
+            case self::COMPRESSOR_PHP_ZSTD:
+                $value = zstd_uncompress($value);
+                break;
+            default:
+                debugging("Invalid compressor: {$this->compressor}");
+        }
+
+        return $this->unserialize($value);
+    }
+
+    /**
+     * Serializes the data according to the configured serializer.
+     *
+     * @param mixed $value
+     * @return string
+     */
+    private function serialize($value) {
+        switch ($this->serializer) {
+            case Redis::SERIALIZER_NONE:
+                return $value;
+            case Redis::SERIALIZER_PHP:
+                return serialize($value);
+            case defined('Redis::SERIALIZER_IGBINARY') && Redis::SERIALIZER_IGBINARY:
+                return igbinary_serialize($value);
+            default:
+                debugging("Invalid serializer: {$this->serializer}");
+                return $value;
+        }
+    }
+
+    /**
+     * Unserializes the data according to the configured serializer
+     *
+     * @param string $value
+     * @return mixed
+     */
+    private function unserialize($value) {
+        switch ($this->serializer) {
+            case Redis::SERIALIZER_NONE:
+                return $value;
+            case Redis::SERIALIZER_PHP:
+                return unserialize($value);
+            case defined('Redis::SERIALIZER_IGBINARY') && Redis::SERIALIZER_IGBINARY:
+                return igbinary_unserialize($value);
+            default:
+                debugging("Invalid serializer: {$this->serializer}");
+                return $value;
+        }
+    }
 }
diff --git a/cache/stores/redis/tests/compressor_test.php b/cache/stores/redis/tests/compressor_test.php
new file mode 100644 (file)
index 0000000..0d9a583
--- /dev/null
@@ -0,0 +1,287 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Redis cache test.
+ *
+ * If you wish to use these unit tests all you need to do is add the following definition to
+ * your config.php file.
+ *
+ * define('TEST_CACHESTORE_REDIS_TESTSERVERS', '127.0.0.1');
+ *
+ * @package   cachestore_redis
+ * @copyright 2018 Catalyst IT Australia {@link http://www.catalyst-au.net}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once(__DIR__.'/../../../tests/fixtures/stores.php');
+require_once(__DIR__.'/../lib.php');
+
+/**
+ * Redis cache test - compressor settings.
+ *
+ * @package   cachestore_redis
+ * @author    Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
+ * @copyright 2018 Catalyst IT Australia {@link http://www.catalyst-au.net}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class cachestore_redis_compressor_test extends advanced_testcase {
+
+    /**
+     * Test set up
+     */
+    public function setUp() {
+        if (!cachestore_redis::are_requirements_met() || !defined('TEST_CACHESTORE_REDIS_TESTSERVERS')) {
+            $this->markTestSkipped('Could not test cachestore_redis. Requirements are not met.');
+        }
+
+        parent::setUp();
+    }
+
+    /**
+     * Create a cachestore.
+     *
+     * @param int $compressor
+     * @param int $serializer
+     * @return cachestore_redis
+     */
+    public function create_store($compressor, $serializer) {
+        /** @var cache_definition $definition */
+        $definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_redis', 'phpunit_test');
+        $config = cachestore_redis::unit_test_configuration();
+        $config['compressor'] = $compressor;
+        $config['serializer'] = $serializer;
+        $store = new cachestore_redis('Test', $config);
+        $store->initialise($definition);
+
+        return $store;
+    }
+
+    /**
+     * It misses a value.
+     */
+    public function test_it_can_miss_one() {
+        $store = $this->create_store(cachestore_redis::COMPRESSOR_PHP_GZIP, Redis::SERIALIZER_PHP);
+
+        self::assertFalse($store->get('missme'));
+    }
+
+    /**
+     * It misses many values.
+     */
+    public function test_it_can_miss_many() {
+        $store = $this->create_store(cachestore_redis::COMPRESSOR_PHP_GZIP, Redis::SERIALIZER_PHP);
+
+        $expected = ['missme' => false, 'missmetoo' => false];
+        $actual = $store->get_many(array_keys($expected));
+        self::assertSame($expected, $actual);
+    }
+
+    /**
+     * It misses some values.
+     */
+    public function test_it_can_miss_some() {
+        $store = $this->create_store(cachestore_redis::COMPRESSOR_PHP_GZIP, Redis::SERIALIZER_PHP);
+        $store->set('iamhere', 'youfoundme');
+
+        $expected = ['missme' => false, 'missmetoo' => false, 'iamhere' => 'youfoundme'];
+        $actual = $store->get_many(array_keys($expected));
+        self::assertSame($expected, $actual);
+    }
+
+    /**
+     * A provider for test_works_with_different_types
+     *
+     * @return array
+     */
+    public function provider_for_test_it_works_with_different_types() {
+        $object = new stdClass();
+        $object->field = 'value';
+
+        return [
+            ['string', 'Abc Def'],
+            ['string_empty', ''],
+            ['string_binary', gzencode('some binary data')],
+            ['int', 123],
+            ['int_zero', 0],
+            ['int_negative', -100],
+            ['int_huge', PHP_INT_MAX],
+            ['float', 3.14],
+            ['boolean_true', true],
+            // Boolean 'false' is not tested as it is not allowed in Moodle.
+            ['array', [1, 'b', 3.4]],
+            ['array_map', ['a' => 'b', 'c' => 'd']],
+            ['object_stdClass', $object],
+            ['null', null],
+        ];
+    }
+
+    /**
+     * It works with different types.
+     *
+     * @dataProvider provider_for_test_it_works_with_different_types
+     * @param string $key
+     * @param mixed $value
+     */
+    public function test_it_works_with_different_types($key, $value) {
+        $store = $this->create_store(cachestore_redis::COMPRESSOR_PHP_GZIP, Redis::SERIALIZER_PHP);
+        $store->set($key, $value);
+
+        self::assertEquals($value, $store->get($key), "Failed set/get for: {$key}");
+    }
+
+    /**
+     * Test it works with different types for many.
+     */
+    public function test_it_works_with_different_types_for_many() {
+        $store = $this->create_store(cachestore_redis::COMPRESSOR_PHP_GZIP, Redis::SERIALIZER_PHP);
+
+        $provider = $this->provider_for_test_it_works_with_different_types();
+        $keys = [];
+        $values = [];
+        $expected = [];
+        foreach ($provider as $item) {
+            $keys[] = $item[0];
+            $values[] = ['key' => $item[0], 'value' => $item[1]];
+            $expected[$item[0]] = $item[1];
+        }
+        $store->set_many($values);
+        $actual = $store->get_many($keys);
+        self::assertEquals($expected, $actual);
+    }
+
+    /**
+     * Provider for set/get combination tests.
+     *
+     * @return array
+     */
+    public function provider_for_tests_setget() {
+        $data = [
+            ['none, none',
+                Redis::SERIALIZER_NONE, cachestore_redis::COMPRESSOR_NONE,
+                'value1', 'value2'],
+            ['none, gzip',
+                Redis::SERIALIZER_NONE, cachestore_redis::COMPRESSOR_PHP_GZIP,
+                gzencode('value1'), gzencode('value2')],
+            ['php, none',
+                Redis::SERIALIZER_PHP, cachestore_redis::COMPRESSOR_NONE,
+                serialize('value1'), serialize('value2')],
+            ['php, gzip',
+                Redis::SERIALIZER_PHP, cachestore_redis::COMPRESSOR_PHP_GZIP,
+                gzencode(serialize('value1')), gzencode(serialize('value2'))],
+        ];
+
+        if (defined('Redis::SERIALIZER_IGBINARY')) {
+            $data[] = [
+                'igbinary, none',
+                    Redis::SERIALIZER_IGBINARY, cachestore_redis::COMPRESSOR_NONE,
+                    igbinary_serialize('value1'), igbinary_serialize('value2'),
+            ];
+            $data[] = [
+                'igbinary, gzip',
+                    Redis::SERIALIZER_IGBINARY, cachestore_redis::COMPRESSOR_PHP_GZIP,
+                    gzencode(igbinary_serialize('value1')), gzencode(igbinary_serialize('value2')),
+            ];
+        }
+
+        if (extension_loaded('zstd')) {
+            $data[] = [
+                'none, zstd',
+                Redis::SERIALIZER_NONE, cachestore_redis::COMPRESSOR_PHP_ZSTD,
+                zstd_compress('value1'), zstd_compress('value2'),
+            ];
+            $data[] = [
+                'php, zstd',
+                Redis::SERIALIZER_PHP, cachestore_redis::COMPRESSOR_PHP_ZSTD,
+                zstd_compress(serialize('value1')), zstd_compress(serialize('value2')),
+            ];
+
+            if (defined('Redis::SERIALIZER_IGBINARY')) {
+                $data[] = [
+                    'igbinary, zstd',
+                    Redis::SERIALIZER_IGBINARY, cachestore_redis::COMPRESSOR_PHP_ZSTD,
+                    zstd_compress(igbinary_serialize('value1')), zstd_compress(igbinary_serialize('value2')),
+                ];
+            }
+        }
+
+        return $data;
+    }
+
+    /**
+     * Test we can use get and set with all combinations.
+     *
+     * @dataProvider provider_for_tests_setget
+     * @param string $name
+     * @param int $serializer
+     * @param int $compressor
+     * @param string $rawexpected1
+     * @param string $rawexpected2
+     */
+    public function test_it_can_use_getset($name, $serializer, $compressor, $rawexpected1, $rawexpected2) {
+        // Create a connection with the desired serialisation.
+        $store = $this->create_store($compressor, $serializer);
+        $store->set('key', 'value1');
+
+        // Disable compressor and serializer to check the actual stored value.
+        $rawstore = $this->create_store(cachestore_redis::COMPRESSOR_NONE, Redis::SERIALIZER_NONE);
+
+        $data = $store->get('key');
+        $rawdata = $rawstore->get('key');
+        self::assertSame('value1', $data, "Invalid serialisation/unserialisation for: {$name}");
+        self::assertSame($rawexpected1, $rawdata, "Invalid rawdata for: {$name}");
+    }
+
+    /**
+     * Test we can use get and set many with all combinations.
+     *
+     * @dataProvider provider_for_tests_setget
+     * @param string $name
+     * @param int $serializer
+     * @param int $compressor
+     * @param string $rawexpected1
+     * @param string $rawexpected2
+     */
+    public function test_it_can_use_getsetmany($name, $serializer, $compressor, $rawexpected1, $rawexpected2) {
+        $many = [
+            ['key' => 'key1', 'value' => 'value1'],
+            ['key' => 'key2', 'value' => 'value2'],
+        ];
+        $keys = ['key1', 'key2'];
+        $expectations = ['key1' => 'value1', 'key2' => 'value2'];
+        $rawexpectations = ['key1' => $rawexpected1, 'key2' => $rawexpected2];
+
+        // Create a connection with the desired serialisation.
+        $store = $this->create_store($compressor, $serializer);
+        $store->set_many($many);
+
+        // Disable compressor and serializer to check the actual stored value.
+        $rawstore = $this->create_store(cachestore_redis::COMPRESSOR_NONE, Redis::SERIALIZER_NONE);
+
+        $data = $store->get_many($keys);
+        $rawdata = $rawstore->get_many($keys);
+        foreach ($keys as $key) {
+            self::assertSame($expectations[$key],
+                             $data[$key],
+                             "Invalid serialisation/unserialisation for {$key} with serializer {$name}");
+            self::assertSame($rawexpectations[$key],
+                             $rawdata[$key],
+                             "Invalid rawdata for {$key} with serializer {$name}");
+        }
+    }
+}
index 4a801da..eaf6344 100644 (file)
@@ -1,6 +1,9 @@
 This files describes API changes in /cache/stores/* - cache store plugins.
 Information provided here is intended especially for developers.
 
+=== 3.8 ===
+* The Redis cache store can now make use of the Zstandard compression algorithm (see MDL-66428).
+
 === 3.7 ===
 * Upgraded MongoDB cache store to use the new lower level PHP-driver and MongoDB PHP Library.
 * The mongodb extension has replaced the old mongo extension. The mongodb pecl extension >= 1.5 must be installed to use MongoDB
index 56b3803..5227584 100644 (file)
@@ -206,17 +206,17 @@ $CFG->admin = 'admin';
 //
 // These variables define DEFAULT block variables for new courses
 // If this one is set it overrides all others and is the only one used.
-//      $CFG->defaultblocks_override = 'participants,activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
+//      $CFG->defaultblocks_override = 'activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
 //
 // These variables define the specific settings for defined course formats.
 // They override any settings defined in the formats own config file.
 //      $CFG->defaultblocks_site = 'site_main_menu,course_list:course_summary,calendar_month';
-//      $CFG->defaultblocks_social = 'participants,search_forums,calendar_month,calendar_upcoming,social_activities,recent_activity,course_list';
-//      $CFG->defaultblocks_topics = 'participants,activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
-//      $CFG->defaultblocks_weeks = 'participants,activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
+//      $CFG->defaultblocks_social = 'search_forums,calendar_month,calendar_upcoming,social_activities,recent_activity,course_list';
+//      $CFG->defaultblocks_topics = 'activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
+//      $CFG->defaultblocks_weeks = 'activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
 //
 // These blocks are used when no other default setting is found.
-//      $CFG->defaultblocks = 'participants,activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
+//      $CFG->defaultblocks = 'activity_modules,search_forums,course_list:news_items,calendar_upcoming,recent_activity';
 //
 // You can specify a different class to be created for the $PAGE global, and to
 // compute which blocks appear on each page. However, I cannot think of any good
index e44cef6..9604b19 100644 (file)
@@ -58,14 +58,17 @@ class core_enrollib_testcase extends advanced_testcase {
 
         $course1 = $this->getDataGenerator()->create_course(array(
             'shortname' => 'Z',
+            'idnumber' => '123',
             'category' => $category1->id,
         ));
         $course2 = $this->getDataGenerator()->create_course(array(
             'shortname' => 'X',
+            'idnumber' => '789',
             'category' => $category2->id,
         ));
         $course3 = $this->getDataGenerator()->create_course(array(
             'shortname' => 'Y',
+            'idnumber' => '456',
             'category' => $category2->id,
             'visible' => 0,
         ));
@@ -163,7 +166,7 @@ class core_enrollib_testcase extends advanced_testcase {
         $this->assertTrue(property_exists($course, 'timecreated'));
 
         $courses = enrol_get_all_users_courses($user2->id, false, null, 'id DESC');
-        $this->assertEquals(array($course3->id, $course2->id, $course1->id), array_keys($courses));
+        $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
 
         // Make sure that implicit sorting defined in navsortmycoursessort is respected.
 
@@ -175,7 +178,54 @@ class core_enrollib_testcase extends advanced_testcase {
         // But still the explicit sorting takes precedence over the implicit one.
 
         $courses = enrol_get_all_users_courses($user1->id, false, null, 'shortname DESC');
+        $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
+
+        // Make sure that implicit visibility sorting defined in navsortmycourseshiddenlast is respected for all course sortings.
+
+        $CFG->navsortmycoursessort = 'sortorder';
+        $CFG->navsortmycourseshiddenlast = true;
+        $courses = enrol_get_all_users_courses($user1->id);
+        $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
+
+        $CFG->navsortmycoursessort = 'sortorder';
+        $CFG->navsortmycourseshiddenlast = false;
+        $courses = enrol_get_all_users_courses($user1->id);
+        $this->assertEquals(array($course1->id, $course3->id, $course2->id), array_keys($courses));
+
+        $CFG->navsortmycoursessort = 'fullname';
+        $CFG->navsortmycourseshiddenlast = true;
+        $courses = enrol_get_all_users_courses($user1->id);
+        $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
+
+        $CFG->navsortmycoursessort = 'fullname';
+        $CFG->navsortmycourseshiddenlast = false;
+        $courses = enrol_get_all_users_courses($user1->id);
+        $this->assertEquals(array($course1->id, $course2->id, $course3->id), array_keys($courses));
+
+        $CFG->navsortmycoursessort = 'shortname';
+        $CFG->navsortmycourseshiddenlast = true;
+        $courses = enrol_get_all_users_courses($user1->id);
+        $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
+
+        $CFG->navsortmycoursessort = 'shortname';
+        $CFG->navsortmycourseshiddenlast = false;
+        $courses = enrol_get_all_users_courses($user1->id);
+        $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
+
+        $CFG->navsortmycoursessort = 'idnumber';
+        $CFG->navsortmycourseshiddenlast = true;
+        $courses = enrol_get_all_users_courses($user1->id);
+        $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
+
+        $CFG->navsortmycoursessort = 'idnumber';
+        $CFG->navsortmycourseshiddenlast = false;
+        $courses = enrol_get_all_users_courses($user1->id);
         $this->assertEquals(array($course1->id, $course3->id, $course2->id), array_keys($courses));
+
+        // But still the explicit visibility sorting takes precedence over the implicit one.
+
+        $courses = enrol_get_all_users_courses($user1->id, false, null, 'visible DESC, shortname DESC');
+        $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
     }
 
     public function test_enrol_user_sees_own_courses() {
index 01b2b5f..2346d39 100644 (file)
--- a/index.php
+++ b/index.php
@@ -91,18 +91,6 @@ if (get_home_page() != HOMEPAGE_SITE) {
 // Trigger event.
 course_view(context_course::instance(SITEID));
 
-// If the hub plugin is installed then we let it take over the homepage here.
-if (file_exists($CFG->dirroot.'/local/hub/lib.php') and get_config('local_hub', 'hubenabled')) {
-    require_once($CFG->dirroot.'/local/hub/lib.php');
-    $hub = new local_hub();
-    $continue = $hub->display_homepage();
-    // Function display_homepage() returns true if the hub home page is not displayed
-    // ...mostly when search form is not displayed for not logged users.
-    if (empty($continue)) {
-        exit;
-    }
-}
-
 $PAGE->set_pagetype('site-index');
 $PAGE->set_docs_path('');
 $editing = $PAGE->user_is_editing();
index c31faad..ea89b1d 100644 (file)
@@ -822,6 +822,8 @@ $string['navshowallcourses'] = 'Show all courses';
 $string['navshowcategories'] = 'Show course categories';
 $string['navshowmycoursecategories'] = 'Show my course categories';
 $string['navshowmycoursecategories_help'] = 'If enabled courses in the users my courses branch will be shown in categories.';
+$string['navsortmycourseshiddenlast'] = 'Sort my hidden courses last';
+$string['navsortmycourseshiddenlast_help'] = 'If enabled, any hidden courses will be listed after visible courses (for users who can view hidden courses). Otherwise, all courses, regardless of their visibility, will be listed according to the \'Sort my courses\' setting.';
 $string['navsortmycoursessort'] = 'Sort my courses';
 $string['navsortmycoursessort_help'] = 'This determines whether courses are listed under My courses according to the sort order (i.e. the order set in Site administration > Courses > Manage courses and categories) or alphabetically by course setting.';
 $string['never'] = 'Never';
@@ -1011,11 +1013,6 @@ $string['quizattemptsupgradedmessage'] = 'In Moodle 2.1 there was a major upgrad
 $string['recaptchaprivatekey'] = 'ReCAPTCHA secret key';
 $string['recaptchapublickey'] = 'ReCAPTCHA site key';
 $string['register'] = 'Register your site';
-$string['registermoodlenet'] = '<p>We\'d love to stay in touch and provide you with important things for your Moodle site!</p><p>By registering:</p><ul><li>You can subscribe to receive notifications of new Moodle releases, security alerts and other important news.</li><li>You can access and activate mobile push notifications from your Moodle site through our free <a href="https://download.moodle.org/mobile/">Moodle app</a>.</li><li>You are contributing to our <a href="https://moodle.net/stats/">Moodle statistics</a> of the worldwide community, which help us improve Moodle and our community sites.</li><li>If you wish, your site can be included in the <a href="https://moodle.net/sites/">list of registered Moodle sites</a> in your country.</li></ul>';
-$string['registermoodleorg'] = 'When you register your site';
-$string['registermoodleorgli1'] = 'You are added to a low-volume mailing list for important notifications such as security alerts and new releases of Moodle.';
-$string['registermoodleorgli2'] = 'Statistics about your site will be added to the {$a} of the worldwide Moodle community.';
-$string['registerwithmoodleorg'] = 'Register your site';
 $string['registration'] = 'Registration';
 $string['registration_help'] = 'By registering:
 
@@ -1432,3 +1429,8 @@ $string['allowblockstodock'] = 'Allow blocks to use the dock';
 $string['configallowblockstodock'] = 'If enabled and supported by the selected theme users can choose to move blocks to a special dock.';
 // Deprecated since Moodle 3.8.
 $string['configuserquota'] = 'The maximum number of bytes that a user can store in their own private file area. {$a->bytes} bytes == {$a->displaysize}';
+$string['registermoodlenet'] = '<p>We\'d love to stay in touch and provide you with important things for your Moodle site!</p><p>By registering:</p><ul><li>You can subscribe to receive notifications of new Moodle releases, security alerts and other important news.</li><li>You can access and activate mobile push notifications from your Moodle site through our free <a href="https://download.moodle.org/mobile/">Moodle app</a>.</li><li>You are contributing to our <a href="https://stats.moodle.org">Moodle statistics</a> of the worldwide community, which help us improve Moodle and our community sites.</li><li>If you wish, your site can be included in the <a href="https://stats.moodle.org/sites/">list of registered Moodle sites</a> in your country.</li></ul>';
+$string['registermoodleorg'] = 'When you register your site';
+$string['registermoodleorgli1'] = 'You are added to a low-volume mailing list for important notifications such as security alerts and new releases of Moodle.';
+$string['registermoodleorgli2'] = 'Statistics about your site will be added to the {$a} of the worldwide Moodle community.';
+$string['registerwithmoodleorg'] = 'Register your site';
index 91d0a4f..0595e0c 100644 (file)
@@ -106,3 +106,12 @@ unpublishalluploadedcourses,core_hub
 unpublishconfirmation,core_hub
 unpublishcourse,core_hub
 updatestatus,core_hub
+registermoodlenet,core_admin
+registermoodleorg,core_admin
+registermoodleorgli1,core_admin
+registermoodleorgli2,core_admin
+registerwithmoodleorg,core_admin
+completeregistration,core_hub
+registersite,core_hub
+updatesite,core_hub
+unregisterexplained,core_hub
index ebe023f..3df03ba 100644 (file)
@@ -33,7 +33,6 @@ $string['audiencestudents'] = 'Students';
 $string['audienceadmins'] = 'Moodle administrators';
 $string['badgesnumber'] = 'Number of badges ({$a})';
 $string['communityremoved'] = 'That course link has been removed from your list';
-$string['completeregistration'] = 'Complete registration with Moodle.net';
 $string['confirmregistration'] = 'Confirm registration';
 $string['coursename'] = 'Name';
 $string['coursepublished'] = 'This course has been shared successfully on \'{$a}\'.';
@@ -55,7 +54,7 @@ $string['eduleveltertiary'] = 'Tertiary';
 $string['emailalert'] = 'Email notifications';
 $string['emailalert_help'] = 'If this is enabled the hub administrator will send you emails about security issues and other important news.';
 $string['enrollable'] = 'Enrollable';
-$string['errorotherhubsnotsupported'] = 'This page can no longer be used for registration with sites other than Moodle.net';
+$string['errorotherhubsnotsupported'] = 'This page can no longer be used for registration with custom sites directories.';
 $string['errorws'] = '{$a}';
 $string['errorwstokenreset'] = '{$a}. Registration token on this site has been reset. You can now register your site again.';
 $string['errorregistrationupdate'] = 'An error occurred during registration update ({$a})';
@@ -86,7 +85,7 @@ $string['none'] = 'None';
 $string['operation'] = 'Actions';
 $string['participantnumberaverage'] = 'Average number of participants ({$a})';
 $string['policyagreed'] = 'Privacy notice and data processing agreement';
-$string['policyagreeddesc'] = 'I agree to the <a href="{$a}" target="_blank">Privacy notice and data processing agreement</a> for Moodle.net';
+$string['policyagreeddesc'] = 'I agree to the <a href="{$a}" target="_blank">Privacy notice and data processing agreement</a>';
 $string['postaladdress'] = 'Postal address';
 $string['postaladdress_help'] = 'Postal address of this site, or of the entity represented by this site.';
 $string['postsnumber'] = 'Number of posts ({$a})';
@@ -97,7 +96,19 @@ $string['registeredsites'] = 'Registered sites';
 $string['registrationinfo'] = 'Registration information';
 $string['registereduserdevices'] = 'Number of users with registered mobile devices ({$a})';
 $string['registeredactiveuserdevices'] = 'Number of active users with registered mobile devices which are receiving notifications ({$a})';
-$string['registersite'] = 'Register with {$a}';
+$string['registerwithmoodleorg'] = 'Register your site';
+$string['registerwithmoodleorgupdate'] = 'Update your site registration';
+$string['registerwithmoodleorgcomplete'] = 'Complete your site registration';
+$string['registerwithmoodleorginfo'] = 'We\'d love to stay in touch and provide you with important things for your Moodle site! By registering:
+
+* You can subscribe to receive notifications of new Moodle releases, security alerts and other important news.
+* You can access and activate mobile push notifications from your Moodle site through our free Moodle app.
+* You are contributing to our Moodle statistics of the worldwide community, which help us improve Moodle and our community sites.
+* If you wish, your site can be included in the list of registered Moodle sites in your country.';
+$string['registerwithmoodleorginfoapp'] = 'About the Moodle app';
+$string['registerwithmoodleorginfostats'] = 'Moodle statistics';
+$string['registerwithmoodleorginfosites'] = 'Other sites in my country';
+$string['registerwithmoodleorgremove'] = 'You are going to unregister your site. If you continue, you will no longer have access to important notifications and security alerts. Your users will not be able to receive push notifications from your site to their Moodle mobile app. Are you sure you want to unregister your site?';
 $string['registrationconfirmed'] = 'Site registration confirmed';
 $string['registrationconfirmedon'] = 'Thank you for registering your site. Registration information will be kept up to date by the \'Site registration\' scheduled task.';
 $string['renewregistration'] = 'Renew registration';
@@ -151,13 +162,11 @@ $string['subject'] = 'Subject';
 $string['subject_help'] = 'Select the main subject area which the course covers.';
 $string['type'] = 'Shared';
 $string['unregister'] = 'Unregister';
-$string['unregisterfrom'] = 'Unregister from {$a}';
-$string['unregistrationerror'] = 'An error occurred when the site tried to unregister from Moodle.net: {$a}';
+$string['unregistrationerror'] = 'An error occurred while attempting to unregister the site: {$a}';
 $string['update'] = 'Update';
-$string['updatesite'] = 'Update registration on {$a}';
+$string['updatesiteregistration'] = 'Update registration';
 $string['usedifferentemail'] = 'Use different email';
-$string['unregisterexplained'] = 'If the site with URL {$a} is registered on Moodle.net its registration will be removed.';
-$string['urlalreadyregistered'] = 'Your site seems to be already registered on Moodle.net, which means something has gone wrong. Please contact the Moodle.net administrator to reset your registration so you can try again.';
+$string['urlalreadyregistered'] = 'Your site seems to be already registered, which means something has gone wrong. Please contact the sites directory administrator to reset your registration so you can try again.';
 $string['usersnumber'] = 'Number of users ({$a})';
 $string['wrongtoken'] = 'The registration failed for some unknown reason (network?). Please try again.';
 
@@ -168,6 +177,7 @@ $string['advertised'] = 'For people to join';
 $string['advertiseon'] = 'Share this course on {$a}';
 $string['readvertiseon'] = 'Update advertising information on {$a}';
 $string['advertisepublication_help'] = 'This course will be listed on Moodle.net as a course that people can enrol in and participate. Email-based self-registration should be enabled on the site and you need to enable self enrolment in this course.';
+$string['completeregistration'] = 'Complete registration with Moodle.net';
 $string['courseunpublished'] = 'The course {$a->courseshortname} is no longer shared on {$a->hubname}.';
 $string['courseurl'] = 'Course URL';
 $string['courseurl_help'] = 'It is the URL of your course. This URL is displayed as a link in a search result.';
@@ -201,6 +211,7 @@ $string['publisheremail'] = 'Publisher email';
 $string['publisheremail_help'] = 'The publisher email address allows the hub administrator to alert the publisher about any changes to the status of the published course.';
 $string['publishername'] = 'Publisher';
 $string['publishername_help'] = 'The publisher is the person or organisation that is the official publisher of the course.  Unless you are publishing it on behalf of someone else, it will usually be you.';
+$string['registersite'] = 'Register with {$a}';
 $string['removefromhub'] = 'Remove from Moodle.net';
 $string['screenshots'] = 'Screenshots';
 $string['screenshots_help'] = 'Any screenshots of the course will be displayed in search results.';
@@ -219,4 +230,7 @@ $string['unpublishalladvertisedcourses'] = 'Remove all courses that were shared
 $string['unpublishalluploadedcourses'] = 'Remove all courses that were shared on Moodle.net for people to download';
 $string['unpublishconfirmation'] = 'Do you really want to remove the course "{$a->courseshortname}" from "{$a->hubname}"';
 $string['unpublishcourse'] = 'Stop sharing {$a}';
-$string['updatestatus'] = 'Check it now.';
\ No newline at end of file
+$string['updatesite'] = 'Update registration on {$a}';
+$string['updatestatus'] = 'Check it now.';
+$string['unregisterfrom'] = 'Unregister from {$a}';
+$string['unregisterexplained'] = 'If the site with URL {$a} is registered, then its registration will be removed.';
\ No newline at end of file
index fc1e1a0..099ec88 100644 (file)
Binary files a/lib/amd/build/str.min.js and b/lib/amd/build/str.min.js differ
index 40e3262..1bfa1a9 100644 (file)
Binary files a/lib/amd/build/str.min.js.map and b/lib/amd/build/str.min.js.map differ
index 7f46e2c..246fa3a 100644 (file)
@@ -63,7 +63,7 @@ export const get_strings = (requests) => {
 
     const stringPromises = requests.map((request) => {
         const cacheKey = getCacheKey(request);
-        const {component, key, param, lang} = request;
+        const {component, key, param, lang = pageLang} = request;
         // Helper function to add the promise to cache.
         const buildReturn = (promise) => {
             // Make sure the promise cache contains our promise.
index 7c0ed37..7f8979d 100644 (file)
@@ -33,7 +33,7 @@ use coding_exception;
 use moodle_url;
 
 /**
- * Methods to communicate with moodle.net web services
+ * Provides methods to communicate with the hub (sites directory) web services.
  *
  * @package    core
  * @copyright  2017 Marina Glancy
@@ -51,11 +51,11 @@ class api {
     const HUB_BACKUP_FILE_TYPE = 'backup';
 
     /**
-     * Calls moodle.net WS
+     * Calls a remote function exposed via web services on the hub.
      *
      * @param string $function name of WS function
      * @param array $data parameters of WS function
-     * @param bool $allowpublic allow request without moodle.net registration
+     * @param bool $allowpublic allow request without registration on the hub
      * @return mixed depends on the function
      * @throws moodle_exception
      */
@@ -71,7 +71,7 @@ class api {
     }
 
     /**
-     * Performs REST request to moodle.net (using GET method)
+     * Performs a REST request to the hub site (using the GET method).
      *
      * @param string $token
      * @param string $function
@@ -95,7 +95,7 @@ class api {
             // Connection error.
             throw new moodle_exception('errorconnect', 'hub', '', $curl->error);
         } else if (isset($curloutput['exception'])) {
-            // Exception occurred on moodle.net .
+            // Exception occurred on the remote side.
             self::process_curl_exception($token, $curloutput);
         } else if ($info['http_code'] != 200) {
             throw new moodle_exception('errorconnect', 'hub', '', $info['http_code']);
@@ -105,7 +105,7 @@ class api {
     }
 
     /**
-     * Analyses exception received from moodle.net
+     * Analyses exception received from the hub server.
      *
      * @param string $token token used for CURL request
      * @param array $curloutput output from CURL request
@@ -128,7 +128,7 @@ class api {
     }
 
     /**
-     * Update site registration on moodle.net
+     * Update site registration on the hub.
      *
      * @param array $siteinfo
      * @throws moodle_exception
@@ -139,20 +139,20 @@ class api {
     }
 
     /**
-     * Returns information about moodle.net
+     * Returns information about the hub.
      *
      * Example of the return array:
      * {
      *     "courses": 384,
-     *     "description": "Moodle.net connects you with free content and courses shared by Moodle ...",
-     *     "downloadablecourses": 190,
-     *     "enrollablecourses": 194,
+     *     "description": "Official Moodle sites directory.",
+     *     "downloadablecourses": 0,
+     *     "enrollablecourses": 0,
      *     "hublogo": 1,
      *     "language": "en",
-     *     "name": "Moodle.net",
+     *     "name": "moodle",
      *     "sites": 274175,
-     *     "url": "https://moodle.net",
-     *     "imgurl": "https://moodle.net/local/hub/webservice/download.php?filetype=hubscreenshot"
+     *     "url": "https://stats.moodle.org",
+     *     "imgurl": "https://stats.moodle.org/local/hub/webservice/download.php?filetype=hubscreenshot"
      * }
      *
      * @return array
@@ -327,7 +327,7 @@ class api {
      *
      * @param array|\stdClass $courseinfo
      * @return int id of the published course on the hub
-     * @throws moodle_exception if communication to moodle.net failed or course could not be published
+     * @throws moodle_exception if the communication with the hub failed or the course could not be published
      */
     public static function register_course($courseinfo) {
         debugging("This function has been deprecated as part of the Moodle.net sunsetting process.");
@@ -339,7 +339,7 @@ class api {
      *
      * @deprecated since Moodle 3.8. Moodle.net has been sunsetted making this function useless.
      *
-     * @param int $hubcourseid id of the published course on moodle.net, it must be published from this site
+     * @param int $hubcourseid id of the published course on the hub, it must be published from this site
      * @param \stored_file $file
      * @param int $screenshotnumber ordinal number of the screenshot
      */
@@ -352,7 +352,7 @@ class api {
      *
      * @deprecated since Moodle 3.8. Moodle.net has been sunsetted making this function useless.
      *
-     * @param int $hubcourseid id of the course on moodle.net
+     * @param int $hubcourseid id of the course on the hub
      * @param string $path local path (in tempdir) to save the downloaded backup to.
      */
     public static function download_course_backup($hubcourseid, $path) {
@@ -364,7 +364,7 @@ class api {
      *
      * @deprecated since Moodle 3.8. Moodle.net has been sunsetted making this function useless.
      *
-     * @param int $hubcourseid id of the published course on moodle.net, it must be published from this site
+     * @param int $hubcourseid id of the published course on the hub, it must be published from this site
      * @param \stored_file $backupfile
      */
     public static function upload_course_backup($hubcourseid, \stored_file $backupfile) {
index cead3bb..cd716ef 100644 (file)
@@ -32,7 +32,7 @@ use stdClass;
 use html_writer;
 
 /**
- * Methods to use when publishing and searching courses on moodle.net
+ * Methods to use when registering the site at the moodle sites directory.
  *
  * @package    core
  * @copyright  2017 Marina Glancy
@@ -147,7 +147,7 @@ class registration {
     }
 
     /**
-     * Calculates and prepares site information to send to moodle.net as part of registration or update
+     * Calculates and prepares site information to send to the sites directory as a part of registration.
      *
      * @param array $defaults default values for inputs in the registration form (if site was never registered before)
      * @return array site info
@@ -158,9 +158,8 @@ class registration {
         require_once($CFG->dirroot . "/course/lib.php");
 
         $siteinfo = array();
-        $cleanhuburl = clean_param(HUB_MOODLEORGHUBURL, PARAM_ALPHANUMEXT);
         foreach (self::FORM_FIELDS as $field) {
-            $siteinfo[$field] = get_config('hub', 'site_'.$field.'_' . $cleanhuburl);
+            $siteinfo[$field] = get_config('hub', 'site_'.$field);
             if ($siteinfo[$field] === false) {
                 $siteinfo[$field] = array_key_exists($field, $defaults) ? $defaults[$field] : null;
             }
@@ -210,7 +209,7 @@ class registration {
     }
 
     /**
-     * Human-readable summary of data that will be sent to moodle.net
+     * Human-readable summary of data that will be sent to the sites directory.
      *
      * @param array $siteinfo result of get_site_info()
      * @return string
@@ -264,13 +263,12 @@ class registration {
      * @param stdClass $formdata data from {@link site_registration_form}
      */
     public static function save_site_info($formdata) {
-        $cleanhuburl = clean_param(HUB_MOODLEORGHUBURL, PARAM_ALPHANUMEXT);
         foreach (self::FORM_FIELDS as $field) {
-            set_config('site_' . $field . '_' . $cleanhuburl, $formdata->$field, 'hub');
+            set_config('site_' . $field, $formdata->$field, 'hub');
         }
-        // Even if the the connection with moodle.net fails, admin has manually submitted the form which means they don't need
+        // Even if the connection with the sites directory fails, admin has manually submitted the form which means they don't need
         // to be redirected to the site registration page any more.
-        set_config('site_regupdateversion_' . $cleanhuburl, max(array_keys(self::CONFIRM_NEW_FIELDS)), 'hub');
+        set_config('site_regupdateversion', max(array_keys(self::CONFIRM_NEW_FIELDS)), 'hub');
     }
 
     /**
@@ -329,7 +327,7 @@ class registration {
     }
 
     /**
-     * Confirms registration by moodle.net
+     * Confirms registration by the sites directory.
      *
      * @param string $token
      * @param string $newtoken
@@ -375,8 +373,8 @@ class registration {
      * Registers a site
      *
      * This method will make sure that unconfirmed registration record is created and then redirect to
-     * registration script on https://moodle.net
-     * Moodle.net will check that the site is accessible, register it and redirect back
+     * registration script on the sites directory.
+     * The sites directory will check that the site is accessible, register it and redirect back
      * to /admin/registration/confirmregistration.php
      *
      * @param string $returnurl
@@ -397,7 +395,7 @@ class registration {
             $hub->token = get_site_identifier();
             $hub->secret = $hub->token;
             $hub->huburl = HUB_MOODLEORGHUBURL;
-            $hub->hubname = 'Moodle.net';
+            $hub->hubname = 'moodle';
             $hub->confirmed = 0;
             $hub->timemodified = time();
             $hub->id = $DB->insert_record('registration_hubs', $hub);
@@ -487,20 +485,20 @@ class registration {
     }
 
     /**
-     * Returns information about moodle.net
+     * Returns information about the sites directory.
      *
      * Example of the return array:
      * {
      *     "courses": 384,
-     *     "description": "Moodle.net connects you with free content and courses shared by Moodle ...",
-     *     "downloadablecourses": 190,
-     *     "enrollablecourses": 194,
+     *     "description": "Official moodle sites directory",
+     *     "downloadablecourses": 0,
+     *     "enrollablecourses": 0,
      *     "hublogo": 1,
      *     "language": "en",
-     *     "name": "Moodle.net",
+     *     "name": "moodle",
      *     "sites": 274175,
-     *     "url": "https://moodle.net",
-     *     "imgurl": moodle_url : "https://moodle.net/local/hub/webservice/download.php?filetype=hubscreenshot"
+     *     "url": "https://stats.moodle.org",
+     *     "imgurl": "https://stats.moodle.org/local/hub/webservice/download.php?filetype=hubscreenshot"
      * }
      *
      * @return array|null
@@ -509,8 +507,8 @@ class registration {
         try {
             return api::get_hub_info();
         } catch (moodle_exception $e) {
-            // Ignore error, we only need it for displaying information about moodle.net, if this request
-            // fails, it's not a big deal.
+            // Ignore error, we only need it for displaying information about the sites directory.
+            // If this request fails, it's not a big deal.
             return null;
         }
     }
@@ -555,8 +553,7 @@ class registration {
             return $fieldsneedconfirm;
         }
 
-        $cleanhuburl = clean_param(HUB_MOODLEORGHUBURL, PARAM_ALPHANUMEXT);
-        $lastupdated = (int)get_config('hub', 'site_regupdateversion_' . $cleanhuburl);
+        $lastupdated = (int)get_config('hub', 'site_regupdateversion');
         foreach (self::CONFIRM_NEW_FIELDS as $version => $fields) {
             if ($version > $lastupdated) {
                 $fieldsneedconfirm = array_merge($fieldsneedconfirm, $fields);
index 0369aa3..f58f9ef 100644 (file)
@@ -32,7 +32,7 @@ global $CFG;
 require_once($CFG->libdir . '/formslib.php');
 
 /**
- * The site registration form. Information will be sent to moodle.net
+ * The site registration form. Information will be sent to the sites directory.
  *
  * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
  * @package    core
@@ -161,16 +161,16 @@ class site_registration_form extends \moodleform {
         $mform->addElement('static', 'urlstring', get_string('siteurl', 'hub'), $siteinfo['url']);
         $mform->addHelpButton('urlstring', 'siteurl', 'hub');
 
-        // Display statistic that are going to be retrieve by moodle.net.
+        // Display statistic that are going to be retrieve by the sites directory.
         $mform->addElement('static', 'siteinfosummary', get_string('sendfollowinginfo', 'hub'), registration::get_stats_summary($siteinfo));
 
         // Check if it's a first registration or update.
         if (registration::is_registered()) {
-            $buttonlabel = get_string('updatesite', 'hub', 'Moodle.net');
+            $buttonlabel = get_string('updatesiteregistration', 'core_hub');
             $mform->addElement('hidden', 'update', true);
             $mform->setType('update', PARAM_BOOL);
         } else {
-            $buttonlabel = get_string('registersite', 'hub', 'Moodle.net');
+            $buttonlabel = get_string('register', 'core_admin');
         }
 
         $this->add_action_buttons(false, $buttonlabel);
diff --git a/lib/classes/hub/site_unregistration_form.php b/lib/classes/hub/site_unregistration_form.php
deleted file mode 100644 (file)
index 70fc070..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Class site_unregistration_form
- *
- * @package    core
- * @copyright  2017 Marina Glancy
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-namespace core\hub;
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-require_once($CFG->libdir . '/formslib.php');
-
-/**
- * This form display a unregistration form.
- *
- * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
- * @package    core
- * @copyright  2017 Marina Glancy
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class site_unregistration_form extends \moodleform {
-
-    /**
-     * Form definition
-     */
-    public function definition() {
-        global $CFG;
-        $mform = & $this->_form;
-        $mform->addElement('header', 'site', get_string('unregister', 'hub'));
-
-        $unregisterlabel = get_string('unregister', 'hub');
-        $mform->addElement('advcheckbox', 'unpublishalladvertisedcourses', '',
-            ' ' . get_string('unpublishalladvertisedcourses', 'hub'));
-        $mform->setType('unpublishalladvertisedcourses', PARAM_INT);
-        $mform->addElement('advcheckbox', 'unpublishalluploadedcourses', '',
-            ' ' . get_string('unpublishalluploadedcourses', 'hub'));
-        $mform->setType('unpublishalluploadedcourses', PARAM_INT);
-
-        $mform->addElement('hidden', 'unregistration', 1);
-        $mform->setType('unregistration', PARAM_INT);
-
-        $mform->addElement('static', 'explanation', '', get_string('unregisterexplained', 'hub', $CFG->wwwroot));
-
-        $this->add_action_buttons(true, $unregisterlabel);
-    }
-}
index 45ed163..32a29d7 100644 (file)
@@ -1647,7 +1647,7 @@ class core_plugin_manager {
         $plugins = array(
             'qformat' => array('blackboard', 'learnwise'),
             'auth' => array('radius', 'fc', 'nntp', 'pam', 'pop3', 'imap'),
-            'block' => array('course_overview', 'messages', 'community'),
+            'block' => array('course_overview', 'messages', 'community', 'participants'),
             'cachestore' => array('memcache'),
             'enrol' => array('authorize'),
             'report' => array('search'),
@@ -1718,7 +1718,7 @@ class core_plugin_manager {
                 'completionstatus', 'course_list', 'course_summary',
                 'feedback', 'globalsearch', 'glossary_random', 'html',
                 'login', 'lp', 'mentees', 'mnet_hosts', 'myoverview', 'myprofile',
-                'navigation', 'news_items', 'online_users', 'participants',
+                'navigation', 'news_items', 'online_users',
                 'private_files', 'quiz_results', 'recent_activity', 'recentlyaccesseditems',
                 'recentlyaccessedcourses', 'rss_client', 'search_forums', 'section_links',
                 'selfcompletion', 'settings', 'site_main_menu',
index 4626e17..bcf2cc9 100644 (file)
@@ -137,6 +137,18 @@ class core_useragent {
         }
     }
 
+    /**
+     * Get the MoodleBot UserAgent for this site.
+     *
+     * @return string UserAgent
+     */
+    public static function get_moodlebot_useragent() {
+        global $CFG;
+
+        $version = moodle_major_version(); // Only major version for security.
+        return "MoodleBot/$version (+{$CFG->wwwroot})";
+    }
+
     /**
      * Returns the user agent string.
      * @return bool|string The user agent string or false if one isn't available.
@@ -215,7 +227,8 @@ class core_useragent {
      * @return bool
      */
     protected function is_useragent_web_crawler() {
-        $regex = '/Googlebot|google\.com|Yahoo! Slurp|\[ZSEBOT\]|msnbot|bingbot|BingPreview|Yandex|AltaVista|Baiduspider|Teoma/i';
+        $regex = '/MoodleBot|Googlebot|google\.com|Yahoo! Slurp|\[ZSEBOT\]|msnbot|bingbot|BingPreview|Yandex|AltaVista'
+                .'|Baiduspider|Teoma/i';
         return (preg_match($regex, $this->useragent));
     }
 
index 5ab80e9..667b6c1 100644 (file)
@@ -3556,5 +3556,58 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2019092700.01);
     }
 
+    if ($oldversion < 2019100800.02) {
+        // Rename the official moodle sites directory the site is registered with.
+        $DB->execute("UPDATE {registration_hubs}
+                         SET hubname = ?, huburl = ?
+                       WHERE huburl = ?", ['moodle', 'https://stats.moodle.org', 'https://moodle.net']);
+
+        // Convert the hub site specific settings to the new naming format without the hub URL in the name.
+        $hubconfig = get_config('hub');
+
+        if (!empty($hubconfig)) {
+            foreach (upgrade_convert_hub_config_site_param_names($hubconfig, 'https://moodle.net') as $name => $value) {
+                set_config($name, $value, 'hub');
+            }
+        }
+
+        upgrade_main_savepoint(true, 2019100800.02);
+    }
+
+    if ($oldversion < 2019100900.00) {
+        // If block_participants is no longer present, remove it.
+        if (!file_exists($CFG->dirroot . '/blocks/participants/block_participants.php')) {
+            // Delete instances.
+            $instances = $DB->get_records_list('block_instances', 'blockname', ['participants']);
+            $instanceids = array_keys($instances);
+
+            if (!empty($instanceids)) {
+                $DB->delete_records_list('block_positions', 'blockinstanceid', $instanceids);
+                $DB->delete_records_list('block_instances', 'id', $instanceids);
+                list($sql, $params) = $DB->get_in_or_equal($instanceids, SQL_PARAMS_NAMED);
+                $params['contextlevel'] = CONTEXT_BLOCK;
+                $DB->delete_records_select('context', "contextlevel=:contextlevel AND instanceid " . $sql, $params);
+
+                $preferences = array();
+                foreach ($instances as $instanceid => $instance) {
+                    $preferences[] = 'block' . $instanceid . 'hidden';
+                    $preferences[] = 'docked_block_instance_' . $instanceid;
+                }
+                $DB->delete_records_list('user_preferences', 'name', $preferences);
+            }
+
+            // Delete the block from the block table.
+            $DB->delete_records('block', array('name' => 'participants'));
+
+            // Remove capabilities.
+            capabilities_cleanup('block_participants');
+
+            // Clean config.
+            unset_all_config_for_plugin('block_participants');
+        }
+
+        upgrade_main_savepoint(true, 2019100900.00);
+    }
+
     return true;
 }
index 4c47550..802417a 100644 (file)
@@ -350,10 +350,10 @@ function upgrade_course_letter_boundary($courseid = null) {
     }
     $lettercolumnsql = '';
     if ($usergradelettercolumnsetting) {
-        // the system default is to show a column with letters (and the course uses the defaults).
+        // The system default is to show a column with letters (and the course uses the defaults).
         $lettercolumnsql = '(gss.value is NULL OR ' . $DB->sql_compare_text('gss.value') .  ' <> \'0\')';
     } else {
-        // the course displays a column with letters.
+        // The course displays a column with letters.
         $lettercolumnsql = $DB->sql_compare_text('gss.value') .  ' = \'1\'';
     }
 
@@ -608,4 +608,48 @@ function upgrade_rename_prediction_actions_useful_incorrectly_flagged() {
 
         $DB->execute($updatesql, $params + ['modelid' => $model->id]);
     }
-}
\ No newline at end of file
+}
+
+/**
+ * Convert the site settings for the 'hub' component in the config_plugins table.
+ *
+ * @param stdClass $hubconfig Settings loaded for the 'hub' component.
+ * @param string $huburl The URL of the hub to use as the valid one in case of conflict.
+ * @return stdClass List of new settings to be applied (including null values to be unset).
+ */
+function upgrade_convert_hub_config_site_param_names(stdClass $hubconfig, string $huburl): stdClass {
+
+    $cleanhuburl = clean_param($huburl, PARAM_ALPHANUMEXT);
+    $converted = [];
+
+    foreach ($hubconfig as $oldname => $value) {
+        if (preg_match('/^site_([a-z]+)([A-Za-z0-9_-]*)/', $oldname, $matches)) {
+            $newname = 'site_'.$matches[1];
+
+            if ($oldname === $newname) {
+                // There is an existing value with the new naming convention already.
+                $converted[$newname] = $value;
+
+            } else if (!array_key_exists($newname, $converted)) {
+                // Add the value under a new name and mark the original to be unset.
+                $converted[$newname] = $value;
+                $converted[$oldname] = null;
+
+            } else if ($matches[2] === '_'.$cleanhuburl) {
+                // The new name already exists, overwrite only if coming from the valid hub.
+                $converted[$newname] = $value;
+                $converted[$oldname] = null;
+
+            } else {
+                // Just unset the old value.
+                $converted[$oldname] = null;
+            }
+
+        } else {
+            // Not a hub-specific site setting, just keep it.
+            $converted[$oldname] = $value;
+        }
+    }
+
+    return (object) $converted;
+}
index 4d3cd85..7ce85d3 100644 (file)
@@ -33,7 +33,6 @@ use \core\dml\table;
  * @copyright  2019 Andrew Nicols <andrew@nicols.co.uk>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @coversDefaultClass \core\dml\table
- * @covers ::<!public>
  */
 class core_dml_table_testcase extends database_driver_testcase {
 
index aac1cac..fbb5c39 100644 (file)
@@ -567,13 +567,8 @@ function enrol_get_my_courses($fields = null, $sort = null, $limit = 0, $coursei
     $offset = 0, $excludecourses = []) {
     global $DB, $USER, $CFG;
 
-    if ($sort === null) {
-        if (empty($CFG->navsortmycoursessort)) {
-            $sort = 'visible DESC, sortorder ASC';
-        } else {
-            $sort = 'visible DESC, '.$CFG->navsortmycoursessort.' ASC';
-        }
-    }
+    // Re-Arrange the course sorting according to the admin settings.
+    $sort = enrol_get_courses_sortingsql($sort);
 
     // Guest account does not have any enrolled courses.
     if (!$allaccessible && (isguestuser() or !isloggedin())) {
@@ -804,6 +799,41 @@ function enrol_get_course_info_icons($course, array $instances = NULL) {
     return $icons;
 }
 
+/**
+ * Returns SQL ORDER arguments which reflect the admin settings to sort my courses.
+ *
+ * @param string|null $sort SQL ORDER arguments which were originally requested (optionally).
+ * @return string SQL ORDER arguments.
+ */
+function enrol_get_courses_sortingsql($sort = null) {
+    global $CFG;
+
+    // Prepare the visible SQL fragment as empty.
+    $visible = '';
+    // Only create a visible SQL fragment if the caller didn't already pass a sort order which contains the visible field.
+    if ($sort === null || strpos($sort, 'visible') === false) {
+        // If the admin did not explicitly want to have shown and hidden courses sorted as one list, we will sort hidden
+        // courses to the end of the course list.
+        if (!isset($CFG->navsortmycourseshiddenlast) || $CFG->navsortmycourseshiddenlast == true) {
+            $visible = 'visible DESC, ';
+        }
+    }
+
+    // Only create a sortorder SQL fragment if the caller didn't already pass one.
+    if ($sort === null) {
+        // If the admin has configured a course sort order, we will use this.
+        if (!empty($CFG->navsortmycoursessort)) {
+            $sort = $CFG->navsortmycoursessort . ' ASC';
+
+            // Otherwise we will fall back to the sortorder sorting.
+        } else {
+            $sort = 'sortorder ASC';
+        }
+    }
+
+    return $visible . $sort;
+}
+
 /**
  * Returns course enrolment detailed information.
  *
@@ -955,15 +985,10 @@ function enrol_user_sees_own_courses($user = null) {
  * @return array
  */
 function enrol_get_all_users_courses($userid, $onlyactive = false, $fields = null, $sort = null) {
-    global $CFG, $DB;
+    global $DB;
 
-    if ($sort === null) {
-        if (empty($CFG->navsortmycoursessort)) {
-            $sort = 'visible DESC, sortorder ASC';
-        } else {
-            $sort = 'visible DESC, '.$CFG->navsortmycoursessort.' ASC';
-        }
-    }
+    // Re-Arrange the course sorting according to the admin settings.
+    $sort = enrol_get_courses_sortingsql($sort);
 
     // Guest account does not have any courses
     if (isguestuser($userid) or empty($userid)) {
index c541731..cb20d06 100644 (file)
@@ -3103,7 +3103,7 @@ class curl {
      */
     public function resetopt() {
         $this->options = array();
-        $this->options['CURLOPT_USERAGENT']         = 'MoodleBot/1.0';
+        $this->options['CURLOPT_USERAGENT']         = \core_useragent::get_moodlebot_useragent();
         // True to include the header in the output
         $this->options['CURLOPT_HEADER']            = 0;
         // True to Exclude the body from the output
@@ -3346,7 +3346,7 @@ class curl {
         } else if (!empty($this->options['CURLOPT_USERAGENT'])) {
             $useragent = $this->options['CURLOPT_USERAGENT'];
         } else {
-            $useragent = 'MoodleBot/1.0';
+            $useragent = \core_useragent::get_moodlebot_useragent();
         }
 
         // Set headers.
index 30c15ad..20db7b7 100644 (file)
@@ -43,7 +43,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Files can be created from strings.
      *
      * @covers ::create_file_from_string
-     * @covers ::<!public>
      */
     public function test_create_file_from_string() {
         global $DB;
@@ -117,7 +116,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Local files can be added to the filepool
      *
      * @covers ::create_file_from_pathname
-     * @covers ::<!public>
      */
     public function test_create_file_from_pathname() {
         global $CFG, $DB;
@@ -200,7 +198,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests get get file.
      *
      * @covers ::get_file
-     * @covers ::<!public>
      */
     public function test_get_file() {
         global $CFG;
@@ -241,7 +238,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @param stored_file $file
      * @depends test_get_file
      * @covers ::get_file_preview
-     * @covers ::<!public>
      */
     public function test_get_file_preview(stored_file $file) {
         global $CFG;
@@ -265,7 +261,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for get_file_preview without an image.
      *
      * @covers ::get_file_preview
-     * @covers ::<!public>
      */
     public function test_get_file_preview_nonimage() {
         $this->resetAfterTest(true);
@@ -293,7 +288,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      *
      * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org}
      * @covers stored_file::rename
-     * @covers ::<!public>
      */
     public function test_file_renaming() {
         global $CFG;
@@ -340,7 +334,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      *
      * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org}
      * @covers ::create_file_from_reference
-     * @covers ::<!public>
      */
     public function test_create_file_from_reference() {
         global $CFG, $DB;
@@ -427,7 +420,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      *
      * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org}
      * @covers ::create_file_from_reference
-     * @covers ::<!public>
      */
     public function test_create_file_from_reference_with_content_hash() {
         global $CFG, $DB;
@@ -537,7 +529,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for get_area_files
      *
      * @covers ::get_area_files
-     * @covers ::<!public>
      */
     public function test_get_area_files() {
         $user = $this->setup_three_private_files();
@@ -598,7 +589,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for get_area_tree
      *
      * @covers ::get_area_tree
-     * @covers ::<!public>
      */
     public function test_get_area_tree() {
         $user = $this->setup_three_private_files();
@@ -658,7 +648,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for get_file_by_id
      *
      * @covers ::get_file_by_id
-     * @covers ::<!public>
      */
     public function test_get_file_by_id() {
         $user = $this->setup_three_private_files();
@@ -680,7 +669,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for get_file_by_hash
      *
      * @covers ::get_file_by_hash
-     * @covers ::<!public>
      */
     public function test_get_file_by_hash() {
         $user = $this->setup_three_private_files();
@@ -701,7 +689,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for get_external_files
      *
      * @covers ::get_external_files
-     * @covers ::<!public>
      */
     public function test_get_external_files() {
         $user = $this->setup_three_private_files();
@@ -768,7 +755,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for create_directory with a negative contextid.
      *
      * @covers ::create_directory
-     * @covers ::<!public>
      */
     public function test_create_directory_contextid_negative() {
         $fs = get_file_storage();
@@ -781,7 +767,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for create_directory with an invalid contextid.
      *
      * @covers ::create_directory
-     * @covers ::<!public>
      */
     public function test_create_directory_contextid_invalid() {
         $fs = get_file_storage();
@@ -794,7 +779,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for create_directory with an invalid component.
      *
      * @covers ::create_directory
-     * @covers ::<!public>
      */
     public function test_create_directory_component_invalid() {
         $fs = get_file_storage();
@@ -808,7 +792,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for create_directory with an invalid filearea.
      *
      * @covers ::create_directory
-     * @covers ::<!public>
      */
     public function test_create_directory_filearea_invalid() {
         $fs = get_file_storage();
@@ -822,7 +805,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for create_directory with a negative itemid
      *
      * @covers ::create_directory
-     * @covers ::<!public>
      */
     public function test_create_directory_itemid_negative() {
         $fs = get_file_storage();
@@ -836,7 +818,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for create_directory with an invalid itemid
      *
      * @covers ::create_directory
-     * @covers ::<!public>
      */
     public function test_create_directory_itemid_invalid() {
         $fs = get_file_storage();
@@ -850,7 +831,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for create_directory with an invalid filepath
      *
      * @covers ::create_directory
-     * @covers ::<!public>
      */
     public function test_create_directory_filepath_invalid() {
         $fs = get_file_storage();
@@ -864,7 +844,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for get_directory_files.
      *
      * @covers ::get_directory_files
-     * @covers ::<!public>
      */
     public function test_get_directory_files() {
         $user = $this->setup_three_private_files();
@@ -927,7 +906,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for search_references.
      *
      * @covers ::search_references
-     * @covers ::<!public>
      */
     public function test_search_references() {
         $user = $this->setup_three_private_files();
@@ -1005,7 +983,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for delete_area_files.
      *
      * @covers ::delete_area_files
-     * @covers ::<!public>
      */
     public function test_delete_area_files() {
         $user = $this->setup_three_private_files();
@@ -1026,7 +1003,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for delete_area_files using an itemid.
      *
      * @covers ::delete_area_files
-     * @covers ::<!public>
      */
     public function test_delete_area_files_itemid() {
         $user = $this->setup_three_private_files();
@@ -1046,7 +1022,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for delete_area_files_select.
      *
      * @covers ::delete_area_files_select
-     * @covers ::<!public>
      */
     public function test_delete_area_files_select() {
         $user = $this->setup_three_private_files();
@@ -1067,7 +1042,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for delete_component_files.
      *
      * @covers ::delete_component_files
-     * @covers ::<!public>
      */
     public function test_delete_component_files() {
         $user = $this->setup_three_private_files();
@@ -1084,7 +1058,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for create_file_from_url.
      *
      * @covers ::create_file_from_url
-     * @covers ::<!public>
      */
     public function test_create_file_from_url() {
         $this->resetAfterTest(true);
@@ -1120,7 +1093,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for cron.
      *
      * @covers ::cron
-     * @covers ::<!public>
      */
     public function test_cron() {
         $this->resetAfterTest(true);
@@ -1137,7 +1109,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for is_area_empty.
      *
      * @covers ::is_area_empty
-     * @covers ::<!public>
      */
     public function test_is_area_empty() {
         $user = $this->setup_three_private_files();
@@ -1155,7 +1126,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for move_area_files_to_new_context.
      *
      * @covers ::move_area_files_to_new_context
-     * @covers ::<!public>
      */
     public function test_move_area_files_to_new_context() {
         $this->resetAfterTest(true);
@@ -1210,7 +1180,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for convert_image.
      *
      * @covers ::convert_image
-     * @covers ::<!public>
      */
     public function test_convert_image() {
         global $CFG;
@@ -1244,7 +1213,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for convert_image with a PNG.
      *
      * @covers ::convert_image
-     * @covers ::<!public>
      */
     public function test_convert_image_png() {
         global $CFG;
@@ -1325,7 +1293,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
     /**
      * @expectedException        file_exception
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile_file_invalid() {
         $this->resetAfterTest(true);
@@ -1342,7 +1309,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid contextid
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile_contextid_invalid() {
         $this->resetAfterTest(true);
@@ -1363,7 +1329,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid component
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile_component_invalid() {
         $this->resetAfterTest(true);
@@ -1384,7 +1349,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid filearea
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile_filearea_invalid() {
         $this->resetAfterTest(true);
@@ -1405,7 +1369,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid itemid
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile_itemid_invalid() {
         $this->resetAfterTest(true);
@@ -1426,7 +1389,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file path
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile_filepath_invalid() {
         $this->resetAfterTest(true);
@@ -1447,7 +1409,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file name
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile_filename_invalid() {
         $this->resetAfterTest(true);
@@ -1467,7 +1428,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file timecreated
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile_timecreated_invalid() {
         $this->resetAfterTest(true);
@@ -1488,7 +1448,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file timemodified
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile_timemodified_invalid() {
         $this->resetAfterTest(true);
@@ -1509,7 +1468,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        stored_file_creation_exception
      * @expectedExceptionMessage Can not create file "1/core/phpunit/0/testfile.txt"
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile_duplicate() {
         $this->resetAfterTest(true);
@@ -1528,7 +1486,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for create_file_from_storedfile.
      *
      * @covers ::create_file_from_storedfile
-     * @covers ::<!public>
      */
     public function test_create_file_from_storedfile() {
         $this->resetAfterTest(true);
@@ -1568,7 +1525,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid contextid
      * @covers ::create_file_from_string
-     * @covers ::<!public>
      */
     public function test_create_file_from_string_contextid_invalid() {
         $this->resetAfterTest(true);
@@ -1585,7 +1541,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid component
      * @covers ::create_file_from_string
-     * @covers ::<!public>
      */
     public function test_create_file_from_string_component_invalid() {
         $this->resetAfterTest(true);
@@ -1602,7 +1557,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid filearea
      * @covers ::create_file_from_string
-     * @covers ::<!public>
      */
     public function test_create_file_from_string_filearea_invalid() {
         $this->resetAfterTest(true);
@@ -1619,7 +1573,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid itemid
      * @covers ::create_file_from_string
-     * @covers ::<!public>
      */
     public function test_create_file_from_string_itemid_invalid() {
         $this->resetAfterTest(true);
@@ -1636,7 +1589,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file path
      * @covers ::create_file_from_string
-     * @covers ::<!public>
      */
     public function test_create_file_from_string_filepath_invalid() {
         $this->resetAfterTest(true);
@@ -1653,7 +1605,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file name
      * @covers ::create_file_from_string
-     * @covers ::<!public>
      */
     public function test_create_file_from_string_filename_invalid() {
         $this->resetAfterTest(true);
@@ -1670,7 +1621,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file timecreated
      * @covers ::create_file_from_string
-     * @covers ::<!public>
      */
     public function test_create_file_from_string_timecreated_invalid() {
         $this->resetAfterTest(true);
@@ -1689,7 +1639,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file timemodified
      * @covers ::create_file_from_string
-     * @covers ::<!public>
      */
     public function test_create_file_from_string_timemodified_invalid() {
         $this->resetAfterTest(true);
@@ -1705,7 +1654,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
     /**
      * Tests for create_file_from_string with a duplicate string.
      * @covers ::create_file_from_string
-     * @covers ::<!public>
      */
     public function test_create_file_from_string_duplicate() {
         $this->resetAfterTest(true);
@@ -1724,7 +1672,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid contextid
      * @covers ::create_file_from_pathname
-     * @covers ::<!public>
      */
     public function test_create_file_from_pathname_contextid_invalid() {
         global $CFG;
@@ -1744,7 +1691,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid component
      * @covers ::create_file_from_pathname
-     * @covers ::<!public>
      */
     public function test_create_file_from_pathname_component_invalid() {
         global $CFG;
@@ -1764,7 +1710,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid filearea
      * @covers ::create_file_from_pathname
-     * @covers ::<!public>
      */
     public function test_create_file_from_pathname_filearea_invalid() {
         global $CFG;
@@ -1784,7 +1729,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid itemid
      * @covers ::create_file_from_pathname
-     * @covers ::<!public>
      */
     public function test_create_file_from_pathname_itemid_invalid() {
         global $CFG;
@@ -1804,7 +1748,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file path
      * @covers ::create_file_from_pathname
-     * @covers ::<!public>
      */
     public function test_create_file_from_pathname_filepath_invalid() {
         global $CFG;
@@ -1824,7 +1767,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file name
      * @covers ::create_file_from_pathname
-     * @covers ::<!public>
      */
     public function test_create_file_from_pathname_filename_invalid() {
         global $CFG;
@@ -1844,7 +1786,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file timecreated
      * @covers ::create_file_from_pathname
-     * @covers ::<!public>
      */
     public function test_create_file_from_pathname_timecreated_invalid() {
         global $CFG;
@@ -1864,7 +1805,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        file_exception
      * @expectedExceptionMessage Invalid file timemodified
      * @covers ::create_file_from_pathname
-     * @covers ::<!public>
      */
     public function test_create_file_from_pathname_timemodified_invalid() {
         global $CFG;
@@ -1884,7 +1824,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * @expectedException        stored_file_creation_exception
      * @expectedExceptionMessage Can not create file "1/core/phpunit/0/testfile.txt"
      * @covers ::create_file_from_pathname
-     * @covers ::<!public>
      */
     public function test_create_file_from_pathname_duplicate_file() {
         global $CFG;
@@ -1906,7 +1845,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Calling stored_file::delete_reference() on a non-reference file throws coding_exception
      *
      * @covers stored_file::delete_reference
-     * @covers ::<!public>
      */
     public function test_delete_reference_on_nonreference() {
 
@@ -1935,7 +1873,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * symlinks to the same original
      *
      * @covers stored_file::delete_reference
-     * @covers ::<!public>
      */
     public function test_delete_reference_one_symlink_does_not_rule_them_all() {
 
@@ -2105,7 +2042,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * Tests for get_unused_filename.
      *
      * @covers ::get_unused_filename
-     * @covers ::<!public>
      */
     public function test_get_unused_filename() {
         global $USER;
@@ -2174,7 +2110,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * file could not be found.
      *
      * @covers ::mimetype
-     * @covers ::<!public>
      */
     public function test_mimetype_not_found() {
         $mimetype = file_storage::mimetype('/path/to/nonexistent/file');
@@ -2190,7 +2125,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * errors and behaves as expected.
      *
      * @covers ::mimetype
-     * @covers ::<!public>
      */
     public function test_mimetype_known() {
         $filepath = __DIR__ . '/fixtures/testimage.jpg';
@@ -2203,7 +2137,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * file could not be found.
      *
      * @covers ::mimetype
-     * @covers ::<!public>
      */
     public function test_mimetype_from_file_not_found() {
         $mimetype = file_storage::mimetype_from_file('/path/to/nonexistent/file');
@@ -2219,7 +2152,6 @@ class core_files_file_storage_testcase extends advanced_testcase {
      * errors and behaves as expected.
      *
      * @covers ::mimetype
-     * @covers ::<!public>
      */
     public function test_mimetype_from_file_known() {
         $filepath = __DIR__ . '/fixtures/testimage.jpg';
index 14421a0..525d770 100644 (file)
@@ -140,7 +140,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * is not writable.
      *
      * @covers ::__construct
-     * @covers ::<!public>
      */
     public function test_readonly_filesystem_filedir() {
         $this->resetAfterTest();
@@ -165,7 +164,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * is not writable.
      *
      * @covers ::__construct
-     * @covers ::<!public>
      */
     public function test_readonly_filesystem_trashdir() {
         $this->resetAfterTest();
@@ -189,7 +187,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Test that the standard Moodle warning message is put into the filedir.
      *
      * @covers ::__construct
-     * @covers ::<!public>
      */
     public function test_warnings_put_in_place() {
         $this->resetAfterTest();
@@ -210,7 +207,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * simply calls get_local_path_from_hash.
      *
      * @covers ::get_remote_path_from_hash
-     * @covers ::<!public>
      */
     public function test_get_remote_path_from_hash() {
         $filecontent = 'example content';
@@ -238,7 +234,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * a failed recovery.
      *
      * @covers ::get_local_path_from_storedfile
-     * @covers ::<!public>
      */
     public function test_get_local_path_from_storedfile_with_recovery() {
         $filecontent = 'example content';
@@ -267,7 +262,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * a failed recovery.
      *
      * @covers ::get_local_path_from_storedfile
-     * @covers ::<!public>
      */
     public function test_get_local_path_from_storedfile_without_recovery() {
         $filecontent = 'example content';
@@ -299,7 +293,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * @param   string  $hashdir Expected format of content directory
      *
      * @covers ::get_fulldir_from_hash
-     * @covers ::<!public>
      */
     public function test_get_fulldir_from_hash($hash, $hashdir) {
         global $CFG;
@@ -322,7 +315,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * @param   string  $hashdir Expected format of content directory
      *
      * @covers ::get_fulldir_from_storedfile
-     * @covers ::<!public>
      */
     public function test_get_fulldir_from_storedfile($hash, $hashdir) {
         global $CFG;
@@ -355,7 +347,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * @param   string  $hashdir Expected format of content directory
      *
      * @covers ::get_contentdir_from_hash
-     * @covers ::<!public>
      */
     public function test_get_contentdir_from_hash($hash, $hashdir) {
         $method = new ReflectionMethod(file_system_filedir::class, 'get_contentdir_from_hash');
@@ -376,7 +367,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * @param   string  $hashdir Expected format of content directory
      *
      * @covers ::get_contentpath_from_hash
-     * @covers ::<!public>
      */
     public function test_get_contentpath_from_hash($hash, $hashdir) {
         $method = new ReflectionMethod(file_system_filedir::class, 'get_contentpath_from_hash');
@@ -398,7 +388,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * @param   string  $hashdir Expected format of content directory
      *
      * @covers ::get_trash_fullpath_from_hash
-     * @covers ::<!public>
      */
     public function test_get_trash_fullpath_from_hash($hash, $hashdir) {
         global $CFG;
@@ -421,7 +410,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * @param   string  $hashdir Expected format of content directory
      *
      * @covers ::get_trash_fulldir_from_hash
-     * @covers ::<!public>
      */
     public function test_get_trash_fulldir_from_hash($hash, $hashdir) {
         global $CFG;
@@ -439,7 +427,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Ensure that copying a file to a target from a stored_file works as anticipated.
      *
      * @covers ::copy_content_from_storedfile
-     * @covers ::<!public>
      */
     public function test_copy_content_from_storedfile() {
         $this->resetAfterTest();
@@ -478,7 +465,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Ensure that content recovery works.
      *
      * @covers ::recover_file
-     * @covers ::<!public>
      */
     public function test_recover_file() {
         $this->resetAfterTest();
@@ -519,7 +505,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Ensure that content recovery works.
      *
      * @covers ::recover_file
-     * @covers ::<!public>
      */
     public function test_recover_file_already_present() {
         $this->resetAfterTest();
@@ -559,7 +544,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Ensure that content recovery works.
      *
      * @covers ::recover_file
-     * @covers ::<!public>
      */
     public function test_recover_file_size_mismatch() {
         $this->resetAfterTest();
@@ -597,7 +581,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Ensure that content recovery works.
      *
      * @covers ::recover_file
-     * @covers ::<!public>
      */
     public function test_recover_file_has_mismatch() {
         $this->resetAfterTest();
@@ -636,7 +619,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * alt trash directory.
      *
      * @covers ::recover_file
-     * @covers ::<!public>
      */
     public function test_recover_file_alttrash() {
         $this->resetAfterTest();
@@ -672,7 +654,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * file to the pool when the pool directory structure is not writable.
      *
      * @covers ::recover_file
-     * @covers ::<!public>
      */
     public function test_recover_file_contentdir_readonly() {
         $this->resetAfterTest();
@@ -710,7 +691,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Test adding a file to the pool.
      *
      * @covers ::add_file_from_path
-     * @covers ::<!public>
      */
     public function test_add_file_from_path() {
         $this->resetAfterTest();
@@ -747,7 +727,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * unavailable file to the pool is attempted.
      *
      * @covers ::add_file_from_path
-     * @covers ::<!public>
      */
     public function test_add_file_from_path_file_unavailable() {
         $this->resetAfterTest();
@@ -768,7 +747,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * the wrong contenthash when adding a file to the pool.
      *
      * @covers ::add_file_from_path
-     * @covers ::<!public>
      */
     public function test_add_file_from_path_mismatched_hash() {
         $this->resetAfterTest();
@@ -791,7 +769,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * file in the pool has the wrong contenthash
      *
      * @covers ::add_file_from_path
-     * @covers ::<!public>
      */
     public function test_add_file_from_path_existing_content_invalid() {
         $this->resetAfterTest();
@@ -837,7 +814,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * file to the pool when the pool directory structure is not writable.
      *
      * @covers ::add_file_from_path
-     * @covers ::<!public>
      */
     public function test_add_file_from_path_existing_cannot_write_hashpath() {
         $this->resetAfterTest();
@@ -871,7 +847,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Test adding a string to the pool.
      *
      * @covers ::add_file_from_string
-     * @covers ::<!public>
      */
     public function test_add_file_from_string() {
         $this->resetAfterTest();
@@ -899,7 +874,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * string to the pool when the pool directory structure is not writable.
      *
      * @covers ::add_file_from_string
-     * @covers ::<!public>
      */
     public function test_add_file_from_string_existing_cannot_write_hashpath() {
         $this->resetAfterTest();
@@ -931,7 +905,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * contenthash is already present.
      *
      * @covers ::add_file_from_string
-     * @covers ::<!public>
      */
     public function test_add_file_from_string_existing_matches() {
         $this->resetAfterTest();
@@ -966,7 +939,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Test the cleanup of deleted files when there are no files to delete.
      *
      * @covers ::remove_file
-     * @covers ::<!public>
      */
     public function test_remove_file_missing() {
         $this->resetAfterTest();
@@ -990,7 +962,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * trash for that path.
      *
      * @covers ::remove_file
-     * @covers ::<!public>
      */
     public function test_remove_file_existing_trash() {
         $this->resetAfterTest();
@@ -1020,7 +991,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Ensure that remove_file does nothing with an empty file.
      *
      * @covers ::remove_file
-     * @covers ::<!public>
      */
     public function test_remove_file_empty() {
         $this->resetAfterTest();
@@ -1044,7 +1014,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * in use.
      *
      * @covers ::remove_file
-     * @covers ::<!public>
      */
     public function test_remove_file_in_use() {
         $this->resetAfterTest();
@@ -1078,7 +1047,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * longer in use.
      *
      * @covers ::remove_file
-     * @covers ::<!public>
      */
     public function test_remove_file_expired() {
         $this->resetAfterTest();
@@ -1111,7 +1079,6 @@ class core_files_file_system_filedir_testcase extends advanced_testcase {
      * Test purging the cache.
      *
      * @covers ::empty_trash
-     * @covers ::<!public>
      */
     public function test_empty_trash() {
         $this->resetAfterTest();
index 8508a67..387d047 100644 (file)
@@ -109,7 +109,6 @@ class core_files_file_system_testcase extends advanced_testcase {
     /**
      * Ensure that the file system is not clonable.
      *
-     * @covers ::<!public>
      */
     public function test_not_cloneable() {
         $reflection = new ReflectionClass('file_system');
@@ -119,7 +118,6 @@ class core_files_file_system_testcase extends advanced_testcase {
     /**
      * Ensure that the filedir file_system extension is used by default.
      *
-     * @covers ::<!public>
      */
     public function test_default_class() {
         $this->resetAfterTest();
@@ -137,7 +135,6 @@ class core_files_file_system_testcase extends advanced_testcase {
     /**
      * Ensure that the specified file_system extension class is used.
      *
-     * @covers ::<!public>
      */
     public function test_supplied_class() {
         global $CFG;
@@ -160,7 +157,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test that the readfile function outputs content to disk.
      *
      * @covers ::readfile
-     * @covers ::<!public>
      */
     public function test_readfile_remote() {
         global $CFG;
@@ -194,7 +190,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test that the readfile function outputs content to disk.
      *
      * @covers ::readfile
-     * @covers ::<!public>
      */
     public function test_readfile_local() {
         global $CFG;
@@ -233,7 +228,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * @param   bool    $fetch Whether the combination of args should have caused a fetch
      *
      * @covers ::get_local_path_from_storedfile
-     * @covers ::<!public>
      */
     public function test_get_local_path_from_storedfile($args, $fetch) {
         $filepath = '/path/to/file';
@@ -261,7 +255,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * fetch.
      *
      * @covers ::get_remote_path_from_storedfile
-     * @covers ::<!public>
      */
     public function test_get_remote_path_from_storedfile() {
         $filepath = '/path/to/file';
@@ -292,7 +285,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Fetching the file is optional.
      *
      * @covers ::is_file_readable_locally_by_hash
-     * @covers ::<!public>
      */
     public function test_is_file_readable_locally_by_hash() {
         $filecontent = 'example content';
@@ -314,7 +306,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of is_file_readable_locally_by_hash with an empty file.
      *
      * @covers ::is_file_readable_locally_by_hash
-     * @covers ::<!public>
      */
     public function test_is_file_readable_locally_by_hash_empty() {
         $filecontent = '';
@@ -334,7 +325,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
      *
      * @covers ::is_file_readable_remotely_by_hash
-     * @covers ::<!public>
      */
     public function test_is_file_readable_remotely_by_hash() {
         $filecontent = 'example content';
@@ -355,7 +345,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
      *
      * @covers ::is_file_readable_remotely_by_hash
-     * @covers ::<!public>
      */
     public function test_is_file_readable_remotely_by_hash_empty() {
         $filecontent = '';
@@ -375,7 +364,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
      *
      * @covers ::is_file_readable_remotely_by_hash
-     * @covers ::<!public>
      */
     public function test_is_file_readable_remotely_by_hash_not_found() {
         $filecontent = 'example content';
@@ -396,7 +384,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
      *
      * @covers ::is_file_readable_remotely_by_storedfile
-     * @covers ::<!public>
      */
     public function test_is_file_readable_remotely_by_storedfile() {
         $file = $this->get_stored_file('example content');
@@ -415,7 +402,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
      *
      * @covers ::is_file_readable_remotely_by_storedfile
-     * @covers ::<!public>
      */
     public function test_is_file_readable_remotely_by_storedfile_empty() {
         $fs = $this->get_testable_mock([
@@ -433,7 +419,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of is_file_readable_locally_by_storedfile with an empty file.
      *
      * @covers ::is_file_readable_locally_by_storedfile
-     * @covers ::<!public>
      */
     public function test_is_file_readable_locally_by_storedfile_empty() {
         $fs = $this->get_testable_mock([
@@ -451,7 +436,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
      *
      * @covers ::is_file_readable_locally_by_storedfile
-     * @covers ::<!public>
      */
     public function test_is_file_readable_remotely_by_storedfile_not_found() {
         $file = $this->get_stored_file('example content');
@@ -470,7 +454,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of is_file_readable_locally_by_storedfile with a valid file.
      *
      * @covers ::is_file_readable_locally_by_storedfile
-     * @covers ::<!public>
      */
     public function test_is_file_readable_locally_by_storedfile_unreadable() {
         $fs = $this->get_testable_mock([
@@ -489,7 +472,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of is_file_readable_locally_by_storedfile with a valid file should pass fetch.
      *
      * @covers ::is_file_readable_locally_by_storedfile
-     * @covers ::<!public>
      */
     public function test_is_file_readable_locally_by_storedfile_passes_fetch() {
         $fs = $this->get_testable_mock([
@@ -508,7 +490,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Ensure that is_file_removable returns correctly for an empty file.
      *
      * @covers ::is_file_removable
-     * @covers ::<!public>
      */
     public function test_is_file_removable_empty() {
         $filecontent = '';
@@ -524,7 +505,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Ensure that is_file_removable returns false if the file is still in use.
      *
      * @covers ::is_file_removable
-     * @covers ::<!public>
      */
     public function test_is_file_removable_in_use() {
         $this->resetAfterTest();
@@ -549,7 +529,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Ensure that is_file_removable returns false if the file is not in use.
      *
      * @covers ::is_file_removable
-     * @covers ::<!public>
      */
     public function test_is_file_removable_not_in_use() {
         $this->resetAfterTest();
@@ -574,7 +553,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of get_content.
      *
      * @covers ::get_content
-     * @covers ::<!public>
      */
     public function test_get_content() {
         global $CFG;
@@ -600,7 +578,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Test the stock implementation of get_content.
      *
      * @covers ::get_content
-     * @covers ::<!public>
      */
     public function test_get_content_empty() {
         global $CFG;
@@ -624,7 +601,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * file, and passes the path to the packer.
      *
      * @covers ::list_files
-     * @covers ::<!public>
      */
     public function test_list_files() {
         $filecontent = 'example content';
@@ -657,7 +633,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * file, and passes the path to the packer.
      *
      * @covers ::extract_to_pathname
-     * @covers ::<!public>
      */
     public function test_extract_to_pathname() {
         $filecontent = 'example content';
@@ -691,7 +666,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * file, and passes the path to the packer.
      *
      * @covers ::extract_to_storage
-     * @covers ::<!public>
      */
     public function test_extract_to_storage() {
         $filecontent = 'example content';
@@ -733,7 +707,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Ensure that the add_storedfile_to_archive function requires a local copy of the
      * file, and passes the path to the archive.
      *
-     * @covers ::<!public>
      */
     public function test_add_storedfile_to_archive_directory() {
         $file = $this->get_stored_file('', '.');
@@ -770,7 +743,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Ensure that the add_storedfile_to_archive function requires a local copy of the
      * file, and passes the path to the archive.
      *
-     * @covers ::<!public>
      */
     public function test_add_storedfile_to_archive_file() {
         $file = $this->get_stored_file('example content');
@@ -812,7 +784,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * file, and passes the path to curl_file_create.
      *
      * @covers ::add_to_curl_request
-     * @covers ::<!public>
      */
     public function test_add_to_curl_request() {
         $file = $this->get_stored_file('example content');
@@ -837,7 +808,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * passed was deemed to not be an image.
      *
      * @covers ::get_imageinfo
-     * @covers ::<!public>
      */
     public function test_get_imageinfo_not_image() {
         $filecontent = 'example content';
@@ -859,7 +829,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Ensure that test_get_imageinfo_not_image returns imageinfo.
      *
      * @covers ::get_imageinfo
-     * @covers ::<!public>
      */
     public function test_get_imageinfo() {
         $filepath = '/path/to/file';
@@ -896,7 +865,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * empty file size.
      *
      * @covers ::is_image_from_storedfile
-     * @covers ::<!public>
      */
     public function test_is_image_empty_filesize() {
         $filecontent = 'example content';
@@ -918,7 +886,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * @param   string  $mimetype Mimetype to test
      * @param   bool    $isimage Whether this mimetype should be detected as an image
      * @covers ::is_image_from_storedfile
-     * @covers ::<!public>
      */
     public function test_is_image_from_storedfile_mimetype($mimetype, $isimage) {
         $filecontent = 'example content';
@@ -937,7 +904,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * for an image.
      *
      * @covers ::get_imageinfo_from_path
-     * @covers ::<!public>
      */
     public function test_get_imageinfo_from_path() {
         $filepath = __DIR__ . "/fixtures/testimage.jpg";
@@ -960,7 +926,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * for a file which is not an image.
      *
      * @covers ::get_imageinfo_from_path
-     * @covers ::<!public>
      */
     public function test_get_imageinfo_from_path_no_image() {
         $filepath = __FILE__;
@@ -979,7 +944,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Ensure that get_content_file_handle returns a valid file handle.
      *
      * @covers ::get_content_file_handle
-     * @covers ::<!public>
      */
     public function test_get_content_file_handle_default() {
         $filecontent = 'example content';
@@ -1000,7 +964,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Ensure that get_content_file_handle returns a valid file handle for a gz file.
      *
      * @covers ::get_content_file_handle
-     * @covers ::<!public>
      */
     public function test_get_content_file_handle_gz() {
         $filecontent = 'example content';
@@ -1020,7 +983,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * Ensure that get_content_file_handle returns an exception when calling for a invalid file handle type.
      *
      * @covers ::get_content_file_handle
-     * @covers ::<!public>
      */
     public function test_get_content_file_handle_invalid() {
         $filecontent = 'example content';
@@ -1039,7 +1001,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * a file whose filename suggests mimetype.
      *
      * @covers ::mimetype_from_hash
-     * @covers ::<!public>
      */
     public function test_mimetype_from_hash_using_filename() {
         $filepath = '/path/to/file/not/currently/on/disk';
@@ -1059,7 +1020,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * a locally available file whose filename does not suggest mimetype.
      *
      * @covers ::mimetype_from_hash
-     * @covers ::<!public>
      */
     public function test_mimetype_from_hash_using_file_content() {
         $filecontent = 'example content';
@@ -1079,7 +1039,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * a remotely available file whose filename does not suggest mimetype.
      *
      * @covers ::mimetype_from_hash
-     * @covers ::<!public>
      */
     public function test_mimetype_from_hash_using_file_content_remote() {
         $filepath = '/path/to/file/not/currently/on/disk';
@@ -1108,7 +1067,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * a file whose filename suggests mimetype.
      *
      * @covers ::mimetype_from_storedfile
-     * @covers ::<!public>
      */
     public function test_mimetype_from_storedfile_empty() {
         $file = $this->get_stored_file('');
@@ -1123,7 +1081,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * a file whose filename suggests mimetype.
      *
      * @covers ::mimetype_from_storedfile
-     * @covers ::<!public>
      */
     public function test_mimetype_from_storedfile_using_filename() {
         $filepath = '/path/to/file/not/currently/on/disk';
@@ -1141,7 +1098,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * a locally available file whose filename does not suggest mimetype.
      *
      * @covers ::mimetype_from_storedfile
-     * @covers ::<!public>
      */
     public function test_mimetype_from_storedfile_using_file_content() {
         $filepath = __DIR__ . "/fixtures/testimage.jpg";
@@ -1159,7 +1115,6 @@ class core_files_file_system_testcase extends advanced_testcase {
      * a remotely available file whose filename does not suggest mimetype.
      *
      * @covers ::mimetype_from_storedfile
-     * @covers ::<!public>
      */
     public function test_mimetype_from_storedfile_using_file_content_remote() {
         $filepath = __DIR__ . "/fixtures/testimage.jpg";
@@ -1212,3 +1167,4 @@ class core_files_file_system_testcase extends advanced_testcase {
         ];
     }
 }
+
index b69b4dd..dc8b0b0 100644 (file)
@@ -487,16 +487,9 @@ define('HOMEPAGE_MY', 1);
 define('HOMEPAGE_USER', 2);
 
 /**
- * Hub directory url (should be moodle.org)
+ * URL of the Moodle sites registration portal.
  */
-define('HUB_HUBDIRECTORYURL', "https://hubdirectory.moodle.org");
-
-
-/**
- * Moodle.net url (should be moodle.net)
- */
-define('HUB_MOODLEORGHUBURL', "https://moodle.net");
-define('HUB_OLDMOODLEORGHUBURL', "http://hub.moodle.org");
+defined('HUB_MOODLEORGHUBURL') || define('HUB_MOODLEORGHUBURL', 'https://stats.moodle.org');
 
 /**
  * Moodle mobile app service name
index f6e0c1b..e3bab6d 100644 (file)
@@ -1060,14 +1060,16 @@ EOF;
         $options = $curl->get_options();
         $this->assertNotEmpty($options);
 
+        $moodlebot = \core_useragent::get_moodlebot_useragent();
+
         $curl->call_apply_opt($options);
-        $this->assertTrue(in_array('User-Agent: MoodleBot/1.0', $curl->header));
+        $this->assertTrue(in_array("User-Agent: $moodlebot", $curl->header));
         $this->assertFalse(in_array('User-Agent: Test/1.0', $curl->header));
 
         $options['CURLOPT_USERAGENT'] = 'Test/1.0';
         $curl->call_apply_opt($options);
         $this->assertTrue(in_array('User-Agent: Test/1.0', $curl->header));
-        $this->assertFalse(in_array('User-Agent: MoodleBot/1.0', $curl->header));
+        $this->assertFalse(in_array("User-Agent: $moodlebot", $curl->header));
 
         $curl->set_option('CURLOPT_USERAGENT', 'AnotherUserAgent/1.0');
         $curl->call_apply_opt();
@@ -1082,7 +1084,7 @@ EOF;
 
         $curl->unset_option('CURLOPT_USERAGENT');
         $curl->call_apply_opt();
-        $this->assertTrue(in_array('User-Agent: MoodleBot/1.0', $curl->header));
+        $this->assertTrue(in_array("User-Agent: $moodlebot", $curl->header));
 
         // Finally, test it via exttests, to ensure the agent is sent properly.
         // Matching.
index 108e185..54e4b4d 100644 (file)
@@ -1124,4 +1124,52 @@ class core_upgradelib_testcase extends advanced_testcase {
         $this->assertEquals(1, $DB->count_records('analytics_prediction_actions',
             ['actionname' => \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED]));
     }
+
+    /**
+     * Test the functionality of the {@link upgrade_convert_hub_config_site_param_names()} function.
+     */
+    public function test_upgrade_convert_hub_config_site_param_names() {
+
+        $config = (object) [
+            // This is how site settings related to registration at https://moodle.net are stored.
+            'site_name_httpsmoodlenet' => 'Foo Site',
+            'site_language_httpsmoodlenet' => 'en',
+            'site_emailalert_httpsmoodlenet' => 1,
+            // These are unexpected relics of a value as registered at the old http://hub.moodle.org site.
+            'site_name_httphubmoodleorg' => 'Bar Site',
+            'site_description_httphubmoodleorg' => 'Old description',
+            // This is the target value we are converting to - here it already somehow exists.
+            'site_emailalert' => 0,
+            // This is a setting not related to particular hub.
+            'custom' => 'Do not touch this',
+            // A setting defined for multiple alternative hubs.
+            'site_foo_httpfirsthuborg' => 'First',
+            'site_foo_httpanotherhubcom' => 'Another',
+            'site_foo_httpyetanotherhubcom' => 'Yet another',
+            // A setting defined for multiple alternative hubs and one referential one.
+            'site_bar_httpfirsthuborg' => 'First',
+            'site_bar_httpanotherhubcom' => 'Another',
+            'site_bar_httpsmoodlenet' => 'One hub to rule them all!',
+            'site_bar_httpyetanotherhubcom' => 'Yet another',
+        ];
+
+        $converted = upgrade_convert_hub_config_site_param_names($config, 'https://moodle.net');
+
+        // Values defined for the moodle.net take precedence over the ones defined for other hubs.
+        $this->assertSame($converted->site_name, 'Foo Site');
+        $this->assertSame($converted->site_bar, 'One hub to rule them all!');
+        $this->assertNull($converted->site_name_httpsmoodlenet);
+        $this->assertNull($converted->site_bar_httpfirsthuborg);
+        $this->assertNull($converted->site_bar_httpanotherhubcom);
+        $this->assertNull($converted->site_bar_httpyetanotherhubcom);
+        // Values defined for alternative hubs only do not have any guaranteed value. Just for convenience, we use the first one.
+        $this->assertSame($converted->site_foo, 'First');
+        $this->assertNull($converted->site_foo_httpfirsthuborg);
+        $this->assertNull($converted->site_foo_httpanotherhubcom);
+        $this->assertNull($converted->site_foo_httpyetanotherhubcom);
+        // Values that are already defined with the new name format are kept.
+        $this->assertSame($converted->site_emailalert, 0);
+        // Eventual custom values not following the expected hub-specific naming format, are kept.
+        $this->assertSame($converted->custom, 'Do not touch this');
+    }
 }
index 3342e35..28a3b00 100644 (file)
@@ -1387,6 +1387,16 @@ class core_useragent_testcase extends advanced_testcase {
                ),
             ),
 
+            // MoodleBot.
+            array(
+                'User-Agent: MoodleBot/3.8 (+https://moodle.org)',
+                array(
+                    'is_web_crawler'                => true,
+                    'versionclasses'                => array(
+                    ),
+               ),
+            ),
+
             // Macos Desktop app.
             array(
                 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) moodlemobile/3.6.0 Chrome/69.0.3497.106 Electron/4.0.1 Safari/537.36 MoodleMobile',
diff --git a/mod/forum/tests/behat/forum_export.feature b/mod/forum/tests/behat/forum_export.feature
new file mode 100644 (file)
index 0000000..0fc6c54
--- /dev/null
@@ -0,0 +1,58 @@
+@mod @mod_forum @javascript
+Feature: Export forum
+  In order to parse forum data for linguistic analysis
+  As a teacher
+  I need to export the forum data for select users
+
+  Background: Add a forum and a discussion
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+      | student1 | Student | 1 | student1@example.com |
+      | student2 | Student | 2 | student1@example.com |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And the following "activities" exist:
+      | activity   | name         | intro                     | type      | course | idnumber |
+      | forum      | Test forum 1 | Test forum 1 description  | general   | C1     | 123      |
+
+  Scenario: Teacher can export forum
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    When I follow "Test forum 1"
+    And I navigate to "Export" in current page administration
+    And I open the autocomplete suggestions list
+    And I should see "Student 1" in the ".form-autocomplete-suggestions" "css_element"
+    And I should see "Teacher 1" in the ".form-autocomplete-suggestions" "css_element"
+    And I should not see "Student 2" in the ".form-autocomplete-suggestions" "css_element"
+    # This will fail if an exception is thrown. This is the best we can do without the ability to use the download. Hence, there is no "Then" step.
+    And I click on "Export" "button"
+    And I log out
+
+  Scenario: Students cannot export forum by default
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    When I follow "Test forum 1"
+    Then "Export" "link" should not exist in current page administration
+    And I log out
+
+  Scenario: User with the capability can export
+    Given the following "permission overrides" exist:
+      | capability                  | permission | role           | contextlevel | reference |
+      | mod/forum:exportforum       | Allow      | student        | Course       | C1        |
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Test forum 1"
+    And I navigate to "Export" in current page administration
+    And I open the autocomplete suggestions list
+    And I should see "Student 1" in the ".form-autocomplete-suggestions" "css_element"
+    And I should see "Teacher 1" in the ".form-autocomplete-suggestions" "css_element"
+    And I should not see "Student 2" in the ".form-autocomplete-suggestions" "css_element"
+    # This will fail if an exception is thrown. This is the best we can do without the ability to use the download. Hence, there is no "Then" step.
+    And I click on "Export" "button"
+    And I log out
index 2f8309d..cd7d66c 100644 (file)
@@ -36,7 +36,6 @@ use mod_forum\local\managers\capability as capability_manager;
  * @copyright  2019 Ryan Wyllie <ryan@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @coversDefaultClass \mod_forum\local\managers\capability
- * @covers ::<!public>
  */
 class mod_forum_managers_capability_testcase extends advanced_testcase {
     // Make use of the test generator trait.
index 3cb4a5b..fbf72c7 100644 (file)
@@ -42,7 +42,6 @@ class mod_forum_vaults_forum_testcase extends advanced_testcase {
      * Test get_from_id.
      *
      * @covers ::get_from_id
-     * @covers ::<!public>
      */
     public function test_get_from_id() {
         $this->resetAfterTest();
@@ -63,7 +62,6 @@ class mod_forum_vaults_forum_testcase extends advanced_testcase {
      * Test get_from_course_module_id.
      *
      * @covers ::get_from_course_module_id
-     * @covers ::<!public>
      */
     public function test_get_from_course_module_id() {
         $this->resetAfterTest();
@@ -90,7 +88,6 @@ class mod_forum_vaults_forum_testcase extends advanced_testcase {
      * Test get_from_course_module_ids.
      *
      * @covers ::get_from_course_module_ids
-     * @covers ::<!public>
      */
     public function test_get_from_course_module_ids() {
         $this->resetAfterTest();
@@ -129,7 +126,6 @@ class mod_forum_vaults_forum_testcase extends advanced_testcase {
      * Test get_from_post_id.
      *
      * @covers ::get_from_post_id
-     * @covers ::<!public>
      */
     public function test_get_from_post_id() {
         $this->resetAfterTest();
index 92d399a..6e607b9 100644 (file)
@@ -77,7 +77,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_from_discussion_id.
      *
      * @covers ::get_from_discussion_id
-     * @covers ::<!public>
      */
     public function test_get_from_discussion_id() {
         $this->resetAfterTest();
@@ -107,7 +106,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * replies.
      *
      * @covers ::get_from_discussion_id
-     * @covers ::<!public>
      */
     public function test_get_from_discussion_id_private_replies() {
         $this->resetAfterTest();
@@ -168,7 +166,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_from_discussion_ids.
      *
      * @covers ::get_from_discussion_ids
-     * @covers ::<!public>
      */
     public function test_get_from_discussion_ids() {
         $this->resetAfterTest();
@@ -215,7 +212,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * replies.
      *
      * @covers ::get_from_discussion_ids
-     * @covers ::<!public>
      */
     public function test_get_from_discussion_ids_private_replies() {
         $this->resetAfterTest();
@@ -312,7 +308,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_replies_to_post.
      *
      * @covers ::get_replies_to_post
-     * @covers ::<!public>
      */
     public function test_get_replies_to_post() {
         $this->resetAfterTest();
@@ -361,7 +356,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_replies_to_post with private replies.
      *
      * @covers ::get_replies_to_post
-     * @covers ::<!public>
      */
     public function test_get_replies_to_post_private_replies() {
         $this->resetAfterTest();
@@ -538,7 +532,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_reply_count_for_discussion_ids.
      *
      * @covers ::get_reply_count_for_discussion_ids
-     * @covers ::<!public>
      */
     public function test_get_reply_count_for_discussion_ids() {
         $this->resetAfterTest();
@@ -588,7 +581,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_reply_count_for_discussion_ids.
      *
      * @covers ::get_reply_count_for_discussion_ids
-     * @covers ::<!public>
      */
     public function test_get_reply_count_for_discussion_ids_private_replies() {
         $this->resetAfterTest();
@@ -639,7 +631,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_reply_count_for_discussion_id.
      *
      * @covers ::get_reply_count_for_post_id_in_discussion_id
-     * @covers ::<!public>
      */
     public function test_get_reply_count_for_post_id_in_discussion_id() {
         $this->resetAfterTest();
@@ -670,7 +661,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_reply_count_for_post_id_in_discussion_id.
      *
      * @covers ::get_reply_count_for_post_id_in_discussion_id
-     * @covers ::<!public>
      */
     public function test_get_reply_count_for_post_id_in_discussion_id_private_replies() {
         $this->resetAfterTest();
@@ -721,7 +711,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_unread_count_for_discussion_ids.
      *
      * @covers ::get_unread_count_for_discussion_ids
-     * @covers ::<!public>
      */
     public function test_get_unread_count_for_discussion_ids() {
         global $CFG;
@@ -798,7 +787,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_latest_posts_for_discussion_ids.
      *
      * @covers ::get_latest_posts_for_discussion_ids
-     * @covers ::<!public>
      */
     public function test_get_latest_posts_for_discussion_ids() {
         $this->resetAfterTest();
@@ -861,7 +849,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_latest_posts_for_discussion_ids when no discussion ids were provided.
      *
      * @covers ::get_latest_posts_for_discussion_ids
-     * @covers ::<!public>
      */
     public function test_get_latest_posts_for_discussion_ids_empty() {
         $this->resetAfterTest();
@@ -878,7 +865,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_first_post_for_discussion_ids.
      *
      * @covers ::get_first_post_for_discussion_ids
-     * @covers ::<!public>
      */
     public function test_get_first_post_for_discussion_ids() {
         $this->resetAfterTest();
@@ -926,7 +912,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_first_post_for_discussion_ids when no discussion ids were provided.
      *
      * @covers ::get_first_post_for_discussion_ids
-     * @covers ::<!public>
      */
     public function test_get_first_post_for_discussion_ids_empty() {
         $this->resetAfterTest();
@@ -943,7 +928,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * Test get_from_discussion_ids_and_user_ids.
      *
      * @covers ::get_from_discussion_ids_and_user_ids
-     * @covers ::<!public>
      */
     public function test_get_from_discussion_ids_and_user_ids() {
         $this->resetAfterTest();
@@ -1027,7 +1011,6 @@ class mod_forum_vaults_post_testcase extends advanced_testcase {
      * replies.
      *
      * @covers ::get_from_discussion_ids_and_user_ids
-     * @covers ::<!public>
      */
     public function test_get_from_discussion_ids_and_user_ids_private_replies() {
         $this->resetAfterTest();
index 2361ad6..4c262dd 100644 (file)
@@ -9,7 +9,6 @@
         processIsolation="false"
         backupGlobals="false"
         backupStaticAttributes="false"
-        forceCoversAnnotation="true"
         stopOnError="false"
         stopOnFailure="false"
         stopOnIncomplete="false"
index 45f6ad5..a5057f0 100644 (file)
@@ -42,7 +42,6 @@ class approved_contextlist_test extends advanced_testcase {
      * The approved contextlist should not be modifiable once set.
      *
      * @covers ::__construct
-     * @covers ::<!public>
      * @covers \core_privacy\local\request\approved_contextlist<extended>
      */
     public function test_default_values_set() {
index 3be87c7..f78e441 100644 (file)
@@ -43,7 +43,6 @@ class approved_userlist_test extends advanced_testcase {
      *
      * @covers ::__construct
      * @covers \core_privacy\local\request\approved_userlist<extended>
-     * @covers ::<!public>
      */
     public function test_default_values_set() {
         $this->resetAfterTest();
@@ -76,7 +75,6 @@ class approved_userlist_test extends advanced_testcase {
     /**
      * @covers ::create_from_userlist
      * @covers \core_privacy\local\request\approved_userlist<extended>
-     * @covers ::<!public>
      */
     public function test_create_from_userlist() {
         $this->resetAfterTest();
index b7403f7..0698670 100644 (file)
@@ -43,7 +43,6 @@ class core_privacy_metadata_collection extends advanced_testcase {
      * Test that adding an unknown type causes the type to be added to the collection.
      *
      * @covers ::add_type
-     * @covers ::<!public>
      */
     public function test_add_type_generic_type() {
         $collection = new collection('core_privacy');
@@ -61,7 +60,6 @@ class core_privacy_metadata_collection extends advanced_testcase {
      * Test that adding a known type works as anticipated.
      *
      * @covers ::add_type
-     * @covers ::<!public>
      */
     public function test_add_type_known_type() {
         $collection = new collection('core_privacy');
@@ -78,7 +76,6 @@ class core_privacy_metadata_collection extends advanced_testcase {
      * Test that adding multiple types returns them all.
      *
      * @covers ::add_type
-     * @covers ::<!public>
      */
     public function test_add_type_multiple() {
         $collection = new collection('core_privacy');
@@ -97,7 +94,6 @@ class core_privacy_metadata_collection extends advanced_testcase {
      * Test that the add_database_table function adds a database table.
      *
      * @covers ::add_database_table
-     * @covers ::<!public>
      */
     public function test_add_database_table() {
         $collection = new collection('core_privacy');
@@ -121,7 +117,6 @@ class core_privacy_metadata_collection extends advanced_testcase {
      * Test that the add_user_preference function adds a single user preference.
      *
      * @covers ::add_user_preference
-     * @covers ::<!public>
      */
     public function test_add_user_preference() {
         $collection = new collection('core_privacy');
@@ -143,7 +138,6 @@ class core_privacy_metadata_collection extends advanced_testcase {
      * Test that the link_external_location function links an external location.
      *
      * @covers ::link_external_location
-     * @covers ::<!public>
      */
     public function test_link_external_location() {
         $collection = new collection('core_privacy');
@@ -167,7 +161,6 @@ class core_privacy_metadata_collection extends advanced_testcase {
      * Test that the link_subsystem function links the subsystem.
      *
      * @covers ::link_subsystem
-     * @covers ::<!public>
      */
     public function test_link_subsystem() {
         $collection = new collection('core_privacy');
@@ -189,7 +182,6 @@ class core_privacy_metadata_collection extends advanced_testcase {
      * Test that the link_plugintype function links the plugin.
      *
      * @covers ::link_plugintype
-     * @covers ::<!public>
      */
     public function test_link_plugintype() {
         $collection = new collection('core_privacy');
@@ -227,7 +219,6 @@ class core_privacy_metadata_collection extends advanced_testcase {
      * @dataProvider component_list_provider
      * @param   string  $component The component to test
      * @covers ::get_component
-     * @covers ::<!public>
      */
     public function test_get_component($component) {
         $collection = new collection($component);
index 742ec33..851710e 100644 (file)
@@ -45,7 +45,6 @@ class contextlist_base_test extends advanced_testcase {
      * @param   array   $expected list of contextids
      * @param   int     $count Expected count
      * @covers ::get_contextids
-     * @covers ::<!public>
      */
     public function test_get_contextids($input, $expected, $count) {
         $uit = new test_contextlist_base();
@@ -89,7 +88,6 @@ class contextlist_base_test extends advanced_testcase {
      * Ensure that get_contexts returns the correct list of contexts.
      *
      * @covers ::get_contexts
-     * @covers ::<!public>
      */
     public function test_get_contexts() {
         global $DB;
@@ -121,7 +119,6 @@ class contextlist_base_test extends advanced_testcase {
      * @param   array   $expected list of contextids
      * @param   int     $count Expected count
      * @covers ::count
-     * @covers ::<!public>
      */
     public function test_countable($input, $expected, $count) {
         $uit = new test_contextlist_base();
@@ -138,7 +135,6 @@ class contextlist_base_test extends advanced_testcase {
      * @covers ::next
      * @covers ::rewind
      * @covers ::valid
-     * @covers ::<!public>
      */
     public function test_context_iteration() {
         global $DB;
@@ -161,7 +157,6 @@ class contextlist_base_test extends advanced_testcase {
      * Test that deleting a context results in current returning nothing.
      *
      * @covers ::current
-     * @covers ::<!public>
      */
     public function test_current_context_one_context() {
         global $DB;
@@ -191,7 +186,6 @@ class contextlist_base_test extends advanced_testcase {
      * Test that deleting a context results in the next record being returned.
      *
      * @covers ::current
-     * @covers ::<!public>
      */
     public function test_current_context_two_contexts() {
         global $DB;
@@ -229,7 +223,6 @@ class contextlist_base_test extends advanced_testcase {
      * Test that if there are no non-deleted contexts that nothing is returned.
      *
      * @covers ::get_contexts
-     * @covers ::<!public>
      */
     public function test_get_contexts_all_deleted() {
         global $DB;
@@ -257,7 +250,6 @@ class contextlist_base_test extends advanced_testcase {
      * Test that get_contexts() returns only active contexts.
      *
      * @covers ::get_contexts
-     * @covers ::<!public>
      */
     public function test_get_contexts_one_deleted() {
         global $DB;
index 2eaf5da..2d75eb8 100644 (file)
@@ -43,7 +43,6 @@ class contextlist_collection_test extends advanced_testcase {
      * A contextlist_collection should support the contextlist type.
      *
      * @covers ::add_contextlist
-     * @covers ::<!public>
      */
     public function test_supports_contextlist() {
         $uit = new contextlist_collection(1);
@@ -58,7 +57,6 @@ class contextlist_collection_test extends advanced_testcase {
      * A contextlist_collection should support the approved_contextlist type.
      *
      * @covers ::add_contextlist
-     * @covers ::<!public>
      */
     public function test_supports_approved_contextlist() {
         $uit = new contextlist_collection(1);
@@ -73,7 +71,6 @@ class contextlist_collection_test extends advanced_testcase {
      * Ensure that get_contextlist_for_component returns the correct contextlist.
      *
      * @covers ::get_contextlist_for_component
-     * @covers ::<!public>
      */
     public function test_get_contextlist_for_component() {
         $uit = new contextlist_collection(1);
@@ -95,7 +92,6 @@ class contextlist_collection_test extends advanced_testcase {
      * Ensure that get_contextlist_for_component does not die horribly when querying a non-existent component.
      *
      * @covers ::get_contextlist_for_component
-     * @covers ::<!public>
      */
     public function test_get_contextlist_for_component_not_found() {
         $uit = new contextlist_collection(1);
@@ -107,7 +103,6 @@ class contextlist_collection_test extends advanced_testcase {
      * Ensure that a duplicate contextlist in the collection throws an Exception.
      *
      * @covers ::add_contextlist
-     * @covers ::<!public>
      */
     public function test_duplicate_addition_throws() {
         $uit = new contextlist_collection(1);
@@ -124,7 +119,6 @@ class contextlist_collection_test extends advanced_testcase {
      * Ensure that the contextlist_collection is countable.
      *
      * @covers ::count
-     * @covers ::<!public>
      */
     public function test_countable() {
         $uit = new contextlist_collection(1);
@@ -148,7 +142,6 @@ class contextlist_collection_test extends advanced_testcase {
      * @covers ::next
      * @covers ::rewind
      * @covers ::valid
-     * @covers ::<!public>
      */
     public function test_iteration() {
         $uit = new contextlist_collection(1);
@@ -184,7 +177,6 @@ class contextlist_collection_test extends advanced_testcase {
      * Test that the userid is correctly returned.
      *
      * @covers ::get_userid
-     * @covers ::<!public>
      */
     public function test_get_userid() {
         $uit = new contextlist_collection(1);
index 26bc701..13db812 100644 (file)
@@ -42,7 +42,6 @@ class contextlist_test extends advanced_testcase {
      * Ensure that valid SQL results in the relevant contexts being added.
      *
      * @covers ::add_from_sql
-     * @covers ::<!public>
      */
     public function test_add_from_sql() {
         global $DB;
@@ -61,7 +60,6 @@ class contextlist_test extends advanced_testcase {
      * Ensure that valid system context id is added.
      *
      * @covers ::add_system_context
-     * @covers ::<!public>
      */
     public function test_add_system_context() {
         $cl = new contextlist();
@@ -78,7 +76,6 @@ class contextlist_test extends advanced_testcase {
      * Ensure that a valid user context id is added.
      *
      * @covers ::add_user_context
-     * @covers ::<!public>
      */
     public function test_add_user_context() {
         $this->resetAfterTest();
@@ -100,7 +97,6 @@ class contextlist_test extends advanced_testcase {
      * Ensure that valid user contexts are added.
      *
      * @covers ::add_user_contexts
-     * @covers ::<!public>
      */
     public function test_add_user_contexts() {
         $this->resetAfterTest();
@@ -126,7 +122,6 @@ class contextlist_test extends advanced_testcase {
      * @param string $sql Input SQL we try to extract the context id field name from.
      * @param string $expected Expected detected value.
      * @covers ::guess_id_field_from_sql
-     * @covers ::<!public>
      */
     public function test_guess_id_field_from_sql($sql, $expected) {
 
index 633ecfe..eb1a055 100644 (file)
@@ -69,7 +69,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test collection of metadata for components implementing a metadata provider.
      *
      * @covers ::get_metadata_for_components
-     * @covers ::<!public>
      */
     public function test_get_metadata_for_components() {
         // Get a mock manager, in which the core components list is mocked to include all mock plugins.
@@ -93,7 +92,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test that get_contexts_for_userid() only returns contextlist collections for core providers.
      *
      * @covers ::get_contexts_for_userid
-     * @covers ::<!public>
      */
     public function test_get_contexts_for_userid() {
         // Get a mock manager, in which the core components list is mocked to include all mock plugins.
@@ -121,7 +119,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test verifying the output of component_is_compliant.
      *
      * @covers ::component_is_compliant
-     * @covers ::<!public>
      */
     public function test_component_is_compliant() {
         // Get a mock manager, in which the core components list is mocked to include all mock plugins.
@@ -168,7 +165,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * @param   string  $component
      * @param   boolean $expected
      * @covers ::component_is_compliant
-     * @covers ::<!public>
      */
     public function test_component_is_compliant_examples($component, $expected) {
         $manager = new \core_privacy\manager();
@@ -180,7 +176,6 @@ class privacy_manager_testcase extends advanced_testcase {
      *  Test verifying only approved contextlists can be used with the export_user_data method.
      *
      * @covers ::export_user_data
-     * @covers ::<!public>
      */
     public function test_export_user_data() {
         // Get a mock manager, in which the core components list is mocked to include all mock plugins.
@@ -216,7 +211,6 @@ class privacy_manager_testcase extends advanced_testcase {
      *  Test verifying only approved contextlists can be used with the delete_data_for_user method.
      *
      * @covers ::delete_data_for_user
-     * @covers ::<!public>
      */
     public function test_delete_data_for_user() {
         $this->resetAfterTest();
@@ -250,7 +244,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * This really just checks that all providers can be safely autoloaded.
      *
      * @covers ::get_metadata_for_components
-     * @covers ::<!public>
      */
     public function test_installed_plugins() {
         $manager = new \core_privacy\manager();
@@ -262,7 +255,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test that the reason for the null provider is returned.
      *
      * @covers ::get_null_provider_reason
-     * @covers ::<!public>
      */
     public function test_get_null_provider_reason() {
         $manager = new \core_privacy\manager();
@@ -277,7 +269,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test that manager::plugintype_class_callback() can be executed.
      *
      * @covers ::plugintype_class_callback
-     * @covers ::<!public>
      */
     public function test_plugintype_class_callback() {
         \core_privacy\manager::plugintype_class_callback('doesnotexist', 'unusable', 'foo', ['bar']);
@@ -287,7 +278,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test that manager::component_class_callback() can be executed.
      *
      * @covers ::component_class_callback
-     * @covers ::<!public>
      */
     public function test_component_class_callback() {
         \core_privacy\manager::component_class_callback('foo_bar', 'unusable', 'foo', ['bar']);
@@ -300,7 +290,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * @param   string  $component
      * @param   bool    $expected
      * @covers ::is_empty_subsystem
-     * @covers ::<!public>
      */
     public function test_is_empty_subsystem($component, $expected) {
         $this->assertEquals($expected, \core_privacy\manager::is_empty_subsystem($component));
@@ -340,7 +329,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test that get_contexts_for_userid() with a failing item.
      *
      * @covers ::get_contexts_for_userid
-     * @covers ::<!public>
      */
     public function test_get_contexts_for_userid_with_failing() {
         // Get a mock manager, in which the core components list is mocked to include all mock plugins.
@@ -378,7 +366,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test that export_user_data() with a failing item.
      *
      * @covers ::export_user_data
-     * @covers ::<!public>
      */
     public function test_export_user_data_with_failing() {
         $user = \core_user::get_user_by_username('admin');
@@ -414,7 +401,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test that delete_data_for_user() with a failing item.
      *
      * @covers ::delete_data_for_user
-     * @covers ::<!public>
      */
     public function test_delete_data_for_user_with_failing() {
         $user = \core_user::get_user_by_username('admin');
@@ -450,7 +436,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test that delete_data_for_all_users_in_context() with a failing item.
      *
      * @covers ::delete_data_for_all_users_in_context
-     * @covers ::<!public>
      */
     public function test_delete_data_for_all_users_in_context_with_failing() {
         $user = \core_user::get_user_by_username('admin');
@@ -481,7 +466,6 @@ class privacy_manager_testcase extends advanced_testcase {
      * Test that get_metadata_for_components() with a failing item.
      *
      * @covers ::get_metadata_for_components
-     * @covers ::<!public>
      */
     public function test_get_metadata_for_components_with_failing() {
         $user = \core_user::get_user_by_username('admin');
index 84824c5..57ada55 100644 (file)
@@ -45,7 +45,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @dataProvider export_data_provider
      * @param   \stdClass  $data Data
      * @covers ::export_data
-     * @covers ::<!public>
      */
     public function test_export_data($data) {
         $context = \context_system::instance();
@@ -71,7 +70,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @dataProvider export_data_provider
      * @param   \stdClass  $data Data
      * @covers ::export_data
-     * @covers ::<!public>
      */
     public function test_export_data_different_context($data) {
         $context = \context_user::instance(\core_user::get_user_by_username('admin')->id);
@@ -95,7 +93,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * Test that exported is saved within the correct directory locations.
      *
      * @covers ::export_data
-     * @covers ::<!public>
      */
     public function test_export_data_writes_to_multiple_context() {
         $subcontext = ['sub', 'context'];
@@ -140,7 +137,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * Test that multiple writes to the same location cause the latest version to be written.
      *
      * @covers ::export_data
-     * @covers ::<!public>
      */
     public function test_export_data_multiple_writes_same_context() {
         $subcontext = ['sub', 'context'];
@@ -197,7 +193,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param   string  $value Value
      * @param   string  $description Description
      * @covers ::export_metadata
-     * @covers ::<!public>
      */
     public function test_export_metadata($key, $value, $description) {
         $context = \context_system::instance();
@@ -223,7 +218,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * Test that metadata can be set additively.
      *
      * @covers ::export_metadata
-     * @covers ::<!public>
      */
     public function test_export_metadata_additive() {
         $context = \context_system::instance();
@@ -260,7 +254,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * Test that metadata can be set additively.
      *
      * @covers ::export_metadata
-     * @covers ::<!public>
      */
     public function test_export_metadata_to_multiple_contexts() {
         $systemcontext = \context_system::instance();
@@ -339,7 +332,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * Exporting a single stored_file should cause that file to be output in the files directory.
      *
      * @covers ::export_area_files
-     * @covers ::<!public>
      */
     public function test_export_area_files() {
         $this->resetAfterTest();
@@ -446,7 +438,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param   string  $content Content
      *
      * @covers ::export_file
-     * @covers ::<!public>
      */
     public function test_export_file($filearea, $itemid, $filepath, $filename, $content) {
         $this->resetAfterTest();
@@ -544,7 +535,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param   string      $value Value
      * @param   string      $desc Description
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_user_preference_context_user($component, $key, $value, $desc) {
         $admin = \core_user::get_user_by_username('admin');
@@ -578,7 +568,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param   string      $value Value
      * @param   string      $desc Description
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_user_preference_context_coursecat($component, $key, $value, $desc) {
         global $DB;
@@ -613,7 +602,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param   string      $value Value
      * @param   string      $desc Description
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_user_preference_context_course($component, $key, $value, $desc) {
         global $DB;
@@ -649,7 +637,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param   string      $value Value
      * @param   string      $desc Description
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_user_preference_context_module($component, $key, $value, $desc) {
         global $DB;
@@ -686,7 +673,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param   string      $value Value
      * @param   string      $desc Description
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_user_preference_context_block($component, $key, $value, $desc) {
         global $DB;
@@ -718,7 +704,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * files.
      *
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_user_preference_context_block_multiple_instances() {
         $this->resetAfterTest();
@@ -781,7 +766,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param   string      $desc Description
      *
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_user_preference_context_system($component, $key, $value, $desc) {
         $context = \context_system::instance();
@@ -806,7 +790,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * User preferences can be exported against the system.
      *
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_multiple_user_preference_context_system() {
         $context = \context_system::instance();
@@ -841,7 +824,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * User preferences can be exported against the system.
      *
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_user_preference_replace() {
         $context = \context_system::instance();
@@ -905,7 +887,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @dataProvider unescaped_unicode_export_provider
      * @param string $text
      * @covers ::export_data
-     * @covers ::<!public>
      */
     public function test_export_data_unescaped_unicode($text) {
         $context = \context_system::instance();
@@ -933,7 +914,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @dataProvider unescaped_unicode_export_provider
      * @param string $text
      * @covers ::export_metadata
-     * @covers ::<!public>
      */
     public function test_export_metadata_unescaped_unicode($text) {
         $context = \context_system::instance();
@@ -962,7 +942,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @dataProvider unescaped_unicode_export_provider
      * @param string $text
      * @covers ::export_related_data
-     * @covers ::<!public>
      */
     public function test_export_related_data_unescaped_unicode($text) {
         $context = \context_system::instance();
@@ -990,7 +969,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @dataProvider unescaped_unicode_export_provider
      * @param string $text
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_user_preference_unescaped_unicode($text) {
         $context = \context_system::instance();
@@ -1033,7 +1011,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param string $text
      *
      * @covers ::export_data
-     * @covers ::<!public>
      */
     public function test_export_data_long_filename($longtext, $expected, $text) {
         $context = \context_system::instance();
@@ -1066,7 +1043,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param string $text
      *
      * @covers ::export_related_data
-     * @covers ::<!public>
      */
     public function test_export_related_data_long_filename($longtext, $expected, $text) {
         $context = \context_system::instance();
@@ -1246,7 +1222,6 @@ class moodle_content_writer_test extends advanced_testcase {
      * @param string $input Raw text as stored in the database.
      * @param string $expectedoutput Expected output of URL rewriting.
      * @covers ::rewrite_pluginfile_urls
-     * @covers ::<!public>
      */
     public function test_rewrite_pluginfile_urls($filearea, $itemid, $input, $expectedoutput) {
 
index d37c462..be8bb46 100644 (file)
@@ -53,7 +53,6 @@ class writer_test extends advanced_testcase {
      * Test that calling with_context multiple times will return the same write instance.
      *
      * @covers ::with_context
-     * @covers ::<!public>
      */
     public function test_with_context() {
         $writer = writer::with_context(\context_system::instance());
@@ -65,7 +64,6 @@ class writer_test extends advanced_testcase {
      * Test that calling with_context multiple times will return the same write instance.
      *
      * @covers ::with_context
-     * @covers ::<!public>
      */
     public function test_with_context_different_context_same_instance() {
         $writer = writer::with_context(\context_system::instance());
@@ -77,7 +75,6 @@ class writer_test extends advanced_testcase {
      * Test that calling writer::reset() causes a new copy of the writer to be returned.
      *
      * @covers ::reset
-     * @covers ::<!public>
      */
     public function test_reset() {
         $writer = writer::with_context(\context_system::instance());
@@ -90,7 +87,6 @@ class writer_test extends advanced_testcase {
      * Test that the export_user_preference calls the writer against the system context.
      *
      * @covers ::export_user_preference
-     * @covers ::<!public>
      */
     public function test_export_user_preference_sets_system_context() {
         $writer = writer::with_context(\context_user::instance(\core_user::get_user_by_username('admin')->id));
index 1867cb3..1133f7b 100644 (file)
@@ -40,7 +40,7 @@ $string['generalsettings'] = 'General settings';
 $string['nobootswatch'] = 'None';
 $string['pluginname'] = 'Boost';
 $string['presetfiles'] = 'Additional theme preset files';
-$string['presetfiles_desc'] = 'Preset files can be used to dramatically alter the appearance of the theme. See <a href="https://docs.moodle.org/dev/Boost_Presets">Boost presets</a> for information on creating and sharing your own preset files, and see the <a href="https://moodle.net/boost">Presets repository</a> for presets that others have shared.';
+$string['presetfiles_desc'] = 'Preset files can be used to dramatically alter the appearance of the theme. See <a href="https://docs.moodle.org/dev/Boost_Presets">Boost presets</a> for information on creating and sharing your own preset files, and see the <a href="https://archive.moodle.net/boost">Presets repository</a> for presets that others have shared.';
 $string['preset'] = 'Theme preset';
 $string['preset_desc'] = 'Pick a preset to broadly change the look of the theme.';
 $string['privacy:metadata'] = 'The Boost theme does not store any personal data about any user.';
index 9dfd1d0..e6f2da4 100644 (file)
@@ -32,7 +32,7 @@ $string['navbardark'] = 'Use a dark style navbar';
 $string['navbardarkdesc'] = 'Swaps text and background colours for the navbar at the top of the page between dark and light.';
 $string['pluginname'] = 'Classic';
 $string['presetfiles'] = 'Additional theme preset files';
-$string['presetfiles_desc'] = 'Preset files can be used to dramatically alter the appearance of the theme. See <a href=https://docs.moodle.org/dev/Boost_Presets>Boost presets</a> for information on creating and sharing your own preset files, and see the <a href=https://moodle.net/boost>Presets repository</a> for presets that others have shared.';
+$string['presetfiles_desc'] = 'Preset files can be used to dramatically alter the appearance of the theme. See <a href="https://docs.moodle.org/dev/Boost_Presets">Boost presets</a> for information on creating and sharing your own preset files, and see the <a href="https://archive.moodle.net/boost">Presets repository</a> for presets that others have shared.';
 $string['preset'] = 'Theme preset';
 $string['preset_desc'] = 'Pick a preset to broadly change the look of the theme.';
 $string['region-side-post'] = 'Right';
index 4caf05b..078289b 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2019100800.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2019100900.00;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.