Integration of edx_proctoring into the LMS

This commit is contained in:
Chris Dodge
2015-07-24 20:22:38 -04:00
parent 5b9b0a8339
commit 6cf5516a84
59 changed files with 2541 additions and 98 deletions

View File

@@ -28,7 +28,7 @@ def register_proctored_exams(course_key):
This is typically called on a course published signal. The course is examined for sequences
that are marked as timed exams. Then these are registered with the edx-proctoring
subsystem. Likewise, if formerly registered exams are unmarked, then those
registred exams are marked as inactive
registered exams are marked as inactive
"""
if not settings.FEATURES.get('ENABLE_PROCTORED_EXAMS'):
@@ -76,6 +76,7 @@ def register_proctored_exams(course_key):
exam_name=timed_exam.display_name,
time_limit_mins=timed_exam.default_time_limit_minutes,
is_proctored=timed_exam.is_proctored_enabled,
is_practice_exam=timed_exam.is_practice_exam,
is_active=True
)
msg = 'Updated timed exam {exam_id}'.format(exam_id=exam['id'])
@@ -87,6 +88,7 @@ def register_proctored_exams(course_key):
exam_name=timed_exam.display_name,
time_limit_mins=timed_exam.default_time_limit_minutes,
is_proctored=timed_exam.is_proctored_enabled,
is_practice_exam=timed_exam.is_practice_exam,
is_active=True
)
msg = 'Created new timed exam {exam_id}'.format(exam_id=exam_id)

View File

@@ -862,7 +862,8 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
xblock_info.update({
"is_proctored_enabled": xblock.is_proctored_enabled,
"is_time_limited": xblock.is_time_limited,
"default_time_limit_minutes": xblock.default_time_limit_minutes
"default_time_limit_minutes": xblock.default_time_limit_minutes,
"is_practice_exam": xblock.is_practice_exam
})
# Entrance exam subsection should be hidden. in_entrance_exam is inherited metadata, all children will have it.

View File

@@ -352,7 +352,6 @@ XBLOCK_SETTINGS = ENV_TOKENS.get('XBLOCK_SETTINGS', {})
XBLOCK_SETTINGS.setdefault("VideoDescriptor", {})["licensing_enabled"] = FEATURES.get("LICENSING", False)
XBLOCK_SETTINGS.setdefault("VideoModule", {})['YOUTUBE_API_KEY'] = AUTH_TOKENS.get('YOUTUBE_API_KEY', YOUTUBE_API_KEY)
################# PROCTORING CONFIGURATION ##################
PROCTORING_BACKEND_PROVIDER = AUTH_TOKENS.get("PROCTORING_BACKEND_PROVIDER", PROCTORING_BACKEND_PROVIDER)

View File

@@ -77,7 +77,8 @@
"SUBDOMAIN_BRANDING": false,
"SUBDOMAIN_COURSE_LISTINGS": false,
"ALLOW_ALL_ADVANCED_COMPONENTS": true,
"ENABLE_CONTENT_LIBRARIES": true
"ENABLE_CONTENT_LIBRARIES": true,
"ENABLE_PROCTORED_EXAMS": true
},
"FEEDBACK_SUBMISSION_EMAIL": "",
"GITHUB_REPO_ROOT": "** OVERRIDDEN **",

View File

@@ -101,6 +101,8 @@ FEATURES['ENABLE_VIDEO_BUMPER'] = True # Enable video bumper in Studio settings
########################### Entrance Exams #################################
FEATURES['ENTRANCE_EXAMS'] = True
FEATURES['ENABLE_PROCTORED_EXAMS'] = True
# Point the URL used to test YouTube availability to our stub YouTube server
YOUTUBE_PORT = 9080
YOUTUBE['API'] = "http://127.0.0.1:{0}/get_youtube_api/".format(YOUTUBE_PORT)

View File

@@ -173,6 +173,9 @@ FEATURES = {
# Show video bumper in Studio
'ENABLE_VIDEO_BUMPER': False,
# Timed Proctored Exams
'ENABLE_PROCTORED_EXAMS': False,
# How many seconds to show the bumper again, default is 7 days:
'SHOW_BUMPER_PERIODICITY': 7 * 24 * 3600,
@@ -775,6 +778,9 @@ INSTALLED_APPS = (
'openedx.core.djangoapps.credit',
'xblock_django',
# edX Proctoring
'edx_proctoring',
)
@@ -1040,11 +1046,10 @@ CREDIT_PROVIDER_TIMESTAMP_EXPIRATION = 15 * 60
DEPRECATED_BLOCK_TYPES = ['peergrading', 'combinedopenended']
#### PROCTORING CONFIGURATION DEFAULTS
PROCTORING_BACKEND_PROVIDER = {
'class': 'edx_proctoring.backends.NullBackendProvider',
'class': 'edx_proctoring.backends.null.NullBackendProvider',
'options': {},
}
PROCTORING_SETTINGS = {}

View File

@@ -620,6 +620,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "js/views/utils/view_ut
has_explicit_staff_lock: true,
staff_only_message: true,
"is_time_limited": true,
"is_practice_exam": false,
"is_proctored_enabled": true,
"default_time_limit_minutes": 150
}, [
@@ -706,6 +707,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "js/views/utils/view_ut
"start":"2014-07-09T00:00:00.000Z",
"due":"2014-07-10T00:00:00.000Z",
"is_time_limited": true,
"is_practice_exam": false,
"is_proctored_enabled": true,
"default_time_limit_minutes": 150
}
@@ -740,6 +742,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "js/views/utils/view_ut
expect($("#staff_lock").is(":checked")).toBe(true);
expect($("#id_timed_examination").is(":checked")).toBe(true);
expect($("#id_exam_proctoring").is(":checked")).toBe(true);
expect($("#is_practice_exam").is(":checked")).toBe(false);
expect($("#id_time_limit").val()).toBe("02:30");
});

View File

@@ -275,11 +275,17 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
event.preventDefault();
if (!$(event.currentTarget).is(':checked')) {
this.$('#id_exam_proctoring').attr('checked', false);
this.$('#id_time_limit').val('00:30');
this.$('#id_time_limit').val('00:00');
this.$('#id_exam_proctoring').attr('disabled','disabled');
this.$('#id_time_limit').attr('disabled', 'disabled');
this.$('#id_practice_exam').attr('checked', false);
this.$('#id_practice_exam').attr('disabled','disabled');
}
else {
if (!this.isValidTimeLimit(this.$('#id_time_limit').val())) {
this.$('#id_time_limit').val('00:30');
}
this.$('#id_practice_exam').removeAttr('disabled');
this.$('#id_exam_proctoring').removeAttr('disabled');
this.$('#id_time_limit').removeAttr('disabled');
}
@@ -289,11 +295,17 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
AbstractEditor.prototype.afterRender.call(this);
this.$('input.time').timepicker({
'timeFormat' : 'H:i',
'minTime': '00:30',
'maxTime': '05:00',
'forceRoundTime': false
});
this.setExamTime(this.model.get('default_time_limit_minutes'));
this.setExamTmePreference(this.model.get('is_time_limited'));
this.setExamProctoring(this.model.get('is_proctored_enabled'));
this.setPracticeExam(this.model.get('is_practice_exam'));
},
setPracticeExam: function(value) {
this.$('#id_practice_exam').prop('checked', value);
},
setExamProctoring: function(value) {
this.$('#id_exam_proctoring').prop('checked', value);
@@ -307,14 +319,18 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
if (!this.$('#id_timed_examination').is(':checked')) {
this.$('#id_exam_proctoring').attr('disabled','disabled');
this.$('#id_time_limit').attr('disabled', 'disabled');
this.$('#id_practice_exam').attr('disabled', 'disabled');
}
},
isExamTimeEnabled: function () {
return this.$('#id_timed_examination').is(':checked');
},
isPracticeExam: function () {
return this.$('#id_practice_exam').is(':checked');
},
isValidTimeLimit: function(time_limit) {
var pattern = new RegExp('^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$');
return pattern.test(time_limit);
return pattern.test(time_limit) && time_limit !== "00:00";
},
getExamTimeLimit: function () {
return this.$('#id_time_limit').val();
@@ -338,6 +354,7 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
var time_limit = this.getExamTimeLimit();
return {
metadata: {
'is_practice_exam': this.isPracticeExam(),
'is_time_limited': this.isExamTimeEnabled(),
'is_proctored_enabled': this.isExamProctoringEnabled(),
'default_time_limit_minutes': this.convertTimeLimitToMinutes(time_limit)

View File

@@ -24,6 +24,17 @@
<p class='field-message'><%- gettext('Students see warnings when 20% and 5% of the allotted time remains. In certain cases, students can be granted allowances that give them extra time to complete the exam.') %></p>
</ul>
</div>
<ul class="list-fields list-input">
<li class="field field-checkbox checkbox-cosmetic">
<input type="checkbox" id="id_practice_exam" name="practice_exam" class="input input-checkbox" />
<label for="id_practice_exam" class="label">
<i class="icon fa fa-check-square-o input-checkbox-checked"></i>
<i class="icon fa fa-square-o input-checkbox-unchecked"></i>
<%- gettext('This exam is for practice only') %>
</label>
</li>
<p class='field-message'> <%- gettext('Learners can experience the proctoring software setup process and try some example problems. Make sure this practice exam is set up as an ungraded exam.') %> </p>
</ul>
<ul class="list-fields list-input">
<li class="field field-checkbox checkbox-cosmetic">
<input type="checkbox" id="id_exam_proctoring" name="exam_proctoring" class="input input-checkbox" />