OL Open edX UAI Content Customization
An Open edX CMS plugin that automates the generation of industry- and length-specific UAI course variants using direct Open edX modulestore APIs.
Version Compatibility
Supports Open edX releases from Sumac and onwards.
For this plugin’s compatibility with Open edX, see the Open edX Release Compatibility table.
Installing The Plugin
For detailed installation instructions, please refer to the plugin installation guide.
Installation required in:
CMS
Overview
For each unique (course_key, industry, duration) row group in the CSV the command clones the source course into a new UAI-specific key, removes every existing section from the clone, and rebuilds the content from the CSV data. This produces multiple industry- and length-specific variants per source course while preserving all course settings (grading policy, certificates, pacing, advanced settings) from the original.
Supported industries are managed in Django admin (Industry model, under OL Open edX UAI Content Customization), not hardcoded — add a row there to support a new industry without a code change. Each row has a name (as used in the industry CSV column) and a short_code used as the course-key suffix. The Original industry — meaning no industry-specific variant, only the duration suffix — is identified by a blank short_code; exactly one Industry row may have one. Length is always one of short/long (code S/F).
Course Key Format
course-v1:ORG+NUMBER.<DURATION>[.<INDUSTRY>]+RUN
For the Original industry, no industry code is appended:
course-v1:UAI_SOURCE+UAI.3.S+1T2026 ← Original, Short
course-v1:UAI_SOURCE+UAI.3.F+1T2026 ← Original, Full
course-v1:UAI_SOURCE+UAI.3.S.HC+1T2026 ← Healthcare, Short
Course Structure
Each generated course has the following structure:
Course (<display name>)
├── Introduction (section, optional)
└── Introduction (subsection)
└── Introduction (unit)
└── Introduction (HTML block)
└── Lectures (section)
└── <Video Title> (subsection)
└── <Video Title> (unit)
└── <Video Title> (video block with edX video ID)
Usage
Prerequisites
You will need a single CSV file:
Processed videos CSV — produced by the video customization workflow. Required columns:
course_key — the Open edX course key of the source course to clone (e.g. course-v1:UAI_SOURCE+UAI.2+1T2026). This course must already exist in the CMS modulestore before the command runs. The command validates all source keys up-front and aborts with an error if any are missing.
industry — must match the name of an Industry row configured in Django admin (case-insensitive), e.g. Healthcare, Finance, Energy, Original
duration — short or long
video_file_name — file name of the video (for reference/display)
video_title — display name for the subsection/unit/video
module_name — used to build the course display name
edx_video_id — the Open edX UUID for the video (exported from Studio / OVS after uploading the customized video)
course_intro — optional introduction content for the generated course. If this value contains HTML tags, it is used as-is. If it is plain text, the command HTML-escapes it and wraps it in <p>...</p>.
Intro resolution precedence for each generated (course_key, industry, duration) variant:
exact match on (course_key, industry, duration)
fallback to (course_key, industry) (industry-only intro, reused for both short and long)
fallback to (course_key, Original industry) (reused across all industries and durations for that source course)
If no intro is resolved, no Introduction section is created for that variant.
Running the Command
Run the management command from inside the CMS container (e.g. Tutor dev shell):
python manage.py cms generate_uai_course_versions \
--processed-videos-csv /path/to/processed_videos.csv \
[--username studio_worker] \
[--dry-run]
--processed-videos-csv also accepts the URL of a publicly readable Google Sheet, so you can point the command directly at the sheet instead of downloading a CSV first:
python manage.py cms generate_uai_course_versions \
--processed-videos-csv "https://docs.google.com/spreadsheets/d/<SHEET_ID>/edit#gid=0" \
[--username studio_worker] \
[--dry-run]
The sheet must be shared as “Anyone with the link can view” (or published to the web). Any standard docs.google.com share/edit link works — the command derives the CSV export link automatically, using the gid from the URL to select the right tab. Only docs.google.com Sheets links are accepted; any other http(s) URL is rejected with an error.
Options
- --processed-videos-csv
Path to the processed video metadata CSV file, or the URL of a publicly readable Google Sheet (docs.google.com share/edit or export link — no other URL is accepted). Required.
- --username
Username of the platform user under whose authority the courses are created. Defaults to studio_worker.
- --dry-run
Print what would be created without writing anything to the modulestore. Use this to verify CSV mapping before committing.
How It Works
For each unique (course_key, industry, duration) group the command:
Validates all source course keys against the live modulestore before making any writes (fail-fast — aborts if any source is missing).
Clones the source course into the new UAI-specific key, inheriting all course settings.
Deletes every existing section (chapter) from the clone.
Rebuilds the content tree from the CSV rows:
Course (cloned — settings inherited) ├── Introduction (optional, created only when ``course_intro`` resolves) └── Introduction (subsection) └── Introduction (unit) └── Introduction (HTML block) └── Lectures (section) └── <Video Title> (subsection) └── <Video Title> (unit) └── <Video Title> (video block)Publishes the course.
Development
# Install dependencies
uv sync --dev
# Run tests (requires Open edX environment — see AGENTS.md)
./run_edx_integration_tests.sh --plugin ol_openedx_uai_content_customization --skip-build
Metadata
Release files for ol-openedx-uai-content-customization 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ol_openedx_uai_content_customization-0.5.0.tar.gz | 15.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ol_openedx_uai_content_customization-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.1 kB
Release files / ol_openedx_uai_content_customization-0.5.0.tar.gz
| Download URL | ol_openedx_uai_content_customization-0.5.0.tar.gz |
|---|---|
| Size | 15.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3b3fe20d0839121db9c33492395ab7978050416e14b3869713001357ada886f2
|
|
BLAKE2b-256 checksum How to use checksums |
e519dff337b2784eb7da5b9ee86ee5873f04a5ec04d53bd1adfaf8569e817451
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / ol_openedx_uai_content_customization-0.5.0-py3-none-any.whl
| Download URL | ol_openedx_uai_content_customization-0.5.0-py3-none-any.whl |
|---|---|
| Size | 21.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
566deb9dd0c897287dbe5839202e69d85eeb11c492236193fb06a3a27127129a
|
|
BLAKE2b-256 checksum How to use checksums |
ccb801d7aab5494c5fd3c718f4ab870770bdd04ac49f3a280c824b6cc1f6aa79
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|