Skip to content

Commit 67e0e34

Browse files
committed
feat: adds python and REST APIs to delete a container
1 parent 6a16e8b commit 67e0e34

4 files changed

Lines changed: 72 additions & 1 deletion

File tree

openedx/core/djangoapps/content_libraries/api/containers.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from openedx_events.content_authoring.data import LibraryContainerData
1717
from openedx_events.content_authoring.signals import (
1818
LIBRARY_CONTAINER_CREATED,
19+
LIBRARY_CONTAINER_DELETED,
1920
LIBRARY_CONTAINER_UPDATED,
2021
)
2122
from openedx_learning.api import authoring as authoring_api
@@ -34,6 +35,7 @@
3435
"get_container_children",
3536
"library_container_locator",
3637
"update_container",
38+
"delete_container",
3739
]
3840

3941

@@ -209,6 +211,27 @@ def update_container(
209211
return ContainerMetadata.from_container(library_key, unit_version.container)
210212

211213

214+
def delete_container(
215+
container_key: LibraryContainerLocator,
216+
) -> None:
217+
"""
218+
Delete a container (e.g. a Unit) (soft delete).
219+
"""
220+
container = _get_container(container_key)
221+
library_key = container_key.library_key
222+
223+
authoring_api.soft_delete_draft(container.pk)
224+
225+
LIBRARY_CONTAINER_DELETED.send_event(
226+
library_container=LibraryContainerData(
227+
library_key=library_key,
228+
container_key=str(container_key),
229+
)
230+
)
231+
232+
# TODO: trigger a LIBRARY_COLLECTION_UPDATED for each collection the container was in
233+
234+
212235
def get_container_children(
213236
container_key: LibraryContainerLocator,
214237
published=False,

openedx/core/djangoapps/content_libraries/rest_api/containers.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,20 @@ def patch(self, request, container_key: LibraryContainerLocator):
106106
)
107107

108108
return Response(serializers.LibraryContainerMetadataSerializer(container).data)
109+
110+
@convert_exceptions
111+
def delete(self, request, container_key: LibraryContainerLocator):
112+
"""
113+
Delete a Container (soft delete).
114+
"""
115+
api.require_permission_for_library_key(
116+
container_key.library_key,
117+
request.user,
118+
permissions.CAN_EDIT_THIS_CONTENT_LIBRARY,
119+
)
120+
121+
api.delete_container(
122+
container_key,
123+
)
124+
125+
return Response({})

openedx/core/djangoapps/content_libraries/tests/base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,3 +368,7 @@ def _update_container(self, container_key: str, display_name: str, expect_respon
368368
""" Update a container (unit etc.) """
369369
data = {"display_name": display_name}
370370
return self._api('patch', URL_LIB_CONTAINER.format(container_key=container_key), data, expect_response)
371+
372+
def _delete_container(self, container_key: str, expect_response=200):
373+
""" Delete a container (unit etc.) """
374+
return self._api('delete', URL_LIB_CONTAINER.format(container_key=container_key), None, expect_response)

openedx/core/djangoapps/content_libraries/tests/test_containers.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99

1010
from opaque_keys.edx.locator import LibraryLocatorV2
1111
from openedx_events.content_authoring.data import LibraryContainerData
12-
from openedx_events.content_authoring.signals import LIBRARY_CONTAINER_CREATED, LIBRARY_CONTAINER_UPDATED
12+
from openedx_events.content_authoring.signals import (
13+
LIBRARY_CONTAINER_CREATED,
14+
LIBRARY_CONTAINER_DELETED,
15+
LIBRARY_CONTAINER_UPDATED,
16+
)
1317
from openedx_events.tests.utils import OpenEdxEventsTestMixin
1418

1519
from openedx.core.djangoapps.content_libraries.tests.base import ContentLibrariesRestApiTest
@@ -38,6 +42,7 @@ class ContainersTestCase(OpenEdxEventsTestMixin, ContentLibrariesRestApiTest):
3842
"""
3943
ENABLED_OPENEDX_EVENTS = [
4044
LIBRARY_CONTAINER_CREATED.event_type,
45+
LIBRARY_CONTAINER_DELETED.event_type,
4146
LIBRARY_CONTAINER_UPDATED.event_type,
4247
]
4348

@@ -54,6 +59,9 @@ def test_unit_crud(self):
5459
update_receiver = mock.Mock()
5560
LIBRARY_CONTAINER_UPDATED.connect(update_receiver)
5661

62+
delete_receiver = mock.Mock()
63+
LIBRARY_CONTAINER_DELETED.connect(delete_receiver)
64+
5765
# Create a unit:
5866
create_date = datetime(2024, 9, 8, 7, 6, 5, tzinfo=timezone.utc)
5967
with freeze_time(create_date):
@@ -117,6 +125,25 @@ def test_unit_crud(self):
117125
# make sure it contains the same data when we read it back:
118126
self.assertDictContainsEntries(unit_as_re_read, expected_data)
119127

128+
# Delete the unit
129+
self._delete_container(container_data["container_key"])
130+
assert delete_receiver.call_count == 1
131+
self.assertDictContainsSubset(
132+
{
133+
"signal": LIBRARY_CONTAINER_DELETED,
134+
"sender": None,
135+
"library_container": LibraryContainerData(
136+
lib_key,
137+
container_key="lct:CL-TEST:containers:unit:u1",
138+
),
139+
},
140+
delete_receiver.call_args_list[0].kwargs,
141+
)
142+
143+
# Make sure it's gone
144+
deleted = self._get_container(container_data["container_key"], expect_response=404)
145+
assert deleted is None
146+
120147
# TODO: test that a regular user with read-only permissions on the library cannot create units
121148

122149
def test_unit_gets_auto_slugs(self):

0 commit comments

Comments
 (0)