diff --git a/cms/djangoapps/contentstore/proctoring.py b/cms/djangoapps/contentstore/proctoring.py index d8dc235ec1..b5bc115b10 100644 --- a/cms/djangoapps/contentstore/proctoring.py +++ b/cms/djangoapps/contentstore/proctoring.py @@ -76,7 +76,8 @@ def register_special_exams(course_key): 'time_limit_mins': timed_exam.default_time_limit_minutes, 'due_date': timed_exam.due, 'is_proctored': timed_exam.is_proctored_exam, - 'is_practice_exam': timed_exam.is_practice_exam, + # backends that support onboarding exams will treat onboarding exams as practice + 'is_practice_exam': timed_exam.is_practice_exam or timed_exam.is_onboarding_exam, 'is_active': True, 'hide_after_due': timed_exam.hide_after_due, 'backend': course.proctoring_provider, @@ -106,7 +107,7 @@ def register_special_exams(course_key): } # only create/update exam policy for the proctored exams - if timed_exam.is_proctored_exam and not timed_exam.is_practice_exam: + if timed_exam.is_proctored_exam and not timed_exam.is_practice_exam and not timed_exam.is_onboarding_exam: try: update_review_policy(**exam_review_policy_metadata) except ProctoredExamReviewPolicyNotFoundException: diff --git a/cms/djangoapps/contentstore/tests/test_proctoring.py b/cms/djangoapps/contentstore/tests/test_proctoring.py index f273517c45..ef2ad670c4 100644 --- a/cms/djangoapps/contentstore/tests/test_proctoring.py +++ b/cms/djangoapps/contentstore/tests/test_proctoring.py @@ -61,10 +61,43 @@ class TestProctoredExams(ModuleStoreTestCase): self.assertEqual(exam['exam_name'], sequence.display_name) self.assertEqual(exam['time_limit_mins'], sequence.default_time_limit_minutes) self.assertEqual(exam['is_proctored'], sequence.is_proctored_exam) - self.assertEqual(exam['is_practice_exam'], sequence.is_practice_exam) + self.assertEqual(exam['is_practice_exam'], sequence.is_practice_exam or sequence.is_onboarding_exam) self.assertEqual(exam['is_active'], expected_active) self.assertEqual(exam['backend'], self.course.proctoring_provider) + @ddt.data( + (False, True), + (True, False), + ) + @ddt.unpack + def test_onboarding_exam_is_practice_exam(self, is_practice_exam, is_onboarding_exam): + """ + Check that an onboarding exam is treated as a practice exam when + communicating with the edx-proctoring subsystem. + """ + default_time_limit_minutes = 10 + is_proctored_exam = True + + chapter = ItemFactory.create(parent=self.course, category='chapter', display_name='Test Section') + sequence = ItemFactory.create( + parent=chapter, + category='sequential', + display_name='Test Proctored Exam', + graded=True, + is_time_limited=True, + default_time_limit_minutes=default_time_limit_minutes, + is_proctored_exam=is_proctored_exam, + is_practice_exam=is_practice_exam, + due=datetime.now(UTC) + timedelta(minutes=default_time_limit_minutes + 1), + exam_review_rules="allow_use_of_paper", + hide_after_due=True, + is_onboarding_exam=is_onboarding_exam, + ) + + listen_for_course_publish(self, self.course.id) + + self._verify_exam_data(sequence, True) + @ddt.data( (True, False, True, False, False), (False, False, True, False, False), @@ -93,6 +126,7 @@ class TestProctoredExams(ModuleStoreTestCase): due=datetime.now(UTC) + timedelta(minutes=default_time_limit_minutes + 1), exam_review_rules="allow_use_of_paper", hide_after_due=hide_after_due, + is_onboarding_exam=False, ) listen_for_course_publish(self, self.course.id) @@ -125,6 +159,7 @@ class TestProctoredExams(ModuleStoreTestCase): default_time_limit_minutes=10, is_proctored_exam=True, hide_after_due=False, + is_onboarding_exam=False, ) listen_for_course_publish(self, self.course.id) diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py index 4e43966fa0..88d2a030c7 100644 --- a/cms/djangoapps/contentstore/views/item.py +++ b/cms/djangoapps/contentstore/views/item.py @@ -68,7 +68,7 @@ from xmodule.modulestore.inheritance import own_metadata from xmodule.services import ConfigurationService, SettingsService from xmodule.tabs import CourseTabList from xmodule.x_module import DEPRECATION_VSCOMPAT_EVENT, PREVIEW_VIEWS, STUDENT_VIEW, STUDIO_VIEW -from edx_proctoring.api import get_exam_configuration_dashboard_url +from edx_proctoring.api import get_exam_configuration_dashboard_url, does_backend_support_onboarding __all__ = [ 'orphan_handler', 'xblock_handler', 'xblock_view_handler', 'xblock_outline_handler', 'xblock_container_handler' @@ -1222,6 +1222,7 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F }) elif xblock.category == 'sequential': rules_url = settings.PROCTORING_SETTINGS.get('LINK_URLS', {}).get('online_proctoring_rules', "") + supports_onboarding = does_backend_support_onboarding(course.proctoring_provider) proctoring_exam_configuration_link = None if xblock.is_proctored_exam: @@ -1232,10 +1233,12 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F 'is_proctored_exam': xblock.is_proctored_exam, 'online_proctoring_rules': rules_url, 'is_practice_exam': xblock.is_practice_exam, + 'is_onboarding_exam': xblock.is_onboarding_exam, 'is_time_limited': xblock.is_time_limited, 'exam_review_rules': xblock.exam_review_rules, 'default_time_limit_minutes': xblock.default_time_limit_minutes, 'proctoring_exam_configuration_link': proctoring_exam_configuration_link, + 'supports_onboarding': supports_onboarding, }) # Update with gating info diff --git a/cms/djangoapps/contentstore/views/tests/test_item.py b/cms/djangoapps/contentstore/views/tests/test_item.py index 70e9d91742..5bc8d82cac 100644 --- a/cms/djangoapps/contentstore/views/tests/test_item.py +++ b/cms/djangoapps/contentstore/views/tests/test_item.py @@ -2786,8 +2786,10 @@ class TestXBlockInfo(ItemTest): self.assertIsNone(xblock_info.get('child_info', None)) @patch.dict('django.conf.settings.FEATURES', {'ENABLE_SPECIAL_EXAMS': True}) + @patch('contentstore.views.item.does_backend_support_onboarding') @patch('contentstore.views.item.get_exam_configuration_dashboard_url') - def test_proctored_exam_xblock_info(self, get_exam_configuration_dashboard_url_patch): + def test_proctored_exam_xblock_info(self, get_exam_configuration_dashboard_url_patch, + does_backend_support_onboarding_patch): self.course.enable_proctored_exams = True self.course.save() self.store.update_item(self.course, self.user.id) @@ -2805,11 +2807,12 @@ class TestXBlockInfo(ItemTest): parent_location=self.chapter.location, category='sequential', display_name="Test Lesson 1", user_id=self.user.id, is_proctored_exam=True, is_time_limited=True, - default_time_limit_minutes=100 + default_time_limit_minutes=100, is_onboarding_exam=False ) sequential = modulestore().get_item(sequential.location) get_exam_configuration_dashboard_url_patch.return_value = 'test_url' + does_backend_support_onboarding_patch.return_value = True xblock_info = create_xblock_info( sequential, include_child_info=True, @@ -2820,6 +2823,8 @@ class TestXBlockInfo(ItemTest): self.assertEqual(xblock_info['is_time_limited'], True) self.assertEqual(xblock_info['default_time_limit_minutes'], 100) self.assertEqual(xblock_info['proctoring_exam_configuration_link'], 'test_url') + self.assertEqual(xblock_info['supports_onboarding'], True) + self.assertEqual(xblock_info['is_onboarding_exam'], False) get_exam_configuration_dashboard_url_patch.assert_called_with(self.course.id, xblock_info['id']) diff --git a/cms/djangoapps/models/settings/course_metadata.py b/cms/djangoapps/models/settings/course_metadata.py index 79a78b14e3..5c77a702f6 100644 --- a/cms/djangoapps/models/settings/course_metadata.py +++ b/cms/djangoapps/models/settings/course_metadata.py @@ -65,6 +65,7 @@ class CourseMetadata(object): 'chrome', 'default_tab', 'highlights_enabled_for_messaging', + 'is_onboarding_exam', ] @classmethod diff --git a/cms/static/js/spec/views/pages/course_outline_spec.js b/cms/static/js/spec/views/pages/course_outline_spec.js index dc5fec49db..a3965bef17 100644 --- a/cms/static/js/spec/views/pages/course_outline_spec.js +++ b/cms/static/js/spec/views/pages/course_outline_spec.js @@ -14,6 +14,7 @@ describe('CourseOutlinePage', function() { selectVisibilitySettings, selectAdvancedSettings, createMockCourseJSON, createMockSectionJSON, createMockSubsectionJSON, verifyTypePublishable, mockCourseJSON, mockEmptyCourseJSON, setSelfPaced, mockSingleSectionCourseJSON, createMockVerticalJSON, createMockIndexJSON, mockCourseEntranceExamJSON, + selectOnboardingExam, mockOutlinePage = readFixtures('templates/mock/mock-course-outline-page.underscore'), mockRerunNotification = readFixtures('templates/mock/mock-course-rerun-notification.underscore'); @@ -1025,6 +1026,12 @@ describe('CourseOutlinePage', function() { $('.field-time-limit input').trigger('focusout'); }; + selectOnboardingExam = function(time_limit) { + $('input.onboarding_exam').prop('checked', true).trigger('change'); + $('.field-time-limit input').val(time_limit); + $('.field-time-limit input').trigger('focusout'); + }; + selectPrerequisite = function() { $('#is_prereq').prop('checked', true).trigger('change'); }; @@ -1070,7 +1077,8 @@ describe('CourseOutlinePage', function() { is_time_limited: false, exam_review_rules: '', is_proctored_enabled: false, - default_time_limit_minutes: null + default_time_limit_minutes: null, + is_onboarding_exam: false } }; @@ -1274,7 +1282,8 @@ describe('CourseOutlinePage', function() { is_practice_exam: false, is_proctored_enabled: false, default_time_limit_minutes: 150, - hide_after_due: true + hide_after_due: true, + is_onboarding_exam: false, } }); expect(requests[0].requestHeaders['X-HTTP-Method-Override']).toBe('PATCH'); @@ -1339,6 +1348,96 @@ describe('CourseOutlinePage', function() { $('.wrapper-modal-window .action-save').click(); }); + it('can select the onboarding exam when a course supports onboarding', function () { + var mockCourseWithSpecialExamJSON = createMockCourseJSON({}, [ + createMockSectionJSON({ + has_changes: true, + enable_proctored_exams: true, + enable_timed_exams: true + + }, [ + createMockSubsectionJSON({ + has_changes: true, + is_time_limited: true, + is_practice_exam: true, + is_proctored_exam: true, + default_time_limit_minutes: 150, + supports_onboarding: true, + }, [ + ]) + ]) + ]); + + createCourseOutlinePage(this, mockCourseWithSpecialExamJSON, false); + outlinePage.$('.outline-subsection .configure-button').click(); + setEditModalValues('7/9/2014', '7/10/2014', 'Lab'); + selectVisibilitySettings(); + setContentVisibility('staff_only'); + selectAdvancedSettings(); + selectOnboardingExam('00:30'); + + // time limit should be visible, review rules should be hidden + checkOptionFieldVisibility(true, false); + + $('.wrapper-modal-window .action-save').click(); + }); + + it('does not show practice exam option when course supports onboarding', function() { + var mockCourseWithSpecialExamJSON = createMockCourseJSON({}, [ + createMockSectionJSON({ + has_changes: true, + enable_proctored_exams: true, + enable_timed_exams: true + + }, [ + createMockSubsectionJSON({ + has_changes: true, + is_time_limited: true, + is_practice_exam: true, + is_proctored_exam: true, + default_time_limit_minutes: 150, + supports_onboarding: true, + }, [ + ]) + ]) + ]); + + createCourseOutlinePage(this, mockCourseWithSpecialExamJSON, false); + outlinePage.$('.outline-subsection .configure-button').click(); + selectAdvancedSettings(); + expect($('input.practice_exam')).not.toExist(); + expect($('input.onboarding_exam')).toExist(); + expect($('.field-time-limit input').val()).toBe('02:30'); + }); + + it('does not show onboarding exam option when course does not support onboarding', function() { + var mockCourseWithSpecialExamJSON = createMockCourseJSON({}, [ + createMockSectionJSON({ + has_changes: true, + enable_proctored_exams: true, + enable_timed_exams: true + + }, [ + createMockSubsectionJSON({ + has_changes: true, + is_time_limited: true, + is_practice_exam: true, + is_proctored_exam: true, + default_time_limit_minutes: 150, + supports_onboarding: false, + }, [ + ]) + ]) + ]); + + createCourseOutlinePage(this, mockCourseWithSpecialExamJSON, false); + outlinePage.$('.outline-subsection .configure-button').click(); + selectAdvancedSettings(); + expect($('input.practice_exam')).toExist(); + expect($('input.onboarding_exam')).not.toExist(); + expect($('.field-time-limit input').val()).toBe('02:30'); + }); + it('can select the timed exam', function() { createCourseOutlinePage(this, mockCourseJSON, false); outlinePage.$('.outline-subsection .configure-button').click(); @@ -1525,6 +1624,36 @@ describe('CourseOutlinePage', function() { expect($('.field-time-limit input').val()).toBe('02:30'); }); + it('can show a saved onboarding exam correctly', function() { + var mockCourseWithSpecialExamJSON = createMockCourseJSON({}, [ + createMockSectionJSON({ + has_changes: true, + enable_proctored_exams: true, + enable_timed_exams: true + + }, [ + createMockSubsectionJSON({ + has_changes: true, + is_time_limited: true, + is_practice_exam: false, + is_proctored_exam: true, + default_time_limit_minutes: 150, + supports_onboarding: true, + is_onboarding_exam: true + }, [ + ]) + ]) + ]); + createCourseOutlinePage(this, mockCourseWithSpecialExamJSON, false); + outlinePage.$('.outline-subsection .configure-button').click(); + selectAdvancedSettings(); + expect($('input.timed_exam').is(':checked')).toBe(false); + expect($('input.proctored_exam').is(':checked')).toBe(false); + expect($('input.no_special_exam').is(':checked')).toBe(false); + expect($('input.onboarding_exam').is(':checked')).toBe(true); + expect($('.field-time-limit input').val()).toBe('02:30'); + }); + it('does not show proctored settings if proctored exams not enabled', function() { var mockCourseWithSpecialExamJSON = createMockCourseJSON({}, [ createMockSectionJSON({ diff --git a/cms/static/js/views/modals/course_outline_modals.js b/cms/static/js/views/modals/course_outline_modals.js index 6bff80e977..1d95a8e294 100644 --- a/cms/static/js/views/modals/course_outline_modals.js +++ b/cms/static/js/views/modals/course_outline_modals.js @@ -70,8 +70,10 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', }, save: function(event) { + var requestData; + event.preventDefault(); - var requestData = this.getRequestData(); + requestData = this.getRequestData(); if (!_.isEqual(requestData, {metadata: {}})) { XBlockViewUtils.updateXBlockFields(this.model, requestData, { success: this.options.onSave @@ -122,10 +124,11 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', }, initializeEditors: function() { + var tabsTemplate; var tabs = this.options.tabs; if (tabs && tabs.length > 0) { if (tabs.length > 1) { - var tabsTemplate = this.loadTemplate('settings-modal-tabs'); + tabsTemplate = this.loadTemplate('settings-modal-tabs'); HtmlUtils.setHtml(this.$('.modal-section'), HtmlUtils.HTML(tabsTemplate({tabs: tabs}))); _.each(this.options.tabs, function(tab) { this.options.editors.push.apply( @@ -411,9 +414,10 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', className: 'edit-settings-timed-examination', events: { 'change input.no_special_exam': 'notTimedExam', - 'change input.timed_exam': 'setTimedExam', - 'change input.practice_exam': 'setPracticeExam', + 'change input.timed_exam': 'setSpecialExamWithoutRules', + 'change input.practice_exam': 'setSpecialExamWithoutRules', 'change input.proctored_exam': 'setProctoredExam', + 'change input.onboarding_exam': 'setSpecialExamWithoutRules', 'focusout .field-time-limit input': 'timeLimitFocusout' }, notTimedExam: function(event) { @@ -433,11 +437,7 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', this.$('.field-exam-review-rules').hide(); } }, - setTimedExam: function(event) { - event.preventDefault(); - this.selectSpecialExam(false); - }, - setPracticeExam: function(event) { + setSpecialExamWithoutRules: function(event) { event.preventDefault(); this.selectSpecialExam(false); }, @@ -446,8 +446,10 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', this.selectSpecialExam(true); }, timeLimitFocusout: function(event) { + var selectedTimeLimit; + event.preventDefault(); - var selectedTimeLimit = $(event.currentTarget).val(); + selectedTimeLimit = $(event.currentTarget).val(); if (!this.isValidTimeLimit(selectedTimeLimit)) { $(event.currentTarget).val('00:30'); } @@ -462,24 +464,26 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', }); this.setExamType(this.model.get('is_time_limited'), this.model.get('is_proctored_exam'), - this.model.get('is_practice_exam')); + this.model.get('is_practice_exam'), this.model.get('is_onboarding_exam')); this.setExamTime(this.model.get('default_time_limit_minutes')); this.setReviewRules(this.model.get('exam_review_rules')); }, - setExamType: function(is_time_limited, is_proctored_exam, is_practice_exam) { + setExamType: function(isTimeLimited, isProctoredExam, isPracticeExam, isOnboardingExam) { this.$('.field-time-limit').hide(); this.$('.field-exam-review-rules').hide(); - if (!is_time_limited) { + if (!isTimeLimited) { this.$('input.no_special_exam').prop('checked', true); return; } this.$('.field-time-limit').show(); - if (this.options.enable_proctored_exams && is_proctored_exam) { - if (is_practice_exam) { + if (this.options.enable_proctored_exams && isProctoredExam) { + if (isOnboardingExam) { + this.$('input.onboarding_exam').prop('checked', true); + } else if (isPracticeExam) { this.$('input.practice_exam').prop('checked', true); } else { this.$('input.proctored_exam').prop('checked', true); @@ -499,9 +503,9 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', setReviewRules: function(value) { this.$('.field-exam-review-rules textarea').val(value); }, - isValidTimeLimit: function(time_limit) { + isValidTimeLimit: function(timeLimit) { var pattern = new RegExp('^\\d{1,2}:[0-5][0-9]$'); - return pattern.test(time_limit) && time_limit !== '00:00'; + return pattern.test(timeLimit) && timeLimit !== '00:00'; }, getExamTimeLimit: function() { return this.$('.field-time-limit input').val(); @@ -513,48 +517,32 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', actualMinutesStr = '00'.substring(0, 2 - actualMinutesStr.length) + actualMinutesStr; return hoursStr + ':' + actualMinutesStr; }, - convertTimeLimitToMinutes: function(time_limit) { - var time = time_limit.split(':'); - var total_time = (parseInt(time[0]) * 60) + parseInt(time[1]); - return total_time; + convertTimeLimitToMinutes: function(timeLimit) { + var time = timeLimit.split(':'); + var totalTime = (parseInt(time[0], 10) * 60) + parseInt(time[1], 10); + return totalTime; }, getRequestData: function() { - var is_time_limited; - var is_practice_exam; - var is_proctored_exam; - var time_limit = this.getExamTimeLimit(); - var exam_review_rules = this.$('.field-exam-review-rules textarea').val(); - - if (this.$('input.no_special_exam').is(':checked')) { - is_time_limited = false; - is_practice_exam = false; - is_proctored_exam = false; - } else if (this.$('input.timed_exam').is(':checked')) { - is_time_limited = true; - is_practice_exam = false; - is_proctored_exam = false; - } else if (this.$('input.proctored_exam').is(':checked')) { - is_time_limited = true; - is_practice_exam = false; - is_proctored_exam = true; - } else if (this.$('input.practice_exam').is(':checked')) { - is_time_limited = true; - is_practice_exam = true; - is_proctored_exam = true; - } + var isNoSpecialExamChecked = this.$('input.no_special_exam').is(':checked'); + var isProctoredExamChecked = this.$('input.proctored_exam').is(':checked'); + var isPracticeExamChecked = this.$('input.practice_exam').is(':checked'); + var isOnboardingExamChecked = this.$('input.onboarding_exam').is(':checked'); + var timeLimit = this.getExamTimeLimit(); + var examReviewRules = this.$('.field-exam-review-rules textarea').val(); return { metadata: { - is_practice_exam: is_practice_exam, - is_time_limited: is_time_limited, - exam_review_rules: exam_review_rules, + is_practice_exam: isPracticeExamChecked, + is_time_limited: !isNoSpecialExamChecked, + exam_review_rules: examReviewRules, // We have to use the legacy field name // as the Ajax handler directly populates // the xBlocks fields. We will have to // update this call site when we migrate // seq_module.py to use 'is_proctored_exam' - is_proctored_enabled: is_proctored_exam, - default_time_limit_minutes: this.convertTimeLimitToMinutes(time_limit) + is_proctored_enabled: isProctoredExamChecked || isPracticeExamChecked || isOnboardingExamChecked, + default_time_limit_minutes: this.convertTimeLimitToMinutes(timeLimit), + is_onboarding_exam: isOnboardingExamChecked } }; } @@ -569,10 +557,12 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', 'keyup #prereq_min_score': 'validateScoreAndCompletion' }, afterRender: function() { + var prereq, prereqMinScore, prereqMinCompletion; + AbstractEditor.prototype.afterRender.call(this); - var prereq = this.model.get('prereq') || ''; - var prereqMinScore = this.model.get('prereq_min_score') || '100'; - var prereqMinCompletion = this.model.get('prereq_min_completion') || '100'; + prereq = this.model.get('prereq') || ''; + prereqMinScore = this.model.get('prereq_min_score') || '100'; + prereqMinCompletion = this.model.get('prereq_min_completion') || '100'; this.$('#is_prereq').prop('checked', this.model.get('is_prereq')); this.$('#prereq option[value="' + prereq + '"]').prop('selected', true); this.$('#prereq_min_score').val(prereqMinScore); @@ -853,9 +843,9 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', }, toggleUnlockWarning: function() { + var display; var warning = this.$('.staff-lock .tip-warning'); if (warning) { - var display; if (this.currentVisibility() !== 'staff_only') { display = 'block'; } else { @@ -868,8 +858,10 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview', }, getRequestData: function() { + var metadata; + if (this.hasChanges()) { - var metadata = {}; + metadata = {}; if (this.currentVisibility() === 'staff_only') { metadata.visible_to_staff_only = true; metadata.hide_after_due = null; diff --git a/cms/templates/js/course-outline.underscore b/cms/templates/js/course-outline.underscore index b201328c9a..20c3149ddb 100644 --- a/cms/templates/js/course-outline.underscore +++ b/cms/templates/js/course-outline.underscore @@ -84,15 +84,19 @@ if (xblockInfo.get('graded')) { var is_proctored_exam = xblockInfo.get('is_proctored_exam'); var is_practice_exam = xblockInfo.get('is_practice_exam'); +var is_onboarding_exam = xblockInfo.get('is_onboarding_exam'); +var exam_value; if (is_proctored_exam) { - if (is_practice_exam) { - var exam_value = gettext('Practice proctored Exam'); + if (is_onboarding_exam) { + exam_value = gettext('Onboarding Exam'); + } else if (is_practice_exam) { + exam_value = gettext('Practice proctored Exam'); } else { - var exam_value = gettext('Proctored Exam'); + exam_value = gettext('Proctored Exam'); } } else { - var exam_value = gettext('Timed Exam'); + exam_value = gettext('Timed Exam'); } %> <% if (parentInfo) { %> diff --git a/cms/templates/js/timed-examination-preference-editor.underscore b/cms/templates/js/timed-examination-preference-editor.underscore index 8853fce368..92f0838de6 100644 --- a/cms/templates/js/timed-examination-preference-editor.underscore +++ b/cms/templates/js/timed-examination-preference-editor.underscore @@ -19,12 +19,23 @@ <%- gettext('Proctored') %>
- - + + <% var supports_onboarding = xblockInfo.get('supports_onboarding'); %> + <% if (supports_onboarding) { %> + + + <% } else { %> + + + <% } %> <% } %>