diff --git a/h5p/classes/framework.php b/h5p/classes/framework.php index 33cba574f3299..10e7c32d77d3c 100644 --- a/h5p/classes/framework.php +++ b/h5p/classes/framework.php @@ -907,6 +907,13 @@ public function updateContent($content, $contentmainid = null) { $params->title = $content['title']; $content['params'] = json_encode($params); } + // Add metadata to 'params'. + if (!empty($content['metadata'])) { + $params = json_decode($content['params']); + $params->metadata = $content['metadata']; + $content['params'] = json_encode($params); + } + $data = [ 'jsoncontent' => $content['params'], 'displayoptions' => $content['disable'], diff --git a/h5p/classes/helper.php b/h5p/classes/helper.php index 72da2fc8799f5..df5789863f1a1 100644 --- a/h5p/classes/helper.php +++ b/h5p/classes/helper.php @@ -66,6 +66,32 @@ public static function save_h5p(factory $factory, \stored_file $file, \stdClass if (!empty($h5pvalidator->h5pC->mainJsonData['title'])) { $content['title'] = $h5pvalidator->h5pC->mainJsonData['title']; } + + // If exists, add the metadata from 'h5p.json' to avoid loosing this information. + $data = $h5pvalidator->h5pC->mainJsonData; + if (!empty($data)) { + // The metadata fields are defined in 'joubel/core/h5p-metadata.class.php'. + $metadatafields = [ + 'title', + 'a11yTitle', + 'changes', + 'authors', + 'source', + 'license', + 'licenseVersion', + 'licenseExtras', + 'authorComments', + 'yearFrom', + 'yearTo', + 'defaultLanguage', + ]; + $content['metadata'] = array_reduce($metadatafields, function ($array, $field) use ($data) { + if (array_key_exists($field, $data)) { + $array[$field] = $data[$field]; + } + return $array; + }, []); + } $h5pstorage->savePackage($content, null, $skipcontent, $options); return $h5pstorage->contentId; diff --git a/h5p/tests/fixtures/guess-the-answer.h5p b/h5p/tests/fixtures/guess-the-answer.h5p index e33f3cbe6c967..3ca4d1cb6ead6 100644 Binary files a/h5p/tests/fixtures/guess-the-answer.h5p and b/h5p/tests/fixtures/guess-the-answer.h5p differ diff --git a/h5p/tests/framework_test.php b/h5p/tests/framework_test.php index 1dd5e391ebd17..185a3624bcae6 100644 --- a/h5p/tests/framework_test.php +++ b/h5p/tests/framework_test.php @@ -1096,6 +1096,57 @@ public function test_updateContent() { $this->assertEquals($content['disable'], $h5pcontent->displayoptions); } + /** + * Test the behaviour of updateContent() with metadata. + * + * @covers ::updateContent + */ + public function test_updateContent_withmetadata(): void { + global $DB; + + $this->resetAfterTest(); + + /** @var \core_h5p_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); + + // Create a library record. + $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2); + + // Create an h5p content with 'TestLibrary' as it's main library. + $contentid = $generator->create_h5p_record($lib->id); + + $params = ['param2' => 'Test2']; + $metadata = [ + 'license' => 'CC BY', + 'licenseVersion' => '4.0', + 'yearFrom' => 2000, + 'yearTo' => 2023, + 'defaultLanguage' => 'ca', + ]; + $content = [ + 'id' => $contentid, + 'params' => json_encode($params), + 'library' => [ + 'libraryId' => $lib->id, + ], + 'disable' => 8, + 'metadata' => $metadata, + ]; + + // Update the h5p content. + $this->framework->updateContent($content); + + $h5pcontent = $DB->get_record('h5p', ['id' => $contentid]); + + // Make sure the h5p content was properly updated. + $this->assertNotEmpty($h5pcontent); + $this->assertNotEmpty($h5pcontent->pathnamehash); + $this->assertNotEmpty($h5pcontent->contenthash); + $this->assertEquals(json_encode(array_merge($params, ['metadata' => $metadata])), $h5pcontent->jsoncontent); + $this->assertEquals($content['library']['libraryId'], $h5pcontent->mainlibraryid); + $this->assertEquals($content['disable'], $h5pcontent->displayoptions); + } + /** * Test the behaviour of saveLibraryDependencies(). */ diff --git a/h5p/tests/helper_test.php b/h5p/tests/helper_test.php index 2f47bcd53139b..66be51cd03079 100644 --- a/h5p/tests/helper_test.php +++ b/h5p/tests/helper_test.php @@ -200,6 +200,56 @@ public function test_save_h5p_existing_libraries(): void { $this->assertStringContainsString('Hello world!', $h5p->jsoncontent); } + /** + * Test the behaviour of save_h5p() when the H5P file contains metadata. + * + * @runInSeparateProcess + * @covers ::save_h5p + */ + public function test_save_h5p_metadata(): void { + global $DB; + + $this->resetAfterTest(); + $factory = new \core_h5p\factory(); + + // Create a user. + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + + // This is a valid .H5P file. + $path = __DIR__ . '/fixtures/guess-the-answer.h5p'; + $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); + $factory->get_framework()->set_file($file); + + $config = (object)[ + 'frame' => 1, + 'export' => 1, + 'embed' => 0, + 'copyright' => 1, + ]; + // The required libraries exist in the system before saving the .h5p file. + $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); + $lib = $generator->create_library_record('H5P.GuessTheAnswer', 'Guess the Answer', 1, 5); + $generator->create_library_record('H5P.Image', 'Image', 1, 1); + $generator->create_library_record('FontAwesome', 'Font Awesome', 4, 5); + $h5pid = helper::save_h5p($factory, $file, $config); + $this->assertNotEmpty($h5pid); + + // No errors are raised. + $errors = $factory->get_framework()->getMessages('error'); + $this->assertCount(0, $errors); + + // And the content in the .h5p file has been saved as expected. + $h5p = $DB->get_record('h5p', ['id' => $h5pid]); + $this->assertEquals($lib->id, $h5p->mainlibraryid); + $this->assertEquals(helper::get_display_options($factory->get_core(), $config), $h5p->displayoptions); + $this->assertStringContainsString('Which fruit is this?', $h5p->jsoncontent); + // Metadata has been also saved. + $this->assertStringContainsString('This is licence extras information added for testing purposes.', $h5p->jsoncontent); + $this->assertStringContainsString('H5P Author', $h5p->jsoncontent); + $this->assertStringContainsString('Add metadata information', $h5p->jsoncontent); + } + /** * Test the behaviour of save_h5p() when the .h5p file is invalid. * @runInSeparateProcess diff --git a/mod/h5pactivity/tests/behat/add_h5pactivity.feature b/mod/h5pactivity/tests/behat/add_h5pactivity.feature index ca2570a825b61..c4c8bec2d83af 100644 --- a/mod/h5pactivity/tests/behat/add_h5pactivity.feature +++ b/mod/h5pactivity/tests/behat/add_h5pactivity.feature @@ -21,7 +21,7 @@ Feature: Add H5P activity And I am on "Course 1" course homepage with editing mode on @javascript - Scenario: Add a h5pactivity activity to a course + Scenario: Add an h5pactivity to a course Given the following "activity" exists: | activity | h5pactivity | | course | C1 | @@ -38,7 +38,7 @@ Feature: Add H5P activity And I should not see "Embed" @javascript - Scenario: Add a h5pactivity activity with download + Scenario: Add an h5pactivity with download display option Given the following "activity" exists: | activity | h5pactivity | | course | C1 | @@ -53,7 +53,7 @@ Feature: Add H5P activity And I should not see "Embed" @javascript - Scenario: Add a h5pactivity activity with embed + Scenario: Add an h5pactivity with embed display option Given the following "activity" exists: | activity | h5pactivity | | course | C1 | @@ -68,22 +68,31 @@ Feature: Add H5P activity And I should see "Embed" @javascript - Scenario: Add a h5pactivity activity with copyright + Scenario: Add an h5pactivity with copyright display option using a content with copyright Given the following "activity" exists: | activity | h5pactivity | | course | C1 | | name | Awesome H5P package | | displayoptions | 6 | | packagefilepath | h5p/tests/fixtures/guess-the-answer.h5p | + And I change window size to "large" When I am on the "Awesome H5P package" "h5pactivity activity" page Then I switch to "h5p-player" class iframe And I switch to "h5p-iframe" class iframe And "Reuse" "text" should not exist in the ".h5p-actions" "css_element" And I should see "Rights of use" And I should not see "Embed" + And I click on "Rights of use" "button" in the ".h5p-actions" "css_element" + And I should see "Fruits" + And I should see "Attribution (CC BY) 4.0 International (CC BY 4.0)" + And I should see "H5P Author" + And I should see "https://h5p.org (Originator)" + And I should see "2000-2023" + And I should see "This is licence extras information added for testing purposes." + And I should see "Add metadata information, Another user, 01-11-23" @javascript - Scenario: Add a h5pactivity activity with copyright in a content without copyright + Scenario: Add an h5pactivity with copyright display option using a content without copyright Given the following "activity" exists: | activity | h5pactivity | | course | C1 | @@ -98,7 +107,7 @@ Feature: Add H5P activity And I should not see "Embed" @javascript - Scenario: Add a h5pactivity activity to a course with all display options enabled + Scenario: Add an h5pactivity with all display options enabled Given the following "activity" exists: | activity | h5pactivity | | course | C1 |