AA-261: Overridding Show Answer functionality for PLS courses

We noticed that since users can choose to reset their due dates,
they would have the ability to let due dates pass and then for any
assessment that allows viewing the answer after the due date would be
visible. The user could thus view all answers and then reset their
due dates to receive a perfect score.

This PR works to fix that issue by changing all show answer values
to not take into account being past the due date when inside a PLS
course.
This commit is contained in:
Dillon Dumesnil
2020-07-28 13:56:08 -07:00
parent 3d1148b874
commit 75f6937003
8 changed files with 149 additions and 5 deletions

View File

@@ -64,6 +64,9 @@ class SHOWANSWER(object):
PAST_DUE = "past_due"
NEVER = "never"
AFTER_SOME_NUMBER_OF_ATTEMPTS = "after_attempts"
AFTER_ALL_ATTEMPTS = "after_all_attempts"
AFTER_ALL_ATTEMPTS_OR_CORRECT = "after_all_attempts_or_correct"
ATTEMPTED_NO_PAST_DUE = "attempted_no_past_due"
class RANDOMIZATION(object):
@@ -167,13 +170,16 @@ class CapaFields(object):
values=[
{"display_name": _("Always"), "value": SHOWANSWER.ALWAYS},
{"display_name": _("Answered"), "value": SHOWANSWER.ANSWERED},
{"display_name": _("Attempted"), "value": SHOWANSWER.ATTEMPTED},
{"display_name": _("Attempted or Past Due"), "value": SHOWANSWER.ATTEMPTED},
{"display_name": _("Closed"), "value": SHOWANSWER.CLOSED},
{"display_name": _("Finished"), "value": SHOWANSWER.FINISHED},
{"display_name": _("Correct or Past Due"), "value": SHOWANSWER.CORRECT_OR_PAST_DUE},
{"display_name": _("Past Due"), "value": SHOWANSWER.PAST_DUE},
{"display_name": _("Never"), "value": SHOWANSWER.NEVER},
{"display_name": _("After Some Number of Attempts"), "value": SHOWANSWER.AFTER_SOME_NUMBER_OF_ATTEMPTS},
{"display_name": _("After All Attempts"), "value": SHOWANSWER.AFTER_ALL_ATTEMPTS},
{"display_name": _("After All Attempts or Correct"), "value": SHOWANSWER.AFTER_ALL_ATTEMPTS_OR_CORRECT},
{"display_name": _("Attempted"), "value": SHOWANSWER.ATTEMPTED_NO_PAST_DUE},
]
)
attempts_before_showanswer_button = Integer(
@@ -877,6 +883,10 @@ class CapaMixin(ScorableXBlockMixin, CapaFields):
hint_index = int(data['hint_index'])
return self.get_demand_hint(hint_index)
def used_all_attempts(self):
""" All attempts have been used """
return self.max_attempts is not None and self.attempts >= self.max_attempts
def is_past_due(self):
"""
Is it now past this problem's due date, including grace period?
@@ -888,7 +898,7 @@ class CapaMixin(ScorableXBlockMixin, CapaFields):
"""
Is the student still allowed to submit answers?
"""
if self.max_attempts is not None and self.attempts >= self.max_attempts:
if self.used_all_attempts():
return True
if self.is_past_due():
return True
@@ -936,7 +946,7 @@ class CapaMixin(ScorableXBlockMixin, CapaFields):
# unless the problem explicitly prevents it
return True
elif self.showanswer == SHOWANSWER.ATTEMPTED:
return self.attempts > 0 or self.is_past_due()
return self.is_attempted() or self.is_past_due()
elif self.showanswer == SHOWANSWER.ANSWERED:
# NOTE: this is slightly different from 'attempted' -- resetting the problems
# makes lcp.done False, but leaves attempts unchanged.
@@ -957,7 +967,12 @@ class CapaMixin(ScorableXBlockMixin, CapaFields):
return self.attempts >= required_attempts
elif self.showanswer == SHOWANSWER.ALWAYS:
return True
elif self.showanswer == SHOWANSWER.AFTER_ALL_ATTEMPTS:
return self.used_all_attempts()
elif self.showanswer == SHOWANSWER.AFTER_ALL_ATTEMPTS_OR_CORRECT:
return self.used_all_attempts() or self.is_correct()
elif self.showanswer == SHOWANSWER.ATTEMPTED_NO_PAST_DUE:
return self.is_attempted()
return False
def correctness_available(self):

View File

@@ -84,7 +84,8 @@ class InheritanceMixin(XBlockMixin):
# specific words for the acceptable values.
'Specify when the Show Answer button appears for each problem. '
'Valid values are "always", "answered", "attempted", "closed", '
'"finished", "past_due", "correct_or_past_due", and "never".'
'"finished", "past_due", "correct_or_past_due", "after_all_attempts", '
'"after_all_attempts_or_correct", "attempted_no_past_due", and "never".'
),
scope=Scope.settings,
default="finished",