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
a7389c5d
Commit
a7389c5d
authored
Aug 05, 2015
by
Chris Dodge
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
complete providing attempt summary info
parent
2f9b287c
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
197 additions
and
45 deletions
+197
-45
edx_proctoring/api.py
+57
-43
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 @
a7389c5d
...
@@ -7,7 +7,11 @@ API which is in the views.py file, per edX coding standards
...
@@ -7,7 +7,11 @@ API which is in the views.py file, per edX coding standards
"""
"""
import
pytz
import
pytz
import
uuid
import
uuid
import
logging
from
datetime
import
datetime
,
timedelta
from
datetime
import
datetime
,
timedelta
from
django.utils.translation
import
ugettext
as
_
from
django.conf
import
settings
from
django.conf
import
settings
from
django.template
import
Context
,
loader
from
django.template
import
Context
,
loader
from
django.core.urlresolvers
import
reverse
,
NoReverseMatch
from
django.core.urlresolvers
import
reverse
,
NoReverseMatch
...
@@ -36,6 +40,8 @@ from edx_proctoring.utils import humanized_time
...
@@ -36,6 +40,8 @@ from edx_proctoring.utils import humanized_time
from
edx_proctoring.backends
import
get_backend_provider
from
edx_proctoring.backends
import
get_backend_provider
from
edx_proctoring.runtime
import
get_runtime_service
from
edx_proctoring.runtime
import
get_runtime_service
log
=
logging
.
getLogger
(
"edx_proctoring_views"
)
def
is_feature_enabled
():
def
is_feature_enabled
():
"""
"""
...
@@ -646,6 +652,45 @@ def _check_credit_eligibility(credit_state):
...
@@ -646,6 +652,45 @@ def _check_credit_eligibility(credit_state):
return
True
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
):
def
get_attempt_status_summary
(
user_id
,
course_id
,
content_id
):
"""
"""
Returns a summary about the status of the attempt for the user
Returns a summary about the status of the attempt for the user
...
@@ -657,7 +702,8 @@ def get_attempt_status_summary(user_id, course_id, content_id):
...
@@ -657,7 +702,8 @@ def get_attempt_status_summary(user_id, course_id, content_id):
{
{
'status': ['eligible', 'declined', 'submitted', 'verified', 'rejected'],
'status': ['eligible', 'declined', 'submitted', 'verified', 'rejected'],
'short_description': <short description of status>,
'short_description': <short description of status>,
'suggested-icon': <recommended font-awesome icon to use>
'suggested_icon': <recommended font-awesome icon to use>,
'in_completed_state': <if the status is considered in a 'completed' state>
}
}
"""
"""
...
@@ -675,50 +721,18 @@ def get_attempt_status_summary(user_id, course_id, content_id):
...
@@ -675,50 +721,18 @@ def get_attempt_status_summary(user_id, course_id, content_id):
log
.
exception
(
ex
)
log
.
exception
(
ex
)
return
None
return
None
attempt
=
get_exam_attempt
(
exam_id
,
user_id
)
attempt
=
get_exam_attempt
(
exam
[
'id'
],
user_id
)
status
=
attempt
[
'status'
]
if
attempt
else
ProctoredExamStudentAttemptStatus
.
eligible
if
not
attempt
:
summary
=
None
return
{
if
status
in
STATUS_SUMMARY_MAP
:
'status'
:
ProctoredExamStudentAttemptStatus
.
eligible
,
summary
=
STATUS_SUMMARY_MAP
[
status
]
'short_description'
:
_
(
'Proctored Option Available'
),
'suggested-icon'
:
'fa-lock'
}
elif
attempt
[
'status'
]
==
ProctoredExamStudentAttemptStatus
.
declined
:
return
{
'status'
:
ProctoredExamStudentAttemptStatus
.
eligible
,
'short_description'
:
_
(
'Taking As Open Exam'
),
'suggested-icon'
:
'fa-unlock'
}
elif
attempt
[
'status'
]
==
ProctoredExamStudentAttemptStatus
.
submitted
:
return
{
'status'
:
ProctoredExamStudentAttemptStatus
.
submitted
,
'short_description'
:
_
(
'Pending Session Review'
),
'suggested-icon'
:
'fa-unlock'
}
elif
attempt
[
'status'
]
==
ProctoredExamStudentAttemptStatus
.
verified
:
return
{
'status'
:
ProctoredExamStudentAttemptStatus
.
submitted
,
'short_description'
:
_
(
'Passed Proctoring'
),
'suggested-icon'
:
'fa-check'
}
elif
attempt
[
'status'
]
==
ProctoredExamStudentAttemptStatus
.
rejected
:
return
{
'status'
:
ProctoredExamStudentAttemptStatus
.
rejected
,
'short_description'
:
_
(
'Failed Proctoring'
),
'suggested-icon'
:
'fa-exclamation-triangle'
}
elif
attempt
[
'status'
]
==
ProctoredExamStudentAttemptStatus
.
started
:
return
{
'status'
:
ProctoredExamStudentAttemptStatus
.
started
,
'short_description'
:
_
(
'Taking As Proctored Exam'
),
'suggested-icon'
:
'fa-lock'
}
else
:
else
:
return
{
summary
=
STATUS_SUMMARY_MAP
[
'_default'
]
'status'
:
ProctoredExamStudentAttemptStatus
.
eligible
,
'short_description'
:
_
(
'Proctored Option Available'
),
summary
.
update
({
"status"
:
status
})
'suggested-icon'
:
'fa-lock'
}
return
summary
def
get_student_view
(
user_id
,
course_id
,
content_id
,
def
get_student_view
(
user_id
,
course_id
,
content_id
,
...
...
edx_proctoring/tests/test_api.py
View file @
a7389c5d
...
@@ -33,6 +33,7 @@ from edx_proctoring.api import (
...
@@ -33,6 +33,7 @@ from edx_proctoring.api import (
mark_exam_attempt_timeout
,
mark_exam_attempt_timeout
,
mark_exam_attempt_as_ready
,
mark_exam_attempt_as_ready
,
update_attempt_status
,
update_attempt_status
,
get_attempt_status_summary
,
)
)
from
edx_proctoring.exceptions
import
(
from
edx_proctoring.exceptions
import
(
ProctoredExamAlreadyExists
,
ProctoredExamAlreadyExists
,
...
@@ -1160,3 +1161,140 @@ class ProctoredExamApiTests(LoggedInTestCase):
...
@@ -1160,3 +1161,140 @@ class ProctoredExamApiTests(LoggedInTestCase):
exam_attempt
[
'status'
],
exam_attempt
[
'status'
],
ProctoredExamStudentAttemptStatus
.
ready_to_submit
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 @
a7389c5d
...
@@ -17,12 +17,12 @@ class MockCreditService(object):
...
@@ -17,12 +17,12 @@ class MockCreditService(object):
Simple mock of the Credit Service
Simple mock of the Credit Service
"""
"""
def
__init__
(
self
):
def
__init__
(
self
,
enrollment_mode
=
'verified'
):
"""
"""
Initializer
Initializer
"""
"""
self
.
status
=
{
self
.
status
=
{
'enrollment_mode'
:
'verified'
,
'enrollment_mode'
:
enrollment_mode
,
'profile_fullname'
:
'Wolfgang von Strucker'
,
'profile_fullname'
:
'Wolfgang von Strucker'
,
'credit_requirement_status'
:
[]
'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