Skip to content

feat: redirect to the embargo blocked-message page on error_code 'embargo' - #2055

Open
asadali145 wants to merge 1 commit into
openedx:masterfrom
mitodl:asadali145/embargo-mfe-redirect
Open

feat: redirect to the embargo blocked-message page on error_code 'embargo'#2055
asadali145 wants to merge 1 commit into
openedx:masterfrom
mitodl:asadali145/embargo-mfe-redirect

Conversation

@asadali145

@asadali145 asadali145 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary

course_access.errorCode can now come back as embargo (a country-embargo block, reported by the LMS course_metadata endpoint - companion backend change: openedx/openedx-platform#39079). It previously fell into getAccessDeniedRedirectUrl's default case: dates/progress redirected to course home, but the outline tab rendered anyway - the "show the page anyway" behavior that's correct for enrollment_required (so an unenrolled learner can preview the outline), but wrong for a sanctions block, which has no preview concept.

Supersedes #2054, which took a different (data-layer) approach to a related embargo-MFE gap; closed in favor of this PR once the backend PR was scoped down to the course_metadata endpoint only.

What changed

  • src/shared/access.js - adds a dedicated 'embargo' case to getAccessDeniedRedirectUrl that redirects every tab, including outline, to /redirect/embargo.
  • src/constants.ts / src/courseware/CoursewareRedirectLandingPage.jsx - registers that route using the existing /redirect/* landing-page pattern (RedirectPage + CoursewareRedirectLandingPage, the same mechanism dashboard/consent/survey redirects already use), pointing at the legacy embargo "blocked message" page (/embargo/blocked-message/courseware/default/) so an embargoed learner sees the same sanctions-specific copy the legacy courseware view already redirects to.
Implementation details

The redirect target is hardcoded to the generic default blocked-message path rather than passed dynamically from the backend. RestrictedCourse supports a per-course custom embargo message, which this won't respect - a deliberate scope trade-off (avoids new backend-to-frontend plumbing for a feature not currently in use), not an oversight.

generatePath() strips the trailing slash from the static pattern before the redirect; Django's APPEND_SLASH restores it with a 301, one harmless extra hop on what's already a full-page navigation.

Testing

npx jest src/shared/access.test.js src/courseware/CoursewareRedirectLandingPage.test.jsx - all passing, including new cases covering the embargo redirect for both the outline tab and a non-outline tab, and the landing-page route itself.

Manual testing

Requires the companion backend PR (openedx/openedx-platform#39079) running - this PR alone has no effect, since nothing produces errorCode: 'embargo' without it.

Mark results as you go - [x] pass, [!] problem (add a note).

  1. Check out both branches in a local devstack: this PR here, and fix: enforce GlobalRestrictedCountry on course access, not just registration openedx-platform#39079 for edx-platform.
  2. In a Django/LMS shell (or /admin/embargo/globalrestrictedcountry/), add a country to GlobalRestrictedCountry:
    from openedx.core.djangoapps.embargo.models import Country, GlobalRestrictedCountry
    country, _ = Country.objects.get_or_create(country='IR')
    GlobalRestrictedCountry.objects.get_or_create(country=country)
  3. Confirm settings.EMBARGO is True for your devstack (it defaults True under lms.envs.tutor.development; False in general envs/common.py).
  4. Set a test learner's profile country to the same code - easiest via shell, since IP-header spoofing needs browser tooling:
    from django.contrib.auth import get_user_model
    from django.core.cache import cache
    user = get_user_model().objects.get(username='<test-learner>')
    user.profile.country = 'IR'
    user.profile.save()
    cache.clear()
  5. Log in as that learner and visit any Learning MFE course tab, e.g. .../learning/course/<course_id>/home.
    • Redirected to the LMS's /embargo/blocked-message/courseware/default/, showing "This Course Unavailable In Your Country" - from the outline/home tab specifically (previously rendered the course anyway).
    • Same redirect from dates and progress tabs.
  6. Log in as a course team member / staff for the same course.
    • Course loads normally - staff/course-author bypass is unaffected.
  7. Clean up: remove the GlobalRestrictedCountry row and reset the test learner's profile.country.

Additional Context

Depends on / must merge after openedx/openedx-platform#39079 (the backend change is what actually produces errorCode: 'embargo' - this PR only changes how the frontend reacts to it).

…argo'

course_access.errorCode can now be 'embargo' (a country-embargo block,
reported by the LMS course_metadata endpoint). It previously fell into
getAccessDeniedRedirectUrl's default case: dates/progress redirected to
course home, but the outline tab rendered anyway - the wrong behavior for
a sanctions block, which has no "preview" concept unlike enrollment_required.

Adds a dedicated 'embargo' case that redirects every tab, including
outline, to the same legacy embargo "blocked message" page
(/embargo/blocked-message/courseware/default/) the legacy courseware view
already redirects to - reusing the existing /redirect/* landing-page
pattern (RedirectPage + CoursewareRedirectLandingPage) used by
dashboard/consent/survey redirects.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@openedx-webhooks openedx-webhooks added the open-source-contribution PR author is not from Axim or 2U label Sep 8, 2026
@openedx-webhooks

Copy link
Copy Markdown

Thanks for the pull request, @asadali145!

This repository is currently maintained by @openedx/committers-frontend-app-learning.

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.

@codecov

codecov Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.59%. Comparing base (020a3ee) to head (50fc953).
⚠️ Report is 23 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2055      +/-   ##
==========================================
+ Coverage   93.53%   93.59%   +0.05%     
==========================================
  Files         363      367       +4     
  Lines        5905     6007     +102     
  Branches     1367     1383      +16     
==========================================
+ Hits         5523     5622      +99     
- Misses        367      369       +2     
- Partials       15       16       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

The changes are small, align with the stated behavior for embargo blocks, and include targeted automated test coverage for both the access-layer redirect and the landing-page route.

Pull request overview

Adds explicit handling for the new course_access.errorCode: 'embargo' case so embargo-blocked learners are redirected away from all Learning MFE course tabs (including outline) to the legacy LMS embargo “blocked message” page via the existing /redirect/* landing-page mechanism.

Changes:

  • Add an 'embargo' case in getAccessDeniedRedirectUrl to redirect all tabs to /redirect/embargo.
  • Register /redirect/embargo in the redirect landing page and map it to /embargo/blocked-message/courseware/default/ on the LMS.
  • Add Jest coverage for the new access redirect behavior and the new landing-page route.
File summaries
File Description
src/shared/access.js Adds 'embargo' redirect handling to route all tabs to /redirect/embargo.
src/shared/access.test.js Adds tests verifying embargo redirects (outline and non-outline).
src/constants.ts Registers new ROUTES.EMBARGO and REDIRECT_MODES.EMBARGO_REDIRECT constants.
src/courseware/CoursewareRedirectLandingPage.jsx Adds /redirect/embargo landing-page route that redirects to the LMS embargo blocked-message page.
src/courseware/CoursewareRedirectLandingPage.test.jsx Adds test verifying the embargo landing-page redirect target URL.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@asadali145 asadali145 moved this from Needs Triage to Ready for Review in Contributions Sep 8, 2026
asadali145 added a commit to mitodl/edx-platform that referenced this pull request Sep 8, 2026
…stration

GlobalRestrictedCountry (added in openedx#36202/openedx#36398) only blocked account
registration and profile-country changes - it had no effect on course
access. The only mechanism enforcing course access was RestrictedCourse +
CountryAccessRule, which needs a row per course, so there was no way to
block a country from every course at once.

Wires GlobalRestrictedCountry into embargo.api.check_course_access() so a
listed country blocks every course, with or without a RestrictedCourse
entry. Per-course CountryAccessRule checks still apply on top where
configured, staff still bypass every check, and a per-course
disable_access_check override can never bypass a global block (only a
per-course one).

Also closes a related enforcement gap for the Learning MFE: the
course_metadata BFF endpoint (the one endpoint the MFE already reads a
course_access hasAccess/errorCode flag from to redirect denied learners)
now runs the same embargo check directly via a new check_embargo_access()
helper, so an embargoed learner's course_access.errorCode comes back as
"embargo". This is deliberately scoped to course_metadata only, not the
shared check_course_access() that outline/dates/progress/navigation route
through - wiring it there too would hard-403 those endpoints, which broke
the Learning MFE (companion frontend fix: openedx/frontend-app-learning#2055
makes the MFE redirect away from every tab, including outline, on
errorCode "embargo").

Motivating use case: mitodl/hq#13170 (OFAC embargo requirement). No
migration (reuses the existing GlobalRestrictedCountry table), no
behavior change for existing deployments (both tables are empty by
default everywhere).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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: Ready for Review

Development

Successfully merging this pull request may close these issues.

4 participants