Commit aae446e6 by chrisndodge

Merge pull request #34 from edx/cdodge/pass-user-name

Cdodge/pass user name
parents 85b670d9 e01228a7
......@@ -34,6 +34,7 @@ from edx_proctoring.serializers import (
from edx_proctoring.utils import humanized_time
from edx_proctoring.backends import get_backend_provider
from edx_proctoring.runtime import get_runtime_service
def is_feature_enabled():
......@@ -235,13 +236,24 @@ def create_exam_attempt(exam_id, user_id, taking_as_proctored=False):
)
)
# get the name of the user, if the service is available
full_name = None
profile_service = get_runtime_service('profile')
if profile_service:
profile = profile_service(user_id)
full_name = profile['name']
# now call into the backend provider to register exam attempt
external_id = get_backend_provider().register_exam_attempt(
exam,
allowed_time_limit_mins,
attempt_code,
False,
callback_url
context={
'time_limit_mins': allowed_time_limit_mins,
'attempt_code': attempt_code,
'is_sample_attempt': False,
'callback_url': callback_url,
'full_name': full_name,
}
)
attempt = ProctoredExamStudentAttempt.create_exam_attempt(
......
......@@ -14,8 +14,7 @@ class ProctoringBackendProvider(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def register_exam_attempt(self, exam, time_limit_mins, attempt_code,
is_sample_attempt, callback_url):
def register_exam_attempt(self, exam, context):
"""
Called when the exam attempt has been created but not started
"""
......
......@@ -10,8 +10,7 @@ class NullBackendProvider(ProctoringBackendProvider):
Implementation of the ProctoringBackendProvider that does nothing
"""
def register_exam_attempt(self, exam, time_limit_mins, attempt_code,
is_sample_attempt, callback_url):
def register_exam_attempt(self, exam, context):
"""
Called when the exam attempt has been created but not started
"""
......
......@@ -40,19 +40,17 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider):
self.timeout = 10
self.software_download_url = software_download_url
def register_exam_attempt(self, exam, time_limit_mins, attempt_code,
is_sample_attempt, callback_url):
def register_exam_attempt(self, exam, context):
"""
Method that is responsible for communicating with the backend provider
to establish a new proctored exam
"""
attempt_code = context['attempt_code']
data = self._get_payload(
exam,
time_limit_mins,
attempt_code,
is_sample_attempt,
callback_url
context
)
headers = {
"Content-Type": 'application/json'
......@@ -114,11 +112,25 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider):
encrypted_text = cipher.encrypt(pad(pwd))
return base64.b64encode(encrypted_text)
def _get_payload(self, exam, time_limit_mins, attempt_code,
is_sample_attempt, callback_url):
def _get_payload(self, exam, context):
"""
Constructs the data payload that Software Secure expects
"""
attempt_code = context['attempt_code']
time_limit_mins = context['time_limit_mins']
is_sample_attempt = context['is_sample_attempt']
callback_url = context['callback_url']
full_name = context['full_name']
first_name = ''
last_name = ''
if full_name:
name_elements = full_name.split(' ')
first_name = name_elements[0]
if len(name_elements) > 1:
last_name = ' '.join(name_elements[1:])
now = datetime.datetime.utcnow()
start_time_str = now.strftime("%a, %d %b %Y %H:%M:%S GMT")
end_time_str = (now + datetime.timedelta(minutes=time_limit_mins)).strftime("%a, %d %b %Y %H:%M:%S GMT")
......@@ -140,6 +152,8 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider):
"noOfStudents": 1,
"examID": exam['id'],
"courseID": exam['course_id'],
"firstName": first_name,
"lastName": last_name,
}
}
......
......@@ -12,8 +12,7 @@ class TestBackendProvider(ProctoringBackendProvider):
Implementation of the ProctoringBackendProvider that does nothing
"""
def register_exam_attempt(self, exam, time_limit_mins, attempt_code,
is_sample_attempt, callback_url):
def register_exam_attempt(self, exam, context):
"""
Called when the exam attempt has been created but not started
"""
......@@ -46,17 +45,13 @@ class PassthroughBackendProvider(ProctoringBackendProvider):
Implementation of the ProctoringBackendProvider that just calls the base class
"""
def register_exam_attempt(self, exam, time_limit_mins, attempt_code,
is_sample_attempt, callback_url):
def register_exam_attempt(self, exam, context):
"""
Called when the exam attempt has been created but not started
"""
return super(PassthroughBackendProvider, self).register_exam_attempt(
exam,
time_limit_mins,
attempt_code,
is_sample_attempt,
callback_url
context
)
def start_exam_attempt(self, exam, attempt):
......@@ -100,7 +95,7 @@ class TestBackends(TestCase):
provider = PassthroughBackendProvider()
with self.assertRaises(NotImplementedError):
provider.register_exam_attempt(None, None, None, None, None)
provider.register_exam_attempt(None, None)
with self.assertRaises(NotImplementedError):
provider.start_exam_attempt(None, None)
......@@ -118,7 +113,7 @@ class TestBackends(TestCase):
provider = NullBackendProvider()
self.assertIsNone(provider.register_exam_attempt(None, None, None, None, None))
self.assertIsNone(provider.register_exam_attempt(None, None))
self.assertIsNone(provider.start_exam_attempt(None, None))
self.assertIsNone(provider.stop_exam_attempt(None, None))
self.assertIsNone(provider.get_software_download_url())
......@@ -8,13 +8,13 @@ import json
from django.test import TestCase
from django.contrib.auth.models import User
from edx_proctoring.runtime import set_runtime_service
from edx_proctoring.backends import get_backend_provider
from edx_proctoring.exceptions import BackendProvideCannotRegisterAttempt
from edx_proctoring.api import get_exam_attempt_by_id
from edx_proctoring.api import (
get_exam_attempt_by_id,
create_exam,
create_exam_attempt,
)
......@@ -71,6 +71,20 @@ class SoftwareSecureTests(TestCase):
self.user = User(username='foo', email='foo@bar.com')
self.user.save()
def mock_profile_service(user_id): # pylint: disable=unused-argument
"""
Mocked out Profile callback endpoint
"""
return {'name': 'Wolfgang von Strucker'}
set_runtime_service('profile', mock_profile_service)
def tearDown(self):
"""
When tests are done
"""
set_runtime_service('profile', None)
def test_provider_instance(self):
"""
Makes sure the instance of the proctoring module can be created
......@@ -108,6 +122,31 @@ class SoftwareSecureTests(TestCase):
self.assertEqual(attempt['external_id'], 'foobar')
self.assertIsNone(attempt['started_at'])
def test_single_name_attempt(self):
"""
Tests to make sure we can parse a fullname which does not have any spaces in it
"""
def mock_profile_service(user_id): # pylint: disable=unused-argument
"""
Mocked out Profile callback endpoint
"""
return {'name': 'Bono'}
set_runtime_service('profile', mock_profile_service)
exam_id = create_exam(
course_id='foo/bar/baz',
content_id='content',
exam_name='Sample Exam',
time_limit_mins=10,
is_proctored=True
)
with HTTMock(response_content):
attempt_id = create_exam_attempt(exam_id, self.user.id, taking_as_proctored=True)
self.assertIsNotNone(attempt_id)
def test_failing_register_attempt(self):
"""
Makes sure we can register an attempt
......
"""
Runtime services that the LMS can register than we can callback on
"""
_RUNTIME_SERVICES = {}
def set_runtime_service(name, callback):
"""
Adds a service provided by the runtime (aka LMS) to our directory
"""
_RUNTIME_SERVICES[name] = callback
def get_runtime_service(name):
"""
Returns a registered runtime service, None if no match is found
"""
return _RUNTIME_SERVICES.get(name)
......@@ -26,8 +26,12 @@
</div>
</div>
<div class="footer-sequence border-b-0 padding-b-0">
<span> {% trans "Note: As soon as you finish installing and setting up the proctoring software,
you will be prompted to start your timed exam." %} </span>
<span>
{% blocktrans %}
Note: As soon as you finish installing and setting up the proctoring software,
you will be prompted to start your timed exam.
{% endblocktrans %}
</span>
<p>
{% blocktrans %}
Be prepared to start your exam and to complete it while adhering to the {{platform_name}}
......
......@@ -3,7 +3,9 @@ Test for the xBlock service
"""
import unittest
from edx_proctoring.services import ProctoringService
from edx_proctoring.services import (
ProctoringService
)
from edx_proctoring import api as edx_proctoring_api
import types
......
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