Skip to content

Commit 6482bf4

Browse files
committed
feat: adds python and REST APIs to delete a container
1 parent 3caa777 commit 6482bf4

File tree

5 files changed

+79
-1
lines changed

5 files changed

+79
-1
lines changed

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

Lines changed: 27 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
@@ -35,6 +36,7 @@
3536
"get_container_children",
3637
"library_container_locator",
3738
"update_container",
39+
"delete_container",
3840
]
3941

4042

@@ -218,6 +220,31 @@ def update_container(
218220
return ContainerMetadata.from_container(library_key, unit_version.container)
219221

220222

223+
def delete_container(
224+
container_key: LibraryContainerLocator,
225+
) -> None:
226+
"""
227+
Delete a container (e.g. a Unit) (soft delete).
228+
229+
No-op if container doesn't exist or has already been soft-deleted.
230+
"""
231+
try:
232+
container = _get_container(container_key)
233+
except ContentLibraryContainerNotFound:
234+
return
235+
236+
authoring_api.soft_delete_draft(container.pk)
237+
238+
LIBRARY_CONTAINER_DELETED.send_event(
239+
library_container=LibraryContainerData(
240+
library_key=container_key.library_key,
241+
container_key=str(container_key),
242+
)
243+
)
244+
245+
# TODO: trigger a LIBRARY_COLLECTION_UPDATED for each collection the container was in
246+
247+
221248
def get_container_children(
222249
container_key: LibraryContainerLocator,
223250
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/rest_api/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ def wrapped_fn(*args, **kwargs):
3434
except api.ContentLibraryCollectionNotFound:
3535
log.exception("Collection not found in content library")
3636
raise NotFound # lint-amnesty, pylint: disable=raise-missing-from
37+
except api.ContentLibraryContainerNotFound:
38+
log.exception("Container not found in content library")
39+
raise NotFound # lint-amnesty, pylint: disable=raise-missing-from
3740
except api.LibraryCollectionAlreadyExists as exc:
3841
log.exception(str(exc))
3942
raise ValidationError(str(exc)) # lint-amnesty, pylint: disable=raise-missing-from

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)