Repository navigation
[QTI] Accept QTI items through the internal API for ricecooker import #6002
Description
Overview
Land assessment items uploaded through the internal/ricecooker API uniformly as QTI: store editor-shaped and arbitrary QTI directly, convert uploaded legacy/structured items to QTI via the #6003 machinery, validate against the schema, and map referenced media.
Complexity: High
Target branch: unstable
Context
create_exercises(contentcuration/contentcuration/views/internal.py) builds items from structured fields and validates only assessment_id uniqueness; type and content go unchecked until publish.- The internal endpoint and
utils/nodes.pyduplicate logic that theAssessmentItemViewSet/serializer ([QTI] Allow API endpoint to handle AssessmentItem.raw_data to store QTI data #5999) already owns; delegating to it cleans up that tech debt. - QTI items carry content as
raw_dataXML and reference media mapped viamap_files_to_assessment_item(utils/nodes.py). - Arbitrary QTI may use interactions Studio can't edit; these are non-editable passthrough, published verbatim.
- The Perseus custom interaction (
data-type='perseus') is a publish-time-only wrapper ([QTI] Publish mixed Perseus + QTI exercises as one QTI package #6006); if our own published QTI is re-imported, it must be unwrapped back to a rawperseus_question.
The Change
- Refactor
create_exercisesto delegate to theAssessmentItemViewSet/serializer machinery ([QTI] Allow API endpoint to handle AssessmentItem.raw_data to store QTI data #5999), removing duplicated logic in the internal endpoint andnodesutils. - Accept
QTIitems (raw_data XML + media) directly; validate each against the schema ([QTI] QTI 3.0 schema XML validation utilities #6005), rejecting non-compliant items with actionable errors. - Convert uploaded legacy/structured items to QTI on ingest via the [QTI] Reusable legacy→QTI assessment-item conversion utility #6003 conversion; leave raw Perseus as raw Perseus (handled by [QTI] Publish mixed Perseus + QTI exercises as one QTI package #6006).
- Unwrap any Perseus custom interaction (
data-type='perseus'): read its referenceddata-perseus-pathpayload from the upload and restore it as a rawperseus_question, rather than storing the custom interaction. - Map media/file dependencies so they are present at publish.
Acceptance Criteria
-
create_exercisesdelegates to the AssessmentItem serializer/machinery; duplicated internal-endpoint andnodeslogic is removed - The API accepts and persists QTI items (raw_data XML + media)
- Uploaded QTI is schema-validated ([QTI] QTI 3.0 schema XML validation utilities #6005); non-compliant items are rejected with a clear error
- Uploaded legacy/structured items are converted to QTI on ingest; raw Perseus is preserved as-is
- A Perseus custom interaction is unwrapped by reading its
data-perseus-pathpayload and restoring the rawperseus_question - Referenced media is mapped and present at publish
- Tests cover QTI upload (editor-shaped + arbitrary), legacy-converted-on-ingest, an invalid upload, and media mapping
References
contentcuration/contentcuration/views/internal.pycontentcuration/contentcuration/utils/nodes.py
AI usage
Architecture decided with the maintainer across an iterative session: blanket
QTItype with the item XML inraw_data; XSD-authoritative validation across all sources; a legacy→QTI global migration with an API-layer dual-read; ricecooker upload delegating to the AssessmentItem serializer; and a Perseus custom-interaction contract confirmed against the QTI 3.0 specification. Claude mapped the existing publish/validation/ricecooker code, proposed the breakdown, and drafted each issue; the maintainer steered every decision and reviewed throughout.
Activity
rtibblesbot commentedon Jul 5, 2026
The bot has been waiting for a response for 2 hour(s). It will resume automatically when someone replies.