mirror of
https://github.com/moodle/moodle.git
synced 2025-08-04 16:36:37 +02:00
MDL-69331 core_contentbank: Hide disabled H5P content-types
If a H5P content-type is disabled: - The content bank won't display existing contents having it as a main library. - The content bank won't allow to create new contents using it.
This commit is contained in:
parent
73a7133ef8
commit
8a81d74244
18 changed files with 565 additions and 87 deletions
|
@ -185,16 +185,20 @@ class api {
|
|||
*
|
||||
* @param string $url H5P pluginfile URL.
|
||||
* @param bool $preventredirect Set to true in scripts that can not redirect (CLI, RSS feeds, etc.), throws exceptions
|
||||
* @param bool $skipcapcheck Whether capabilities should be checked or not to get the pluginfile URL because sometimes they
|
||||
* might be controlled before calling this method.
|
||||
*
|
||||
* @return array of [file, stdClass|false]:
|
||||
* - file local file for this $url.
|
||||
* - stdClass is an H5P object or false if there isn't any H5P with this URL.
|
||||
*/
|
||||
public static function get_content_from_pluginfile_url(string $url, bool $preventredirect = true): array {
|
||||
public static function get_content_from_pluginfile_url(string $url, bool $preventredirect = true,
|
||||
bool $skipcapcheck = false): array {
|
||||
|
||||
global $DB;
|
||||
|
||||
// Deconstruct the URL and get the pathname associated.
|
||||
if (self::can_access_pluginfile_hash($url, $preventredirect)) {
|
||||
if ($skipcapcheck || self::can_access_pluginfile_hash($url, $preventredirect)) {
|
||||
$pathnamehash = self::get_pluginfile_hash($url);
|
||||
}
|
||||
|
||||
|
@ -223,17 +227,19 @@ class api {
|
|||
* @param factory $factory The \core_h5p\factory object
|
||||
* @param stdClass $messages The error, exception and info messages, raised while preparing and running an H5P content.
|
||||
* @param bool $preventredirect Set to true in scripts that can not redirect (CLI, RSS feeds, etc.), throws exceptions
|
||||
* @param bool $skipcapcheck Whether capabilities should be checked or not to get the pluginfile URL because sometimes they
|
||||
* might be controlled before calling this method.
|
||||
*
|
||||
* @return array of [file, h5pid]:
|
||||
* - file local file for this $url.
|
||||
* - h5pid is the H5P identifier or false if there isn't any H5P with this URL.
|
||||
*/
|
||||
public static function create_content_from_pluginfile_url(string $url, \stdClass $config, factory $factory,
|
||||
\stdClass &$messages, bool $preventredirect = true): array {
|
||||
\stdClass &$messages, bool $preventredirect = true, bool $skipcapcheck = false): array {
|
||||
global $USER;
|
||||
|
||||
$core = $factory->get_core();
|
||||
list($file, $h5p) = self::get_content_from_pluginfile_url($url, $preventredirect);
|
||||
list($file, $h5p) = self::get_content_from_pluginfile_url($url, $preventredirect, $skipcapcheck);
|
||||
|
||||
if (!$file) {
|
||||
$core->h5pF->setErrorMessage(get_string('h5pfilenotfound', 'core_h5p'));
|
||||
|
@ -657,4 +663,60 @@ class api {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an H5P package is valid or not.
|
||||
*
|
||||
* @param \stored_file $file The file with the H5P content.
|
||||
* @param bool $onlyupdatelibs Whether new libraries can be installed or only the existing ones can be updated
|
||||
* @param bool $skipcontent Should the content be skipped (so only the libraries will be saved)?
|
||||
* @param factory|null $factory The \core_h5p\factory object
|
||||
* @param bool $deletefiletree Should the temporary files be deleted before returning?
|
||||
* @return bool True if the H5P file is valid (expected format, valid libraries...); false otherwise.
|
||||
*/
|
||||
public static function is_valid_package(\stored_file $file, bool $onlyupdatelibs, bool $skipcontent = false,
|
||||
?factory $factory = null, bool $deletefiletree = true): bool {
|
||||
|
||||
// This may take a long time.
|
||||
\core_php_time_limit::raise();
|
||||
|
||||
$isvalid = false;
|
||||
|
||||
if (empty($factory)) {
|
||||
$factory = new factory();
|
||||
}
|
||||
$core = $factory->get_core();
|
||||
$h5pvalidator = $factory->get_validator();
|
||||
|
||||
// Set the H5P file path.
|
||||
$core->h5pF->set_file($file);
|
||||
$path = $core->fs->getTmpPath();
|
||||
$core->h5pF->getUploadedH5pFolderPath($path);
|
||||
// Add manually the extension to the file to avoid the validation fails.
|
||||
$path .= '.h5p';
|
||||
$core->h5pF->getUploadedH5pPath($path);
|
||||
// Copy the .h5p file to the temporary folder.
|
||||
$file->copy_content_to($path);
|
||||
|
||||
if ($h5pvalidator->isValidPackage($skipcontent, $onlyupdatelibs)) {
|
||||
if ($skipcontent) {
|
||||
$isvalid = true;
|
||||
} else if (!empty($h5pvalidator->h5pC->mainJsonData['mainLibrary'])) {
|
||||
$mainlibrary = (object) ['machinename' => $h5pvalidator->h5pC->mainJsonData['mainLibrary']];
|
||||
if (self::is_library_enabled($mainlibrary)) {
|
||||
$isvalid = true;
|
||||
} else {
|
||||
// If the main library of the package is disabled, the H5P content will be considered invalid.
|
||||
$core->h5pF->setErrorMessage(get_string('mainlibrarydisabled', 'core_h5p'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($deletefiletree) {
|
||||
// Remove temp content folder.
|
||||
\H5PCore::deleteFileTree($path);
|
||||
}
|
||||
|
||||
return $isvalid;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,8 @@ class editor_ajax implements H5PEditorAjaxInterface {
|
|||
global $DB;
|
||||
|
||||
$sql = "SELECT hl2.id, hl2.machinename as machine_name, hl2.title, hl2.majorversion as major_version,
|
||||
hl2.minorversion AS minor_version, hl2.patchversion as patch_version, '' as has_icon, 0 as restricted
|
||||
hl2.minorversion AS minor_version, hl2.patchversion as patch_version, '' as has_icon, 0 as restricted,
|
||||
hl2.enabled
|
||||
FROM {h5p_libraries} hl2
|
||||
LEFT JOIN {h5p_libraries} hl1
|
||||
ON hl1.machinename = hl2.machinename
|
||||
|
|
|
@ -50,30 +50,10 @@ class helper {
|
|||
*/
|
||||
public static function save_h5p(factory $factory, \stored_file $file, \stdClass $config, bool $onlyupdatelibs = false,
|
||||
bool $skipcontent = false) {
|
||||
// This may take a long time.
|
||||
\core_php_time_limit::raise();
|
||||
|
||||
$core = $factory->get_core();
|
||||
$core->h5pF->set_file($file);
|
||||
$path = $core->fs->getTmpPath();
|
||||
$core->h5pF->getUploadedH5pFolderPath($path);
|
||||
// Add manually the extension to the file to avoid the validation fails.
|
||||
$path .= '.h5p';
|
||||
$core->h5pF->getUploadedH5pPath($path);
|
||||
|
||||
// Copy the .h5p file to the temporary folder.
|
||||
$file->copy_content_to($path);
|
||||
|
||||
// Check if the h5p file is valid before saving it.
|
||||
$h5pvalidator = $factory->get_validator();
|
||||
if ($h5pvalidator->isValidPackage($skipcontent, $onlyupdatelibs)) {
|
||||
// If the main library of the package is disabled, the H5P content won't be saved.
|
||||
$mainlibrary = (object) ['machinename' => $h5pvalidator->h5pC->mainJsonData['mainLibrary']];
|
||||
if (!api::is_library_enabled($mainlibrary)) {
|
||||
$core->h5pF->setErrorMessage(get_string('mainlibrarydisabled', 'core_h5p'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (api::is_valid_package($file, $onlyupdatelibs, $skipcontent, $factory, false)) {
|
||||
$core = $factory->get_core();
|
||||
$h5pvalidator = $factory->get_validator();
|
||||
$h5pstorage = $factory->get_storage();
|
||||
|
||||
$content = [
|
||||
|
@ -90,6 +70,7 @@ class helper {
|
|||
|
||||
return $h5pstorage->contentId;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,8 +105,11 @@ class player {
|
|||
* @param stdClass $config Configuration for H5P buttons.
|
||||
* @param bool $preventredirect Set to true in scripts that can not redirect (CLI, RSS feeds, etc.), throws exceptions
|
||||
* @param string $component optional moodle component to sent xAPI tracking
|
||||
* @param bool $skipcapcheck Whether capabilities should be checked or not to get the pluginfile URL because sometimes they
|
||||
* might be controlled before calling this method.
|
||||
*/
|
||||
public function __construct(string $url, \stdClass $config, bool $preventredirect = true, string $component = '') {
|
||||
public function __construct(string $url, \stdClass $config, bool $preventredirect = true, string $component = '',
|
||||
bool $skipcapcheck = false) {
|
||||
if (empty($url)) {
|
||||
throw new \moodle_exception('h5pinvalidurl', 'core_h5p');
|
||||
}
|
||||
|
@ -128,7 +131,8 @@ class player {
|
|||
$config,
|
||||
$this->factory,
|
||||
$this->messages,
|
||||
$this->preventredirect
|
||||
$this->preventredirect,
|
||||
$skipcapcheck
|
||||
);
|
||||
if ($file) {
|
||||
$this->context = \context::instance_by_id($file->get_contextid());
|
||||
|
|
|
@ -37,7 +37,7 @@ defined('MOODLE_INTERNAL') || die();
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \core_h5p\api
|
||||
*/
|
||||
class api_testcase extends \advanced_testcase {
|
||||
class api_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test the behaviour of delete_library().
|
||||
|
@ -742,4 +742,101 @@ class api_testcase extends \advanced_testcase {
|
|||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the behaviour of is_valid_package().
|
||||
* @runInSeparateProcess
|
||||
*
|
||||
* @covers ::is_valid_package
|
||||
* @dataProvider is_valid_package_provider
|
||||
*
|
||||
* @param string $filename The H5P content to validate.
|
||||
* @param bool $expected Expected result after calling the method.
|
||||
* @param bool $isadmin Whether the user calling the method will be admin or not.
|
||||
* @param bool $onlyupdatelibs Whether new libraries can be installed or only the existing ones can be updated.
|
||||
* @param bool $skipcontent Should the content be skipped (so only the libraries will be saved)?
|
||||
*/
|
||||
public function test_is_valid_package(string $filename, bool $expected, bool $isadmin = false, bool $onlyupdatelibs = false,
|
||||
bool $skipcontent = false): void {
|
||||
global $USER;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
if ($isadmin) {
|
||||
$this->setAdminUser();
|
||||
$user = $USER;
|
||||
} else {
|
||||
// Create a user.
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->setUser($user);
|
||||
}
|
||||
|
||||
// Prepare the file.
|
||||
$path = __DIR__ . $filename;
|
||||
$file = helper::create_fake_stored_file_from_path($path, (int)$user->id);
|
||||
|
||||
// Check if the H5P content is valid or not.
|
||||
$result = api::is_valid_package($file, $onlyupdatelibs, $skipcontent);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_is_valid_package().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function is_valid_package_provider(): array {
|
||||
return [
|
||||
'Valid H5P file (as admin)' => [
|
||||
'filename' => '/fixtures/greeting-card-887.h5p',
|
||||
'expected' => true,
|
||||
'isadmin' => true,
|
||||
],
|
||||
'Valid H5P file (as user) without library update and checking content' => [
|
||||
'filename' => '/fixtures/greeting-card-887.h5p',
|
||||
'expected' => false, // Libraries are missing and user hasn't the right permissions to upload them.
|
||||
'isadmin' => false,
|
||||
'onlyupdatelibs' => false,
|
||||
'skipcontent' => false,
|
||||
],
|
||||
'Valid H5P file (as user) with library update and checking content' => [
|
||||
'filename' => '/fixtures/greeting-card-887.h5p',
|
||||
'expected' => false, // Libraries are missing and user hasn't the right permissions to upload them.
|
||||
'isadmin' => false,
|
||||
'onlyupdatelibs' => true,
|
||||
'skipcontent' => false,
|
||||
],
|
||||
'Valid H5P file (as user) without library update and skipping content' => [
|
||||
'filename' => '/fixtures/greeting-card-887.h5p',
|
||||
'expected' => true, // Content check is skipped so the package will be considered valid.
|
||||
'isadmin' => false,
|
||||
'onlyupdatelibs' => false,
|
||||
'skipcontent' => true,
|
||||
],
|
||||
'Valid H5P file (as user) with library update and skipping content' => [
|
||||
'filename' => '/fixtures/greeting-card-887.h5p',
|
||||
'expected' => true, // Content check is skipped so the package will be considered valid.
|
||||
'isadmin' => false,
|
||||
'onlyupdatelibs' => true,
|
||||
'skipcontent' => true,
|
||||
],
|
||||
'Invalid H5P file (as admin)' => [
|
||||
'filename' => '/fixtures/h5ptest.zip',
|
||||
'expected' => false,
|
||||
'isadmin' => true,
|
||||
],
|
||||
'Invalid H5P file (as user)' => [
|
||||
'filename' => '/fixtures/h5ptest.zip',
|
||||
'expected' => false,
|
||||
'isadmin' => false,
|
||||
],
|
||||
'Invalid H5P file (as user) skipping content' => [
|
||||
'filename' => '/fixtures/h5ptest.zip',
|
||||
'expected' => true, // Content check is skipped so the package will be considered valid.
|
||||
'isadmin' => false,
|
||||
'onlyupdatelibs' => false,
|
||||
'skipcontent' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 3.11 ===
|
||||
* Added $skipcapcheck parameter to H5P constructor, api::create_content_from_pluginfile_url() and
|
||||
api::get_content_from_pluginfile_url() to let skip capabilities check to get the pluginfile URL.
|
||||
* Added new field "enabled" to h5p_libraries to let define if a content type is enabled (1) or not (0).
|
||||
For now, only runnable content-types can be disabled/enabled. When a content-type is disabled, their
|
||||
contents are not displayed and no new contents using it can be created/uploaded.
|
||||
Some extra methods have been added to the api too in order to support this field:
|
||||
- set_library_enabled
|
||||
- is_library_enabled
|
||||
- is_valid_package
|
||||
|
||||
=== 3.10 ===
|
||||
* Added a new cache for h5p_library_files (MDL-69207)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue