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
6a1a6b7a
Commit
6a1a6b7a
authored
Aug 05, 2015
by
chrisndodge
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #63 from edx/cdodge/add-nav-states
Cdodge/add nav states
parents
3e6edabd
b1282624
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
229 additions
and
2 deletions
+229
-2
edx_proctoring/api.py
+89
-0
edx_proctoring/tests/test_api.py
+138
-0
edx_proctoring/tests/test_services.py
+2
-2
No files found.
edx_proctoring/api.py
View file @
6a1a6b7a
...
...
@@ -7,7 +7,11 @@ API which is in the views.py file, per edX coding standards
"""
import
pytz
import
uuid
import
logging
from
datetime
import
datetime
,
timedelta
from
django.utils.translation
import
ugettext
as
_
from
django.conf
import
settings
from
django.template
import
Context
,
loader
from
django.core.urlresolvers
import
reverse
,
NoReverseMatch
...
...
@@ -36,6 +40,8 @@ from edx_proctoring.utils import humanized_time
from
edx_proctoring.backends
import
get_backend_provider
from
edx_proctoring.runtime
import
get_runtime_service
log
=
logging
.
getLogger
(
__name__
)
def
is_feature_enabled
():
"""
...
...
@@ -646,6 +652,89 @@ def _check_credit_eligibility(credit_state):
return
True
STATUS_SUMMARY_MAP
=
{
'_default'
:
{
'short_description'
:
_
(
'Taking As Proctored Exam'
),
'suggested_icon'
:
'fa-lock'
,
'in_completed_state'
:
False
},
ProctoredExamStudentAttemptStatus
.
eligible
:
{
'short_description'
:
_
(
'Proctored Option Available'
),
'suggested_icon'
:
'fa-lock'
,
'in_completed_state'
:
False
},
ProctoredExamStudentAttemptStatus
.
declined
:
{
'short_description'
:
_
(
'Taking As Open Exam'
),
'suggested_icon'
:
'fa-unlock'
,
'in_completed_state'
:
False
},
ProctoredExamStudentAttemptStatus
.
submitted
:
{
'short_description'
:
_
(
'Pending Session Review'
),
'suggested_icon'
:
'fa-spinner fa-spin'
,
'in_completed_state'
:
True
},
ProctoredExamStudentAttemptStatus
.
verified
:
{
'short_description'
:
_
(
'Passed Proctoring'
),
'suggested_icon'
:
'fa-check'
,
'in_completed_state'
:
True
},
ProctoredExamStudentAttemptStatus
.
rejected
:
{
'short_description'
:
_
(
'Failed Proctoring'
),
'suggested_icon'
:
'fa-exclamation-triangle'
,
'in_completed_state'
:
True
},
ProctoredExamStudentAttemptStatus
.
error
:
{
'short_description'
:
_
(
'Failed Proctoring'
),
'suggested_icon'
:
'fa-exclamation-triangle'
,
'in_completed_state'
:
True
}
}
def
get_attempt_status_summary
(
user_id
,
course_id
,
content_id
):
"""
Returns a summary about the status of the attempt for the user
in the course_id and content_id
Return will be:
None: Not applicable
- or -
{
'status': ['eligible', 'declined', 'submitted', 'verified', 'rejected'],
'short_description': <short description of status>,
'suggested_icon': <recommended font-awesome icon to use>,
'in_completed_state': <if the status is considered in a 'completed' state>
}
"""
# as a quick exit, let's check credit eligibility
credit_service
=
get_runtime_service
(
'credit'
)
if
credit_service
:
credit_state
=
credit_service
.
get_credit_state
(
user_id
,
unicode
(
course_id
))
if
not
_check_credit_eligibility
(
credit_state
):
return
None
try
:
exam
=
get_exam_by_content_id
(
course_id
,
content_id
)
except
ProctoredExamNotFoundException
,
ex
:
# this really shouldn't happen, but log it at least
log
.
exception
(
ex
)
return
None
attempt
=
get_exam_attempt
(
exam
[
'id'
],
user_id
)
status
=
attempt
[
'status'
]
if
attempt
else
ProctoredExamStudentAttemptStatus
.
eligible
summary
=
None
if
status
in
STATUS_SUMMARY_MAP
:
summary
=
STATUS_SUMMARY_MAP
[
status
]
else
:
summary
=
STATUS_SUMMARY_MAP
[
'_default'
]
summary
.
update
({
"status"
:
status
})
return
summary
def
get_student_view
(
user_id
,
course_id
,
content_id
,
context
,
user_role
=
'student'
):
"""
...
...
edx_proctoring/tests/test_api.py
View file @
6a1a6b7a
...
...
@@ -33,6 +33,7 @@ from edx_proctoring.api import (
mark_exam_attempt_timeout
,
mark_exam_attempt_as_ready
,
update_attempt_status
,
get_attempt_status_summary
,
)
from
edx_proctoring.exceptions
import
(
ProctoredExamAlreadyExists
,
...
...
@@ -1160,3 +1161,140 @@ class ProctoredExamApiTests(LoggedInTestCase):
exam_attempt
[
'status'
],
ProctoredExamStudentAttemptStatus
.
ready_to_submit
)
@ddt.data
(
(
ProctoredExamStudentAttemptStatus
.
eligible
,
{
'status'
:
ProctoredExamStudentAttemptStatus
.
eligible
,
'short_description'
:
'Proctored Option Available'
,
'suggested_icon'
:
'fa-lock'
,
'in_completed_state'
:
False
}
),
(
ProctoredExamStudentAttemptStatus
.
declined
,
{
'status'
:
ProctoredExamStudentAttemptStatus
.
declined
,
'short_description'
:
'Taking As Open Exam'
,
'suggested_icon'
:
'fa-unlock'
,
'in_completed_state'
:
False
}
),
(
ProctoredExamStudentAttemptStatus
.
submitted
,
{
'status'
:
ProctoredExamStudentAttemptStatus
.
submitted
,
'short_description'
:
'Pending Session Review'
,
'suggested_icon'
:
'fa-spinner fa-spin'
,
'in_completed_state'
:
True
}
),
(
ProctoredExamStudentAttemptStatus
.
verified
,
{
'status'
:
ProctoredExamStudentAttemptStatus
.
verified
,
'short_description'
:
'Passed Proctoring'
,
'suggested_icon'
:
'fa-check'
,
'in_completed_state'
:
True
}
),
(
ProctoredExamStudentAttemptStatus
.
rejected
,
{
'status'
:
ProctoredExamStudentAttemptStatus
.
rejected
,
'short_description'
:
'Failed Proctoring'
,
'suggested_icon'
:
'fa-exclamation-triangle'
,
'in_completed_state'
:
True
}
),
(
ProctoredExamStudentAttemptStatus
.
error
,
{
'status'
:
ProctoredExamStudentAttemptStatus
.
error
,
'short_description'
:
'Failed Proctoring'
,
'suggested_icon'
:
'fa-exclamation-triangle'
,
'in_completed_state'
:
True
}
),
(
ProctoredExamStudentAttemptStatus
.
created
,
{
'status'
:
ProctoredExamStudentAttemptStatus
.
created
,
'short_description'
:
'Taking As Proctored Exam'
,
'suggested_icon'
:
'fa-lock'
,
'in_completed_state'
:
False
}
),
(
ProctoredExamStudentAttemptStatus
.
ready_to_start
,
{
'status'
:
ProctoredExamStudentAttemptStatus
.
ready_to_start
,
'short_description'
:
'Taking As Proctored Exam'
,
'suggested_icon'
:
'fa-lock'
,
'in_completed_state'
:
False
}
),
(
ProctoredExamStudentAttemptStatus
.
started
,
{
'status'
:
ProctoredExamStudentAttemptStatus
.
started
,
'short_description'
:
'Taking As Proctored Exam'
,
'suggested_icon'
:
'fa-lock'
,
'in_completed_state'
:
False
}
),
(
ProctoredExamStudentAttemptStatus
.
ready_to_submit
,
{
'status'
:
ProctoredExamStudentAttemptStatus
.
ready_to_submit
,
'short_description'
:
'Taking As Proctored Exam'
,
'suggested_icon'
:
'fa-lock'
,
'in_completed_state'
:
False
}
)
)
@ddt.unpack
def
test_attempt_status_summary
(
self
,
status
,
expected
):
"""
Assert that we get the expected status summaries
"""
exam_attempt
=
self
.
_create_started_exam_attempt
()
update_attempt_status
(
exam_attempt
.
proctored_exam_id
,
self
.
user
.
id
,
status
)
summary
=
get_attempt_status_summary
(
self
.
user
.
id
,
exam_attempt
.
proctored_exam
.
course_id
,
exam_attempt
.
proctored_exam
.
content_id
)
self
.
assertIn
(
summary
,
[
expected
])
@ddt.data
(
'honor'
,
'staff'
)
def
test_status_summary_honor
(
self
,
enrollment_mode
):
"""
Make sure status summary is None for a non-verified person
"""
set_runtime_service
(
'credit'
,
MockCreditService
(
enrollment_mode
=
enrollment_mode
))
exam_attempt
=
self
.
_create_started_exam_attempt
()
summary
=
get_attempt_status_summary
(
self
.
user
.
id
,
exam_attempt
.
proctored_exam
.
course_id
,
exam_attempt
.
proctored_exam
.
content_id
)
self
.
assertIsNone
(
summary
)
def
test_status_summary_bad
(
self
):
"""
Make sure we get back a None when getting summary for content that does not
exist
"""
summary
=
get_attempt_status_summary
(
self
.
user
.
id
,
'foo'
,
'foo'
)
self
.
assertIsNone
(
summary
)
edx_proctoring/tests/test_services.py
View file @
6a1a6b7a
...
...
@@ -17,12 +17,12 @@ class MockCreditService(object):
Simple mock of the Credit Service
"""
def
__init__
(
self
):
def
__init__
(
self
,
enrollment_mode
=
'verified'
):
"""
Initializer
"""
self
.
status
=
{
'enrollment_mode'
:
'verified'
,
'enrollment_mode'
:
enrollment_mode
,
'profile_fullname'
:
'Wolfgang von Strucker'
,
'credit_requirement_status'
:
[]
}
...
...
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