11"""
2- Content Library Transformer.
2+ Item Bank Transformer.
3+
4+ Transformers for handling item bank blocks (library_content, itembank, etc.)
5+ that use ItemBankMixin for randomized content selection.
36"""
47
58
69import json
710import logging
811
912from eventtracking import tracker
13+ from xblock .core import XBlock
1014
1115from common .djangoapps .track import contexts
1216from lms .djangoapps .courseware .models import StudentModule
1317from openedx .core .djangoapps .content .block_structure .transformer import (
1418 BlockStructureTransformer ,
1519 FilteringTransformerMixin ,
1620)
17- from xmodule .library_content_block import LegacyLibraryContentBlock # lint-amnesty, pylint: disable=wrong-import-order
21+ from xmodule .item_bank_block import ItemBankMixin # lint-amnesty, pylint: disable=wrong-import-order
1822from xmodule .modulestore .django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
1923
2024from ..utils import get_student_module_as_dict
2529class ContentLibraryTransformer (FilteringTransformerMixin , BlockStructureTransformer ):
2630 """
2731 A transformer that manipulates the block structure by removing all
28- blocks within a library_content block to which a user should not
29- have access.
32+ blocks within item bank blocks (library_content, itembank, etc.)
33+ to which a user should not have access.
34+
35+ This transformer works with any XBlock that inherits from ItemBankMixin,
36+ filtering children based on the selection logic defined by each block type.
3037
31- Staff users are not to be exempted from library content pathways.
38+ Staff users are not to be exempted from item bank pathways.
3239 """
3340 WRITE_VERSION = 1
3441 READ_VERSION = 1
@@ -61,10 +68,10 @@ def summarize_block(usage_key):
6168 "original_usage_version" : str (orig_version ) if orig_version else None ,
6269 }
6370
64- # For each block check if block is library_content.
65- # If library_content add children array to content_library_children field
71+ # For each block check if block uses ItemBankMixin (e.g., library_content, itembank) .
72+ # If so add block analytics summary for each of its children.
6673 for block_key in block_structure .topological_traversal (
67- filter_func = lambda block_key : block_key .block_type == 'library_content' ,
74+ filter_func = lambda block_key : issubclass ( XBlock . load_class ( block_key .block_type ), ItemBankMixin ) ,
6875 yield_descendants_of_unyielded = True ,
6976 ):
7077 xblock = block_structure .get_xblock (block_key )
@@ -76,7 +83,9 @@ def transform_block_filters(self, usage_info, block_structure):
7683 all_library_children = set ()
7784 all_selected_children = set ()
7885 for block_key in block_structure :
79- if block_key .block_type != 'library_content' :
86+ block_class = XBlock .load_class (block_key .block_type )
87+
88+ if block_class is None or not issubclass (block_class , ItemBankMixin ):
8089 continue
8190 library_children = block_structure .get_children (block_key )
8291 if library_children :
@@ -98,7 +107,12 @@ def transform_block_filters(self, usage_info, block_structure):
98107
99108 # Update selected
100109 previous_count = len (selected )
101- block_keys = LegacyLibraryContentBlock .make_selection (selected , library_children , max_count )
110+ # Get the cached block class to call make_selection
111+ block_class = XBlock .load_class (block_key .block_type )
112+ if block_class is None :
113+ logger .error ('Failed to load block class for %s' , block_key )
114+ continue
115+ block_keys = block_class .make_selection (selected , library_children , max_count )
102116 selected = block_keys ['selected' ]
103117
104118 # Save back any changes
@@ -128,7 +142,7 @@ def check_child_removal(block_key):
128142 """
129143 Return True if selected block should be removed.
130144
131- Block is removed if it is part of library_content , but has
145+ Block is removed if it is a child of an item bank block , but has
132146 not been selected for current user.
133147 """
134148 if block_key not in all_library_children :
@@ -156,6 +170,12 @@ def format_block_keys(keys):
156170 json_result .append (info )
157171 return json_result
158172
173+ # Get the cached block class to call publish_selected_children_events
174+ block_class = XBlock .load_class (location .block_type )
175+ if block_class is None :
176+ logger .error ('Failed to load block class for publishing events: %s' , location )
177+ return
178+
159179 def publish_event (event_name , result , ** kwargs ):
160180 """
161181 Helper function to publish an event for analytics purposes
@@ -170,11 +190,12 @@ def publish_event(event_name, result, **kwargs):
170190 context = contexts .course_context_from_course_id (location .course_key )
171191 if user_id :
172192 context ['user_id' ] = user_id
173- full_event_name = f"edx.librarycontentblock.content.{ event_name } "
193+ event_prefix = block_class .get_selected_event_prefix ()
194+ full_event_name = f"{ event_prefix } .{ event_name } "
174195 with tracker .get_tracker ().context (full_event_name , context ):
175196 tracker .emit (full_event_name , event_data )
176197
177- LegacyLibraryContentBlock .publish_selected_children_events (
198+ block_class .publish_selected_children_events (
178199 block_keys ,
179200 format_block_keys ,
180201 publish_event ,
@@ -184,12 +205,14 @@ def publish_event(event_name, result, **kwargs):
184205class ContentLibraryOrderTransformer (BlockStructureTransformer ):
185206 """
186207 A transformer that manipulates the block structure by modifying the order of the
187- selected blocks within a library_content block to match the order of the selections
188- made by the ContentLibraryTransformer or the corresponding XBlock. So this transformer
189- requires the selections for the randomized content block to be already
190- made either by the ContentLibraryTransformer or the XBlock.
208+ selected blocks within item bank blocks (library_content, itembank, etc.)
209+ to match the order of the selections made by the ContentLibraryTransformer or the
210+ corresponding XBlock. This transformer requires the selections for the item bank block
211+ to be already made either by the ContentLibraryTransformer or the XBlock.
212+
213+ This transformer works with any XBlock that inherits from ItemBankMixin.
191214
192- Staff users are *not* exempted from library content pathways.
215+ Staff users are *not* exempted from item bank pathways.
193216 """
194217 WRITE_VERSION = 1
195218 READ_VERSION = 1
@@ -217,7 +240,8 @@ def transform(self, usage_info, block_structure):
217240 to match the order of the selections made and stored in the XBlock 'selected' field.
218241 """
219242 for block_key in block_structure :
220- if block_key .block_type != 'library_content' :
243+ block_class = XBlock .load_class (block_key .block_type )
244+ if block_class is None or not issubclass (block_class , ItemBankMixin ):
221245 continue
222246
223247 library_children = block_structure .get_children (block_key )
@@ -228,7 +252,7 @@ def transform(self, usage_info, block_structure):
228252 current_selected_blocks = {item [1 ] for item in state_dict .get ('selected' , [])}
229253
230254 # As the selections should have already been made by the ContentLibraryTransformer,
231- # the current children of the library_content block should be the same as the stored
255+ # the current children of the item bank block should be the same as the stored
232256 # selections. If they aren't, some other transformer that ran before this transformer
233257 # has modified those blocks (for example, content gating may have affected this). So do not
234258 # transform the order in that case.
0 commit comments