diff --git a/common/lib/xmodule/xmodule/util/misc.py b/common/lib/xmodule/xmodule/util/misc.py index b121dc52a3..abc09d0111 100644 --- a/common/lib/xmodule/xmodule/util/misc.py +++ b/common/lib/xmodule/xmodule/util/misc.py @@ -99,3 +99,14 @@ def get_default_short_labeler(course): default_labelers[assignment_type]['index'] += 1 return labeler(index) return default_labeler + + +def is_xblock_an_assignment(xblock): + """ + Takes in a leaf xblock and returns a boolean if the xblock is an assignment. + """ + graded = getattr(xblock, 'graded', False) + has_score = getattr(xblock, 'has_score', False) + weight = getattr(xblock, 'weight', 1) + scored = has_score and (weight is None or weight > 0) + return graded and scored diff --git a/common/lib/xmodule/xmodule/vertical_block.py b/common/lib/xmodule/xmodule/vertical_block.py index f5ca8988a0..17a302c869 100644 --- a/common/lib/xmodule/xmodule/vertical_block.py +++ b/common/lib/xmodule/xmodule/vertical_block.py @@ -12,6 +12,8 @@ import pytz import six from lxml import etree from web_fragments.fragment import Fragment + +from common.lib.xmodule.xmodule.util.misc import is_xblock_an_assignment from xblock.core import XBlock from xmodule.mako_module import MakoTemplateBlockBase from xmodule.progress import Progress @@ -257,11 +259,7 @@ class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParse all_complete = None for child in children: complete = completions[child.scope_ids.usage_id] == 1 - graded = getattr(child, 'graded', False) - has_score = getattr(child, 'has_score', False) - weight = getattr(child, 'weight', 1) - scored = has_score and (weight is None or weight > 0) - if graded and scored: + if is_xblock_an_assignment(child): if not complete: return False all_complete = True diff --git a/openedx/features/personalized_learner_schedules/call_to_action.py b/openedx/features/personalized_learner_schedules/call_to_action.py index adaafcc713..34c56bdc3b 100644 --- a/openedx/features/personalized_learner_schedules/call_to_action.py +++ b/openedx/features/personalized_learner_schedules/call_to_action.py @@ -10,6 +10,7 @@ from django.conf import settings from django.urls import reverse from django.utils.translation import ngettext, gettext as _ +from common.lib.xmodule.xmodule.util.misc import is_xblock_an_assignment from lms.djangoapps.course_home_api.utils import is_request_from_learning_mfe from openedx.core.lib.mobile_utils import is_request_from_mobile_app from openedx.features.course_experience.utils import dates_banner_should_display @@ -49,19 +50,19 @@ class PersonalizedLearnerScheduleCallToAction: if category == self.CAPA_SUBMIT_DISABLED: # xblock is a capa problem, and the submit button is disabled. Check if it's because of a personalized # schedule due date being missed, and if so, we can offer to shift it. - if self._is_block_shiftable(xblock): + if self._is_block_shiftable(xblock, category): ctas.append(self._make_reset_deadlines_cta(xblock, category, is_learning_mfe)) elif category == self.VERTICAL_BANNER and not completed: # xblock is a vertical, so we'll check all the problems inside it. If there are any that will show a # a "shift dates" CTA under CAPA_SUBMIT_DISABLED, then we'll also show the same CTA as a vertical banner. - if any(self._is_block_shiftable(item) for item in xblock.get_display_items()): + if any(self._is_block_shiftable(item, category) for item in xblock.get_display_items()): ctas.append(self._make_reset_deadlines_cta(xblock, category, is_learning_mfe)) return ctas - @staticmethod - def _is_block_shiftable(xblock): + @classmethod + def _is_block_shiftable(cls, xblock, category): """ Test if the xblock would be solvable if we were to shift dates. @@ -81,7 +82,14 @@ class PersonalizedLearnerScheduleCallToAction: PersonalizedLearnerScheduleCallToAction._log_past_due_warning(type(xblock).__name__) is_past_due = xblock.is_past_due - return xblock.self_paced and can_attempt and is_past_due + can_shift = xblock.self_paced and can_attempt and is_past_due + + # Note: we will still show the CTA at the xblock level (next to the submit button) regardless + # of if the xblock is an assignment (meaning graded *and* scored) + if category == cls.VERTICAL_BANNER: + can_shift = can_shift and is_xblock_an_assignment(xblock) + + return can_shift @staticmethod def _log_past_due_warning(name):