fix: Loosen the restriction on updating exam_type (#30022)

Currently, if a subsection was a special exam, we do not allow it to be changed back as a special exam. This PR would loosen that change to only disallow reintroducing the exam back to proctored exam. Timed exam can be updated however the user wants

Co-authored-by: Simon Chen <schen@edX-C02FW0GUML85.local>
This commit is contained in:
Simon Chen
2022-03-08 13:00:59 -05:00
committed by GitHub
parent b4bd552365
commit 0940fc5e49
4 changed files with 33 additions and 25 deletions

View File

@@ -1308,7 +1308,7 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
xblock_info.update({
'is_proctored_exam': xblock.is_proctored_exam,
'was_ever_special_exam': _was_xblock_ever_special_exam(
'was_ever_proctored_exam': _was_xblock_ever_proctored_exam(
course, xblock
),
'online_proctoring_rules': rules_url,
@@ -1364,13 +1364,14 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
return xblock_info
def _was_xblock_ever_special_exam(course, xblock):
def _was_xblock_ever_proctored_exam(course, xblock):
"""
Determine whether this XBlock is or was ever configured as a special exam.
Determine whether this XBlock is or was ever configured as a proctored exam.
If this block is *not* currently a special exam, the best way for us to tell
whether it was was *ever* configured as a special exam is by checking whether
edx-proctoring has an exam record associated with the block's ID.
If this block is *not* currently a proctored exam, the best way for us to tell
whether it was was *ever* configured as a proctored exam is by checking whether
edx-proctoring has an exam record associated with the block's ID,
and the exam record is proctored.
If an exception is not raised, then we know that such a record exists,
indicating that this *was* once a special exam.
@@ -1380,14 +1381,13 @@ def _was_xblock_ever_special_exam(course, xblock):
Returns: bool
"""
if xblock.is_time_limited:
if xblock.is_proctored_enabled:
return True
try:
get_exam_by_content_id(course.id, xblock.location)
exam = get_exam_by_content_id(course.id, xblock.location)
return 'is_proctored' in exam and exam['is_proctored']
except ProctoredExamNotFoundException:
return False
else:
return True
def add_container_page_publishing_info(xblock, xblock_info):

View File

@@ -2843,6 +2843,7 @@ class TestXBlockInfo(ItemTest):
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_SPECIAL_EXAMS': True})
@ddt.ddt
class TestSpecialExamXBlockInfo(ItemTest):
"""
Unit tests for XBlock outline handling, specific to special exam XBlocks.
@@ -2854,7 +2855,7 @@ class TestSpecialExamXBlockInfo(ItemTest):
item_module, 'does_backend_support_onboarding', return_value=True
)
patch_get_exam_by_content_id_success = patch.object(
item_module, 'get_exam_by_content_id'
item_module, 'get_exam_by_content_id', return_value={'is_proctored': True}
)
patch_get_exam_by_content_id_not_found = patch.object(
item_module, 'get_exam_by_content_id', side_effect=ProctoredExamNotFoundException
@@ -2908,7 +2909,7 @@ class TestSpecialExamXBlockInfo(ItemTest):
)
# exam proctoring should be enabled and time limited.
assert xblock_info['is_proctored_exam'] is True
assert xblock_info['was_ever_special_exam'] is True
assert xblock_info['was_ever_proctored_exam'] is True
assert xblock_info['is_time_limited'] is True
assert xblock_info['default_time_limit_minutes'] == 100
assert xblock_info['proctoring_exam_configuration_link'] == 'test_url'
@@ -2920,8 +2921,15 @@ class TestSpecialExamXBlockInfo(ItemTest):
@patch_get_exam_configuration_dashboard_url
@patch_does_backend_support_onboarding
@patch_get_exam_by_content_id_success
def test_xblock_was_ever_special_exam(
@ddt.data(
(True, True),
(False, False),
)
@ddt.unpack
def test_xblock_was_ever_proctored_exam(
self,
is_proctored,
expected_value,
mock_get_exam_by_content_id,
_mock_does_backend_support_onboarding_patch,
_mock_get_exam_configuration_dashboard_url,
@@ -2935,13 +2943,14 @@ class TestSpecialExamXBlockInfo(ItemTest):
is_time_limited=False,
is_onboarding_exam=False,
)
mock_get_exam_by_content_id.return_value = {'is_proctored': is_proctored}
sequential = modulestore().get_item(sequential.location)
xblock_info = create_xblock_info(
sequential,
include_child_info=True,
include_children_predicate=ALWAYS,
)
assert xblock_info['was_ever_special_exam'] is True
assert xblock_info['was_ever_proctored_exam'] is expected_value
assert mock_get_exam_by_content_id.call_count == 1
@patch_get_exam_configuration_dashboard_url
@@ -2968,7 +2977,7 @@ class TestSpecialExamXBlockInfo(ItemTest):
include_child_info=True,
include_children_predicate=ALWAYS,
)
assert xblock_info['was_ever_special_exam'] is False
assert xblock_info['was_ever_proctored_exam'] is False
assert mock_get_exam_by_content_id.call_count == 1

View File

@@ -325,8 +325,8 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
isTimedExam: isTimeLimited && !(
isProctoredExam || isPracticeExam || isOnboardingExam
),
specialExamLockedIn: (
xblockInfo.get('released_to_students') && xblockInfo.get('was_ever_special_exam')
proctoredExamLockedIn: (
xblockInfo.get('released_to_students') && xblockInfo.get('was_ever_proctored_exam')
)
}, this.getContext()));

View File

@@ -2,19 +2,19 @@
<h3 class="modal-section-title"><%- gettext('Set as a Special Exam') %></h3>
<div class="modal-section-content has-actions">
<div class="list-fields list-input exam-types" role="group" aria-label="<%- gettext('Exam Types') %>">
<% if (specialExamLockedIn && !isSpecialExam) { %>
<% if (proctoredExamLockedIn && !isProctoredExam) { %>
<div class="summary-message summary-message-warning">
<span class="icon fa fa-exclamation-triangle" aria-hidden="true"></span>
<p class="copy">
<%- gettext("This subsection was released to learners as a special exam, but was reverted back to a basic exam. You may not configure it as a special exam now. Contact edX Support for assistance.") %>
<%- gettext("This subsection was released to learners as a proctored exam, but was reverted back to a basic or timed exam. You may not configure it as a proctored exam now. Contact edX Support for assistance.") %>
</p>
</div>
<% } %>
<% if (specialExamLockedIn && isSpecialExam) { %>
<% if (proctoredExamLockedIn && isProctoredExam) { %>
<div class="summary-message summary-message-warning">
<span class="icon fa fa-exclamation-triangle" aria-hidden="true"></span>
<p class="copy">
<%- gettext("This special exam has been released to learners. You may not convert it to another type of special exam. You may revert this subsection back to being a basic exam by selecting 'None', but you will NOT be able to configure it as a special exam in the future.") %>
<%- gettext("This proctored exam has been released to learners. You may not convert it to another type of special exam. You may revert this subsection back to being a basic exam by selecting 'None', or a timed exam, but you will NOT be able to configure it as a proctored exam in the future.") %>
</p>
</div>
<% } %>
@@ -25,7 +25,6 @@
<label class="label">
<input type="radio" name="exam_type" class="input input-radio timed_exam"
aria-describedby="timed-exam-description"
<%- specialExamLockedIn && !isTimedExam ? 'disabled' : '' %>
/>
<%- gettext('Timed') %>
</label>
@@ -34,7 +33,7 @@
<label class="label">
<input type="radio" name="exam_type" class="input input-radio proctored_exam"
aria-describedby="proctored-exam-description"
<%- specialExamLockedIn && (!isProctoredExam || isOnboardingExam) ? 'disabled' : '' %>
<%- proctoredExamLockedIn && (!isProctoredExam || isOnboardingExam) ? 'disabled' : '' %>
/>
<%- gettext('Proctored') %>
</label>
@@ -45,7 +44,7 @@
<label class="label">
<input type="radio" name="exam_type" class="input input-radio onboarding_exam"
aria-describedby="onboarding-exam-description"
<%- specialExamLockedIn && !isOnboardingExam ? 'disabled' : '' %>
<%- proctoredExamLockedIn && !isOnboardingExam ? 'disabled' : '' %>
/>
<%- gettext('Onboarding') %>
</label>
@@ -54,7 +53,7 @@
<label class="label">
<input type="radio" name="exam_type" class="input input-radio practice_exam"
aria-describedby="practice-exam-description"
<%- specialExamLockedIn && !isPracticeExam ? 'disabled' : '' %>
<%- proctoredExamLockedIn && !isPracticeExam ? 'disabled' : '' %>
/>
<%- gettext('Practice Proctored') %>
</label>