Skip to content

Commit f81f028

Browse files
feat!: Simplify import/export page redirects to always use MFE for courses.
The import and export pages in Studio have been replaced with new views in the Authoring MFE for courses. The legacy condition guarded by the 'legacy_studio.import' and 'legacy_studio.export' waffle flags is removed. Courses now always redirect to the MFE; libraries continue to use the legacy HTML page as v2 libraries are not yet fully rolled out. This work is part of #36108 BREAKING CHANGE: The 'legacy_studio.import' and 'legacy_studio.export' waffle flags will no longer be respected for courses. The system will behave as if the flags are set to false permanently for courses.
1 parent fd54b24 commit f81f028

9 files changed

Lines changed: 26 additions & 137 deletions

File tree

cms/djangoapps/contentstore/rest_api/v1/serializers/course_waffle_flags.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,13 @@ def get_use_new_import_page(self, obj):
111111
"""
112112
Method to get the use_new_import_page switch
113113
"""
114-
course_key = self.get_course_key()
115-
return toggles.use_new_import_page(course_key)
114+
return True
116115

117116
def get_use_new_export_page(self, obj):
118117
"""
119118
Method to get the use_new_export_page switch
120119
"""
121-
course_key = self.get_course_key()
122-
return toggles.use_new_export_page(course_key)
120+
return True
123121

124122
def get_use_new_files_uploads_page(self, obj):
125123
"""

cms/djangoapps/contentstore/tests/test_contentstore.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,11 +1487,11 @@ def test_get_json(handler):
14871487
self.assertContains(resp, 'Chapter 2')
14881488

14891489
# go to various pages
1490-
with override_waffle_flag(toggles.LEGACY_STUDIO_IMPORT, True):
1491-
test_get_html('import_handler')
1492-
with override_waffle_flag(toggles.LEGACY_STUDIO_EXPORT, True):
1493-
test_get_html('export_handler')
14941490
with override_settings(COURSE_AUTHORING_MICROFRONTEND_URL='https://mfe.example'):
1491+
resp = self.client.get_html(get_url('import_handler', course_key, 'course_key_string'))
1492+
self.assertEqual(resp.status_code, 302) # noqa: PT009
1493+
resp = self.client.get_html(get_url('export_handler', course_key, 'course_key_string'))
1494+
self.assertEqual(resp.status_code, 302) # noqa: PT009
14951495
resp = self.client.get_html(get_url('course_team_handler', course_key, 'course_key_string'))
14961496
self.assertEqual(resp.status_code, 302) # noqa: PT009
14971497
with override_settings(COURSE_AUTHORING_MICROFRONTEND_URL='https://mfe.example'):

cms/djangoapps/contentstore/tests/test_course_settings.py

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@
2929
from pytz import UTC
3030
from xblock.fields import Date
3131

32-
from cms.djangoapps.contentstore import toggles
33-
from cms.djangoapps.contentstore.utils import get_advanced_settings_url, reverse_course_url, reverse_usage_url
32+
from cms.djangoapps.contentstore.utils import reverse_course_url, reverse_usage_url
3433
from cms.djangoapps.models.settings.course_grading import (
3534
GRADING_POLICY_CHANGED_EVENT_TYPE,
3635
CourseGradingModel,
@@ -160,45 +159,17 @@ def test_discussion_fields_available(self, is_pages_and_resources_enabled,
160159
self.assertEqual('discussion_topics' in data, fields_visible) # noqa: PT009
161160

162161
@ddt.data(False, True)
163-
@override_waffle_flag(toggles.LEGACY_STUDIO_IMPORT, True)
164-
@override_waffle_flag(toggles.LEGACY_STUDIO_EXPORT, True)
165162
def test_disable_advanced_settings_feature(self, disable_advanced_settings):
166163
"""
167-
If this feature is enabled, only Django Staff/Superuser should be able to access the "Advanced Settings" page.
168-
For non-staff users the "Advanced Settings" tab link should not be visible.
164+
When DISABLE_ADVANCED_SETTINGS is enabled, non-staff users should receive
165+
a 403 on the advanced settings URL; staff users should always be redirected.
169166
"""
170167
with override_settings(FEATURES={
171168
'DISABLE_ADVANCED_SETTINGS': disable_advanced_settings,
172169
}, COURSE_AUTHORING_MICROFRONTEND_URL='https://mfe.example'):
173-
advanced_settings_link_html = (
174-
f'<a href="{get_advanced_settings_url(self.course.id)}">Advanced Settings</a>'
175-
).encode()
176-
for handler in (
177-
'import_handler',
178-
'export_handler',
179-
):
180-
# Test that non-staff users don't see the "Advanced Settings" tab link.
181-
response = self.non_staff_client.get_html(
182-
get_url(self.course.id, handler)
183-
)
184-
self.assertEqual(response.status_code, 200) # noqa: PT009
185-
if disable_advanced_settings:
186-
self.assertNotIn(advanced_settings_link_html, response.content) # noqa: PT009
187-
else:
188-
self.assertIn(advanced_settings_link_html, response.content) # noqa: PT009
189-
190-
# Test that staff users see the "Advanced Settings" tab link.
191-
response = self.client.get_html(
192-
get_url(self.course.id, handler)
193-
)
194-
self.assertEqual(response.status_code, 200) # noqa: PT009
195-
self.assertIn(advanced_settings_link_html, response.content) # noqa: PT009
196-
197-
# Test that non-staff users can't access the "Advanced Settings" page.
198170
response = self.non_staff_client.get_html(self.course_setting_url)
199171
self.assertEqual(response.status_code, 403 if disable_advanced_settings else 302) # noqa: PT009
200172

201-
# Test that staff users are redirected to the MFE advanced settings page.
202173
response = self.client.get_html(self.course_setting_url)
203174
self.assertEqual(response.status_code, 302) # noqa: PT009
204175

cms/djangoapps/contentstore/tests/tests.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
This test file will test registration, login, activation, and session activity timeouts
33
44
TODO: Rewrite several of these assertions so that they check the output of the REST or Python
5-
APIs rather than parsing HTML from the deprecated legacy frontend pages. In particular, any
6-
test case using override_waffle_flag(toggles.LEGACY_STUDIO_*, True) will need to be fixed.
7-
Part of https://github.com/openedx/edx-platform/issues/36275.
5+
APIs rather than parsing HTML from the deprecated legacy frontend pages.
86
"""
97

