Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-proctoring
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
edx-proctoring
Commits
be829dc2
Commit
be829dc2
authored
Dec 14, 2015
by
chrisndodge
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #244 from edx/ibrahimahmed443/SOL-1476-timed-exam-time-ran-out-message
add expiry message when exam times out
parents
bbc18b98
7174a034
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
83 additions
and
4 deletions
+83
-4
edx_proctoring/api.py
+16
-0
edx_proctoring/templates/timed_exam/submitted.html
+11
-3
edx_proctoring/tests/test_api.py
+56
-1
No files found.
edx_proctoring/api.py
View file @
be829dc2
...
...
@@ -53,6 +53,8 @@ from edx_proctoring.runtime import get_runtime_service
log
=
logging
.
getLogger
(
__name__
)
SHOW_EXPIRY_MESSAGE_DURATION
=
1
*
60
# duration within which expiry message is shown for a timed-out exam
def
create_exam
(
course_id
,
content_id
,
exam_name
,
time_limit_mins
,
due_date
=
None
,
is_proctored
=
True
,
is_practice_exam
=
False
,
external_id
=
None
,
is_active
=
True
):
...
...
@@ -1389,6 +1391,7 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
"""
student_view_template
=
None
attempt
=
get_exam_attempt
(
exam_id
,
user_id
)
has_time_expired
=
False
attempt_status
=
attempt
[
'status'
]
if
attempt
else
None
has_due_date
=
True
if
exam
[
'due_date'
]
is
not
None
else
False
...
...
@@ -1410,6 +1413,18 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
student_view_template
=
'timed_exam/submitted.html'
current_datetime
=
datetime
.
now
(
pytz
.
UTC
)
start_time
=
attempt
[
'started_at'
]
end_time
=
attempt
[
'completed_at'
]
attempt_duration_sec
=
(
end_time
-
start_time
)
.
total_seconds
()
allowed_duration_sec
=
attempt
[
'allowed_time_limit_mins'
]
*
60
since_exam_ended_sec
=
(
current_datetime
-
end_time
)
.
total_seconds
()
# if the user took >= the available time, then the exam must have expired.
# but we show expiry message only when the exam was taken recently (less than SHOW_EXPIRY_MESSAGE_DURATION)
if
attempt_duration_sec
>=
allowed_duration_sec
and
since_exam_ended_sec
<
SHOW_EXPIRY_MESSAGE_DURATION
:
has_time_expired
=
True
if
student_view_template
:
template
=
loader
.
get_template
(
student_view_template
)
django_context
=
Context
(
context
)
...
...
@@ -1452,6 +1467,7 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
'exam_name'
:
exam
[
'exam_name'
],
'progress_page_url'
:
progress_page_url
,
'does_time_remain'
:
_does_time_remain
(
attempt
),
'has_time_expired'
:
has_time_expired
,
'enter_exam_endpoint'
:
reverse
(
'edx_proctoring.proctored_exam.attempt.collection'
),
'change_state_url'
:
reverse
(
'edx_proctoring.proctored_exam.attempt'
,
...
...
edx_proctoring/templates/timed_exam/submitted.html
View file @
be829dc2
{% load i18n %}
<div
class=
"sequence proctored-exam completed"
data-exam-id=
"{{exam_id}}"
>
<h3>
{% blocktrans %}
You have submitted your timed exam.
{% endblocktrans %}
{% if has_time_expired %}
{% blocktrans %}
The time allotted for this exam has expired. Your exam has been submitted and any work you completed will be graded.
{% endblocktrans %}
{% else %}
{% blocktrans %}
You have submitted your timed exam.
{% endblocktrans %}
{% endif %}
</h3>
<hr>
<p>
...
...
edx_proctoring/tests/test_api.py
View file @
be829dc2
...
...
@@ -121,6 +121,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
self
.
start_an_exam_msg
=
'This exam is proctored'
self
.
exam_expired_msg
=
'The due date for this exam has passed'
self
.
timed_exam_msg
=
'{exam_name} is a Timed Exam'
self
.
timed_exam_submitted
=
'You have submitted your timed exam.'
self
.
timed_exam_expired
=
'The time allotted for this exam has expired.'
self
.
submitted_timed_exam_msg_with_due_date
=
'After the due date has passed,'
self
.
exam_time_expired_msg
=
'You did not complete the exam in the allotted time'
self
.
exam_time_error_msg
=
'There was a problem with your proctoring session'
...
...
@@ -284,7 +286,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
"""
Creates the ProctoredExamStudentAttempt object.
"""
return
ProctoredExamStudentAttempt
.
objects
.
create
(
attempt
=
ProctoredExamStudentAttempt
(
proctored_exam_id
=
exam_id
,
user_id
=
self
.
user_id
,
external_id
=
self
.
external_id
,
...
...
@@ -292,6 +295,17 @@ class ProctoredExamApiTests(LoggedInTestCase):
status
=
status
)
if
status
in
(
ProctoredExamStudentAttemptStatus
.
started
,
ProctoredExamStudentAttemptStatus
.
ready_to_submit
,
ProctoredExamStudentAttemptStatus
.
submitted
):
attempt
.
started_at
=
datetime
.
now
(
pytz
.
UTC
)
if
ProctoredExamStudentAttemptStatus
.
is_completed_status
(
status
):
attempt
.
completed_at
=
datetime
.
now
(
pytz
.
UTC
)
attempt
.
save
()
return
attempt
def
_create_unstarted_exam_attempt
(
self
,
is_proctored
=
True
,
is_practice
=
False
):
"""
Creates the ProctoredExamStudentAttempt object.
...
...
@@ -1918,6 +1932,9 @@ class ProctoredExamApiTests(LoggedInTestCase):
"""
exam_attempt
=
self
.
_create_started_exam_attempt
(
is_proctored
=
False
)
exam_attempt
.
status
=
status
if
status
==
'submitted'
:
exam_attempt
.
completed_at
=
datetime
.
now
(
pytz
.
UTC
)
exam_attempt
.
save
()
rendered_response
=
get_student_view
(
...
...
@@ -1930,6 +1947,44 @@ class ProctoredExamApiTests(LoggedInTestCase):
)
self
.
assertIn
(
expected_content
,
rendered_response
)
def
test_expired_exam
(
self
):
"""
Test that an expired exam shows a difference message when the exam is expired just recently
"""
# create exam with completed_at equal to current time and started_at equal to allowed_time_limit_mins ago
attempt
=
self
.
_create_started_exam_attempt
(
is_proctored
=
False
)
attempt
.
status
=
"submitted"
attempt
.
started_at
=
attempt
.
started_at
-
timedelta
(
minutes
=
attempt
.
allowed_time_limit_mins
)
attempt
.
completed_at
=
attempt
.
started_at
+
timedelta
(
minutes
=
attempt
.
allowed_time_limit_mins
)
attempt
.
save
()
rendered_response
=
get_student_view
(
user_id
=
self
.
user_id
,
course_id
=
self
.
course_id
,
content_id
=
self
.
content_id_timed
,
context
=
{
'display_name'
:
self
.
exam_name
,
}
)
self
.
assertIn
(
self
.
timed_exam_expired
,
rendered_response
)
# update start and completed time such that completed_time is allowed_time_limit_mins ago than the current time
attempt
.
started_at
=
attempt
.
started_at
-
timedelta
(
minutes
=
attempt
.
allowed_time_limit_mins
)
attempt
.
completed_at
=
attempt
.
completed_at
-
timedelta
(
minutes
=
attempt
.
allowed_time_limit_mins
)
attempt
.
save
()
rendered_response
=
get_student_view
(
user_id
=
self
.
user_id
,
course_id
=
self
.
course_id
,
content_id
=
self
.
content_id_timed
,
context
=
{
'display_name'
:
self
.
exam_name
,
}
)
self
.
assertIn
(
self
.
timed_exam_submitted
,
rendered_response
)
def
test_submitted_credit_state
(
self
):
"""
Verify that putting an attempt into the submitted state will also mark
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment