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
7174a034
Commit
7174a034
authored
Dec 10, 2015
by
ibrahimahmed443
Committed by
Chris Dodge
Dec 14, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add expiry message when exam times out
parent
74eaaa9f
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 @
7174a034
...
@@ -50,6 +50,8 @@ from edx_proctoring.runtime import get_runtime_service
...
@@ -50,6 +50,8 @@ from edx_proctoring.runtime import get_runtime_service
log
=
logging
.
getLogger
(
__name__
)
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
,
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
):
is_proctored
=
True
,
is_practice_exam
=
False
,
external_id
=
None
,
is_active
=
True
):
...
@@ -1272,6 +1274,7 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
...
@@ -1272,6 +1274,7 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
"""
"""
student_view_template
=
None
student_view_template
=
None
attempt
=
get_exam_attempt
(
exam_id
,
user_id
)
attempt
=
get_exam_attempt
(
exam_id
,
user_id
)
has_time_expired
=
False
attempt_status
=
attempt
[
'status'
]
if
attempt
else
None
attempt_status
=
attempt
[
'status'
]
if
attempt
else
None
has_due_date
=
True
if
exam
[
'due_date'
]
is
not
None
else
False
has_due_date
=
True
if
exam
[
'due_date'
]
is
not
None
else
False
...
@@ -1293,6 +1296,18 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
...
@@ -1293,6 +1296,18 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
student_view_template
=
'timed_exam/submitted.html'
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
:
if
student_view_template
:
template
=
loader
.
get_template
(
student_view_template
)
template
=
loader
.
get_template
(
student_view_template
)
django_context
=
Context
(
context
)
django_context
=
Context
(
context
)
...
@@ -1335,6 +1350,7 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
...
@@ -1335,6 +1350,7 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
'exam_name'
:
exam
[
'exam_name'
],
'exam_name'
:
exam
[
'exam_name'
],
'progress_page_url'
:
progress_page_url
,
'progress_page_url'
:
progress_page_url
,
'does_time_remain'
:
_does_time_remain
(
attempt
),
'does_time_remain'
:
_does_time_remain
(
attempt
),
'has_time_expired'
:
has_time_expired
,
'enter_exam_endpoint'
:
reverse
(
'edx_proctoring.proctored_exam.attempt.collection'
),
'enter_exam_endpoint'
:
reverse
(
'edx_proctoring.proctored_exam.attempt.collection'
),
'change_state_url'
:
reverse
(
'change_state_url'
:
reverse
(
'edx_proctoring.proctored_exam.attempt'
,
'edx_proctoring.proctored_exam.attempt'
,
...
...
edx_proctoring/templates/timed_exam/submitted.html
View file @
7174a034
{% load i18n %}
{% load i18n %}
<div
class=
"sequence proctored-exam completed"
data-exam-id=
"{{exam_id}}"
>
<div
class=
"sequence proctored-exam completed"
data-exam-id=
"{{exam_id}}"
>
<h3>
<h3>
{% blocktrans %}
You have submitted your timed exam.
{% if has_time_expired %}
{% endblocktrans %}
{% 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>
</h3>
<hr>
<hr>
<p>
<p>
...
...
edx_proctoring/tests/test_api.py
View file @
7174a034
...
@@ -103,6 +103,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -103,6 +103,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
self
.
start_an_exam_msg
=
'This exam is proctored'
self
.
start_an_exam_msg
=
'This exam is proctored'
self
.
exam_expired_msg
=
'The due date for this exam has passed'
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_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
.
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_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'
self
.
exam_time_error_msg
=
'There was a problem with your proctoring session'
...
@@ -259,7 +261,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -259,7 +261,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
"""
"""
Creates the ProctoredExamStudentAttempt object.
Creates the ProctoredExamStudentAttempt object.
"""
"""
return
ProctoredExamStudentAttempt
.
objects
.
create
(
attempt
=
ProctoredExamStudentAttempt
(
proctored_exam_id
=
exam_id
,
proctored_exam_id
=
exam_id
,
user_id
=
self
.
user_id
,
user_id
=
self
.
user_id
,
external_id
=
self
.
external_id
,
external_id
=
self
.
external_id
,
...
@@ -267,6 +270,17 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -267,6 +270,17 @@ class ProctoredExamApiTests(LoggedInTestCase):
status
=
status
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
):
def
_create_unstarted_exam_attempt
(
self
,
is_proctored
=
True
,
is_practice
=
False
):
"""
"""
Creates the ProctoredExamStudentAttempt object.
Creates the ProctoredExamStudentAttempt object.
...
@@ -1676,6 +1690,9 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1676,6 +1690,9 @@ class ProctoredExamApiTests(LoggedInTestCase):
"""
"""
exam_attempt
=
self
.
_create_started_exam_attempt
(
is_proctored
=
False
)
exam_attempt
=
self
.
_create_started_exam_attempt
(
is_proctored
=
False
)
exam_attempt
.
status
=
status
exam_attempt
.
status
=
status
if
status
==
'submitted'
:
exam_attempt
.
completed_at
=
datetime
.
now
(
pytz
.
UTC
)
exam_attempt
.
save
()
exam_attempt
.
save
()
rendered_response
=
get_student_view
(
rendered_response
=
get_student_view
(
...
@@ -1688,6 +1705,44 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1688,6 +1705,44 @@ class ProctoredExamApiTests(LoggedInTestCase):
)
)
self
.
assertIn
(
expected_content
,
rendered_response
)
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
):
def
test_submitted_credit_state
(
self
):
"""
"""
Verify that putting an attempt into the submitted state will also mark
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