Commit fa19afd7 by chrisndodge

Merge pull request #221 from edx/rc/release-0.10.x

Rc/release 0.10.x
parents b8332996 b757a025
......@@ -15,13 +15,13 @@ In order to use edx-proctoring, you must obtain an account (and secret configura
CONFIGURATION:
You will need to turn on the ENABLE_PROCTORED_EXAMS in lms.env.json and cms.env.json FEATURES dictionary:
You will need to turn on the ENABLE_SPECIAL_EXAMS in lms.env.json and cms.env.json FEATURES dictionary:
```
:
"FEATURES": {
:
"ENABLE_PROCTORED_EXAMS": true,
"ENABLE_SPECIAL_EXAMS": true,
:
}
```
......
......@@ -49,14 +49,6 @@ from edx_proctoring.runtime import get_runtime_service
log = logging.getLogger(__name__)
def is_feature_enabled():
"""
Returns if this feature has been enabled in our FEATURE flags
"""
return hasattr(settings, 'FEATURES') and settings.FEATURES.get('ENABLE_PROCTORED_EXAMS', False)
def create_exam(course_id, content_id, exam_name, time_limit_mins, due_date=None,
is_proctored=True, is_practice_exam=False, external_id=None, is_active=True):
"""
......@@ -475,7 +467,7 @@ def create_exam_attempt(exam_id, user_id, taking_as_proctored=False):
update_attempt_status(
exam_id,
user_id,
ProctoredExamStudentAttemptStatus.declined
ProctoredExamStudentAttemptStatus.expired
)
log_msg = (
......@@ -1297,15 +1289,12 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
# time limit, including any accommodations
allowed_time_limit_mins = exam['time_limit_mins']
allowance = ProctoredExamStudentAllowance.get_allowance_for_user(
exam_id,
user_id,
"Additional time (minutes)"
)
allowance_extra_mins = ProctoredExamStudentAllowance.get_additional_time_granted(exam_id, user_id)
if allowance:
allowed_time_limit_mins += int(allowance.value)
if allowance_extra_mins:
allowed_time_limit_mins += int(allowance_extra_mins)
# apply any cut off times according to due dates
allowed_time_limit_mins, _ = _calculate_allowed_mins(
exam['due_date'],
allowed_time_limit_mins
......@@ -1328,6 +1317,7 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id):
'total_time': total_time,
'has_due_date': has_due_date,
'exam_id': exam_id,
'exam_name': exam['exam_name'],
'progress_page_url': progress_page_url,
'does_time_remain': _does_time_remain(attempt),
'enter_exam_endpoint': reverse('edx_proctoring.proctored_exam.attempt.collection'),
......
......@@ -154,8 +154,8 @@ var edx = edx || {};
}
_.each(data_json.proctored_exam_attempts, function(proctored_exam_attempt) {
if (proctored_exam_attempt.taking_as_proctored) {
if (proctored_exam_attempt.is_sample_attempt) {
if (proctored_exam_attempt.proctored_exam.is_proctored) {
if (proctored_exam_attempt.proctored_exam.is_practice_exam) {
proctored_exam_attempt.exam_attempt_type = gettext('Practice');
} else {
proctored_exam_attempt.exam_attempt_type = gettext('Proctored');
......
......@@ -12,9 +12,7 @@
{% endblocktrans %}
</p>
<button class="gated-sequence start-timed-exam" data-ajax-url="{{enter_exam_endpoint}}" data-exam-id="{{exam_id}}" data-attempt-proctored=true data-start-immediately=false>
<a>
{% trans "Continue to my practice exam" %}
</a>
<p>
{% blocktrans %}
You will be guided through steps to set up online proctoring software and to perform various checks.
......
......@@ -12,7 +12,7 @@
{% endblocktrans %}
</div>
<div class="proctored-exam-skip-actions">
<button class="proctored-exam-skip-confirm-button btn btn-primary btn-base" data-ajax-url="{{enter_exam_endpoint}}" data-exam-id="{{exam_id}}">
<button class="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" %}
</button>
<button class="proctored-exam-skip-cancel-button btn btn-default btn-base">
......
......@@ -11,9 +11,7 @@
{% endblocktrans %}
</p>
<button class="gated-sequence start-timed-exam" data-ajax-url="{{enter_exam_endpoint}}" data-exam-id="{{exam_id}}" data-attempt-proctored=true data-start-immediately=false>
<a>
{% trans "Continue to my proctored exam. I want to be eligible for credit." %}
</a>
{% trans "Continue to my proctored exam. I want to be eligible for credit." %}
<p>
{% blocktrans %}
You will be guided through steps to set up online proctoring software and to perform various checks.</br>
......@@ -23,9 +21,7 @@
<i class="fa fa-arrow-circle-right"></i>
</button>
<button class="gated-sequence start-timed-exam" data-attempt-proctored=false>
<a>
{% trans "Take this exam without proctoring." %}
</a>
{% trans "Take this exam without proctoring." %}
<i class="fa fa-arrow-circle-right"></i>
<p>
{% blocktrans %}
......
......@@ -15,7 +15,7 @@
{% endblocktrans %}
</p>
<div>
<button type="button" class="proctored-enter-exam btn btn-primary btn-base" data-action="start" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}">
<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}}">
{% blocktrans %}
Start my exam
{% endblocktrans %}
......
......@@ -12,13 +12,13 @@
as well as achieve a final grade that meets credit requirements for the course.
{% endblocktrans %}
</p>
<button type="button" name="submit-proctored-exam" class="exam-action-button btn btn-primary btn-base" data-action="submit" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}">
<button type="button" name="submit-proctored-exam" class="exam-action-button btn btn-pl-primary btn-base" data-action="submit" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}">
{% blocktrans %}
Yes, end my proctored exam
{% endblocktrans %}
</button>
{% if does_time_remain %}
<button type="button" name="goback-proctored-exam" class="exam-action-button btn btn-secondary btn-base" data-action="start" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}">
<button type="button" name="goback-proctored-exam" class="exam-action-button btn btn-secondary btn-base" data-action="start" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}" style="box-shadow: none">
{% blocktrans %}
No, I'd like to continue working
{% endblocktrans %}
......
......@@ -2,7 +2,7 @@
<div class="sequence timed-exam entrance" data-exam-id="{{exam_id}}">
<h3>
{% blocktrans %}
{{ display_name }} is a Timed Exam ({{total_time}})
{{ exam_name }} is a Timed Exam ({{total_time}})
{% endblocktrans %}
</h3>
<p>
......
......@@ -10,13 +10,13 @@
Make sure your answers are ready to be submitted, and then submit your exam. Your exam will then be graded.
{% endblocktrans %}
</p>
<button type="button" name="submit-proctored-exam" class="exam-action-button btn btn-primary btn-base" data-action="submit" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}">
<button type="button" name="submit-proctored-exam" class="exam-action-button btn btn-pl-primary btn-base" data-action="submit" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}">
{% blocktrans %}
Yes, submit my timed exam.
{% endblocktrans %}
</button>
{% if does_time_remain %}
<button type="button" name="goback-proctored-exam" class="exam-action-button btn btn-secondary btn-base" data-action="start" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}">
<button type="button" name="goback-proctored-exam" class="exam-action-button btn btn-secondary btn-base" data-action="start" data-exam-id="{{exam_id}}" data-change-state-url="{{change_state_url}}" style="box-shadow: none">
{% blocktrans %}
No, I want to continue working.
{% endblocktrans %}
......
......@@ -31,7 +31,6 @@ from edx_proctoring.api import (
remove_exam_attempt,
get_all_exam_attempts,
get_filtered_exam_attempts,
is_feature_enabled,
mark_exam_attempt_timeout,
mark_exam_attempt_as_ready,
update_attempt_status,
......@@ -95,7 +94,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
self.value = '10'
self.external_id = 'test_external_id'
self.proctored_exam_id = self._create_proctored_exam()
self.timed_exam = self._create_timed_exam()
self.timed_exam_id = self._create_timed_exam()
self.practice_exam_id = self._create_practice_exam()
self.disabled_exam_id = self._create_disabled_exam()
......@@ -276,7 +275,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
else:
exam_id = self.proctored_exam_id
else:
exam_id = self.timed_exam
exam_id = self.timed_exam_id
return ProctoredExamStudentAttempt.objects.create(
proctored_exam_id=exam_id,
......@@ -291,7 +290,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
Creates the ProctoredExamStudentAttempt object.
"""
return ProctoredExamStudentAttempt.objects.create(
proctored_exam_id=self.proctored_exam_id if is_proctored else self.timed_exam,
proctored_exam_id=self.proctored_exam_id if is_proctored else self.timed_exam_id,
user_id=self.user_id,
external_id=self.external_id,
started_at=started_at if started_at else datetime.now(pytz.UTC),
......@@ -324,18 +323,6 @@ class ProctoredExamApiTests(LoggedInTestCase):
proctored_exam_id=self.proctored_exam_id, user_id=self.user_id, key=self.key, value=self.value
)
def test_feature_enabled(self):
"""
Checks the is_feature_enabled method
"""
self.assertFalse(is_feature_enabled())
with patch.dict('django.conf.settings.FEATURES', {'ENABLE_PROCTORED_EXAMS': False}):
self.assertFalse(is_feature_enabled())
with patch.dict('django.conf.settings.FEATURES', {'ENABLE_PROCTORED_EXAMS': True}):
self.assertTrue(is_feature_enabled())
def test_create_duplicate_exam(self):
"""
Test to create a proctored exam that has already exist in the
......@@ -414,7 +401,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
test to get the exam by the exam_id and
then compare their values.
"""
timed_exam = get_exam_by_id(self.timed_exam)
timed_exam = get_exam_by_id(self.timed_exam_id)
self.assertEqual(timed_exam['course_id'], self.course_id)
self.assertEqual(timed_exam['content_id'], self.content_id_timed)
self.assertEqual(timed_exam['exam_name'], self.exam_name)
......@@ -546,7 +533,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
with freeze_time(reset_time):
attempt_id = create_exam_attempt(exam_id, self.user_id)
attempt = get_exam_attempt_by_id(attempt_id)
self.assertEqual(attempt['status'], ProctoredExamStudentAttemptStatus.declined)
self.assertEqual(attempt['status'], ProctoredExamStudentAttemptStatus.expired)
def test_create_an_exam_attempt(self):
"""
......@@ -1647,29 +1634,26 @@ class ProctoredExamApiTests(LoggedInTestCase):
But user has an allowance
"""
ProctoredExamStudentAllowance.objects.create(
proctored_exam_id=self.timed_exam,
user_id=self.user_id,
key='Additional time (minutes)',
value=15
allowed_extra_time = 10
add_allowance_for_user(
self.timed_exam_id,
self.user.username,
ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED,
str(allowed_extra_time)
)
rendered_response = get_student_view(
user_id=self.user_id,
course_id=self.course_id,
content_id=self.content_id_timed,
context={
'is_proctored': False,
'display_name': self.exam_name,
'default_time_limit_mins': 90
}
context={}
)
self.assertNotIn(
'data-exam-id="{proctored_exam_id}"'.format(proctored_exam_id=self.proctored_exam_id),
rendered_response
)
self.assertIn(self.timed_exam_msg.format(exam_name=self.exam_name), rendered_response)
self.assertIn('36 minutes', rendered_response)
self.assertIn('31 minutes', rendered_response)
self.assertNotIn(self.start_an_exam_msg.format(exam_name=self.exam_name), rendered_response)
@ddt.data(
......@@ -1696,9 +1680,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
course_id=self.course_id,
content_id=self.content_id_timed,
context={
'is_proctored': False,
'display_name': self.exam_name,
'default_time_limit_mins': 90
}
)
self.assertIn(expected_content, rendered_response)
......@@ -2102,7 +2084,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
Assert that we get the expected status summaries
for the timed exams.
"""
timed_exam = get_exam_by_id(self.timed_exam)
timed_exam = get_exam_by_id(self.timed_exam_id)
summary = get_attempt_status_summary(
self.user.id,
timed_exam['course_id'],
......
......@@ -34,7 +34,7 @@ def load_requirements(*requirements_paths):
setup(
name='edx-proctoring',
version='0.10.10',
version='0.10.15',
description='Proctoring subsystem for Open edX',
long_description=open('README.md').read(),
author='edX',
......
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