diff --git a/h5p/classes/core.php b/h5p/classes/core.php index c3a9a884fec..3d806119f23 100644 --- a/h5p/classes/core.php +++ b/h5p/classes/core.php @@ -190,6 +190,13 @@ class core extends \H5PCore { 'minorVersion' => $type->version->minor, 'patchVersion' => $type->version->patch, ]; + // Add example and tutorial to the library, to store this information too. + if (isset($type->example)) { + $library['example'] = $type->example; + } + if (isset($type->tutorial)) { + $library['tutorial'] = $type->tutorial; + } $shoulddownload = true; if ($framework->getLibraryId($type->id, $type->version->major, $type->version->minor)) { @@ -221,6 +228,8 @@ class core extends \H5PCore { * @return int|null Returns the id of the content type library installed, null otherwise. */ public function fetch_content_type(array $library): ?int { + global $DB; + $factory = new factory(); // Download the latest content type from the H5P official repository. @@ -250,6 +259,18 @@ class core extends \H5PCore { $librarykey = static::libraryToString($library); $libraryid = $factory->get_storage()->h5pC->librariesJsonData[$librarykey]["libraryId"]; + // Update example and tutorial (if any of them are defined in $library). + $params = ['id' => $libraryid]; + if (array_key_exists('example', $library)) { + $params['example'] = $library['example']; + } + if (array_key_exists('tutorial', $library)) { + $params['tutorial'] = $library['tutorial']; + } + if (count($params) > 1) { + $DB->update_record('h5p_libraries', $params); + } + return $libraryid; } diff --git a/h5p/classes/editor_ajax.php b/h5p/classes/editor_ajax.php index 6f293d01dc7..43e42480d73 100644 --- a/h5p/classes/editor_ajax.php +++ b/h5p/classes/editor_ajax.php @@ -76,8 +76,23 @@ class editor_ajax implements H5PEditorAjaxInterface { * @return mixed|null Returns results from querying the database */ public function getContentTypeCache($machinename = null) { - // This is to be implemented when the Hub client is used. - return []; + global $DB; + + // Added some extra fields to the result because they are expected by functions calling this. They have been + // taken from method getCachedLibsMap() in h5peditor.class.php. + $sql = "SELECT l.id, l.machinename AS machine_name, l.majorversion AS major_version, + l.minorversion AS minor_version, l.patchversion AS patch_version, l.coremajor AS h5p_major_version, + l.coreminor AS h5p_minor_version, l.title, l.tutorial, l.example, + '' AS summary, '' AS description, '' AS icon, 0 AS created_at, 0 AS updated_at, 0 AS is_recommended, + 0 AS popularity, '' AS screenshots, '' AS license, '' AS owner + FROM {h5p_libraries} l"; + $params = []; + if (!empty($machinename)) { + $sql .= ' WHERE l.machinename = :machine_name'; + $params = ['machine_name' => $machinename]; + } + + return $DB->get_records_sql($sql, $params); } /** diff --git a/h5p/classes/editor_framework.php b/h5p/classes/editor_framework.php index 8f97a36a89e..587b83490f5 100644 --- a/h5p/classes/editor_framework.php +++ b/h5p/classes/editor_framework.php @@ -228,7 +228,7 @@ class editor_framework implements H5peditorStorage { if ($libraries !== null) { // Get details for the specified libraries. $librariesin = []; - $fields = 'title, runnable, metadatasettings'; + $fields = 'title, runnable, metadatasettings, example, tutorial'; foreach ($libraries as $library) { $params = [ @@ -243,11 +243,13 @@ class editor_framework implements H5peditorStorage { $library->title = $details->title; $library->runnable = $details->runnable; $library->metadataSettings = json_decode($details->metadatasettings); + $library->example = $details->example; + $library->tutorial = $details->tutorial; $librariesin[] = $library; } } } else { - $fields = 'id, machinename as name, title, majorversion, minorversion, metadatasettings'; + $fields = 'id, machinename as name, title, majorversion, minorversion, metadatasettings, example, tutorial'; $librariesin = api::get_contenttype_libraries($fields); } diff --git a/h5p/classes/framework.php b/h5p/classes/framework.php index 25d0ad9650d..d4b0d6ad1e1 100644 --- a/h5p/classes/framework.php +++ b/h5p/classes/framework.php @@ -115,7 +115,16 @@ class framework implements \H5PFrameworkInterface { * @param string $url */ public function setLibraryTutorialUrl($libraryname, $url) { - // Tutorial url is currently not being used or stored in libraries. + global $DB; + + $sql = 'UPDATE {h5p_libraries} + SET tutorial = :tutorial + WHERE machinename = :machinename'; + $params = [ + 'tutorial' => $url, + 'machinename' => $libraryname, + ]; + $DB->execute($sql, $params); } /** diff --git a/h5p/tests/editor_ajax_test.php b/h5p/tests/editor_ajax_test.php index c0b67348f8d..13f46c9d861 100644 --- a/h5p/tests/editor_ajax_test.php +++ b/h5p/tests/editor_ajax_test.php @@ -79,6 +79,35 @@ class editor_ajax_testcase extends \advanced_testcase { $this->assertEquals($expectedlibraries, array_keys($actuallibraries)); } + /** + * Test that getContentTypeCache method retrieves the latest library versions that exists locally. + */ + public function test_getContentTypeCache(): void { + $this->resetAfterTest(); + + $h5pgenerator = \testing_util::get_data_generator()->get_plugin_generator('core_h5p'); + + // Create several libraries records. + $lib1 = $h5pgenerator->create_library_record('Library1', 'Lib1', 1, 0, 1, '', null, 'http://tutorial.org', + 'http://example.org'); + $lib2 = $h5pgenerator->create_library_record('Library2', 'Lib2', 2, 0, 1, '', null, 'http://tutorial.org'); + $lib3 = $h5pgenerator->create_library_record('Library3', 'Lib3', 3, 0); + $libs = [$lib1, $lib2, $lib3]; + + $libraries = $this->editorajax->getContentTypeCache(); + $this->assertCount(3, $libraries); + foreach ($libs as $lib) { + $library = $libraries[$lib->id]; + $this->assertEquals($library->id, $lib->id); + $this->assertEquals($library->machine_name, $lib->machinename); + $this->assertEquals($library->major_version, $lib->majorversion); + $this->assertEquals($library->tutorial, $lib->tutorial); + $this->assertEquals($library->example, $lib->example); + $this->assertEquals($library->is_recommended, 0); + $this->assertEquals($library->summary, ''); + } + } + /** * Test that the method getTranslations retrieves the translations of several libraries. * diff --git a/h5p/tests/framework_test.php b/h5p/tests/framework_test.php index cee8266744b..13883c1c40b 100644 --- a/h5p/tests/framework_test.php +++ b/h5p/tests/framework_test.php @@ -174,6 +174,55 @@ class framework_testcase extends \advanced_testcase { $this->assertEmpty($data); } + /** + * Test the behaviour of setLibraryTutorialUrl(). + */ + public function test_setLibraryTutorialUrl() { + global $DB; + + $this->resetAfterTest(); + + $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); + + // Create several libraries records. + $lib1 = $generator->create_library_record('Library1', 'Lib1', 1, 0, 1, '', null, 'http://tutorial1.org', + 'http://example.org'); + $lib2 = $generator->create_library_record('Library2', 'Lib2', 2, 0, 1, '', null, 'http://tutorial2.org'); + $lib3 = $generator->create_library_record('Library3', 'Lib3', 3, 0); + + // Check only lib1 tutorial URL is updated. + $url = 'https://newtutorial.cat'; + $this->framework->setLibraryTutorialUrl($lib1->machinename, $url); + + $libraries = $DB->get_records('h5p_libraries'); + $this->assertEquals($libraries[$lib1->id]->tutorial, $url); + $this->assertNotEquals($libraries[$lib2->id]->tutorial, $url); + + // Check lib1 tutorial URL is set to null. + $this->framework->setLibraryTutorialUrl($lib1->machinename, null); + + $libraries = $DB->get_records('h5p_libraries'); + $this->assertCount(3, $libraries); + $this->assertNull($libraries[$lib1->id]->tutorial); + + // Check no tutorial URL is set if library name doesn't exist. + $this->framework->setLibraryTutorialUrl('Unexisting library', $url); + + $libraries = $DB->get_records('h5p_libraries'); + $this->assertCount(3, $libraries); + $this->assertNull($libraries[$lib1->id]->tutorial); + $this->assertEquals($libraries[$lib2->id]->tutorial, 'http://tutorial2.org'); + $this->assertNull($libraries[$lib3->id]->tutorial); + + // Check tutorial is set as expected when it was null. + $this->framework->setLibraryTutorialUrl($lib3->machinename, $url); + + $libraries = $DB->get_records('h5p_libraries'); + $this->assertEquals($libraries[$lib3->id]->tutorial, $url); + $this->assertNull($libraries[$lib1->id]->tutorial); + $this->assertEquals($libraries[$lib2->id]->tutorial, 'http://tutorial2.org'); + } + /** * Test the behaviour of setErrorMessage(). */ diff --git a/h5p/tests/generator/lib.php b/h5p/tests/generator/lib.php index 72e80870220..78c234be536 100644 --- a/h5p/tests/generator/lib.php +++ b/h5p/tests/generator/lib.php @@ -173,9 +173,10 @@ class core_h5p_generator extends \component_generator_base { */ public function generate_h5p_data(bool $createlibraryfiles = false): stdClass { // Create libraries. - $mainlib = $libraries[] = $this->create_library_record('MainLibrary', 'Main Lib', 1, 0); - $lib1 = $libraries[] = $this->create_library_record('Library1', 'Lib1', 2, 0); - $lib2 = $libraries[] = $this->create_library_record('Library2', 'Lib2', 2, 1); + $mainlib = $libraries[] = $this->create_library_record('MainLibrary', 'Main Lib', 1, 0, 1, '', null, + 'http://tutorial.org', 'http://example.org'); + $lib1 = $libraries[] = $this->create_library_record('Library1', 'Lib1', 2, 0, 1, '', null, null, 'http://example.org'); + $lib2 = $libraries[] = $this->create_library_record('Library2', 'Lib2', 2, 1, 1, '', null, 'http://tutorial.org'); $lib3 = $libraries[] = $this->create_library_record('Library3', 'Lib3', 3, 2); $lib4 = $libraries[] = $this->create_library_record('Library4', 'Lib4', 1, 1); $lib5 = $libraries[] = $this->create_library_record('Library5', 'Lib5', 1, 3); @@ -248,10 +249,13 @@ class core_h5p_generator extends \component_generator_base { * @param int $patchversion The library's patch version * @param string $semantics Json describing the content structure for the library * @param string $addto The plugin configuration data + * @param string $tutorial The tutorial URL + * @param string $examlpe The example URL * @return stdClass An object representing the added library record */ public function create_library_record(string $machinename, string $title, int $majorversion = 1, - int $minorversion = 0, int $patchversion = 1, string $semantics = '', string $addto = null): stdClass { + int $minorversion = 0, int $patchversion = 1, string $semantics = '', string $addto = null, + string $tutorial = null, string $example = null): stdClass { global $DB; $content = array( @@ -266,7 +270,9 @@ class core_h5p_generator extends \component_generator_base { 'preloadedcss' => 'css/example.css', 'droplibrarycss' => '', 'semantics' => $semantics, - 'addto' => $addto + 'addto' => $addto, + 'tutorial' => $tutorial, + 'example' => $example ); $libraryid = $DB->insert_record('h5p_libraries', $content); diff --git a/h5p/tests/generator_test.php b/h5p/tests/generator_test.php index dc266f5f2f8..05be9670cd6 100644 --- a/h5p/tests/generator_test.php +++ b/h5p/tests/generator_test.php @@ -227,7 +227,9 @@ class generator_testcase extends \advanced_testcase { $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); - $data = $generator->create_library_record('Library', 'Lib', 1, 2, 3, 'Semantics example', '/regex11/'); + $data = $generator->create_library_record( + 'Library', 'Lib', 1, 2, 3, 'Semantics example', '/regex11/', 'http://tutorial.org/', 'http://example.org/' + ); unset($data->id); $expected = (object) [ @@ -244,6 +246,8 @@ class generator_testcase extends \advanced_testcase { 'droplibrarycss' => '', 'semantics' => 'Semantics example', 'addto' => '/regex11/', + 'tutorial' => 'http://tutorial.org/', + 'example' => 'http://example.org/', 'coremajor' => null, 'coreminor' => null, 'metadatasettings' => null, diff --git a/h5p/tests/h5p_core_test.php b/h5p/tests/h5p_core_test.php index 8d7f088eb80..d441fdc4c19 100644 --- a/h5p/tests/h5p_core_test.php +++ b/h5p/tests/h5p_core_test.php @@ -68,8 +68,14 @@ class h5p_core_testcase extends \advanced_testcase { // Get info of latest content types versions. $contenttypes = $this->core->get_latest_content_types()->contentTypes; - // We are installing the first content type. + // We are installing the first content type with tutorial and example fields (or the first one if none has them). $librarydata = $contenttypes[0]; + foreach ($contenttypes as $contentype) { + if (isset($contenttype->tutorial) && isset($contenttype->example)) { + $librarydata = $contenttype; + break; + } + } $library = [ 'machineName' => $librarydata->id, @@ -77,6 +83,13 @@ class h5p_core_testcase extends \advanced_testcase { 'minorVersion' => $librarydata->version->minor, 'patchVersion' => $librarydata->version->patch, ]; + // Add example and tutorial to the library. + if (isset($librarydata->example)) { + $library['example'] = $librarydata->example; + } + if (isset($librarydata->tutorial)) { + $library['tutorial'] = $librarydata->tutorial; + } // Verify that the content type is not yet installed. $conditions['machinename'] = $library['machineName']; @@ -92,6 +105,10 @@ class h5p_core_testcase extends \advanced_testcase { $this->assertEquals($librarydata->id, $typeinstalled->machinename); $this->assertEquals($librarydata->coreApiVersionNeeded->major, $typeinstalled->coremajor); $this->assertEquals($librarydata->coreApiVersionNeeded->minor, $typeinstalled->coreminor); + if (isset($librarydata->tutorial)) { + $this->assertEquals($librarydata->tutorial, $typeinstalled->tutorial); + $this->assertEquals($librarydata->example, $typeinstalled->example); + } } /** diff --git a/lib/db/install.xml b/lib/db/install.xml index bcc3e18afce..478146184cc 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -4198,6 +4198,8 @@ + + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index f7665dff8bc..412f94b1be8 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2762,5 +2762,25 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2021052500.20); } + if ($oldversion < 2021052500.24) { + // Define fields tutorial and example to be added to h5p_libraries. + $table = new xmldb_table('h5p_libraries'); + + // Add tutorial field. + $field = new xmldb_field('tutorial', XMLDB_TYPE_TEXT, null, null, null, null, null, 'metadatasettings'); + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Add example field. + $field = new xmldb_field('example', XMLDB_TYPE_TEXT, null, null, null, null, null, 'tutorial'); + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Main savepoint reached. + upgrade_main_savepoint(true, 2021052500.24); + } + return true; } diff --git a/version.php b/version.php index 803ea6b248b..0f7c65054c7 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2021052500.23; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2021052500.24; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. $release = '4.0dev (Build: 20201013)'; // Human-friendly version name