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
edx
edx-proctoring
Commits
5ad4465d
Commit
5ad4465d
authored
Aug 05, 2015
by
chrisndodge
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #61 from edx/cdodge/review-punchlist1
address some review feedback
parents
c57c8095
e6cb0693
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
115 additions
and
32 deletions
+115
-32
edx_proctoring/api.py
+9
-0
edx_proctoring/callbacks.py
+1
-0
edx_proctoring/static/proctoring/js/views/proctored_exam_view.js
+2
-5
edx_proctoring/templates/proctoring/seq_proctored_exam_entrance.html
+11
-0
edx_proctoring/templates/proctoring/seq_proctored_exam_error.html
+54
-4
edx_proctoring/templates/proctoring/seq_proctored_exam_instructions.html
+12
-1
edx_proctoring/templates/proctoring/seq_proctored_exam_submitted.html
+1
-10
edx_proctoring/templates/proctoring/seq_proctored_exam_verified.html
+1
-10
edx_proctoring/tests/test_api.py
+24
-2
No files found.
edx_proctoring/api.py
View file @
5ad4465d
...
@@ -418,6 +418,15 @@ def update_attempt_status(exam_id, user_id, to_status):
...
@@ -418,6 +418,15 @@ def update_attempt_status(exam_id, user_id, to_status):
Internal helper to handle state transitions of attempt status
Internal helper to handle state transitions of attempt status
"""
"""
# In some configuration we may treat timeouts the same
# as the user saying he/she wises to submit the exam
alias_timeout
=
(
to_status
==
ProctoredExamStudentAttemptStatus
.
timed_out
and
not
settings
.
PROCTORING_SETTINGS
.
get
(
'ALLOW_TIMED_OUT_STATE'
,
False
)
)
if
alias_timeout
:
to_status
=
ProctoredExamStudentAttemptStatus
.
ready_to_submit
exam_attempt_obj
=
ProctoredExamStudentAttempt
.
objects
.
get_exam_attempt
(
exam_id
,
user_id
)
exam_attempt_obj
=
ProctoredExamStudentAttempt
.
objects
.
get_exam_attempt
(
exam_id
,
user_id
)
if
exam_attempt_obj
is
None
:
if
exam_attempt_obj
is
None
:
raise
StudentExamAttemptDoesNotExistsException
(
'Error. Trying to look up an exam that does not exist.'
)
raise
StudentExamAttemptDoesNotExistsException
(
'Error. Trying to look up an exam that does not exist.'
)
...
...
edx_proctoring/callbacks.py
View file @
5ad4465d
...
@@ -39,6 +39,7 @@ def start_exam_callback(request, attempt_code): # pylint: disable=unused-argume
...
@@ -39,6 +39,7 @@ def start_exam_callback(request, attempt_code): # pylint: disable=unused-argume
IMPORTANT: This is an unauthenticated endpoint, so be VERY CAREFUL about extending
IMPORTANT: This is an unauthenticated endpoint, so be VERY CAREFUL about extending
this endpoint
this endpoint
"""
"""
attempt
=
get_exam_attempt_by_code
(
attempt_code
)
attempt
=
get_exam_attempt_by_code
(
attempt_code
)
if
not
attempt
:
if
not
attempt
:
return
HttpResponse
(
return
HttpResponse
(
...
...
edx_proctoring/static/proctoring/js/views/proctored_exam_view.js
View file @
5ad4465d
...
@@ -102,7 +102,6 @@ var edx = edx || {};
...
@@ -102,7 +102,6 @@ var edx = edx || {};
return
this
;
return
this
;
},
},
unloadMessage
:
function
()
{
unloadMessage
:
function
()
{
return
null
;
return
gettext
(
"As you are currently taking a proctored exam,
\
n"
+
return
gettext
(
"As you are currently taking a proctored exam,
\
n"
+
"you should not be navigation away from the exam.
\
n"
+
"you should not be navigation away from the exam.
\
n"
+
"This may be considered as a violation of the
\
n"
+
"This may be considered as a violation of the
\
n"
+
...
@@ -115,10 +114,8 @@ var edx = edx || {};
...
@@ -115,10 +114,8 @@ var edx = edx || {};
var
url
=
self
.
model
.
url
+
'/'
+
self
.
model
.
get
(
'attempt_id'
);
var
url
=
self
.
model
.
url
+
'/'
+
self
.
model
.
get
(
'attempt_id'
);
$
.
ajax
(
url
).
success
(
function
(
data
)
{
$
.
ajax
(
url
).
success
(
function
(
data
)
{
if
(
data
.
status
===
'error'
)
{
if
(
data
.
status
===
'error'
)
{
// Let the student know that his exam has failed due to an error.
// The proctoring session is in error state
// This alert may or may not bring the browser window back to the
// refresh the page to
// foreground (depending on browser as well as user settings)
alert
(
gettext
(
'Your exam has failed'
));
clearInterval
(
self
.
timerId
);
// stop the timer once the time finishes.
clearInterval
(
self
.
timerId
);
// stop the timer once the time finishes.
$
(
window
).
unbind
(
'beforeunload'
,
self
.
unloadMessage
);
$
(
window
).
unbind
(
'beforeunload'
,
self
.
unloadMessage
);
// refresh the page when the timer expired
// refresh the page when the timer expired
...
...
edx_proctoring/templates/proctoring/seq_proctored_exam_entrance.html
View file @
5ad4465d
...
@@ -53,6 +53,17 @@
...
@@ -53,6 +53,17 @@
var
exam_id
=
$
(
this
).
data
(
'exam-id'
);
var
exam_id
=
$
(
this
).
data
(
'exam-id'
);
var
attempt_proctored
=
$
(
this
).
data
(
'attempt-proctored'
);
var
attempt_proctored
=
$
(
this
).
data
(
'attempt-proctored'
);
var
start_immediately
=
$
(
this
).
data
(
'start-immediately'
);
var
start_immediately
=
$
(
this
).
data
(
'start-immediately'
);
if
(
!
attempt_proctored
)
{
var
msg
=
gettext
(
"Are you sure you want to take this exam without proctoring? "
+
"This will make you no longer eligible to earn credit for this course."
)
if
(
!
confirm
(
msg
))
{
return
;
}
}
if
(
typeof
action_url
===
"undefined"
)
{
if
(
typeof
action_url
===
"undefined"
)
{
return
false
;
return
false
;
}
}
...
...
edx_proctoring/templates/proctoring/seq_proctored_exam_error.html
View file @
5ad4465d
{% load i18n %}
{% load i18n %}
<div
class=
"sequence proctored-exam error"
>
<div
class=
"failure sequence proctored-exam"
data-exam-id=
"{{exam_id}}"
>
<div
class=
"gated-sequence"
>
<h3>
{% trans "Your exam has been marked as failed due to an error." %}
{% blocktrans %}
</div>
Your proctoring session is in error
{% endblocktrans %}
</h3>
<h4>
{% blocktrans %}
Your Proctoring Session review:
<b
class=
"failure"
>
Failed
</b>
{% endblocktrans %}
</h4>
<p>
{% blocktrans %}
It appears that your proctoring session has been shut down while you were taking this
exam. This invalidates your proctored exam and you will not be eligible for course
credit.
{% endblocktrans %}
</p>
<hr>
<p>
{% blocktrans %}
Please see
<a
href=
"{{progress_page_url}}"
>
your progress in this course
</a>
for your general course credit worthiness.
{% endblocktrans %}
</p>
</div>
<div
class=
"footer-sequence border-b-0 padding-b-0"
>
<span>
{% trans "Can I contest this review?" %}
</span>
<p
class=
"proctored-exam-option"
>
{% blocktrans %}
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor.
Aenean massa.
{% endblocktrans %}
</p>
<a
href=
"#"
class=
"contest-review"
>
Contest this review
</a>
<hr
class=
"clearfix"
>
<span>
{% trans "Is there anything I can do to make up/replace this session?" %}
</span>
<p
class=
"proctored-exam-option"
>
{% blocktrans %}
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor.
Aenean massa.
{% endblocktrans %}
</p>
<hr
class=
"clearfix"
>
<span>
{% trans "See Also" %}
</span>
<p>
{% blocktrans %}
<a
class=
"footer-link"
href=
"#"
>
Frequently asked questions about proctoring and earning college credit.
</a>
{% endblocktrans %}
</p>
</div>
</div>
edx_proctoring/templates/proctoring/seq_proctored_exam_instructions.html
View file @
5ad4465d
...
@@ -51,11 +51,22 @@
...
@@ -51,11 +51,22 @@
var
_waiting_for_proctored_interval
=
null
;
var
_waiting_for_proctored_interval
=
null
;
$
(
'.proctored-decline-exam'
).
click
(
$
(
'.proctored-decline-exam'
).
click
(
function
(
event
)
{
function
(
e
)
{
e
.
preventDefault
();
e
.
stopPropagation
();
var
action_url
=
$
(
this
).
data
(
'change-state-url'
);
var
action_url
=
$
(
this
).
data
(
'change-state-url'
);
var
exam_id
=
$
(
this
).
data
(
'exam-id'
);
var
exam_id
=
$
(
this
).
data
(
'exam-id'
);
var
action
=
$
(
this
).
data
(
'action'
)
var
action
=
$
(
this
).
data
(
'action'
)
var
msg
=
gettext
(
"Are you sure you want to take this exam without proctoring? "
+
"This will make you no longer eligible to earn credit for this course."
)
if
(
!
confirm
(
msg
))
{
return
;
}
// Update the state of the attempt
// Update the state of the attempt
$
.
ajax
({
$
.
ajax
({
url
:
action_url
,
url
:
action_url
,
...
...
edx_proctoring/templates/proctoring/seq_proctored_exam_submitted.html
View file @
5ad4465d
...
@@ -26,13 +26,4 @@
...
@@ -26,13 +26,4 @@
{% endblocktrans %}
{% endblocktrans %}
</p>
</p>
</div>
</div>
<div
class=
"footer-sequence border-b-0 padding-b-0"
>
{% include 'proctoring/seq_proctored_exam_footer.html' %}
<span>
{% trans "See Also" %}
</span>
<p>
{% blocktrans %}
<a
class=
"footer-link"
href=
"#"
>
Frequently asked questions about proctoring and earning college credit.
</a>
{% endblocktrans %}
</p>
</div>
edx_proctoring/templates/proctoring/seq_proctored_exam_verified.html
View file @
5ad4465d
...
@@ -26,13 +26,4 @@
...
@@ -26,13 +26,4 @@
{% endblocktrans %}
{% endblocktrans %}
</p>
</p>
</div>
</div>
<div
class=
"footer-sequence border-b-0 padding-b-0"
>
{% include 'proctoring/seq_proctored_exam_footer.html' %}
<span>
{% trans "See Also" %}
</span>
<p>
{% blocktrans %}
<a
class=
"footer-link"
href=
"#"
>
Frequently asked questions about proctoring and earning college credit.
</a>
{% endblocktrans %}
</p>
</div>
edx_proctoring/tests/test_api.py
View file @
5ad4465d
...
@@ -92,7 +92,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -92,7 +92,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
self
.
start_an_exam_msg
=
'Would you like to take
%
s as a proctored exam?'
self
.
start_an_exam_msg
=
'Would you like to take
%
s as a proctored exam?'
self
.
timed_exam_msg
=
'
%
s is a Timed Exam'
self
.
timed_exam_msg
=
'
%
s is a Timed Exam'
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
=
'Your
exam has been marked as failed due to an error.
'
self
.
exam_time_error_msg
=
'Your
proctoring session is in error
'
self
.
chose_proctored_exam_msg
=
'You have chosen to take
%
s as a proctored exam'
self
.
chose_proctored_exam_msg
=
'You have chosen to take
%
s as a proctored exam'
self
.
proctored_exam_completed_msg
=
'This is the end of your proctored exam'
self
.
proctored_exam_completed_msg
=
'This is the end of your proctored exam'
self
.
proctored_exam_submitted_msg
=
'You have submitted this proctored exam for review'
self
.
proctored_exam_submitted_msg
=
'You have submitted this proctored exam for review'
...
@@ -839,6 +839,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -839,6 +839,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
)
)
self
.
assertIsNone
(
rendered_response
)
self
.
assertIsNone
(
rendered_response
)
@patch.dict
(
'django.conf.settings.PROCTORING_SETTINGS'
,
{
'ALLOW_TIMED_OUT_STATE'
:
True
})
def
test_get_studentview_timedout
(
self
):
def
test_get_studentview_timedout
(
self
):
"""
"""
Verifies that if we call get_studentview when the timer has expired
Verifies that if we call get_studentview when the timer has expired
...
@@ -959,6 +960,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -959,6 +960,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
)
)
self
.
assertIn
(
self
.
proctored_exam_completed_msg
,
rendered_response
)
self
.
assertIn
(
self
.
proctored_exam_completed_msg
,
rendered_response
)
@patch.dict
(
'django.conf.settings.PROCTORING_SETTINGS'
,
{
'ALLOW_TIMED_OUT_STATE'
:
True
})
def
test_get_studentview_expired
(
self
):
def
test_get_studentview_expired
(
self
):
"""
"""
Test for get_student_view proctored exam which has expired.
Test for get_student_view proctored exam which has expired.
...
@@ -1095,6 +1097,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1095,6 +1097,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
(
ProctoredExamStudentAttemptStatus
.
error
,
ProctoredExamStudentAttemptStatus
.
started
),
(
ProctoredExamStudentAttemptStatus
.
error
,
ProctoredExamStudentAttemptStatus
.
started
),
)
)
@ddt.unpack
@ddt.unpack
@patch.dict
(
'django.conf.settings.PROCTORING_SETTINGS'
,
{
'ALLOW_TIMED_OUT_STATE'
:
True
})
def
test_illegal_status_transition
(
self
,
from_status
,
to_status
):
def
test_illegal_status_transition
(
self
,
from_status
,
to_status
):
"""
"""
Verify that we cannot reset backwards an attempt status
Verify that we cannot reset backwards an attempt status
...
@@ -1109,9 +1112,28 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1109,9 +1112,28 @@ class ProctoredExamApiTests(LoggedInTestCase):
)
)
with
self
.
assertRaises
(
ProctoredExamIllegalStatusTransition
):
with
self
.
assertRaises
(
ProctoredExamIllegalStatusTransition
):
print
'*** from = {} to {}'
.
format
(
from_status
,
to_status
)
update_attempt_status
(
update_attempt_status
(
exam_attempt
.
proctored_exam_id
,
exam_attempt
.
proctored_exam_id
,
self
.
user
.
id
,
self
.
user
.
id
,
to_status
to_status
)
)
def
test_alias_timed_out
(
self
):
"""
Verified that timed_out will automatically state transition
to ready_to_submit
"""
exam_attempt
=
self
.
_create_started_exam_attempt
()
update_attempt_status
(
exam_attempt
.
proctored_exam_id
,
self
.
user
.
id
,
ProctoredExamStudentAttemptStatus
.
timed_out
)
exam_attempt
=
get_exam_attempt_by_id
(
exam_attempt
.
id
)
self
.
assertEqual
(
exam_attempt
[
'status'
],
ProctoredExamStudentAttemptStatus
.
ready_to_submit
)
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