From 55c576b2646c83c6786381a3a7ab08942a49778f Mon Sep 17 00:00:00 2001 From: Zach Hancock Date: Tue, 12 Sep 2023 13:01:07 -0400 Subject: [PATCH] feat: exam end return url --- edx_exams/apps/lti/tests/test_views.py | 15 +++++++++++---- edx_exams/apps/lti/views.py | 15 ++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/edx_exams/apps/lti/tests/test_views.py b/edx_exams/apps/lti/tests/test_views.py index 46b1ed6b..0817a8cb 100644 --- a/edx_exams/apps/lti/tests/test_views.py +++ b/edx_exams/apps/lti/tests/test_views.py @@ -8,6 +8,7 @@ import ddt from Cryptodome.PublicKey import RSA +from django.conf import settings from django.contrib.auth.models import AnonymousUser from django.urls import reverse from lti_consumer.data import Lti1p3LaunchData, Lti1p3ProctoringLaunchData @@ -488,7 +489,7 @@ def setUp(self): super().setUp() self.course_id = 'course-v1:edx+test+f19' - self.content_id = '11111111' + self.content_id = 'block-v1:edX+test+2023+type@sequential+block@1111111111' self.exam = ExamFactory( course_id=self.course_id, @@ -540,23 +541,29 @@ def test_get_end_assessment_url_launch_data(self, mock_get_lti_launch_url): message_type='LtiEndAssessment', proctoring_launch_data=expected_proctoring_launch_data, context_id=self.course_id, + launch_presentation_return_url=f'{settings.LEARNING_MICROFRONTEND_URL}/' + f'course/{self.course_id}/{self.content_id}', ) mock_get_lti_launch_url.assert_called_with(expected_launch_data) - def test_end_assessment_redirect(self, mock_get_lti_launch_url): + def test_end_assessment_requires_lti(self, mock_get_lti_launch_url): with patch('edx_exams.apps.lti.views.get_end_assessment_return', return_value=True): headers = self.build_jwt_headers(self.user) response = self.client.get(self.url, **headers) self.assertRedirects(response, mock_get_lti_launch_url.return_value, fetch_redirect_response=False) - def test_end_assessment_no_redirect(self, mock_get_lti_launch_url): # pylint: disable=unused-argument + def test_end_assessment_no_lti_endassessment(self, mock_get_lti_launch_url): # pylint: disable=unused-argument with patch('edx_exams.apps.lti.views.get_end_assessment_return', return_value=False): headers = self.build_jwt_headers(self.user) response = self.client.get(self.url, **headers) - self.assertEqual(response.status_code, 200) + self.assertRedirects( + response, + f'{settings.LEARNING_MICROFRONTEND_URL}/course/{self.course_id}/{self.content_id}', + fetch_redirect_response=False + ) def test_end_assessment_updated_attempt(self, mock_get_lti_launch_url): # pylint: disable=unused-argument """ diff --git a/edx_exams/apps/lti/views.py b/edx_exams/apps/lti/views.py index 97c68ba5..fea0e87b 100644 --- a/edx_exams/apps/lti/views.py +++ b/edx_exams/apps/lti/views.py @@ -8,7 +8,6 @@ from urllib.parse import urljoin from django.contrib.auth import login -from django.http import JsonResponse from django.shortcuts import redirect from django.urls import reverse from django.views.decorators.http import require_http_methods @@ -27,6 +26,7 @@ get_attempt_by_id, get_attempt_for_user_with_attempt_number_and_resource_id, get_exam_by_id, + get_exam_url_path, update_attempt_status ) from edx_exams.apps.core.exceptions import ExamIllegalStatusTransition @@ -290,11 +290,6 @@ def end_assessment(request, attempt_id): update_attempt_status(attempt_id, ExamAttemptStatus.submitted) - # user is authenticated via JWT so use that to create a - # session with this service's authentication backend - request.user.backend = EDX_OAUTH_BACKEND - login(request, user) - exam = attempt.exam resource_link_id = exam.resource_id end_assessment_return = get_end_assessment_return(request.user.anonymous_user_id, resource_link_id) @@ -303,6 +298,11 @@ def end_assessment(request, attempt_id): # Platform MUST send an End Assessment message to the Proctoring Tool. Otherwise, the Assessment Platform can # complete its normal post-assessment flow. if end_assessment_return: + # user is authenticated via JWT so use that to create a + # session with this service's authentication backend + request.user.backend = EDX_OAUTH_BACKEND + login(request, user) + lti_config_id = exam.provider.lti_configuration_id lti_config = LtiConfiguration.objects.get(id=lti_config_id) @@ -319,6 +319,7 @@ def end_assessment(request, attempt_id): message_type='LtiEndAssessment', proctoring_launch_data=proctoring_launch_data, context_id=exam.course_id, + launch_presentation_return_url=get_exam_url_path(exam.course_id, exam.content_id), ) # TODO: "If the assessment needs to close due to an error NOT handled by the Assessment Platform that error MUST @@ -328,7 +329,7 @@ def end_assessment(request, attempt_id): return redirect(preflight_url) - return JsonResponse({}) + return redirect(get_exam_url_path(exam.course_id, exam.content_id)) @api_view(['GET'])