Improve legacy package migration from mod_exeweb and mod_exescorm#89
Merged
Conversation
Introduce a shared classifier/resolver that decides migratability by the eXeLearning source a stored legacy package actually carries, rather than by filename or assumption. A package is migratable when content.xml (ODE 2.0) sits at the archive root (a native .elpx, a content.xml zip or an IMS export) or when it embeds exactly one safe .elpx; legacy .elp (contentv3.xml), source-less SCORM or web exports, multiple embedded .elpx, and corrupt archives are not. Detection reads only the ZIP central directory (preflight-cheap) and reuses the existing zip_utils path-traversal/symlink defences. Add helper_trait builders for the new package shapes and a unit test covering every branch.
Replace the .elpx-filename + embedded-.elpx scan with the shared content-based probe (keeping the external/aiccurl/localsync short-circuit). A non-.elpx package carrying content.xml at its root (an eXeLearning content zip or IMS export) is now migratable as a direct package instead of being reported nosource; a single embedded .elpx still resolves as before. Add tests for the content.xml zip case and the legacy .elp exclusion.
Locate the stored package (revision itemid, with the restored-backup fallback scan) and defer migratability to the shared content-based probe. A package with no recoverable content.xml source is now reported nosource cleanly instead of classifying ok and failing at extraction. Add tests for the content.xml gate.
Refine migratescormnote and migratestatus_nosource to state that activities are migrated only when an eXeLearning content.xml source can be recovered (root content.xml or a single embedded .elpx), and that legacy .elp and source-less SCORM/web exports are skipped. Reuses the existing nosource bucket; no new keys.
Cover the detection gap through resolution and installation: a content.xml package stored under a non-.elpx name is detected, resolved and installed into a servable, graded activity.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #89 +/- ##
============================================
+ Coverage 89.49% 89.51% +0.02%
- Complexity 976 980 +4
============================================
Files 52 53 +1
Lines 4236 4236
============================================
+ Hits 3791 3792 +1
+ Misses 445 444 -1
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Spanish research note documenting the package variants each legacy plugin stores, the content.xml migratability criterion and verdict table, why legacy .elp and source-less SCORM/web exports are excluded (no data loss; source kept), and the test matrix.
5c40906 to
80c3990
Compare
…prove-legacy-package-migration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
mod_exelearningships a non-destructive, site-wide tool that migrates legacymod_exewebandmod_exescormactivities into new eXeLearning activities (admin/migrate.php,classes/local/migration/*). The detection that decided what was migratable was fragile and inconsistent between the two source handlers:exescorm_sourceonly treated a package as migratable when its filename ended in.elpxor the SCORM zip embedded an.elpx. A package that is itself acontent.xml-bearing.zip(an eXeLearning content export / IMS export stored under a non-.elpxname) was reportednosourceand silently skipped.exeweb_sourcenever inspected the package contents — it returnedokwhenever any file existed in thepackagefilearea, so a package with no recoverable eXeLearning source either failed at extraction (STATUS_ERROR) or migrated as a sourceless shell.The migratability rule is now explicit and content-based: a package is migrated only when an eXeLearning
content.xml(ODE 2.0) source can be recovered from it.Package types now covered
.elpxcontent.xmlat root.zip/ IMS export / web export bundling sourcecontent.xmlat root.elpx.elpx.elpxambiguoussource.elpcontentv3.xml, nocontent.xmlnosourcecontent.xml, no.elpxnosourceexescormtypeunsupportednosource(no exception)Skipped packages lose no data: the migration never deletes the source, so the legacy activity stays intact and is reported in the preflight/result table.
Changes
classes/local/migration/source/package_probe.php— a shared, content-based classifier/resolver used by both source handlers. It reads only the ZIP central directory (preflight-cheap), decides the verdict from a rootcontent.xml(precedence) or a single safe embedded.elpx, and resolves the package to a temp path (whole archive for a direct package; only the embedded entry otherwise). It reuses the existingzip_utilspath-traversal/symlink defences.exescorm_sourceandexeweb_sourcenow delegate detection and resolution topackage_probe.exescorm_sourcekeeps itsexternal/aiccurl/localsync→unsupportedshort-circuit;exeweb_sourcekeeps its revision-itemid resolution with the restored-backup fallback scan.lang/en/exelearning.php—migratescormnoteandmigratestatus_nosourcenow state thecontent.xmlcriterion and that legacy.elp/ source-less SCORM / web exports are skipped. The existingnosourcebucket is reused (no new statuses or table columns).package_manager::extract_stored),migration_service, grade sync,view.phpand the DB schema are unchanged — the change is confined to source detection.mod_exeweb vs mod_exescorm differences
packagefilearea atitemid = {exeweb}.revisionand wipes the area on each save; it has no grades, so the target uses the per-iDevice grade model and no grade migration runs. Detection had to inspect contents (it previously did not).itemid 0, supports severalexescormtypes (local,localsync,embedded= a raw.elpx,external,aiccurl), and carries grades that are copied to the target's overall grade item. External/AICC-URL and synchronized types keep no migratable static snapshot and stayunsupported. The gap was a genuine SCORM/content.zipwith no embedded.elpx.Both now share one detector, so the rule lives in exactly one place.
Testing performed
tests/local/migration/package_probe_test.phpcovers every branch (native.elpx, content.xml zip, single/multiple embedded.elpx, source-less SCORM, legacy.elp, corrupt archive, itemid threading, blocked-verdict and unsafe-entry resolution).exescorm_source_test,exeweb_source_testandmigration_service_test(end-to-end install of a content.xml zip resolved byexescorm_source).php -landphpcs --standard=moodleclean on all changed/added files.Known limitations
.elpxcase is validated by extension (the nested zip is not opened during the cheap preflight); the extractor'sindex.htmlguard is the backstop.content.xml) are intentionally not preserved as static content — they cannot be reconstructed as editable eXeLearning activities. Offering such preservation would be a separate product decision.Research notes
See
research/analisis/notas/AN-015-deteccion-content-xml-migracion.md(Spanish) for the analysis of what each legacy plugin stores, thecontent.xmlcriterion and verdict table, the rationale for excluding legacy.elp/source-less packages, and the test matrix.Moodle Playground Preview
The changes in this pull request can be previewed and tested using a Moodle Playground instance.
ℹ️ The eXeLearning editor is fetched from the shared release and unpacked into the plugin when the playground boots, so the first load may take a few extra seconds. ELPX upload, viewer and preview work normally.