Skip to content

feat: Configured subsection prerequisites persist during course olx/xml export/import#37475

Open
haftamuk wants to merge 3 commits into
openedx:masterfrom
haftamuk:ESHE
Open

feat: Configured subsection prerequisites persist during course olx/xml export/import#37475
haftamuk wants to merge 3 commits into
openedx:masterfrom
haftamuk:ESHE

Conversation

@haftamuk

@haftamuk haftamuk commented Oct 12, 2025

Copy link
Copy Markdown
Contributor

Configured subsection prerequisites persist during course olx/xml export/import

Overview

This PR introduces support for subsection (sequential) prerequisites in the OLX course format. Course authors can define prerequisite relationships between subsections with configurable completion criteria including minimum score and completion percentage requirements. Currently this information is lost during course import/export. This PR ensures configured subsection prerequisites are persisted during course olx/xml export/import. It allows course authors to define prerequisite relationships, have them exported to OLX format, and finally, have them properly imported.

Problem Statement

Currently, Open edX supports to define prerequisite relationships between subsections in Studio. This enables course authors from enforcing learning pathways where students must complete certain subsections before accessing others, which is crucial for structured learning experiences. But when a course is exported (XML/OLX) all configured relationships of subsections are lost and authors has to do it again manually in studio. This is time consuming and error prone!

Proposed Solution

  • Extend the element in OLX to support prerequisite definitions
  • Maintain full backward compatibility with existing OLX courses

Key Files

  1. Service Layer (xmodule/seq_block.py)

    • Adds prerequisite information to sequential XML for export.
  2. Import Processing Layer (xmodule/modulestore/xml_importer.py)

    • Processes prerequisite relationships during course import

OLX Format

Prerequisite information attached to sequential xml element

<sequential 
required_content="91d0290972c4488db10d7ca3694e13ca" 
min_score="100" 
min_completion="100" 
... >
    <vertical url_name="some_vertical"/>
   ...
</sequential>

Subsection prerequisite configuration how-to

  1. Settings -> Advanced -> Enable subsection prerequisites -> true
image

Note : Even after configuring a complete learning path for a course you can disable the gating feature by simply turning this in to false. Also, if you switch it back to true, all the previous configured learning path will appear with out further work. This means, switching this setting to true/false will not impact persisted learning path configuration, but will impact how the learner will interact with the course.

Note : When you export a course with this flag set to true, the exported XML will contain the information

<course cert_html_view_enabled="true" discussions_settings="{&quot;enable_graded_units&quot;: false, &quot;enable_in_context&quot;: true, &quot;provider_type&quot;: &quot;openedx&quot;, &quot;unit_level_visibility&quot;: true}" display_name="Saturday1"

enable_subsection_gating="true" 
end="null" language="en" start="2030-01-01T00:00:00Z">
  <chapter url_name="ca81aeb19a7f41a49f05a87c95fe299a"/>
  <chapter url_name="4d13584e169241bb890871bd44059d43"/>
  <wiki slug="Saturday1.Saturday1.Saturday1"/>
</course>

Later during import this setting will be applied to the destination course. This is also the case when it is set to false (the destination course will be enable_subsection_gating set to false)

  1. Make a subsection to serve as a prerequisite
image
  1. Use the subsection as a prerequisite for other subsection
image

How to test

python -Wd -m pytest -p no:randomly --ds=cms.envs.test ./xmodule/modulestore/tests/test_xml_importer.py::TestSequentialPrerequisitesImport::test_gating_api_calls

python -Wd -m pytest -p no:randomly --ds=cms.envs.test ./xmodule/tests/test_sequence.py::SequenceBlockTestCase::test_export_sequence_with_prerequisites

Linked Issue: #36995

Supporting information

  1. Unit Prerequisites Lost During Course Export/Import #36995
  2. https://discuss.openedx.org/t/request-for-comments-course-export-import-and-re-run/16508?u=haftamu.kebede

@openedx-webhooks openedx-webhooks added the open-source-contribution PR author is not from Axim or 2U label Oct 12, 2025
@openedx-webhooks

