Skip to content

Commit 3010e9d

Browse files
author
Andrii
committed
refactor: update child entities to new API, fix some name & style issues
1 parent fc13d39 commit 3010e9d

File tree

4 files changed

+61
-33
lines changed

4 files changed

+61
-33
lines changed

openedx_learning/apps/authoring/publishing/api.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,9 +1059,8 @@ def contains_unpublished_changes(container_id: int) -> bool:
10591059

10601060
# We only care about children that are un-pinned, since published changes to pinned children don't matter
10611061
entity_list = getattr(container.versioning.draft, "entity_list", None)
1062-
# ?FOR REVIEW: Is this correct?
10631062
if entity_list is None:
1064-
# This container has not been published yet, or has been deleted.
1063+
# This container has been soft-deleted, so it has no children.
10651064
return False
10661065

10671066
# This is a naive and inefficient implementation but should be correct.

openedx_learning/apps/authoring/subsections/api.py

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ def create_subsection_version(
6262
version_num: int,
6363
*,
6464
title: str,
65-
publishable_entities_pks: list[int],
66-
entity_version_pks: list[int | None],
65+
entity_rows: list[publishing_api.ContainerEntityRow],
6766
created: datetime,
6867
created_by: int | None = None,
6968
) -> SubsectionVersion:
@@ -78,17 +77,15 @@ def create_subsection_version(
7877
subsection_pk: The subsection ID.
7978
version_num: The version number.
8079
title: The title.
81-
publishable_entities_pk: The publishable entities.
82-
entity: The entity.
80+
entity_rows: child entities/versions
8381
created: The creation date.
8482
created_by: The user who created the subsection.
8583
"""
8684
return publishing_api.create_container_version(
8785
subsection.pk,
8886
version_num,
8987
title=title,
90-
publishable_entities_pks=publishable_entities_pks,
91-
entity_version_pks=entity_version_pks,
88+
entity_rows=entity_rows,
9289
created=created,
9390
created_by=created_by,
9491
container_version_cls=SubsectionVersion,
@@ -97,30 +94,33 @@ def create_subsection_version(
9794

9895
def _pub_entities_for_units(
9996
units: list[Unit | UnitVersion] | None,
100-
) -> tuple[list[int], list[int | None]] | tuple[None, None]:
97+
) -> list[publishing_api.ContainerEntityRow] | None:
10198
"""
10299
Helper method: given a list of Unit | UnitVersion, return the
103-
lists of publishable_entities_pks and entity_version_pks needed for the
104-
base container APIs.
100+
list of ContainerEntityRows needed for the base container APIs.
105101
106102
UnitVersion is passed when we want to pin a specific version, otherwise
107103
Unit is used for unpinned.
108104
"""
109105
if units is None:
110106
# When these are None, that means don't change the entities in the list.
111-
return None, None
107+
return None
112108
for u in units:
113109
if not isinstance(u, (Unit, UnitVersion)):
114110
raise TypeError("Subsection units must be either Unit or UnitVersion.")
115-
publishable_entities_pks = [
116-
(u.publishable_entity_id if isinstance(u, Unit) else u.unit.publishable_entity_id)
111+
return [
112+
(
113+
publishing_api.ContainerEntityRow(
114+
entity_pk=u.container.publishable_entity_id,
115+
version_pk=None,
116+
) if isinstance(u, Unit)
117+
else publishing_api.ContainerEntityRow(
118+
entity_pk=u.unit.container.publishable_entity_id,
119+
version_pk=u.container_version.publishable_entity_version_id,
120+
)
121+
)
117122
for u in units
118123
]
119-
entity_version_pks = [
120-
(uv.pk if isinstance(uv, UnitVersion) else None)
121-
for uv in units
122-
]
123-
return publishable_entities_pks, entity_version_pks
124124

125125

126126
def create_next_subsection_version(
@@ -143,12 +143,11 @@ def create_next_subsection_version(
143143
created: The creation date.
144144
created_by: The user who created the subsection.
145145
"""
146-
publishable_entities_pks, entity_version_pks = _pub_entities_for_units(units)
146+
entity_rows = _pub_entities_for_units(units)
147147
subsection_version = publishing_api.create_next_container_version(
148148
subsection.pk,
149149
title=title,
150-
publishable_entities_pks=publishable_entities_pks,
151-
entity_version_pks=entity_version_pks,
150+
entity_rows=entity_rows,
152151
created=created,
153152
created_by=created_by,
154153
container_version_cls=SubsectionVersion,
@@ -177,7 +176,7 @@ def create_subsection_and_version(
177176
created_by: The user who created the subsection.
178177
can_stand_alone: Set to False when created as part of containers
179178
"""
180-
publishable_entities_pks, entity_version_pks = _pub_entities_for_units(units)
179+
entity_rows = _pub_entities_for_units(units)
181180
with atomic():
182181
subsection = create_subsection(
183182
learning_package_id,
@@ -190,8 +189,7 @@ def create_subsection_and_version(
190189
subsection,
191190
1,
192191
title=title,
193-
publishable_entities_pks=publishable_entities_pks or [],
194-
entity_version_pks=entity_version_pks or [],
192+
entity_rows=entity_rows or [],
195193
created=created,
196194
created_by=created_by,
197195
)
@@ -286,7 +284,9 @@ def get_units_in_published_subsection_as_of(
286284
ancestors of every modified PublishableEntity in the publish.
287285
"""
288286
assert isinstance(subsection, Subsection)
289-
subsection_pub_entity_version = publishing_api.get_published_version_as_of(subsection.publishable_entity_id, publish_log_id)
287+
subsection_pub_entity_version = publishing_api.get_published_version_as_of(
288+
subsection.publishable_entity_id, publish_log_id
289+
)
290290
if subsection_pub_entity_version is None:
291291
return None # This subsection was not published as of the given PublishLog ID.
292292
container_version = subsection_pub_entity_version.containerversion
@@ -303,5 +303,7 @@ def get_units_in_published_subsection_as_of(
303303
# This is not optimized. It could be done in one query per subsection rather than one query per unit.
304304
pub_entity_version = publishing_api.get_published_version_as_of(row.entity_id, publish_log_id)
305305
if pub_entity_version:
306-
entity_list.append(SubsectionListEntry(unit_version=pub_entity_version.containerversion.unitversion, pinned=False))
306+
entity_list.append(
307+
SubsectionListEntry(unit_version=pub_entity_version.containerversion.unitversion, pinned=False)
308+
)
307309
return entity_list

openedx_learning/apps/authoring/subsections/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Models that implement units
2+
Models that implement subsections
33
"""
44
from django.db import models
55

tests/openedx_learning/apps/authoring/subsections/test_api.py

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""
2-
Basic tests for the units API.
2+
Basic tests for the subsections API.
33
"""
4+
from unittest.mock import patch
5+
46
import ddt # type: ignore[import]
57
import pytest
68
from django.core.exceptions import ValidationError
@@ -180,7 +182,7 @@ def test_create_subsection_queries(self):
180182
# The exact numbers here aren't too important - this is just to alert us if anything significant changes.
181183
with self.assertNumQueries(22):
182184
_empty_subsection = self.create_subsection_with_units([])
183-
with self.assertNumQueries(26):
185+
with self.assertNumQueries(27):
184186
# And try with a non-empty subsection:
185187
self.create_subsection_with_units([self.unit_1, self.unit_2_v1], key="u2")
186188

@@ -243,7 +245,28 @@ def test_adding_external_units(self):
243245
created_by=None,
244246
)
245247

246-
# ?FOR REVIEW
248+
@patch('openedx_learning.apps.authoring.subsections.api._pub_entities_for_units')
249+
def test_adding_mismatched_versions(self, mock_entities_for_units):
250+
"""
251+
Test that versioned units must match their entities.
252+
"""
253+
mock_entities_for_units.return_value = [
254+
authoring_api.ContainerEntityRow(
255+
entity_pk=self.unit_1.pk,
256+
version_pk=self.unit_2_v1.pk,
257+
),
258+
]
259+
# Try adding a a unit from LP 1 (self.learning_package) to a subsection from LP 2
260+
with pytest.raises(ValidationError, match="Container entity versions must belong to the specified entity"):
261+
authoring_api.create_subsection_and_version(
262+
learning_package_id=self.unit_1.container.publishable_entity.learning_package.pk,
263+
key="subsection:key",
264+
title="Subsection",
265+
units=[self.unit_1],
266+
created=self.now,
267+
created_by=None,
268+
)
269+
247270
@ddt.data(True, False)
248271
@pytest.mark.skip(reason="FIXME: This test is failing because the publishable_entity is not deleted from the database with the unit.")
249272
# FIXME: Also, exception is Container.DoesNotExist, not Unit.DoesNotExist
@@ -360,7 +383,9 @@ def test_auto_publish_children(self):
360383
# Publish ONLY the subsection. This should however also auto-publish units 1 & 2 since they're children
361384
authoring_api.publish_from_drafts(
362385
self.learning_package.pk,
363-
draft_qset=authoring_api.get_all_drafts(self.learning_package.pk).filter(entity=subsection.publishable_entity),
386+
draft_qset=authoring_api.get_all_drafts(self.learning_package.pk).filter(
387+
entity=subsection.publishable_entity
388+
),
364389
)
365390
# Now all changes to the subsection and to unit 1 are published:
366391
subsection.refresh_from_db()
@@ -976,7 +1001,9 @@ def test_subsections_containing(self):
9761001
with self.assertNumQueries(1):
9771002
result2 = [
9781003
c.subsection for c in
979-
authoring_api.get_containers_with_entity(self.unit_1.pk, ignore_pinned=True).select_related("subsection")
1004+
authoring_api.get_containers_with_entity(
1005+
self.unit_1.pk, ignore_pinned=True
1006+
).select_related("subsection")
9801007
]
9811008
assert result2 == [subsection4_unpinned]
9821009

0 commit comments

Comments
 (0)