def __iter__(self): def parent_or_requested_block_type(usage_key): """ Returns whether the usage_key's block_type is one of self.block_types or a parent type. """ return ( usage_key.block_type in self.block_types or usage_key.block_type in BLOCK_TYPES_WITH_CHILDREN ) def create_module(descriptor): """ Factory method for creating and binding a module for the given descriptor. """ field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course_id, self.request.user, descriptor, depth=0, ) return get_module_for_descriptor( self.request.user, self.request, descriptor, field_data_cache, self.course_id ) child_to_parent = {} stack = [self.start_block] while stack: curr_block = stack.pop() if curr_block.hide_from_toc: # For now, if the 'hide_from_toc' setting is set on the block, do not traverse down # the hierarchy. The reason being is that these blocks may not have human-readable names # to display on the mobile clients. # Eventually, we'll need to figure out how we want these blocks to be displayed on the # mobile clients. As they are still accessible in the browser, just not navigatable # from the table-of-contents. continue if curr_block.location.block_type in self.block_types: if not has_access(self.request.user, 'load', curr_block, course_key=self.course_id): continue summary_fn = self.block_types[curr_block.category] block_path = list(path(curr_block, child_to_parent, self.start_block)) unit_url, section_url = find_urls(self.course_id, curr_block, child_to_parent, self.request) yield { "path": block_path, "named_path": [b["name"] for b in block_path], "unit_url": unit_url, "section_url": section_url, "summary": summary_fn(self.course_id, curr_block, self.request, self.local_cache) } if curr_block.has_children: children = get_dynamic_descriptor_children( curr_block, create_module, usage_key_filter=parent_or_requested_block_type ) for block in reversed(children): stack.append(block) child_to_parent[block] = curr_block
def recurse_blocks_nav(self, request_info, result_data, block_info): """ A depth-first recursive function that supports calculation of both the list of blocks in the course and the navigation information up to the requested navigation_depth of the course. Arguments: request_info - Object encapsulating the request information. result_data - Running result data that is updated during the recursion. block_info - Information about the current block in the recursion. """ # bind user data to the block block_info.block = get_module_for_descriptor( request_info.request.user, request_info.request, block_info.block, request_info.field_data_cache, request_info.course.id, course=request_info.course ) # verify the user has access to this block if (block_info.block is None or not has_access( request_info.request.user, 'load', block_info.block, course_key=request_info.course.id )): return # add the block's value to the result result_data.blocks[unicode(block_info.block.location)] = block_info.value # descendants self.update_descendants(request_info, result_data, block_info) # children: recursively call the function for each of the children, while supporting dynamic children. if block_info.block.has_children: block_info.children = get_dynamic_descriptor_children(block_info.block, request_info.request.user.id) for child in block_info.children: self.recurse_blocks_nav( request_info, result_data, self.BlockInfo(child, request_info, parent_block_info=block_info) ) # block count self.update_block_count(request_info, result_data, block_info) # block JSON data self.add_block_json(request_info, block_info) # multi-device support if 'multi_device' in request_info.fields: block_info.value['multi_device'] = block_info.block.has_support( getattr(block_info.block, 'student_view', None), 'multi_device' ) # additional fields self.add_additional_fields(request_info, block_info)