MDL-68448 core_h5p: Add get export information to helper

Create a new method in the helper to use in the player,
in the external WS and in the API. Also, add a
new method in API to help to get export information
by other WS.
This commit is contained in:
cescobedo 2020-05-21 21:12:38 +02:00
parent 71965a8572
commit 14b463c92a
7 changed files with 374 additions and 138 deletions

View File

@ -502,4 +502,43 @@ class api {
return ($h5p) ? $h5p : null;
}
/**
* Return the H5P export information file when the file has been deployed.
* Otherwise, return null if H5P file:
* i) has not been deployed.
* ii) has changed the content.
*
* The information returned will be:
* - filename, filepath, mimetype, filesize, timemodified and fileurl.
*
* @param int $contextid ContextId of the H5P activity.
* @param factory $factory The \core_h5p\factory object.
* @param string $component component
* @param string $filearea file area
* @return array|null Return file info otherwise null.
*/
public static function get_export_info_from_context_id(int $contextid,
factory $factory,
string $component,
string $filearea): ?array {
$core = $factory->get_core();
$fs = get_file_storage();
$files = $fs->get_area_files($contextid, $component, $filearea, 0, 'id', false);
$file = reset($files);
if ($h5p = self::get_content_from_pathnamehash($file->get_pathnamehash())) {
if ($h5p->contenthash == $file->get_contenthash()) {
$content = $core->loadContent($h5p->id);
$slug = $content['slug'] ? $content['slug'] . '-' : '';
$filename = "{$slug}{$content['id']}.h5p";
$deployedfile = helper::get_export_info($filename, null, $factory);
return $deployedfile;
}
}
return null;
}
}

View File

@ -429,4 +429,50 @@ class helper {
return $strings;
}
/**
* Get the information related to the H5P export file.
* The information returned will be:
* - filename, filepath, mimetype, filesize, timemodified and fileurl.
*
* @param string $exportfilename The H5P export filename (with slug).
* @param \moodle_url $url The URL of the exported file.
* @param factory $factory The \core_h5p\factory object
* @return array|null The information export file otherwise null.
*/
public static function get_export_info(string $exportfilename, \moodle_url $url = null, ?factory $factory = null): ?array {
if (!$factory) {
$factory = new factory();
}
$core = $factory->get_core();
// Get export file.
if (!$fileh5p = $core->fs->get_export_file($exportfilename)) {
return null;
}
// Build the export info array.
$file = [];
$file['filename'] = $fileh5p->get_filename();
$file['filepath'] = $fileh5p->get_filepath();
$file['mimetype'] = $fileh5p->get_mimetype();
$file['filesize'] = $fileh5p->get_filesize();
$file['timemodified'] = $fileh5p->get_timemodified();
if (!$url) {
$url = \moodle_url::make_webservice_pluginfile_url(
$fileh5p->get_contextid(),
$fileh5p->get_component(),
$fileh5p->get_filearea(),
'',
'',
$fileh5p->get_filename()
);
}
$file['fileurl'] = $url->out(false);
return $file;
}
}

View File

@ -456,7 +456,7 @@ class player {
}
/**
* Return the export file for Mobile App.
* Return the info export file for Mobile App.
*
* @return array
*/
@ -467,23 +467,8 @@ class player {
$path = $exporturl->out_as_local_url();
$parts = explode('/', $path);
$filename = array_pop($parts);
// Get the the export file.
$systemcontext = \context_system::instance();
$fs = get_file_storage();
$fileh5p = $fs->get_file($systemcontext->id,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA,
0,
'/',
$filename);
// Get the options that the Mobile App needs.
$file = [];
$file['filename'] = $fileh5p->get_filename();
$file['filepath'] = $fileh5p->get_filepath();
$file['mimetype'] = $fileh5p->get_mimetype();
$file['filesize'] = $fileh5p->get_filesize();
$file['timemodified'] = $fileh5p->get_timemodified();
$file['fileurl'] = $exporturl->out(false);
// Get the required info from the export file to be able to get the export file by third apps.
$file = helper::get_export_info($filename, $exporturl);
return $file;
}

View File

