diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index 5c33e156721b..bd0032ac2820 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -1497,8 +1497,9 @@ def test_get_json(handler): test_get_html('settings_handler') with override_waffle_flag(toggles.LEGACY_STUDIO_GRADING, True): test_get_html('grading_handler') - with override_waffle_flag(toggles.LEGACY_STUDIO_ADVANCED_SETTINGS, True): - test_get_html('advanced_settings_handler') + # advanced_settings_handler always redirects to MFE; just verify no 5xx + resp = self.client.get_html(get_url('advanced_settings_handler', course_key, 'course_key_string')) + self.assertIn(resp.status_code, [200, 302]) # noqa: PT009 test_get_json('textbooks_list_handler') # Test that studio updates load diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py index 5d726627f27e..42b4f0398504 100644 --- a/cms/djangoapps/contentstore/tests/test_course_settings.py +++ b/cms/djangoapps/contentstore/tests/test_course_settings.py @@ -30,7 +30,7 @@ from xblock.fields import Date from cms.djangoapps.contentstore import toggles -from cms.djangoapps.contentstore.utils import reverse_course_url, reverse_usage_url +from cms.djangoapps.contentstore.utils import get_advanced_settings_url, reverse_course_url, reverse_usage_url from cms.djangoapps.models.settings.course_grading import ( GRADING_POLICY_CHANGED_EVENT_TYPE, CourseGradingModel, @@ -124,7 +124,6 @@ def setUp(self): CourseStaffRole(self.course.id).add_users(self.nonstaff) @override_settings(FEATURES={'DISABLE_MOBILE_COURSE_AVAILABLE': True}) - @override_waffle_flag(toggles.LEGACY_STUDIO_ADVANCED_SETTINGS, True) def test_mobile_field_available(self): """ @@ -132,10 +131,9 @@ def test_mobile_field_available(self): when DISABLE_MOBILE_COURSE_AVAILABLE is true. """ - response = self.client.get_html(self.course_setting_url) - start = response.content.decode('utf-8').find("mobile_available") - end = response.content.decode('utf-8').find("}", start) - settings_fields = json.loads(response.content.decode('utf-8')[start + len("mobile_available: "):end + 1]) + response = self.client.get(self.course_setting_url, HTTP_ACCEPT='application/json') + data = json.loads(response.content.decode('utf-8')) + settings_fields = data.get('mobile_available') self.assertEqual(settings_fields["display_name"], "Mobile Course Available") # noqa: PT009 self.assertEqual(settings_fields["deprecated"], True) # noqa: PT009 @@ -147,7 +145,6 @@ def test_mobile_field_available(self): (False, True, True) ) @ddt.unpack - @override_waffle_flag(toggles.LEGACY_STUDIO_ADVANCED_SETTINGS, True) def test_discussion_fields_available(self, is_pages_and_resources_enabled, is_legacy_discussion_setting_enabled, fields_visible): """ @@ -156,14 +153,14 @@ def test_discussion_fields_available(self, is_pages_and_resources_enabled, with override_waffle_flag(ENABLE_PAGES_AND_RESOURCES_MICROFRONTEND, is_pages_and_resources_enabled): with override_waffle_flag(OVERRIDE_DISCUSSION_LEGACY_SETTINGS_FLAG, is_legacy_discussion_setting_enabled): - response = self.client.get_html(self.course_setting_url).content.decode('utf-8') - self.assertEqual('allow_anonymous' in response, fields_visible) # noqa: PT009 - self.assertEqual('allow_anonymous_to_peers' in response, fields_visible) # noqa: PT009 - self.assertEqual('discussion_blackouts' in response, fields_visible) # noqa: PT009 - self.assertEqual('discussion_topics' in response, fields_visible) # noqa: PT009 + response = self.client.get(self.course_setting_url, HTTP_ACCEPT='application/json') + data = json.loads(response.content.decode('utf-8')) + self.assertEqual('allow_anonymous' in data, fields_visible) # noqa: PT009 + self.assertEqual('allow_anonymous_to_peers' in data, fields_visible) # noqa: PT009 + self.assertEqual('discussion_blackouts' in data, fields_visible) # noqa: PT009 + self.assertEqual('discussion_topics' in data, fields_visible) # noqa: PT009 @ddt.data(False, True) - @override_waffle_flag(toggles.LEGACY_STUDIO_ADVANCED_SETTINGS, True) @override_waffle_flag(toggles.LEGACY_STUDIO_IMPORT, True) @override_waffle_flag(toggles.LEGACY_STUDIO_EXPORT, True) @override_waffle_flag(toggles.LEGACY_STUDIO_COURSE_TEAM, True) @@ -174,7 +171,9 @@ def test_disable_advanced_settings_feature(self, disable_advanced_settings): If this feature is enabled, only Django Staff/Superuser should be able to access the "Advanced Settings" page. For non-staff users the "Advanced Settings" tab link should not be visible. """ - advanced_settings_link_html = f"Advanced Settings".encode('utf-8') # noqa: UP012 # pylint: disable=line-too-long + advanced_settings_link_html = ( + f'Advanced Settings' + ).encode() with override_settings(FEATURES={ 'DISABLE_ADVANCED_SETTINGS': disable_advanced_settings, @@ -205,11 +204,11 @@ def test_disable_advanced_settings_feature(self, disable_advanced_settings): # Test that non-staff users can't access the "Advanced Settings" page. response = self.non_staff_client.get_html(self.course_setting_url) - self.assertEqual(response.status_code, 403 if disable_advanced_settings else 200) # noqa: PT009 + self.assertEqual(response.status_code, 403 if disable_advanced_settings else 302) # noqa: PT009 - # Test that staff users can access the "Advanced Settings" page. + # Test that staff users are redirected to the MFE advanced settings page. response = self.client.get_html(self.course_setting_url) - self.assertEqual(response.status_code, 200) # noqa: PT009 + self.assertEqual(response.status_code, 302) # noqa: PT009 @ddt.ddt diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index 35818125efab..81f547d1f25f 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -41,7 +41,6 @@ libraries_v1_enabled, libraries_v2_enabled, split_library_view_on_dashboard, - use_new_advanced_settings_page, use_new_certificates_page, use_new_course_team_page, use_new_export_page, @@ -317,13 +316,10 @@ def get_advanced_settings_url(course_locator) -> str: """ Gets course authoring microfrontend URL for advanced settings page view. """ - advanced_settings_url = None - if use_new_advanced_settings_page(course_locator): - mfe_base_url = get_course_authoring_url(course_locator) - course_mfe_url = f'{mfe_base_url}/course/{course_locator}/settings/advanced' - if mfe_base_url: - advanced_settings_url = course_mfe_url - return advanced_settings_url + mfe_base_url = get_course_authoring_url(course_locator) + if mfe_base_url: + return f'{mfe_base_url}/course/{course_locator}/settings/advanced' + return '' def get_grading_url(course_locator) -> str: diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 3d248944bdd5..8b9d39a4c7cf 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -78,7 +78,6 @@ from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.credit.tasks import update_credit_course_requirements from openedx.core.djangoapps.models.course_details import CourseDetails -from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangolib.js_utils import dump_js_escaped_json from openedx.core.lib.api.view_utils import view_auth_classes from openedx.core.lib.course_tabs import CourseTabPluginManager @@ -99,7 +98,6 @@ from ..tasks import rerun_course as rerun_course_task from ..toggles import ( default_enable_flexible_peer_openassessments, - use_new_advanced_settings_page, use_new_grading_page, use_new_group_configurations_page, use_new_schedule_details_page, @@ -115,7 +113,6 @@ get_group_configurations_context, get_group_configurations_url, get_lms_link_for_item, - get_proctored_exam_settings_url, get_schedule_details_url, get_studio_home_url, get_textbooks_url, @@ -1522,27 +1519,10 @@ def advanced_settings_handler(request, course_key_string): advanced_dict.get('mobile_available')['deprecated'] = True if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET': - if use_new_advanced_settings_page(course_key): - return redirect(get_advanced_settings_url(course_key)) - publisher_enabled = configuration_helpers.get_value_for_org( - course_block.location.org, - 'ENABLE_PUBLISHER', - settings.FEATURES.get('ENABLE_PUBLISHER', False) - ) - # gather any errors in the currently stored proctoring settings. - proctoring_errors = CourseMetadata.validate_proctoring_settings(course_block, advanced_dict, request.user) - - return render_to_response('settings_advanced.html', { - 'context_course': course_block, - 'advanced_dict': advanced_dict, - 'advanced_settings_url': reverse_course_url('advanced_settings_handler', course_key), - 'publisher_enabled': publisher_enabled, - 'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_block.id), - 'proctoring_errors': proctoring_errors, - }) + return redirect(get_advanced_settings_url(course_key)) elif 'application/json' in request.META.get('HTTP_ACCEPT', ''): if request.method == 'GET': - return JsonResponse(CourseMetadata.fetch(course_block)) + return JsonResponse(advanced_dict) else: try: return JsonResponse( diff --git a/cms/djangoapps/contentstore/views/tests/test_exam_settings_view.py b/cms/djangoapps/contentstore/views/tests/test_exam_settings_view.py index ef1d7f945dd7..693d749d1fb0 100644 --- a/cms/djangoapps/contentstore/views/tests/test_exam_settings_view.py +++ b/cms/djangoapps/contentstore/views/tests/test_exam_settings_view.py @@ -1,9 +1,6 @@ """ Exam Settings View Tests """ -from unittest import SkipTest -from unittest.mock import patch - import ddt import lxml from django.conf import settings @@ -12,7 +9,7 @@ from cms.djangoapps.contentstore import toggles from cms.djangoapps.contentstore.tests.utils import CourseTestCase -from cms.djangoapps.contentstore.utils import get_proctored_exam_settings_url, reverse_course_url +from cms.djangoapps.contentstore.utils import reverse_course_url from common.djangoapps.util.testing import UrlResetMixin @@ -55,7 +52,6 @@ def _get_exam_settings_alert_text(raw_html_content): "settings_handler", "group_configurations_list_handler", "grading_handler", - "advanced_settings_handler" ) def test_view_without_exam_settings_enabled(self, handler): """ @@ -72,7 +68,6 @@ def test_view_without_exam_settings_enabled(self, handler): "settings_handler", "group_configurations_list_handler", "grading_handler", - "advanced_settings_handler" ) def test_view_with_exam_settings_enabled(self, handler): """ @@ -83,148 +78,3 @@ def test_view_with_exam_settings_enabled(self, handler): resp = self.client.get(outline_url, HTTP_ACCEPT='text/html') self.assertEqual(resp.status_code, 200) # noqa: PT009 self.assertContains(resp, 'Proctored Exam Settings') - - @override_settings( - PROCTORING_BACKENDS={ - 'DEFAULT': 'test_proctoring_provider', - 'test_proctoring_provider': {"requires_escalation_email": True} - }, - ) - @ddt.data( - "advanced_settings_handler", - ) - def test_exam_settings_alert_with_exam_settings_enabled(self, page_handler): - """ - An alert should appear if current exam settings are invalid. - The exam settings alert should direct users to the exam settings page. - """ - # create an error by setting 'requires_escalation_email' as 'True' and not setting - # the (required) escalation contact - self.course.proctoring_provider = 'test_proctoring_provider' - self.course.enable_proctored_exams = True - self.save_course() - - # course_handler raise 404 for old mongo course - if self.course.id.deprecated: - raise SkipTest("course_handler raise 404 for old mongo course") - - url = reverse_course_url(page_handler, self.course.id) - resp = self.client.get(url, HTTP_ACCEPT='text/html') - alert_text = self._get_exam_settings_alert_text(resp.content) - assert ( - 'This course has proctored exam settings that are incomplete or invalid.' - in alert_text - ) - assert ( - 'To update these settings go to the Proctored Exam Settings page.' - in alert_text - ) - - @override_settings( - PROCTORING_BACKENDS={ - 'DEFAULT': 'test_proctoring_provider', - 'test_proctoring_provider': {"requires_escalation_email": True} - }, - ) - @ddt.data( - "advanced_settings_handler", - ) - @override_waffle_flag(toggles.LEGACY_STUDIO_EXAM_SETTINGS, True) - def test_exam_settings_alert_with_exam_settings_disabled(self, page_handler): - """ - An alert should appear if current exam settings are invalid. - The exam settings alert should direct users to the advanced settings page - if the exam settings feature is not available. - """ - # create an error by setting 'requires_escalation_email' as 'True' and not setting - # the (required) escalation contact - self.course.proctoring_provider = 'test_proctoring_provider' - self.course.enable_proctored_exams = True - self.save_course() - - # course_handler raise 404 for old mongo course - if self.course.id.deprecated and page_handler == 'course_handler': - raise SkipTest("course_handler raise 404 for old mongo course") - url = reverse_course_url(page_handler, self.course.id) - resp = self.client.get(url, HTTP_ACCEPT='text/html') - alert_text = self._get_exam_settings_alert_text(resp.content) - assert ( - 'This course has proctored exam settings that are incomplete or invalid.' - in alert_text - ) - self.maxDiff = None - if page_handler == 'advanced_settings_handler': - assert ( - 'You will be unable to make changes until the following settings are updated on the page below.' - in alert_text - ) - else: - assert 'To update these settings go to the Advanced Settings page.' in alert_text - - @override_settings( - PROCTORING_BACKENDS={ - 'DEFAULT': 'test_proctoring_provider', - 'test_proctoring_provider': {}, - }, - ) - @ddt.data( - "advanced_settings_handler", - ) - def test_invalid_provider_alert(self, page_handler): - """ - An alert should appear if the course has a proctoring provider that is not valid. - """ - # create an error by setting an invalid proctoring provider - self.course.proctoring_provider = 'invalid_provider' - self.course.enable_proctored_exams = True - self.save_course() - - url = reverse_course_url(page_handler, self.course.id) - resp = self.client.get(url, HTTP_ACCEPT='text/html') - alert_text = self._get_exam_settings_alert_text(resp.content) - assert ( - 'This course has proctored exam settings that are incomplete or invalid.' - in alert_text - ) - assert ( - 'The proctoring provider configured for this course, \'invalid_provider\', is not valid.' - in alert_text - ) - - @ddt.data( - "advanced_settings_handler", - ) - def test_exam_settings_alert_not_shown(self, page_handler): - """ - Alert should not be visible if no proctored exam setting error exists - """ - # course_handler raise 404 for old mongo course - if self.course.id.deprecated and page_handler == 'course_handler': - raise SkipTest("course_handler raise 404 for old mongo course") - url = reverse_course_url(page_handler, self.course.id) - resp = self.client.get(url, HTTP_ACCEPT='text/html') - parsed_html = lxml.html.fromstring(resp.content) - alert_nodes = parsed_html.find_class('exam-settings-alert') - assert len(alert_nodes) == 0 - - @patch('cms.djangoapps.models.settings.course_metadata.CourseMetadata.validate_proctoring_settings') - def test_proctoring_link_is_visible(self, mock_validate_proctoring_settings): - - """ - Test to check proctored exam settings mfe url is rendering properly - """ - mock_validate_proctoring_settings.return_value = [ - { - 'key': 'proctoring_provider', - 'message': 'error message', - 'model': {'display_name': 'proctoring_provider'} - }, - { - 'key': 'proctoring_provider', - 'message': 'error message', - 'model': {'display_name': 'proctoring_provider'} - } - ] - response = self.client.get_html(reverse_course_url('advanced_settings_handler', self.course.id)) - proctored_exam_settings_url = get_proctored_exam_settings_url(self.course.id) - self.assertContains(response, proctored_exam_settings_url, 3) diff --git a/cms/static/cms/js/build.js b/cms/static/cms/js/build.js index 73089ed04a76..b2c57ceb4548 100644 --- a/cms/static/cms/js/build.js +++ b/cms/static/cms/js/build.js @@ -27,7 +27,6 @@ 'js/factories/manage_users', 'js/factories/outline', 'js/factories/settings', - 'js/factories/settings_advanced', 'js/factories/settings_graders' ]), /** diff --git a/cms/static/js/factories/settings_advanced.js b/cms/static/js/factories/settings_advanced.js deleted file mode 100644 index 4ddc2305d6f6..000000000000 --- a/cms/static/js/factories/settings_advanced.js +++ /dev/null @@ -1,52 +0,0 @@ -define([ - 'jquery', 'gettext', 'js/models/settings/advanced', 'js/views/settings/advanced' -], function($, gettext, AdvancedSettingsModel, AdvancedSettingsView) { - 'use strict'; - - return function(advancedDict, advancedSettingsUrl, publisherEnabled) { - var advancedModel, editor; - - $('form :input') - .focus(function() { - $('label[for="' + this.id + '"]').addClass('is-focused'); - }) - .blur(function() { - $('label').removeClass('is-focused'); - }); - - // proactively populate advanced b/c it has the filtered list and doesn't really follow the model pattern - advancedModel = new AdvancedSettingsModel(advancedDict, {parse: true}); - advancedModel.url = advancedSettingsUrl; - - // set the hidden property to true on relevant fields if publisher is enabled - if (publisherEnabled && advancedModel.attributes) { - Object.keys(advancedModel.attributes).forEach(function(am) { - var field = advancedModel.attributes[am]; - field.hidden = field.hide_on_enabled_publisher; - }); - } - - editor = new AdvancedSettingsView({ - el: $('.settings-advanced'), - model: advancedModel - }); - editor.render(); - - $('#deprecated-settings').click(function() { - var $wrapperDeprecatedSetting = $('.wrapper-deprecated-setting'), - $deprecatedSettingsLabel = $('.deprecated-settings-label'); - - if ($(this).is(':checked')) { - $wrapperDeprecatedSetting.addClass('is-set'); - $deprecatedSettingsLabel.text(gettext('Hide Deprecated Settings')); - editor.render_deprecated = true; - } else { - $wrapperDeprecatedSetting.removeClass('is-set'); - $deprecatedSettingsLabel.text(gettext('Show Deprecated Settings')); - editor.render_deprecated = false; - } - - editor.render(); - }); - }; -}); diff --git a/cms/templates/settings_advanced.html b/cms/templates/settings_advanced.html deleted file mode 100644 index 3eccb3528d94..000000000000 --- a/cms/templates/settings_advanced.html +++ /dev/null @@ -1,160 +0,0 @@ -<%page expression_filter="h"/> -<%inherit file="base.html" /> -<%def name="online_help_token()"><% return "advanced" %>%def> -<%namespace name='static' file='static_content.html'/> -<%! - from six.moves.urllib.parse import quote - from django.utils.translation import gettext as _ - from cms.djangoapps.contentstore import utils - from openedx.core.djangolib.js_utils import ( - dump_js_escaped_json, js_escaped_string - ) - from openedx.core.djangolib.markup import HTML, Text -%> -<%block name="title">${_("Advanced Settings")}%block> -<%block name="bodyclass">is-signedin course advanced view-settings%block> - -<%block name="header_extras"> -% for template_name in ["advanced_entry", "basic-modal", "modal-button", "validation-error-modal"]: - -% endfor -%block> - -<%block name="requirejs"> - require(["js/factories/settings_advanced"], function(SettingsAdvancedFactory) { - SettingsAdvancedFactory( - ${advanced_dict | n, dump_js_escaped_json}, - "${advanced_settings_url | n, js_escaped_string}", - ${publisher_enabled | n, dump_js_escaped_json} - ); - }); -%block> - -<%block name="page_alert"> - %if proctoring_errors: -
- % if mfe_proctored_exam_settings_url: - <% url_encoded_course_id = quote(str(context_course.id).encode('utf-8'), safe='') %> - ${Text(_("You will be unable to make changes until the errors are resolved. To update these settings go to the {link_start}Proctored Exam Settings page{link_end}.")).format( - link_start=HTML('').format( - mfe_proctored_exam_settings_url=mfe_proctored_exam_settings_url - ), - link_end=HTML("") - )} - % else: - ${_("You will be unable to make changes until the following settings are updated on the page below.")} - % endif -
-