diff --git a/cms/djangoapps/modulestore_migrator/tasks.py b/cms/djangoapps/modulestore_migrator/tasks.py index 1c4736a3d76a..c65c8af0c59c 100644 --- a/cms/djangoapps/modulestore_migrator/tasks.py +++ b/cms/djangoapps/modulestore_migrator/tasks.py @@ -959,16 +959,18 @@ def _migrate_component( return component.versioning.draft.publishable_entity_version, None # If component existed and was deleted or we have to replace the current version - # Create the new component version for it - component_version = libraries_api.set_library_block_olx(target_key, new_olx_str=olx) + paths_to_media_ids = {} for filename, media_pk in context.content_by_filename.items(): filename_no_ext, _ = os.path.splitext(filename) if filename_no_ext not in olx: continue new_path = f"static/{filename}" - content_api.create_component_version_media( - component_version.pk, media_pk, path=new_path - ) + paths_to_media_ids[new_path] = media_pk + + # Create the new component version for it + component_version = libraries_api.set_library_block_olx( + target_key, new_olx_str=olx, paths_to_media=paths_to_media_ids, + ) # Publish the component libraries_api.publish_component_changes(target_key, context.created_by) diff --git a/openedx/core/djangoapps/content_libraries/api/blocks.py b/openedx/core/djangoapps/content_libraries/api/blocks.py index 33cfeff297b6..892bc3a62b28 100644 --- a/openedx/core/djangoapps/content_libraries/api/blocks.py +++ b/openedx/core/djangoapps/content_libraries/api/blocks.py @@ -399,7 +399,11 @@ def get_library_component_creation_entry( ) -def set_library_block_olx(usage_key: LibraryUsageLocatorV2, new_olx_str: str) -> ComponentVersion: +def set_library_block_olx( + usage_key: LibraryUsageLocatorV2, + new_olx_str: str, + paths_to_media: dict | None = None, +) -> ComponentVersion: """ Replace the OLX source of the given XBlock. @@ -407,9 +411,19 @@ def set_library_block_olx(usage_key: LibraryUsageLocatorV2, new_olx_str: str) -> very little validation is done and this can easily result in a broken XBlock that won't load. + The optional ``paths_to_media`` parameter can be used to attach + openedx_content Media to this XBlock. A common use case for this would be to + add images or other static assets to a text block:: + + figure_a_media = content_api.get_or_create_file_media(...) + paths_to_media={ + 'static/figure_a.png': figure_a_media, + } + Returns the version number of the newly created ComponentVersion. """ assert isinstance(usage_key, LibraryUsageLocatorV2) + paths_to_media = paths_to_media or {} # HTMLBlock uses CDATA to preserve HTML inside the XML, so make sure we # don't strip that out. @@ -446,7 +460,7 @@ def set_library_block_olx(usage_key: LibraryUsageLocatorV2, new_olx_str: str) -> now = datetime.now(tz=timezone.utc) # noqa: UP017 with transaction.atomic(): - new_content = content_api.get_or_create_text_media( + new_olx_media = content_api.get_or_create_text_media( component.learning_package_id, get_or_create_olx_media_type(usage_key.block_type).id, text=new_olx_str, @@ -456,7 +470,8 @@ def set_library_block_olx(usage_key: LibraryUsageLocatorV2, new_olx_str: str) -> component.id, title=new_title, media_to_replace={ - 'block.xml': new_content.pk, + **paths_to_media, + 'block.xml': new_olx_media.pk, }, created=now, ) @@ -606,11 +621,7 @@ def _import_staged_block( created_by=user.id, ) - # This will create the first component version and set the OLX/title - # appropriately. It will not publish. Once we get the newly created - # ComponentVersion back from this, we can attach all our files to it. - component_version = set_library_block_olx(usage_key, olx_str) - + paths_to_media = {} for staged_content_file_data in staged_content_files: # The ``data`` attribute is going to be None because the clipboard # is optimized to not do redundant file copying when copying/pasting @@ -657,17 +668,18 @@ def _import_staged_block( media_type_str = "application/octet-stream" media_type = content_api.get_or_create_media_type(media_type_str) - content = content_api.get_or_create_file_media( + media = content_api.get_or_create_file_media( learning_package.id, media_type.id, data=file_data, created=now, ) - content_api.create_component_version_media( - component_version.pk, - content.id, - path=filename, - ) + paths_to_media[filename] = media.id + + # This will create the first component version and set the OLX/title + # appropriately. It will not publish. Once we get the newly created + # ComponentVersion back from this, we can attach all our files to it. + set_library_block_olx(usage_key, olx_str, paths_to_media) # Now return the metadata about the new block return get_library_block(usage_key) @@ -1087,7 +1099,13 @@ def _create_component_for_block( component_type = content_api.get_or_create_component_type( "xblock.v1", usage_key.block_type ) - component, component_version = content_api.create_component_and_version( + block_olx_media = content_api.get_or_create_text_media( + learning_package.id, + get_or_create_olx_media_type(usage_key.block_type).id, + text=xml_text, + created=now, + ) + _component, component_version = content_api.create_component_and_version( learning_package.id, component_type=component_type, component_code=usage_key.block_id, @@ -1095,17 +1113,9 @@ def _create_component_for_block( created=now, created_by=user_id, can_stand_alone=can_stand_alone, - ) - content = content_api.get_or_create_text_media( - learning_package.id, - get_or_create_olx_media_type(usage_key.block_type).id, - text=xml_text, - created=now, - ) - content_api.create_component_version_media( - component_version.pk, - content.id, - path="block.xml", + media={ + 'block.xml': block_olx_media + } ) return component_version diff --git a/requirements/constraints.txt b/requirements/constraints.txt index b5edefc436f6..5f4a7a515ccb 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -65,7 +65,7 @@ numpy<2.0.0 # breaking changes which openedx-core devs want to roll out manually. New patch versions # are OK to accept automatically. # Issue for unpinning: https://github.com/openedx/edx-platform/issues/35269 -openedx-core<0.47 +openedx-core<0.48 # Date: 2023-11-29 # Open AI version 1.0.0 dropped support for openai.ChatCompletion which is currently in use in enterprise. diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 01b8e02103f6..d6ff2d082a96 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -840,7 +840,7 @@ openedx-calc==5.0.0 # via # -r requirements/edx/kernel.in # xblocks-contrib -openedx-core==0.46.0 +openedx-core==0.47.0 # via # -c requirements/constraints.txt # -r requirements/edx/kernel.in diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index fd45f0164de7..c7c3f9c19aec 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -1394,7 +1394,7 @@ openedx-calc==5.0.0 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # xblocks-contrib -openedx-core==0.46.0 +openedx-core==0.47.0 # via # -c requirements/constraints.txt # -r requirements/edx/doc.txt diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index 34a2516e92ee..627922a4f53e 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -1018,7 +1018,7 @@ openedx-calc==5.0.0 # via # -r requirements/edx/base.txt # xblocks-contrib -openedx-core==0.46.0 +openedx-core==0.47.0 # via # -c requirements/constraints.txt # -r requirements/edx/base.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 77a3f6ef7d9d..78d1d86cdef0 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -1065,7 +1065,7 @@ openedx-calc==5.0.0 # via # -r requirements/edx/base.txt # xblocks-contrib -openedx-core==0.46.0 +openedx-core==0.47.0 # via # -c requirements/constraints.txt # -r requirements/edx/base.txt