def check_children_for_content_type_gating_paywall(self, item, course_id): """ Arguments: item (xblock such as a sequence or vertical block) course_id (CourseLocator) If: This xblock contains problems which this user cannot load due to content type gating Then: Return the first content type gating paywall (Fragment) Else: Return None """ user = self._get_user() if not user: return None if not self._enabled_for_enrollment(user=user, course_key=course_id): return None # Check children for content type gated content for block in traverse_pre_order(item, get_children, leaf_filter): gate_fragment = self._content_type_gate_for_block( user, block, course_id) if gate_fragment is not None: return gate_fragment.content return None
def _check_children_for_content_type_gating_paywall(self, item): """ If: This xblock contains problems which this user cannot load due to content type gating Then: Return the first content type gating paywall (Fragment) Else: Return None """ try: user = self._get_user() course_id = self.runtime.course_id content_type_gating_service = self.runtime.service( self, 'content_type_gating') if not (content_type_gating_service and content_type_gating_service.enabled_for_enrollment( user=user, course_key=course_id)): return None for block in traverse_pre_order(item, get_children, leaf_filter): gate_fragment = content_type_gating_service.content_type_gate_for_block( user, block, course_id) if gate_fragment is not None: return gate_fragment.content except get_user_model().DoesNotExist: pass return None
def _has_assignment_blocks(item): """ Check if a given block contains children that are assignments. Assignments have graded, has_score and nonzero weight attributes. """ return any( is_xblock_an_assignment(block) for block in traverse_pre_order(item, get_children, leaf_filter))
def _get_leaf_blocks(cls, unit): # lint-amnesty, pylint: disable=missing-function-docstring def leaf_filter(block): return ( block.location.block_type not in ('chapter', 'sequential', 'vertical') and len(cls._get_children(block)) == 0 ) return list(traverse_pre_order(unit, cls._get_visible_children, leaf_filter))
def _get_leaf_blocks(cls, unit): def leaf_filter(block): return (block.location.block_type not in ('chapter', 'sequential', 'vertical') and len(cls._get_children(block)) == 0) return [ block for block in traverse_pre_order( unit, cls._get_visible_children, leaf_filter) ]
def _get_leaf_blocks(cls, unit): def leaf_filter(block): return ( block.location.block_type not in ('chapter', 'sequential', 'vertical') and len(cls._get_children(block)) == 0 ) return [ block for block in traverse_pre_order(unit, cls._get_visible_children, leaf_filter) ]
def gate_sequence_if_it_is_a_timed_exam_and_contains_content_type_gated_problems( self): """ Problem: Content type gating for FBE (Feature Based Enrollments) previously only gated individual blocks. This was an issue because audit learners could start a timed exam and then be unable to complete it because the graded content would be gated. Even if they later upgraded, they could still be unable to complete the exam because the timer could have expired. Solution: Gate the entire sequence when we think the above problem can occur. If: 1. This sequence is a timed exam 2. And this sequence contains problems which this user cannot load due to content type gating Then: We will gate access to the entire sequence. Otherwise, learners would have the ability to start their timer for an exam, but then not have the ability to complete it. We are displaying the gating fragment within the sequence, as is done for gating for prereqs, rather than content type gating the entire sequence because that would remove the next/previous navigation. When gated_sequence_fragment is not set to None, the sequence will be gated. This functionality still needs to be replicated in the frontend-app-learning courseware MFE The ticket to track this is https://openedx.atlassian.net/browse/REV-1220 Note that this will break compatability with using sequences outside of edx-platform but we are ok with this for now """ if not self.is_time_limited: self.gated_sequence_fragment = None return try: user = self._get_user() course_id = self.runtime.course_id content_type_gating_service = self.runtime.service( self, 'content_type_gating') if not (content_type_gating_service and content_type_gating_service.enabled_for_enrollment( user=user, course_key=course_id)): self.gated_sequence_fragment = None return def leaf_filter(block): # This function is used to check if this is a leaf block # Blocks with children are not currently gated by content type gating # Other than the outer function here return (block.location.block_type not in ('chapter', 'sequential', 'vertical') and not block.has_children) def get_children(parent): # This function is used to get the children of a block in the traversal below if parent.has_children: return parent.get_children() else: return [] # If any block inside a timed exam has been gated by content type gating # then gate the entire sequence. # In order to avoid scope creep, we are not handling other potential causes # of access failures as part of this work. for block in traverse_pre_order(self, get_children, leaf_filter): gate_fragment = content_type_gating_service.content_type_gate_for_block( user, block, course_id) if gate_fragment is not None: self.gated_sequence_fragment = gate_fragment return else: self.gated_sequence_fragment = None except User.DoesNotExist: self.gated_sequence_fragment = None