@ -451,4 +451,56 @@ class api_testcase extends \advanced_testcase {
api::delete_content_from_pluginfile_url($url->out(), $factory);
$this->assertEquals(0, $DB->count_records('h5p'));
}
/**
* Test the behaviour of get_export_info_from_context_id().
*/
public function test_get_export_info_from_context_id(): void {
global $DB;
$this->setRunTestInSeparateProcess(true);
$this->resetAfterTest();
$factory = new factory();
// Create the H5P data.
$filename = 'find-the-words.h5p';
$syscontext = \context_system::instance();
// Test scenario 1: H5P exists and deployed.
$generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
$fakeexportfile = $generator->create_export_file($filename,
$syscontext->id,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA);
$exportfile = api::get_export_info_from_context_id($syscontext->id,
$factory,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA);
$this->assertEquals($fakeexportfile['filename'], $exportfile['filename']);
$this->assertEquals($fakeexportfile['filepath'], $exportfile['filepath']);
$this->assertEquals($fakeexportfile['filesize'], $exportfile['filesize']);
$this->assertEquals($fakeexportfile['timemodified'], $exportfile['timemodified']);
$this->assertEquals($fakeexportfile['fileurl'], $exportfile['fileurl']);
// Test scenario 2: H5P exist, deployed but the content has changed.
// We need to change the contenthash to simulate the H5P file was changed.
$h5pfile = $DB->get_record('h5p', []);
$h5pfile->contenthash = sha1('testedit');
$DB->update_record('h5p', $h5pfile);
$exportfile = api::get_export_info_from_context_id($syscontext->id,
$factory,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA);
$this->assertNull($exportfile);
// Tests scenario 3: H5P is not deployed.
// We need to delete the H5P record to simulate the H5P was not deployed.
$DB->delete_records('h5p', ['id' => $h5pfile->id]);
$exportfile = api::get_export_info_from_context_id($syscontext->id,
$factory,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA);
$this->assertNull($exportfile);
}
}

View File

