Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: exam end return url #171

Merged
merged 1 commit into from
Sep 13, 2023
Merged
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
15 changes: 11 additions & 4 deletions edx_exams/apps/lti/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
"""
Expand Down
15 changes: 8 additions & 7 deletions edx_exams/apps/lti/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this since it's only necessary if we're performing an end assessment launch

# 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)

Expand All @@ -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
Expand All @@ -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))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will leave us on a blank page with '{}'. If we don't need to perform an LtiEndAssessment launch return to the exam section.



@api_view(['GET'])
Expand Down