Skip to content

Commit 92670d4

Browse files
feat: add new ContainerType model, refactor Containers implementation
1 parent c6a9e0d commit 92670d4

31 files changed

Lines changed: 3421 additions & 4754 deletions

File tree

src/openedx_content/admin.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,3 @@
88
from .applets.components.admin import *
99
from .applets.media.admin import *
1010
from .applets.publishing.admin import *
11-
from .applets.sections.admin import *
12-
from .applets.subsections.admin import *
13-
from .applets.units.admin import *

src/openedx_content/applets/backup_restore/zipper.py

Lines changed: 75 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@
3333
from ..components import api as components_api
3434
from ..media import api as media_api
3535
from ..publishing import api as publishing_api
36-
from ..sections import api as sections_api
37-
from ..subsections import api as subsections_api
38-
from ..units import api as units_api
36+
from ..units.models import Unit
37+
from ..subsections.models import Subsection
38+
from ..sections.models import Section
3939
from .serializers import (
4040
CollectionSerializer,
4141
ComponentSerializer,
@@ -804,70 +804,70 @@ def _save_components(self, learning_package, components, component_static_files)
804804
**valid_published
805805
)
806806

807-
def _save_units(self, learning_package, containers):
808-
"""Save units and published unit versions."""
809-
for valid_unit in containers.get("unit", []):
810-
entity_key = valid_unit.get("key")
811-
unit = units_api.create_unit(learning_package.id, created_by=self.user_id, **valid_unit)
812-
self.units_map_by_key[entity_key] = unit
807+
def _save_container(
808+
self,
809+
learning_package,
810+
containers,
811+
*,
812+
container_type: publishing_api.ContainerType,
813+
container_map: dict,
814+
children_map: dict,
815+
):
816+
"""Internal logic for _save_units, _save_subsections, and _save_sections"""
817+
type_code = container_type.type_code # e.g. "unit"
818+
for data in containers.get(type_code, []):
819+
entity_key = data.get("key")
820+
container = publishing_api.create_container(
821+
learning_package.id,
822+
**data, # should this be allowed to override any of the following fields?
823+
created_by=self.user_id,
824+
container_type=container_type,
825+
)
826+
container_map[entity_key] = container # e.g. `self.units_map_by_key[entity_key] = unit`
813827

814-
for valid_published in containers.get("unit_published", []):
828+
for valid_published in containers.get(f"{type_code}_published", []):
815829
entity_key = valid_published.pop("entity_key")
816-
children = self._resolve_children(valid_published, self.components_map_by_key)
830+
children = self._resolve_children(valid_published, children_map)
817831
self.all_published_entities_versions.add(
818832
(entity_key, valid_published.get('version_num'))
819833
) # Track published version
820-
units_api.create_next_unit_version(
821-
self.units_map_by_key[entity_key],
834+
publishing_api.create_next_container_version(
835+
container_map[entity_key],
836+
**valid_published, # should this be allowed to override any of the following fields?
822837
force_version_num=valid_published.pop("version_num", None),
823-
components=children,
838+
entities=children,
824839
created_by=self.user_id,
825-
**valid_published
826840
)
827841

842+
def _save_units(self, learning_package, containers):
843+
"""Save units and published unit versions."""
844+
self._save_container(
845+
learning_package,
846+
containers,
847+
container_type=Unit,
848+
container_map=self.units_map_by_key,
849+
children_map=self.components_map_by_key,
850+
)
851+
828852
def _save_subsections(self, learning_package, containers):
829853
"""Save subsections and published subsection versions."""
830-
for valid_subsection in containers.get("subsection", []):
831-
entity_key = valid_subsection.get("key")
832-
subsection = subsections_api.create_subsection(
833-
learning_package.id, created_by=self.user_id, **valid_subsection
834-
)
835-
self.subsections_map_by_key[entity_key] = subsection
836-
837-
for valid_published in containers.get("subsection_published", []):
838-
entity_key = valid_published.pop("entity_key")
839-
children = self._resolve_children(valid_published, self.units_map_by_key)
840-
self.all_published_entities_versions.add(
841-
(entity_key, valid_published.get('version_num'))
842-
) # Track published version
843-
subsections_api.create_next_subsection_version(
844-
self.subsections_map_by_key[entity_key],
845-
units=children,
846-
force_version_num=valid_published.pop("version_num", None),
847-
created_by=self.user_id,
848-
**valid_published
849-
)
854+
self._save_container(
855+
learning_package,
856+
containers,
857+
container_type=Subsection,
858+
container_map=self.subsections_map_by_key,
859+
children_map=self.units_map_by_key,
860+
)
850861

851862
def _save_sections(self, learning_package, containers):
852863
"""Save sections and published section versions."""
853-
for valid_section in containers.get("section", []):
854-
entity_key = valid_section.get("key")
855-
section = sections_api.create_section(learning_package.id, created_by=self.user_id, **valid_section)
856-
self.sections_map_by_key[entity_key] = section
857-
858-
for valid_published in containers.get("section_published", []):
859-
entity_key = valid_published.pop("entity_key")
860-
children = self._resolve_children(valid_published, self.subsections_map_by_key)
861-
self.all_published_entities_versions.add(
862-
(entity_key, valid_published.get('version_num'))
863-
) # Track published version
864-
sections_api.create_next_section_version(
865-
self.sections_map_by_key[entity_key],
866-
subsections=children,
867-
force_version_num=valid_published.pop("version_num", None),
868-
created_by=self.user_id,
869-
**valid_published
870-
)
864+
self._save_container(
865+
learning_package,
866+
containers,
867+
container_type=Section,
868+
container_map=self.sections_map_by_key,
869+
children_map=self.subsections_map_by_key,
870+
)
871871

872872
def _save_draft_versions(self, components, containers, component_static_files):
873873
"""Save draft versions for all entity types."""
@@ -888,47 +888,29 @@ def _save_draft_versions(self, components, containers, component_static_files):
888888
**valid_draft
889889
)
890890