@ -55,56 +55,45 @@ class core_h5p_external_testcase extends externallib_advanced_testcase {
* test_get_trusted_h5p_file description
*/
public function test_get_trusted_h5p_file() {
global $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
// This is a valid .H5P file.
$filename = 'find-the-words.h5p';
$path = __DIR__ . '/fixtures/'.$filename;
$syscontext = \context_system::instance();
$filerecord = [
'contextid' => $syscontext->id,
'component' => \core_h5p\file_storage::COMPONENT,
'filearea' => 'unittest',
'itemid' => 0,
'filepath' => '/',
'filename' => $filename,
];
// Load the h5p file into DB.
$fs = get_file_storage();
$file = $fs->create_file_from_pathname($filerecord, $path);
// Create a fake export H5P file with normal pluginfile call.
$generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
$deployedfile = $generator->create_export_file($filename,
$syscontext->id,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA,
$generator::PLUGINFILE);
// Make the URL to pass to the WS.
$url = \moodle_url::make_pluginfile_url(
$syscontext->id,
\core_h5p\file_storage::COMPONENT,
'unittest',
\core_h5p\file_storage::EXPORT_FILEAREA,
0,
'/',
$filename
);
// Call the WS.
$result = external::get_trusted_h5p_file($url->out(), 0, 0, 0, 0);
$result = external::get_trusted_h5p_file($url->out(false), 0, 0, 0, 0);
$result = external_api::clean_returnvalue(external::get_trusted_h5p_file_returns(), $result);
// Expected result: Just 1 record on files and none on warnings.
$this->assertCount(1, $result['files']);
$this->assertCount(0, $result['warnings']);
// Get the export file in the DB to compare with the ws's results.
$fileh5p = $this->get_export_file($filename, $file->get_pathnamehash());
$fileh5purl = \moodle_url::make_pluginfile_url(
$syscontext->id,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA,
'',
'',
$fileh5p->get_filename()
);
$this->assertEquals($fileh5p->get_filepath(), $result['files'][0]['filepath']);
$this->assertEquals($fileh5p->get_mimetype(), $result['files'][0]['mimetype']);
$this->assertEquals($fileh5p->get_filesize(), $result['files'][0]['filesize']);
$this->assertEquals($fileh5p->get_timemodified(), $result['files'][0]['timemodified']);
$this->assertEquals($fileh5p->get_filename(), $result['files'][0]['filename']);
$this->assertEquals($fileh5purl->out(), $result['files'][0]['fileurl']);
// Check info export file to compare with the ws's results.
$this->assertEquals($deployedfile['filepath'], $result['files'][0]['filepath']);
$this->assertEquals($deployedfile['mimetype'], $result['files'][0]['mimetype']);
$this->assertEquals($deployedfile['filesize'], $result['files'][0]['filesize']);
$this->assertEquals($deployedfile['timemodified'], $result['files'][0]['timemodified']);
$this->assertEquals($deployedfile['filename'], $result['files'][0]['filename']);
$this->assertEquals($deployedfile['fileurl'], $result['files'][0]['fileurl']);
}
/**
@ -170,56 +159,41 @@ class core_h5p_external_testcase extends externallib_advanced_testcase {
* using webservice/pluginfile.php as url param.
*/
public function test_allow_webservice_pluginfile_in_url_param() {
global $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
// This is a valid .H5P file.
$filename = 'find-the-words.h5p';
$path = __DIR__ . '/fixtures/'.$filename;
$syscontext = \context_system::instance();
$filerecord = [
'contextid' => $syscontext->id,
'component' => \core_h5p\file_storage::COMPONENT,
'filearea' => 'unittest',
'itemid' => 0,
'filepath' => '/',
'filename' => $filename,
];
// Load the h5p file into DB.
$fs = get_file_storage();
$file = $fs->create_file_from_pathname($filerecord, $path);
// Create a fake export H5P file with webservice call.
$generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
$deployedfile = $generator->create_export_file($filename,
$syscontext->id,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA);
// Make the URL to pass to the WS.
$url = \moodle_url::make_webservice_pluginfile_url(
$syscontext->id,
\core_h5p\file_storage::COMPONENT,
'unittest',
\core_h5p\file_storage::EXPORT_FILEAREA,
0,
'/',
$filename
);
// Call the WS.
$result = external::get_trusted_h5p_file($url->out(), 0, 0, 0, 0);
$result = external_api::clean_returnvalue(external::get_trusted_h5p_file_returns(), $result);
// Expected result: Just 1 record on files and none on warnings.
$this->assertCount(1, $result['files']);
$this->assertCount(0, $result['warnings']);
// Get the export file in the DB to compare with the ws's results.
$fileh5p = $this->get_export_file($filename, $file->get_pathnamehash());
$fileh5purl = \moodle_url::make_webservice_pluginfile_url(
$syscontext->id,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA,
'',
'',
$fileh5p->get_filename()
);
$this->assertEquals($fileh5p->get_filepath(), $result['files'][0]['filepath']);
$this->assertEquals($fileh5p->get_mimetype(), $result['files'][0]['mimetype']);
$this->assertEquals($fileh5p->get_filesize(), $result['files'][0]['filesize']);
$this->assertEquals($fileh5p->get_timemodified(), $result['files'][0]['timemodified']);
$this->assertEquals($fileh5p->get_filename(), $result['files'][0]['filename']);
$this->assertEquals($fileh5purl->out(), $result['files'][0]['fileurl']);
// Check info export file to compare with the ws's results.
$this->assertEquals($deployedfile['filepath'], $result['files'][0]['filepath']);
$this->assertEquals($deployedfile['mimetype'], $result['files'][0]['mimetype']);
$this->assertEquals($deployedfile['filesize'], $result['files'][0]['filesize']);
$this->assertEquals($deployedfile['timemodified'], $result['files'][0]['timemodified']);
$this->assertEquals($deployedfile['filename'], $result['files'][0]['filename']);
$this->assertEquals($deployedfile['fileurl'], $result['files'][0]['fileurl']);
}
/**
@ -227,83 +201,46 @@ class core_h5p_external_testcase extends externallib_advanced_testcase {
* using tokenpluginfile.php as url param.
*/
public function test_allow_tokenluginfile_in_url_param() {
global $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
// This is a valid .H5P file.
$filename = 'find-the-words.h5p';
$path = __DIR__ . '/fixtures/'.$filename;
$syscontext = \context_system::instance();
$filerecord = [
'contextid' => $syscontext->id,
'component' => \core_h5p\file_storage::COMPONENT,
'filearea' => 'unittest',
'itemid' => 0,
'filepath' => '/',
'filename' => $filename,
];
// Load the h5p file into DB.
$fs = get_file_storage();
$file = $fs->create_file_from_pathname($filerecord, $path);
// Create a fake export H5P file with tokenfile call.
$generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
$deployedfile = $generator->create_export_file($filename,
$syscontext->id,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA,
$generator::TOKENPLUGINFILE);
// Make the URL to pass to the WS.
$url = \moodle_url::make_pluginfile_url(
$syscontext->id,
\core_h5p\file_storage::COMPONENT,
'unittest',
\core_h5p\file_storage::EXPORT_FILEAREA,
0,
'/',
$filename,
false,
true
);
// Call the WS.
$result = external::get_trusted_h5p_file($url->out(), 0, 0, 0, 0);
$result = external::get_trusted_h5p_file($url->out(false), 0, 0, 0, 0);
$result = external_api::clean_returnvalue(external::get_trusted_h5p_file_returns(), $result);
// Expected result: Just 1 record on files and none on warnings.
$this->assertCount(1, $result['files']);
$this->assertCount(0, $result['warnings']);
// Get the export file in the DB to compare with the ws's results.
$fileh5p = $this->get_export_file($filename, $file->get_pathnamehash());
$fileh5purl = \moodle_url::make_pluginfile_url(
$syscontext->id,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA,
'',
'',
$fileh5p->get_filename(),
false,
true
);
$this->assertEquals($fileh5p->get_filepath(), $result['files'][0]['filepath']);
$this->assertEquals($fileh5p->get_mimetype(), $result['files'][0]['mimetype']);
$this->assertEquals($fileh5p->get_filesize(), $result['files'][0]['filesize']);
$this->assertEquals($fileh5p->get_timemodified(), $result['files'][0]['timemodified']);
$this->assertEquals($fileh5p->get_filename(), $result['files'][0]['filename']);
$this->assertEquals($fileh5purl->out(), $result['files'][0]['fileurl']);
}
/**
* Get the H5P export file.
*
* @param string $filename
* @param string $pathnamehash
* @return stored_file
*/
protected function get_export_file($filename, $pathnamehash) {
global $DB;
// Simulate the filenameexport using slug as H5P does.
$id = $DB->get_field('h5p', 'id', ['pathnamehash' => $pathnamehash]);
$filenameexport = basename($filename, '.h5p').'-'.$id.'-'.$id.'.h5p';
$syscontext = \context_system::instance();
$fs = get_file_storage();
$fileh5p = $fs->get_file($syscontext->id,
\core_h5p\file_storage::COMPONENT,
\core_h5p\file_storage::EXPORT_FILEAREA,
0,
'/',
$filenameexport);
return $fileh5p;
// Check info export file to compare with the ws's results.
$this->assertEquals($deployedfile['filepath'], $result['files'][0]['filepath']);
$this->assertEquals($deployedfile['mimetype'], $result['files'][0]['mimetype']);
$this->assertEquals($deployedfile['filesize'], $result['files'][0]['filesize']);
$this->assertEquals($deployedfile['timemodified'], $result['files'][0]['timemodified']);
$this->assertEquals($deployedfile['filename'], $result['files'][0]['filename']);
$this->assertEquals($deployedfile['fileurl'], $result['files'][0]['fileurl']);
}
}