108

@@ -17,10 +15,8 @@
1715
from django.core.cache import cache
1816
from django.test.utils import override_settings
1917
from django.urls import reverse
20-
from edx_toggles.toggles.testutils import override_waffle_flag
2118
from pytz import UTC
2219

23-
from cms.djangoapps.contentstore import toggles
2420
from cms.djangoapps.contentstore.tests.test_course_settings import CourseTestCase
2521
from cms.djangoapps.contentstore.tests.utils import AjaxEnabledTestClient, parse_json, registration, user
2622
from cms.djangoapps.contentstore.utils import get_studio_home_url
@@ -237,20 +233,19 @@ def setUp(self):
237233
super().setUp()
238234
self.course = CourseFactory.create(org='edX', number='test_course_key', display_name='Test Course')
239235

240-
@data(('edX/test_course_key/Test_Course', 200), ('garbage:edX+test_course_key+Test_Course', 404))
236+
@data(('edX/test_course_key/Test_Course', 302, 200), ('garbage:edX+test_course_key+Test_Course', 404, 404))
241237
@unpack
242-
@override_waffle_flag(toggles.LEGACY_STUDIO_IMPORT, True)
243-
def test_course_key_decorator(self, course_key, status_code):
238+
def test_course_key_decorator(self, course_key, import_status_code, import_status_handler_code):
244239
"""
245240
Tests for the ensure_valid_course_key decorator.
246241
"""
247242
url = f'/import/{course_key}'
248243
resp = self.client.get_html(url)
249-
self.assertEqual(resp.status_code, status_code) # noqa: PT009
244+
self.assertEqual(resp.status_code, import_status_code) # noqa: PT009
250245

251246
url = '/import_status/{course_key}/{filename}'.format(
252247
course_key=course_key,
253248
filename='xyz.tar.gz'
254249
)
255250
resp = self.client.get_html(url)
256-
self.assertEqual(resp.status_code, status_code) # noqa: PT009
251+
self.assertEqual(resp.status_code, import_status_handler_code) # noqa: PT009

cms/djangoapps/contentstore/toggles.py

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -161,43 +161,6 @@ def use_react_markdown_editor(course_key):
161161

162162

163163

