Multiple issues with library dependencies

Hi,

We have modules using the Question set library and within that we have a variety of question types e.g. multiple choice, fill in the blanks, complex fill in the blanks. These were created a while ago and the content/libraries need to be updated. However, we encountered a few issues.

  1. Site runs on PHP 8.x and on Drupal 9.4.x using Opigno LMS 3.0.3 distro
  2. When editing the interactive content (Question Set with Advanced/Complex Blanks question type) - this error pops up The H5P.AdvancedBlanks 1.2 used in the content is not valid (Screen shot attached)
  3. On saving the activity/content the Advanced Blank/Complex question type gets removed altogether
  4. The hub does not show any available updates to Advanced Blanks and the latest available version is 1.2.2.
  5. After updating the Advanced Blanks library to 1.2.2 the question type still doesn't appear within the Question Set module as an option
  6. I've checked the latest AdvancedBlanks library and it seems to be compatible with Question Set - however, I can't seem to get it integrated.
  7. I'm unable to download the content to send it across as the moment I save the activity (after enabling the download option) - the AdvancedBlanks question type widget gets removed

Any help would be greatly appreciated.

 

BV52's picture

Hi lazareye,

Are you running a custom version of Question Set? I don't remember that we ever released a version of Question Set that includes Advanced/Complex Fill i the Blanks.

-BV

otacke's picture

Would be my best guess as well.

Looking at the semantics.json under Question Set I'd reckon the same. But I can't find any customisation that would have injected AdvancedBlanks into a parent Quiz. We inherited some of the code but looking at the below custom snippet it seems as though AdvancedBlanks was an option:

              contentData.questions
                .forEach(function(question) {
                    if (question.library.split(' ')[0] === 'H5P.AdvancedBlanks') {
                      blankListCtr += question.params.content.blanksList.length
                      if (advanceBlanksCtr > 0) {
                        for (var i = 0; i < blankListCtr; i++) {
                          // Just add empty blank item, empty blank items will not be rendered.
                          // This is the only way to update the indexing in an array.
                          question.params.content.blanksList.unshift({correctAnswerText : '', incorrectAnswersList : []});
                        }
                      }
                      advanceBlanksCtr++;
                    }
                });

Looking at the AdvancedBlanks 1.2.x library there's a line in the TODO which seems to imply this is possible

    ✔ Question Set @done(18-08-04 16:35)

So right now, my workaround is to shoe-horn AdvancedBlanks into a parent Quiz using semantics_alter hook. This seems to work, however, the activity has to be re-built and re-saved.

Thanks for the quick reply:

We inherited most of this code and this is what I've come across in terms of customisation - and it looks like Advanced Blanks has been injected into the parent libraries within the activity as seen below.

function update_8006() { // Get the latest Complex fill the blank library. $database = \Drupal::database(); $query = $database->select('h5p_libraries', 'h5p_libraries') ->fields('h5p_libraries') ->condition('h5p_libraries.machine_name', 'H5P.AdvancedBlanks', '=') ->orderBy('h5p_libraries.library_id', 'DESC'); $advanceBlank = $query->execute() ->fetch(); // Prepare the question type option value. $advanceBlankOption = ''; if ($advanceBlank) { $advanceBlankOption = "{$advanceBlank->machine_name} {$advanceBlank->major_version}.{$advanceBlank->minor_version}"; } // Insert only if there is a Complex fill the blank library. if ($advanceBlankOption) { // Get the latest Question Set library. $query = $database->select('h5p_libraries', 'h5p_libraries') ->fields('h5p_libraries') ->condition('h5p_libraries.machine_name', 'H5P.QuestionSet', '=') ->orderBy('h5p_libraries.library_id', 'DESC'); $qusetionSet = $query->execute() ->fetch(); $semantics = json_decode($qusetionSet->semantics, true); // Add only iff Complex fill the blank is not yet added. if (!in_array($advanceBlankOption, $semantics[4]['field']['options'])) { $semantics[4]['field']['options'][] = $advanceBlankOption; // Update Question set with the Complex fill the blank library option. $database->update('h5p_libraries') ->fields(['semantics' => json_encode($semantics)]) ->condition('library_id', $qusetionSet->library_id) ->execute(); } } }

So it looks like when the parent library is updated it throws the H5P.AdvancedBlanks is not valid error.

Any ideas - how the dependant AdvancedBlanks library can be updated alongside the parent?

otacke's picture

It's not a bug in Question Set or H5P core or AdvancedBlanks.

So, somebody tampered with the database on your platform before and modified the list of available subcontents in Question Set - adding AdvancedBlanks as an option. Now, when you updated QuestionSet to a later (minor) version, the later version got it's own database entry which will holds the original entries only. You will need to patch that one as well before content can be upgraded - or invalid entries (here AdvancedBlanks) will be filtered out from the contents' parameters. Running the drupal hook again should do the trick.

If you have already upgraded content (in case this was a minor version update), H5P might still hold a copy of the original parameters in the database table for the contents (column "parameters" for the original values, column "filtered_parameters" for the filtered versions), but I am not entirely sure about that - and when editing/saving content, the illegal values should be gone for good either way. The patched parameters would need to be retrieved from the "parameters" column.

Given the way that the customization was done, you will need to do this for every (minor version) update of QuestionSet that you install. Also, your platform lost the option to share the content with other H5P platforms (there, the AdvancedBlanks contents will be stripped away just like you're experiencing it now).

Best,

Oliver 

Thanks Oliver for your insight.

I think we'll be moving away from the 'injected' approach as there's no guarantee that will work when future updates roll through for the parent packages i.e. Column and QuestionSet.

In saying that, is there a possibility AdvancedBlanks would be included in the above packages - as it seems to be compatible.

Thanks again,

otacke's picture

I am not a member of the H5P core team, I am merely a community member with some knowledge to share. So I cannot tell what the plans for AdvancedBlanks are.

Thanks Oliver

due to this injected dependency - the parent library Column fails to update past a certain point. Is there a way to find out which Column instances use the injected AdvancedBlanks and how it could be possibly removed without deleting the content in the activity (that's not of the AdvancedBlank type).

otacke's picture

You'd have to check the database. There's a table with an entry for every H5P content that contains a "parameters" and a "filtered_parameters" column. The respective fields hold the parameters in JSON format, and you'd have to remove the AdvancedBlanks entries from that JSON structure.

Checking the database didn't show up with the injected sub-library for the column entries  - however, when trying to update form Column 1.15.x to 1.16.x the update stalls at around 50% and console shows:

h5p-content-upgrade-process.js:71 Uncaught TypeError: Cannot read properties of null (reading 'content') at h5p-content-upgrade-process.js:71:20 at h5p-content-upgrade-process.js:159:7 at h5p-content-upgrade-process.js:312:11

I managed to isolate the records that were stalling the process - however, it's not possible to edit the activities as I'm unable to save the activity until I update the parent Column library. I've updated all the libraries via the Hub's dropdown with no effect on the stalled libraries update (in the admin section).

Are there any options here other than deleting and re-creating the problematic instances?

otacke's picture

Without knowing what your database holds, this is like flying blind.