From 7f5465346ee75817023f225531b3b9ccb938d690 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Thu, 24 Jun 2021 12:59:49 -0400 Subject: [PATCH 01/22] Change put URL --- .../proctoring/js/models/proctored_exam_allowance_model.js | 2 +- .../js/views/proctored_exam_add_allowance_view.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/edx_proctoring/static/proctoring/js/models/proctored_exam_allowance_model.js b/edx_proctoring/static/proctoring/js/models/proctored_exam_allowance_model.js index d5459474755..0962b318576 100644 --- a/edx_proctoring/static/proctoring/js/models/proctored_exam_allowance_model.js +++ b/edx_proctoring/static/proctoring/js/models/proctored_exam_allowance_model.js @@ -7,7 +7,7 @@ edx = edx || {}; edx.instructor_dashboard.proctoring = edx.instructor_dashboard.proctoring || {}; edx.instructor_dashboard.proctoring.ProctoredExamAllowanceModel = Backbone.Model.extend({ - url: '/api/edx_proctoring/v1/proctored_exam/allowance' + url: '/api/edx_proctoring/v1/proctored_exam/bulk_allowance' }); this.edx.instructor_dashboard.proctoring.ProctoredExamAllowanceModel = diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js index 0ded3e0d6e7..716dec1fd66 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js @@ -140,9 +140,9 @@ edx = edx || {}; }, type: 'PUT', data: { - exam_id: values.proctored_exam, - user_info: values.user_info, - key: values.allowance_type, + exam_ids: values.proctored_exam, + user_ids: ["verified"], + allowance_type: "additional_time", value: values.allowance_value }, success: function() { From 41f589c430614381b767a066744a6a2f9aa1409b Mon Sep 17 00:00:00 2001 From: mohtamba Date: Thu, 1 Jul 2021 15:26:02 -0400 Subject: [PATCH 02/22] Working backend, Unfinished Front End --- edx_proctoring/api.py | 6 +- edx_proctoring/constants.py | 2 - .../proctored_exam_add_allowance_view.js | 13 +-- .../js/views/proctored_exam_allowance_view.js | 3 +- .../templates/add-new-allowance.underscore | 4 +- edx_proctoring/tests/test_api.py | 16 ++-- edx_proctoring/tests/test_views.py | 96 ++++++++++++------- edx_proctoring/views.py | 11 ++- setup.cfg | 2 +- 9 files changed, 93 insertions(+), 60 deletions(-) diff --git a/edx_proctoring/api.py b/edx_proctoring/api.py index 65067884603..d7a5e80b116 100644 --- a/edx_proctoring/api.py +++ b/edx_proctoring/api.py @@ -508,6 +508,8 @@ def add_bulk_allowances(exam_ids, user_ids, allowance_type, value): """ Adds (or updates) an allowance for multiple users and exams """ + + # Input pasrsing exam_ids = set(exam_ids) user_ids = set(user_ids) @@ -535,7 +537,7 @@ def add_bulk_allowances(exam_ids, user_ids, allowance_type, value): if multiplier < 0: raise AllowanceValueNotAllowedException(err_msg) - if allowance_type == constants.ADDITIONAL_TIME: + if allowance_type == ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED: err_msg = ( u'allowance_value "{value}" should be a non-negative integer value' ).format(value=value) @@ -597,7 +599,7 @@ def add_bulk_allowances(exam_ids, user_ids, allowance_type, value): for user_id in user_ids: try: add_allowance_for_user(exam_id, user_id, - ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, + allowance_type, value) successes += 1 data.append({ diff --git a/edx_proctoring/constants.py b/edx_proctoring/constants.py index 3396b2d9c8e..cec9c49d042 100644 --- a/edx_proctoring/constants.py +++ b/edx_proctoring/constants.py @@ -75,5 +75,3 @@ CONTENT_VIEWABLE_PAST_DUE_DATE = getattr(settings, 'PROCTORED_EXAM_VIEWABLE_PAST_DUE', False) TIME_MULTIPLIER = 'time_multiplier' - -ADDITIONAL_TIME = 'additional_time' diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js index 716dec1fd66..a045e3f2f6c 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js @@ -15,6 +15,7 @@ edx = edx || {}; this.proctored_exam_allowance_view = options.proctored_exam_allowance_view; this.course_id = options.course_id; this.allowance_types = options.allowance_types; + this.selectedExams = '' this.model = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceModel(); _.bindAll(this, 'render'); this.loadTemplateData(); @@ -33,7 +34,6 @@ edx = edx || {}; self.render(); self.showModal(); self.updateCss(); - self.selectExamAtIndex(0); }); }, updateCss: function() { @@ -89,7 +89,7 @@ edx = edx || {}; }, getCurrentFormValues: function() { return { - proctored_exam: $('select#proctored_exam').val(), + proctored_exam: this.selectedExams, allowance_type: $('select#allowance_type').val(), allowance_value: $('#allowance_value').val(), user_info: $('#user_info').val() @@ -141,8 +141,8 @@ edx = edx || {}; type: 'PUT', data: { exam_ids: values.proctored_exam, - user_ids: ["verified"], - allowance_type: "additional_time", + user_ids: values.user_info, + allowance_type: values.allowance_type, value: values.allowance_value }, success: function() { @@ -162,7 +162,8 @@ edx = edx || {}; }, selectExamAtIndex: function(index) { var selectedExam = this.proctored_exams[index]; - + console.log("in selected function") + this.selectedExams += String(selectedExam.id) + "," if (selectedExam.is_proctored) { // Selected Exam is a Proctored or Practice-Proctored exam. if (selectedExam.is_practice_exam) { @@ -217,4 +218,4 @@ edx = edx || {}; return this; } }); -}).call(this, Backbone, $, _, gettext); +}).call(this, Backbone, $, _, gettext); \ No newline at end of file diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js index a05510f2b37..445e172cc89 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js @@ -10,7 +10,8 @@ edx = edx || {}; initialize: function() { this.allowance_types = [ ['additional_time_granted', gettext('Additional Time (minutes)')], - ['review_policy_exception', gettext('Review Policy Exception')] + ['review_policy_exception', gettext('Review Policy Exception')], + ['time_multiplier', gettext('Time Multiplier')] ]; this.collection = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceCollection(); diff --git a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore index 58c83340ee3..424a58ea9d8 100644 --- a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore +++ b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore @@ -14,7 +14,7 @@ diff --git a/edx_proctoring/tests/test_api.py b/edx_proctoring/tests/test_api.py index dc42e3363e3..5d9d611ed47 100644 --- a/edx_proctoring/tests/test_api.py +++ b/edx_proctoring/tests/test_api.py @@ -65,7 +65,7 @@ update_review_policy ) from edx_proctoring.backends.tests.test_backend import TestBackendProvider -from edx_proctoring.constants import ADDITIONAL_TIME, DEFAULT_CONTACT_EMAIL, TIME_MULTIPLIER +from edx_proctoring.constants import DEFAULT_CONTACT_EMAIL, TIME_MULTIPLIER from edx_proctoring.exceptions import ( AllowanceValueNotAllowedException, BackendProviderSentNoAttemptID, @@ -502,7 +502,7 @@ def test_remove_allowance_for_user(self): @ddt.data( ( - ADDITIONAL_TIME, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, '30', '30', '30' @@ -629,7 +629,7 @@ def test_add_same_exam_bulk_allowance(self): @ddt.data( ( - ADDITIONAL_TIME, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, '30', '30', '30' @@ -684,7 +684,7 @@ def test_add_bulk_allowance_invalid_user(self, allowance_type, value, exam1_allo @ddt.data( ( - ADDITIONAL_TIME, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, '30', '30', '30' @@ -739,19 +739,19 @@ def test_add_bulk_allowance_invalid_exam(self, allowance_type, value, exam1_allo @ddt.data( ( - ADDITIONAL_TIME, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, '3.0' ), ( - ADDITIONAL_TIME, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, 'invalid' ), ( - ADDITIONAL_TIME, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, '-30' ), ( - ADDITIONAL_TIME, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, 'd30' ), ( diff --git a/edx_proctoring/tests/test_views.py b/edx_proctoring/tests/test_views.py index cfde79bea60..852089c658c 100644 --- a/edx_proctoring/tests/test_views.py +++ b/edx_proctoring/tests/test_views.py @@ -32,7 +32,7 @@ from edx_proctoring.backends.tests.test_backend import TestBackendProvider from edx_proctoring.backends.tests.test_review_payload import create_test_review_payload from edx_proctoring.backends.tests.test_software_secure import mock_response_content -from edx_proctoring.constants import ADDITIONAL_TIME, TIME_MULTIPLIER +from edx_proctoring.constants import TIME_MULTIPLIER from edx_proctoring.exceptions import ( BackendProviderOnboardingProfilesException, ProctoredExamIllegalStatusTransition, @@ -4894,12 +4894,20 @@ def setUp(self): @ddt.data( ( - ADDITIONAL_TIME, + 'additional_time_granted', '30' ), ( TIME_MULTIPLIER, '1.5' + ), + ( + 'review_policy_exception', + 'notes' + ), + ( + 'review_policy_exception', + 25 ) ) @ddt.unpack @@ -4927,8 +4935,8 @@ def test_add_bulk_time_allowances(self, allowance_type, value): exam_list = [exam1.id, exam2.id] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, + 'exam_ids': ','.join(str(exam) for exam in exam_list), + 'user_ids': ','.join(str(user) for user in user_id_list), 'allowance_type': allowance_type, 'value': value } @@ -4967,9 +4975,9 @@ def test_add_bulk_allowance_non_staff_user(self): # pylint: disable=invalid-nam exam_list = [exam1.id, exam2.id] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, - 'allowance_type': ADDITIONAL_TIME, + 'exam_ids': ','.join(str(exam) for exam in exam_list), + 'user_ids': ','.join(str(user) for user in user_id_list), + 'allowance_type': 'additional_time_granted', 'value': '30' } response = self.client.put( @@ -4983,12 +4991,20 @@ def test_add_bulk_allowance_non_staff_user(self): # pylint: disable=invalid-nam @ddt.data( ( - ADDITIONAL_TIME, + 'additional_time_granted', '30' ), ( TIME_MULTIPLIER, '1.5' + ), + ( + 'review_policy_exception', + 'notes' + ), + ( + 'review_policy_exception', + 25 ) ) @ddt.unpack @@ -5017,8 +5033,9 @@ def test_add_bulk_allowance_invalid_user(self, allowance_type, value): # pylint exam_list = [exam1.id, exam2.id] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, + 'exam_ids': ','.join(str(exam) for exam in exam_list), + # Add additonal whitesapce for invalid users + 'user_ids': ','.join(str(user) for user in user_id_list) + ',, , ,w', 'allowance_type': allowance_type, 'value': value } @@ -5031,12 +5048,20 @@ def test_add_bulk_allowance_invalid_user(self, allowance_type, value): # pylint @ddt.data( ( - ADDITIONAL_TIME, + 'additional_time_granted', '30' ), ( TIME_MULTIPLIER, '1.5' + ), + ( + 'review_policy_exception', + 'notes' + ), + ( + 'review_policy_exception', + 25 ) ) @ddt.unpack @@ -5064,8 +5089,9 @@ def test_add_bulk_allowance_invalid_exam(self, allowance_type, value): # pylint exam_list = [exam1.id, exam2.id, -99] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, + # Test added whitesapce in the exam id input + 'exam_ids': ','.join(str(exam) for exam in exam_list) + ',2 3, 22,', + 'user_ids': ','.join(str(user) for user in user_id_list), 'allowance_type': allowance_type, 'value': value } @@ -5078,7 +5104,7 @@ def test_add_bulk_allowance_invalid_exam(self, allowance_type, value): # pylint @ddt.data( ( - ADDITIONAL_TIME, + 'additional_time_granted', '-30' ), ( @@ -5115,8 +5141,8 @@ def test_add_bulk_allowance_invalid_allowance_value(self, allowance_type, value) exam_list = [exam1.id, exam2.id] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, + 'exam_ids': ','.join(str(exam) for exam in exam_list), + 'user_ids': ','.join(str(user) for user in user_id_list), 'allowance_type': allowance_type, 'value': value } @@ -5136,9 +5162,9 @@ def test_add_bulk_allowance_all_invalid_data(self): # pylint: disable=invalid-n exam_list = [-99, -98] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, - 'allowance_type': ADDITIONAL_TIME, + 'exam_ids': ','.join(str(exam) for exam in exam_list), + 'user_ids': ','.join(str(user) for user in user_id_list), + 'allowance_type': 'additional_time_granted', 'value': '30' } response = self.client.put( @@ -5153,7 +5179,6 @@ def test_add_bulk_allowance_no_users(self): # pylint: disable=invalid-name Test to add bulk allowance with no users """ # Create exams. - user_id_list = [] exam1 = ProctoredExam.objects.create( course_id='a/b/c', content_id='test_content', @@ -5171,9 +5196,9 @@ def test_add_bulk_allowance_no_users(self): # pylint: disable=invalid-name exam_list = [exam1.id, exam2.id] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, - 'allowance_type': ADDITIONAL_TIME, + 'exam_ids': ','.join(str(exam) for exam in exam_list), + 'user_ids': ' ', + 'allowance_type': 'additional_time_granted', 'value': '30' } response = self.client.put( @@ -5190,12 +5215,11 @@ def test_add_bulk_allowance_no_exams(self): # pylint: disable=invalid-name # Create exams. user_list = self.create_batch_users(3) user_id_list = [user.email for user in user_list] - exam_list = [] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, - 'allowance_type': ADDITIONAL_TIME, + 'exam_ids': ' ', + 'user_ids': ','.join(str(user) for user in user_id_list), + 'allowance_type': 'additional_time_granted', 'value': '30' } response = self.client.put( @@ -5237,9 +5261,9 @@ def test_get_grouped_allowances(self): exam_list = [exam1.id] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, - 'allowance_type': ADDITIONAL_TIME, + 'exam_ids': ','.join(str(exam) for exam in exam_list), + 'user_ids': ','.join(str(user) for user in user_id_list), + 'allowance_type': 'additional_time_granted', 'value': '30' } self.client.put( @@ -5299,9 +5323,9 @@ def test_get_grouped_allowances_non_staff(self): exam_list = [exam1.id, exam2.id] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, - 'allowance_type': ADDITIONAL_TIME, + 'exam_ids': ','.join(str(exam) for exam in exam_list), + 'user_ids': ','.join(str(user) for user in user_id_list), + 'allowance_type': 'additional_time_granted', 'value': '30' } self.client.put( @@ -5361,9 +5385,9 @@ def test_get_grouped_allowances_non_global_staff(self): exam_list = [exam1.id, exam2.id] allowance_data = { - 'exam_ids': exam_list, - 'user_ids': user_id_list, - 'allowance_type': ADDITIONAL_TIME, + 'exam_ids': ','.join(str(exam) for exam in exam_list), + 'user_ids': ','.join(str(user) for user in user_id_list), + 'allowance_type': 'additional_time_granted', 'value': '30' } self.client.put( diff --git a/edx_proctoring/views.py b/edx_proctoring/views.py index c279bfb5093..63990bc1ef6 100644 --- a/edx_proctoring/views.py +++ b/edx_proctoring/views.py @@ -1593,9 +1593,16 @@ def put(self, request): HTTP PUT handler. Adds or updates Allowances for many exams and students """ try: + exams = request.data.get('exam_ids', '') + users = request.data.get('user_ids', '') + + # We need to remove whitespace from the exam ids as they are ints + filtered_ids = ''.join(exams.split()) + filtered_users = ''.join(users.split()) data, successes, failures = add_bulk_allowances( - exam_ids=request.data.get('exam_ids', None), - user_ids=request.data.get('user_ids', None), + # We only want to pass ints that are not empty + exam_ids=[each_exam for each_exam in filtered_ids.split(',') if each_exam], + user_ids=[each_user.strip() for each_user in filtered_users.split(',') if each_user], allowance_type=request.data.get('allowance_type', None), value=request.data.get('value', None) ) diff --git a/setup.cfg b/setup.cfg index 39e11344e5c..723d37204df 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,4 +33,4 @@ match-dir = (?!migrations) [tool:pytest] DJANGO_SETTINGS_MODULE = test_settings -addopts = -rfe --cov=edx_proctoring --cov-report=html -n 3 \ No newline at end of file +#addopts = -rfe --cov=edx_proctoring --cov-report=html -n 3 \ No newline at end of file From 53b52e9487e2d410b7cb02a8126d9fc492199e04 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Tue, 6 Jul 2021 09:38:20 -0400 Subject: [PATCH 03/22] Create taga --- .../proctored_exam_add_allowance_view.js | 37 ++++++++++++--- .../templates/add-new-allowance.underscore | 45 ++++++++++++++++++- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js index a045e3f2f6c..c058e9866ec 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js @@ -15,7 +15,7 @@ edx = edx || {}; this.proctored_exam_allowance_view = options.proctored_exam_allowance_view; this.course_id = options.course_id; this.allowance_types = options.allowance_types; - this.selectedExams = '' + this.selectedExams = new Set() this.model = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceModel(); _.bindAll(this, 'render'); this.loadTemplateData(); @@ -116,13 +116,14 @@ edx = edx || {}; this.updateCss(); }, addAllowance: function(event) { - var $errorResponse, values, formHasErrors; + var $errorResponse, values, formHasErrors, exams; var self = this; event.preventDefault(); $errorResponse = $('.error-response'); $errorResponse.html(); values = this.getCurrentFormValues(); formHasErrors = false; + exams = this.setToString(values.proctored_exam, ',') $.each(values, function(key, value) { if (value === '') { @@ -140,7 +141,7 @@ edx = edx || {}; }, type: 'PUT', data: { - exam_ids: values.proctored_exam, + exam_ids: exams, user_ids: values.user_info, allowance_type: values.allowance_type, value: values.allowance_value @@ -161,9 +162,13 @@ edx = edx || {}; } }, selectExamAtIndex: function(index) { - var selectedExam = this.proctored_exams[index]; - console.log("in selected function") - this.selectedExams += String(selectedExam.id) + "," + var selectedExam = this.proctored_exams[index - 1]; + console.log("added exam", selectedExam); + this.selectedExams.add(selectedExam.id); + var createdTag = this.createTag(selectedExam.exam_name) + console.log(createdTag) + $('#selected_exams').append(createdTag); + console.log($('#selected_exam')); if (selectedExam.is_proctored) { // Selected Exam is a Proctored or Practice-Proctored exam. if (selectedExam.is_practice_exam) { @@ -202,6 +207,26 @@ edx = edx || {}; $('#allowance_value_label').text(gettext('Value')); } }, + setToString(set, delim){ + let str = ''; + set.forEach(function(elem){ + str += elem + delim + }); + return str.slice(0, -1) + }, + createTag(examName) { + const div = document.createElement('div'); + div.setAttribute('class', 'tag'); + const span = document.createElement('span'); + span.innerHTML = examName; + const closeIcon = document.createElement('i'); + closeIcon.innerHTML = 'close'; + closeIcon.setAttribute('class', 'material-icons'); + closeIcon.setAttribute('data-item', examName); + div.appendChild(span); + div.appendChild(closeIcon); + return div; + }, render: function() { $(this.el).html(this.template({ diff --git a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore index 424a58ea9d8..3e23f918b0f 100644 --- a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore +++ b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore @@ -2,6 +2,43 @@ select#proctored_exam { width: 100%; } + .tag-container { + border: 2px solid #ccc; + border-radius: 3px; + background: #fff; + display: flex; + flex-wrap: wrap; + align-content: flex-start; + padding: 6px; + overflow-x: scroll; + } + .tag-container .tag { + height: 30px; + margin: 5px; + padding: 5px 6px; + border: 1px solid #ccc; + border-radius: 3px; + background: #eee; + display: flex; + align-items: center; + color: #333; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.2), inset 0 1px 1px #fff; + cursor: default; + } + .tag i { + font-size: 16px; + color: #666; + margin-left: 5px; + } + .tag-container input { + padding: 5px; + font-size: 16px; + border: 0; + outline: none; + font-family: 'Rubik'; + color: #333; + flex: 1; + }
@@ -9,10 +46,11 @@ + + +
- +
+
+
From 60456746e5539363d9a2ee30c3ba9a8572ed8cae Mon Sep 17 00:00:00 2001 From: mohtamba Date: Wed, 7 Jul 2021 12:09:21 -0400 Subject: [PATCH 04/22] Dropdown Not Showing Up --- .../proctored_exam_add_allowance_view.js | 98 +++++++++++-------- .../templates/add-new-allowance.underscore | 41 +------- 2 files changed, 60 insertions(+), 79 deletions(-) diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js index c058e9866ec..98e445db21c 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js @@ -11,11 +11,12 @@ edx = edx || {}; template: null, template_url: '/static/proctoring/templates/add-new-allowance.underscore', initialize: function(options) { - this.proctored_exams = options.proctored_exams; + this.all_exams = options.proctored_exams; + this.proctored_exams = []; + this.timed_exams = []; this.proctored_exam_allowance_view = options.proctored_exam_allowance_view; this.course_id = options.course_id; this.allowance_types = options.allowance_types; - this.selectedExams = new Set() this.model = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceModel(); _.bindAll(this, 'render'); this.loadTemplateData(); @@ -24,7 +25,8 @@ edx = edx || {}; events: { 'submit form': 'addAllowance', 'change #proctored_exam': 'selectExam', - 'change #allowance_type': 'selectAllowance' + 'change #allowance_type': 'selectAllowance', + 'change #exam_type': 'selectExamType' }, loadTemplateData: function() { var self = this; @@ -32,6 +34,7 @@ edx = edx || {}; .done(function(templateData) { self.template = _.template(templateData); self.render(); + console.log(this.all_exams); self.showModal(); self.updateCss(); }); @@ -123,7 +126,7 @@ edx = edx || {}; $errorResponse.html(); values = this.getCurrentFormValues(); formHasErrors = false; - exams = this.setToString(values.proctored_exam, ',') + exams = '' $.each(values, function(key, value) { if (value === '') { @@ -134,6 +137,10 @@ edx = edx || {}; } }); + $('.close').each(function() { + exams += $(this).attr('data-item') + ',' + }) + if (!formHasErrors) { self.model.fetch({ headers: { @@ -162,35 +169,14 @@ edx = edx || {}; } }, selectExamAtIndex: function(index) { - var selectedExam = this.proctored_exams[index - 1]; + var selectedExam = this.all_exams[index - 1]; console.log("added exam", selectedExam); - this.selectedExams.add(selectedExam.id); - var createdTag = this.createTag(selectedExam.exam_name) + document.getElementById('proctored_exam').value = 'default' + var createdTag = this.createTag(selectedExam.exam_name, selectedExam.id, this.selectedExams) console.log(createdTag) $('#selected_exams').append(createdTag); console.log($('#selected_exam')); - if (selectedExam.is_proctored) { - // Selected Exam is a Proctored or Practice-Proctored exam. - if (selectedExam.is_practice_exam) { - $('#exam_type_label').text(gettext('Practice Exam')); - } else { - $('#exam_type_label').text(gettext('Proctored Exam')); - } - - // In case of Proctored Exams, we hide the Additional Time label and show the Allowance Types Select - $('#additional_time_label').hide(); - $('select#allowance_type').val('additional_time_granted').show(); - } else { - // Selected Exam is a Timed Exam. - $('#exam_type_label').text(gettext('Timed Exam')); - - // In case of Timed Exams, we show the "Additional Time" label and hide the Allowance Types Select - $('#additional_time_label').show(); - // Even though we have the Select element hidden, the backend will still be using - // the Select's value for the allowance type (key). - $('select#allowance_type').val('additional_time_granted').hide(); - } - this.updateAllowanceLabels('additional_time_granted'); + document.getElementById('proctored_exam').value = 'default' }, selectExam: function() { this.selectExamAtIndex($('#proctored_exam')[0].selectedIndex); @@ -207,30 +193,62 @@ edx = edx || {}; $('#allowance_value_label').text(gettext('Value')); } }, - setToString(set, delim){ - let str = ''; - set.forEach(function(elem){ - str += elem + delim + sortExams: function() { + this.all_exams.forEach(exam => { + if (exam.is_proctored) { + this.proctored_exams.push(exam) + } else { + this.timed_exams.push(exam) + } + // if (selectedExam.is_proctored) { + // // Selected Exam is a Proctored or Practice-Proctored exam. + // if (selectedExam.is_practice_exam) { + // $('#exam_type_label').text(gettext('Practice Exam')); + // } else { + // $('#exam_type_label').text(gettext('Proctored Exam')); + // } + + // // In case of Proctored Exams, we hide the Additional Time label and show the Allowance Types Select + // $('#additional_time_label').hide(); + // $('select#allowance_type').val('additional_time_granted').show(); + // } else { + // // Selected Exam is a Timed Exam. + // $('#exam_type_label').text(gettext('Timed Exam')); + + // // In case of Timed Exams, we show the "Additional Time" label and hide the Allowance Types Select + // $('#additional_time_label').show(); + // // Even though we have the Select element hidden, the backend will still be using + // // the Select's value for the allowance type (key). + // $('select#allowance_type').val('additional_time_granted').hide(); + // } }); - return str.slice(0, -1) + console.log(this.timed_exams); + console.log(this.proctored_exams); }, - createTag(examName) { + createTag(examName, examID) { const div = document.createElement('div'); div.setAttribute('class', 'tag'); const span = document.createElement('span'); span.innerHTML = examName; - const closeIcon = document.createElement('i'); - closeIcon.innerHTML = 'close'; - closeIcon.setAttribute('class', 'material-icons'); - closeIcon.setAttribute('data-item', examName); + const closeIcon = document.createElement('button'); + closeIcon.innerHTML = 'x'; + closeIcon.setAttribute('class', 'close'); + closeIcon.setAttribute('data-item', examID); + closeIcon.onclick = this.deleteTag; div.appendChild(span); div.appendChild(closeIcon); return div; }, + deleteTag() { + console.log($(this)); + var examID = $(this).data('item'); + $(this).closest("div").remove(); + + }, render: function() { $(this.el).html(this.template({ - proctored_exams: this.proctored_exams, + proctored_exams: this.all_exams, allowance_types: this.allowance_types })); diff --git a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore index 3e23f918b0f..308b2c2252b 100644 --- a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore +++ b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore @@ -2,43 +2,6 @@ select#proctored_exam { width: 100%; } - .tag-container { - border: 2px solid #ccc; - border-radius: 3px; - background: #fff; - display: flex; - flex-wrap: wrap; - align-content: flex-start; - padding: 6px; - overflow-x: scroll; - } - .tag-container .tag { - height: 30px; - margin: 5px; - padding: 5px 6px; - border: 1px solid #ccc; - border-radius: 3px; - background: #eee; - display: flex; - align-items: center; - color: #333; - box-shadow: 0 0 4px rgba(0, 0, 0, 0.2), inset 0 1px 1px #fff; - cursor: default; - } - .tag i { - font-size: 16px; - color: #666; - margin-left: 5px; - } - .tag-container input { - padding: 5px; - font-size: 16px; - border: 0; - outline: none; - font-family: 'Rubik'; - color: #333; - flex: 1; - } @@ -50,8 +13,8 @@ + + + + - diff --git a/edx_proctoring/views.py b/edx_proctoring/views.py index 190370e08f7..9026746f6f5 100644 --- a/edx_proctoring/views.py +++ b/edx_proctoring/views.py @@ -1620,7 +1620,7 @@ def put(self, request): if successes == 0: return Response( status=status.HTTP_400_BAD_REQUEST, - data=data + data={"detail": _("Enter a valid username or email")} ) if failures > 0: return Response( @@ -1633,7 +1633,7 @@ def put(self, request): except AllowanceValueNotAllowedException: return Response( status=status.HTTP_400_BAD_REQUEST, - data={"detail": _("Must be a Staff User to Perform this request.")} + data={"detail": _("Enter a valid value number")} ) From 3b9785d6f77266f1595c905a4bf28ea75a58b329 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Fri, 9 Jul 2021 11:56:38 -0400 Subject: [PATCH 06/22] Update setup.cfg --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 723d37204df..39e11344e5c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,4 +33,4 @@ match-dir = (?!migrations) [tool:pytest] DJANGO_SETTINGS_MODULE = test_settings -#addopts = -rfe --cov=edx_proctoring --cov-report=html -n 3 \ No newline at end of file +addopts = -rfe --cov=edx_proctoring --cov-report=html -n 3 \ No newline at end of file From 55097cce3356386005dcf3a710e3da981b83ccbe Mon Sep 17 00:00:00 2001 From: mohtamba Date: Fri, 9 Jul 2021 12:08:38 -0400 Subject: [PATCH 07/22] Update test_api.py --- edx_proctoring/tests/test_api.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/edx_proctoring/tests/test_api.py b/edx_proctoring/tests/test_api.py index 5d9d611ed47..f4604f05c3e 100644 --- a/edx_proctoring/tests/test_api.py +++ b/edx_proctoring/tests/test_api.py @@ -629,7 +629,7 @@ def test_add_same_exam_bulk_allowance(self): @ddt.data( ( - ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED[0], '30', '30', '30' @@ -684,7 +684,7 @@ def test_add_bulk_allowance_invalid_user(self, allowance_type, value, exam1_allo @ddt.data( ( - ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED[0], '30', '30', '30' @@ -739,19 +739,19 @@ def test_add_bulk_allowance_invalid_exam(self, allowance_type, value, exam1_allo @ddt.data( ( - ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED[0], '3.0' ), ( - ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED[0], 'invalid' ), ( - ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED[0], '-30' ), ( - ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED, + ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED[0], 'd30' ), ( From a8c04d3e9c37a3111e04192852b5eff3844ad37b Mon Sep 17 00:00:00 2001 From: mohtamba Date: Mon, 12 Jul 2021 12:17:16 -0400 Subject: [PATCH 08/22] Fixed labels and full functionality applied --- edx_proctoring/api.py | 2 +- .../proctored_exam_add_allowance_view.js | 71 +++++++++-------- .../templates/add-new-allowance.underscore | 53 ++++++------- npm-shrinkwrap.json | 76 ++++++++++++++++++- package.json | 1 - 5 files changed, 134 insertions(+), 69 deletions(-) diff --git a/edx_proctoring/api.py b/edx_proctoring/api.py index 1e0d733fd90..5366e7f1936 100644 --- a/edx_proctoring/api.py +++ b/edx_proctoring/api.py @@ -537,7 +537,7 @@ def add_bulk_allowances(exam_ids, user_ids, allowance_type, value): if multiplier < 0: raise AllowanceValueNotAllowedException(err_msg) - if allowance_type == ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED[0]: + if allowance_type in ProctoredExamStudentAllowance.ADDITIONAL_TIME_GRANTED: err_msg = ( u'allowance_value "{value}" should be a non-negative integer value' ).format(value=value) diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js index 0b2f4b6ddba..4659c52a752 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js @@ -33,7 +33,7 @@ edx = edx || {}; var self = this; $.ajax({url: self.template_url, dataType: 'html'}) .done(function(templateData) { - self.sortExams(); + self.sortExamsByExamType(); self.template = _.template(templateData); self.render(); self.showModal(); @@ -69,7 +69,8 @@ edx = edx || {}; $el.find('form input[type="text"]').css({ height: '26px', padding: '1px 8px 2px', - 'font-size': '14px' + 'font-size': '14px', + width: '100%' }); $el.find('form input[type="submit"]').css({ 'margin-top': '10px', @@ -88,11 +89,12 @@ edx = edx || {}; }); $el.find('form select').css({ padding: '2px 0px 2px 2px', - 'font-size': '16px' + 'font-size': '16px', + width: '100%' }); $el.find('#selected_exams').css({ 'border-radius': '3px', - 'background': '#fff', + background: '#fff', display: 'flex', 'flex-wrap': 'wrap', 'align-content': 'flex-start', @@ -102,22 +104,24 @@ edx = edx || {}; $el.find('.tag').css({ 'font-size': '14px', height: '15px', - 'margin': '5px', + margin: '5px', padding: '5px 6px', - 'border': '1px solid #ccc', + border: '1px solid #ccc', 'border-radius': '3px', - 'background': '#eee', + background: '#eee', display: 'flex', 'align-items': 'center', color: '#333', 'box-shadow': '0 0 4px rgba(0, 0, 0, 0.2), inset 0 1px 1px #fff', - 'cursor': 'default' + cursor: 'default' }); $el.find('.close').css({ 'font-size': '16px', - 'margin': '5px' + margin: '5px' + }); + $el.find('.exam_dropdown').css({ + height: '60px' }); - }, getCurrentFormValues: function() { return { @@ -164,7 +168,6 @@ edx = edx || {}; $.each(values, function(key, value) { if (value === '') { formHasErrors = true; - console.log(key); self.showError(self, key, gettext('Required field')); } else { self.hideError(self, key); @@ -206,12 +209,9 @@ edx = edx || {}; } }, selectExamAtIndex: function(examID, examName) { - console.log(examID); - console.log(examName); - $('.exam_dropdown:visible').val("default"); - $('.exam_dropdown:visible option[value=' + examID + ']').remove(); var createdTag = this.createTag(examName, examID); - console.log(createdTag); + $('.exam_dropdown:visible').val('default'); + $('.exam_dropdown:visible option[value=' + examID + ']').remove(); $('#selected_exams').append(createdTag); this.updateCss(); }, @@ -221,45 +221,45 @@ edx = edx || {}; selectAllowance: function() { this.updateAllowanceLabels($('#allowance_type').val()); }, - selectExamType: function () { + selectExamType: function() { $('.close').each(function() { $(this).trigger('click'); }); - if($('#proctored_exam').is(":visible")){ + if ($('#proctored_exam').is(':visible')) { $('#proctored_exam').hide(); $('#timed_exam').show(); $('#allowance_type option[value="review_policy_exception"]').remove(); } else { $('#proctored_exam').show(); $('#timed_exam').hide(); - $('#allowance_type').append(new Option(gettext('Review Policy Exception'), 'review_policy_exception')); + $('#allowance_type').append(new Option(gettext('Review Policy Exception'), 'review_policy_exception')); } - }, updateAllowanceLabels: function(selectedAllowanceType) { if (selectedAllowanceType === 'additional_time_granted') { - $('#minutes_label').show(); - $('#allowance_value_label').text(gettext('Additional Time')); + $('#allowance_value_label').text(gettext('Input Additional Minutes as a Number')); + } else if (selectedAllowanceType === 'time_multiplier') { + $('#allowance_value_label').text(gettext('Input Multiplier as a Number')); } else { - $('#minutes_label').hide(); - $('#allowance_value_label').text(gettext('Value')); + $('#allowance_value_label').text(gettext('Add Policy Exception')); } }, - sortExams: function() { - this.all_exams.forEach(exam => { + sortExamsByExamType: function() { + var self = this; + self.all_exams.forEach(function(exam) { if (exam.is_proctored) { - this.proctored_exams.push(exam); + self.proctored_exams.push(exam); } else { - this.timed_exams.push(exam); + self.timed_exams.push(exam); } }); }, - createTag(examName, examID) { - const div = document.createElement('div'); + createTag: function(examName, examID) { + var div = document.createElement('div'); + var span = document.createElement('span'); + var closeIcon = document.createElement('span'); div.setAttribute('class', 'tag'); - const span = document.createElement('span'); span.innerHTML = examName; - const closeIcon = document.createElement('span'); closeIcon.innerHTML = 'x'; closeIcon.setAttribute('class', 'close'); closeIcon.setAttribute('data-item', examID); @@ -269,11 +269,10 @@ edx = edx || {}; div.appendChild(closeIcon); return div; }, - deleteTag() { - console.log($(this)); + deleteTag: function() { var examID = $(this).data('item'); var examName = $(this).data('name'); - $(this).closest("div").remove(); + $(this).closest('div').remove(); $('.exam_dropdown:visible').append(new Option(examName, examID)); }, @@ -294,4 +293,4 @@ edx = edx || {}; return this; } }); -}).call(this, Backbone, $, _, gettext); \ No newline at end of file +}).call(this, Backbone, $, _, gettext); diff --git a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore index fbf2fba04f7..a0d04b35093 100644 --- a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore +++ b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore @@ -5,6 +5,9 @@ select#timed_exam { width: 100%; } + table, td { + width: 100%; + } @@ -12,8 +15,20 @@
+ + + + + +
- - <% _.each(all_exams, function(proctored_exam){ %> + <% _.each(proctored_exams, function(proctored_exam){ %> <% }); %> +
-
+
+
+ + + + + + + + + + - - - - -
- + +
+ +
+
- -
- +
- - - +
- - - -
- - - - +
- - - +
- +
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index bff737cb4d5..e8d1b56a9c7 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "@edx/edx-proctoring", - "version": "3.9.1", + "version": "3.17.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -880,6 +880,12 @@ "osenv": "0.0.3" }, "dependencies": { + "graceful-fs": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", + "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", + "dev": true + }, "osenv": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.0.3.tgz", @@ -1053,6 +1059,15 @@ } } }, + "graceful-fs": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", + "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", + "dev": true, + "requires": { + "natives": "^1.1.3" + } + }, "handlebars": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-2.0.0.tgz", @@ -1232,6 +1247,14 @@ "deep-extend": "~0.2.5", "graceful-fs": "~2.0.0", "intersect": "~0.0.3" + }, + "dependencies": { + "graceful-fs": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", + "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", + "dev": true + } } }, "bower-logger": { @@ -1256,6 +1279,12 @@ "rimraf": "~2.2.0" }, "dependencies": { + "graceful-fs": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", + "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", + "dev": true + }, "lru-cache": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.3.1.tgz", @@ -1768,6 +1797,15 @@ "xdg-basedir": "^1.0.0" }, "dependencies": { + "graceful-fs": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", + "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", + "dev": true, + "requires": { + "natives": "^1.1.3" + } + }, "object-assign": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", @@ -1976,6 +2014,15 @@ "touch": "0.0.2" }, "dependencies": { + "graceful-fs": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", + "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", + "dev": true, + "requires": { + "natives": "^1.1.3" + } + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -4474,6 +4521,12 @@ "minimatch": "~0.2.11" } }, + "graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", + "dev": true + }, "inherits": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", @@ -4656,6 +4709,12 @@ } } }, + "graceful-fs": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", + "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", + "dev": true + }, "gulp-util": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-1.2.0.tgz", @@ -7174,6 +7233,12 @@ "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", "dev": true }, + "natives": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", + "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", + "dev": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -10165,6 +10230,15 @@ "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", "dev": true }, + "graceful-fs": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", + "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", + "dev": true, + "requires": { + "natives": "^1.1.3" + } + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", diff --git a/package.json b/package.json index 83408eb4410..4e1e1dfd7c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,5 @@ { "name": "@edx/edx-proctoring", - "//": "Be sure to update the version number in edx_proctoring/__init__.py", "//": "Note that the version format is slightly different than that of the Python version when using prereleases.", "version": "3.17.2", "main": "edx_proctoring/static/index.js", From 232cd9335914027203c08889415a1b0abf6dc841 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Mon, 12 Jul 2021 12:17:28 -0400 Subject: [PATCH 09/22] Update proctored_exam_add_allowance_view.js --- .../proctoring/js/views/proctored_exam_add_allowance_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js index 4659c52a752..b5c3bc470e0 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js @@ -74,7 +74,7 @@ edx = edx || {}; }); $el.find('form input[type="submit"]').css({ 'margin-top': '10px', - padding: '2px 32px' + float: 'right' }); $el.find('.error-message').css({ color: '#ff0000', From bd505fad5d2a0c429d9f0814653ff09ab7b0d8fd Mon Sep 17 00:00:00 2001 From: mohtamba Date: Mon, 12 Jul 2021 14:33:30 -0400 Subject: [PATCH 10/22] Update test data --- .../spec/proctored_exam_add_allowance_spec.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js index 52b3bfaab54..36fe895c23f 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js @@ -79,7 +79,8 @@ describe('ProctoredExamAddAllowanceView', function() { var allowanceTypes = [ ['additional_time_granted', gettext('Additional Time (minutes)')], - ['review_policy_exception', gettext('Review Policy Exception')] + ['review_policy_exception', gettext('Review Policy Exception')], + ['time_multiplier', gettext('Time Multiplier')] ]; beforeEach(function() { @@ -87,7 +88,7 @@ describe('ProctoredExamAddAllowanceView', function() { // from http://www.howtocreate.co.uk/tutorials/jsexamples/syntax/prepareInline.html // eslint-disable-next-line max-len - html = '
<%- gettext("Add a New Allowance") %>
\n\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n \n \n
\n \n \n \n
\n \n \n \n\n \n
\n \n \n \n \n
\n \n \n \n
\n \n
\n\n'; + html = '
<%- gettext(\"Add a New Allowance\") %><\/div>\n
\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n
\n \n <\/td>\n <\/tr>\n
\n
\n
\n
\n \n
\n
<\/div>\n <\/td>\n <\/tr>\n
\n
\n
\n
\n \n <\/td>\n <\/tr>\n
\n \n <\/td>\n <\/tr>\n <\/table>\n<\/form>\n'; allowancesHtml = '' + '<%- gettext("Allowances") %>' + @@ -189,10 +190,7 @@ describe('ProctoredExamAddAllowanceView', function() { expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Midterm Exam'); expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Final Exam'); expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Test Exam'); - expect(addAllowanceView.$el.find('#exam_type_label')).toExist(); $('#proctored_exam').val('5'); - $('#proctored_exam').trigger('change'); - expect(addAllowanceView.$el.find('#exam_type_label').html()).toContain('Proctored Exam'); }); @@ -211,7 +209,7 @@ describe('ProctoredExamAddAllowanceView', function() { this.proctored_exam_allowance = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceView(); addAllowanceView = new edx.instructor_dashboard.proctoring.AddAllowanceView({ course_id: 'test_course_id', - proctored_exams: proctoredExamJson, + all_exams: proctoredExamJson, proctored_exam_allowance_view: this.proctored_exam_allowance, allowance_types: allowanceTypes }); @@ -222,10 +220,7 @@ describe('ProctoredExamAddAllowanceView', function() { expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Midterm Exam'); expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Final Exam'); expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Test Exam'); - expect(addAllowanceView.$el.find('#exam_type_label')).toExist(); $('#proctored_exam').val('6'); - $('#proctored_exam').trigger('change'); - expect(addAllowanceView.$el.find('#exam_type_label').html()).toContain('Timed Exam'); }); @@ -244,7 +239,7 @@ describe('ProctoredExamAddAllowanceView', function() { // eslint-disable-next-line no-new new edx.instructor_dashboard.proctoring.AddAllowanceView({ course_id: 'test_course_id', - proctored_exams: proctoredExamJson, + all_exams: proctoredExamJson, proctored_exam_allowance_view: this.proctored_exam_allowance, allowance_types: allowanceTypes }); From efa6fc87a1ade2366d43e2f465d8cd7ce8e7dbb7 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Mon, 12 Jul 2021 14:37:36 -0400 Subject: [PATCH 11/22] Update proctored_exam_add_allowance_spec.js --- .../static/proctoring/spec/proctored_exam_add_allowance_spec.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js index 36fe895c23f..7007646a15f 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js @@ -188,7 +188,6 @@ describe('ProctoredExamAddAllowanceView', function() { this.server.respond(); expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Midterm Exam'); - expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Final Exam'); expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Test Exam'); $('#proctored_exam').val('5'); }); @@ -218,7 +217,6 @@ describe('ProctoredExamAddAllowanceView', function() { this.server.respond(); expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Midterm Exam'); - expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Final Exam'); expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Test Exam'); $('#proctored_exam').val('6'); }); From 4a94106b185b88e8d9f69154901515a5a984f130 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Mon, 12 Jul 2021 14:45:19 -0400 Subject: [PATCH 12/22] Update proctored_exam_add_allowance_spec.js --- .../static/proctoring/spec/proctored_exam_add_allowance_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js index 7007646a15f..b735358fd5f 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js @@ -88,7 +88,7 @@ describe('ProctoredExamAddAllowanceView', function() { // from http://www.howtocreate.co.uk/tutorials/jsexamples/syntax/prepareInline.html // eslint-disable-next-line max-len - html = '
<%- gettext(\"Add a New Allowance\") %><\/div>\n\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n diff --git a/edx_proctoring/views.py b/edx_proctoring/views.py index 9026746f6f5..d185229e194 100644 --- a/edx_proctoring/views.py +++ b/edx_proctoring/views.py @@ -1633,7 +1633,7 @@ def put(self, request): except AllowanceValueNotAllowedException: return Response( status=status.HTTP_400_BAD_REQUEST, - data={"detail": _("Enter a valid value number")} + data={"detail": _("Enter a valid positive value number")} ) From 0384c799e3df055a25f68f10a9a2e8e336bcfbf1 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Wed, 14 Jul 2021 13:10:48 -0400 Subject: [PATCH 16/22] Add Waffle Flag Cabability --- .../models/proctored_exam_allowance_model.js | 2 +- .../proctored_exam_bulk_allowance_model.js | 15 + .../proctored_exam_add_allowance_view.js | 157 +++----- .../proctored_exam_add_bulk_allowance_view.js | 295 +++++++++++++++ .../js/views/proctored_exam_allowance_view.js | 25 +- .../spec/proctored_exam_add_allowance_spec.js | 70 +++- .../proctored_exam_add_bulk_allowance_spec.js | 336 ++++++++++++++++++ .../templates/add-new-allowance.underscore | 79 ++-- .../add-new-bulk-allowance.underscore | 105 ++++++ 9 files changed, 902 insertions(+), 182 deletions(-) create mode 100644 edx_proctoring/static/proctoring/js/models/proctored_exam_bulk_allowance_model.js create mode 100644 edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js create mode 100644 edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js create mode 100644 edx_proctoring/static/proctoring/templates/add-new-bulk-allowance.underscore diff --git a/edx_proctoring/static/proctoring/js/models/proctored_exam_allowance_model.js b/edx_proctoring/static/proctoring/js/models/proctored_exam_allowance_model.js index 0962b318576..d5459474755 100644 --- a/edx_proctoring/static/proctoring/js/models/proctored_exam_allowance_model.js +++ b/edx_proctoring/static/proctoring/js/models/proctored_exam_allowance_model.js @@ -7,7 +7,7 @@ edx = edx || {}; edx.instructor_dashboard.proctoring = edx.instructor_dashboard.proctoring || {}; edx.instructor_dashboard.proctoring.ProctoredExamAllowanceModel = Backbone.Model.extend({ - url: '/api/edx_proctoring/v1/proctored_exam/bulk_allowance' + url: '/api/edx_proctoring/v1/proctored_exam/allowance' }); this.edx.instructor_dashboard.proctoring.ProctoredExamAllowanceModel = diff --git a/edx_proctoring/static/proctoring/js/models/proctored_exam_bulk_allowance_model.js b/edx_proctoring/static/proctoring/js/models/proctored_exam_bulk_allowance_model.js new file mode 100644 index 00000000000..dffb201ef9c --- /dev/null +++ b/edx_proctoring/static/proctoring/js/models/proctored_exam_bulk_allowance_model.js @@ -0,0 +1,15 @@ +edx = edx || {}; + +(function(Backbone) { + 'use strict'; + + edx.instructor_dashboard = edx.instructor_dashboard || {}; + edx.instructor_dashboard.proctoring = edx.instructor_dashboard.proctoring || {}; + + edx.instructor_dashboard.proctoring.ProctoredExamBulkAllowanceModel = Backbone.Model.extend({ + url: '/api/edx_proctoring/v1/proctored_exam/bulk_allowance' + + }); + this.edx.instructor_dashboard.proctoring.ProctoredExamBulkAllowanceModel = + edx.instructor_dashboard.proctoring.ProctoredExamBulkAllowanceModel; +}).call(this, Backbone); diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js index 5152884a6cc..0ded3e0d6e7 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js @@ -11,9 +11,7 @@ edx = edx || {}; template: null, template_url: '/static/proctoring/templates/add-new-allowance.underscore', initialize: function(options) { - this.all_exams = options.proctored_exams; - this.proctored_exams = []; - this.timed_exams = []; + this.proctored_exams = options.proctored_exams; this.proctored_exam_allowance_view = options.proctored_exam_allowance_view; this.course_id = options.course_id; this.allowance_types = options.allowance_types; @@ -25,19 +23,17 @@ edx = edx || {}; events: { 'submit form': 'addAllowance', 'change #proctored_exam': 'selectExam', - 'change #timed_exam': 'selectExam', - 'change #allowance_type': 'selectAllowance', - 'change #exam_type': 'selectExamType' + 'change #allowance_type': 'selectAllowance' }, loadTemplateData: function() { var self = this; $.ajax({url: self.template_url, dataType: 'html'}) .done(function(templateData) { - self.sortExamsByExamType(); self.template = _.template(templateData); self.render(); self.showModal(); self.updateCss(); + self.selectExamAtIndex(0); }); }, updateCss: function() { @@ -69,12 +65,11 @@ edx = edx || {}; $el.find('form input[type="text"]').css({ height: '26px', padding: '1px 8px 2px', - 'font-size': '14px', - width: '100%' + 'font-size': '14px' }); $el.find('form input[type="submit"]').css({ 'margin-top': '10px', - float: 'right' + padding: '2px 32px' }); $el.find('.error-message').css({ color: '#ff0000', @@ -89,41 +84,12 @@ edx = edx || {}; }); $el.find('form select').css({ padding: '2px 0px 2px 2px', - 'font-size': '16px', - width: '100%' - }); - $el.find('#selected_exams').css({ - background: '#fff', - display: 'flex', - 'flex-wrap': 'wrap', - 'align-content': 'flex-start', - 'overflow-x': 'scroll' - }); - $el.find('.tag').css({ - 'font-size': '14px', - height: '15px', - 'margin-right': '5px', - padding: '5px 6px', - border: '1px solid #ccc', - 'border-radius': '3px', - background: '#eee', - display: 'flex', - 'align-items': 'center', - color: '#333', - 'box-shadow': '0 0 4px rgba(0, 0, 0, 0.2), inset 0 1px 1px #fff', - cursor: 'default' - }); - $el.find('.close').css({ - 'font-size': '16px', - margin: '5px' - }); - $el.find('.exam_dropdown').css({ - height: '60px' + 'font-size': '16px' }); }, getCurrentFormValues: function() { return { - proctored_exam: this.selectedExams, + proctored_exam: $('select#proctored_exam').val(), allowance_type: $('select#allowance_type').val(), allowance_value: $('#allowance_value').val(), user_info: $('#user_info').val() @@ -150,18 +116,13 @@ edx = edx || {}; this.updateCss(); }, addAllowance: function(event) { - var $errorResponse, values, formHasErrors, exams; + var $errorResponse, values, formHasErrors; var self = this; event.preventDefault(); $errorResponse = $('.error-response'); $errorResponse.html(); values = this.getCurrentFormValues(); formHasErrors = false; - exams = ''; - - $('.close').each(function() { - exams += $(this).attr('data-item') + ','; - }); $.each(values, function(key, value) { if (value === '') { @@ -172,13 +133,6 @@ edx = edx || {}; } }); - if (exams === '') { - formHasErrors = true; - self.showError(self, 'proctored_exam', gettext('Required field')); - } else { - self.hideError(self, 'proctored_exam'); - } - if (!formHasErrors) { self.model.fetch({ headers: { @@ -186,9 +140,9 @@ edx = edx || {}; }, type: 'PUT', data: { - exam_ids: exams, - user_ids: values.user_info, - allowance_type: values.allowance_type, + exam_id: values.proctored_exam, + user_info: values.user_info, + key: values.allowance_type, value: values.allowance_value }, success: function() { @@ -206,85 +160,56 @@ edx = edx || {}; }); } }, - selectExamAtIndex: function(examID, examName) { - var createdTag = this.createTag(examName, examID); - $('.exam_dropdown:visible').val('default'); - $('.exam_dropdown:visible option[value=' + examID + ']').remove(); - $('#selected_exams').append(createdTag); - this.updateCss(); + selectExamAtIndex: function(index) { + var selectedExam = this.proctored_exams[index]; + + if (selectedExam.is_proctored) { + // Selected Exam is a Proctored or Practice-Proctored exam. + if (selectedExam.is_practice_exam) { + $('#exam_type_label').text(gettext('Practice Exam')); + } else { + $('#exam_type_label').text(gettext('Proctored Exam')); + } + + // In case of Proctored Exams, we hide the Additional Time label and show the Allowance Types Select + $('#additional_time_label').hide(); + $('select#allowance_type').val('additional_time_granted').show(); + } else { + // Selected Exam is a Timed Exam. + $('#exam_type_label').text(gettext('Timed Exam')); + + // In case of Timed Exams, we show the "Additional Time" label and hide the Allowance Types Select + $('#additional_time_label').show(); + // Even though we have the Select element hidden, the backend will still be using + // the Select's value for the allowance type (key). + $('select#allowance_type').val('additional_time_granted').hide(); + } + this.updateAllowanceLabels('additional_time_granted'); }, selectExam: function() { - this.selectExamAtIndex($('.exam_dropdown:visible').val(), $('.exam_dropdown:visible :selected').text()); + this.selectExamAtIndex($('#proctored_exam')[0].selectedIndex); }, selectAllowance: function() { this.updateAllowanceLabels($('#allowance_type').val()); }, - selectExamType: function() { - $('.close').each(function() { - $(this).trigger('click'); - }); - if ($('#proctored_exam').is(':visible')) { - $('#proctored_exam').hide(); - $('#timed_exam').show(); - $('#allowance_type option[value="review_policy_exception"]').remove(); - } else { - $('#proctored_exam').show(); - $('#timed_exam').hide(); - $('#allowance_type').append(new Option(gettext('Review Policy Exception'), 'review_policy_exception')); - } - this.updateAllowanceLabels($('#allowance_type').val()); - }, updateAllowanceLabels: function(selectedAllowanceType) { if (selectedAllowanceType === 'additional_time_granted') { - $('#allowance_value_label').text(gettext('Input Additional Minutes as a Positive Number')); - } else if (selectedAllowanceType === 'time_multiplier') { - $('#allowance_value_label').text(gettext('Input Multiplier as a Number Greater Than 1')); + $('#minutes_label').show(); + $('#allowance_value_label').text(gettext('Additional Time')); } else { - $('#allowance_value_label').text(gettext('Add Policy Exception')); + $('#minutes_label').hide(); + $('#allowance_value_label').text(gettext('Value')); } }, - sortExamsByExamType: function() { - var self = this; - self.all_exams.forEach(function(exam) { - if (exam.is_proctored) { - self.proctored_exams.push(exam); - } else { - self.timed_exams.push(exam); - } - }); - }, - createTag: function(examName, examID) { - var div = document.createElement('div'); - var span = document.createElement('span'); - var closeIcon = document.createElement('span'); - div.setAttribute('class', 'tag'); - span.innerHTML = examName; - closeIcon.innerHTML = 'x'; - closeIcon.setAttribute('class', 'close'); - closeIcon.setAttribute('data-item', examID); - closeIcon.setAttribute('data-name', examName); - closeIcon.onclick = this.deleteTag; - div.appendChild(span); - div.appendChild(closeIcon); - return div; - }, - deleteTag: function() { - var examID = $(this).data('item'); - var examName = $(this).data('name'); - $(this).closest('div').remove(); - $('.exam_dropdown:visible').append(new Option(examName, examID)); - }, render: function() { $(this.el).html(this.template({ proctored_exams: this.proctored_exams, - timed_exams: this.timed_exams, allowance_types: this.allowance_types })); this.$form = { proctored_exam: this.$('select#proctored_exam'), - timed_exam: this.$('select#timed_exam'), allowance_type: this.$('select#allowance_type'), allowance_value: this.$('#allowance_value'), user_info: this.$('#user_info') diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js new file mode 100644 index 00000000000..dee570d76e7 --- /dev/null +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js @@ -0,0 +1,295 @@ +edx = edx || {}; + +(function(Backbone, $, _, gettext) { + 'use strict'; + + edx.instructor_dashboard = edx.instructor_dashboard || {}; + edx.instructor_dashboard.proctoring = edx.instructor_dashboard.proctoring || {}; + + edx.instructor_dashboard.proctoring.AddAllowanceView = Backbone.ModalView.extend({ + name: 'AddBulkAllowanceView', + template: null, + template_url: '/static/proctoring/templates/add-new-bulk-allowance.underscore', + initialize: function(options) { + this.all_exams = options.proctored_exams; + this.proctored_exams = []; + this.timed_exams = []; + this.proctored_exam_allowance_view = options.proctored_exam_allowance_view; + this.course_id = options.course_id; + this.allowance_types = options.allowance_types; + this.model = new edx.instructor_dashboard.proctoring.ProctoredExamBulkAllowanceModel(); + _.bindAll(this, 'render'); + this.loadTemplateData(); + // Backbone.Validation.bind( this, {valid:this.hideError, invalid:this.showError}); + }, + events: { + 'submit form': 'addAllowance', + 'change #proctored_exam': 'selectExam', + 'change #timed_exam': 'selectExam', + 'change #allowance_type': 'selectAllowance', + 'change #exam_type': 'selectExamType' + }, + loadTemplateData: function() { + var self = this; + $.ajax({url: self.template_url, dataType: 'html'}) + .done(function(templateData) { + self.sortExamsByExamType(); + self.template = _.template(templateData); + self.render(); + self.showModal(); + self.updateCss(); + }); + }, + updateCss: function() { + var $el = $(this.el); + $el.find('.modal-header').css({ + color: '#1580b0', + 'font-size': '20px', + 'font-weight': '600', + 'line-height': 'normal', + padding: '10px 15px', + 'border-bottom': '1px solid #ccc' + }); + $el.find('form').css({ + padding: '15px' + }); + $el.find('form table.compact td').css({ + 'vertical-align': 'middle', + padding: '4px 8px' + }); + $el.find('form label').css({ + display: 'block', + 'font-size': '14px', + margin: 0, + cursor: 'default' + }); + $el.find('form #minutes_label').css({ + display: 'inline-block' + }); + $el.find('form input[type="text"]').css({ + height: '26px', + padding: '1px 8px 2px', + 'font-size': '14px', + width: '100%' + }); + $el.find('form input[type="submit"]').css({ + 'margin-top': '10px', + float: 'right' + }); + $el.find('.error-message').css({ + color: '#ff0000', + 'line-height': 'normal', + 'font-size': '14px' + }); + $el.find('.error-response').css({ + color: '#ff0000', + 'line-height': 'normal', + 'font-size': '14px', + padding: '0px 10px 5px 7px' + }); + $el.find('form select').css({ + padding: '2px 0px 2px 2px', + 'font-size': '16px', + width: '100%' + }); + $el.find('#selected_exams').css({ + background: '#fff', + display: 'flex', + 'flex-wrap': 'wrap', + 'align-content': 'flex-start', + 'overflow-x': 'scroll' + }); + $el.find('.tag').css({ + 'font-size': '14px', + height: '15px', + 'margin-right': '5px', + padding: '5px 6px', + border: '1px solid #ccc', + 'border-radius': '3px', + background: '#eee', + display: 'flex', + 'align-items': 'center', + color: '#333', + 'box-shadow': '0 0 4px rgba(0, 0, 0, 0.2), inset 0 1px 1px #fff', + cursor: 'default' + }); + $el.find('.close').css({ + 'font-size': '16px', + margin: '5px' + }); + $el.find('.exam_dropdown').css({ + height: '60px' + }); + }, + getCurrentFormValues: function() { + return { + proctored_exam: this.selectedExams, + allowance_type: $('select#allowance_type').val(), + allowance_value: $('#allowance_value').val(), + user_info: $('#user_info').val() + }; + }, + hideError: function(view, attr) { + var $element = view.$form[attr]; + + $element.removeClass('error'); + $element.parent().find('.error-message').empty(); + }, + showError: function(view, attr, errorMessage) { + var $element = view.$form[attr]; + var $errorMessage; + + $element.addClass('error'); + $errorMessage = $element.parent().find('.error-message'); + if ($errorMessage.length === 0) { + $errorMessage = $("
"); + $element.parent().append($errorMessage); + } + + $errorMessage.empty().append(errorMessage); + this.updateCss(); + }, + addAllowance: function(event) { + var $errorResponse, values, formHasErrors, exams; + var self = this; + event.preventDefault(); + $errorResponse = $('.error-response'); + $errorResponse.html(); + values = this.getCurrentFormValues(); + formHasErrors = false; + exams = ''; + + $('.close').each(function() { + exams += $(this).attr('data-item') + ','; + }); + + $.each(values, function(key, value) { + if (value === '') { + formHasErrors = true; + self.showError(self, key, gettext('Required field')); + } else { + self.hideError(self, key); + } + }); + + if (exams === '') { + formHasErrors = true; + self.showError(self, 'proctored_exam', gettext('Required field')); + } else { + self.hideError(self, 'proctored_exam'); + } + + if (!formHasErrors) { + self.model.fetch({ + headers: { + 'X-CSRFToken': self.proctored_exam_allowance_view.getCSRFToken() + }, + type: 'PUT', + data: { + exam_ids: exams, + user_ids: values.user_info, + allowance_type: values.allowance_type, + value: values.allowance_value + }, + success: function() { + // fetch the allowances again. + $errorResponse.html(); + self.proctored_exam_allowance_view.collection.url = + self.proctored_exam_allowance_view.initial_url + self.course_id + '/allowance'; + self.proctored_exam_allowance_view.hydrate(); + self.hideModal(); + }, + error: function(unused, response) { + var data = $.parseJSON(response.responseText); + $errorResponse.html(gettext(data.detail)); + } + }); + } + }, + selectExamAtIndex: function(examID, examName) { + var createdTag = this.createTag(examName, examID); + $('.exam_dropdown:visible').val('default'); + $('.exam_dropdown:visible option[value=' + examID + ']').remove(); + $('#selected_exams').append(createdTag); + this.updateCss(); + }, + selectExam: function() { + this.selectExamAtIndex($('.exam_dropdown:visible').val(), $('.exam_dropdown:visible :selected').text()); + }, + selectAllowance: function() { + this.updateAllowanceLabels($('#allowance_type').val()); + }, + selectExamType: function() { + $('.close').each(function() { + $(this).trigger('click'); + }); + if ($('#proctored_exam').is(':visible')) { + $('#proctored_exam').hide(); + $('#timed_exam').show(); + $('#allowance_type option[value="review_policy_exception"]').remove(); + } else { + $('#proctored_exam').show(); + $('#timed_exam').hide(); + $('#allowance_type').append(new Option(gettext('Review Policy Exception'), 'review_policy_exception')); + } + this.updateAllowanceLabels($('#allowance_type').val()); + }, + updateAllowanceLabels: function(selectedAllowanceType) { + if (selectedAllowanceType === 'additional_time_granted') { + $('#allowance_value_label').text(gettext('Input Additional Minutes as a Positive Number')); + } else if (selectedAllowanceType === 'time_multiplier') { + $('#allowance_value_label').text(gettext('Input Multiplier as a Number Greater Than 1')); + } else { + $('#allowance_value_label').text(gettext('Add Policy Exception')); + } + }, + sortExamsByExamType: function() { + var self = this; + self.all_exams.forEach(function(exam) { + if (exam.is_proctored) { + self.proctored_exams.push(exam); + } else { + self.timed_exams.push(exam); + } + }); + }, + createTag: function(examName, examID) { + var div = document.createElement('div'); + var span = document.createElement('span'); + var closeIcon = document.createElement('span'); + div.setAttribute('class', 'tag'); + span.innerHTML = examName; + closeIcon.innerHTML = 'x'; + closeIcon.setAttribute('class', 'close'); + closeIcon.setAttribute('data-item', examID); + closeIcon.setAttribute('data-name', examName); + closeIcon.onclick = this.deleteTag; + div.appendChild(span); + div.appendChild(closeIcon); + return div; + }, + deleteTag: function() { + var examID = $(this).data('item'); + var examName = $(this).data('name'); + $(this).closest('div').remove(); + $('.exam_dropdown:visible').append(new Option(examName, examID)); + }, + + render: function() { + $(this.el).html(this.template({ + proctored_exams: this.proctored_exams, + timed_exams: this.timed_exams, + allowance_types: this.allowance_types + })); + + this.$form = { + proctored_exam: this.$('select#proctored_exam'), + timed_exam: this.$('select#timed_exam'), + allowance_type: this.$('select#allowance_type'), + allowance_value: this.$('#allowance_value'), + user_info: this.$('#user_info') + }; + return this; + } + }); +}).call(this, Backbone, $, _, gettext); diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js index 445e172cc89..88e65bb394e 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js @@ -144,15 +144,28 @@ edx = edx || {}; }, showAddModal: function(event) { var self = this; + var enable_bulk_allowance = + self.$el.data('enable-exam-resume-proctoring-improvements'); + enable_bulk_allowance = this.enable_exam_resume_proctoring_improvements && + this.enable_exam_resume_proctoring_improvements.toLowerCase() === 'true'; self.proctoredExamCollection.fetch({ success: function() { // eslint-disable-next-line no-new - new edx.instructor_dashboard.proctoring.AddAllowanceView({ - course_id: self.course_id, - proctored_exams: self.proctoredExamCollection.toJSON(), - proctored_exam_allowance_view: self, - allowance_types: self.allowance_types - }); + if (!this.enable_exam_resume_proctoring_improvements) { + new edx.instructor_dashboard.proctoring.AddAllowanceView({ + course_id: self.course_id, + proctored_exams: self.proctoredExamCollection.toJSON(), + proctored_exam_allowance_view: self, + allowance_types: self.allowance_types + }); + } else { + new edx.instructor_dashboard.proctoring.AddBulkAllowanceView({ + course_id: self.course_id, + proctored_exams: self.proctoredExamCollection.toJSON(), + proctored_exam_allowance_view: self, + allowance_types: self.allowance_types + }); + } } }); event.stopPropagation(); diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js index a31ddc0dd08..52b3bfaab54 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js @@ -79,8 +79,7 @@ describe('ProctoredExamAddAllowanceView', function() { var allowanceTypes = [ ['additional_time_granted', gettext('Additional Time (minutes)')], - ['review_policy_exception', gettext('Review Policy Exception')], - ['time_multiplier', gettext('Time Multiplier')] + ['review_policy_exception', gettext('Review Policy Exception')] ]; beforeEach(function() { @@ -88,7 +87,7 @@ describe('ProctoredExamAddAllowanceView', function() { // from http://www.howtocreate.co.uk/tutorials/jsexamples/syntax/prepareInline.html // eslint-disable-next-line max-len - html = '
<%- gettext("Add a New Allowance") %>
\n
\n

\n

\n
\n \n <\/td>\n <\/tr>\n
\n
\n
\n
\n \n
\n
<\/div>\n <\/td>\n <\/tr>\n
\n
\n
\n
\n \n <\/td>\n <\/tr>\n
\n \n <\/td>\n <\/tr>\n <\/table>\n<\/form>\n'; + html = '
<%- gettext(Add a New Allowance) %>
\n\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n \n
\n \n
\n \n \n
\n \n
\n \n \n \n
\n
\n
\n
\n \n
\n \n \n
\n \n
\n \n \n
\n \n \n
\n\n'; allowancesHtml = '' + '<%- gettext("Allowances") %>' + From c7081f64e8a829ad30bacfaaab6bc02cf6182bc7 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Tue, 13 Jul 2021 10:22:00 -0400 Subject: [PATCH 13/22] Fixed styling and js tests --- .../proctored_exam_add_allowance_view.js | 5 +- .../spec/proctored_exam_add_allowance_spec.js | 63 ++----------------- 2 files changed, 7 insertions(+), 61 deletions(-) diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js index b5c3bc470e0..e246f02850f 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js @@ -93,18 +93,16 @@ edx = edx || {}; width: '100%' }); $el.find('#selected_exams').css({ - 'border-radius': '3px', background: '#fff', display: 'flex', 'flex-wrap': 'wrap', 'align-content': 'flex-start', - padding: '6px', 'overflow-x': 'scroll' }); $el.find('.tag').css({ 'font-size': '14px', height: '15px', - margin: '5px', + 'margin-right': '5px', padding: '5px 6px', border: '1px solid #ccc', 'border-radius': '3px', @@ -234,6 +232,7 @@ edx = edx || {}; $('#timed_exam').hide(); $('#allowance_type').append(new Option(gettext('Review Policy Exception'), 'review_policy_exception')); } + this.updateAllowanceLabels($('#allowance_type').val()); }, updateAllowanceLabels: function(selectedAllowanceType) { if (selectedAllowanceType === 'additional_time_granted') { diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js index b735358fd5f..5dd801cb704 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js @@ -88,7 +88,7 @@ describe('ProctoredExamAddAllowanceView', function() { // from http://www.howtocreate.co.uk/tutorials/jsexamples/syntax/prepareInline.html // eslint-disable-next-line max-len - html = '
<%- gettext(Add a New Allowance) %>
\n\n

\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n \n
\n \n
\n \n \n
\n \n
\n \n \n \n
\n
\n
\n
\n \n
\n \n \n
\n \n
\n \n \n
\n \n \n
\n\n'; + html = '
<%- gettext("Add a New Allowance") %>
\n\n

\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n
\n \n
\n \n
\n \n
\n \n \n
\n
\n
\n \n
\n \n
\n \n
\n \n
\n \n
\n'; allowancesHtml = '' + '<%- gettext("Allowances") %>' + @@ -208,7 +208,7 @@ describe('ProctoredExamAddAllowanceView', function() { this.proctored_exam_allowance = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceView(); addAllowanceView = new edx.instructor_dashboard.proctoring.AddAllowanceView({ course_id: 'test_course_id', - all_exams: proctoredExamJson, + proctored_exams: proctoredExamJson, proctored_exam_allowance_view: this.proctored_exam_allowance, allowance_types: allowanceTypes }); @@ -216,9 +216,8 @@ describe('ProctoredExamAddAllowanceView', function() { this.server.respond(); this.server.respond(); - expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Midterm Exam'); - expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Test Exam'); - $('#proctored_exam').val('6'); + expect(addAllowanceView.$el.find('#timed_exam').html()).toContain('Final Exam'); + $('#timed_exam').val('6'); }); @@ -237,7 +236,7 @@ describe('ProctoredExamAddAllowanceView', function() { // eslint-disable-next-line no-new new edx.instructor_dashboard.proctoring.AddAllowanceView({ course_id: 'test_course_id', - all_exams: proctoredExamJson, + proctored_exams: proctoredExamJson, proctored_exam_allowance_view: this.proctored_exam_allowance, allowance_types: allowanceTypes }); @@ -265,41 +264,6 @@ describe('ProctoredExamAddAllowanceView', function() { JSON.stringify([]) ] ); - - // again fetch the results after the proctored exam allowance addition - this.server.respondWith('GET', '/api/edx_proctoring/v1/proctored_exam/test_course_id/allowance', - [ - 200, - { - 'Content-Type': 'application/json' - }, - JSON.stringify(expectedProctoredAllowanceJson) - ] - ); - - // select the form values - - $('#proctored_exam').val('Test Exam'); - $('#allowance_type').val('additional_time_granted'); - $('#allowance_value').val('1'); - $('#user_info').val('testuser1'); - - // trigger the add allowance event. - spyOnEvent('form', 'submit'); - $('form').trigger('submit'); - - // process the deleted allowance requests. - this.server.respond(); - this.server.respond(); - - expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) - .toContain('testuser1'); - expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) - .toContain('testuser1@test.com'); - expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) - .toContain('Additional Time (minutes)'); - expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) - .toContain('Test Exam'); }); it('should send error when adding proctored exam allowance', function() { var addAllowanceView; @@ -356,23 +320,6 @@ describe('ProctoredExamAddAllowanceView', function() { ] ); - // select the form values - // invalid user_info returns error - $('#proctored_exam').val('Test Exam'); - $('#allowance_type').val('additional_time_granted'); - $('#allowance_value').val('2'); - $('#user_info').val('testuser112321'); - - // trigger the add allowance event. - spyOnEvent('form', 'submit'); - $('form').trigger('submit'); - - // process the deleted allowance requests. - this.server.respond(); - this.server.respond(); - - expect(addAllowanceView.$el.find('.error-response').html()).toContain('Cannot find user'); - // select the form values // empty value returns error $('#proctored_exam').val('Test Exam'); From 20ed108235ee4011ba52f3132a6d71d50689af28 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Tue, 13 Jul 2021 10:27:23 -0400 Subject: [PATCH 14/22] Fix js-lint issue --- .../static/proctoring/spec/proctored_exam_add_allowance_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js index 5dd801cb704..c84d30bd657 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js @@ -88,7 +88,7 @@ describe('ProctoredExamAddAllowanceView', function() { // from http://www.howtocreate.co.uk/tutorials/jsexamples/syntax/prepareInline.html // eslint-disable-next-line max-len - html = '
<%- gettext("Add a New Allowance") %>
\n
\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n
\n \n
\n \n
\n \n
\n \n \n
\n
\n
\n \n
\n \n
\n \n
\n \n
\n \n
\n'; + html = '
<%- gettext("Add a New Allowance") %>
\n
\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n
\n \n
\n \n
\n \n
\n \n \n
\n
\n
\n \n
\n \n
\n \n
\n \n
\n \n
\n'; allowancesHtml = '' + '<%- gettext("Allowances") %>' + From f26f52f9cdc3f4316a504186b60792bd77bab1da Mon Sep 17 00:00:00 2001 From: mohtamba Date: Tue, 13 Jul 2021 11:20:33 -0400 Subject: [PATCH 15/22] Fix error wording --- .../proctoring/js/views/proctored_exam_add_allowance_view.js | 4 ++-- .../proctoring/spec/proctored_exam_add_allowance_spec.js | 2 +- .../static/proctoring/templates/add-new-allowance.underscore | 2 +- edx_proctoring/views.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js index e246f02850f..5152884a6cc 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_allowance_view.js @@ -236,9 +236,9 @@ edx = edx || {}; }, updateAllowanceLabels: function(selectedAllowanceType) { if (selectedAllowanceType === 'additional_time_granted') { - $('#allowance_value_label').text(gettext('Input Additional Minutes as a Number')); + $('#allowance_value_label').text(gettext('Input Additional Minutes as a Positive Number')); } else if (selectedAllowanceType === 'time_multiplier') { - $('#allowance_value_label').text(gettext('Input Multiplier as a Number')); + $('#allowance_value_label').text(gettext('Input Multiplier as a Number Greater Than 1')); } else { $('#allowance_value_label').text(gettext('Add Policy Exception')); } diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js index c84d30bd657..a31ddc0dd08 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_allowance_spec.js @@ -88,7 +88,7 @@ describe('ProctoredExamAddAllowanceView', function() { // from http://www.howtocreate.co.uk/tutorials/jsexamples/syntax/prepareInline.html // eslint-disable-next-line max-len - html = '
<%- gettext("Add a New Allowance") %>
\n
\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n
\n \n
\n \n
\n \n
\n \n \n
\n
\n
\n \n
\n \n
\n \n
\n \n
\n \n
\n'; + html = '
<%- gettext("Add a New Allowance") %>
\n
\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n
\n \n
\n \n
\n \n
\n \n \n
\n
\n
\n \n
\n \n
\n \n
\n \n
\n \n
\n'; allowancesHtml = '' + '<%- gettext("Allowances") %>' + diff --git a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore index a0d04b35093..74dbb238c83 100644 --- a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore +++ b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore @@ -88,7 +88,7 @@

- +
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n
\n \n
\n \n
\n \n
\n \n \n
\n
\n
\n \n
\n \n
\n \n
\n \n
\n \n
\n'; + html = '
<%- gettext("Add a New Allowance") %>
\n
\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n \n \n
\n \n \n \n
\n \n \n \n\n \n
\n \n \n \n \n
\n \n \n \n
\n \n
\n\n'; allowancesHtml = '' + '<%- gettext("Allowances") %>' + @@ -188,8 +187,12 @@ describe('ProctoredExamAddAllowanceView', function() { this.server.respond(); expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Midterm Exam'); + expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Final Exam'); expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Test Exam'); + expect(addAllowanceView.$el.find('#exam_type_label')).toExist(); $('#proctored_exam').val('5'); + $('#proctored_exam').trigger('change'); + expect(addAllowanceView.$el.find('#exam_type_label').html()).toContain('Proctored Exam'); }); @@ -216,8 +219,13 @@ describe('ProctoredExamAddAllowanceView', function() { this.server.respond(); this.server.respond(); - expect(addAllowanceView.$el.find('#timed_exam').html()).toContain('Final Exam'); - $('#timed_exam').val('6'); + expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Midterm Exam'); + expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Final Exam'); + expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Test Exam'); + expect(addAllowanceView.$el.find('#exam_type_label')).toExist(); + $('#proctored_exam').val('6'); + $('#proctored_exam').trigger('change'); + expect(addAllowanceView.$el.find('#exam_type_label').html()).toContain('Timed Exam'); }); @@ -264,6 +272,41 @@ describe('ProctoredExamAddAllowanceView', function() { JSON.stringify([]) ] ); + + // again fetch the results after the proctored exam allowance addition + this.server.respondWith('GET', '/api/edx_proctoring/v1/proctored_exam/test_course_id/allowance', + [ + 200, + { + 'Content-Type': 'application/json' + }, + JSON.stringify(expectedProctoredAllowanceJson) + ] + ); + + // select the form values + + $('#proctored_exam').val('Test Exam'); + $('#allowance_type').val('additional_time_granted'); + $('#allowance_value').val('1'); + $('#user_info').val('testuser1'); + + // trigger the add allowance event. + spyOnEvent('form', 'submit'); + $('form').trigger('submit'); + + // process the deleted allowance requests. + this.server.respond(); + this.server.respond(); + + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .toContain('testuser1'); + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .toContain('testuser1@test.com'); + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .toContain('Additional Time (minutes)'); + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .toContain('Test Exam'); }); it('should send error when adding proctored exam allowance', function() { var addAllowanceView; @@ -320,6 +363,23 @@ describe('ProctoredExamAddAllowanceView', function() { ] ); + // select the form values + // invalid user_info returns error + $('#proctored_exam').val('Test Exam'); + $('#allowance_type').val('additional_time_granted'); + $('#allowance_value').val('2'); + $('#user_info').val('testuser112321'); + + // trigger the add allowance event. + spyOnEvent('form', 'submit'); + $('form').trigger('submit'); + + // process the deleted allowance requests. + this.server.respond(); + this.server.respond(); + + expect(addAllowanceView.$el.find('.error-response').html()).toContain('Cannot find user'); + // select the form values // empty value returns error $('#proctored_exam').val('Test Exam'); diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js new file mode 100644 index 00000000000..a31ddc0dd08 --- /dev/null +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js @@ -0,0 +1,336 @@ +describe('ProctoredExamAddAllowanceView', function() { + 'use strict'; + + var html = ''; + var allowancesHtml = ''; + var errorAddingAllowance = { + detail: 'Cannot find user' + }; + var expectedProctoredAllowanceJson = [ + { + created: '2015-08-10T09:15:45Z', + id: 1, + modified: '2015-08-10T09:15:45Z', + key: 'additional_time_granted', + value: '1', + proctored_exam: { + content_id: 'i4x://edX/DemoX/sequential/9f5e9b018a244ea38e5d157e0019e60c', + course_id: 'edX/DemoX/Demo_Course', + exam_name: 'Test Exam', + external_id: null, + id: 6, + is_active: true, + is_practice_exam: false, + is_proctored: true, + time_limit_mins: 1 + }, + user: { + username: 'testuser1', + email: 'testuser1@test.com' + } + } + ]; + + var expectedTimedAllowanceJson = [ + { + created: '2015-08-10T09:15:45Z', + id: 1, + modified: '2015-08-10T09:15:45Z', + key: 'additional_time_granted', + value: '1', + proctored_exam: { + content_id: 'i4x://edX/DemoX/sequential/9f5e9b018a244ea38e5d157e0019e60c', + course_id: 'edX/DemoX/Demo_Course', + exam_name: 'Test Exam', + external_id: null, + id: 6, + is_active: true, + is_practice_exam: false, + is_proctored: false, + time_limit_mins: 1 + }, + user: { + username: 'testuser1', + email: 'testuser1@test.com' + } + } + ]; + + var proctoredExamJson = [ + { + exam_name: 'Midterm Exam', + is_proctored: true, + is_practice: false, + id: 5 + }, + { + exam_name: 'Final Exam', + is_proctored: false, + is_practice: false, + id: 6 + }, + { + exam_name: 'Test Exam', + is_proctored: true, + is_practice: true, + id: 7 + } + ]; + + var allowanceTypes = [ + ['additional_time_granted', gettext('Additional Time (minutes)')], + ['review_policy_exception', gettext('Review Policy Exception')], + ['time_multiplier', gettext('Time Multiplier')] + ]; + + beforeEach(function() { + // We have converted the edx_proctoring/static/proctoring/templates/add-new-allowance.underscore template + // from http://www.howtocreate.co.uk/tutorials/jsexamples/syntax/prepareInline.html + + // eslint-disable-next-line max-len + html = '
<%- gettext("Add a New Allowance") %>
\n
\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n \n
\n \n
\n \n
\n \n
\n \n \n
\n
\n
\n \n
\n \n
\n \n
\n \n
\n \n
\n'; + + allowancesHtml = '' + + '<%- gettext("Allowances") %>' + + ' +' + + '<%- gettext("Add Allowance") %>' + + ' ' + + '<% var is_allowances = proctored_exam_allowances.length !== 0 %>' + + '<% if (is_allowances) { %>' + + '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '<% _.each(proctored_exam_allowances, function(proctored_exam_allowance){ %>' + + '' + + '' + + '<% if (proctored_exam_allowance.user){ %>' + + '' + + '' + + '<% }else{ %>' + + '' + + '<% } %>' + + '' + + '' + + '' + + '<% }); %>' + + '
Exam NameUsernameAllowance TypeAllowance ValueActions
' + + '<%- interpolate(gettext(" %(exam_display_name)s "),' + + '{ exam_display_name: proctored_exam_allowance.proctored_exam.exam_name }, true) %>' + + '' + + '<%- interpolate(gettext(" %(username)s "),' + + '{ username: proctored_exam_allowance.user.username }, true) %>' + + '' + + '<%- interpolate(gettext(" %(email)s "),' + + '{ email: proctored_exam_allowance.user.email }, true) %>' + + 'N/AN/A' + + '<%- interpolate(gettext(" %(allowance_name)s "),' + + '{ allowance_name: proctored_exam_allowance.key_display_name }, true) %>' + + '' + + '<%= proctored_exam_allowance.value %>' + + '' + + '[x]' + + '
' + + '<% } %>'; + this.server = sinon.fakeServer.create(); + this.server.autoRespond = true; + + setFixtures('
'); + // load the underscore template response before calling the proctored exam allowance view. + this.server.respondWith('GET', '/static/proctoring/templates/add-new-allowance.underscore', + [ + 200, + {'Content-Type': 'text/html'}, + html + ] + ); + this.server.respondWith('GET', '/static/proctoring/templates/course_allowances.underscore', + [ + 200, + {'Content-Type': 'text/html'}, + allowancesHtml + ] + ); + }); + + afterEach(function() { + this.server.restore(); + }); + it('should render the proctored exam add allowance view properly', function() { + var addAllowanceView; + this.server.respondWith('GET', '/api/edx_proctoring/v1/proctored_exam/test_course_id/allowance', + [ + 200, + { + 'Content-Type': 'application/json' + }, + JSON.stringify(expectedProctoredAllowanceJson) + ] + ); + + this.proctored_exam_allowance = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceView(); + addAllowanceView = new edx.instructor_dashboard.proctoring.AddAllowanceView({ + course_id: 'test_course_id', + proctored_exams: proctoredExamJson, + proctored_exam_allowance_view: this.proctored_exam_allowance, + allowance_types: allowanceTypes + }); + this.server.respond(); + this.server.respond(); + this.server.respond(); + + expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Midterm Exam'); + expect(addAllowanceView.$el.find('#proctored_exam').html()).toContain('Test Exam'); + $('#proctored_exam').val('5'); + }); + + + it('should render the timed exam add allowance view properly', function() { + var addAllowanceView; + this.server.respondWith('GET', '/api/edx_proctoring/v1/proctored_exam/test_course_id/allowance', + [ + 200, + { + 'Content-Type': 'application/json' + }, + JSON.stringify(expectedTimedAllowanceJson) + ] + ); + + this.proctored_exam_allowance = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceView(); + addAllowanceView = new edx.instructor_dashboard.proctoring.AddAllowanceView({ + course_id: 'test_course_id', + proctored_exams: proctoredExamJson, + proctored_exam_allowance_view: this.proctored_exam_allowance, + allowance_types: allowanceTypes + }); + this.server.respond(); + this.server.respond(); + this.server.respond(); + + expect(addAllowanceView.$el.find('#timed_exam').html()).toContain('Final Exam'); + $('#timed_exam').val('6'); + }); + + + it('should add the proctored exam allowance', function() { + this.server.respondWith('GET', '/api/edx_proctoring/v1/proctored_exam/test_course_id/allowance', + [ + 200, + { + 'Content-Type': 'application/json' + }, + JSON.stringify([]) + ] + ); + + this.proctored_exam_allowance = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceView(); + // eslint-disable-next-line no-new + new edx.instructor_dashboard.proctoring.AddAllowanceView({ + course_id: 'test_course_id', + proctored_exams: proctoredExamJson, + proctored_exam_allowance_view: this.proctored_exam_allowance, + allowance_types: allowanceTypes + }); + + this.server.respond(); + this.server.respond(); + this.server.respond(); + + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .not.toContain('testuser1'); + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .not.toContain('testuser1@test.com'); + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .not.toContain('Additional Time (minutes)'); + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .not.toContain('Test Exam'); + + // add the proctored exam allowance + this.server.respondWith('PUT', '/api/edx_proctoring/v1/proctored_exam/allowance', + [ + 200, + { + 'Content-Type': 'application/json' + }, + JSON.stringify([]) + ] + ); + }); + it('should send error when adding proctored exam allowance', function() { + var addAllowanceView; + this.server.respondWith('GET', '/api/edx_proctoring/v1/proctored_exam/test_course_id/allowance', + [ + 200, + { + 'Content-Type': 'application/json' + }, + JSON.stringify([]) + ] + ); + + this.proctored_exam_allowance = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceView(); + addAllowanceView = new edx.instructor_dashboard.proctoring.AddAllowanceView({ + course_id: 'test_course_id', + proctored_exams: proctoredExamJson, + proctored_exam_allowance_view: this.proctored_exam_allowance, + allowance_types: allowanceTypes + }); + + this.server.respond(); + this.server.respond(); + this.server.respond(); + + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .not.toContain('testuser1'); + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .not.toContain('testuser1@test.com'); + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .not.toContain('Additional Time (minutes)'); + expect(this.proctored_exam_allowance.$el.find('tr.allowance-items').html()) + .not.toContain('Test Exam'); + + // add the proctored exam allowance + this.server.respondWith('PUT', '/api/edx_proctoring/v1/proctored_exam/allowance', + [ + 400, + { + 'Content-Type': 'application/json' + }, + JSON.stringify(errorAddingAllowance) + ] + ); + + // again fetch the results after the proctored exam allowance addition + this.server.respondWith('GET', '/api/edx_proctoring/v1/proctored_exam/test_course_id/allowance', + [ + 200, + { + 'Content-Type': 'application/json' + }, + JSON.stringify(expectedProctoredAllowanceJson) + ] + ); + + // select the form values + // empty value returns error + $('#proctored_exam').val('Test Exam'); + $('#allowance_type').val('Additional Time (minutes)'); + $('#allowance_value').val(''); + $('#user_info').val('testuser1'); + + // trigger the add allowance event. + spyOnEvent('form', 'submit'); + $('form').trigger('submit'); + + expect(addAllowanceView.$el.find('.error-message').html()).toContain('Required field'); + }); +}); diff --git a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore index 74dbb238c83..58c83340ee3 100644 --- a/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore +++ b/edx_proctoring/static/proctoring/templates/add-new-allowance.underscore @@ -2,12 +2,6 @@ select#proctored_exam { width: 100%; } - select#timed_exam { - width: 100%; - } - table, td { - width: 100%; - }
@@ -15,67 +9,32 @@ - - - - - - - - - - - - - - - + - - + + +
- +
- -
- -
- -
- -
- <% _.each(proctored_exams, function(proctored_exam){ %> - <% }); %> -
-
+
+ + +
+ +
- + + + +
- + + +
- +
diff --git a/edx_proctoring/static/proctoring/templates/add-new-bulk-allowance.underscore b/edx_proctoring/static/proctoring/templates/add-new-bulk-allowance.underscore new file mode 100644 index 00000000000..74dbb238c83 --- /dev/null +++ b/edx_proctoring/static/proctoring/templates/add-new-bulk-allowance.underscore @@ -0,0 +1,105 @@ + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+
+ +
+ +
+ +
+ +
+ +
+ From 4d3ff87b2e475172dc77951f2fc46cedeead442b Mon Sep 17 00:00:00 2001 From: mohtamba Date: Wed, 14 Jul 2021 13:22:55 -0400 Subject: [PATCH 17/22] Update proctored_exam_allowance_view.js --- .../js/views/proctored_exam_allowance_view.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js index 88e65bb394e..e3d93b4217c 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js @@ -144,14 +144,15 @@ edx = edx || {}; }, showAddModal: function(event) { var self = this; - var enable_bulk_allowance = - self.$el.data('enable-exam-resume-proctoring-improvements'); - enable_bulk_allowance = this.enable_exam_resume_proctoring_improvements && - this.enable_exam_resume_proctoring_improvements.toLowerCase() === 'true'; + var enableBulkAllowanceModal = + self.$el.data('enable-bulk-allowance-modal'); + enableBulkAllowanceModal = enableBulkAllowanceModal && + enableBulkAllowanceModal.toLowerCase() === 'true'; self.proctoredExamCollection.fetch({ success: function() { - // eslint-disable-next-line no-new - if (!this.enable_exam_resume_proctoring_improvements) { + + if (enableBulkAllowanceModal) { + // eslint-disable-next-line no-new new edx.instructor_dashboard.proctoring.AddAllowanceView({ course_id: self.course_id, proctored_exams: self.proctoredExamCollection.toJSON(), @@ -159,6 +160,7 @@ edx = edx || {}; allowance_types: self.allowance_types }); } else { + // eslint-disable-next-line no-new new edx.instructor_dashboard.proctoring.AddBulkAllowanceView({ course_id: self.course_id, proctored_exams: self.proctoredExamCollection.toJSON(), From 73d6c990d83d337c1ef837c94f223a1688a60800 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Wed, 14 Jul 2021 13:53:34 -0400 Subject: [PATCH 18/22] Update proctored_exam_allowance_view.js --- .../static/proctoring/js/views/proctored_exam_allowance_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js index e3d93b4217c..7cbb6389a71 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js @@ -151,7 +151,7 @@ edx = edx || {}; self.proctoredExamCollection.fetch({ success: function() { - if (enableBulkAllowanceModal) { + if (!enableBulkAllowanceModal) { // eslint-disable-next-line no-new new edx.instructor_dashboard.proctoring.AddAllowanceView({ course_id: self.course_id, From baa37310d7a7648d9c07674b64e7b86bb96248ff Mon Sep 17 00:00:00 2001 From: mohtamba Date: Thu, 15 Jul 2021 12:22:59 -0400 Subject: [PATCH 19/22] Updated Waffle Flag --- .../proctored_exam_add_bulk_allowance_view.js | 2 +- .../js/views/proctored_exam_allowance_view.js | 10 +- .../proctored_exam_add_bulk_allowance_spec.js | 12 +- npm-shrinkwrap.json | 363 ++++++------------ 4 files changed, 124 insertions(+), 263 deletions(-) diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js index dee570d76e7..cdd6daf52c8 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_add_bulk_allowance_view.js @@ -6,7 +6,7 @@ edx = edx || {}; edx.instructor_dashboard = edx.instructor_dashboard || {}; edx.instructor_dashboard.proctoring = edx.instructor_dashboard.proctoring || {}; - edx.instructor_dashboard.proctoring.AddAllowanceView = Backbone.ModalView.extend({ + edx.instructor_dashboard.proctoring.AddBulkAllowanceView = Backbone.ModalView.extend({ name: 'AddBulkAllowanceView', template: null, template_url: '/static/proctoring/templates/add-new-bulk-allowance.underscore', diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js index 7cbb6389a71..f0bcf2a15c4 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js @@ -144,14 +144,14 @@ edx = edx || {}; }, showAddModal: function(event) { var self = this; - var enableBulkAllowanceModal = - self.$el.data('enable-bulk-allowance-modal'); - enableBulkAllowanceModal = enableBulkAllowanceModal && - enableBulkAllowanceModal.toLowerCase() === 'true'; + var enableBulkAllowance = + self.$el.data('enable-bulk-allowance'); + enableBulkAllowance = enableBulkAllowance && + enableBulkAllowance.toLowerCase() === 'true'; self.proctoredExamCollection.fetch({ success: function() { - if (!enableBulkAllowanceModal) { + if (!enableBulkAllowance) { // eslint-disable-next-line no-new new edx.instructor_dashboard.proctoring.AddAllowanceView({ course_id: self.course_id, diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js index a31ddc0dd08..74f15fcf628 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js @@ -1,4 +1,4 @@ -describe('ProctoredExamAddAllowanceView', function() { +describe('ProctoredExamAAllowanceView', function() { 'use strict'; var html = ''; @@ -143,7 +143,7 @@ describe('ProctoredExamAddAllowanceView', function() { this.server = sinon.fakeServer.create(); this.server.autoRespond = true; - setFixtures('
'); + setFixtures('
'); // load the underscore template response before calling the proctored exam allowance view. this.server.respondWith('GET', '/static/proctoring/templates/add-new-allowance.underscore', [ @@ -177,7 +177,7 @@ describe('ProctoredExamAddAllowanceView', function() { ); this.proctored_exam_allowance = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceView(); - addAllowanceView = new edx.instructor_dashboard.proctoring.AddAllowanceView({ + addAllowanceView = new edx.instructor_dashboard.proctoring.AddBulkAllowanceView({ course_id: 'test_course_id', proctored_exams: proctoredExamJson, proctored_exam_allowance_view: this.proctored_exam_allowance, @@ -206,7 +206,7 @@ describe('ProctoredExamAddAllowanceView', function() { ); this.proctored_exam_allowance = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceView(); - addAllowanceView = new edx.instructor_dashboard.proctoring.AddAllowanceView({ + addAllowanceView = new edx.instructor_dashboard.proctoring.AddBulkAllowanceView({ course_id: 'test_course_id', proctored_exams: proctoredExamJson, proctored_exam_allowance_view: this.proctored_exam_allowance, @@ -234,7 +234,7 @@ describe('ProctoredExamAddAllowanceView', function() { this.proctored_exam_allowance = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceView(); // eslint-disable-next-line no-new - new edx.instructor_dashboard.proctoring.AddAllowanceView({ + new edx.instructor_dashboard.proctoring.AddBulkAllowanceView({ course_id: 'test_course_id', proctored_exams: proctoredExamJson, proctored_exam_allowance_view: this.proctored_exam_allowance, @@ -278,7 +278,7 @@ describe('ProctoredExamAddAllowanceView', function() { ); this.proctored_exam_allowance = new edx.instructor_dashboard.proctoring.ProctoredExamAllowanceView(); - addAllowanceView = new edx.instructor_dashboard.proctoring.AddAllowanceView({ + addAllowanceView = new edx.instructor_dashboard.proctoring.AddBulkAllowanceView({ course_id: 'test_course_id', proctored_exams: proctoredExamJson, proctored_exam_allowance_view: this.proctored_exam_allowance, diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index e8d1b56a9c7..8b58cc938cc 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -5,27 +5,27 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", "dev": true, "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.14.5" } }, "@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", "dev": true }, "@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.0", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } @@ -77,12 +77,6 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", @@ -114,9 +108,9 @@ "dev": true }, "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, "active-x-obfuscator": { @@ -351,9 +345,9 @@ "dev": true }, "array-filter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", - "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", "dev": true }, "array-find-index": { @@ -495,13 +489,10 @@ "dev": true }, "available-typed-arrays": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", - "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", - "dev": true, - "requires": { - "array-filter": "^1.0.0" - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz", + "integrity": "sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA==", + "dev": true }, "aws-sign2": { "version": "0.5.0", @@ -737,16 +728,6 @@ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, "bl": { "version": "0.9.5", "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz", @@ -880,12 +861,6 @@ "osenv": "0.0.3" }, "dependencies": { - "graceful-fs": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", - "dev": true - }, "osenv": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.0.3.tgz", @@ -1059,15 +1034,6 @@ } } }, - "graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "requires": { - "natives": "^1.1.3" - } - }, "handlebars": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-2.0.0.tgz", @@ -1247,14 +1213,6 @@ "deep-extend": "~0.2.5", "graceful-fs": "~2.0.0", "intersect": "~0.0.3" - }, - "dependencies": { - "graceful-fs": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", - "dev": true - } } }, "bower-logger": { @@ -1279,12 +1237,6 @@ "rimraf": "~2.2.0" }, "dependencies": { - "graceful-fs": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", - "dev": true - }, "lru-cache": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.3.1.tgz", @@ -1772,9 +1724,9 @@ } }, "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "dev": true, "requires": { "ini": "^1.3.4", @@ -1797,15 +1749,6 @@ "xdg-basedir": "^1.0.0" }, "dependencies": { - "graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "requires": { - "natives": "^1.1.3" - } - }, "object-assign": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", @@ -1845,16 +1788,6 @@ } } }, - "contains-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-1.0.0.tgz", - "integrity": "sha1-NFizMhhWA+ju0Y9RjUoQiIo6vJE=", - "dev": true, - "requires": { - "normalize-path": "^2.1.1", - "path-starts-with": "^1.0.0" - } - }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -1979,9 +1912,9 @@ "dev": true }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -2014,15 +1947,6 @@ "touch": "0.0.2" }, "dependencies": { - "graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "requires": { - "natives": "^1.1.3" - } - }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -2372,9 +2296,9 @@ } }, "engine.io-client": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.5.tgz", - "integrity": "sha512-AYTgHyeVUPitsseqjoedjhYJapNVoSPShbZ+tEUX9/73jgZ/Z3sUlJf9oYgdEBBdVhupUpUqSxH0kBCXlQnmZg==", + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.6.tgz", + "integrity": "sha512-6+rInQu8xU7c0fIF6RC4SRKuHVWPt8Xq0bZYS4lMrTwmhRineOlEMsU3X0zS5mHIvCgJsmpOKEX7DhihGk7j0g==", "dev": true, "requires": { "component-emitter": "1.2.1", @@ -2387,7 +2311,7 @@ "parseqs": "0.0.5", "parseuri": "0.0.5", "ws": "~1.1.5", - "xmlhttprequest-ssl": "1.5.3", + "xmlhttprequest-ssl": "1.6.3", "yeast": "0.1.2" }, "dependencies": { @@ -2454,9 +2378,9 @@ } }, "es-abstract": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", - "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", + "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -2467,14 +2391,14 @@ "has-symbols": "^1.0.2", "is-callable": "^1.2.3", "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.2", - "is-string": "^1.0.5", - "object-inspect": "^1.9.0", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.0" + "unbox-primitive": "^1.0.1" } }, "es-get-iterator": { @@ -3314,14 +3238,13 @@ "dev": true }, "eslint-plugin-import": { - "version": "2.23.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.2.tgz", - "integrity": "sha512-LmNoRptHBxOP+nb0PIKz1y6OSzCJlB+0g0IGS3XV4KaKk2q4szqQ6s6F1utVf5ZRkxk/QOTjdxe7v4VjS99Bsg==", + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", "dev": true, "requires": { "array-includes": "^3.1.3", "array.prototype.flat": "^1.2.4", - "contains-path": "^1.0.0", "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.4", @@ -3387,9 +3310,9 @@ } }, "eslint-plugin-react": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.23.2.tgz", - "integrity": "sha512-AfjgFQB+nYszudkxRkTFu0UR1zEQig0ArVMPloKhxwlwkzaw/fBiH0QWcBBhZONlXqQC51+nfqFrkn4EzHcGBw==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz", + "integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==", "dev": true, "requires": { "array-includes": "^3.1.3", @@ -3398,12 +3321,12 @@ "has": "^1.0.3", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.0.4", - "object.entries": "^1.1.3", + "object.entries": "^1.1.4", "object.fromentries": "^2.0.4", - "object.values": "^1.1.3", + "object.values": "^1.1.4", "prop-types": "^15.7.2", "resolve": "^2.0.0-next.3", - "string.prototype.matchall": "^4.0.4" + "string.prototype.matchall": "^4.0.5" }, "dependencies": { "doctrine": { @@ -3916,9 +3839,9 @@ "dev": true }, "fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz", + "integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==", "dev": true }, "fd-slicer": { @@ -3954,13 +3877,6 @@ "flat-cache": "^2.0.1" } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", @@ -4227,6 +4143,15 @@ "optional": true, "requires": { "nan": "~0.8.0" + }, + "dependencies": { + "nan": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-0.8.0.tgz", + "integrity": "sha1-AiqPpen+hCCWSsH7PclOF/RJ9f0=", + "dev": true, + "optional": true + } } }, "fstream": { @@ -4521,12 +4446,6 @@ "minimatch": "~0.2.11" } }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, "inherits": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", @@ -4709,12 +4628,6 @@ } } }, - "graceful-fs": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", - "dev": true - }, "gulp-util": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-1.2.0.tgz", @@ -4962,9 +4875,9 @@ "dev": true }, "uglify-js": { - "version": "3.13.6", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.6.tgz", - "integrity": "sha512-rRprLwl8RVaS+Qvx3Wh5hPfPBn9++G6xkGlUupya0s5aDmNjI7z3lnRLB3u7sN4OmbB0pWgzhM9BEJyiWAwtAA==", + "version": "3.13.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.10.tgz", + "integrity": "sha512-57H3ACYFXeo1IaZ1w02sfA71wI60MGco/IQFjOqK+WtKoprh7Go2/yvd2HPtoJILO2Or84ncLccI4xoHMTSbGg==", "dev": true, "optional": true }, @@ -5526,9 +5439,9 @@ "dev": true }, "is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", + "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", "dev": true, "requires": { "has": "^1.0.3" @@ -5976,12 +5889,12 @@ "dev": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { - "minimist": "^1.2.0" + "minimist": "^1.2.5" } }, "jsonfile": { @@ -6153,11 +6066,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } + "optional": true }, "http-proxy": { "version": "1.18.1", @@ -6203,13 +6112,6 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", - "dev": true, - "optional": true - }, "object-assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", @@ -7061,18 +6963,18 @@ "dev": true }, "mime-db": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", "dev": true }, "mime-types": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", - "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", "dev": true, "requires": { - "mime-db": "1.47.0" + "mime-db": "1.48.0" } }, "mimic-fn": { @@ -7202,11 +7104,10 @@ "dev": true }, "nan": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-0.8.0.tgz", - "integrity": "sha1-AiqPpen+hCCWSsH7PclOF/RJ9f0=", - "dev": true, - "optional": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-1.0.0.tgz", + "integrity": "sha1-riT4hQgY1mL8q1rPfzuVv6oszzg=", + "dev": true }, "nanomatch": { "version": "1.2.13", @@ -7233,12 +7134,6 @@ "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", "dev": true }, - "natives": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", - "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7432,9 +7327,9 @@ } }, "object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", "dev": true }, "object-is": { @@ -7487,15 +7382,14 @@ } }, "object.entries": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", + "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" + "es-abstract": "^1.18.2" } }, "object.fromentries": { @@ -7551,15 +7445,14 @@ } }, "object.values": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", - "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" + "es-abstract": "^1.18.2" } }, "on-finished": { @@ -7874,9 +7767,9 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-root": { @@ -7894,15 +7787,6 @@ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", "dev": true }, - "path-starts-with": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-starts-with/-/path-starts-with-1.0.0.tgz", - "integrity": "sha1-soJDAV6LE43lcmgqxS2kLmRq2E4=", - "dev": true, - "requires": { - "normalize-path": "^2.1.1" - } - }, "path-to-regexp": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", @@ -8909,14 +8793,6 @@ "array-map": "~0.0.0", "array-reduce": "~0.0.0", "jsonify": "~0.0.0" - }, - "dependencies": { - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", - "dev": true - } } }, "side-channel": { @@ -9270,9 +9146,9 @@ } }, "spdx-license-ids": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.8.tgz", - "integrity": "sha512-NDgA96EnaLSvtbM7trJj+t1LUR3pirkDCcz9nOUlPb5DMBGsH7oES6C3hs3j7R9oHEa1EMvReS/BUAIT5Tcr0g==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", "dev": true }, "split": { @@ -9453,15 +9329,16 @@ } }, "string.prototype.matchall": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", - "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz", + "integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has-symbols": "^1.0.1", + "es-abstract": "^1.18.2", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", "regexp.prototype.flags": "^1.3.1", "side-channel": "^1.0.4" @@ -9841,13 +9718,12 @@ "dev": true }, "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz", + "integrity": "sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==", "dev": true, "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", + "json5": "^2.2.0", "minimist": "^1.2.0", "strip-bom": "^3.0.0" } @@ -10230,15 +10106,6 @@ "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", "dev": true }, - "graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "requires": { - "natives": "^1.1.3" - } - }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -10470,12 +10337,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=", "dev": true - }, - "nan": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-1.0.0.tgz", - "integrity": "sha1-riT4hQgY1mL8q1rPfzuVv6oszzg=", - "dev": true } } }, @@ -10501,9 +10362,9 @@ "dev": true }, "xmlhttprequest-ssl": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", - "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz", + "integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==", "dev": true }, "xtend": { From ed239c29dd40315b638773506fee7009ce92fdf4 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Thu, 15 Jul 2021 16:08:35 -0400 Subject: [PATCH 20/22] Fixed Waffle Flag issues --- edx_proctoring/settings/common.py | 2 ++ .../proctoring/js/views/proctored_exam_allowance_view.js | 1 - .../spec/proctored_exam_add_bulk_allowance_spec.js | 9 +++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/edx_proctoring/settings/common.py b/edx_proctoring/settings/common.py index b04e79fef77..80841654025 100644 --- a/edx_proctoring/settings/common.py +++ b/edx_proctoring/settings/common.py @@ -16,6 +16,7 @@ def plugin_settings(settings): [ 'proctoring/js/models/proctored_exam_allowance_model.js', 'proctoring/js/models/proctored_exam_attempt_model.js', + 'proctoring/js/models/proctored_exam_bulk_allowance_model.js', 'proctoring/js/models/proctored_exam_model.js', 'proctoring/js/models/learner_onboarding_model.js', 'proctoring/js/collections/proctored_exam_allowance_collection.js', @@ -24,6 +25,7 @@ def plugin_settings(settings): '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_add_bulk_allowance_view.js', 'proctoring/js/views/proctored_exam_allowance_view.js', 'proctoring/js/views/proctored_exam_attempt_view.js', 'proctoring/js/views/proctored_exam_onboarding_view.js', diff --git a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js index f0bcf2a15c4..fd53dd045c6 100644 --- a/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js +++ b/edx_proctoring/static/proctoring/js/views/proctored_exam_allowance_view.js @@ -150,7 +150,6 @@ edx = edx || {}; enableBulkAllowance.toLowerCase() === 'true'; self.proctoredExamCollection.fetch({ success: function() { - if (!enableBulkAllowance) { // eslint-disable-next-line no-new new edx.instructor_dashboard.proctoring.AddAllowanceView({ diff --git a/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js b/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js index 74f15fcf628..ab51a804140 100644 --- a/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js +++ b/edx_proctoring/static/proctoring/spec/proctored_exam_add_bulk_allowance_spec.js @@ -143,9 +143,10 @@ describe('ProctoredExamAAllowanceView', function() { this.server = sinon.fakeServer.create(); this.server.autoRespond = true; - setFixtures('
'); + setFixtures('
'); // load the underscore template response before calling the proctored exam allowance view. - this.server.respondWith('GET', '/static/proctoring/templates/add-new-allowance.underscore', + this.server.respondWith('GET', '/static/proctoring/templates/add-new-bulk-allowance.underscore', [ 200, {'Content-Type': 'text/html'}, @@ -255,7 +256,7 @@ describe('ProctoredExamAAllowanceView', function() { .not.toContain('Test Exam'); // add the proctored exam allowance - this.server.respondWith('PUT', '/api/edx_proctoring/v1/proctored_exam/allowance', + this.server.respondWith('PUT', '/api/edx_proctoring/v1/proctored_exam/bulk_allowance', [ 200, { @@ -299,7 +300,7 @@ describe('ProctoredExamAAllowanceView', function() { .not.toContain('Test Exam'); // add the proctored exam allowance - this.server.respondWith('PUT', '/api/edx_proctoring/v1/proctored_exam/allowance', + this.server.respondWith('PUT', '/api/edx_proctoring/v1/proctored_exam/bulk_allowance', [ 400, { From 4941bcf696151401f01936cf5925aa63a255415e Mon Sep 17 00:00:00 2001 From: mohtamba Date: Fri, 16 Jul 2021 08:09:06 -0400 Subject: [PATCH 21/22] Version bump --- CHANGELOG.rst | 5 +++++ edx_proctoring/__init__.py | 2 +- package.json | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 939e004dd83..bcbc44d82ec 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,11 @@ Change Log Unreleased ~~~~~~~~~~ +[3.18.0] - 2021-07-16 +~~~~~~~~~~~~~~~~~~~~~ +* Updated allowance modal to allow bulk allowances to be added. +* Added waffle flag to enable/disable bulk allowances feature. + [3.17.1] - 2021-07-2 ~~~~~~~~~~~~~~~~~~~~~ * Updated ProctoredExamAttempt view to use the content id from the query. diff --git a/edx_proctoring/__init__.py b/edx_proctoring/__init__.py index 6164d7790eb..93aebd9dc21 100644 --- a/edx_proctoring/__init__.py +++ b/edx_proctoring/__init__.py @@ -3,6 +3,6 @@ """ # Be sure to update the version number in edx_proctoring/package.json -__version__ = '3.17.2' +__version__ = '3.18.0' default_app_config = 'edx_proctoring.apps.EdxProctoringConfig' # pylint: disable=invalid-name diff --git a/package.json b/package.json index 4e1e1dfd7c0..49c7acb1d69 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@edx/edx-proctoring", "//": "Note that the version format is slightly different than that of the Python version when using prereleases.", - "version": "3.17.2", + "version": "3.18.0", "main": "edx_proctoring/static/index.js", "scripts": { "test": "gulp test" From e5cf13f27ee1d24f594ebb64d038273bee96e3a2 Mon Sep 17 00:00:00 2001 From: mohtamba Date: Fri, 16 Jul 2021 08:14:05 -0400 Subject: [PATCH 22/22] Version Fix --- edx_proctoring/__init__.py | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/edx_proctoring/__init__.py b/edx_proctoring/__init__.py index 93aebd9dc21..9856164995c 100644 --- a/edx_proctoring/__init__.py +++ b/edx_proctoring/__init__.py @@ -3,6 +3,6 @@ """ # Be sure to update the version number in edx_proctoring/package.json -__version__ = '3.18.0' +__version__ = '3.19.0' default_app_config = 'edx_proctoring.apps.EdxProctoringConfig' # pylint: disable=invalid-name diff --git a/package.json b/package.json index 49c7acb1d69..13a43e08aa8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@edx/edx-proctoring", "//": "Note that the version format is slightly different than that of the Python version when using prereleases.", - "version": "3.18.0", + "version": "3.19.0", "main": "edx_proctoring/static/index.js", "scripts": { "test": "gulp test"