Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fc8aa44
fix / GH#597 json_decode called with null
danowar2k Jun 17, 2026
1e514f4
AU-7178 Fix editor placed on top of sticky footer
icc Jun 19, 2026
f372170
For Moodle ≤ 3.11, define MESSAGE_DEFAULT_ENABLED.
lucaboesch Apr 12, 2026
91ea303
Add extraTableClasses to work with Bootstrap 5
otacke Jun 30, 2026
f4d4ae7
Merge pull request #616 from lucaboesch/issue-615
icc Jul 1, 2026
d1ba26c
Merge pull request #626 from danowar2k/GH#597-json_decode-null
icc Jul 1, 2026
d77f9bf
Merge pull request #631 from otacke/fix-table-bootstrap-5
icc Jul 1, 2026
ef8fda9
Merge branch 'stable'
icc Jul 1, 2026
a7a10ef
fix / Remove deprecated FEATURE_GROUPMEMBERSONLY from hvp_supports()
thisismyurl Jul 27, 2026
0aad9f1
MBS-10983: fix / Make look_for_updates task handle errors properly
PhMemmel Aug 5, 2026
97b9d3d
Merge branch 'master' into au-7178-fix-editor-z-index
icc Aug 7, 2026
fb840b5
Update editor + reporting with latest fixes
icc Aug 10, 2026
b5b4fef
Merge pull request #637 from thisismyurl/fix/636-remove-feature-group…
icc Aug 10, 2026
312896c
Merge pull request #640 from PhMemmel/MBS-10983-Fix_error_handling_lo…
icc Aug 10, 2026
6c24517
Merge branch 'stable'
icc Aug 10, 2026
57443d4
Merge branch 'stable' into au-7178-fix-editor-z-index
icc Aug 10, 2026
731da42
Merge branch 'master' into au-7178-fix-editor-z-index
icc Aug 10, 2026
3d41c7d
Merge pull request #628 from h5p/au-7178-fix-editor-z-index
thomasmars Aug 11, 2026
a4029b4
Prepare for release 1.28.3
makmentins Aug 13, 2026
f053073
AU-8017 Add option to re-upgrade subcontent
icc Aug 14, 2026
98e26a1
AU-8017 Fix regular content upgrade...
icc Aug 14, 2026
2d38732
AU-8017 Fix using content ID to track upgrade process
icc Aug 14, 2026
772b78b
AU-8017 Fix lastId not always int
icc Aug 17, 2026
a265eb6
AU-8017 Fix JS variable name typo
icc Aug 17, 2026
da87752
Update core library
icc Aug 18, 2026
c1f2c3a
Merge pull request #642 from h5p/fix-subcontent
thomasmars Aug 18, 2026
6527ec5
Prepare for release 1.28.4
makmentins Sep 1, 2026
1a429bc
Merge remote-tracking branch 'upstream/stable' into stable-catalyst
niko-hoogeveen Sep 22, 2026
b0435dc
Fix failing CI unit test
niko-hoogeveen Sep 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion classes/editor_framework.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ public function getLibraries($libraries = null) {
$library->title = $details->title;
$library->runnable = $details->runnable;
$library->restricted = $superuser ? false : ($details->restricted === '1' ? true : false);
$library->metadataSettings = json_decode($details->metadata_settings);
$library->metadataSettings =
is_string($details->metadata_settings) ? json_decode($details->metadata_settings) : null;
$librarieswithdetails[] = $library;
}
}
Expand Down
6 changes: 3 additions & 3 deletions classes/framework.php
Original file line number Diff line number Diff line change
Expand Up @@ -1604,13 +1604,13 @@ public function getNumNotFiltered() {
* Implements getNumContent().
*/
// @codingStandardsIgnoreLine
public function getNumContent($libraryid, $skip = NULL) {
public function getNumContent($libraryid, $skip = NULL, $lastid = 0) {
global $DB;
$skipquery = empty($skip) ? '' : " AND id NOT IN ($skip)";

return (int) $DB->get_field_sql(
"SELECT COUNT(id) FROM {hvp} WHERE main_library_id = ?{$skipquery}",
array($libraryid));
"SELECT COUNT(id) FROM {hvp} WHERE main_library_id = ? AND id > ?{$skipquery}",
array($libraryid, $lastid));
}

/**
Expand Down
51 changes: 39 additions & 12 deletions classes/task/look_for_updates.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,11 @@
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Defines the task which looks for H5P updates.
*
* @package mod_hvp
* @copyright 2016 Joubel AS <contact@joubel.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace mod_hvp\task;

/**
* The mod_hvp look for updates task class
* Defines the task which looks for H5P updates.
*
* @package mod_hvp
* @copyright 2016 Joubel AS <contact@joubel.com>
Expand All @@ -36,10 +29,44 @@ public function get_name() {
}

public function execute() {
// Check to make sure external communications hasn't been disabled.
if (get_config('mod_hvp', 'hub_is_enabled') || get_config('mod_hvp', 'send_usage_statistics')) {
$core = \mod_hvp\framework::instance();
$core->fetchLibrariesMetadata();
// Check to make sure external communications have not been disabled.
if (!get_config('mod_hvp', 'hub_is_enabled') && !get_config('mod_hvp', 'send_usage_statistics')) {
mtrace(get_string('lookforupdatesskippeddisabledlog', 'mod_hvp'));
return;
}

$core = \mod_hvp\framework::instance();
$result = $core->fetchLibrariesMetadata();

if ($result === false) {
mtrace(get_string('fetchlibrariesmetadatafailedlog', 'mod_hvp'));
} else if (is_object($result)) {
$librariescount = 0;
if (isset($result->libraries) && is_array($result->libraries)) {
$librariescount = count($result->libraries);
}
mtrace(get_string('fetchlibrariesmetadatasuccesslog', 'mod_hvp', $librariescount));
} else {
mtrace(get_string('fetchlibrariesmetadataunexpectedlog', 'mod_hvp'));
}

$errors = \mod_hvp\framework::messages('error');
foreach ($errors as $error) {
$code = $error->code ?? 'N/A';
$text = $error->message ?? 'N/A';
mtrace(get_string('fetchlibrariesmetadataerrorlog', 'mod_hvp', (object) [
'code' => $code,
'message' => $text,
]));
}

$infos = \mod_hvp\framework::messages('info');
foreach ($infos as $info) {
mtrace(get_string('fetchlibrariesmetadatainfolog', 'mod_hvp', $info));
}

if ($result === false) {
throw new \moodle_exception('fetchlibrariesmetadatafailed', 'mod_hvp');
}
}
}
2 changes: 1 addition & 1 deletion editor
Submodule editor updated 1 files
+1 −1 h5peditor.class.php
4 changes: 4 additions & 0 deletions editor.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#fgroup_id_h5peditor {
z-index: 1;
position: relative;
}
7 changes: 7 additions & 0 deletions lang/en/hvp.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@
$string['noh5ps'] = 'There\'s no interactive content available for this course.';

$string['lookforupdates'] = 'Look for H5P updates';
$string['fetchlibrariesmetadatafailed'] = 'Failed to fetch H5P libraries metadata.';
$string['fetchlibrariesmetadatafailedlog'] = 'Fetching H5P content types from the Hub failed.';
$string['fetchlibrariesmetadatasuccesslog'] = 'H5P Hub request completed successfully ({$a} content types in the response).';
$string['fetchlibrariesmetadataunexpectedlog'] = 'H5P Hub request returned an unexpected response.';
$string['fetchlibrariesmetadataerrorlog'] = 'H5P Hub error: [code: {$a->code}, message: {$a->message}]';
$string['fetchlibrariesmetadatainfolog'] = 'H5P Hub notice: {$a}';
$string['lookforupdatesskippeddisabledlog'] = 'Task skipped: both H5P Hub and usage statistics are disabled.';
$string['updatelibraries'] = 'Update All Libraries';
$string['removetmpfiles'] = 'Remove old H5P temporary files';
$string['removeoldlogentries'] = 'Remove old H5P log entries';
Expand Down
2 changes: 0 additions & 2 deletions lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ function hvp_supports($feature) {
return true;
case FEATURE_GROUPINGS:
return true;
case FEATURE_GROUPMEMBERSONLY:
return true;
case FEATURE_MOD_INTRO:
return true;
case FEATURE_COMPLETION_TRACKS_VIEWS:
Expand Down
10 changes: 7 additions & 3 deletions library_list.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
// No guest autologin.
require_login(0, false);

$fixsubcontent = optional_param('fix_subcontent', false, PARAM_BOOL); // Special fix to re-run upgrade for subcontent only

$pageurl = new moodle_url('/mod/hvp/library_list.php');
$PAGE->set_url($pageurl);

Expand Down Expand Up @@ -70,11 +72,13 @@
$i = 0;
foreach ($libraries as $versions) {
foreach ($versions as $library) {
$numContent = $core->h5pF->getNumContent($library->id);
$usage = $core->h5pF->getLibraryUsage($library->id, $numnotfiltered ? true : false);
if ($library->runnable) {
$upgrades = $core->getUpgrades($library, $versions);
$upgradeurl = empty($upgrades) ? false : (new moodle_url('/mod/hvp/upgrade_content_page.php', array(
'library_id' => $library->id
$upgradeurl = ($fixsubcontent ? empty($numContent) : empty($upgrades)) ? false : (new moodle_url('/mod/hvp/upgrade_content_page.php', array(
'library_id' => $library->id,
'fix_subcontent' => $fixsubcontent
)))->out(false);

$restricted = (isset($library->restricted) && $library->restricted == 1 ? true : false);
Expand All @@ -94,7 +98,7 @@
'title' => $library->title . ' (' . \H5PCore::libraryVersion($library) . ')',
'restricted' => $restricted,
'restrictedUrl' => $restrictedurl,
'numContent' => $core->h5pF->getNumContent($library->id),
'numContent' => $numContent,
'numContentDependencies' => $usage['content'] === -1 ? '' : $usage['content'],
'numLibraryDependencies' => $usage['libraries'],
'upgradeUrl' => $upgradeurl,
Expand Down
10 changes: 7 additions & 3 deletions locallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ function hvp_add_editor_assets($id = null, $mformid = null) {
$PAGE->requires->js('/mod/hvp/editor/scripts/h5peditor-editor.js', true);
$PAGE->requires->js('/mod/hvp/editor/scripts/h5peditor-init.js', true);
$PAGE->requires->js('/mod/hvp/editor.js', true);
$PAGE->requires->css('/mod/hvp/editor.css', true);

// Add translations.
$language = \mod_hvp\framework::get_language();
Expand Down Expand Up @@ -316,6 +317,7 @@ function hvp_admin_add_generic_css_and_js($page, $settings = null) {
'deleteLibrary' => '',
'upgradeLibrary' => get_string('upgradelibrarycontent', 'hvp')
);
$settings['extraTableClasses'] = 'table-reboot';

$page->requires->data_for_js('H5PAdminIntegration', $settings, true);
$page->requires->css(generate_css_url('/mod/hvp/library/styles/h5p.css'));
Expand Down Expand Up @@ -416,9 +418,10 @@ function hvp_content_upgrade_progress($libraryid) {
} else {
$out->skipped = array();
}
$lastid = optional_param('lastId', 0, PARAM_INT);

// Get number of contents for this library.
$out->left = $interface->getNumContent($libraryid, $skipped);
$out->left = $interface->getNumContent($libraryid, $skipped, $lastid);

if ($out->left) {
$skipquery = empty($skipped) ? '' : " AND id NOT IN ($skipped)";
Expand All @@ -430,8 +433,9 @@ function hvp_content_upgrade_progress($libraryid) {
a11y_title
FROM {hvp}
WHERE main_library_id = ?
AND id > ?
{$skipquery}
ORDER BY name ASC", array($libraryid), 0 , 40
ORDER BY id ASC", array($libraryid, $lastid), 0 , 40
);

foreach ($results as $content) {
Expand Down Expand Up @@ -471,7 +475,7 @@ function hvp_get_library_upgrade_info($name, $major, $minor) {
$response->upgradesScript = "{$basepath}pluginfile.php/{$context->id}/mod_hvp/libraries/{$libraryfoldername}/upgrades.js";
}
$response->semantics = $core->loadLibrarySemantics($name, $major, $minor);

return $response;
}

Expand Down
110 changes: 110 additions & 0 deletions tests/look_for_updates_test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php
// 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/>.

namespace mod_hvp;

/**
* Unit tests for look_for_updates scheduled task.
*
* @package mod_hvp
* @copyright 2026
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_hvp\task\look_for_updates
*/
final class look_for_updates_test extends \advanced_testcase {
/**
* Verifies
* - that the task exits early exactly when both hub_is_enabled and send_usage_statistics_setting are disabled
* - that the task does proper error handling and logging
*
* @dataProvider execute_provider
* @param int $hubisenabled Hub setting value.
* @param int $sendusagestatistics Usage statistics setting value.
* @param bool $expectearlyexit Whether execute() is expected to return via early-exit.
*/
public function test_execute(
int $hubisenabled,
int $sendusagestatistics,
bool $expectearlyexit
): void {
$this->resetAfterTest();

set_config('hub_is_enabled', $hubisenabled, 'mod_hvp');
set_config('send_usage_statistics', $sendusagestatistics, 'mod_hvp');
// Keep site unregistered so all non-early-exit paths fail deterministically at registration.
set_config('site_uuid', '', 'mod_hvp');

if ($hubisenabled || $sendusagestatistics) {
// Force deterministic no-network behavior for all non-early-exit cases.
\curl::mock_response('');
}

$task = new \mod_hvp\task\look_for_updates();

ob_start();
try {
$task->execute();
$output = ob_get_clean();
if (!$expectearlyexit) {
$this->fail('Expected moodle_exception for failed metadata fetch. Output: ' . $output);
}
} catch (\moodle_exception $exception) {
$output = ob_get_clean();
if ($expectearlyexit) {
$this->fail('Did not expect moodle_exception. Got: ' . $exception->errorcode);
}
$this->assertEquals('fetchlibrariesmetadatafailed', $exception->errorcode);
}

if ($expectearlyexit) {
$this->assertStringContainsString(get_string('lookforupdatesskippeddisabledlog', 'mod_hvp'), $output);
} else {
$this->assertStringContainsString(get_string('fetchlibrariesmetadatafailedlog', 'mod_hvp'), $output);
$this->assertStringContainsString('registration-failed-hub-disabled', $output);
$this->assertStringNotContainsString(get_string('lookforupdatesskippeddisabledlog', 'mod_hvp'), $output);
}
}

/**
* Data provider for test_execute_setting_combinations.
*
* @return array
*/
public static function execute_provider(): array {
return [
'both_disabled' => [
'hubisenabled' => 0,
'sendusagestatistics' => 0,
'expectearlyexit' => true,
],
'hub_enabled_only' => [
'hubisenabled' => 1,
'sendusagestatistics' => 0,
'expectearlyexit' => false,
],
'usage_statistics_enabled_only' => [
'hubisenabled' => 0,
'sendusagestatistics' => 1,
'expectearlyexit' => false,
],
'both_enabled' => [
'hubisenabled' => 1,
'sendusagestatistics' => 1,
'expectearlyexit' => false,
],
];
}
}
8 changes: 5 additions & 3 deletions upgrade_content_page.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
require_login(0, false);

$libraryid = required_param('library_id', PARAM_INT);
$fixsubcontent = optional_param('fix_subcontent', false, PARAM_BOOL); // Special fix to re-run upgrade for subcontent only
$pageurl = new moodle_url('/mod/hvp/upgrade_content_page.php', array('library_id' => $libraryid));
$PAGE->set_url($pageurl);
admin_externalpage_setup('h5plibraries');
Expand Down Expand Up @@ -73,7 +74,7 @@
'errorTooHighVersion' => get_string('upgradeerrortoohighversion', 'hvp'),
'errorNotSupported' => get_string('upgradeerrornotsupported', 'hvp'),
'done' => get_string('upgradedone', 'hvp', $numcontents) .
' <a href="' . (new moodle_url('/mod/hvp/library_list.php'))->out(false) . '">' .
' <a href="' . (new moodle_url('/mod/hvp/library_list.php', array('fix_subcontent' => $fixsubcontent)))->out(false) . '">' .
get_string('upgradereturn', 'hvp') . '</a>',
'library' => array(
'name' => $library->name,
Expand All @@ -83,13 +84,14 @@
array('action' => 'getlibrarydataforupgrade')))->out(false) . '&library=',
'scriptBaseUrl' => (new moodle_url('/lib/javascript.php/' . get_jsrev() . '/mod/hvp/library/js'))->out(false),
'buster' => '',
'versions' => $upgrades,
'versions' => $fixsubcontent ? [$libraryid => \H5PCore::libraryVersion($versions[$libraryid])] : $upgrades,
'contents' => $numcontents,
'buttonLabel' => get_string('upgradebuttonlabel', 'hvp'),
'infoUrl' => (new moodle_url('/mod/hvp/ajax.php', array('action' => 'libraryupgradeprogress',
'library_id' => $libraryid)))->out(false),
'total' => $numcontents,
'token' => \H5PCore::createToken('contentupgrade')
'token' => \H5PCore::createToken('contentupgrade'),
'fixSubcontent' => !!$fixsubcontent,
)
);

Expand Down
4 changes: 2 additions & 2 deletions version.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@

defined('MOODLE_INTERNAL') || die();

$plugin->version = 2026062501;
$plugin->version = 2026090101;
$plugin->requires = 2022112800; // 4.1.0
$plugin->cron = 0;
$plugin->component = 'mod_hvp';
$plugin->maturity = MATURITY_STABLE;
$plugin->supported = [401, 404];
$plugin->release = '1.28.2';
$plugin->release = '1.28.4';
Loading