View File

@ -25,6 +25,8 @@
use core_h5p\local\library\autoloader;
use core_h5p\core;
use core_h5p\player;
use core_h5p\factory;
defined('MOODLE_INTERNAL') || die();
@ -38,6 +40,13 @@ defined('MOODLE_INTERNAL') || die();
*/
class core_h5p_generator extends \component_generator_base {
/** Url pointing to webservice plugin file. */
public const WSPLUGINFILE = 0;
/** Url pointing to token plugin file. */
public const TOKENPLUGINFILE = 1;
/** Url pointing to plugin file. */
public const PLUGINFILE = 2;
/**
* Convenience function to create a file.
*
@ -428,4 +437,121 @@ class core_h5p_generator extends \component_generator_base {
$fs = new file_storage();
return $fs->create_file_from_string($filerecord, $content);
}
/**
* Create a fake export H5P deployed file.
*
* @param string $filename Name of the H5P file to deploy.
* @param int $contextid Context id of the H5P activity.
* @param string $component component.
* @param string $filearea file area.
* @param int $typeurl Type of url to create the export url plugin file.
* @return array return deployed file information.
*/
public function create_export_file(string $filename, int $contextid,
string $component,
string $filearea,
int $typeurl = self::WSPLUGINFILE): array {
global $CFG;
// We need the autoloader for H5P player.
autoloader::register();
$path = $CFG->dirroot.'/h5p/tests/fixtures/'.$filename;
$filerecord = [
'contextid' => $contextid,
'component' => $component,
'filearea' => $filearea,
'itemid' => 0,
'filepath' => '/',
'filename' => $filename,
];
// Load the h5p file into DB.
$fs = get_file_storage();
if (!$fs->get_file($contextid, $component, $filearea, $filerecord['itemid'], $filerecord['filepath'], $filename)) {
$fs->create_file_from_pathname($filerecord, $path);
}
// Make the URL to pass to the player.
if ($typeurl == self::WSPLUGINFILE) {
$url = \moodle_url::make_webservice_pluginfile_url(
$filerecord['contextid'],
$filerecord['component'],
$filerecord['filearea'],
$filerecord['itemid'],
$filerecord['filepath'],
$filerecord['filename']
);
} else {
$includetoken = false;
if ($typeurl == self::TOKENPLUGINFILE) {
$includetoken = true;
}
$url = \moodle_url::make_pluginfile_url(
$filerecord['contextid'],
$filerecord['component'],
$filerecord['filearea'],
$filerecord['itemid'],
$filerecord['filepath'],
$filerecord['filename'],
false,
$includetoken
);
}
$config = new stdClass();
$h5pplayer = new player($url->out(false), $config);
// We need to add assets to page to create the export file.
$h5pplayer->add_assets_to_page();
// Call the method. We need the id of the new H5P content.
$rc = new \ReflectionClass(player::class);
$rcp = $rc->getProperty('h5pid');
$rcp->setAccessible(true);
$h5pid = $rcp->getValue($h5pplayer);
// Get the info export file.
$factory = new factory();
$core = $factory->get_core();
$content = $core->loadContent($h5pid);
$slug = $content['slug'] ? $content['slug'] . '-' : '';
$exportfilename = "{$slug}{$h5pid}.h5p";
$fileh5p = $core->fs->get_export_file($exportfilename);
$deployedfile = [];
$deployedfile['filename'] = $fileh5p->get_filename();
$deployedfile['filepath'] = $fileh5p->get_filepath();
$deployedfile['mimetype'] = $fileh5p->get_mimetype();
$deployedfile['filesize'] = $fileh5p->get_filesize();
$deployedfile['timemodified'] = $fileh5p->get_timemodified();
// Create the url depending the request was made through typeurl.
if ($typeurl == self::WSPLUGINFILE) {
$url = \moodle_url::make_webservice_pluginfile_url(
$fileh5p->get_contextid(),
$fileh5p->get_component(),
$fileh5p->get_filearea(),
'',
'',
$fileh5p->get_filename()
);
} else {
$includetoken = false;
if ($typeurl == self::TOKENPLUGINFILE) {
$includetoken = true;
}
$url = \moodle_url::make_pluginfile_url(
$fileh5p->get_contextid(),
$fileh5p->get_component(),
$fileh5p->get_filearea(),
'',
'',
$fileh5p->get_filename(),
false,
$includetoken
);
}
$deployedfile['fileurl'] = $url->out(false);
return $deployedfile;
}
}

View File

@ -328,4 +328,55 @@ class helper_testcase extends \advanced_testcase {
$this->assertCount(7, $messages->error);
$this->assertCount(2, $messages->info);
}
/**
* Test the behaviour of get_export_info().
*/
public function test_get_export_info(): void {
$this->resetAfterTest();
$filename = 'guess-the-answer.h5p';
$syscontext = \context_system::instance();
$generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
$deployedfile = $generator->create_export_file($filename,
$syscontext->id,
file_storage::COMPONENT,
file_storage::EXPORT_FILEAREA);
// Test scenario 1: Get export information from correct filename.
$helperfile = helper::get_export_info($deployedfile['filename']);
$this->assertEquals($deployedfile['filename'], $helperfile['filename']);
$this->assertEquals($deployedfile['filepath'], $helperfile['filepath']);
$this->assertEquals($deployedfile['filesize'], $helperfile['filesize']);
$this->assertEquals($deployedfile['timemodified'], $helperfile['timemodified']);
$this->assertEquals($deployedfile['fileurl'], $helperfile['fileurl']);
// Test scenario 2: Get export information from correct filename and url.
$url = \moodle_url::make_pluginfile_url(
$syscontext->id,
file_storage::COMPONENT,
'unittest',
0,
'/',
$deployedfile['filename'],
false,
true
);
$helperfile = helper::get_export_info($deployedfile['filename'], $url);
$this->assertEquals($url, $helperfile['fileurl']);
// Test scenario 3: Get export information from correct filename and factory.
$factory = new \core_h5p\factory();
$helperfile = helper::get_export_info($deployedfile['filename'], null, $factory);
$this->assertEquals($deployedfile['filename'], $helperfile['filename']);
$this->assertEquals($deployedfile['filepath'], $helperfile['filepath']);
$this->assertEquals($deployedfile['filesize'], $helperfile['filesize']);
$this->assertEquals($deployedfile['timemodified'], $helperfile['timemodified']);
$this->assertEquals($deployedfile['fileurl'], $helperfile['fileurl']);
// Test scenario 4: Get export information from wrong filename.
$helperfile = helper::get_export_info('nofileexist.h5p', $url);
$this->assertNull($helperfile);
}
}