Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cms/djangoapps/modulestore_migrator/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class CompositionLevel(Enum):
Unit = ContainerType.Unit.value
Subsection = ContainerType.Subsection.value
Section = ContainerType.Section.value
OutlineRoot = ContainerType.OutlineRoot.value

@property
def is_container(self) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions cms/djangoapps/modulestore_migrator/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ def _migrate_node(
container_type = ContainerType.from_source_olx_tag(source_node.tag)
except ValueError:
container_type = None
if source_node.tag in {"course", "library"}:
if source_node.tag == "library":
should_migrate_node = False
should_migrate_children = True
else:
Expand Down Expand Up @@ -473,7 +473,7 @@ def _migrate_container(
],
created=created_at,
created_by=created_by,
container_version_cls=ContainerVersion,
container_version_cls=container_type.container_model_classes[1],
).publishable_entity_version


Expand Down
2 changes: 2 additions & 0 deletions openedx/core/djangoapps/content/search/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,8 @@ def index_container_batch(batch, num_done, library_key) -> int:
doc.update(searchable_doc_containers(container_key, "subsections"))
case lib_api.ContainerType.Subsection:
doc.update(searchable_doc_containers(container_key, "sections"))
case lib_api.ContainerType.Section:
doc.update(searchable_doc_containers(container_key, "outline_roots"))
docs.append(doc)
except Exception as err: # pylint: disable=broad-except
status_cb(f"Error indexing container {container.key}: {err}")
Expand Down
2 changes: 1 addition & 1 deletion openedx/core/djangoapps/content/search/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ def get_child_keys(children) -> list[str]:
str(child.usage_key)
for child in children
]
case lib_api.ContainerType.Subsection | lib_api.ContainerType.Section:
case lib_api.ContainerType.Subsection | lib_api.ContainerType.Section | lib_api.ContainerType.OutlineRoot:
return [
str(child.container_key)
for child in children
Expand Down
73 changes: 71 additions & 2 deletions openedx/core/djangoapps/content_libraries/api/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,39 @@ class ContainerType(Enum):
Unit = "unit"
Subsection = "subsection"
Section = "section"
OutlineRoot = "outline_root"

@property
def container_model_classes(self) -> tuple[type[Container], type[ContainerVersion]]:
"""
Get the container, containerversion subclasses associated with this type.

@@TODO Is this what we want, a hard mapping between container_types and Container classes?
* If so, then expand on this pattern, so that all ContainerType logic is contained within
this class, and get rid of the match-case statements that are all over the content_libraries
app.
* If not, then figure out what to do instead.
"""
from openedx_learning.api.authoring_models import (
Unit,
UnitVersion,
Subsection,
SubsectionVersion,
Section,
SectionVersion,
OutlineRoot,
OutlineRootVersion,
)
match self:
case self.Unit:
return (Unit, UnitVersion)
case self.Subsection:
return (Subsection, SubsectionVersion)
case self.Section:
return (Section, SectionVersion)
case self.OutlineRoot:
return (OutlineRoot, OutlineRootVersion)
raise TypeError(f"unexpected ContainerType: {self!r}")

@property
def olx_tag(self) -> str:
Expand All @@ -83,6 +116,8 @@ def olx_tag(self) -> str:
return "sequential"
case self.Section:
return "chapter"
case self.OutlineRoot:
return "course"
raise TypeError(f"unexpected ContainerType: {self!r}")

@classmethod
Expand Down Expand Up @@ -165,6 +200,8 @@ def library_container_locator(
container_type = ContainerType.Subsection
elif hasattr(container, 'section'):
container_type = ContainerType.Section
elif hasattr(container, 'outlineroot'):
container_type = ContainerType.OutlineRoot

assert container_type is not None

Expand Down Expand Up @@ -277,6 +314,14 @@ def create_container(
created=created,
created_by=user_id,
)
case ContainerType.OutlineRoot:
container, _initial_version = authoring_api.create_outline_root_and_version(
content_library.learning_package_id,
key=slug,
title=title,
created=created,
created_by=user_id,
)
case _:
raise NotImplementedError(f"Library does not support {container_type} yet")

Expand Down Expand Up @@ -330,8 +375,15 @@ def update_container(
created=created,
created_by=user_id,
)

# The `affected_containers` are not obtained, because the sections are
affected_containers = get_containers_contains_item(container_key)
case ContainerType.OutlineRoot:
version = authoring_api.create_next_outline_root_version(
container.outlineroot,
title=display_name,
created=created,
created_by=user_id,
)
# The `affected_containers` are not obtained, because the outline_roots are
# not contained in any container.
case _:
raise NotImplementedError(f"Library does not support {container_type} yet")
Expand Down Expand Up @@ -546,6 +598,23 @@ def update_container_children(
entities_action=entities_action,
)

for key in children_ids:
CONTENT_OBJECT_ASSOCIATIONS_CHANGED.send_event(
content_object=ContentObjectChangedData(
object_id=str(key),
changes=["sections"],
),
)
case ContainerType.OutlineRoot:
subsections = [_get_container_from_key(key).outlineroot for key in children_ids] # type: ignore[arg-type]
new_version = authoring_api.create_next_outline_root_version(
container.outlineroot,
sections=sections, # type: ignore[arg-type]
created=created,
created_by=user_id,
entities_action=entities_action,
)

for key in children_ids:
CONTENT_OBJECT_ASSOCIATIONS_CHANGED.send_event(
content_object=ContentObjectChangedData(
Expand Down
Loading