diff --git a/lms/djangoapps/course_blocks/api.py b/lms/djangoapps/course_blocks/api.py index c978f54e02d5..de4e0443fb08 100644 --- a/lms/djangoapps/course_blocks/api.py +++ b/lms/djangoapps/course_blocks/api.py @@ -108,4 +108,5 @@ def get_course_blocks( transformers, starting_block_usage_key, collected_block_structure, + user, ) diff --git a/openedx/core/djangoapps/content/block_structure/manager.py b/openedx/core/djangoapps/content/block_structure/manager.py index 2f8a041c3163..ec2b5489afc4 100644 --- a/openedx/core/djangoapps/content/block_structure/manager.py +++ b/openedx/core/djangoapps/content/block_structure/manager.py @@ -35,7 +35,7 @@ def __init__(self, root_block_usage_key, modulestore, cache): self.modulestore = modulestore self.store = BlockStructureStore(cache) - def get_transformed(self, transformers, starting_block_usage_key=None, collected_block_structure=None): + def get_transformed(self, transformers, starting_block_usage_key=None, collected_block_structure=None, user=None): """ Returns the transformed Block Structure for the root_block_usage_key, starting at starting_block_usage_key, getting block data from the cache @@ -57,11 +57,14 @@ def get_transformed(self, transformers, starting_block_usage_key=None, collected get_collected. Can be optionally provided if already available, for optimization. + user (django.contrib.auth.models.User) - User object for + which the block structure is to be transformed. + Returns: BlockStructureBlockData - A transformed block structure, starting at starting_block_usage_key. """ - block_structure = collected_block_structure.copy() if collected_block_structure else self.get_collected() + block_structure = collected_block_structure.copy() if collected_block_structure else self.get_collected(user) if starting_block_usage_key: # Override the root_block_usage_key so traversals start at the @@ -77,7 +80,7 @@ def get_transformed(self, transformers, starting_block_usage_key=None, collected transformers.transform(block_structure) return block_structure - def get_collected(self): + def get_collected(self, user=None): """ Returns the collected Block Structure for the root_block_usage_key, getting block data from the cache and modulestore, as needed. @@ -86,6 +89,10 @@ def get_collected(self): the modulestore is accessed if needed (at cache miss), and the transformers data is collected if needed. + In the case of a cache miss, the function bypasses runtime access checks for the current + user. This is done to prevent inconsistencies in the data, which can occur when + certain blocks are inaccessible due to access restrictions. + Returns: BlockStructureBlockData - A collected block structure, starting at root_block_usage_key, with collected data @@ -99,7 +106,15 @@ def get_collected(self): BlockStructureTransformers.verify_versions(block_structure) except (BlockStructureNotFound, TransformerDataIncompatible): - block_structure = self._update_collected() + if user: + # This bypasses the runtime access checks. When we are populating the course blocks cache, + # we do not want to perform access checks. Access checks result in inconsistent blocks where + # inaccessible blocks are missing from the cache. Cached course blocks are then used for all the users. + user.known = False + block_structure = self._update_collected() + user.known = True + else: + block_structure = self._update_collected() return block_structure