Skip to content

Import Common Cartridge and SCORM packages#105

Open
swilla wants to merge 22 commits into
4.xfrom
import-cartridge
Open

Import Common Cartridge and SCORM packages#105
swilla wants to merge 22 commits into
4.xfrom
import-cartridge

Conversation

@swilla

@swilla swilla commented May 21, 2026

Copy link
Copy Markdown
Member

Summary

  • Add Common Cartridge import: parse imsmanifest.xml, build courses/lessons/steps from cartridge structure, and extract Articulate Storyline slide content into document steps where possible.
  • Add SCORM / HTML5 package support: store extracted packages, serve them via authenticated routes, and embed them in document steps (Articulate Rise, Storyline HTML5, and cartridges that bundle Articulate content).
  • Expose imports from the admin UI (course list header action) and a new filament-lms:import-cartridges Artisan command (sync or queued), with completion notifications and config under common_cartridge_import.

Test plan

  • Run vendor/bin/pest tests/Feature/CommonCartridgeImportTest.php tests/Feature/ImportCartridgesCommandTest.php tests/Feature/ScormPackageServingTest.php
  • Publish/run the new document migration stub (scorm_package_* columns on lms_documents)
  • Import a Common Cartridge ZIP from Courses → Import cartridge and confirm course/lesson/step structure
  • Import Articulate Rise / Storyline HTML5 ZIPs via CLI (filament-lms:import-cartridges --file=... --sync) and verify SCORM content loads in a document step
  • Confirm SCORM asset URLs require auth and return expected MIME types

Made with Cursor


Note

High Risk
Large feature touching course completion, authenticated file serving, and client-side SCORM bridges; incorrect progress or auth checks could mark courses complete prematurely or expose package files.

Overview
Adds Common Cartridge / SCORM / Articulate import and learner playback: ZIP packages are parsed (imsmanifest.xml or Storyline frame.xml), courses are created via a queued job or filament-lms:import-cartridges, and retained packages are stored on documents with new schema columns.

Embedded player mode (embedded_player, completion_mode on courses) hides LMS step navigation, serves package assets through authenticated ScormPackageController, and syncs progress via ScormCommitController plus in-page SCORM 1.2 / HTML5 bridges. ScormProgressService enforces minimum session time and guards manual completion.

Admin gains Import SCORM Package on the course list, course fields for embedded player settings, and a backfill command for existing package documents. Learner UX updates include full-width interactive iframes, optional exit-with-complete flow, LmsTestFormShow for card-style knowledge checks, and sanitized step text rendering.

Reviewed by Cursor Bugbot for commit a7ac69e. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread src/FilamentLmsServiceProvider.php
Comment thread src/Services/CommonCartridge/ArticulateSlideContentExtractor.php
Comment thread src/Jobs/ImportCommonCartridgeJob.php
Comment thread src/Jobs/ImportCommonCartridgeJob.php Outdated
Comment thread src/Services/CommonCartridge/ScormPackageStorage.php Outdated
Comment thread src/Jobs/ImportCommonCartridgeJob.php
Comment thread src/Console/Commands/BackfillEmbeddedPlayerCourses.php
Comment thread src/Services/CommonCartridge/ManifestParser.php Outdated
Comment thread routes/web.php Outdated
Comment thread resources/views/components/exit-lms.blade.php
Comment thread src/Http/Controllers/ScormPackageController.php
Comment thread src/Services/CommonCartridge/CommonCartridgeImportService.php
Comment thread src/FilamentLmsServiceProvider.php
Comment thread src/Livewire/DocumentStep.php
Comment thread src/Models/Step.php
Comment thread src/Services/CommonCartridge/CommonCartridgeImportService.php
Comment thread src/Models/Step.php
Comment thread src/Http/Controllers/ScormPackageController.php Outdated
Comment thread src/LmsPanelProvider.php
Comment thread src/LmsPanelProvider.php Outdated
swilla and others added 3 commits May 28, 2026 14:48
Comment thread resources/views/filament/pages/create-test-entry.blade.php
Comment thread resources/views/components/exit-lms.blade.php
swilla and others added 3 commits June 8, 2026 15:50
Align the user-side relation manager with CourseUsersRelationManager by adding assigned course labels, search columns, bulk detach, and pivot timestamps.

Co-authored-by: Cursor <cursoragent@cursor.com>
…s-relation-manager

Enhance CoursesRelationManager for user course assignment
Comment thread src/Services/ScormProgressService.php
Comment thread src/Services/ScormProgressService.php
Comment thread src/Services/CommonCartridge/ManifestParser.php Outdated
Register the test form Livewire component, keep learners on course when HTML5 completion is blocked, dispatch CourseStarted from the launch step, and only use Rise launch paths that exist on disk.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a7ac69e. Configure here.


if (count > 0 && index >= count - 1) {
notifyCompleted();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single-slide HTML5 auto-completes

Medium Severity

The HTML5 package bridge treats GetCurrentSlideIndex() >= GetSlideCount() - 1 as course completion. When a Storyline export has only one slide, that condition is true on the first poll, so the parent player posts completion before the learner has meaningfully progressed.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a7ac69e. Configure here.

Comment thread src/LmsPanelProvider.php
$builder->groups([]);

$course = Course::where('slug', $courseSlug)->firstOrFail();
return $builder;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embedded courses hide certificate nav

Medium Severity

Imported SCORM/HTML5 courses enable embedded player mode and clear sidebar navigation, including the Certificate group. linkToCurrentStep always returns the launch step URL for embedded courses, so learners who finish via the player have no in-panel path to the completion or certificate page.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a7ac69e. Configure here.

Comment thread src/Models/Course.php

$step = $this->steps()->first();

return $step instanceof Step ? $step : null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Launch step fallback ignores lesson order

Medium Severity

launchStep() falls back to $this->steps()->first() when no document has a retained SCORM package. The steps() relation orders only by lms_steps.order, not lesson order, so the chosen step can be the wrong lesson’s step or a non-document step in multi-lesson embedded courses.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a7ac69e. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants