From b3a8fc43646442f5ebcb7418e0c868f767badd69 Mon Sep 17 00:00:00 2001 From: Michael Roytman Date: Mon, 26 Aug 2019 18:37:31 -0400 Subject: [PATCH] prevent RPNow exam re-entry --- edx_proctoring/__init__.py | 2 +- edx_proctoring/callbacks.py | 9 +++++++-- edx_proctoring/tests/test_views.py | 10 ++++++---- package.json | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/edx_proctoring/__init__.py b/edx_proctoring/__init__.py index 8660e5573be..d692c344546 100644 --- a/edx_proctoring/__init__.py +++ b/edx_proctoring/__init__.py @@ -5,6 +5,6 @@ from __future__ import absolute_import # Be sure to update the version number in edx_proctoring/package.json -__version__ = '2.0.6' +__version__ = '2.0.7' default_app_config = 'edx_proctoring.apps.EdxProctoringConfig' # pylint: disable=invalid-name diff --git a/edx_proctoring/callbacks.py b/edx_proctoring/callbacks.py index 6472f6da33b..a961cee5aeb 100644 --- a/edx_proctoring/callbacks.py +++ b/edx_proctoring/callbacks.py @@ -12,6 +12,7 @@ from edx_proctoring.api import ( get_exam_attempt_by_code, mark_exam_attempt_as_ready, + update_attempt_status, ) from edx_proctoring.constants import RPNOWV4_WAFFLE_NAME from edx_proctoring.statuses import ProctoredExamStudentAttemptStatus @@ -30,7 +31,6 @@ def start_exam_callback(request, attempt_code): # pylint: disable=unused-argume IMPORTANT: This is an unauthenticated endpoint, so be VERY CAREFUL about extending this endpoint """ - attempt = get_exam_attempt_by_code(attempt_code) if not attempt: log.warning("Attempt code %r cannot be found.", attempt_code) @@ -42,6 +42,12 @@ def start_exam_callback(request, attempt_code): # pylint: disable=unused-argume if attempt['status'] in [ProctoredExamStudentAttemptStatus.created, ProctoredExamStudentAttemptStatus.download_software_clicked]: mark_exam_attempt_as_ready(attempt['proctored_exam']['id'], attempt['user']['id']) + # if a user attempts to re-enter an exam that has not yet been submitted, submit the exam + if attempt['status'] in [ProctoredExamStudentAttemptStatus.started, + ProctoredExamStudentAttemptStatus.ready_to_submit]: + update_attempt_status(attempt['proctored_exam']['id'], + attempt['user']['id'], + ProctoredExamStudentAttemptStatus.submitted) else: log.warning("Attempted to enter proctored exam attempt {attempt_id} when status was {attempt_status}" .format( @@ -49,7 +55,6 @@ def start_exam_callback(request, attempt_code): # pylint: disable=unused-argume attempt_status=attempt['status'], )) - log.info("Exam %r has been marked as ready", attempt['proctored_exam']['id']) if switch_is_active(RPNOWV4_WAFFLE_NAME): course_id = attempt['proctored_exam']['course_id'] content_id = attempt['proctored_exam']['content_id'] diff --git a/edx_proctoring/tests/test_views.py b/edx_proctoring/tests/test_views.py index 4e4117c9c85..8c23aa5664d 100644 --- a/edx_proctoring/tests/test_views.py +++ b/edx_proctoring/tests/test_views.py @@ -496,14 +496,15 @@ def _test_repeated_start_exam_callbacks(self, attempt, is_rpnow4_on): attempt = get_exam_attempt_by_id(attempt_id) self.assertEqual(attempt['status'], "started") - # hit callback again and verify that status is still 'started' and not 'ready to start' + # hit callback again and verify that status has moved to submitted with patch('edx_proctoring.callbacks.switch_is_active') as mock_switch_is_active: mock_switch_is_active.return_value = is_rpnow4_on self.client.get( reverse('edx_proctoring:anonymous.proctoring_launch_callback.start_exam', kwargs={'attempt_code': code}) ) attempt = get_exam_attempt_by_id(attempt_id) - self.assertEqual(attempt['status'], "started") + self.assertEqual(attempt['status'], "submitted") + self.assertNotEqual(attempt['status'], "started") self.assertNotEqual(attempt['status'], "ready_to_start") @ddt.data( @@ -600,7 +601,7 @@ def test_start_exam(self): def test_start_exam_callback_when_created(self, is_rpnow4_on): """ Test that hitting software secure callback URL twice when the attempt state begins at - 'created' does not change the state from 'started' back to 'ready to start' + 'created' changes the state from 'started' to 'submitted' and not back to 'ready to start' """ attempt = self._test_exam_attempt_creation() self._test_repeated_start_exam_callbacks(attempt, is_rpnow4_on) @@ -609,7 +610,8 @@ def test_start_exam_callback_when_created(self, is_rpnow4_on): def test_start_exam_callback_when_download_software_clicked(self, is_rpnow4_on): """ Test that hitting software secure callback URL twice when the attempt state begins at - 'download_software_clicked' does not change the state from 'started' back to 'ready to start' + 'download_software_clicked' changes the state to 'submitted' and does not change the + state from 'started' back to 'ready to start' """ # Create an exam. attempt = self._test_exam_attempt_creation() diff --git a/package.json b/package.json index 680de5bf7f6..f19a6763120 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@edx/edx-proctoring", "//": "Be sure to update the version number in edx_proctoring/__init__.py", "//": "Note that the version format is slightly different than that of the Python version when using prereleases.", - "version": "2.0.6", + "version": "2.0.7", "main": "edx_proctoring/static/index.js", "repository": { "type": "git",