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
a9aeb462
Unverified
Commit
a9aeb462
authored
Nov 10, 2017
by
Rabia Iftikhar
Committed by
GitHub
Nov 10, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #391 from edx/ri/EDUCATOR-1648
EDUCATOR-1648 give proctored exams access to course staff
parents
580c32ad
4ca93ade
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
24 additions
and
36 deletions
+24
-36
edx_proctoring/api.py
+2
-2
edx_proctoring/models.py
+3
-13
edx_proctoring/tests/test_api.py
+1
-1
edx_proctoring/tests/test_views.py
+13
-10
edx_proctoring/views.py
+5
-10
No files found.
edx_proctoring/api.py
View file @
a9aeb462
...
...
@@ -353,12 +353,12 @@ def add_allowance_for_user(exam_id, user_info, key, value):
emit_event
(
exam
,
'allowance.{action}'
.
format
(
action
=
action
),
override_data
=
data
)
def
get_allowances_for_course
(
course_id
,
timed_exams_only
=
False
):
def
get_allowances_for_course
(
course_id
):
"""
Get all the allowances for the course.
"""
student_allowances
=
ProctoredExamStudentAllowance
.
get_allowances_for_course
(
course_id
,
timed_exams_only
=
timed_exams_only
course_id
)
return
[
ProctoredExamStudentAllowanceSerializer
(
allowance
)
.
data
for
allowance
in
student_allowances
]
...
...
edx_proctoring/models.py
View file @
a9aeb462
...
...
@@ -394,27 +394,20 @@ class ProctoredExamStudentAttemptManager(models.Manager):
exam_attempt_obj
=
None
return
exam_attempt_obj
def
get_all_exam_attempts
(
self
,
course_id
,
timed_exams_only
=
False
):
def
get_all_exam_attempts
(
self
,
course_id
):
"""
Returns the Student Exam Attempts for the given course_id.
"""
filtered_query
=
Q
(
proctored_exam__course_id
=
course_id
)
if
timed_exams_only
:
filtered_query
=
filtered_query
&
Q
(
proctored_exam__is_proctored
=
False
)
return
self
.
filter
(
filtered_query
)
.
order_by
(
'-created'
)
def
get_filtered_exam_attempts
(
self
,
course_id
,
search_by
,
timed_exams_only
=
False
):
def
get_filtered_exam_attempts
(
self
,
course_id
,
search_by
):
"""
Returns the Student Exam Attempts for the given course_id filtered by search_by.
"""
filtered_query
=
Q
(
proctored_exam__course_id
=
course_id
)
&
(
Q
(
user__username__contains
=
search_by
)
|
Q
(
user__email__contains
=
search_by
)
)
if
timed_exams_only
:
filtered_query
=
filtered_query
&
Q
(
proctored_exam__is_proctored
=
False
)
return
self
.
filter
(
filtered_query
)
.
order_by
(
'-created'
)
# pylint: disable=no-member
def
get_proctored_exam_attempts
(
self
,
course_id
,
username
):
...
...
@@ -720,14 +713,11 @@ class ProctoredExamStudentAllowance(TimeStampedModel):
verbose_name
=
'proctored allowance'
@classmethod
def
get_allowances_for_course
(
cls
,
course_id
,
timed_exams_only
=
False
):
def
get_allowances_for_course
(
cls
,
course_id
):
"""
Returns all the allowances for a course.
"""
filtered_query
=
Q
(
proctored_exam__course_id
=
course_id
)
if
timed_exams_only
:
filtered_query
=
filtered_query
&
Q
(
proctored_exam__is_proctored
=
False
)
return
cls
.
objects
.
filter
(
filtered_query
)
@classmethod
...
...
edx_proctoring/tests/test_api.py
View file @
a9aeb462
...
...
@@ -409,7 +409,7 @@ class ProctoredExamApiTests(ProctoredExamTestCase):
Test to get all the allowances for a course.
"""
allowance
=
self
.
_add_allowance_for_user
()
course_allowances
=
get_allowances_for_course
(
self
.
course_id
,
False
)
course_allowances
=
get_allowances_for_course
(
self
.
course_id
)
self
.
assertEqual
(
len
(
course_allowances
),
1
)
self
.
assertEqual
(
course_allowances
[
0
][
'proctored_exam'
][
'course_id'
],
allowance
.
proctored_exam
.
course_id
)
...
...
edx_proctoring/tests/test_views.py
View file @
a9aeb462
...
...
@@ -1190,11 +1190,10 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
response_data
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
len
(
response_data
[
'proctored_exam_attempts'
]),
1
)
def
test_exam_attempts_not_staff
(
self
):
def
test_exam_attempts_not_
global_
staff
(
self
):
"""
Test to get the exam attempts in a course as a not
staff user but still we get the timed exams attempts
but not the proctored exam attempts
Test to get both timed and proctored exam attempts
in a course as a course staff
"""
# Create an timed_exam.
timed_exam
=
ProctoredExam
.
objects
.
create
(
...
...
@@ -1241,11 +1240,15 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
response
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
response_data
=
json
.
loads
(
response
.
content
)
#
we should only get the timed exam attempt in this case
# so the len should be
1
self
.
assertEqual
(
len
(
response_data
[
'proctored_exam_attempts'
]),
1
)
#
assert that both timed and proctored exam attempts are in response data
# so the len should be
2
self
.
assertEqual
(
len
(
response_data
[
'proctored_exam_attempts'
]),
2
)
self
.
assertEqual
(
response_data
[
'proctored_exam_attempts'
][
0
][
'proctored_exam'
][
'is_proctored'
],
proctored_exam
.
is_proctored
)
self
.
assertEqual
(
response_data
[
'proctored_exam_attempts'
][
1
][
'proctored_exam'
][
'is_proctored'
],
timed_exam
.
is_proctored
)
...
...
@@ -2317,9 +2320,9 @@ class TestExamAllowanceView(LoggedInTestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
response_data
=
json
.
loads
(
response
.
content
)
#
we should only get the timed exam allowance
#
We are not logged in as a global user
self
.
assertEqual
(
len
(
response_data
),
1
)
#
assert that both timed and proctored exams allowance are in response data
#
so the len should be 2
self
.
assertEqual
(
len
(
response_data
),
2
)
self
.
assertEqual
(
response_data
[
0
][
'proctored_exam'
][
'course_id'
],
timed_exam
.
course_id
)
self
.
assertEqual
(
response_data
[
0
][
'proctored_exam'
][
'content_id'
],
timed_exam
.
content_id
)
self
.
assertEqual
(
response_data
[
0
][
'key'
],
allowance_data
[
'key'
])
...
...
edx_proctoring/views.py
View file @
a9aeb462
...
...
@@ -611,18 +611,16 @@ class StudentProctoredExamAttemptsByCourse(AuthenticatedAPIView):
def
get
(
self
,
request
,
course_id
,
search_by
=
None
):
# pylint: disable=unused-argument
"""
HTTP GET Handler. Returns the status of the exam attempt.
Course and Global staff can view both timed and proctored exam attempts.
"""
# course staff only views attempts of timed exams. edx staff can view both timed and proctored attempts.
time_exams_only
=
not
request
.
user
.
is_staff
if
search_by
is
not
None
:
exam_attempts
=
ProctoredExamStudentAttempt
.
objects
.
get_filtered_exam_attempts
(
course_id
,
search_by
,
time_exams_only
course_id
,
search_by
)
attempt_url
=
reverse
(
'edx_proctoring.proctored_exam.attempts.search'
,
args
=
[
course_id
,
search_by
])
else
:
exam_attempts
=
ProctoredExamStudentAttempt
.
objects
.
get_all_exam_attempts
(
course_id
,
time_exams_only
course_id
)
attempt_url
=
reverse
(
'edx_proctoring.proctored_exam.attempts.course'
,
args
=
[
course_id
])
...
...
@@ -701,13 +699,10 @@ class ExamAllowanceView(AuthenticatedAPIView):
def
get
(
self
,
request
,
course_id
):
# pylint: disable=unused-argument
"""
HTTP GET handler. Get all allowances for a course.
Course and Global staff can view both timed and proctored exam allowances.
"""
# course staff only views attempts of timed exams. edx staff can view both timed and proctored attempts.
time_exams_only
=
not
request
.
user
.
is_staff
result_set
=
get_allowances_for_course
(
course_id
=
course_id
,
timed_exams_only
=
time_exams_only
course_id
=
course_id
)
return
Response
(
result_set
)
...
...
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