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
5b074962
Commit
5b074962
authored
Jul 16, 2015
by
Chris Dodge
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add status to attempts
parent
f004c530
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
93 additions
and
10 deletions
+93
-10
edx_proctoring/api.py
+21
-3
edx_proctoring/models.py
+46
-1
edx_proctoring/static/proctoring/js/views/proctored_exam_attempt_view.js
+8
-3
edx_proctoring/static/proctoring/templates/student-proctored-exam-attempts.underscore
+2
-3
edx_proctoring/tests/test_api.py
+16
-0
No files found.
edx_proctoring/api.py
View file @
5b074962
...
...
@@ -24,6 +24,7 @@ from edx_proctoring.models import (
ProctoredExam
,
ProctoredExamStudentAllowance
,
ProctoredExamStudentAttempt
,
ProctoredExamStudentAttemptStatus
,
)
from
edx_proctoring.serializers
import
(
ProctoredExamSerializer
,
...
...
@@ -308,9 +309,23 @@ def stop_exam_attempt(exam_id, user_id):
"""
exam_attempt_obj
=
ProctoredExamStudentAttempt
.
objects
.
get_exam_attempt
(
exam_id
,
user_id
)
if
exam_attempt_obj
is
None
:
raise
StudentExamAttemptDoesNotExistsException
(
'Error. Trying to stop an exam that
is not in progress
.'
)
raise
StudentExamAttemptDoesNotExistsException
(
'Error. Trying to stop an exam that
does not exist
.'
)
else
:
exam_attempt_obj
.
completed_at
=
datetime
.
now
(
pytz
.
UTC
)
exam_attempt_obj
.
status
=
ProctoredExamStudentAttemptStatus
.
completed
exam_attempt_obj
.
save
()
return
exam_attempt_obj
.
id
def
mark_exam_attempt_timeout
(
exam_id
,
user_id
):
"""
Marks the exam attempt as timed_out
"""
exam_attempt_obj
=
ProctoredExamStudentAttempt
.
objects
.
get_exam_attempt
(
exam_id
,
user_id
)
if
exam_attempt_obj
is
None
:
raise
StudentExamAttemptDoesNotExistsException
(
'Error. Trying to time out an exam that does not exist.'
)
else
:
exam_attempt_obj
.
status
=
ProctoredExamStudentAttemptStatus
.
timed_out
exam_attempt_obj
.
save
()
return
exam_attempt_obj
.
id
...
...
@@ -419,7 +434,7 @@ def get_active_exams_for_user(user_id, course_id=None):
return
result
def
get_student_view
(
user_id
,
course_id
,
content_id
,
context
):
def
get_student_view
(
user_id
,
course_id
,
content_id
,
context
):
# pylint: disable=too-many-branches
"""
Helper method that will return the view HTML related to the exam control
flow (i.e. entering, expired, completed, etc.) If there is no specific
...
...
@@ -463,6 +478,10 @@ def get_student_view(user_id, course_id, content_id, context):
expires_at
=
attempt
[
'started_at'
]
+
timedelta
(
minutes
=
attempt
[
'allowed_time_limit_mins'
])
has_time_expired
=
now_utc
>
expires_at
# make sure the attempt has been marked as timed_out, if need be
if
has_time_expired
and
attempt
[
'status'
]
!=
ProctoredExamStudentAttemptStatus
.
timed_out
:
mark_exam_attempt_timeout
(
exam_id
,
user_id
)
if
not
has_started_exam
:
# determine whether to show a timed exam only entrance screen
# or a screen regarding proctoring
...
...
@@ -483,7 +502,6 @@ def get_student_view(user_id, course_id, content_id, context):
student_view_template
=
'proctoring/seq_timed_exam_completed.html'
elif
has_time_expired
:
student_view_template
=
'proctoring/seq_timed_exam_expired.html'
if
student_view_template
:
template
=
loader
.
get_template
(
student_view_template
)
django_context
=
Context
(
context
)
...
...
edx_proctoring/models.py
View file @
5b074962
...
...
@@ -141,6 +141,49 @@ class ProctoredExamStudentAttemptManager(models.Manager):
return
self
.
filter
(
filtered_query
)
class
ProctoredExamStudentAttemptStatus
(
object
):
"""
A class to enumerate the various status that an attempt can have
IMPORTANT: Since these values are stored in a database, they are system
constants and should not be language translated, since translations
might change over time.
"""
# the student is eligible to decide if he/she wants to persue credit
eligible
=
'Eligible'
# the attempt record has been created, but the exam has not yet
# been started
created
=
'Created'
# the attempt is ready to start but requires
# user to acknowledge that he/she wants to start the exam
ready_to_start
=
'Ready to start'
# the student has started the exam and is
# in the process of completing the exam
started
=
'Started'
# the exam has timed out
timed_out
=
'Timed Out'
# the student has completed the exam
completed
=
'Completed'
# the student has submitted the exam for proctoring review
submitted
=
'Submitted'
# the exam has been verified and approved
verified
=
'Verified'
# the exam has been rejected
rejected
=
'Rejected'
# the exam is believed to be in error
error
=
'Error'
class
ProctoredExamStudentAttempt
(
TimeStampedModel
):
"""
Information about the Student Attempt on a
...
...
@@ -205,7 +248,8 @@ class ProctoredExamStudentAttempt(TimeStampedModel):
attempt_code
=
attempt_code
,
taking_as_proctored
=
taking_as_proctored
,
is_sample_attempt
=
is_sample_attempt
,
external_id
=
external_id
external_id
=
external_id
,
status
=
ProctoredExamStudentAttemptStatus
.
created
,
)
def
start_exam_attempt
(
self
):
...
...
@@ -213,6 +257,7 @@ class ProctoredExamStudentAttempt(TimeStampedModel):
sets the model's state when an exam attempt has started
"""
self
.
started_at
=
datetime
.
now
(
pytz
.
UTC
)
self
.
status
=
ProctoredExamStudentAttemptStatus
.
started
self
.
save
()
def
delete_exam_attempt
(
self
):
...
...
edx_proctoring/static/proctoring/js/views/proctored_exam_attempt_view.js
View file @
5b074962
var
edx
=
edx
||
{};
(
function
(
Backbone
,
$
,
_
)
{
(
function
(
Backbone
,
$
,
_
,
gettext
)
{
'use strict'
;
edx
.
instructor_dashboard
=
edx
.
instructor_dashboard
||
{};
...
...
@@ -11,7 +11,7 @@ var edx = edx || {};
return
new
Date
(
date
).
toString
(
'MMM dd, yyyy h:mmtt'
);
}
else
{
return
'
N/A
'
;
return
'
---
'
;
}
}
...
...
@@ -130,6 +130,11 @@ var edx = edx || {};
},
onRemoveAttempt
:
function
(
event
)
{
event
.
preventDefault
();
// confirm the user's intent
if
(
!
confirm
(
gettext
(
'Are you sure you wish to remove this student
\'
s exam attempt?'
)))
{
return
;
}
var
$target
=
$
(
event
.
currentTarget
);
var
attemptId
=
$target
.
data
(
"attemptId"
);
...
...
@@ -148,4 +153,4 @@ var edx = edx || {};
}
});
this
.
edx
.
instructor_dashboard
.
proctoring
.
ProctoredExamAttemptView
=
edx
.
instructor_dashboard
.
proctoring
.
ProctoredExamAttemptView
;
}).
call
(
this
,
Backbone
,
$
,
_
);
}).
call
(
this
,
Backbone
,
$
,
_
,
gettext
);
edx_proctoring/static/proctoring/templates/student-proctored-exam-attempts.underscore
View file @
5b074962
...
...
@@ -2,7 +2,7 @@
<section class="content">
<div class="top-header">
<div class='search-attempts'>
<input type="text" id="search_attempt_id" placeholder="e.g johndoe or john.do@gmail.com"
<input type="text" id="search_attempt_id" placeholder="e.g johndoe or john.do
e
@gmail.com"
<% if (inSearchMode) { %>
value="<%= searchText %>"
<%} %>
...
...
@@ -118,4 +118,4 @@
</tbody>
</table>
</section>
</div>
\ No newline at end of file
</div>
edx_proctoring/tests/test_api.py
View file @
5b074962
...
...
@@ -27,6 +27,7 @@ from edx_proctoring.api import (
get_all_exam_attempts
,
get_filtered_exam_attempts
,
is_feature_enabled
,
mark_exam_attempt_timeout
,
)
from
edx_proctoring.exceptions
import
(
ProctoredExamAlreadyExists
,
...
...
@@ -373,6 +374,21 @@ class ProctoredExamApiTests(LoggedInTestCase):
with
self
.
assertRaises
(
StudentExamAttemptDoesNotExistsException
):
stop_exam_attempt
(
self
.
proctored_exam_id
,
self
.
user_id
)
def
test_mark_exam_attempt_timeout
(
self
):
"""
Tests the mark exam as timed out
"""
with
self
.
assertRaises
(
StudentExamAttemptDoesNotExistsException
):
mark_exam_attempt_timeout
(
self
.
proctored_exam_id
,
self
.
user_id
)
proctored_exam_student_attempt
=
self
.
_create_unstarted_exam_attempt
()
self
.
assertIsNone
(
proctored_exam_student_attempt
.
completed_at
)
proctored_exam_attempt_id
=
mark_exam_attempt_timeout
(
proctored_exam_student_attempt
.
proctored_exam
,
self
.
user_id
)
self
.
assertEqual
(
proctored_exam_student_attempt
.
id
,
proctored_exam_attempt_id
)
def
test_get_active_exams_for_user
(
self
):
"""
Test to get the all the active
...
...
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