164-
# .. toggle_name: legacy_studio.import
165-
# .. toggle_implementation: WaffleFlag
166-
# .. toggle_default: False
167-
# .. toggle_description: Temporarily fall back to the old Course Import page.
168-
# .. toggle_use_cases: temporary
169-
# .. toggle_creation_date: 2025-03-14
170-
# .. toggle_target_removal_date: 2025-09-14
171-
# .. toggle_tickets: https://github.com/openedx/edx-platform/issues/36275
172-
# .. toggle_warning: In Ulmo, this toggle will be removed. Only the new (React-based) experience will be available.
173-
LEGACY_STUDIO_IMPORT = CourseWaffleFlag('legacy_studio.import', __name__)
174-
175-
176-
def use_new_import_page(course_key):
177-
"""
178-
Returns a boolean if new studio import mfe is enabled
179-
"""
180-
return not LEGACY_STUDIO_IMPORT.is_enabled(course_key)
181-
182-
183-
# .. toggle_name: legacy_studio.export
184-
# .. toggle_implementation: WaffleFlag
185-
# .. toggle_default: False
186-
# .. toggle_description: Temporarily fall back to the old Course Export page.
187-
# .. toggle_use_cases: temporary
188-
# .. toggle_creation_date: 2025-03-14
189-
# .. toggle_target_removal_date: 2025-09-14
190-
# .. toggle_tickets: https://github.com/openedx/edx-platform/issues/36275
191-
# .. toggle_warning: In Ulmo, this toggle will be removed. Only the new (React-based) experience will be available.
192-
LEGACY_STUDIO_EXPORT = CourseWaffleFlag('legacy_studio.export', __name__)
193-
194-
195-
def use_new_export_page(course_key):
196-
"""
197-
Returns a boolean if new studio export mfe is enabled
198-
"""
199-
return not LEGACY_STUDIO_EXPORT.is_enabled(course_key)
200-
201164

202165
# .. toggle_name: contentstore.new_studio_mfe.use_new_video_uploads_page
203166
# .. toggle_implementation: CourseWaffleFlag

cms/djangoapps/contentstore/utils.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@
4141
libraries_v1_enabled,
4242
libraries_v2_enabled,
4343
split_library_view_on_dashboard,
44-
use_new_export_page,
45-
use_new_import_page,
4644
use_new_unit_page,
4745
)
4846
from cms.djangoapps.models.settings.course_grading import CourseGradingModel
@@ -346,30 +344,24 @@ def get_updates_url(course_locator) -> str:
346344
return updates_url
347345

348346

349-
def get_import_url(course_locator) -> str:
347+
def get_import_url(course_locator) -> str | None:
350348
"""
351349
Gets course authoring microfrontend URL for import page view.
352350
"""
353-
import_url = None
354-
if use_new_import_page(course_locator):
355-
mfe_base_url = get_course_authoring_url(course_locator)
356-
course_mfe_url = f'{mfe_base_url}/course/{course_locator}/import'
357-
if mfe_base_url:
358-
import_url = course_mfe_url
359-
return import_url
351+
mfe_base_url = get_course_authoring_url(course_locator)
352+
if mfe_base_url:
353+
return f'{mfe_base_url}/course/{course_locator}/import'
354+
return None
360355

361356

362-
def get_export_url(course_locator) -> str:
357+
def get_export_url(course_locator) -> str | None:
363358
"""
364359
Gets course authoring microfrontend URL for export page view.
365360
"""
366-
export_url = None
367-
if use_new_export_page(course_locator):
368-
mfe_base_url = get_course_authoring_url(course_locator)
369-
course_mfe_url = f'{mfe_base_url}/course/{course_locator}/export'
370-
if mfe_base_url:
371-
export_url = course_mfe_url
372-
return export_url
361+
mfe_base_url = get_course_authoring_url(course_locator)
362+
if mfe_base_url:
363+
return f'{mfe_base_url}/course/{course_locator}/export'
364+
return None
373365

374366

375367
def get_optimizer_url(course_locator) -> str:

cms/djangoapps/contentstore/views/import_export.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343

4444
from ..storage import course_import_export_storage
4545
from ..tasks import CourseExportTask, CourseImportTask, export_olx, import_olx
46-
from ..toggles import use_new_export_page, use_new_import_page
4746
from ..utils import IMPORTABLE_FILE_TYPES, get_export_url, get_import_url, reverse_course_url, reverse_library_url
4847

