diff --git a/openedx/core/djangoapps/content_libraries/api/containers.py b/openedx/core/djangoapps/content_libraries/api/containers.py
index 3a0a89550cc4..393755ed1c91 100644
--- a/openedx/core/djangoapps/content_libraries/api/containers.py
+++ b/openedx/core/djangoapps/content_libraries/api/containers.py
@@ -60,7 +60,47 @@
class ContainerType(Enum):
+ """
+ The container types supported by content_libraries, and logic to map them to OLX.
+ """
Unit = "unit"
+ Subsection = "subsection"
+ Section = "section"
+
+ @property
+ def olx_tag(self) -> str:
+ """
+ Canonical XML tag to use when representing this container as OLX.
+
+ For example, Units are encoded as ....
+
+ These tag names are historical. We keep them around for the backwards compatibility of OLX
+ and for easier interaction with legacy modulestore-powered structural XBlocks
+ (e.g., copy-paste of Units between courses and V2 libraries).
+ """
+ match self:
+ case self.Unit:
+ return "vertical"
+ case self.Subsection:
+ return "sequential"
+ case self.Section:
+ return "chapter"
+ raise TypeError(f"unexpected ContainerType: {self!r}")
+
+ @classmethod
+ def from_source_olx_tag(cls, olx_tag: str) -> 'ContainerType':
+ """
+ Get the ContainerType that this OLX tag maps to.
+ """
+ if olx_tag == "unit":
+ # There is an alternative implementation to VerticalBlock called UnitBlock whose
+ # OLX tag is . When converting from OLX, we want to handle both
+ # and as Unit containers, although the canonical serialization is still .
+ return cls.Unit
+ try:
+ return next(ct for ct in cls if olx_tag == ct.olx_tag)
+ except StopIteration:
+ raise ValueError(f"no container_type for XML tag: <{olx_tag}>") from None
@dataclass(frozen=True, kw_only=True)
@@ -83,7 +123,6 @@ def from_container(cls, library_key, container: Container, associated_collection
container=container,
)
container_type = ContainerType(container_key.container_type)
-
published_by = ""
if last_publish_log and last_publish_log.published_by:
published_by = last_publish_log.published_by.username
@@ -209,7 +248,7 @@ def create_container(
created_by=user_id,
)
case _:
- raise ValueError(f"Invalid container type: {container_type}")
+ raise NotImplementedError(f"Library support for {container_type} is in progress")
LIBRARY_CONTAINER_CREATED.send_event(
library_container=LibraryContainerData(