Commit 089e1d69 by chrisndodge

Merge pull request #228 from edx/cdodge/release-rebase3

Cdodge/release rebase3
parents 1d8b10f6 f4898f58
...@@ -36,6 +36,9 @@ from edx_proctoring.serializers import ( ...@@ -36,6 +36,9 @@ from edx_proctoring.serializers import (
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
SOFTWARE_SECURE_INVALID_CHARS = '[]<>#:|?/\'"*\\'
class SoftwareSecureBackendProvider(ProctoringBackendProvider): class SoftwareSecureBackendProvider(ProctoringBackendProvider):
""" """
Implementation of the ProctoringBackendProvider for Software Secure's Implementation of the ProctoringBackendProvider for Software Secure's
...@@ -372,6 +375,10 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider): ...@@ -372,6 +375,10 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider):
now = datetime.datetime.utcnow() now = datetime.datetime.utcnow()
start_time_str = now.strftime("%a, %d %b %Y %H:%M:%S GMT") 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") end_time_str = (now + datetime.timedelta(minutes=time_limit_mins)).strftime("%a, %d %b %Y %H:%M:%S GMT")
# remove all illegal characters from the exam name
exam_name = exam['exam_name']
for character in SOFTWARE_SECURE_INVALID_CHARS:
exam_name = exam_name.replace(character, '_')
return { return {
"examCode": attempt_code, "examCode": attempt_code,
"organization": self.organization, "organization": self.organization,
...@@ -382,7 +389,7 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider): ...@@ -382,7 +389,7 @@ class SoftwareSecureBackendProvider(ProctoringBackendProvider):
"reviewerNotes": reviewer_notes, "reviewerNotes": reviewer_notes,
"examPassword": self._encrypt_password(self.crypto_key, attempt_code), "examPassword": self._encrypt_password(self.crypto_key, attempt_code),
"examSponsor": self.exam_sponsor, "examSponsor": self.exam_sponsor,
"examName": exam['exam_name'], "examName": 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": callback_url, "examUrl": callback_url,
......
...@@ -41,9 +41,12 @@ from edx_proctoring.models import ( ...@@ -41,9 +41,12 @@ from edx_proctoring.models import (
ProctoredExamStudentAttemptHistory, ProctoredExamStudentAttemptHistory,
ProctoredExamStudentAllowance ProctoredExamStudentAllowance
) )
from edx_proctoring.backends.tests.test_review_payload import TEST_REVIEW_PAYLOAD from edx_proctoring.backends.tests.test_review_payload import (
TEST_REVIEW_PAYLOAD
)
from edx_proctoring.tests.test_services import MockCreditService from edx_proctoring.tests.test_services import MockCreditService
from edx_proctoring.backends.software_secure import SOFTWARE_SECURE_INVALID_CHARS
@all_requests @all_requests
...@@ -216,14 +219,6 @@ class SoftwareSecureTests(TestCase): ...@@ -216,14 +219,6 @@ class SoftwareSecureTests(TestCase):
Create an unstarted proctoring attempt with no review policy associated with it. Create an unstarted proctoring attempt with no review policy associated with it.
""" """
exam_id = create_exam(
course_id='foo/bar/baz',
content_id='content',
exam_name='Sample Exam',
time_limit_mins=10,
is_proctored=True
)
def assert_get_payload_mock_no_policy(exam, context): def assert_get_payload_mock_no_policy(exam, context):
""" """
Add a mock shim so we can assert that the _get_payload has been called with the right Add a mock shim so we can assert that the _get_payload has been called with the right
...@@ -236,23 +231,40 @@ class SoftwareSecureTests(TestCase): ...@@ -236,23 +231,40 @@ class SoftwareSecureTests(TestCase):
# assert that we use the default that is defined in system configuration # assert that we use the default that is defined in system configuration
self.assertEqual(result['reviewerNotes'], constants.DEFAULT_SOFTWARE_SECURE_REVIEW_POLICY) self.assertEqual(result['reviewerNotes'], constants.DEFAULT_SOFTWARE_SECURE_REVIEW_POLICY)
# the check that if a colon was passed in for the exam name, then the colon was changed to
# a dash. This is because SoftwareSecure cannot handle a colon in the exam name
for illegal_char in SOFTWARE_SECURE_INVALID_CHARS:
if illegal_char in exam['exam_name']:
self.assertNotIn(illegal_char, result['examName'])
self.assertIn('_', result['examName'])
return result return result
with HTTMock(mock_response_content): for illegal_char in SOFTWARE_SECURE_INVALID_CHARS:
# patch the _get_payload method on the backend provider exam_id = create_exam(
# so that we can assert that we are called with the review policy course_id='foo/bar/baz',
# undefined and that we use the system default content_id='content with {}'.format(illegal_char),
with patch.object(get_backend_provider(), '_get_payload', assert_get_payload_mock_no_policy): # pylint: disable=protected-access exam_name='Sample Exam with {} character'.format(illegal_char),
attempt_id = create_exam_attempt( time_limit_mins=10,
exam_id, is_proctored=True
self.user.id, )
taking_as_proctored=True
)
self.assertGreater(attempt_id, 0)
# make sure we recorded that there is no review policy with HTTMock(mock_response_content):
attempt = get_exam_attempt_by_id(attempt_id) # patch the _get_payload method on the backend provider
self.assertIsNone(attempt['review_policy_id']) # so that we can assert that we are called with the review policy
# undefined and that we use the system default
with patch.object(get_backend_provider(), '_get_payload', assert_get_payload_mock_no_policy): # pylint: disable=protected-access
attempt_id = create_exam_attempt(
exam_id,
self.user.id,
taking_as_proctored=True
)
self.assertGreater(attempt_id, 0)
# make sure we recorded that there is no review policy
attempt = get_exam_attempt_by_id(attempt_id)
self.assertIsNone(attempt['review_policy_id'])
def test_single_name_attempt(self): def test_single_name_attempt(self):
""" """
......
...@@ -60,7 +60,7 @@ class ProctoredExam(TimeStampedModel): ...@@ -60,7 +60,7 @@ class ProctoredExam(TimeStampedModel):
How to serialize myself as a string How to serialize myself as a string
""" """
return "{course_id}: {exam_name} ({active})".format( return u"{course_id}: {exam_name} ({active})".format(
course_id=self.course_id, course_id=self.course_id,
exam_name=self.exam_name, exam_name=self.exam_name,
active='active' if self.is_active else 'inactive', active='active' if self.is_active else 'inactive',
......
{% load i18n %} {% load i18n %}
<div class="proctored-exam-skip-confirm-wrapper hidden"> <div class="proctored-exam skip-confirm-wrapper warning hidden">
<div class="proctored-exam-skip-confirm"> <div class="proctored-exam-skip-confirm">
<div class="msg-title"> <div class="msg-title">
{% blocktrans %} {% blocktrans %}
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
{% endblocktrans %} {% endblocktrans %}
</div> </div>
<div class="proctored-exam-skip-actions"> <div class="proctored-exam-skip-actions">
<button class="proctored-exam-skip-confirm-button btn btn-pl-primary btn-base" data-ajax-url="{{enter_exam_endpoint}}" data-exam-id="{{exam_id}}"> <button class="exam-action-button proctored-exam-skip-confirm-button btn btn-pl-primary btn-base" data-ajax-url="{{enter_exam_endpoint}}" data-exam-id="{{exam_id}}">
{% trans "Continue Exam Without Proctoring" %} {% trans "Continue Exam Without Proctoring" %}
</button> </button>
<button class="proctored-exam-skip-cancel-button btn btn-default btn-base"> <button class="exam-action-button proctored-exam-skip-cancel-button btn btn-secondary btn-base">
{% trans "Go Back" %} {% trans "Go Back" %}
</button> </button>
</div> </div>
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
if (!inProcess) { if (!inProcess) {
enableClickEvent($(this)); enableClickEvent($(this));
$(".proctored-exam.entrance").removeClass('hidden'); $(".proctored-exam.entrance").removeClass('hidden');
$(".proctored-exam-skip-confirm-wrapper").addClass('hidden'); $(".proctored-exam.skip-confirm-wrapper").addClass('hidden');
} else { } else {
return false; return false;
} }
......
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
if (!attempt_proctored) { if (!attempt_proctored) {
enableClickEvent($(this)); enableClickEvent($(this));
$(".proctored-exam.entrance").addClass('hidden'); $(".proctored-exam.entrance").addClass('hidden');
$(".proctored-exam-skip-confirm-wrapper").removeClass('hidden'); $(".proctored-exam.skip-confirm-wrapper").removeClass('hidden');
} else { } else {
var action_url = $(this).data('ajax-url'); var action_url = $(this).data('ajax-url');
var exam_id = $(this).data('exam-id'); var exam_id = $(this).data('exam-id');
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
{% endblocktrans %} {% endblocktrans %}
</p> </p>
<div> <div>
<button type="button" class="proctored-enter-exam btn btn-pl-primary btn-base" data-action="start" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}"> <button type="button" class="exam-action-button proctored-enter-exam btn btn-pl-primary btn-base" data-action="start" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}">
{% blocktrans %} {% blocktrans %}
Start my exam Start my exam
{% endblocktrans %} {% endblocktrans %}
......
# coding=utf-8
# pylint: disable=invalid-name
""" """
All tests for the models.py All tests for the models.py
""" """
# pylint: disable=invalid-name
from edx_proctoring.models import ( from edx_proctoring.models import (
ProctoredExam, ProctoredExam,
ProctoredExamStudentAllowance, ProctoredExamStudentAllowance,
...@@ -29,6 +30,20 @@ class ProctoredExamModelTests(LoggedInTestCase): ...@@ -29,6 +30,20 @@ class ProctoredExamModelTests(LoggedInTestCase):
""" """
super(ProctoredExamModelTests, self).setUp() super(ProctoredExamModelTests, self).setUp()
def test_unicode(self):
"""
Make sure we support Unicode characters
"""
proctored_exam = ProctoredExam.objects.create(
course_id='test_course',
content_id='test_content',
exam_name=u'अआईउऊऋऌ अआईउऊऋऌ',
external_id='123aXqe3',
time_limit_mins=90
)
output = unicode(proctored_exam)
self.assertEquals(output, u"test_course: अआईउऊऋऌ अआईउऊऋऌ (inactive)")
def test_save_proctored_exam_student_allowance_history(self): # pylint: disable=invalid-name def test_save_proctored_exam_student_allowance_history(self): # pylint: disable=invalid-name
""" """
Test to Save and update the proctored Exam Student Allowance object. Test to Save and update the proctored Exam Student Allowance object.
......
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