diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c62916d6524..a079d287e9e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,6 +13,10 @@ Change Log Unreleased ~~~~~~~~~~ + +[3.15.1] - 2021-06-16 +~~~~~~~~~~~~~~~~~~~~~ +* Fix a bug in exam attempt API where total time allowed for the exam would not include allowance time. * Add `test_plan` document to describe key features and test cases [3.15.0] - 2021-06-15 diff --git a/edx_proctoring/__init__.py b/edx_proctoring/__init__.py index fff3a666688..bc8d38447b5 100644 --- a/edx_proctoring/__init__.py +++ b/edx_proctoring/__init__.py @@ -3,6 +3,6 @@ """ # Be sure to update the version number in edx_proctoring/package.json -__version__ = '3.15.0' +__version__ = '3.15.1' default_app_config = 'edx_proctoring.apps.EdxProctoringConfig' # pylint: disable=invalid-name diff --git a/edx_proctoring/api.py b/edx_proctoring/api.py index 0a19f92915d..65067884603 100644 --- a/edx_proctoring/api.py +++ b/edx_proctoring/api.py @@ -81,6 +81,14 @@ USER_MODEL = get_user_model() +def get_total_allowed_time_for_exam(exam, user_id): + """ + Returns total allowed time in humanized form for exam including allowance time. + """ + total_allowed_time = _calculate_allowed_mins(exam, user_id) + return humanized_time(total_allowed_time) + + def get_proctoring_settings_by_exam_id(exam_id): """ Return proctoring settings and exam proctoring backend for proctored exam by exam_id. @@ -744,7 +752,6 @@ def get_exam_attempt_data(exam_id, attempt_id, is_learning_mfe=False): # a same process as the LMS if is_learning_mfe: exam_url_path = resolve_exam_url_for_learning_mfe(exam['course_id'], exam['content_id']) - else: exam_url_path = reverse('jump_to', args=[exam['course_id'], exam['content_id']]) diff --git a/edx_proctoring/tests/test_mfe_views.py b/edx_proctoring/tests/test_mfe_views.py index 9dde76f4611..10049f7533d 100644 --- a/edx_proctoring/tests/test_mfe_views.py +++ b/edx_proctoring/tests/test_mfe_views.py @@ -11,10 +11,11 @@ from django.test.utils import override_settings from django.urls import reverse -from edx_proctoring.api import get_review_policy_by_exam_id +from edx_proctoring.api import get_exam_by_id, get_review_policy_by_exam_id from edx_proctoring.exceptions import BackendProviderNotConfigured, ProctoredExamNotFoundException -from edx_proctoring.models import ProctoredExam +from edx_proctoring.models import ProctoredExam, ProctoredExamStudentAllowance from edx_proctoring.statuses import ProctoredExamStudentAttemptStatus +from edx_proctoring.utils import humanized_time from .utils import ProctoredExamTestCase @@ -65,6 +66,25 @@ def assertHasExamData(self, response_data, has_attempt, self.assertEqual(exam_data['content_id'], self.content_id if not content_id else content_id) self.assertEqual(exam_data['time_limit_mins'], self.default_time_limit) + def test_exam_total_time_with_allowance_time_before_exam_starts(self): + """ + Tests that exam has correct total time when user has additional + time allowance and exam has not started yet. + """ + allowed_extra_time = 10 + ProctoredExamStudentAllowance.objects.create( + proctored_exam_id=self.proctored_exam_id, + user_id=self.user_id, + key=self.key, + value=str(allowed_extra_time) + ) + response = self.client.get(self.url) + exam = get_exam_by_id(self.proctored_exam_id) + self.assertEqual(response.status_code, 200) + response_data = json.loads(response.content.decode('utf-8')) + expected_total_time = humanized_time(exam['time_limit_mins'] + allowed_extra_time) + self.assertEqual(response_data['exam']['total_time'], expected_total_time) + def test_get_started_proctored_exam_attempts_data(self): """ Tests the get proctored exam attempts data by course id and usage key endpoint for started exam. diff --git a/edx_proctoring/views.py b/edx_proctoring/views.py index b0549c9b87d..5554b722267 100644 --- a/edx_proctoring/views.py +++ b/edx_proctoring/views.py @@ -48,6 +48,7 @@ get_onboarding_attempt_data_for_learner, get_proctoring_settings_by_exam_id, get_review_policy_by_exam_id, + get_total_allowed_time_for_exam, get_user_attempts_by_exam_id, is_exam_passed_due, mark_exam_attempt_as_ready, @@ -238,12 +239,17 @@ def get(self, request, course_id, content_id): attempt.get('id'), is_learning_mfe=is_learning_mfe ) - # Exam hasn't been started yet but it is proctored so needs to be checked - # if prerequisites are satisfied. We only do this for proctored exam hence - # additional check 'not exam['is_practice_exam']', meaning we do not check - # prerequisites for practice or onboarding exams - elif exam['is_proctored'] and not exam['is_practice_exam']: - exam = check_prerequisites(exam, request.user.id) + else: + # calculate total allowed time for the exam including + # allowance time to show on the MFE entrance pages + exam['total_time'] = get_total_allowed_time_for_exam(exam, request.user.id) + + # Exam hasn't been started yet but it is proctored so needs to be checked + # if prerequisites are satisfied. We only do this for proctored exam hence + # additional check 'not exam['is_practice_exam']', meaning we do not check + # prerequisites for practice or onboarding exams + if exam['is_proctored'] and not exam['is_practice_exam']: + exam = check_prerequisites(exam, request.user.id) # if user hasn't completed required onboarding exam before taking # proctored exam we need to navigate them to it with a link diff --git a/package.json b/package.json index 27dcbf32b73..b0ac3aacc3c 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": "3.15.0", + "version": "3.15.1", "main": "edx_proctoring/static/index.js", "scripts": { "test": "gulp test"