Commit b070ed0d by chrisndodge

Merge pull request #25 from edx/cdodge/click-through-link-for-download

integrate with new SoftwareSecure v2.x build
parents de4b37df c0612897
...@@ -9,6 +9,7 @@ API which is in the views.py file, per edX coding standards ...@@ -9,6 +9,7 @@ API which is in the views.py file, per edX coding standards
import pytz import pytz
import uuid import uuid
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django.conf import settings
from django.template import Context, loader from django.template import Context, loader
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
...@@ -206,9 +207,12 @@ def create_exam_attempt(exam_id, user_id, taking_as_proctored=False): ...@@ -206,9 +207,12 @@ def create_exam_attempt(exam_id, user_id, taking_as_proctored=False):
external_id = None external_id = None
if taking_as_proctored: if taking_as_proctored:
callback_url = reverse( callback_url = 'http://{hostname}{path}'.format(
'edx_proctoring.anonymous.proctoring_launch_callback.start_exam', hostname=settings.SITE_NAME,
args=[attempt_code] path=reverse(
'edx_proctoring.anonymous.proctoring_launch_callback.start_exam',
args=[attempt_code]
)
) )
# now call into the backend provider to register exam attempt # now call into the backend provider to register exam attempt
...@@ -425,8 +429,12 @@ def get_student_view(user_id, course_id, content_id, context): ...@@ -425,8 +429,12 @@ def get_student_view(user_id, course_id, content_id, context):
if not attempt: if not attempt:
student_view_template = 'proctoring/seq_proctored_exam_entrance.html' student_view_template = 'proctoring/seq_proctored_exam_entrance.html'
else: else:
provider = get_backend_provider()
student_view_template = 'proctoring/seq_proctored_exam_instructions.html' student_view_template = 'proctoring/seq_proctored_exam_instructions.html'
context.update({'exam_code': attempt['attempt_code']}) context.update({
'exam_code': attempt['attempt_code'],
'software_download_url': provider.get_software_download_url(),
})
else: else:
student_view_template = 'proctoring/seq_timed_exam_entrance.html' student_view_template = 'proctoring/seq_timed_exam_entrance.html'
elif has_finished_exam: elif has_finished_exam:
......
...@@ -36,3 +36,11 @@ class ProctoringBackendProvider(object): ...@@ -36,3 +36,11 @@ class ProctoringBackendProvider(object):
to establish a new proctored exam to establish a new proctored exam
""" """
raise NotImplementedError() raise NotImplementedError()
@abc.abstractmethod
def get_software_download_url(self):
"""
Returns the URL that the user needs to go to in order to download
the corresponding desktop software
"""
raise NotImplementedError()
...@@ -30,3 +30,10 @@ class NullBackendProvider(ProctoringBackendProvider): ...@@ -30,3 +30,10 @@ class NullBackendProvider(ProctoringBackendProvider):
to establish a new proctored exam to establish a new proctored exam
""" """
return None return None
def get_software_download_url(self):
"""
Returns the URL that the user needs to go to in order to download
the corresponding desktop software
"""
return None
...@@ -26,7 +26,7 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider): ...@@ -26,7 +26,7 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider):
""" """
def __init__(self, organization, exam_sponsor, exam_register_endpoint, def __init__(self, organization, exam_sponsor, exam_register_endpoint,
secret_key_id, secret_key, crypto_key): secret_key_id, secret_key, crypto_key, software_download_url):
""" """
Class initializer Class initializer
""" """
...@@ -38,6 +38,7 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider): ...@@ -38,6 +38,7 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider):
self.secret_key = secret_key self.secret_key = secret_key
self.crypto_key = crypto_key self.crypto_key = crypto_key
self.timeout = 10 self.timeout = 10
self.software_download_url = software_download_url
def register_exam_attempt(self, exam, time_limit_mins, attempt_code, def register_exam_attempt(self, exam, time_limit_mins, attempt_code,
is_sample_attempt, callback_url): is_sample_attempt, callback_url):
...@@ -91,6 +92,13 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider): ...@@ -91,6 +92,13 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider):
""" """
return None return None
def get_software_download_url(self):
"""
Returns the URL that the user needs to go to in order to download
the corresponding desktop software
"""
return self.software_download_url
def _encrypt_password(self, key, pwd): def _encrypt_password(self, key, pwd):
""" """
Encrypt the exam passwork with the given key Encrypt the exam passwork with the given key
...@@ -125,9 +133,7 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider): ...@@ -125,9 +133,7 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider):
"examName": exam['exam_name'], "examName": exam['exam_name'],
"ssiProduct": 'rp-now', "ssiProduct": 'rp-now',
# need to pass in a URL to the LMS? # need to pass in a URL to the LMS?
"examUrl": ( "examUrl": callback_url,
'http://localhost:8000/{}'.format(callback_url)
),
"orgExtra": { "orgExtra": {
"examStartDate": start_time_str, "examStartDate": start_time_str,
"examEndDate": end_time_str, "examEndDate": end_time_str,
......
...@@ -33,6 +33,13 @@ class TestBackendProvider(ProctoringBackendProvider): ...@@ -33,6 +33,13 @@ class TestBackendProvider(ProctoringBackendProvider):
""" """
return None return None
def get_software_download_url(self):
"""
Returns the URL that the user needs to go to in order to download
the corresponding desktop software
"""
return None
class PassthroughBackendProvider(ProctoringBackendProvider): class PassthroughBackendProvider(ProctoringBackendProvider):
""" """
...@@ -72,6 +79,13 @@ class PassthroughBackendProvider(ProctoringBackendProvider): ...@@ -72,6 +79,13 @@ class PassthroughBackendProvider(ProctoringBackendProvider):
attempt attempt
) )
def get_software_download_url(self):
"""
Returns the URL that the user needs to go to in order to download
the corresponding desktop software
"""
return super(PassthroughBackendProvider, self).get_software_download_url()
class TestBackends(TestCase): class TestBackends(TestCase):
""" """
...@@ -94,6 +108,9 @@ class TestBackends(TestCase): ...@@ -94,6 +108,9 @@ class TestBackends(TestCase):
with self.assertRaises(NotImplementedError): with self.assertRaises(NotImplementedError):
provider.stop_exam_attempt(None, None) provider.stop_exam_attempt(None, None)
with self.assertRaises(NotImplementedError):
provider.get_software_download_url()
def test_null_provider(self): def test_null_provider(self):
""" """
Assert that the Null provider does nothing Assert that the Null provider does nothing
...@@ -104,3 +121,4 @@ class TestBackends(TestCase): ...@@ -104,3 +121,4 @@ class TestBackends(TestCase):
self.assertIsNone(provider.register_exam_attempt(None, None, None, None, None)) self.assertIsNone(provider.register_exam_attempt(None, None, None, None, None))
self.assertIsNone(provider.start_exam_attempt(None, None)) self.assertIsNone(provider.start_exam_attempt(None, None))
self.assertIsNone(provider.stop_exam_attempt(None, None)) self.assertIsNone(provider.stop_exam_attempt(None, None))
self.assertIsNone(provider.get_software_download_url())
...@@ -55,6 +55,7 @@ def response_error(url, request): # pylint: disable=unused-argument ...@@ -55,6 +55,7 @@ def response_error(url, request): # pylint: disable=unused-argument
"exam_register_endpoint": "http://test", "exam_register_endpoint": "http://test",
"organization": "edx", "organization": "edx",
"exam_sponsor": "edX LMS", "exam_sponsor": "edX LMS",
"software_download_url": "http://example.com"
} }
} }
) )
...@@ -78,6 +79,14 @@ class SoftwareSecureTests(TestCase): ...@@ -78,6 +79,14 @@ class SoftwareSecureTests(TestCase):
provider = get_backend_provider() provider = get_backend_provider()
self.assertIsNotNone(provider) self.assertIsNotNone(provider)
def test_get_software_download_url(self):
"""
Makes sure we get the expected download url
"""
provider = get_backend_provider()
self.assertEqual(provider.get_software_download_url(), 'http://example.com')
def test_register_attempt(self): def test_register_attempt(self):
""" """
Makes sure we can register an attempt Makes sure we can register an attempt
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<p> <p>
{% blocktrans %} {% blocktrans %}
You've chosen to take {{display_name}} as a proctored exam. You should be directed to a new window You've chosen to take {{display_name}} as a proctored exam. You should be directed to a new window
with installation and setup instructions. You can also <a href="#">open the installation window directly.</a> with installation and setup instructions. You can also <a href="{{software_download_url}}" target="_blank">open the installation window directly.</a>
{% endblocktrans %} {% endblocktrans %}
</p> </p>
<div class="proctored-exam-message"> <div class="proctored-exam-message">
......
...@@ -25,6 +25,7 @@ DATABASES = { ...@@ -25,6 +25,7 @@ DATABASES = {
} }
SITE_ID = 1 SITE_ID = 1
SITE_NAME = 'localhost:8000'
INSTALLED_APPS = ( INSTALLED_APPS = (
'django.contrib.auth', 'django.contrib.auth',
......
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