diff --git a/openedx_learning/__init__.py b/openedx_learning/__init__.py index 23b5c7c2..f99dcab8 100644 --- a/openedx_learning/__init__.py +++ b/openedx_learning/__init__.py @@ -2,4 +2,4 @@ Open edX Learning ("Learning Core"). """ -__version__ = "0.17.0" +__version__ = "0.18.0" diff --git a/openedx_learning/apps/authoring/publishing/api.py b/openedx_learning/apps/authoring/publishing/api.py index 7e2c6ba9..3facc891 100644 --- a/openedx_learning/apps/authoring/publishing/api.py +++ b/openedx_learning/apps/authoring/publishing/api.py @@ -50,6 +50,7 @@ "soft_delete_draft", "reset_drafts_to_published", "register_content_models", + "filter_publishable_entities", ] @@ -493,3 +494,22 @@ def ready(self): return PublishableContentModelRegistry.register( content_model_cls, content_version_model_cls ) + + +def filter_publishable_entities( + entities: QuerySet[PublishableEntity], + has_draft=None, + has_published=None +) -> QuerySet[PublishableEntity]: + """ + Filter an entities query set. + + has_draft: You can filter by entities that has a draft or not. + has_published: You can filter by entities that has a published version or not. + """ + if has_draft is not None: + entities = entities.filter(draft__version__isnull=not has_draft) + if has_published is not None: + entities = entities.filter(published__version__isnull=not has_published) + + return entities diff --git a/tests/openedx_learning/apps/authoring/publishing/test_api.py b/tests/openedx_learning/apps/authoring/publishing/test_api.py index 421dd66c..119a5548 100644 --- a/tests/openedx_learning/apps/authoring/publishing/test_api.py +++ b/tests/openedx_learning/apps/authoring/publishing/test_api.py @@ -368,6 +368,80 @@ def test_get_entities_with_unpublished_changes(self) -> None: # should not return published soft-deleted entities. assert len(entities) == 0 + def test_filter_publishable_entities(self) -> None: + count_published = 7 + count_drafts = 6 + count_no_drafts = 3 + + for index in range(count_published): + # Create entities to publish + entity = publishing_api.create_publishable_entity( + self.learning_package.id, + f"entity_published_{index}", + created=self.now, + created_by=None, + ) + + publishing_api.create_publishable_entity_version( + entity.id, + version_num=1, + title=f"Entity_published_{index}", + created=self.now, + created_by=None, + ) + + publishing_api.publish_all_drafts(self.learning_package.id) + + for index in range(count_drafts): + # Create entities with drafts + entity = publishing_api.create_publishable_entity( + self.learning_package.id, + f"entity_draft_{index}", + created=self.now, + created_by=None, + ) + + publishing_api.create_publishable_entity_version( + entity.id, + version_num=1, + title=f"Entity_draft_{index}", + created=self.now, + created_by=None, + ) + + for index in range(count_no_drafts): + # Create entities without drafts + entity = publishing_api.create_publishable_entity( + self.learning_package.id, + f"entity_no_draft_{index}", + created=self.now, + created_by=None, + ) + + drafts = publishing_api.filter_publishable_entities( + PublishableEntity.objects.all(), + has_draft=True, + ) + assert drafts.count() == (count_published + count_drafts) + + no_drafts = publishing_api.filter_publishable_entities( + PublishableEntity.objects.all(), + has_draft=False, + ) + assert no_drafts.count() == count_no_drafts + + published = publishing_api.filter_publishable_entities( + PublishableEntity.objects.all(), + has_published=True, + ) + assert published.count() == count_published + + no_published = publishing_api.filter_publishable_entities( + PublishableEntity.objects.all(), + has_published=False, + ) + assert no_published.count() == (count_drafts + count_no_drafts) + def _get_published_version_num(self, entity: PublishableEntity) -> int | None: published_version = publishing_api.get_published_version(entity.id) if published_version is not None: