Merge branch 'MDL-67146-master-enfix-2' of git://github.com/mudrd8mz/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Sat, 9 Nov 2019 15:11:39 +0000 (16:11 +0100)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Sat, 9 Nov 2019 15:11:39 +0000 (16:11 +0100)
16 files changed:
blocks/classes/external.php
blocks/tests/externallib_test.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]
lang/en/h5p.php
lib/classes/plugin_manager.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 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 016016d..e309933 100644 (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}';
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'
             ),