Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions cms/djangoapps/contentstore/tests/test_contentstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 16 additions & 17 deletions cms/djangoapps/contentstore/tests/test_course_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -124,18 +124,16 @@ 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):

"""
Test to check `Mobile Course Available` field is not viewable in Studio
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
Expand All @@ -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):
"""
Expand All @@ -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)
Expand All @@ -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"<a href=\"{self.course_setting_url}\">Advanced Settings</a>".encode('utf-8') # noqa: UP012 # pylint: disable=line-too-long
advanced_settings_link_html = (
f'<a href="{get_advanced_settings_url(self.course.id)}">Advanced Settings</a>'
).encode()

with override_settings(FEATURES={
'DISABLE_ADVANCED_SETTINGS': disable_advanced_settings,
Expand Down Expand Up @@ -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
Expand Down
12 changes: 4 additions & 8 deletions cms/djangoapps/contentstore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand Down
24 changes: 2 additions & 22 deletions cms/djangoapps/contentstore/views/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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(
Expand Down
152 changes: 1 addition & 151 deletions cms/djangoapps/contentstore/views/tests/test_exam_settings_view.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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


Expand Down Expand Up @@ -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):
"""
Expand All @@ -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):
"""
Expand All @@ -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)
1 change: 0 additions & 1 deletion cms/static/cms/js/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
'js/factories/manage_users',
'js/factories/outline',
'js/factories/settings',
'js/factories/settings_advanced',
'js/factories/settings_graders'
]),
/**
Expand Down
Loading
Loading