From a6697a2a977a2a08108e6c38dbb70d821ed5ea6c Mon Sep 17 00:00:00 2001 From: Zachary Hancock Date: Fri, 15 Dec 2023 16:06:17 -0500 Subject: [PATCH] feat: add proctorio redirect url (#227) --- edx_exams/apps/core/admin.py | 8 +++++--- edx_exams/apps/lti/tests/test_views.py | 6 +++--- edx_exams/apps/lti/utils.py | 8 -------- edx_exams/apps/lti/views.py | 17 +++++++++-------- edx_exams/urls.py | 4 ++++ 5 files changed, 21 insertions(+), 22 deletions(-) delete mode 100644 edx_exams/apps/lti/utils.py diff --git a/edx_exams/apps/core/admin.py b/edx_exams/apps/core/admin.py index 78a57fcb..14551589 100644 --- a/edx_exams/apps/core/admin.py +++ b/edx_exams/apps/core/admin.py @@ -3,8 +3,7 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin from django.utils.translation import gettext_lazy as _ - -from edx_exams.apps.lti.utils import get_lti_root +from lti_consumer.utils import get_lti_api_base from .models import ( AssessmentControlResult, @@ -61,7 +60,10 @@ class ExamAttemptAdmin(admin.ModelAdmin): def change_view(self, request, object_id, form_url='', extra_context=None): extra_context = extra_context or {} - extra_context['LTI_ROOT'] = get_lti_root() + # technically this should be be using get_lti_view_base() but the + # setting behind that isn't available in edx-exams and we know they + # are the same in this service. + extra_context['LTI_ROOT'] = get_lti_api_base() return super().change_view( request, object_id, form_url, extra_context=extra_context, ) diff --git a/edx_exams/apps/lti/tests/test_views.py b/edx_exams/apps/lti/tests/test_views.py index e76aac72..1bfc1e0e 100644 --- a/edx_exams/apps/lti/tests/test_views.py +++ b/edx_exams/apps/lti/tests/test_views.py @@ -14,6 +14,7 @@ from lti_consumer.data import Lti1p3LaunchData, Lti1p3ProctoringLaunchData from lti_consumer.lti_1p3.extensions.rest_framework.authentication import Lti1p3ApiAuthentication from lti_consumer.models import LtiConfiguration, LtiProctoringConsumer +from lti_consumer.utils import get_lti_api_base from edx_exams.apps.api.test_utils import ExamsAPITestCase, UserFactory from edx_exams.apps.core.models import AssessmentControlResult, CourseStaffRole @@ -24,7 +25,6 @@ ExamFactory, ProctoringProviderFactory ) -from edx_exams.apps.lti.utils import get_lti_root log = logging.getLogger(__name__) @@ -404,7 +404,7 @@ def test_start_proctoring_launch_data(self, mock_get_lti_launch_url): self.client.get(self.url, **headers) expected_proctoring_start_assessment_url = urljoin( - get_lti_root(), + get_lti_api_base(), reverse('lti_consumer:lti_consumer.start_proctoring_assessment_endpoint') ) expected_proctoring_launch_data = Lti1p3ProctoringLaunchData( @@ -425,7 +425,7 @@ def test_start_proctoring_launch_data(self, mock_get_lti_launch_url): context_id=self.course_id, context_label=self.content_id, custom_parameters={ - 'custom_url': 'https://test.learning:2000/exam', + 'custom_url': 'test.exams:18740/browser_lock/', }, ) diff --git a/edx_exams/apps/lti/utils.py b/edx_exams/apps/lti/utils.py deleted file mode 100644 index 969cdba4..00000000 --- a/edx_exams/apps/lti/utils.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -LTI Utility Functions -""" -from django.conf import settings - - -def get_lti_root(): - return settings.ROOT_URL diff --git a/edx_exams/apps/lti/views.py b/edx_exams/apps/lti/views.py index c3ea04d3..5df74626 100644 --- a/edx_exams/apps/lti/views.py +++ b/edx_exams/apps/lti/views.py @@ -5,7 +5,7 @@ import logging from decimal import Decimal -from urllib.parse import urljoin +from urllib.parse import urljoin, urlparse from django.conf import settings from django.contrib.auth import login @@ -20,6 +20,7 @@ from lti_consumer.lti_1p3.extensions.rest_framework.authentication import Lti1p3ApiAuthentication from lti_consumer.lti_1p3.extensions.rest_framework.permissions import LtiProctoringAcsPermissions from lti_consumer.models import LtiConfiguration +from lti_consumer.utils import get_lti_api_base from rest_framework import status from rest_framework.decorators import api_view, authentication_classes, permission_classes from rest_framework.permissions import IsAuthenticated @@ -36,7 +37,6 @@ from edx_exams.apps.core.exceptions import ExamIllegalStatusTransition from edx_exams.apps.core.models import AssessmentControlResult, User from edx_exams.apps.core.statuses import ExamAttemptStatus -from edx_exams.apps.lti.utils import get_lti_root log = logging.getLogger(__name__) @@ -235,12 +235,12 @@ def start_proctoring(request, attempt_id): lti_config = LtiConfiguration.objects.get(id=lti_config_id) proctoring_start_assessment_url = urljoin( - get_lti_root(), + get_lti_api_base(), reverse('lti_consumer:lti_consumer.start_proctoring_assessment_endpoint') ) assessment_control_url = urljoin( - get_lti_root(), + get_lti_api_base(), reverse('lti:acs', kwargs={'lti_config_id': lti_config_id}), ) @@ -261,12 +261,13 @@ def start_proctoring(request, attempt_id): proctoring_launch_data=proctoring_launch_data, context_id=exam.course_id, context_label=exam.content_id, + custom_parameters={ + # The protocol is intentionally stripped from this url, the proctoring tool + # is appending https:// to anything we pass here. This is unavoidable at the moment. + 'custom_url': urlparse(get_lti_api_base()).netloc + reverse('browser_lock'), + }, ) - # temporary addition for testing with Proctorio in stage - if settings.LTI_CUSTOM_URL_CLAIM: # pragma: no cover - launch_data.custom_parameters['custom_url'] = settings.LTI_CUSTOM_URL_CLAIM - return redirect(get_lti_1p3_launch_start_url(launch_data)) diff --git a/edx_exams/urls.py b/edx_exams/urls.py index ef61ddb9..fb2e66a7 100644 --- a/edx_exams/urls.py +++ b/edx_exams/urls.py @@ -21,6 +21,7 @@ from django.conf import settings from django.contrib import admin from django.urls import include, path +from django.views.generic import RedirectView from edx_api_doc_tools import make_api_info, make_docs_urls from edx_exams.apps.api import urls as api_urls @@ -37,6 +38,9 @@ path('health/', core_views.Health.as_view(), name='health'), path('lti/', include(lti_urls)), path('lti/', include('lti_consumer.plugin.urls')), + # url for the exam inside the Proctorio browser extension the browser will fall through + # to this redirect if the browser extension is not installed + path('browser_lock/', RedirectView.as_view(url='https://getproctorio.com'), name='browser_lock'), ] if settings.DEBUG and os.environ.get('ENABLE_DJANGO_TOOLBAR', False): # pragma: no cover