891-
for valid_draft in containers.get("unit_drafts", []):
892-
entity_key = valid_draft.pop("entity_key")
893-
version_num = valid_draft["version_num"] # Should exist, validated earlier
894-
if self._is_version_already_exists(entity_key, version_num):
895-
continue
896-
children = self._resolve_children(valid_draft, self.components_map_by_key)
897-
units_api.create_next_unit_version(
898-
self.units_map_by_key[entity_key],
899-
components=children,
900-
force_version_num=valid_draft.pop("version_num", None),
901-
created_by=self.user_id,
902-
**valid_draft
903-
)
904-
905-
for valid_draft in containers.get("subsection_drafts", []):
906-
entity_key = valid_draft.pop("entity_key")
907-
version_num = valid_draft["version_num"] # Should exist, validated earlier
908-
if self._is_version_already_exists(entity_key, version_num):
909-
continue
910-
children = self._resolve_children(valid_draft, self.units_map_by_key)
911-
subsections_api.create_next_subsection_version(
912-
self.subsections_map_by_key[entity_key],
913-
units=children,
914-
force_version_num=valid_draft.pop("version_num", None),
915-
created_by=self.user_id,
916-
**valid_draft
917-
)
891+
def _process_draft_containers(
892+
container_type: publishing_api.ContainerType,
893+
container_map: dict,
894+
children_map: dict,
895+
):
896+
for valid_draft in containers.get(f"{container_type.type_code}_drafts", []):
897+
entity_key = valid_draft.pop("entity_key")
898+
version_num = valid_draft["version_num"] # Should exist, validated earlier
899+
if self._is_version_already_exists(entity_key, version_num):
900+
continue
901+
children = self._resolve_children(valid_draft, children_map)
902+
del valid_draft["version_num"]
903+
publishing_api.create_next_container_version(
904+
container_map[entity_key],
905+
**valid_draft, # should this be allowed to override any of the following fields?
906+
entities=children,
907+
force_version_num=version_num,
908+
created_by=self.user_id,
909+
)
918910

919-
for valid_draft in containers.get("section_drafts", []):
920-
entity_key = valid_draft.pop("entity_key")
921-
version_num = valid_draft["version_num"] # Should exist, validated earlier
922-
if self._is_version_already_exists(entity_key, version_num):
923-
continue
924-
children = self._resolve_children(valid_draft, self.subsections_map_by_key)
925-
sections_api.create_next_section_version(
926-
self.sections_map_by_key[entity_key],
927-
subsections=children,
928-
force_version_num=valid_draft.pop("version_num", None),
929-
created_by=self.user_id,
930-
**valid_draft
931-
)
911+
_process_draft_containers(Unit, self.units_map_by_key, children_map=self.components_map_by_key)
912+
_process_draft_containers(Subsection, self.subsections_map_by_key, children_map=self.units_map_by_key)
913+
_process_draft_containers(Section, self.sections_map_by_key, children_map=self.subsections_map_by_key)
932914

933915
# --------------------------
934916
# Utilities

src/openedx_content/applets/collections/api.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from django.db.models import QuerySet
1010

1111
from ..publishing import api as publishing_api
12-
from ..publishing.models import PublishableEntity
12+
from ..publishing.models import Container, PublishableEntity
1313
from .models import Collection, CollectionPublishableEntity
1414

1515
# The public API that will be re-exported by openedx_content.api
@@ -24,6 +24,7 @@
2424
"get_collection",
2525
"get_collections",
2626
"get_entity_collections",
27+
"get_collection_containers",
2728
"remove_from_collection",
2829
"restore_collection",
2930
"update_collection",
@@ -195,6 +196,18 @@ def get_entity_collections(learning_package_id: int, entity_key: str) -> QuerySe
195196
return entity.collections.filter(enabled=True).order_by("pk")
196197

197198

199+
def get_collection_containers(learning_package_id: int, collection_key: str) -> QuerySet[Container]:
200+
"""
201+
Returns a QuerySet of Containers relating to the PublishableEntities in a Collection.
202+
203+
Containers have a one-to-one relationship with PublishableEntity, but the reverse may not always be true.
204+
"""
205+
return Container.objects.filter(
206+
publishable_entity__learning_package_id=learning_package_id,
207+
publishable_entity__collections__key=collection_key,
208+
).order_by("pk")
209+
210+
198211
def get_collections(learning_package_id: int, enabled: bool | None = True) -> QuerySet[Collection]:
199212
"""
200213
Get all collections for a given learning package

0 commit comments

Comments
 (0)