4948
__all__ = [
@@ -99,7 +98,7 @@ def import_handler(request, course_key_string):
9998
return _write_chunk(request, courselike_key)
10099
elif request.method == 'GET': # assume html
101100

102-
if use_new_import_page(courselike_key) and not library:
101+
if not library:
103102
return redirect(get_import_url(courselike_key))
104103
status_url = reverse_course_url(
105104
"import_status_handler", courselike_key, kwargs={'filename': "fillerName"}
@@ -358,7 +357,7 @@ def export_handler(request, course_key_string):
358357
export_olx.delay(request.user.id, course_key_string, request.LANGUAGE_CODE)
359358
return JsonResponse({'ExportStatus': 1})
360359
elif 'text/html' in requested_format:
361-
if use_new_export_page(course_key) and not library:
360+
if not library:
362361
return redirect(get_export_url(course_key))
363362
return render_to_response('export.html', context)
364363
else:

cms/djangoapps/contentstore/views/tests/test_import_export.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from django.core.exceptions import SuspiciousOperation
2424
from django.core.files.storage import FileSystemStorage
2525
from django.test.utils import override_settings
26-
from edx_toggles.toggles.testutils import override_waffle_flag
2726
from milestones.tests.utils import MilestonesTestCaseMixin
2827
from opaque_keys.edx.locator import LibraryLocator
2928
from openedx_authz.constants.roles import COURSE_DATA_RESEARCHER, COURSE_STAFF
@@ -34,7 +33,6 @@
3433
from user_tasks.models import UserTaskStatus
3534

3635
from cms.djangoapps.contentstore import errors as import_error
37-
from cms.djangoapps.contentstore import toggles
3836
from cms.djangoapps.contentstore.api.tests.base import BaseCourseViewTest
3937
from cms.djangoapps.contentstore.storage import course_import_export_storage
4038
from cms.djangoapps.contentstore.tests.test_libraries import LibraryTestCase
@@ -754,15 +752,6 @@ def setUp(self):
754752
self.url = reverse_course_url('export_handler', self.course.id)
755753
self.status_url = reverse_course_url('export_status_handler', self.course.id)
756754

757-
@override_waffle_flag(toggles.LEGACY_STUDIO_EXPORT, True)
758-
def test_export_html(self):
759-
"""
760-
Get the HTML for the page.
761-
"""
762-
resp = self.client.get_html(self.url)
763-
self.assertEqual(resp.status_code, 200) # noqa: PT009
764-
self.assertContains(resp, "Export My Course Content")
765-
766755
def test_export_json_unsupported(self):
767756
"""
768757
JSON is unsupported.

cms/templates/widgets/header.html

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,10 @@ <h1 class="branding">
3333
assets_url = reverse('assets_handler', kwargs={'course_key_string': str(course_key)})
3434
textbooks_url = reverse('textbooks_list_handler', kwargs={'course_key_string': str(course_key)})
3535
videos_url = reverse('videos_handler', kwargs={'course_key_string': str(course_key)})
36-
import_url = reverse('import_handler', kwargs={'course_key_string': str(course_key)})
3736
course_info_url = reverse('course_info_handler', kwargs={'course_key_string': str(course_key)})
38-
export_url = reverse('export_handler', kwargs={'course_key_string': str(course_key)})
3937
tabs_url = reverse('tabs_handler', kwargs={'course_key_string': str(course_key)})
4038
checklists_url = reverse('checklists_handler', kwargs={'course_key_string': str(course_key)})
4139
pages_and_resources_mfe_enabled = ENABLE_PAGES_AND_RESOURCES_MICROFRONTEND.is_enabled(context_course.id)
42-
import_mfe_enabled = toggles.use_new_import_page(context_course.id)
43-
export_mfe_enabled = toggles.use_new_export_page(context_course.id)
4440
optimizer_enabled = toggles.enable_course_optimizer(context_course.id)
4541
libraries_v2_enabled = toggles.libraries_v2_enabled()
4642

@@ -149,26 +145,12 @@ <h3 class="title"><span class="label">${_("Tools")}</span> <span class="icon fa
149145
<div class="wrapper wrapper-nav-sub">
150146
<div class="nav-sub">
151147
<ul>
152-
% if not import_mfe_enabled:
153-
<li class="nav-item nav-course-tools-import">
154-
<a href="${import_url}">${_("Import")}</a>
155-
</li>
156-
% endif
157-
% if import_mfe_enabled:
158148
<li class="nav-item nav-course-tools-import">
159149
<a href="${get_import_url(course_key)}">${_("Import")}</a>
160150
</li>
161-
% endif
162-
% if not export_mfe_enabled:
163-
<li class="nav-item nav-course-tools-export">
164-
<a href="${export_url}">${_("Export")}</a>
165-
</li>
166-
% endif
167-
% if export_mfe_enabled:
168151
<li class="nav-item nav-course-tools-export">
169152
<a href="${get_export_url(course_key)}">${_("Export")}</a>
170153
</li>
171-
% endif
172154
% if toggles.EXPORT_GIT.is_enabled() and context_course.giturl:
173155
<li class="nav-item nav-course-tools-export-git">
174156
<a href="${reverse('export_git', kwargs=dict(course_key_string=str(course_key)))}">${_("Export to Git")}</a>

0 commit comments

Comments
 (0)