Merge pull request #19366 from edx/dahlia/proctoring-master

Upgrade edx-proctoring to version 1.5
This commit is contained in:
Dave St.Germain
2019-01-02 11:37:55 -05:00
committed by GitHub
42 changed files with 1139 additions and 677 deletions

View File

@@ -88,7 +88,7 @@ class InstructorService(object):
"""
return auth.user_has_role(user, CourseStaffRole(CourseKey.from_string(course_id)))
def send_support_notification(self, course_id, exam_name, student_username, review_status):
def send_support_notification(self, course_id, exam_name, student_username, review_status, review_url=None):
"""
Creates a Zendesk ticket for an exam attempt review from the proctoring system.
Currently, it sends notifications for 'Suspicious" status, but additional statuses can be supported
@@ -103,15 +103,17 @@ class InstructorService(object):
if course.create_zendesk_tickets:
requester_name = "edx-proctoring"
email = "edx-proctoring@edx.org"
subject = _("Proctored Exam Review: {review_status}").format(review_status=review_status)
subject = _(u"Proctored Exam Review: {review_status}").format(review_status=review_status)
body = _(
"A proctored exam attempt for {exam_name} in {course_name} by username: {student_username} "
"was reviewed as {review_status} by the proctored exam review provider."
u"A proctored exam attempt for {exam_name} in {course_name} by username: {student_username} "
"was reviewed as {review_status} by the proctored exam review provider.\n"
"Review link: {review_url}"
).format(
exam_name=exam_name,
course_name=course.display_name,
student_username=student_username,
review_status=review_status
review_status=review_status,
review_url=review_url or u'not available',
)
tags = ["proctoring"]
create_zendesk_ticket(requester_name, email, subject, body, tags)

View File

