Commit 340bb79c by Chris Dodge

do polling to see when the students attempt status has transitioned to a…

do polling to see when the students attempt status has transitioned to a completed state, then shut down the proctoring software
parent a401b0f1
"""
Various callback paths
Various callback paths that support callbacks from SoftwareSecure
"""
import logging
from django.template import Context, loader
from django.http import HttpResponse
from django.core.urlresolvers import reverse
from rest_framework.views import APIView
from rest_framework.response import Response
......@@ -27,7 +28,10 @@ def start_exam_callback(request, attempt_code): # pylint: disable=unused-argume
NOTE: This returns HTML as it will be displayed in an embedded browser
This is an authenticated endpoint and the attempt_code is passed in
as a query string parameter
as part of the URL path
IMPORTANT: This is an unauthenticated endpoint, so be VERY CAREFUL about extending
this endpoint
"""
attempt = get_exam_attempt_by_code(attempt_code)
......@@ -41,13 +45,27 @@ def start_exam_callback(request, attempt_code): # pylint: disable=unused-argume
template = loader.get_template('proctoring/proctoring_launch_callback.html')
return HttpResponse(template.render(Context({})))
poll_url = reverse(
'edx_proctoring.anonymous.proctoring_poll_status',
args=[attempt_code]
)
return HttpResponse(
template.render(
Context({
'exam_attempt_status_url': poll_url,
})
)
)
class ExamReviewCallback(APIView):
"""
This endpoint is called by a 3rd party proctoring review service when
there are results available for us to record
IMPORTANT: This is an unauthenticated endpoint, so be VERY CAREFUL about extending
this endpoint
"""
def post(self, request):
......@@ -63,3 +81,36 @@ class ExamReviewCallback(APIView):
data='OK',
status=200
)
class AttemptStatus(APIView):
"""
This endpoint is called by a 3rd party proctoring review service to determine
status of an exam attempt.
IMPORTANT: This is an unauthenticated endpoint, so be VERY CAREFUL about extending
this endpoint
"""
def get(self, request, attempt_code): # pylint: disable=unused-argument
"""
Returns the status of an exam attempt. Given that this is an unauthenticated
caller, we will only return the status string, no additional information
about the exam
"""
attempt = get_exam_attempt_by_code(attempt_code)
if not attempt:
return HttpResponse(
content='You have entered an exam code that is not valid.',
status=404
)
return Response(
data={
# IMPORTANT: Don't add more information to this as it is an
# unauthenticated endpoint
'status': attempt['status'],
},
status=200
)
......@@ -145,7 +145,7 @@
background: rgb(8, 92, 150);
}
</style>
<link rel="stylesheet" href="main.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
</head>
{% load i18n %}
<body>
......@@ -200,6 +200,29 @@
</div>
</div>
<script type="text/javascript">
var _poll_interval = null;
$(document).ready(function() {
_poll_interval = setInterval(
poll_exam_status,
5000
);
});
function poll_exam_status() {
var url = '{{exam_attempt_status_url}}';
$.ajax(url).success(function(data){
// has the end user completed the exam in the LMS?!?
if (data.status === 'completed' || data.status === 'submitted' || data.status === 'verified') {
// Signal that the desktop software should terminate
// NOTE: This is per the API documentation from SoftwareSecure
window.external.quitApplication();
}
});
}
</script>
</body>
</html>
......@@ -66,6 +66,10 @@ urlpatterns = patterns( # pylint: disable=invalid-name
views.ActiveExamsForUserView.as_view(),
name='edx_proctoring.proctored_exam.active_exams_for_user'
),
#
# Unauthenticated callbacks from SoftwareSecure. Note we use other
# security token measures to protect data
#
url(
r'edx_proctoring/proctoring_launch_callback/start_exam/(?P<attempt_code>[-\w]+)$',
callbacks.start_exam_callback,
......@@ -76,5 +80,10 @@ urlpatterns = patterns( # pylint: disable=invalid-name
callbacks.ExamReviewCallback.as_view(),
name='edx_proctoring.anonymous.proctoring_review_callback'
),
url(
r'edx_proctoring/proctoring_poll_status/(?P<attempt_code>[-\w]+)$',
callbacks.AttemptStatus.as_view(),
name='edx_proctoring.anonymous.proctoring_poll_status'
),
url(r'^', include('rest_framework.urls', namespace='rest_framework'))
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment