Skip to content

Commit 0ac3994

Browse files
authored
fix: handle block.xml content properly (#419)
OLX must be stored as text content, not file content.
1 parent 1a7f9b1 commit 0ac3994

File tree

3 files changed

+31
-5
lines changed

3 files changed

+31
-5
lines changed

openedx_learning/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
Open edX Learning ("Learning Core").
33
"""
44

5-
__version__ = "0.29.0"
5+
__version__ = "0.29.1"

openedx_learning/apps/authoring/backup_restore/zipper.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
)
4848
from openedx_learning.apps.authoring.collections import api as collections_api
4949
from openedx_learning.apps.authoring.components import api as components_api
50+
from openedx_learning.apps.authoring.contents import api as contents_api
5051
from openedx_learning.apps.authoring.publishing import api as publishing_api
5152
from openedx_learning.apps.authoring.sections import api as sections_api
5253
from openedx_learning.apps.authoring.subsections import api as subsections_api
@@ -493,6 +494,7 @@ def __init__(self, zipf: zipfile.ZipFile, key: str | None = None, user: UserType
493494
self.zipf = zipf
494495
self.user = user
495496
self.lp_key = key # If provided, use this key for the restored learning package
497+
self.learning_package_id: int | None = None # Will be set upon restoration
496498
self.utc_now: datetime = datetime.now(timezone.utc)
497499
self.component_types_cache: dict[tuple[str, str], ComponentType] = {}
498500
self.errors: list[dict[str, Any]] = []
@@ -735,6 +737,7 @@ def _save(
735737
learning_package["key"] = self.lp_key
736738

737739
learning_package_obj = publishing_api.create_learning_package(**learning_package)
740+
self.learning_package_id = learning_package_obj.id
738741

739742
with publishing_api.bulk_draft_changes_for(learning_package_obj.id):
740743
self._save_components(learning_package_obj, components, component_static_files)
@@ -937,16 +940,31 @@ def _resolve_static_files(
937940
num_version: int,
938941
entity_key: str,
939942
static_files_map: dict[str, List[str]]
940-
) -> dict[str, bytes]:
943+
) -> dict[str, bytes | int]:
941944
"""Resolve static file paths into their binary content."""
942-
resolved_files: dict[str, bytes] = {}
945+
resolved_files: dict[str, bytes | int] = {}
943946

944-
static_file_key = f"{entity_key}:v{num_version}" # e.g., "my_component:123:v1"
947+
static_file_key = f"{entity_key}:v{num_version}" # e.g., "xblock.v1:html:my_component_123456:v1"
948+
block_type = entity_key.split(":")[1] # e.g., "html"
945949
static_files = static_files_map.get(static_file_key, [])
946950
for static_file in static_files:
947951
local_key = static_file.split(f"v{num_version}/")[-1]
948952
with self.zipf.open(static_file, "r") as f:
949-
resolved_files[local_key] = f.read()
953+
content_bytes = f.read()
954+
if local_key == "block.xml":
955+
# Special handling for block.xml to ensure
956+
# storing the value as a content instance
957+
if not self.learning_package_id:
958+
raise ValueError("learning_package_id must be set before resolving static files.")
959+
text_content = contents_api.get_or_create_text_content(
960+
self.learning_package_id,
961+
contents_api.get_or_create_media_type(f"application/vnd.openedx.xblock.v1.{block_type}+xml").id,
962+
text=content_bytes.decode("utf-8"),
963+
created=self.utc_now,
964+
)
965+
resolved_files[local_key] = text_content.id
966+
else:
967+
resolved_files[local_key] = content_bytes
950968
return resolved_files
951969

952970
def _resolve_children(self, entity_data: dict[str, Any], lookup_map: dict[str, Any]) -> list[Any]:

tests/openedx_learning/apps/authoring/backup_restore/test_restore.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ def verify_containers(self, lp):
8282
assert False, f"Unexpected container key: {container.key}"
8383

8484
def verify_components(self, lp):
85+
# pylint: disable=too-many-statements
8586
"""Verify the components and their versions were restored correctly."""
8687
component_qs = components_api.get_components(lp.id)
8788
expected_component_keys = [
@@ -103,6 +104,13 @@ def verify_components(self, lp):
103104
assert draft_version is not None
104105
assert draft_version.version_num == 2
105106
assert published_version is None
107+
# Get the content associated with this component
108+
contents = draft_version.componentversion.contents.all()
109+
content = contents.first() if contents.exists() else None
110+
assert content is not None
111+
assert "<drag-and-drop-v2" in content.text
112+
assert not content.has_file
113+
assert str(content.media_type) == "application/vnd.openedx.xblock.v1.drag-and-drop-v2+xml"
106114
elif component.key == "xblock.v1:html:e32d5479-9492-41f6-9222-550a7346bc37":
107115
assert component.component_type.name == "html"
108116
assert component.component_type.namespace == "xblock.v1"

0 commit comments

Comments
 (0)