From b189f61fbfffe6998e899a72520fc019a3782ef9 Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Mon, 9 Dec 2024 19:58:28 +0530 Subject: [PATCH] feat: api to restore soft-deleted component --- .../core/djangoapps/content_libraries/api.py | 32 +++++++++++++++++++ .../core/djangoapps/content_libraries/urls.py | 1 + .../djangoapps/content_libraries/views.py | 16 ++++++++++ 3 files changed, 49 insertions(+) diff --git a/openedx/core/djangoapps/content_libraries/api.py b/openedx/core/djangoapps/content_libraries/api.py index 5195826468c2..1f771600a9e3 100644 --- a/openedx/core/djangoapps/content_libraries/api.py +++ b/openedx/core/djangoapps/content_libraries/api.py @@ -1133,6 +1133,38 @@ def delete_library_block(usage_key, remove_from_parent=True): ) +def restore_library_block(usage_key): + """ + Restore the specified library block. + """ + component = get_component_from_usage_key(usage_key) + library_key = usage_key.context_key + affected_collections = authoring_api.get_entity_collections(component.learning_package_id, component.key) + + # Set draft version back to the latest available component version id. + authoring_api.set_draft_version(component.pk, component.versioning.latest.pk) + + LIBRARY_BLOCK_CREATED.send_event( + library_block=LibraryBlockData( + library_key=library_key, + usage_key=usage_key + ) + ) + + # For each collection, trigger LIBRARY_COLLECTION_UPDATED signal and set background=True to trigger + # collection indexing asynchronously. + # + # To delete the component on collections + for collection in affected_collections: + LIBRARY_COLLECTION_UPDATED.send_event( + library_collection=LibraryCollectionData( + library_key=library_key, + collection_key=collection.key, + background=True, + ) + ) + + def get_library_block_static_asset_files(usage_key) -> list[LibraryXBlockStaticFile]: """ Given an XBlock in a content library, list all the static asset files diff --git a/openedx/core/djangoapps/content_libraries/urls.py b/openedx/core/djangoapps/content_libraries/urls.py index 857126eef7c9..1272d79b3873 100644 --- a/openedx/core/djangoapps/content_libraries/urls.py +++ b/openedx/core/djangoapps/content_libraries/urls.py @@ -57,6 +57,7 @@ path('blocks//', include([ # Get metadata about a specific XBlock in this library, or delete the block: path('', views.LibraryBlockView.as_view()), + path('restore/', views.LibraryBlockRestore.as_view()), # Update collections for a given component path('collections/', views.LibraryBlockCollectionsView.as_view(), name='update-collections'), # Get the LTI URL of a specific XBlock diff --git a/openedx/core/djangoapps/content_libraries/views.py b/openedx/core/djangoapps/content_libraries/views.py index 3dc7f538df86..94197f508775 100644 --- a/openedx/core/djangoapps/content_libraries/views.py +++ b/openedx/core/djangoapps/content_libraries/views.py @@ -644,6 +644,22 @@ def delete(self, request, usage_key_str): # pylint: disable=unused-argument return Response({}) +@view_auth_classes() +class LibraryBlockRestore(APIView): + """ + View to restore soft-deleted library xblocks. + """ + @convert_exceptions + def post(self, request, usage_key_str) -> Response: + """ + Restores a soft-deleted library block that belongs to a Content Library + """ + key = LibraryUsageLocatorV2.from_string(usage_key_str) + api.require_permission_for_library_key(key.lib_key, request.user, permissions.CAN_EDIT_THIS_CONTENT_LIBRARY) + api.restore_library_block(key) + return Response(None, status=status.HTTP_204_NO_CONTENT) + + @method_decorator(non_atomic_requests, name="dispatch") @view_auth_classes() class LibraryBlockCollectionsView(APIView):