Skip to content

[QTI] Accept QTI items through the internal API for ricecooker import #6002

Description

@rtibbles

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 #6 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.py duplicate logic that the AssessmentItemViewSet/serializer (Introducing Content Curation #1) already owns; delegating to it cleans up that tech debt.
  • QTI items carry content as raw_data XML and reference media mapped via map_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 (Browserify #8); if our own published QTI is re-imported, it must be unwrapped back to a raw perseus_question.

The Change

  • Refactor create_exercises to delegate to the AssessmentItemViewSet/serializer machinery (Introducing Content Curation #1), removing duplicated logic in the internal endpoint and nodes utils.
  • Accept QTI items (raw_data XML + media) directly; validate each against the schema (Ant's backend plus setting up front end files #2), rejecting non-compliant items with actionable errors.
  • Convert uploaded legacy/structured items to QTI on ingest via the resolves merge conflict that i allowed in... #6 conversion; leave raw Perseus as raw Perseus (handled by Browserify #8).
  • Unwrap any Perseus custom interaction (data-type='perseus'): read its referenced data-perseus-path payload from the upload and restore it as a raw perseus_question, rather than storing the custom interaction.
  • Map media/file dependencies so they are present at publish.

Acceptance Criteria

  • create_exercises delegates to the AssessmentItem serializer/machinery; duplicated internal-endpoint and nodes logic is removed
  • The API accepts and persists QTI items (raw_data XML + media)
  • Uploaded QTI is schema-validated (Ant's backend plus setting up front end files #2); 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-path payload and restoring the raw perseus_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.py
  • contentcuration/contentcuration/utils/nodes.py

AI usage

Architecture decided with the maintainer across an iterative session: blanket QTI type with the item XML in raw_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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No fields configured for Task.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions