diff --git a/openedx_learning/__init__.py b/openedx_learning/__init__.py index 1521ec581..23b5c7c22 100644 --- a/openedx_learning/__init__.py +++ b/openedx_learning/__init__.py @@ -2,4 +2,4 @@ Open edX Learning ("Learning Core"). """ -__version__ = "0.16.3" +__version__ = "0.17.0" diff --git a/openedx_learning/apps/authoring/collections/api.py b/openedx_learning/apps/authoring/collections/api.py index 07b7a2eaf..8119ac060 100644 --- a/openedx_learning/apps/authoring/collections/api.py +++ b/openedx_learning/apps/authoring/collections/api.py @@ -9,8 +9,8 @@ from django.db.models import QuerySet from ..publishing import api as publishing_api -from ..publishing.models import PublishableEntity -from .models import Collection +from ..publishing.models import PublishableEntity, Published +from .models import Collection, CollectionPublishableEntity # The public API that will be re-exported by openedx_learning.apps.authoring.api # is listed in the __all__ entries below. Internal helper functions that are @@ -27,6 +27,7 @@ "remove_from_collection", "restore_collection", "update_collection", + "remove_unpublished_from_collections", ] @@ -204,3 +205,38 @@ def get_collections(learning_package_id: int, enabled: bool | None = True) -> Qu if enabled is not None: qs = qs.filter(enabled=enabled) return qs.select_related("learning_package").order_by('pk') + + +def remove_unpublished_from_collections(learning_package_id: int) -> None: + """ + Removes all unpublished entities from collections for a + given learning package. + + One use case for this function is when reverting a library to published version. + If a collection of a library has unpublished entities and the library is reverted + to the published version, the unpublished entities need to be removed + to reflect the published state of the library. + """ + collections = get_collections(learning_package_id) + + all_entities = CollectionPublishableEntity.objects.filter( + collection__learning_package__id=learning_package_id + ).values_list('entity_id', flat=True) + + entities_with_version = Published.objects.select_related("version").filter( + entity_id__in=all_entities + ).values_list('entity_id', flat=True) + + for collection in collections: + entities_for_remove = [] + + for entity in collection.entities.all(): + if entity.id not in entities_with_version: + entities_for_remove.append(entity.id) + + if entities_for_remove: + remove_from_collection( + learning_package_id, + collection.key, + PublishableEntity.objects.filter(id__in=entities_for_remove) + ) diff --git a/tests/openedx_learning/apps/authoring/collections/test_api.py b/tests/openedx_learning/apps/authoring/collections/test_api.py index 179869a34..736bc8d3a 100644 --- a/tests/openedx_learning/apps/authoring/collections/test_api.py +++ b/tests/openedx_learning/apps/authoring/collections/test_api.py @@ -405,6 +405,22 @@ def test_get_collection_components(self): self.collection3.key, )) + def test_remove_unpublished_components(self): + api.remove_unpublished_from_collections(self.learning_package.id) + + assert list(api.get_collection_components( + self.learning_package.id, + self.collection1.key, + )) == [self.published_component] + assert list(api.get_collection_components( + self.learning_package.id, + self.collection2.key, + )) == [self.published_component] + assert not list(api.get_collection_components( + self.learning_package.id, + self.collection3.key, + )) + class UpdateCollectionTestCase(CollectionTestCase): """