Merge branch 'MDL-67196' of https://github.com/stronk7/moodle
authorSara Arjona <sara@moodle.com>
Sat, 9 Nov 2019 19:06:11 +0000 (20:06 +0100)
committerSara Arjona <sara@moodle.com>
Sat, 9 Nov 2019 19:06:11 +0000 (20:06 +0100)
25 files changed:
blocks/classes/external.php
blocks/tests/externallib_test.php
filter/displayh5p/lang/en/filter_displayh5p.php
h5p/classes/external.php
h5p/classes/framework.php
h5p/libraries.php
h5p/templates/h5pdiv.mustache
h5p/templates/h5pembed.mustache
h5p/templates/h5perror.mustache
h5p/templates/h5plibraries.mustache [new file with mode: 0644]
h5p/templates/h5presize.mustache
h5p/tests/behat/h5p_libraries.feature [new file with mode: 0644]
h5p/tests/external_test.php
h5p/tests/fixtures/essay.zip [new file with mode: 0644]
h5p/tests/fixtures/filltheblanks.h5p [new file with mode: 0644]
h5p/tests/framework_test.php
h5p/tests/generator_test.php
h5p/tests/h5p_file_storage_test.php
lang/en/admin.php
lang/en/h5p.php
lib/classes/plugin_manager.php
lib/editor/atto/plugins/h5p/lang/en/atto_h5p.php
lib/editor/atto/plugins/h5p/tests/behat/h5p.feature
mod/forum/lang/en/forum.php
mod/forum/report/summary/classes/summary_table.php

index a22cab2..e9f09ac 100644 (file)
@@ -71,7 +71,7 @@ class core_block_external extends external_api {
                     new external_single_structure(
                         array(
                             'name' => new external_value(PARAM_RAW, 'Name.'),
-                            'value' => new external_value(PARAM_RAW, 'Value.'),
+                            'value' => new external_value(PARAM_RAW, 'JSON encoded representation of the config value.'),
                             'type' => new external_value(PARAM_ALPHA, 'Type (instance or plugin).'),
                         )
                     ),
@@ -125,7 +125,7 @@ class core_block_external extends external_api {
                     foreach ((array) $data as $name => $value) {
                         $block['configs'][] = [
                             'name' => $name,
-                            'value' => $value,
+                            'value' => json_encode($value), // Always JSON encode, we may receive non-scalar values.
                             'type' => $type,
                         ];
                     }
index 6b894b9..bd815e6 100644 (file)
@@ -177,6 +177,9 @@ class core_block_externallib_testcase extends externallib_advanced_testcase {
         $blocks = $page->blocks->get_blocks_for_region($page->blocks->get_default_region());
         $block = end($blocks);
         $block = block_instance('html', $block->instance);
+        $nonscalar = [
+            'something' => true,
+        ];
         $configdata = (object) [
             'title' => $title,
             'text' => [
@@ -184,6 +187,7 @@ class core_block_externallib_testcase extends externallib_advanced_testcase {
                 'text' => $body,
                 'format' => $bodyformat,
             ],
+            'nonscalar' => $nonscalar
         ];
         $block->instance_config_save((object) $configdata);
         $filename = 'img.png';
@@ -215,17 +219,20 @@ class core_block_externallib_testcase extends externallib_advanced_testcase {
         $this->assertEquals($newblock, $result['blocks'][0]['name']);
         $configcounts = 0;
         foreach ($result['blocks'][0]['configs'] as $config) {
-            if ($config['type'] = 'plugin' && $config['name'] == 'allowcssclasses' && $config['value'] == 0) {
+            if ($config['type'] = 'plugin' && $config['name'] == 'allowcssclasses' && $config['value'] == json_encode('0')) {
+                $configcounts++;
+            } else if ($config['type'] = 'instance' && $config['name'] == 'text' && $config['value'] == json_encode($body)) {
                 $configcounts++;
-            } else if ($config['type'] = 'instance' && $config['name'] == 'text' && $config['value'] == $body) {
+            } else if ($config['type'] = 'instance' && $config['name'] == 'title' && $config['value'] == json_encode($title)) {
                 $configcounts++;
-            } else if ($config['type'] = 'instance' && $config['name'] == 'title' && $config['value'] == $title) {
+            } else if ($config['type'] = 'instance' && $config['name'] == 'format' && $config['value'] == json_encode('0')) {
                 $configcounts++;
-            } else if ($config['type'] = 'instance' && $config['name'] == 'format' && $config['value'] == 0) {
+            } else if ($config['type'] = 'instance' && $config['name'] == 'nonscalar' &&
+                    $config['value'] == json_encode($nonscalar)) {
                 $configcounts++;
             }
         }
-        $this->assertEquals(4, $configcounts);
+        $this->assertEquals(5, $configcounts);
     }
 
     /**
@@ -261,7 +268,7 @@ class core_block_externallib_testcase extends externallib_advanced_testcase {
             // Check the configuration returned for this default block.
             if ($block['name'] == 'recentlyaccessedcourses') {
                 $this->assertEquals('displaycategories', $block['configs'][0]['name']);
-                $this->assertEquals(0, $block['configs'][0]['value']);
+                $this->assertEquals(json_encode('0'), $block['configs'][0]['value']);
                 $this->assertEquals('plugin', $block['configs'][0]['type']);
             }
         }
index dfb1f12..950324d 100644 (file)
@@ -27,6 +27,8 @@ defined('MOODLE_INTERNAL') || die;
 $string['allowedsourceslist'] = 'Allowed sources';
 $string['allowedsourceslistdesc'] = 'A list of URLs from which users can embed H5P content. If none are specified, all URLs will remain as links and not be displayed as embedded H5P content.
 
-\'[id]\' is a placeholder for the H5P content ID in the external source.';
+\'[id]\' is a placeholder for the H5P content ID in the external source.
+
+The wildcard character \'*\' may be used to specify subdomains. For example, *.example.com will allow embedded H5P content from any subdomain of example.com, but not from the example.com domain.';
 $string['filtername'] = 'Display H5P';
 $string['privacy:metadata'] = 'The display H5P filter does not store any personal data.';
index bf02172..837f628 100644 (file)
@@ -99,9 +99,18 @@ class external extends external_api {
             $messages = $h5pplayer->get_messages();
         } catch (\moodle_exception $e) {
             $messages = (object) [
-                'exception' => $e->getMessage(),
                 'code' => $e->getCode(),
             ];
+            // To mantain the coherence between web coding error and Mobile coding errors.
+            // We need to return the same message error to Mobile.
+            // The 'out_al_local_url called on a non-local URL' error is provided by the \moodle_exception.
+            // We have to translate to h5pinvalidurl which is the same coding error showed in web.
+            if ($e->errorcode === 'codingerror' &&
+                    $e->a === 'out_as_local_url called on a non-local URL') {
+                $messages->exception = get_string('h5pinvalidurl', 'core_h5p');
+            } else {
+                $messages->exception = $e->getMessage();
+            }
         }
 
         if (empty($messages->error) && empty($messages->exception)) {
index e5293cf..3c63966 100644 (file)
@@ -510,8 +510,8 @@ class framework implements \H5PFrameworkInterface {
         global $DB;
 
         $results = $DB->get_records('h5p_libraries', [], 'title ASC, majorversion ASC, minorversion ASC',
-            'machinename AS machine_name, majorversion AS major_version, minorversion AS minor_version,
-            patchversion AS patch_version');
+            'id, machinename AS machine_name, majorversion AS major_version, minorversion AS minor_version,
+            patchversion AS patch_version, runnable, title');
 
         $libraries = array();
         foreach ($results as $library) {
index ad9c6e2..66b4e58 100644 (file)
@@ -43,6 +43,7 @@ echo $OUTPUT->heading($pagetitle);
 echo $OUTPUT->box(get_string('librariesmanagerdescription', 'core_h5p'));
 
 $form = new \core_h5p\form\uploadlibraries_form();
+$h5pfactory = new \core_h5p\factory();
 if ($data = $form->get_data()) {
     require_sesskey();
 
@@ -54,7 +55,6 @@ if ($data = $form->get_data()) {
     $file = reset($files);
 
     // Validate and save the H5P package.
-    $h5pfactory = new \core_h5p\factory();
     // Because we are passing skipcontent = true to save_h5p function, the returning value is false in an error
     // is encountered, null when successfully saving the package without creating the content.
     if (\core_h5p\helper::save_h5p($h5pfactory, $file, new stdClass(), false, true) === false) {
@@ -64,4 +64,19 @@ if ($data = $form->get_data()) {
     }
 }
 $form->display();
+
+// Load installed Libraries.
+$framework = $h5pfactory->get_framework();
+$libraries = $framework->loadLibraries();
+$installed = [];
+foreach ($libraries as $libraryname => $versions) {
+    foreach ($versions as $version) {
+        $installed[] = $version;
+    }
+}
+
+if (count($installed)) {
+    echo $OUTPUT->render_from_template('core_h5p/h5plibraries', (object)['contenttypes' => $installed]);
+}
+
 echo $OUTPUT->footer();
index 2e914d4..0f95bfc 100644 (file)
@@ -15,7 +15,7 @@
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
 {{!
-    @template core_message/h5pdiv
+    @template core_h5p/h5pdiv
 
     This template will render an div for h5p content.
 
index 7f36477..9f26126 100644 (file)
@@ -15,7 +15,7 @@
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
 {{!
-    @template core_message/h5pembed
+    @template core_h5p/h5pembed
 
     This template will render the embed code shown in the H5P content embed popup.
 
index 76107c9..d455985 100644 (file)
@@ -15,7 +15,7 @@
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
 {{!
-    @template core_message/h5perror
+    @template core_h5p/h5perror
 
     This template will render the embed code shown in the H5P content embed popup.
 
diff --git a/h5p/templates/h5plibraries.mustache b/h5p/templates/h5plibraries.mustache
new file mode 100644 (file)
index 0000000..3ac8ee5
--- /dev/null
@@ -0,0 +1,111 @@
+{{!
+    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/>.
+}}
+{{!
+    @template core_h5p/h5plibraries
+
+    Example context (json):
+    {
+        "contenttypes": [
+            {
+                "title": "Accordion",
+                "major_version": 1,
+                "minor_version:": 0,
+                "patch_version:": 0,
+                "runnable": 1
+            },
+            {
+                "title": "Collage",
+                "major_version": 0,
+                "minor_version:": 3,
+                "patch_version:": 1,
+                "runnable": 1
+            },
+            {
+                "title": "FontAwesome",
+                "major_version": 4,
+                "minor_version:": 5,
+                "patch_version:": 0,
+                "runnable": 0
+            }
+        ]
+    }
+
+}}
+<h3 class="mt-3">{{#str}} installedh5p, h5p {{/str}}</h3>
+
+<ul class="nav nav-tabs mb-3" id="myTab" role="tablist">
+    <li class="nav-item">
+        <a class="nav-link active" id="contenttypes-tab" data-toggle="tab" href="#contenttypes" role="tab" aria-controls="contenttypes" aria-selected="true">
+            {{#str}} installedcontenttypes, h5p {{/str}}
+        </a>
+    </li>
+    <li class="nav-item">
+        <a class="nav-link" id="libraries-tab" data-toggle="tab" href="#libraries" role="tab" aria-controls="libraries" aria-selected="false">
+            {{#str}} installedcontentlibraries, h5p {{/str}}
+        </a>
+    </li>
+</ul>
+<div class="tab-content" id="myTabContent">
+    <div class="tab-pane fade show active" id="contenttypes" role="tabpanel" aria-labelledby="contenttypes-tab">
+        <div class="overview px-3 mb-5">
+            <table class="admintable generaltable" id="h5pcontenttypes">
+                <thead>
+                    <tr>
+                        <th>{{#str}}description, core{{/str}}</th>
+                        <th>{{#str}}version, core{{/str}}</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {{#contenttypes}}
+                        {{#runnable}}
+                        <tr class="">
+                            <td>
+                                {{{ title }}}
+                            </td>
+                            <td>{{{ major_version }}}.{{{ minor_version }}}.{{{ patch_version }}}</td>
+                        </tr>
+                        {{/runnable}}
+                    {{/contenttypes}}
+                </tbody>
+            </table>
+        </div>
+    </div>
+    <div class="tab-pane fade" id="libraries" role="tabpanel" aria-labelledby="libraries-tab">
+        <div class="overview px-3 mb-5">
+            <table class="admintable generaltable" id="h5plibraries">
+                <thead>
+                    <tr>
+                        <th>{{#str}}description, core{{/str}}</th>
+                        <th>{{#str}}version, core{{/str}}</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {{#contenttypes}}
+                        {{^runnable}}
+                        <tr class="">
+                            <td>
+                                {{{ title }}}
+                            </td>
+                            <td>{{{ major_version }}}.{{{ minor_version }}}.{{{ patch_version }}}</td>
+                        </tr>
+                        {{/runnable}}
+                    {{/contenttypes}}
+                </tbody>
+            </table>
+        </div>
+    </div>
+</div>
\ No newline at end of file
index 4400b60..fd58324 100644 (file)
@@ -15,7 +15,7 @@
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
 {{!
-    @template core_message/h5presize
+    @template core_h5p/h5presize
 
     This template will render the resize JS code.
 
diff --git a/h5p/tests/behat/h5p_libraries.feature b/h5p/tests/behat/h5p_libraries.feature
new file mode 100644 (file)
index 0000000..103c057
--- /dev/null
@@ -0,0 +1,46 @@
+@editor @core_h5p @_file_upload
+Feature: Upload and list H5P libraries and content types installed
+
+  @javascript
+  Scenario: No library installed in new installations.
+    Given I log in as "admin"
+    When I navigate to "H5P > Manage H5P content types" in site administration
+    Then I should see "Upload H5P content types"
+    And I should not see "Installed H5P"
+
+  @javascript
+  Scenario: Upload an invalid content type.
+    Given I log in as "admin"
+    And I navigate to "H5P > Manage H5P content types" in site administration
+    When I upload "h5p/tests/fixtures/h5ptest.zip" file to "H5P content type" filemanager
+    And I click on "Upload H5P content types" "button" in the "#fitem_id_submitbutton" "css_element"
+    And I wait until the page is ready
+    Then I should see "Invalid H5P content type"
+    And I should not see "Installed H5P"
+
+  @javascript
+  Scenario: Upload a valid content type.
+    Given I log in as "admin"
+    And I navigate to "H5P > Manage H5P content types" in site administration
+    When I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
+    And I click on "Upload H5P content types" "button" in the "#fitem_id_submitbutton" "css_element"
+    And I wait until the page is ready
+    Then I should see "H5P content types uploaded successfully"
+    And I should see "Installed H5P"
+    And I should see "Installed H5P content types"
+    And I should see "Fill in the Blanks"
+    And I should not see "Essay"
+    And I should see "Installed H5P libraries"
+    And I click on "Installed H5P libraries" "link"
+    And I should see "Question"
+    And I should see "1.4" in the "Question" "table_row"
+    And I should not see "1.3" in the "Question" "table_row"
+    And I upload "h5p/tests/fixtures/essay.zip" file to "H5P content type" filemanager
+    And I click on "Upload H5P content types" "button" in the "#fitem_id_submitbutton" "css_element"
+    And I wait until the page is ready
+#   Existing content types are kept and new added
+    And I should see "Fill in the Blanks"
+    And I should see "Essay"
+    And I click on "Installed H5P libraries" "link"
+    And I should see "1.3" in the "Question" "table_row"
+    And I should see "1.4"
index 70f613a..9d02199 100644 (file)
@@ -124,6 +124,17 @@ class core_h5p_external_testcase extends externallib_advanced_testcase {
         // Check the warnings to be sure that h5pinvalidurl is the message by moodle_exception.
         $this->assertEquals($urlempty, $result['warnings'][0]['item']);
         $this->assertEquals(get_string('h5pinvalidurl', 'core_h5p'), $result['warnings'][0]['message']);
+
+        // Create a non-local URL.
+        $urlnonlocal = 'http://www.google.com/pluginfile.php/644/block_html/content/arithmetic-quiz-1-1.h5p';
+        $result = external::get_trusted_h5p_file($urlnonlocal, 0, 0, 0, 0);
+        $result = external_api::clean_returnvalue(external::get_trusted_h5p_file_returns(), $result);
+        // Expected result: Just 1 record on warnings and none on files.
+        $this->assertCount(0, $result['files']);
+        $this->assertCount(1, $result['warnings']);
+        // Check the warnings to be sure that h5pinvalidurl is the message by moodle_exception.
+        $this->assertEquals($urlnonlocal, $result['warnings'][0]['item']);
+        $this->assertEquals(get_string('h5pinvalidurl', 'core_h5p'), $result['warnings'][0]['message']);
     }
 
     /**
diff --git a/h5p/tests/fixtures/essay.zip b/h5p/tests/fixtures/essay.zip
new file mode 100644 (file)
index 0000000..59e377c
Binary files /dev/null and b/h5p/tests/fixtures/essay.zip differ
diff --git a/h5p/tests/fixtures/filltheblanks.h5p b/h5p/tests/fixtures/filltheblanks.h5p
new file mode 100644 (file)
index 0000000..45a01d3
Binary files /dev/null and b/h5p/tests/fixtures/filltheblanks.h5p differ
index 555dbba..4042be1 100644 (file)
@@ -34,6 +34,7 @@ defined('MOODLE_INTERNAL') || die();
  * @package    core_h5p
  * @copyright  2019 Mihail Geshoski <mihail@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @runTestsInSeparateProcesses
  */
 class framework_testcase extends \advanced_testcase {
 
@@ -67,8 +68,17 @@ class framework_testcase extends \advanced_testcase {
 
     /**
      * Test the behaviour of fetchExternalData() when the store path is not defined.
+     *
+     * This test is intensive and requires downloading content of an external file,
+     * therefore it might take longer time to execute.
+     * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
      */
     public function test_fetchExternalData_no_path_defined() {
+
+        if (!PHPUNIT_LONGTEST) {
+            $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
+        }
+
         $this->resetAfterTest();
 
         // Provide a valid URL to an external H5P content.
@@ -88,10 +98,18 @@ class framework_testcase extends \advanced_testcase {
 
     /**
      * Test the behaviour of fetchExternalData() when the store path is defined.
+     *
+     * This test is intensive and requires downloading content of an external file,
+     * therefore it might take longer time to execute.
+     * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
      */
     public function test_fetchExternalData_path_defined() {
         global $CFG;
 
+        if (!PHPUNIT_LONGTEST) {
+            $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
+        }
+
         $this->resetAfterTest();
 
         // Provide a valid URL to an external H5P content.
@@ -112,8 +130,18 @@ class framework_testcase extends \advanced_testcase {
     /**
      * Test the behaviour of fetchExternalData() when the URL is pointing to an external file that is
      * not an h5p content.
+     *
+     * This test is intensive and requires downloading content of an external file,
+     * therefore it might take longer time to execute.
+     * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
      */
     public function test_fetchExternalData_url_not_h5p() {
+
+        if (!PHPUNIT_LONGTEST) {
+            // This test is intensive and requires downloading the content of an external file.
+            $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
+        }
+
         $this->resetAfterTest();
 
         // Provide an URL to an external file that is not an H5P content file.
index 0ad41d4..2ddd341 100644 (file)
@@ -25,6 +25,8 @@
 
 namespace core_h5p;
 
+use core_h5p\autoloader;
+
 defined('MOODLE_INTERNAL') || die();
 
 /**
@@ -34,9 +36,19 @@ defined('MOODLE_INTERNAL') || die();
 * @category   test
 * @copyright  2019 Mihail Geshoski <mihail@moodle.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+* @runTestsInSeparateProcesses
 */
 class generator_testcase extends \advanced_testcase {
 
+    /**
+     * Tests set up.
+     */
+    protected function setUp() {
+        parent::setUp();
+
+        autoloader::register();
+    }
+
     /**
      * Test the returned data of generate_h5p_data() when the method is called without requesting
      * creation of library files.
index 832b4f0..17354a1 100644 (file)
@@ -38,6 +38,7 @@ defined('MOODLE_INTERNAL') || die();
  * @package    core_h5p
  * @copyright  2019 Victor Deniz <victor@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @runTestsInSeparateProcesses
  */
 class h5p_file_storage_testcase extends \advanced_testcase {
 
@@ -462,7 +463,7 @@ class h5p_file_storage_testcase extends \advanced_testcase {
         ];
         $filestorage = new file_storage();
         $fs->create_file_from_string($filerecord, 'test string info');
-        $expectedfilepath = DIRECTORY_SEPARATOR . file_storage::LIBRARY_FILEAREA . $filepath . 'upgrade.js';
+        $expectedfilepath = '/' . file_storage::LIBRARY_FILEAREA . $filepath . 'upgrade.js';
         $this->assertEquals($expectedfilepath, $filestorage->getUpgradeScript($machinename, $majorversion, $minorversion));
         $this->assertNull($filestorage->getUpgradeScript($machinename, $majorversion, 7));
     }
@@ -489,9 +490,9 @@ class h5p_file_storage_testcase extends \advanced_testcase {
         foreach ($files as $file) {
             if (!$file->is_directory) {
                 $stream = $ziparchive->get_stream($file->index);
-                $items = explode(DIRECTORY_SEPARATOR, $file->pathname);
+                $items = explode('/', $file->pathname);
                 array_shift($items);
-                $path = implode(DIRECTORY_SEPARATOR, $items);
+                $path = implode('/', $items);
                 $this->h5p_file_storage->saveFileFromZip($this->h5p_tempath, $path, $stream);
                 $filestocheck[] = $path;
             }
index 602cb1a..400e094 100644 (file)
@@ -154,7 +154,7 @@ $string['configallowcohortthemes'] = 'If you enable this, then themes can be set
 $string['configallowcoursethemes'] = 'If you enable this, then courses will be allowed to set their own themes.  Course themes override all other theme choices (site, user, or session themes)';
 $string['configallowedemaildomains'] = 'List email domains that are allowed to be disclosed in the "From" section of outgoing email. The default of "Empty" will use the No-reply address for all outgoing email. The use of wildcards is allowed e.g. *.example.com will allow emails sent from any subdomain of example.com, but not example.com itself. This will require separate entry.';
 $string['configallowemailaddresses'] = 'To restrict new email addresses to particular domains, list them here separated by spaces. All other domains will be rejected. To allow subdomains, add the domain with a preceding \'.\'. To allow a root domain together with its subdomains, add the domain twice - once with a preceding \'.\' and once without e.g. .ourcollege.edu.au ourcollege.edu.au.';
-$string['configallowemojipicker'] = 'The emoji picker enables users to select emojis, such as smilies, to add to messages.';
+$string['configallowemojipicker'] = 'The emoji picker enables users to select emojis, such as smilies, to add to messages and other text areas via an emoji picker button in the Atto toolbar.';
 $string['configallowemojipickerincompatible'] = 'Your current database configuration does not properly support emojis. In order to enable the emoji picker you will need to <a href="https://docs.moodle.org/en/MySQL_full_unicode_support">upgrade your database for full unicode support</a>.';
 $string['configallowguestmymoodle'] = 'If enabled guests can access Dashboard, otherwise guests are redirected to the site front page.';
 $string['configallowobjectembed'] = 'As a default security measure, normal users are not allowed to embed multimedia (like Flash) within texts using explicit EMBED and OBJECT tags in their HTML (although it can still be done safely using the mediaplugins filter).  If you wish to allow these tags then enable this option.';
index 221c3c4..e309933 100644 (file)
@@ -32,7 +32,7 @@ $string['addednewlibrary'] = 'Added {$a->%new} new H5P library.';
 $string['additionallicenseinfo'] = 'Any additional information about the license';
 $string['author'] = 'Author';
 $string['authorcomments'] = 'Author comments';
-$string['authorcommentsdescription'] = 'Comments for the editor of the content (This text will not be published as a part of copyright info)';
+$string['authorcommentsdescription'] = 'Comments for the editor of the content. (This text will not be published as a part of the copyright info.)';
 $string['authorname'] = 'Author\'s name';
 $string['authorrole'] = 'Author\'s role';
 $string['by'] = 'by';
@@ -49,14 +49,14 @@ $string['changedescription'] = 'Description of change';
 $string['changelog'] = 'Changelog';
 $string['changeplaceholder'] = 'Photo cropped, text changed, etc.';
 $string['close'] = 'Close';
-$string['confirmdialogbody'] = 'Please confirm that you wish to proceed. This action is not reversible.';
+$string['confirmdialogbody'] = 'Please confirm that you wish to proceed. This action cannot be undone.';
 $string['confirmdialogheader'] = 'Confirm action';
 $string['confirmlabel'] = 'Confirm';
-$string['connectionLost'] = 'Connection lost. Results will be stored and sent when you regain connection.';
+$string['connectionLost'] = 'Connection lost. Results will be stored and sent when the connection is reestablished.';
 $string['connectionReestablished'] = 'Connection reestablished.';
 $string['contentCopied'] = 'Content is copied to the clipboard';
 $string['contentchanged'] = 'This content has changed since you last used it.';
-$string['contenttype'] = 'Content Type';
+$string['contenttype'] = 'Content type';
 $string['copyright'] = 'Rights of use';
 $string['copyrightinfo'] = 'Copyright information';
 $string['copyrightstring'] = 'Copyright';
@@ -78,7 +78,7 @@ $string['fileExceedsMaxSize'] = 'One of the files inside the package exceeds the
 $string['fullscreen'] = 'Fullscreen';
 $string['gpl'] = 'General Public License v3';
 $string['h5p'] = 'H5P';
-$string['h5ptitle'] = 'Visit H5P.org to check out more cool content.';
+$string['h5ptitle'] = 'Visit h5p.org to check out more content.';
 $string['h5pfilenotfound'] = 'H5P file not found';
 $string['h5pinvalidurl'] = 'Invalid H5P content URL.';
 $string['h5pprivatefile'] = 'This H5P content can\'t be displayed because you don\'t have access to the .h5p file.';
@@ -86,6 +86,9 @@ $string['h5pmanage'] = 'Manage H5P content types';
 $string['h5ppackage'] = 'H5P content type';
 $string['h5ppackage_help'] = 'An H5P content type is a file with an H5P or ZIP extension containing all libraries required to display the content.';
 $string['hideadvanced'] = 'Hide advanced';
+$string['installedcontentlibraries'] = 'Installed H5P libraries';
+$string['installedcontenttypes'] = 'Installed H5P content types';
+$string['installedh5p'] = 'Installed H5P';
 $string['invalidcontextid'] = 'H5P file not found (invalid contextid)';
 $string['invalidfile'] = 'File "{$a->%filename}" not allowed. Only files with the following extensions are allowed: {$a->%files-allowed}.';
 $string['invalidlanguagefile'] = 'Invalid language file {$a->%file} in library {$a->%library}';
@@ -121,23 +124,23 @@ $string['licenseV1'] = 'Version 1';
 $string['licenseV2'] = 'Version 2';
 $string['licenseV3'] = 'Version 3';
 $string['licensee'] = 'Licensee';
-$string['licenseextras'] = 'License Extras';
-$string['licenseversion'] = 'License Version';
+$string['licenseextras'] = 'License extras';
+$string['licenseversion'] = 'License version';
 $string['missingcontentfolder'] = 'A valid content folder is missing';
-$string['missingcoreversion'] = 'The system was unable to install the {$a->%component} component from the package, it requires a newer version of the H5P plugin. This site is currently running version {$a->%current}, whereas the required version is {$a->%required} or higher. You should consider upgrading and then try again.';
+$string['missingcoreversion'] = 'The system was unable to install the {$a->%component} component from the package, as it requires a newer version of the H5P plugin. This site is currently running version {$a->%current}, whereas the required version is {$a->%required} or higher. Please upgrade and then try again.';
 $string['missingdependency'] = 'Missing dependency {$a->@dep} required by {$a->@lib}.';
 $string['missinglibrary'] = 'Missing required library {$a->@library}';
 $string['missinglibraryfile'] = 'The file "{$a->%file}" is missing from library: "{$a->%name}"';
 $string['missinglibraryjson'] = 'Could not find library.json file with valid json format for library {$a->%name}';
 $string['missinglibraryproperty'] = 'The required property {$a->%property} is missing from {$a->%library}';
-$string['missingmbstring'] = 'The mbstring PHP extension is not loaded. H5P need this to function properly';
-$string['missinguploadpermissions'] = 'Note that the libraries may exist in the file you uploaded, but you\'re not allowed to upload new libraries. Contact the site administrator about this.';
+$string['missingmbstring'] = 'The mbstring PHP extension is not loaded. It is required for H5P to function properly.';
+$string['missinguploadpermissions'] = 'Note that the libraries may exist in the file you uploaded, but you\'re not allowed to upload new libraries. Please contact your administrator.';
 $string['nocopyright'] = 'No copyright information available for this content.';
-$string['noextension'] = 'The file you uploaded is not a valid HTML5 Package (It does not have the .h5p file extension)';
+$string['noextension'] = 'The file you uploaded is not a valid HTML5 Package. (It doesn\'t have the .h5p file extension.)';
 $string['nopermissiontodeploy'] = 'This file can\'t be displayed because it has been uploaded by a user without the required capability to deploy H5P content.';
 $string['nojson'] = 'The main h5p.json file is not valid';
 $string['notrustablefile'] = 'This file can\'t be displayed because it has been uploaded by a user without the capability to update H5P content types.  Please contact your administrator to ask for the content type to be installed.';
-$string['nounzip'] = 'The file you uploaded is not a valid HTML5 Package (We are unable to unzip it)';
+$string['nounzip'] = 'The file you uploaded is not a valid HTML5 Package. (It is not possible to unzip it.)';
 $string['offlineDialogBody'] = 'We were unable to send information about your completion of this task. Please check your internet connection.';
 $string['offlineDialogHeader'] = 'Your connection to the server was lost';
 $string['offlineDialogRetryButtonLabel'] = 'Retry now';
@@ -152,7 +155,7 @@ $string['privacy:metadata'] = 'H5P subsystem does not store any personal data.';
 $string['resizescript'] = 'Include this script on your website if you want dynamic sizing of the embedded content:';
 $string['resubmitScores'] = 'Attempting to submit stored results.';
 $string['reuse'] = 'Reuse';
-$string['reuseContent'] = 'Reuse Content';
+$string['reuseContent'] = 'Reuse content';
 $string['reuseDescription'] = 'Reuse this content.';
 $string['showadvanced'] = 'Show advanced';
 $string['showless'] = 'Show less';
index 2fa5847..33e4a28 100644 (file)
@@ -1687,7 +1687,7 @@ class core_plugin_manager {
                 'equation', 'fontcolor', 'html', 'image', 'indent', 'italic',
                 'link', 'managefiles', 'media', 'noautolink', 'orderedlist',
                 'recordrtc', 'rtl', 'strike', 'subscript', 'superscript', 'table',
-                'title', 'underline', 'undo', 'unorderedlist', 'h5p'
+                'title', 'underline', 'undo', 'unorderedlist', 'h5p', 'emojipicker',
             ),
 
             'assignment' => array(
@@ -1786,6 +1786,10 @@ class core_plugin_manager {
                 'singleactivity', 'social', 'topics', 'weeks'
             ),
 
+            'forumreport' => array(
+                'summary',
+            ),
+
             'gradeexport' => array(
                 'ods', 'txt', 'xls', 'xml'
             ),
index 382ba5f..feefb27 100644 (file)
@@ -27,7 +27,7 @@ $string['copyrightbutton'] = 'Copyright button';
 $string['downloadbutton'] = 'Allow download';
 $string['either'] = 'Either';
 $string['embedbutton'] = 'Embed button';
-$string['enterurl'] = 'URL or Embed code';
+$string['enterurl'] = 'URL or embed code';
 $string['h5p:addembed'] = 'Add embedded H5P';
 $string['h5pfile'] = 'H5P file upload';
 $string['h5poptions'] = 'H5P options';
index 467e74e..c4a506a 100644 (file)
@@ -85,7 +85,7 @@ Feature: Add h5ps to Atto
     And I follow "PageName1"
     When I navigate to "Edit settings" in current page administration
     And I click on "Insert H5P" "button"
-    Then I should not see "URL or Embed code" in the "Insert H5P" "dialogue"
+    Then I should not see "URL or embed code" in the "Insert H5P" "dialogue"
 
   @javascript
   Scenario: No upload h5p capabilities
index 8efd14f..ad90b32 100644 (file)
@@ -285,7 +285,7 @@ $string['forum:allowforcesubscribe'] = 'Allow force subscribe';
 $string['forum:canoverridecutoff'] = 'Post to forums after their cut-off date';
 $string['forum:canoverridediscussionlock'] = 'Reply to locked discussions';
 $string['forum:cantogglefavourite'] = 'Star discussions';
-$string['forum:grade'] = 'Grade other users';
+$string['forum:grade'] = 'Grade forum';
 $string['forumauthorhidden'] = 'Author (hidden)';
 $string['forumblockingalmosttoomanyposts'] = 'You are approaching the posting threshold. You have posted {$a->numposts} times in the last {$a->blockperiod} and the limit is {$a->blockafter} posts.';
 $string['forumbodyhidden'] = 'This post cannot be viewed by you, probably because you have not posted in the discussion, the maximum editing time hasn\'t passed yet, the discussion has not started or the discussion has expired.';
@@ -737,7 +737,7 @@ $string['forumbodydeleted'] = 'The content of this forum post has been removed a
 $string['gradeusers'] = 'Grade users';
 $string['forumgrader'] = 'Forum grader';
 $string['grading'] = 'Grading';
-$string['viewconversation'] = 'View conversation';
+$string['viewconversation'] = 'View discussion';
 
 $string['grade_forum_header'] = 'Whole forum grading';
 $string['grade_forum_title'] = 'Grade';
index 4f13779..7cc4ba5 100644 (file)
@@ -628,6 +628,11 @@ class summary_table extends table_sql {
         $this->build_table();
         $this->close_recordset();
         $this->finish_output();
+
+        // Drop the temp table when necessary.
+        if ($this->logreader) {
+            $this->drop_log_summary_temp_table();
+        }
     }
 
     /**
@@ -764,6 +769,22 @@ class summary_table extends table_sql {
         $dbman->create_temp_table($xmldbtable);
     }
 
+    /**
+     * Drops the temp table.
+     *
+     * This should be called once the processing for the summary table has been done.
+     */
+    protected function drop_log_summary_temp_table(): void {
+        global $DB;
+
+        // Drop the temp table if it exists.
+        $temptable = new \xmldb_table(self::LOG_SUMMARY_TEMP_TABLE);
+        $dbman = $DB->get_manager();
+        if ($dbman->table_exists($temptable)) {
+            $dbman->drop_table($temptable);
+        }
+    }
+
     /**
      * Get the final list of groups to filter by, based on the groups submitted,
      * and those the user has access to.