openedx-webhooks commented Oct 12, 2025

Copy link
Copy Markdown

Thanks for the pull request, @haftamuk!

This repository is currently maintained by @openedx/wg-maintenance-openedx-platform.

Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review.

🔘 Get product approval

If you haven't already, check this list to see if your contribution needs to go through the product review process.

  • If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the Product Working Group.
    • This process (including the steps you'll need to take) is documented here.
  • If it doesn't, simply proceed with the next step.
🔘 Provide context

To help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:

  • Dependencies

    This PR must be merged before / after / at the same time as ...

  • Blockers

    This PR is waiting for OEP-1234 to be accepted.

  • Timeline information

    This PR must be merged by XX date because ...

  • Partner information

    This is for a course on edx.org.

  • Supporting documentation
  • Relevant Open edX discussion forum threads
🔘 Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.

Details
Where can I find more information?

If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources:

When can I expect my changes to be merged?

Our goal is to get community contributions seen and reviewed as efficiently as possible.

However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:

  • The size and impact of the changes that it introduces
  • The need for product review
  • Maintenance status of the parent repository

💡 As a result it may take up to several weeks or months to complete a review and merge your PR.

@github-project-automation github-project-automation Bot moved this to Needs Triage in Contributions Oct 12, 2025
@haftamuk haftamuk force-pushed the ESHE branch 4 times, most recently from c847977 to d43f4b4 Compare October 13, 2025 08:41
@haftamuk haftamuk changed the title feat: Unit Prerequisites Lost During Course Export/Import feat: Subsection(sequential) prerequisites lost during course export/import Oct 13, 2025
@haftamuk haftamuk force-pushed the ESHE branch 4 times, most recently from 8a6be77 to f675094 Compare October 13, 2025 09:28
@haftamuk haftamuk marked this pull request as ready for review October 13, 2025 09:53

@tecoholic tecoholic 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.

@haftamuk Hi, the changes look good on the export side. I was able to verify that the <prerequisite> block is added to the output XML as expected. However, when I tried to reimport it in a new course, I ended up with this:

image

So, we are clearly missing the "import" part of the solution. Can you kindly add that functionality?

Additionally, I would recommend adding some unit test around the newly created functions. This is a very "core" part of the system and it's best to have unit tests in place.

@mphilbrick211 mphilbrick211 moved this from Needs Triage to In Eng Review in Contributions Oct 15, 2025
@haftamuk

Copy link
Copy Markdown
Contributor Author

So, we are clearly missing the "import" part of the solution. Can you kindly add that functionality?

Kindly see the import functionality is added!

@haftamuk

Copy link
Copy Markdown
Contributor Author

Additionally, I would recommend adding some unit test around the newly created functions. This is a very "core" part of the system and it's best to have unit tests in place.

@tecoholic I will proceed to ensure existing unit tests pass and introduce new unit tests for the main changes made.
Thank you.

@tecoholic

Copy link
Copy Markdown
Contributor

@haftamuk Thanks for updating the PR with the import implementation. It looks like you have used a Generative AI / LLM for the implementation and hence can't be used as is. Kindly consult the [official policy on use of LLMs for acceptable usage guidelines. In short, you can use it to experiment and create solutions, but the final code should be from the developer.

That doesn't mean we will have to discard this work. Let's use this as a base for the final solution.

I have an important request - for future work on this PR, please do not force-push changes. This will allow us to work ahead incrementally and rollback things if we end up doing something we don't want in the final solution. Kindly see my inline comments in the diff for specific details.

Comment thread cms/djangoapps/contentstore/tasks.py Outdated
Comment thread xmodule/modulestore/xml.py Outdated
Comment thread xmodule/modulestore/xml.py Outdated
Comment thread cms/djangoapps/contentstore/tasks.py
Comment thread xmodule/modulestore/xml.py Outdated
Comment thread xmodule/modulestore/xml_importer.py
Comment thread xmodule/seq_block.py Outdated
Comment thread xmodule/xml_block.py Outdated
Comment thread xmodule/xml_block.py Outdated
Comment thread cms/djangoapps/contentstore/tasks.py Outdated
@tecoholic

Copy link
Copy Markdown
Contributor

@haftamuk I realized, there is lot of things I have noted in comments. So, let's go step by step in addressing them

  1. Just do a pass on cleaning up the single line changes like empty lines, comments..etc.,
  2. Next, let's focus on the export XML format - this comment

Ping me for a review after that. Let's move on to the import part of the changes after that.

Comment thread openedx/core/lib/gating/services.py Outdated
Comment thread xmodule/xml_block.py Outdated
@tecoholic

Copy link
Copy Markdown
Contributor

@Agrendalath Hi, a gentle reminder on taking a look at this PR.

@Agrendalath

Copy link
Copy Markdown
Member

Sorry for the delay, @haftamuk, @tecoholic. I will review this later this week.

@haftamuk haftamuk force-pushed the ESHE branch 2 times, most recently from 053784a to d663324 Compare December 5, 2025 13:56
@haftamuk

haftamuk commented Dec 5, 2025

Copy link
Copy Markdown
Contributor Author

Hello @Agrendalath ,
i did rebased the PR branch on top of the recent changes. Also bringing this to top as a reminder.

Thank you.

@Agrendalath Agrendalath linked an issue Dec 10, 2025 that may be closed by this pull request

@Agrendalath Agrendalath left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hi @haftamuk, sorry for the delay. I reviewed non-test code and left some comments.

Comment thread xmodule/seq_block.py Outdated
Comment on lines +996 to +997
prereq_id is None
or not isinstance(prereq_id, str)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: the second condition already covers the first one.

Comment thread xmodule/seq_block.py
self.add_prerequisite_to_xml(xml_object)
return xml_object

def add_prerequisite_to_xml(self, xml_object):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The exports do not contain the information whether a subsection is available as a prerequisite: https://github.com/openedx/edx-platform/blob/d6633243a8397bb56eb21e38cc43efada4f05931/cms/templates/js/access-editor.underscore#L43-L55

@Agrendalath Agrendalath Jan 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@haftamuk, a reminder about this one. It should be reflected here and in the importer.

Comment thread xmodule/seq_block.py Outdated
Comment thread xmodule/seq_block.py Outdated
Comment thread xmodule/seq_block.py Outdated
Comment thread xmodule/modulestore/xml_importer.py Outdated
Comment thread xmodule/modulestore/xml_importer.py
Comment thread xmodule/modulestore/xml_importer.py Outdated

prerequisite_usage_key = course_key.make_usage_key('sequential', required_content)

gating_api.add_prerequisite(course_key, prerequisite_usage_key)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's consider the opposite scenario: the existing sequential in the course has prerequisites, but its equivalent in the course export does not. Should we delete the prerequisites in such a case?

Comment thread xmodule/modulestore/xml_importer.py Outdated
Comment thread xmodule/modulestore/xml_importer.py Outdated
Comment on lines +874 to +880
gating_api.set_required_content(
course_key,
block.location,
prerequisite_usage_key,
min_score,
min_completion
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will raise an exception if the subsection does not exist. It should be okay to mark the import as failed in this scenario (instead of silently ignoring the errors), but we should ensure that the error message is clear to the course author.

@haftamuk haftamuk force-pushed the ESHE branch 2 times, most recently from 061b9d2 to aaef363 Compare December 12, 2025 16:34
@mphilbrick211 mphilbrick211 moved this from Waiting on Author to In Eng Review in Contributions Dec 12, 2025
@haftamuk haftamuk force-pushed the ESHE branch 2 times, most recently from 3181af7 to 2c0ceab Compare December 15, 2025 06:54
@haftamuk

Copy link
Copy Markdown
Contributor Author

@Agrendalath
I have gone through the review comments. Kindly let me know if the solutions/approaches make sense.

Thank you.

@tecoholic

Copy link
Copy Markdown
Contributor

@Agrendalath A gentle reminder for a review here.

@Agrendalath Agrendalath left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@tecoholic, I did another pass. The redundant checks are gone, but the crucial edge cases from my previous review remain unaddressed.

cc: @haftamuk

Comment on lines +859 to +860
min_score = int(min_score)
min_completion = int(min_completion)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This (+catching the exceptions) is redundant. set_required_content already validates casting these variables to integers with _validate_min_score and raises GatingValidationError.

Comment thread xmodule/seq_block.py
self.add_prerequisite_to_xml(xml_object)
return xml_object

def add_prerequisite_to_xml(self, xml_object):

@Agrendalath Agrendalath Jan 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@haftamuk, a reminder about this one. It should be reflected here and in the importer.

Comment thread xmodule/seq_block.py
Comment on lines +994 to +997
prereq_usage_key_str, min_score, min_completion = prereq_info
if not isinstance(prereq_usage_key_str, str):
return
prereq_usage_key = UsageKey.from_string(prereq_usage_key_str)

@Agrendalath Agrendalath Jan 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@haftamuk, I did not test this one, but wouldn't it be sufficient to add prereq_usage_key_str to XML (without building the UsageKey?

Comment thread xmodule/modulestore/xml_importer.py Outdated
min_completion
)
except (GatingValidationError) as e:
logging.debug('Gating validation error : %s', {e})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@haftamuk, a reminder about this comment. Importing the course would still fail silently.

Comment thread xmodule/modulestore/xml_importer.py Outdated

prerequisite_usage_key = course_key.make_usage_key('sequential', required_content)
try:
gating_api.add_prerequisite(course_key, prerequisite_usage_key)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@haftamuk, a reminder about this comment.

sarina added a commit to openedx/docs.openedx.org that referenced this pull request Feb 3, 2026
@mphilbrick211

Copy link
Copy Markdown

Hi @haftamuk! Is this still in progress?

@mphilbrick211 mphilbrick211 added the waiting on author PR author needs to resolve review requests, answer questions, fix tests, etc. label Feb 25, 2026
@mphilbrick211

Copy link
Copy Markdown

Friendly ping on this, @haftamuk!

@mphilbrick211 mphilbrick211 added the inactive PR author has been unresponsive for several months label Jun 1, 2026
@haftamuk

Copy link
Copy Markdown
Contributor Author

@mphilbrick211, kindly facilitate CC review of the recent changes.
Thank you for your patience.

@mphilbrick211

Copy link
Copy Markdown

@Agrendalath would you be able to take another look at this?

@Agrendalath

Copy link
Copy Markdown
Member

@haftamuk, thanks for the updates. I will review this within the next 3 weeks.

cc: @mphilbrick211

@Agrendalath

Copy link
Copy Markdown
Member

@haftamuk, would you mind rebasing this on the master branch in the meantime? It's been a while, so I will need to review this from scratch anyway.

haftamuk and others added 2 commits July 1, 2026 08:28
…rt/import

     *  feat: adds prerequisite information attributes to exported OLX. e.g.
<sequential
required_content="91d0290972c4488db10d7ca3694e13ca"
min_score="100"
min_completion="100"
... >
    <vertical url_name="some_vertical"/>
   ...
</sequential>

    * feat: parse prerequisite information attributes during import and
create gating relationship.

Issue Link: openedx#36995
This commit contans fixes as per review recomendations. This commit
changes will be merged later after review approval
@haftamuk

haftamuk commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@Agrendalath I rebased it.

The import implementation collects the gating_information initially and persists at the end:
- This ensures all blocks in the course are imported before dealing with gating_information
- This prevents import order failures (e.g., when the prerequisite block
  appears after the block that references it).
- Missing prerequisite blocks are logged as errors and skipped, rather
  than failing the entire import.

This implementation avoids ordering dependencies(during imprt order of course components is
unpredictable/not sequantial). In this implementation, invalid relationships are
gracefully skipped with an error log instead of crashing the import.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

open-source-contribution PR author is not from Axim or 2U

Projects

Status: In Eng Review

Development

Successfully merging this pull request may close these issues.

Unit Prerequisites Lost During Course Export/Import

5 participants