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
da76a638
Commit
da76a638
authored
Apr 21, 2016
by
Eric Fischer
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #288 from edx/efischer/hide_timed_exams
TNL-4366 Add ability to hide timed exam after due date
parents
fcd3a1d6
ff1b3d15
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
85 additions
and
26 deletions
+85
-26
edx_proctoring/api.py
+16
-11
edx_proctoring/migrations/0005_proctoredexam_hide_after_due.py
+19
-0
edx_proctoring/models.py
+3
-0
edx_proctoring/serializers.py
+3
-1
edx_proctoring/templates/timed_exam/submitted.html
+1
-1
edx_proctoring/tests/test_api.py
+33
-8
edx_proctoring/tests/test_serializer.py
+2
-1
edx_proctoring/tests/test_views.py
+4
-2
edx_proctoring/views.py
+3
-1
setup.py
+1
-1
No files found.
edx_proctoring/api.py
View file @
da76a638
...
@@ -57,7 +57,7 @@ SHOW_EXPIRY_MESSAGE_DURATION = 1 * 60 # duration within which expiry message is
...
@@ -57,7 +57,7 @@ SHOW_EXPIRY_MESSAGE_DURATION = 1 * 60 # duration within which expiry message is
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
,
hide_after_due
=
False
):
"""
"""
Creates a new ProctoredExam entity, if the course_id/content_id pair do not already exist.
Creates a new ProctoredExam entity, if the course_id/content_id pair do not already exist.
If that pair already exists, then raise exception.
If that pair already exists, then raise exception.
...
@@ -77,19 +77,20 @@ def create_exam(course_id, content_id, exam_name, time_limit_mins, due_date=None
...
@@ -77,19 +77,20 @@ def create_exam(course_id, content_id, exam_name, time_limit_mins, due_date=None
due_date
=
due_date
,
due_date
=
due_date
,
is_proctored
=
is_proctored
,
is_proctored
=
is_proctored
,
is_practice_exam
=
is_practice_exam
,
is_practice_exam
=
is_practice_exam
,
is_active
=
is_active
is_active
=
is_active
,
hide_after_due
=
hide_after_due
,
)
)
log_msg
=
(
log_msg
=
(
u'Created exam ({exam_id}) with parameters: course_id={course_id}, '
u'Created exam ({exam_id}) with parameters: course_id={course_id}, '
u'content_id={content_id}, exam_name={exam_name}, time_limit_mins={time_limit_mins}, '
u'content_id={content_id}, exam_name={exam_name}, time_limit_mins={time_limit_mins}, '
u'is_proctored={is_proctored}, is_practice_exam={is_practice_exam}, '
u'is_proctored={is_proctored}, is_practice_exam={is_practice_exam}, '
u'external_id={external_id}, is_active={is_active}'
.
format
(
u'external_id={external_id}, is_active={is_active}
, hide_after_due={hide_after_due}
'
.
format
(
exam_id
=
proctored_exam
.
id
,
exam_id
=
proctored_exam
.
id
,
course_id
=
course_id
,
content_id
=
content_id
,
course_id
=
course_id
,
content_id
=
content_id
,
exam_name
=
exam_name
,
time_limit_mins
=
time_limit_mins
,
exam_name
=
exam_name
,
time_limit_mins
=
time_limit_mins
,
is_proctored
=
is_proctored
,
is_practice_exam
=
is_practice_exam
,
is_proctored
=
is_proctored
,
is_practice_exam
=
is_practice_exam
,
external_id
=
external_id
,
is_active
=
is_active
external_id
=
external_id
,
is_active
=
is_active
,
hide_after_due
=
hide_after_due
)
)
)
)
log
.
info
(
log_msg
)
log
.
info
(
log_msg
)
...
@@ -202,7 +203,7 @@ def get_review_policy_by_exam_id(exam_id):
...
@@ -202,7 +203,7 @@ def get_review_policy_by_exam_id(exam_id):
def
update_exam
(
exam_id
,
exam_name
=
None
,
time_limit_mins
=
None
,
due_date
=
constants
.
MINIMUM_TIME
,
def
update_exam
(
exam_id
,
exam_name
=
None
,
time_limit_mins
=
None
,
due_date
=
constants
.
MINIMUM_TIME
,
is_proctored
=
None
,
is_practice_exam
=
None
,
external_id
=
None
,
is_active
=
None
):
is_proctored
=
None
,
is_practice_exam
=
None
,
external_id
=
None
,
is_active
=
None
,
hide_after_due
=
None
):
"""
"""
Given a Django ORM id, update the existing record, otherwise raise exception if not found.
Given a Django ORM id, update the existing record, otherwise raise exception if not found.
If an argument is not passed in, then do not change it's current value.
If an argument is not passed in, then do not change it's current value.
...
@@ -214,10 +215,10 @@ def update_exam(exam_id, exam_name=None, time_limit_mins=None, due_date=constant
...
@@ -214,10 +215,10 @@ def update_exam(exam_id, exam_name=None, time_limit_mins=None, due_date=constant
u'Updating exam_id {exam_id} with parameters '
u'Updating exam_id {exam_id} with parameters '
u'exam_name={exam_name}, time_limit_mins={time_limit_mins}, due_date={due_date}'
u'exam_name={exam_name}, time_limit_mins={time_limit_mins}, due_date={due_date}'
u'is_proctored={is_proctored}, is_practice_exam={is_practice_exam}, '
u'is_proctored={is_proctored}, is_practice_exam={is_practice_exam}, '
u'external_id={external_id}, is_active={is_active}'
.
format
(
u'external_id={external_id}, is_active={is_active}
, hide_after_due={hide_after_due}
'
.
format
(
exam_id
=
exam_id
,
exam_name
=
exam_name
,
time_limit_mins
=
time_limit_mins
,
exam_id
=
exam_id
,
exam_name
=
exam_name
,
time_limit_mins
=
time_limit_mins
,
due_date
=
due_date
,
is_proctored
=
is_proctored
,
is_practice_exam
=
is_practice_exam
,
due_date
=
due_date
,
is_proctored
=
is_proctored
,
is_practice_exam
=
is_practice_exam
,
external_id
=
external_id
,
is_active
=
is_active
external_id
=
external_id
,
is_active
=
is_active
,
hide_after_due
=
hide_after_due
)
)
)
)
log
.
info
(
log_msg
)
log
.
info
(
log_msg
)
...
@@ -240,6 +241,8 @@ def update_exam(exam_id, exam_name=None, time_limit_mins=None, due_date=constant
...
@@ -240,6 +241,8 @@ def update_exam(exam_id, exam_name=None, time_limit_mins=None, due_date=constant
proctored_exam
.
external_id
=
external_id
proctored_exam
.
external_id
=
external_id
if
is_active
is
not
None
:
if
is_active
is
not
None
:
proctored_exam
.
is_active
=
is_active
proctored_exam
.
is_active
=
is_active
if
hide_after_due
is
not
None
:
proctored_exam
.
hide_after_due
=
hide_after_due
proctored_exam
.
save
()
proctored_exam
.
save
()
# read back exam so we can emit an event on it
# read back exam so we can emit an event on it
...
@@ -1444,9 +1447,10 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
...
@@ -1444,9 +1447,10 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
elif
attempt_status
==
ProctoredExamStudentAttemptStatus
.
ready_to_submit
:
elif
attempt_status
==
ProctoredExamStudentAttemptStatus
.
ready_to_submit
:
student_view_template
=
'timed_exam/ready_to_submit.html'
student_view_template
=
'timed_exam/ready_to_submit.html'
elif
attempt_status
==
ProctoredExamStudentAttemptStatus
.
submitted
:
elif
attempt_status
==
ProctoredExamStudentAttemptStatus
.
submitted
:
# check if the exam's due_date has passed then we return None
# If we are not hiding the exam after the due_date has passed,
# check if the exam's due_date has passed. If so, return None
# so that the user can see his exam answers in read only mode.
# so that the user can see his exam answers in read only mode.
if
has_due_date_passed
(
exam
[
'due_date'
]):
if
not
exam
[
'hide_after_due'
]
and
has_due_date_passed
(
exam
[
'due_date'
]):
return
None
return
None
student_view_template
=
'timed_exam/submitted.html'
student_view_template
=
'timed_exam/submitted.html'
...
@@ -1500,7 +1504,7 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
...
@@ -1500,7 +1504,7 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
django_context
.
update
({
django_context
.
update
({
'total_time'
:
total_time
,
'total_time'
:
total_time
,
'
has_due_date'
:
has_due_date
,
'
will_be_revealed'
:
has_due_date
and
not
exam
[
'hide_after_due'
]
,
'exam_id'
:
exam_id
,
'exam_id'
:
exam_id
,
'exam_name'
:
exam
[
'exam_name'
],
'exam_name'
:
exam
[
'exam_name'
],
'progress_page_url'
:
progress_page_url
,
'progress_page_url'
:
progress_page_url
,
...
@@ -1816,7 +1820,8 @@ def get_student_view(user_id, course_id, content_id,
...
@@ -1816,7 +1820,8 @@ def get_student_view(user_id, course_id, content_id,
time_limit_mins
=
context
[
'default_time_limit_mins'
],
time_limit_mins
=
context
[
'default_time_limit_mins'
],
is_proctored
=
context
.
get
(
'is_proctored'
,
False
),
is_proctored
=
context
.
get
(
'is_proctored'
,
False
),
is_practice_exam
=
context
.
get
(
'is_practice_exam'
,
False
),
is_practice_exam
=
context
.
get
(
'is_practice_exam'
,
False
),
due_date
=
context
.
get
(
'due_date'
,
None
)
due_date
=
context
.
get
(
'due_date'
,
None
),
hide_after_due
=
context
.
get
(
'hide_after_due'
,
None
),
)
)
exam
=
get_exam_by_content_id
(
course_id
,
content_id
)
exam
=
get_exam_by_content_id
(
course_id
,
content_id
)
...
...
edx_proctoring/migrations/0005_proctoredexam_hide_after_due.py
0 → 100644
View file @
da76a638
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'edx_proctoring'
,
'0004_auto_20160201_0523'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'proctoredexam'
,
name
=
'hide_after_due'
,
field
=
models
.
BooleanField
(
default
=
False
),
),
]
edx_proctoring/models.py
View file @
da76a638
...
@@ -50,6 +50,9 @@ class ProctoredExam(TimeStampedModel):
...
@@ -50,6 +50,9 @@ class ProctoredExam(TimeStampedModel):
# Whether this exam will be active.
# Whether this exam will be active.
is_active
=
models
.
BooleanField
(
default
=
False
)
is_active
=
models
.
BooleanField
(
default
=
False
)
# Whether to hide this exam after the due date
hide_after_due
=
models
.
BooleanField
(
default
=
False
)
class
Meta
:
class
Meta
:
""" Meta class for this Django model """
""" Meta class for this Django model """
unique_together
=
((
'course_id'
,
'content_id'
),)
unique_together
=
((
'course_id'
,
'content_id'
),)
...
...
edx_proctoring/serializers.py
View file @
da76a638
...
@@ -25,6 +25,7 @@ class ProctoredExamSerializer(serializers.ModelSerializer):
...
@@ -25,6 +25,7 @@ class ProctoredExamSerializer(serializers.ModelSerializer):
is_practice_exam
=
serializers
.
BooleanField
(
required
=
True
)
is_practice_exam
=
serializers
.
BooleanField
(
required
=
True
)
is_proctored
=
serializers
.
BooleanField
(
required
=
True
)
is_proctored
=
serializers
.
BooleanField
(
required
=
True
)
due_date
=
serializers
.
DateTimeField
(
required
=
False
,
format
=
None
)
due_date
=
serializers
.
DateTimeField
(
required
=
False
,
format
=
None
)
hide_after_due
=
serializers
.
BooleanField
(
required
=
True
)
class
Meta
:
class
Meta
:
"""
"""
...
@@ -34,7 +35,8 @@ class ProctoredExamSerializer(serializers.ModelSerializer):
...
@@ -34,7 +35,8 @@ class ProctoredExamSerializer(serializers.ModelSerializer):
fields
=
(
fields
=
(
"id"
,
"course_id"
,
"content_id"
,
"external_id"
,
"exam_name"
,
"id"
,
"course_id"
,
"content_id"
,
"external_id"
,
"exam_name"
,
"time_limit_mins"
,
"is_proctored"
,
"is_practice_exam"
,
"is_active"
,
"due_date"
"time_limit_mins"
,
"is_proctored"
,
"is_practice_exam"
,
"is_active"
,
"due_date"
,
"hide_after_due"
)
)
...
...
edx_proctoring/templates/timed_exam/submitted.html
View file @
da76a638
...
@@ -18,7 +18,7 @@
...
@@ -18,7 +18,7 @@
{% blocktrans %}
{% blocktrans %}
Your grade for this timed exam will be immediately available on the
<a
href=
"{{progress_page_url}}"
>
Progress
</a>
page.
Your grade for this timed exam will be immediately available on the
<a
href=
"{{progress_page_url}}"
>
Progress
</a>
page.
{% endblocktrans %}
{% endblocktrans %}
{% if
has_due_date
%}
{% if
will_be_revealed
%}
{% blocktrans %}
{% blocktrans %}
After the due date has passed, you can review the exam, but you cannot change your answers.
After the due date has passed, you can review the exam, but you cannot change your answers.
{% endblocktrans %}
{% endblocktrans %}
...
...
edx_proctoring/tests/test_api.py
View file @
da76a638
...
@@ -413,6 +413,18 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -413,6 +413,18 @@ class ProctoredExamApiTests(LoggedInTestCase):
self
.
assertEqual
(
update_proctored_exam
.
course_id
,
'test_course'
)
self
.
assertEqual
(
update_proctored_exam
.
course_id
,
'test_course'
)
self
.
assertEqual
(
update_proctored_exam
.
content_id
,
'test_content_id'
)
self
.
assertEqual
(
update_proctored_exam
.
content_id
,
'test_content_id'
)
def
test_update_timed_exam
(
self
):
"""
test update the existing timed exam
"""
updated_timed_exam_id
=
update_exam
(
self
.
timed_exam_id
,
hide_after_due
=
True
)
self
.
assertEqual
(
self
.
timed_exam_id
,
updated_timed_exam_id
)
update_timed_exam
=
ProctoredExam
.
objects
.
get
(
id
=
updated_timed_exam_id
)
self
.
assertEqual
(
update_timed_exam
.
hide_after_due
,
True
)
def
test_update_non_existing_exam
(
self
):
def
test_update_non_existing_exam
(
self
):
"""
"""
test to update the non-existing proctored exam
test to update the non-existing proctored exam
...
@@ -1022,7 +1034,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1022,7 +1034,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
context
=
{
context
=
{
'is_proctored'
:
True
,
'is_proctored'
:
True
,
'display_name'
:
self
.
exam_name
,
'display_name'
:
self
.
exam_name
,
'default_time_limit_mins'
:
90
'default_time_limit_mins'
:
90
,
'hide_after_due'
:
False
,
}
}
)
)
self
.
assertIn
(
self
.
assertIn
(
...
@@ -1041,6 +1054,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1041,6 +1054,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
'display_name'
:
self
.
exam_name
,
'display_name'
:
self
.
exam_name
,
'default_time_limit_mins'
:
90
,
'default_time_limit_mins'
:
90
,
'is_practice_exam'
:
True
,
'is_practice_exam'
:
True
,
'hide_after_due'
:
False
,
}
}
)
)
self
.
assertIn
(
self
.
start_a_practice_exam_msg
.
format
(
exam_name
=
self
.
exam_name
),
rendered_response
)
self
.
assertIn
(
self
.
start_a_practice_exam_msg
.
format
(
exam_name
=
self
.
exam_name
),
rendered_response
)
...
@@ -1186,7 +1200,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1186,7 +1200,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
'is_proctored'
:
False
,
'is_proctored'
:
False
,
'is_practice_exam'
:
True
,
'is_practice_exam'
:
True
,
'display_name'
:
self
.
exam_name
,
'display_name'
:
self
.
exam_name
,
'default_time_limit_mins'
:
90
'default_time_limit_mins'
:
90
,
'hide_after_due'
:
False
,
},
},
user_role
=
'student'
user_role
=
'student'
)
)
...
@@ -1209,7 +1224,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1209,7 +1224,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
'is_practice_exam'
:
False
,
'is_practice_exam'
:
False
,
'display_name'
:
self
.
exam_name
,
'display_name'
:
self
.
exam_name
,
'default_time_limit_mins'
:
90
,
'default_time_limit_mins'
:
90
,
'due_date'
:
None
'due_date'
:
None
,
'hide_after_due'
:
False
,
},
},
user_role
=
'student'
user_role
=
'student'
)
)
...
@@ -1250,7 +1266,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1250,7 +1266,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
'is_practice_exam'
:
True
,
'is_practice_exam'
:
True
,
'display_name'
:
self
.
exam_name
,
'display_name'
:
self
.
exam_name
,
'default_time_limit_mins'
:
90
,
'default_time_limit_mins'
:
90
,
'due_date'
:
None
'due_date'
:
None
,
'hide_after_due'
:
False
,
},
},
user_role
=
'student'
user_role
=
'student'
)
)
...
@@ -1436,16 +1453,19 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1436,16 +1453,19 @@ class ProctoredExamApiTests(LoggedInTestCase):
@ddt.data
(
@ddt.data
(
(
datetime
.
now
(
pytz
.
UTC
)
+
timedelta
(
days
=
1
),
False
),
(
datetime
.
now
(
pytz
.
UTC
)
+
timedelta
(
days
=
1
),
False
),
(
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
days
=
1
),
False
),
(
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
days
=
1
),
True
),
(
datetime
.
now
(
pytz
.
UTC
)
-
timedelta
(
days
=
1
),
True
),
)
)
@ddt.unpack
@ddt.unpack
def
test_get_studentview_submitted_timed_exam_with_past_due_date
(
self
,
due_date
,
h
as_due_date_passed
):
def
test_get_studentview_submitted_timed_exam_with_past_due_date
(
self
,
due_date
,
h
ide_after_due
):
"""
"""
Test for get_student_view timed exam with the due date.
Test for get_student_view timed exam with the due date.
"""
"""
# exam is created with due datetime which has already passed
# exam is created with due datetime which has already passed
exam_id
=
self
.
_create_exam_with_due_time
(
is_proctored
=
False
,
due_date
=
due_date
)
exam_id
=
self
.
_create_exam_with_due_time
(
is_proctored
=
False
,
due_date
=
due_date
)
if
hide_after_due
:
update_exam
(
exam_id
,
hide_after_due
=
hide_after_due
)
# now create the timed_exam attempt in the submitted state
# now create the timed_exam attempt in the submitted state
self
.
_create_exam_attempt
(
exam_id
,
status
=
'submitted'
)
self
.
_create_exam_attempt
(
exam_id
,
status
=
'submitted'
)
...
@@ -1461,10 +1481,14 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1461,10 +1481,14 @@ class ProctoredExamApiTests(LoggedInTestCase):
'due_date'
:
due_date
,
'due_date'
:
due_date
,
}
}
)
)
if
not
has_due_date_passed
:
if
datetime
.
now
(
pytz
.
UTC
)
<
due_date
:
self
.
assertIn
(
self
.
timed_exam_submitted
,
rendered_response
)
self
.
assertIn
(
self
.
submitted_timed_exam_msg_with_due_date
,
rendered_response
)
self
.
assertIn
(
self
.
submitted_timed_exam_msg_with_due_date
,
rendered_response
)
elif
hide_after_due
:
self
.
assertIn
(
self
.
timed_exam_submitted
,
rendered_response
)
self
.
assertNotIn
(
self
.
submitted_timed_exam_msg_with_due_date
,
rendered_response
)
else
:
else
:
self
.
assertIsNone
(
Non
e
)
self
.
assertIsNone
(
rendered_respons
e
)
def
test_proctored_exam_attempt_with_past_due_datetime
(
self
):
def
test_proctored_exam_attempt_with_past_due_datetime
(
self
):
"""
"""
...
@@ -1925,7 +1949,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1925,7 +1949,8 @@ class ProctoredExamApiTests(LoggedInTestCase):
context
=
{
context
=
{
'is_proctored'
:
False
,
'is_proctored'
:
False
,
'display_name'
:
self
.
exam_name
,
'display_name'
:
self
.
exam_name
,
'default_time_limit_mins'
:
90
'default_time_limit_mins'
:
90
,
'hide_after_due'
:
False
,
}
}
)
)
self
.
assertNotIn
(
self
.
assertNotIn
(
...
...
edx_proctoring/tests/test_serializer.py
View file @
da76a638
...
@@ -23,7 +23,8 @@ class TestProctoredExamSerializer(unittest.TestCase):
...
@@ -23,7 +23,8 @@ class TestProctoredExamSerializer(unittest.TestCase):
'external_id'
:
'123'
,
'external_id'
:
'123'
,
'is_proctored'
:
'bla'
,
'is_proctored'
:
'bla'
,
'is_practice_exam'
:
'bla'
,
'is_practice_exam'
:
'bla'
,
'is_active'
:
'f'
'is_active'
:
'f'
,
'hide_after_due'
:
't'
,
}
}
serializer
=
ProctoredExamSerializer
(
data
=
data
)
serializer
=
ProctoredExamSerializer
(
data
=
data
)
...
...
edx_proctoring/tests/test_views.py
View file @
da76a638
...
@@ -101,7 +101,8 @@ class ProctoredExamViewTests(LoggedInTestCase):
...
@@ -101,7 +101,8 @@ class ProctoredExamViewTests(LoggedInTestCase):
'external_id'
:
'123'
,
'external_id'
:
'123'
,
'is_proctored'
:
True
,
'is_proctored'
:
True
,
'is_practice_exam'
:
False
,
'is_practice_exam'
:
False
,
'is_active'
:
True
'is_active'
:
True
,
'hide_after_due'
:
False
,
}
}
response
=
self
.
client
.
post
(
response
=
self
.
client
.
post
(
reverse
(
'edx_proctoring.proctored_exam.exam'
),
reverse
(
'edx_proctoring.proctored_exam.exam'
),
...
@@ -136,7 +137,8 @@ class ProctoredExamViewTests(LoggedInTestCase):
...
@@ -136,7 +137,8 @@ class ProctoredExamViewTests(LoggedInTestCase):
'external_id'
:
'123'
,
'external_id'
:
'123'
,
'is_proctored'
:
True
,
'is_proctored'
:
True
,
'is_practice_exam'
:
False
,
'is_practice_exam'
:
False
,
'is_active'
:
True
'is_active'
:
True
,
'hide_after_due'
:
False
,
}
}
response
=
self
.
client
.
post
(
response
=
self
.
client
.
post
(
reverse
(
'edx_proctoring.proctored_exam.exam'
),
reverse
(
'edx_proctoring.proctored_exam.exam'
),
...
...
edx_proctoring/views.py
View file @
da76a638
...
@@ -189,7 +189,8 @@ class ProctoredExamView(AuthenticatedAPIView):
...
@@ -189,7 +189,8 @@ class ProctoredExamView(AuthenticatedAPIView):
is_proctored
=
request
.
data
.
get
(
'is_proctored'
,
None
),
is_proctored
=
request
.
data
.
get
(
'is_proctored'
,
None
),
is_practice_exam
=
request
.
data
.
get
(
'is_practice_exam'
,
None
),
is_practice_exam
=
request
.
data
.
get
(
'is_practice_exam'
,
None
),
external_id
=
request
.
data
.
get
(
'external_id'
,
None
),
external_id
=
request
.
data
.
get
(
'external_id'
,
None
),
is_active
=
request
.
data
.
get
(
'is_active'
,
None
)
is_active
=
request
.
data
.
get
(
'is_active'
,
None
),
hide_after_due
=
request
.
data
.
get
(
'hide_after_due'
,
None
),
)
)
return
Response
({
'exam_id'
:
exam_id
})
return
Response
({
'exam_id'
:
exam_id
})
else
:
else
:
...
@@ -213,6 +214,7 @@ class ProctoredExamView(AuthenticatedAPIView):
...
@@ -213,6 +214,7 @@ class ProctoredExamView(AuthenticatedAPIView):
is_practice_exam
=
request
.
data
.
get
(
'is_practice_exam'
,
None
),
is_practice_exam
=
request
.
data
.
get
(
'is_practice_exam'
,
None
),
external_id
=
request
.
data
.
get
(
'external_id'
,
None
),
external_id
=
request
.
data
.
get
(
'external_id'
,
None
),
is_active
=
request
.
data
.
get
(
'is_active'
,
None
),
is_active
=
request
.
data
.
get
(
'is_active'
,
None
),
hide_after_due
=
request
.
data
.
get
(
'hide_after_due'
,
None
),
)
)
return
Response
({
'exam_id'
:
exam_id
})
return
Response
({
'exam_id'
:
exam_id
})
except
ProctoredExamNotFoundException
,
ex
:
except
ProctoredExamNotFoundException
,
ex
:
...
...
setup.py
View file @
da76a638
...
@@ -34,7 +34,7 @@ def load_requirements(*requirements_paths):
...
@@ -34,7 +34,7 @@ def load_requirements(*requirements_paths):
setup
(
setup
(
name
=
'edx-proctoring'
,
name
=
'edx-proctoring'
,
version
=
'0.12.1
5
'
,
version
=
'0.12.1
6
'
,
description
=
'Proctoring subsystem for Open edX'
,
description
=
'Proctoring subsystem for Open edX'
,
long_description
=
open
(
'README.md'
)
.
read
(),
long_description
=
open
(
'README.md'
)
.
read
(),
author
=
'edX'
,
author
=
'edX'
,
...
...
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