feat: add lti proctoring provider option (#30950)

This commit is contained in:
alangsto
2022-09-08 13:53:23 -04:00
committed by GitHub
parent 6985bc3d1e
commit 92b60f11b2
5 changed files with 133 additions and 5 deletions

View File

@@ -7,6 +7,7 @@ from mock import patch
from django.conf import settings
from django.test.utils import override_settings
from django.urls import reverse
from edx_toggles.toggles.testutils import override_waffle_flag
from opaque_keys.edx.keys import CourseKey
from rest_framework import status
from rest_framework.test import APITestCase
@@ -14,6 +15,7 @@ from rest_framework.test import APITestCase
from common.djangoapps.student.tests.factories import GlobalStaffFactory
from common.djangoapps.student.tests.factories import InstructorFactory
from common.djangoapps.student.tests.factories import UserFactory
from openedx.core.djangoapps.course_apps.toggles import EXAMS_IDA
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
@@ -118,6 +120,46 @@ class ProctoringExamSettingsGetTests(ProctoringExamSettingsTestMixin, ModuleStor
assert response.status_code == status.HTTP_200_OK
assert response.data == self.get_expected_response_data(self.course, self.course_instructor)
@override_waffle_flag(EXAMS_IDA, active=False)
def test_providers_with_disabled_lti(self):
self.client.login(username=self.course_instructor.username, password=self.password)
response = self.make_request()
assert response.status_code == status.HTTP_200_OK
# expected data should not include lti_external value
expected_data = {
'proctored_exam_settings': {
'enable_proctored_exams': self.course.enable_proctored_exams,
'allow_proctoring_opt_out': self.course.allow_proctoring_opt_out,
'proctoring_provider': self.course.proctoring_provider,
'proctoring_escalation_email': self.course.proctoring_escalation_email,
'create_zendesk_tickets': self.course.create_zendesk_tickets,
},
'course_start_date': '2030-01-01T00:00:00Z',
'available_proctoring_providers': ['null'],
}
assert response.data == expected_data
@override_waffle_flag(EXAMS_IDA, active=True)
def test_providers_with_enabled_lti(self):
self.client.login(username=self.course_instructor.username, password=self.password)
response = self.make_request()
assert response.status_code == status.HTTP_200_OK
# expected data should include lti_external value
expected_data = {
'proctored_exam_settings': {
'enable_proctored_exams': self.course.enable_proctored_exams,
'allow_proctoring_opt_out': self.course.allow_proctoring_opt_out,
'proctoring_provider': self.course.proctoring_provider,
'proctoring_escalation_email': self.course.proctoring_escalation_email,
'create_zendesk_tickets': self.course.create_zendesk_tickets,
},
'course_start_date': '2030-01-01T00:00:00Z',
'available_proctoring_providers': ['lti_external', 'null'],
}
assert response.data == expected_data
@ddt.ddt
class ProctoringExamSettingsPostTests(ProctoringExamSettingsTestMixin, ModuleStoreTestCase, APITestCase):
@@ -339,3 +381,59 @@ class ProctoringExamSettingsPostTests(ProctoringExamSettingsTestMixin, ModuleSto
updated = modulestore().get_item(self.course.location)
assert updated.create_zendesk_tickets is create_zendesk_tickets
@override_waffle_flag(EXAMS_IDA, active=True)
def test_200_for_lti_provider(self):
self.client.login(username=self.global_staff.username, password=self.password)
PROCTORED_EXAMS_ENABLED_FEATURES = settings.FEATURES
PROCTORED_EXAMS_ENABLED_FEATURES['ENABLE_PROCTORED_EXAMS'] = True
with override_settings(FEATURES=PROCTORED_EXAMS_ENABLED_FEATURES):
data = self.get_request_data(
enable_proctored_exams=True,
proctoring_provider='lti_external',
)
response = self.make_request(data=data)
# response is correct
assert response.status_code == status.HTTP_200_OK
self.assertDictEqual(response.data, {
'proctored_exam_settings': {
'enable_proctored_exams': True,
'allow_proctoring_opt_out': True,
'proctoring_provider': 'lti_external',
'proctoring_escalation_email': None,
'create_zendesk_tickets': True,
}
})
# course settings have been updated
updated = modulestore().get_item(self.course.location)
assert updated.enable_proctored_exams is True
assert updated.proctoring_provider == 'lti_external'
@override_waffle_flag(EXAMS_IDA, active=False)
def test_400_for_disabled_lti(self):
self.client.login(username=self.global_staff.username, password=self.password)
PROCTORED_EXAMS_ENABLED_FEATURES = settings.FEATURES
PROCTORED_EXAMS_ENABLED_FEATURES['ENABLE_PROCTORED_EXAMS'] = True
with override_settings(FEATURES=PROCTORED_EXAMS_ENABLED_FEATURES):
data = self.get_request_data(
enable_proctored_exams=True,
proctoring_provider='lti_external',
)
response = self.make_request(data=data)
# response is correct
assert response.status_code == status.HTTP_400_BAD_REQUEST
self.assertDictEqual(response.data, {
'detail': [{
'proctoring_provider': "The selected proctoring provider, lti_external, is not a valid provider. "
"Please select from one of ['null']."
}]
})
# course settings have been updated
updated = modulestore().get_item(self.course.location)
assert updated.enable_proctored_exams is False
assert updated.proctoring_provider == 'null'

View File

@@ -10,6 +10,7 @@ from rest_framework.views import APIView
from cms.djangoapps.contentstore.views.course import get_course_and_check_access
from cms.djangoapps.models.settings.course_metadata import CourseMetadata
from xmodule.course_module import get_available_providers # lint-amnesty, pylint: disable=wrong-import-order
from openedx.core.djangoapps.course_apps.toggles import exams_ida_enabled
from openedx.core.lib.api.view_utils import view_auth_classes
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
@@ -98,9 +99,14 @@ class ProctoredExamSettingsView(APIView):
data = {}
data['proctored_exam_settings'] = proctored_exam_settings
data['available_proctoring_providers'] = get_available_providers()
data['course_start_date'] = course_metadata['start'].get('value')
available_providers = get_available_providers()
if not exams_ida_enabled(CourseKey.from_string(course_id)):
available_providers.remove('lti_external')
data['available_proctoring_providers'] = available_providers
serializer = ProctoredExamConfigurationSerializer(data)
return Response(serializer.data)
@@ -147,8 +153,8 @@ class ProctoredExamSettingsView(APIView):
# merge updated settings with all existing settings.
# do this because fields that could not be modified are excluded from the result
course_metadata = {**course_metadata, **updated_data}
updated_setttings = self._get_proctored_exam_setting_values(course_metadata)
serializer = ProctoredExamSettingsSerializer(updated_setttings)
updated_settings = self._get_proctored_exam_setting_values(course_metadata)
serializer = ProctoredExamSettingsSerializer(updated_settings)
return Response({
'proctored_exam_settings': serializer.data
})