Skip to content

Commit

Permalink
fix: Display Useful Status in InstructorDashboard StudentOnboardingPa…
Browse files Browse the repository at this point in the history
…nel for "onboarding reset" Attempt Status

JIRA: MST-736

Due to inconsistencies in the way we handle attempts in past due practice proctored/onboarding exams, learners can end up in an unintended liminal state after attempting to reset their onboarding attempt. If a learner attempts to reset their rejected onboarding attempt after the exam's due date, we process the reset request and move their attempt into the "onboarding_reset" state. Theoretically, a new exam attempt should be created immediately thereafter. However, we have code that prevents the creation of an exam attempt after the exam's due date, so the call to create a subsequent exam attempt fails, leaving the learner with an exam attempt with the "onboarding_reset" status. Theoretically, this situation should never occur, and the fact that it does is a bug. Because of this, we did not handle the "onboarding_reset" status in the StudentOnboardingStatus panel, and this status appears as "null". As an intermediate step, while we think about our due date logic, this pull request adds a new onboarding status "onboarding_status_past_due". This status is displayed as "Onboarding Reset Failed Due to Past Due Exam" in the StudentOnboardingPanel in the InstructorDashboard, which should provide course staff with a clearer explanation.

JIRA: MST-745 tracks the removal of this intermediate code from the code base once we fix the underlying cause of this bug.
JIRA: MST-749 tracks the fix for the behavior that allowed for this state to occur.
  • Loading branch information
MichaelRoytman committed Apr 7, 2021
1 parent 17d5a0b commit 2767816
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 4 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ Change Log
Unreleased
~~~~~~~~~~

[3.8.5] - 2021-04-07
~~~~~~~~~~~~~~~~~~~~~
* Add handling of the "onboarding_reset" attempt status to the
StudentOnboardingStatusByCourseView view and the StudentOnboardingStatus
panel in the Instructor Dashboard.

[3.8.4] - 2021-04-05
~~~~~~~~~~~~~~~~~~~~~
* Add the request username to the proctoring info panel, allowing course staff to masquerade as
Expand Down
2 changes: 1 addition & 1 deletion edx_proctoring/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"""

# Be sure to update the version number in edx_proctoring/package.json
__version__ = '3.8.4'
__version__ = '3.8.5'

default_app_config = 'edx_proctoring.apps.EdxProctoringConfig' # pylint: disable=invalid-name
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ edx = edx || {};
verified: gettext('Verified'),
rejected: gettext('Rejected'),
error: gettext('Error'),
// TODO: remove as part of MST-745
onboarding_reset_past_due: gettext('Onboarding Reset Failed Due to Past Due Exam'),
// Enrollment modes (Note: 'verified' is both a status and enrollment mode)
audit: gettext('Audit'),
honor: gettext('Honor'),
Expand Down
8 changes: 8 additions & 0 deletions edx_proctoring/statuses.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ class InstructorDashboardOnboardingAttemptStatus:
# user's onboarding profile is approved in a different course.
other_course_approved = 'other_course_approved'

# The following status is not a true attempt status that has a corresponding database
# state. This is a consequence of a bug in our software that allows a learner to end up
# with their only or their most recent exam attempt being in the "onboarding_reset" state.
# The learner should not end up in this state, but while we work on a fix, we should not
# display "null" in the Instructor Dashboard Student Onboarding Panel.
# TODO: remove as part of MST-745
onboarding_reset_past_due = 'onboarding_reset_past_due'

onboarding_statuses = {
ProctoredExamStudentAttemptStatus.created: setup_started,
ProctoredExamStudentAttemptStatus.download_software_clicked: setup_started,
Expand Down
63 changes: 63 additions & 0 deletions edx_proctoring/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,69 @@ def test_other_course_verified(self):
}
self.assertEqual(response_data, expected_data)

def test_onboarding_reset_failed_past_due(self):
# TODO: remove as part of MST-745
onboarding_attempt_id = create_exam_attempt(
self.onboarding_exam.id,
self.user.id,
True,
)

# Update the exam attempt to rejected to allow onboarding exam to be reset.
update_attempt_status(onboarding_attempt_id, ProctoredExamStudentAttemptStatus.rejected)

# Update the exam to have a due date in the past.
self.onboarding_exam.due_date = datetime.now(pytz.UTC) - timedelta(minutes=10)
self.onboarding_exam.save()

# Reset the practice exam.
response = self.client.put(
reverse('edx_proctoring:proctored_exam.attempt', args=[onboarding_attempt_id]),
json.dumps({
'action': 'reset_attempt',
}),
content_type='application/json'
)

# Get serialized onboarding_attempt to get modified time.
serialized_onboarding_attempt = get_exam_attempt_by_id(onboarding_attempt_id)

response = self.client.get(reverse(
'edx_proctoring:user_onboarding.status.course',
kwargs={'course_id': self.onboarding_exam.course_id}
)
)
self.assertEqual(response.status_code, 200)

response_data = json.loads(response.content.decode('utf-8'))
expected_data = {
'results': [
{
'username': self.user.username,
'enrollment_mode': self.enrollment_modes[0],
'status': InstructorDashboardOnboardingAttemptStatus.onboarding_reset_past_due,
'modified': serialized_onboarding_attempt.get('modified')
},
{
'username': self.learner_1.username,
'enrollment_mode': self.enrollment_modes[1],
'status': InstructorDashboardOnboardingAttemptStatus.not_started,
'modified': None,
},
{
'username': self.learner_2.username,
'enrollment_mode': self.enrollment_modes[2],
'status': InstructorDashboardOnboardingAttemptStatus.not_started,
'modified': None,
},
],
'count': 3,
'previous': None,
'next': None,
'num_pages': 1,
}
self.assertEqual(response_data, expected_data)

def test_not_staff_or_course_staff(self):
self.user.is_staff = False
self.user.save()
Expand Down
20 changes: 18 additions & 2 deletions edx_proctoring/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,24 @@ def get(self, request, course_id):
data['status'] = InstructorDashboardOnboardingAttemptStatus.other_course_approved
data['modified'] = other_verified_attempt.modified
else:
data['status'] = (InstructorDashboardOnboardingAttemptStatus
.get_onboarding_status_from_attempt_status(user_attempt.get('status')))
attempt_status = user_attempt.get('status')

# If the learner's most recent attempt is in the "onboarding_reset" state,
# return the onboarding_reset_past_due state.
# This is a consequence of a bug in our software that allows a learner to end up
# with their only or their most recent exam attempt being in the "onboarding_reset" state.
# The learner should not end up in this state, but while we work on a fix, we should not
# display "null" in the Instructor Dashboard Student Onboarding Panel.
# TODO: remove as part of MST-745
if user_attempt.get('status') == ProctoredExamStudentAttemptStatus.onboarding_reset:
onboarding_status = InstructorDashboardOnboardingAttemptStatus.onboarding_reset_past_due
else:
onboarding_status = \
InstructorDashboardOnboardingAttemptStatus.get_onboarding_status_from_attempt_status(
attempt_status
)

data['status'] = onboarding_status
data['modified'] = user_attempt.get('modified')

onboarding_data.append(data)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.8.4",
"version": "3.8.5",
"main": "edx_proctoring/static/index.js",
"scripts":{
"test":"gulp test"
Expand Down

0 comments on commit 2767816

Please sign in to comment.