@@ -147,21 +147,40 @@ class InstructorServiceTests(SharedModuleStoreTestCase):
"""
requester_name = "edx-proctoring"
email = "edx-proctoring@edx.org"
subject = "Proctored Exam Review: {review_status}".format(review_status="Suspicious")
subject = u"Proctored Exam Review: {review_status}".format(review_status="Suspicious")
body = "A proctored exam attempt for {exam_name} in {course_name} by username: {student_username} was " \
"reviewed as {review_status} by the proctored exam review provider."
body = body.format(
exam_name="test_exam", course_name=self.course.display_name, student_username="test_student",
review_status="Suspicious"
)
"reviewed as {review_status} by the proctored exam review provider.\n" \
"Review link: {url}"
args = {
'exam_name': 'test_exam',
'student_username': 'test_student',
'url': 'not available',
'course_name': self.course.display_name,
'review_status': 'Suspicious',
}
expected_body = body.format(**args)
tags = ["proctoring"]
with mock.patch("lms.djangoapps.instructor.services.create_zendesk_ticket") as mock_create_zendesk_ticket:
self.service.send_support_notification(
course_id=unicode(self.course.id),
exam_name="test_exam",
student_username="test_student",
review_status="Suspicious"
exam_name=args['exam_name'],
student_username=args["student_username"],
review_status="Suspicious",
review_url=None,
)
mock_create_zendesk_ticket.assert_called_with(requester_name, email, subject, body, tags)
mock_create_zendesk_ticket.assert_called_with(requester_name, email, subject, expected_body, tags)
# Now check sending a notification with a review link
args['url'] = 'http://review/url'
with mock.patch("lms.djangoapps.instructor.services.create_zendesk_ticket") as mock_create_zendesk_ticket:
self.service.send_support_notification(
course_id=unicode(self.course.id),
exam_name=args['exam_name'],
student_username=args["student_username"],
review_status="Suspicious",
review_url=args['url'],
)
expected_body = body.format(**args)
mock_create_zendesk_ticket.assert_called_with(requester_name, email, subject, expected_body, tags)

View File

@@ -892,11 +892,6 @@ CREDIT_HELP_LINK_URL = ENV_TOKENS.get('CREDIT_HELP_LINK_URL', CREDIT_HELP_LINK_U
JWT_AUTH.update(ENV_TOKENS.get('JWT_AUTH', {}))
JWT_AUTH.update(AUTH_TOKENS.get('JWT_AUTH', {}))
################# PROCTORING CONFIGURATION ##################
PROCTORING_BACKEND_PROVIDER = AUTH_TOKENS.get("PROCTORING_BACKEND_PROVIDER", PROCTORING_BACKEND_PROVIDER)
PROCTORING_SETTINGS = ENV_TOKENS.get("PROCTORING_SETTINGS", PROCTORING_SETTINGS)
################# MICROSITE ####################
MICROSITE_CONFIGURATION = ENV_TOKENS.get('MICROSITE_CONFIGURATION', {})
MICROSITE_ROOT_DIR = path(ENV_TOKENS.get('MICROSITE_ROOT_DIR', ''))

View File

@@ -1345,28 +1345,6 @@ courseware_js = [
'js/modules/tab.js',
]
proctoring_js = (
[
'proctoring/js/models/proctored_exam_allowance_model.js',
'proctoring/js/models/proctored_exam_attempt_model.js',
'proctoring/js/models/proctored_exam_model.js'
] +
[
'proctoring/js/collections/proctored_exam_allowance_collection.js',
'proctoring/js/collections/proctored_exam_attempt_collection.js',
'proctoring/js/collections/proctored_exam_collection.js'
] +
[
'proctoring/js/views/Backbone.ModalDialog.js',
'proctoring/js/views/proctored_exam_add_allowance_view.js',
'proctoring/js/views/proctored_exam_allowance_view.js',
'proctoring/js/views/proctored_exam_attempt_view.js',
'proctoring/js/views/proctored_exam_view.js'
] +
[
'proctoring/js/proctored_app.js'
]
)
# Before a student accesses courseware, we do not
# need many of the JS dependencies. This includes
@@ -1693,10 +1671,6 @@ PIPELINE_JS = {
),
'output_filename': 'js/lms-application.js',
},
'proctoring': {
'source_filenames': proctoring_js,
'output_filename': 'js/lms-proctoring.js',
},
'courseware': {
'source_filenames': courseware_js,
'output_filename': 'js/lms-courseware.js',
@@ -1841,6 +1815,10 @@ WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(STATIC_ROOT, 'webpack-stats.json')
},
'WORKERS': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(STATIC_ROOT, 'webpack-worker-stats.json')
}
}
WEBPACK_CONFIG_PATH = 'webpack.prod.config.js'
@@ -2881,9 +2859,6 @@ OPTIONAL_APPS = [
# edxval
('edxval', 'openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig'),
# edX Proctoring
('edx_proctoring', None),
# Organizations App (http://github.com/edx/edx-organizations)
('organizations', None),
@@ -3215,14 +3190,6 @@ MICROSITE_DATABASE_TEMPLATE_CACHE_TTL = 5 * 60
RSS_PROXY_CACHE_TIMEOUT = 3600 # The length of time we cache RSS retrieved from remote URLs in seconds
#### PROCTORING CONFIGURATION DEFAULTS
PROCTORING_BACKEND_PROVIDER = {
'class': 'edx_proctoring.backends.null.NullBackendProvider',
'options': {},
}
PROCTORING_SETTINGS = {}
#### Custom Courses for EDX (CCX) configuration
# This is an arbitrary hard limit.

View File

@@ -112,6 +112,7 @@ STATIC_ROOT_BASE = ENV_TOKENS.get('STATIC_ROOT_BASE', None)
if STATIC_ROOT_BASE:
STATIC_ROOT = path(STATIC_ROOT_BASE)
WEBPACK_LOADER['DEFAULT']['STATS_FILE'] = STATIC_ROOT / "webpack-stats.json"
WEBPACK_LOADER['WORKERS']['STATS_FILE'] = STATIC_ROOT / "webpack-worker-stats.json"
# STATIC_URL_BASE specifies the base url to use for static files
@@ -888,11 +889,6 @@ CREDIT_HELP_LINK_URL = ENV_TOKENS.get('CREDIT_HELP_LINK_URL', CREDIT_HELP_LINK_U
JWT_AUTH.update(ENV_TOKENS.get('JWT_AUTH', {}))
JWT_AUTH.update(AUTH_TOKENS.get('JWT_AUTH', {}))
################# PROCTORING CONFIGURATION ##################
PROCTORING_BACKEND_PROVIDER = AUTH_TOKENS.get("PROCTORING_BACKEND_PROVIDER", PROCTORING_BACKEND_PROVIDER)
PROCTORING_SETTINGS = ENV_TOKENS.get("PROCTORING_SETTINGS", PROCTORING_SETTINGS)
################# MICROSITE ####################
MICROSITE_CONFIGURATION = ENV_TOKENS.get('MICROSITE_CONFIGURATION', {})
MICROSITE_ROOT_DIR = path(ENV_TOKENS.get('MICROSITE_ROOT_DIR', ''))

View File

@@ -35,6 +35,11 @@ XQUEUE_INTERFACE = {
"basic_auth": ('anant', 'agarwal'),
}
PROCTORING_BACKENDS = {
'DEFAULT': 'mock',
'mock': {},
'mock_proctoring_without_rules': {},
}
######################### PIPELINE ####################################

View File

@@ -206,6 +206,9 @@ such that the value can be defined later than this assignment (file load order).
}, {
constructor: edx.instructor_dashboard.proctoring.ProctoredExamAttemptView,
$element: idashContent.find('.' + CSS_IDASH_SECTION + '#special_exams')
}, {
constructor: edx.instructor_dashboard.proctoring.ProctoredExamDashboardView,
$element: idashContent.find('.' + CSS_IDASH_SECTION + '#special_exams')
}
]);
}

View File

@@ -7,15 +7,9 @@ $(function() {
$proctoringAccordionPane.accordion(
{
heightStyle: 'content',
activate: function(event, ui) {
var active = $proctoringAccordionPane.accordion('option', 'active');
$.cookie('saved_index', null);
$.cookie('saved_index', active);
},
animate: 400,
header: '> .wrap > .hd',
icons: icons,
active: isNaN(parseInt($.cookie('saved_index'))) ? 0 : parseInt($.cookie('saved_index')),
collapsible: true
}
);

View File

@@ -14,5 +14,9 @@ import pytz
<h3 class="hd hd-3">${_('Student Special Exam Attempts')}</h3>
<div class="student-proctored-exam-container" data-course-id="${ section_data['course_id'] }"></div>
</div>
<div class="wrap">
<h3 class="hd hd-3">${_('Review Dashboard')}</h3>
<div class="student-review-dashboard-container" data-course-id="${ section_data['course_id'] }"></div>
</div>
</div>
</div>

View File

@@ -1012,11 +1012,6 @@ if 'debug_toolbar' in settings.INSTALLED_APPS:
url(r'^__debug__/', include(debug_toolbar.urls)),
]
# include into our URL patterns the HTTP REST API that comes with edx-proctoring.
urlpatterns += [
url(r'^api/', include('edx_proctoring.urls')),
]
if settings.FEATURES.get('ENABLE_FINANCIAL_ASSISTANCE_FORM'):
urlpatterns += [
url(