diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index bcbb0221139..0025d1b48aa 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -14,6 +14,10 @@ Change Log
Unreleased
~~~~~~~~~~
+[4.6.0] - 2021-11-03
+~~~~~~~~~~~~~~~~~~~~
+* Remove references to "ready_to_resume" and "resumed" statuses.
+
[4.5.0] - 2021-11-01
~~~~~~~~~~~~~~~~~~~~
* Remove references to VERIFIED_NAME_FLAG Django waffle flag.
diff --git a/edx_proctoring/__init__.py b/edx_proctoring/__init__.py
index 7724cd05af8..2c3bc535850 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__ = '4.5.0'
+__version__ = '4.6.0'
default_app_config = 'edx_proctoring.apps.EdxProctoringConfig' # pylint: disable=invalid-name
diff --git a/edx_proctoring/admin.py b/edx_proctoring/admin.py
index 8ff858212ee..73fb95582f1 100644
--- a/edx_proctoring/admin.py
+++ b/edx_proctoring/admin.py
@@ -397,7 +397,6 @@ class Meta:
(ProctoredExamStudentAttemptStatus.verified, _('Verified')),
(ProctoredExamStudentAttemptStatus.rejected, _('Rejected')),
(ProctoredExamStudentAttemptStatus.error, _('Error')),
- (ProctoredExamStudentAttemptStatus.ready_to_resume, _('Ready To Resume')),
]
if settings.DEBUG:
STATUS_CHOICES.extend([
diff --git a/edx_proctoring/api.py b/edx_proctoring/api.py
index 578862d4d20..121f31aba02 100644
--- a/edx_proctoring/api.py
+++ b/edx_proctoring/api.py
@@ -1232,7 +1232,7 @@ def mark_exam_attempt_timeout(attempt_id):
def mark_exam_attempt_as_ready(attempt_id):
"""
- Marks the exam attemp as ready to start
+ Marks the exam attempt as ready to start
"""
return update_attempt_status(attempt_id, ProctoredExamStudentAttemptStatus.ready_to_start)
@@ -1282,28 +1282,18 @@ def is_attempt_ready_to_resume(attempt):
"""
# if the attempt has been marked as ready to resume, check to see that it has not been resumed yet
- # we also want to check if the status is ready to resume for backwards compatibility. Older attempts
- # may still have this status, but not have the correct value for the ready_to_resume_field
- return (
- (attempt['ready_to_resume'] or attempt['status'] == ProctoredExamStudentAttemptStatus.ready_to_resume)
- and not attempt['resumed']
- )
+ return attempt['ready_to_resume'] and not attempt['resumed']
def is_attempt_in_resume_process(attempt_obj):
"""
Determine if an exam attempt is in the resume process. This should check if either of the resume
- related fields are set to true, or if the attempt status is a resume status. We must check both
- in order for older attempts with the resume statuses to function as expected.
+ related fields are set to true.
Arguments:
attempt_obj: attempt object
"""
- return (
- attempt_obj.ready_to_resume
- or attempt_obj.resumed
- or ProctoredExamStudentAttemptStatus.is_resume_status(attempt_obj.status)
- )
+ return attempt_obj.ready_to_resume or attempt_obj.resumed
def is_state_transition_legal(from_status, to_status):
diff --git a/edx_proctoring/exceptions.py b/edx_proctoring/exceptions.py
index 4427f2032ac..26581c65ac5 100644
--- a/edx_proctoring/exceptions.py
+++ b/edx_proctoring/exceptions.py
@@ -151,7 +151,7 @@ class ProctoredExamIllegalStatusTransition(ProctoredBaseException):
class ProctoredExamIllegalResumeUpdate(ProctoredBaseException):
"""
Raised if an update to the ready_to_resume or resumed fields should not be allowed,
- e.g. if we try to update ready_to_resume to True on an examp attempt, but the attempt
+ e.g. if we try to update ready_to_resume to True on an exam attempt, but the attempt
is not resumable.
"""
diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_attempt_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_attempt_view.js
index 1acbd231f10..18c909bae76 100644
--- a/edx_proctoring/static/proctoring/js/views/proctored_exam_attempt_view.js
+++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_attempt_view.js
@@ -11,7 +11,6 @@ edx = edx || {};
created: gettext('Created'),
download_software_clicked: gettext('Download Software Clicked'),
ready_to_start: gettext('Ready to start'),
- ready_to_resume: gettext('Ready to resume'),
started: gettext('Started'),
ready_to_submit: gettext('Ready to submit'),
declined: gettext('Declined'),
diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_attempt_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_attempt_spec.js
index bdacd691ea3..c7f6e350899 100644
--- a/edx_proctoring/static/proctoring/spec/proctored_exam_attempt_spec.js
+++ b/edx_proctoring/static/proctoring/spec/proctored_exam_attempt_spec.js
@@ -290,8 +290,7 @@ describe('ProctoredExamAttemptView', function() {
'<% } else { %> N/A <% } %>' +
'' +
'<% if (' +
- '(proctored_exam_attempt.ready_to_resume || proctored_exam_attempt.status == "ready_to_resume") ' +
- '&& !proctored_exam_attempt.resumed' +
+ 'proctored_exam_attempt.ready_to_resume && !proctored_exam_attempt.resumed' +
') { %>' +
'
' +
'' +
@@ -361,8 +360,7 @@ describe('ProctoredExamAttemptView', function() {
'<%= getExamAttemptStatus(proctored_exam_attempt.status) %>' +
'<% } else { %> N/A <% } %> | ' +
'<% if (' +
- '(proctored_exam_attempt.ready_to_resume || proctored_exam_attempt.status == "ready_to_resume") ' +
- '&& !proctored_exam_attempt.resumed' +
+ 'proctored_exam_attempt.ready_to_resume && !proctored_exam_attempt.resumed' +
') { %>' +
'' +
'' +
@@ -590,7 +588,7 @@ describe('ProctoredExamAttemptView', function() {
'Content-Type': 'application/json'
},
JSON.stringify(getExpectedGroupedProctoredExamAttemptWithAttemptStatusJson(
- 'ready_to_resume', false, false, false, true)
+ 'error', false, false, false, true)
)
]
);
@@ -651,7 +649,9 @@ describe('ProctoredExamAttemptView', function() {
{
'Content-Type': 'application/json'
},
- JSON.stringify(getExpectedGroupedProctoredExamAttemptWithAttemptStatusJson('ready_to_resume'))
+ JSON.stringify(getExpectedGroupedProctoredExamAttemptWithAttemptStatusJson(
+ 'error', false, false, true, false
+ ))
]
);
@@ -685,7 +685,6 @@ describe('ProctoredExamAttemptView', function() {
expect(this.proctored_exam_attempt_view.$el.find('tbody').html()).toContain('testuser1');
expect(this.proctored_exam_attempt_view.$el.find('tbody').html()).toContain('Normal Exam');
- expect(this.proctored_exam_attempt_view.$el.find('tbody.accordion-panel').html()).toContain('Ready to resume');
expect(this.proctored_exam_attempt_view.$el.find('tbody.accordion-panel').html()).toContain('fa-check-circle');
expect(this.proctored_exam_attempt_view.$el.find('.actions-dropdown').hasClass('is-visible')).toEqual(false);
});
diff --git a/edx_proctoring/static/proctoring/templates/student-proctored-exam-attempts-grouped.underscore b/edx_proctoring/static/proctoring/templates/student-proctored-exam-attempts-grouped.underscore
index 39a728822f9..620eb6ee8f4 100644
--- a/edx_proctoring/static/proctoring/templates/student-proctored-exam-attempts-grouped.underscore
+++ b/edx_proctoring/static/proctoring/templates/student-proctored-exam-attempts-grouped.underscore
@@ -194,8 +194,7 @@
<% } %>
|
<% if (
- (proctored_exam_attempt.ready_to_resume || proctored_exam_attempt.status == "ready_to_resume")
- && !proctored_exam_attempt.resumed
+ proctored_exam_attempt.ready_to_resume && !proctored_exam_attempt.resumed
) { %>
@@ -264,8 +263,7 @@
<% } %>
|
<% if (
- (proctored_exam_attempt.ready_to_resume || proctored_exam_attempt.status == "ready_to_resume")
- && !proctored_exam_attempt.resumed
+ proctored_exam_attempt.ready_to_resume && !proctored_exam_attempt.resumed
) { %>
diff --git a/edx_proctoring/statuses.py b/edx_proctoring/statuses.py
index 07c680290e3..859dcb13f50 100644
--- a/edx_proctoring/statuses.py
+++ b/edx_proctoring/statuses.py
@@ -65,12 +65,6 @@ class ProctoredExamStudentAttemptStatus:
# the course end date has passed
expired = 'expired'
- # the learner is ready to resume their errored proctored exam
- ready_to_resume = 'ready_to_resume'
-
- # the exam has been resumed and new attempt has been created
- resumed = 'resumed'
-
# the onboarding attempt has been reset
onboarding_reset = 'onboarding_reset'
@@ -94,8 +88,8 @@ def is_completed_status(cls, status):
"""
return status in [
cls.declined, cls.timed_out, cls.submitted, cls.second_review_required,
- cls.verified, cls.rejected, cls.error, cls.ready_to_resume, cls.resumed,
- cls.onboarding_missing, cls.onboarding_pending, cls.onboarding_failed, cls.onboarding_expired
+ cls.verified, cls.rejected, cls.error, cls.onboarding_missing, cls.onboarding_pending,
+ cls.onboarding_failed, cls.onboarding_expired
]
@classmethod
@@ -161,15 +155,6 @@ def is_in_progress_status(cls, status):
cls.started, cls.ready_to_submit
]
- @classmethod
- def is_resume_status(cls, status):
- """
- Returns a boolean if the status passed is "resumed" or "ready to resume"
- """
- return status in [
- cls.ready_to_resume, cls.resumed
- ]
-
class ReviewStatus:
"""
diff --git a/edx_proctoring/tests/test_api.py b/edx_proctoring/tests/test_api.py
index 88d5fe37259..97ed8325e39 100644
--- a/edx_proctoring/tests/test_api.py
+++ b/edx_proctoring/tests/test_api.py
@@ -1032,7 +1032,7 @@ def test_resume_exam_attempt(self, should_resume):
"""
# create an attempt that has been marked ready to resume
initial_attempt = self._create_exam_attempt(
- self.proctored_exam_id, ProctoredExamStudentAttemptStatus.ready_to_resume
+ self.proctored_exam_id, ProctoredExamStudentAttemptStatus.error, ready_to_resume=True
)
# populate the remaining time
initial_attempt.time_remaining_seconds = 600
@@ -1068,7 +1068,7 @@ def test_resume_from_invalid_attempt(self, status):
"""
An exam cannot be resumed if the previous attempt is not 'ready to resume' or 'resumed'
"""
- self._create_exam_attempt(self.proctored_exam_id, status)
+ self._create_exam_attempt(self.proctored_exam_id, status, ready_to_resume=False, resumed=False)
with self.assertRaises(StudentExamAttemptAlreadyExistsException):
create_exam_attempt(self.proctored_exam_id, self.user_id)
@@ -1144,15 +1144,14 @@ def test_get_user_attempts_by_exam_id(self):
"""
first_attempt_id = create_exam_attempt(self.proctored_exam_id, self.user_id, taking_as_proctored=True)
update_attempt_status(first_attempt_id, ProctoredExamStudentAttemptStatus.error)
- update_attempt_status(first_attempt_id, ProctoredExamStudentAttemptStatus.ready_to_resume)
+ mark_exam_attempt_as_ready_to_resume(first_attempt_id)
second_attempt_id = create_exam_attempt(self.proctored_exam_id, self.user_id, taking_as_proctored=True)
update_attempt_status(second_attempt_id, ProctoredExamStudentAttemptStatus.error)
- update_attempt_status(second_attempt_id, ProctoredExamStudentAttemptStatus.ready_to_resume)
+ mark_exam_attempt_as_ready_to_resume(second_attempt_id)
third_attempt_id = create_exam_attempt(self.proctored_exam_id, self.user_id, taking_as_proctored=True)
update_attempt_status(third_attempt_id, ProctoredExamStudentAttemptStatus.error)
- update_attempt_status(third_attempt_id, ProctoredExamStudentAttemptStatus.ready_to_resume)
attempts = get_user_attempts_by_exam_id(self.user_id, self.proctored_exam_id)
self.assertEqual(len(attempts), 3)
@@ -1426,14 +1425,15 @@ def test_get_filtered_exam_attempts_resumed(self):
# create the first attempt
first_exam_attempt = self._create_exam_attempt(
exam_id=self.proctored_exam_id,
- status=ProctoredExamStudentAttemptStatus.ready_to_resume,
- time_remaining_seconds=600
+ status=ProctoredExamStudentAttemptStatus.error,
+ time_remaining_seconds=600,
+ ready_to_resume=True
)
- # create the second attempt, transitioning from error to ready_to_resume
+ # create the second attempt, setting the status to error and mark ready to resume
second_exam_attempt_id = create_exam_attempt(exam_id=self.proctored_exam_id, user_id=self.user_id)
update_attempt_status(second_exam_attempt_id, ProctoredExamStudentAttemptStatus.error)
update_exam_attempt(second_exam_attempt_id, time_remaining_seconds=500)
- update_attempt_status(second_exam_attempt_id, ProctoredExamStudentAttemptStatus.ready_to_resume)
+ mark_exam_attempt_as_ready_to_resume(second_exam_attempt_id)
# create the third attempt, then assert that all attempts return correctly
third_exam_attempt_id = create_exam_attempt(exam_id=self.proctored_exam_id, user_id=self.user_id)
all_attempts = get_filtered_exam_attempts(self.course_id, self.user.username)
@@ -1443,7 +1443,7 @@ def test_get_filtered_exam_attempts_resumed(self):
self.assertEqual(all_attempts[2]['id'], first_exam_attempt.id)
# the time remaining on the newest attempt should match the previous attempt
self.assertEqual(all_attempts[0]['time_remaining_seconds'], all_attempts[1]['time_remaining_seconds'])
- # when a new attempt is created, the previous attempt should have resumed sest to true
+ # when a new attempt is created, the previous attempt should have resumed set to true
self.assertFalse(all_attempts[0]['resumed'])
self.assertTrue(all_attempts[1]['resumed'])
self.assertTrue(all_attempts[2]['resumed'])
@@ -2437,7 +2437,7 @@ def test_update_exam_attempt_ready_to_resume(self, resumable_status):
"""
Assert that an attempted transition of a proctored exam attempt from an error state
to a ready_to_resume state completes successfully and does not raise a
- ProctoredExamIllegalStatusTransition exception.
+ ProctoredExamIllegalResumeUpdate exception.
"""
exam_attempt = self._create_started_exam_attempt()
@@ -2457,31 +2457,12 @@ def test_update_exam_attempt_ready_to_resume(self, resumable_status):
attempt = get_exam_attempt_by_id(exam_attempt.id)
self.assertEqual(attempt['status'], resumable_status)
+ self.assertTrue(attempt['is_resumable'])
- update_attempt_status(
- exam_attempt.id,
- ProctoredExamStudentAttemptStatus.ready_to_resume
- )
+ mark_exam_attempt_as_ready_to_resume(exam_attempt.id)
attempt = get_exam_attempt_by_id(exam_attempt.id)
- self.assertEqual(attempt['status'], ProctoredExamStudentAttemptStatus.ready_to_resume)
-
- @ddt.data(
- ProctoredExamStudentAttemptStatus.ready_to_resume,
- ProctoredExamStudentAttemptStatus.resumed
- )
- def test_update_exam_attempt_resumed(self, from_status):
- """
- Assert that transition status to 'resumed' is successful if the previous status is
- 'ready_to_resume' or 'resumed'.
- """
- exam_attempt = self._create_exam_attempt(self.proctored_exam_id, status=from_status)
- update_attempt_status(
- exam_attempt.id,
- ProctoredExamStudentAttemptStatus.resumed
- )
- attempt = get_exam_attempt_by_id(exam_attempt.id)
- self.assertEqual(attempt['status'], ProctoredExamStudentAttemptStatus.resumed)
+ self.assertTrue(attempt['ready_to_resume'])
@ddt.data(True, False)
@patch('edx_proctoring.api.exam_attempt_status_signal.send')
@@ -2595,16 +2576,12 @@ def test_mark_ready_to_resume(self):
with self.assertRaises(ProctoredExamIllegalResumeUpdate):
mark_exam_attempt_as_ready_to_resume(exam_attempt.id)
- @ddt.data(
- (ProctoredExamStudentAttemptStatus.ready_to_resume, False, False),
- (ProctoredExamStudentAttemptStatus.resumed, False, False),
- (ProctoredExamStudentAttemptStatus.error, True, False),
- (ProctoredExamStudentAttemptStatus.error, False, True),
- (ProctoredExamStudentAttemptStatus.ready_to_resume, True, False)
- )
+ @ddt.data((True, False), (False, True))
@ddt.unpack
- def test_mark_resumed(self, status, ready_to_resume, expect_error):
- exam_attempt = self._create_exam_attempt(self.proctored_exam_id, status=status)
+ def test_mark_resumed(self, ready_to_resume, expect_error):
+ exam_attempt = self._create_exam_attempt(
+ self.proctored_exam_id, status=ProctoredExamStudentAttemptStatus.error
+ )
exam_attempt.ready_to_resume = ready_to_resume
exam_attempt.save()
@@ -3683,7 +3660,8 @@ def test_get_exam_attempt_has_total_time_if_status_is_ready_to_resume(self):
taking_as_proctored=True,
is_sample_attempt=False,
external_id=proctored_exam.external_id,
- status=ProctoredExamStudentAttemptStatus.ready_to_resume
+ status=ProctoredExamStudentAttemptStatus.error,
+ ready_to_resume=True
)
data = get_exam_attempt_data(proctored_exam.id, attempt.id)
diff --git a/edx_proctoring/tests/test_views.py b/edx_proctoring/tests/test_views.py
index 7b57620500d..765702308fe 100644
--- a/edx_proctoring/tests/test_views.py
+++ b/edx_proctoring/tests/test_views.py
@@ -26,6 +26,7 @@
create_exam_attempt,
get_backend_provider,
get_exam_attempt_by_id,
+ mark_exam_attempt_as_ready_to_resume,
reset_practice_exam,
update_attempt_status
)
@@ -3380,12 +3381,12 @@ def test_get_grouped_exam_attempts(self):
# create two attempts each for exam 1
attempt_1 = create_exam_attempt(exam_id_1, self.user.id, taking_as_proctored=True)
update_attempt_status(attempt_1, ProctoredExamStudentAttemptStatus.error)
- update_attempt_status(attempt_1, ProctoredExamStudentAttemptStatus.ready_to_resume)
+ mark_exam_attempt_as_ready_to_resume(attempt_1)
attempt_2 = create_exam_attempt(exam_id_1, self.user.id, taking_as_proctored=True)
attempt_3 = create_exam_attempt(exam_id_1, self.second_user.id, taking_as_proctored=True)
update_attempt_status(attempt_3, ProctoredExamStudentAttemptStatus.error)
- update_attempt_status(attempt_3, ProctoredExamStudentAttemptStatus.ready_to_resume)
+ mark_exam_attempt_as_ready_to_resume(attempt_3)
attempt_4 = create_exam_attempt(exam_id_1, self.second_user.id, taking_as_proctored=True)
# create one attempt each for exam 2
@@ -4377,7 +4378,7 @@ def test_action_not_mark_ready_to_resume_attempt_for_other_as_staff(self, action
self.assertEqual(response.status_code, 403)
self.assertRaises(ProctoredExamPermissionDenied)
- # Make sure the exam attempt is in the ready_to_resume state.
+ # Make sure the exam attempt is in the original state.
attempt = get_exam_attempt_by_id(old_attempt_id)
self.assertEqual(attempt['status'], ProctoredExamStudentAttemptStatus.created)
@@ -6001,7 +6002,8 @@ def _create_attempts(self, last_status):
True
)
ready_first = ProctoredExamStudentAttempt.objects.get(id=first_attempt_id)
- ready_first.status = ProctoredExamStudentAttemptStatus.ready_to_resume
+ ready_first.status = ProctoredExamStudentAttemptStatus.error
+ ready_first.resumed = True
ready_first.save()
second_attempt_id = create_exam_attempt(
self.exam_id,
@@ -6009,7 +6011,8 @@ def _create_attempts(self, last_status):
True
)
ready_second = ProctoredExamStudentAttempt.objects.get(id=second_attempt_id)
- ready_second.status = ProctoredExamStudentAttemptStatus.ready_to_resume
+ ready_second.status = ProctoredExamStudentAttemptStatus.error
+ ready_second.resumed = True
ready_second.save()
third_attempt_id = create_exam_attempt(
self.exam_id,
diff --git a/edx_proctoring/tests/utils.py b/edx_proctoring/tests/utils.py
index 47f4ad0c1a2..d0a0978a268 100644
--- a/edx_proctoring/tests/utils.py
+++ b/edx_proctoring/tests/utils.py
@@ -18,7 +18,7 @@
from django.test import TestCase
from django.test.client import Client
-from edx_proctoring.api import create_exam, create_exam_review_policy
+from edx_proctoring.api import create_exam, create_exam_review_policy, is_attempt_in_resume_process
from edx_proctoring.models import ProctoredExamStudentAttempt
from edx_proctoring.runtime import set_runtime_service
from edx_proctoring.statuses import ProctoredExamStudentAttemptStatus
@@ -284,8 +284,10 @@ def _create_disabled_exam(self):
is_active=False
)
- def _create_exam_attempt(self, exam_id, status=ProctoredExamStudentAttemptStatus.created,
- is_practice_exam=False, time_remaining_seconds=None):
+ def _create_exam_attempt(
+ self, exam_id, status=ProctoredExamStudentAttemptStatus.created, is_practice_exam=False,
+ time_remaining_seconds=None, ready_to_resume=False, resumed=False
+ ):
"""
Creates the ProctoredExamStudentAttempt object.
"""
@@ -298,6 +300,8 @@ def _create_exam_attempt(self, exam_id, status=ProctoredExamStudentAttemptStatus
taking_as_proctored=True,
is_sample_attempt=is_practice_exam,
time_remaining_seconds=time_remaining_seconds,
+ ready_to_resume=ready_to_resume,
+ resumed=resumed
)
if status in (ProctoredExamStudentAttemptStatus.started,
@@ -307,7 +311,7 @@ def _create_exam_attempt(self, exam_id, status=ProctoredExamStudentAttemptStatus
if ProctoredExamStudentAttemptStatus.is_completed_status(status):
attempt.completed_at = datetime.now(pytz.UTC)
- if status == ProctoredExamStudentAttemptStatus.error:
+ if status == ProctoredExamStudentAttemptStatus.error and not is_attempt_in_resume_process(attempt):
attempt.is_resumable = True
attempt.save()
diff --git a/package.json b/package.json
index 8d0074488b4..98acf91b99c 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@edx/edx-proctoring",
"//": "Note that the version format is slightly different than that of the Python version when using prereleases.",
- "version": "4.5.0",
+ "version": "4.6.0",
"main": "edx_proctoring/static/index.js",
"scripts": {
"test": "gulp test"
|