Skip to content

Commit

Permalink
Merge branch 'master' into fix/previewlink-language
Browse files Browse the repository at this point in the history
  • Loading branch information
fsbraun authored Nov 10, 2023
2 parents 455dafa + 97f2801 commit 5a41f0e
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Unreleased
==========
* fix: Add keyword arguments in VersionAdminMixin render_change_form
* feat: Reversable generic foreign key lookup from version
* feat: Provide additional information about unpublished/published versions when sending signals
* fix: formatted files through ruff to fix tests
* fix: Remove version check when evaluating CMS PageContent objects

Expand Down
16 changes: 11 additions & 5 deletions djangocms_versioning/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,13 +357,16 @@ def publish(self, user):
content_type=self.content_type,
)
for version in to_unpublish:
version.unpublish(user)
version.unpublish(user, to_be_published=self)
on_publish = self.versionable.on_publish
if on_publish:
on_publish(self)
# trigger post operation signal
send_post_version_operation(
constants.OPERATION_PUBLISH, version=self, token=action_token
constants.OPERATION_PUBLISH,
version=self,
token=action_token,
unpublished=list(to_unpublish),
)
if emit_content_change:
emit_content_change(self.content)
Expand Down Expand Up @@ -391,11 +394,11 @@ def _set_publish(self, user):
def can_be_unpublished(self):
return can_proceed(self._set_unpublish)

def unpublish(self, user):
def unpublish(self, user, to_be_published=None):
"""Change state to UNPUBLISHED"""
# trigger pre operation signal
action_token = send_pre_version_operation(
constants.OPERATION_UNPUBLISH, version=self
constants.OPERATION_UNPUBLISH, version=self, to_be_published=to_be_published
)
self._set_unpublish(user)
self.modified = timezone.now()
Expand All @@ -411,7 +414,10 @@ def unpublish(self, user):
on_unpublish(self)
# trigger post operation signal
send_post_version_operation(
constants.OPERATION_UNPUBLISH, version=self, token=action_token
constants.OPERATION_UNPUBLISH,
version=self,
token=action_token,
to_be_published=to_be_published,
)
if emit_content_change:
emit_content_change(self.content)
Expand Down
15 changes: 15 additions & 0 deletions docs/api/signals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,18 @@ The CMS used to provide page publish and unpublish signals which have since been
# ... do something
Handling the effect of a (un-)publish to other items via signals
----------------------------------------------------------------

Events often times do not happen in isolation.
A publish signal indicates a publish of an item but it also means that potentially other items are unpublished as part of the same action, also triggering unpublish signals.
To be able to react accordingly, information is added to the publish signal which other items were potentially unpublished as part of this action (`unpublished`) and information is also added to the unpublish singal which other items are going to get published (`to_be_published`).
This information allows you to differentiate if an item is published for the first time - because nothing is unpublished - or if it is just a new version of an existing item.

For example, the differentiation can be benefitial if you integrate with other services like Elasticsearch and you want to update the Elasticsearch index via signals. You can get in the following situations:
- Publish signal with no unpublished item results in a new entry in the index.
- Publish signal with at least one unpublished item results in an update of an existing entry in the index.
- Unpublish singal with no to be published items results in the removal of the entry from the index.
- Unpublish signal with a to be published item results in the update on an existing entry in the index but will be handled in the corresponding publish signal and can be ignored.

All those situations are distinct, require different information, and can be handled according to requirements.
25 changes: 25 additions & 0 deletions tests/test_signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,31 @@ def test_publish_signals_fired(self):
)
self.assertEqual(post_call_kwargs["obj"], version)


def test_publish_signals_fired_with_to_be_published_and_unpublished(self):
poll = factories.PollFactory()
version1 = factories.PollVersionFactory(
state=constants.DRAFT, content__poll=poll
)
version2 = version1.copy(self.superuser)

# Here, we just expect the signals for version 1
with signal_tester(pre_version_operation, post_version_operation) as env:
version1.publish(self.superuser)
self.assertEqual(env.call_count, 2)

# Here, we expect the signals for the unpublish of version 1 and the
# publish of version 2.
with signal_tester(pre_version_operation, post_version_operation) as env:
version2.publish(self.superuser)
self.assertEqual(env.call_count, 4)
version_1_pre_call_kwargs = env.calls[1][1]
version_2_post_call_kwargs = env.calls[3][1]

self.assertEqual(version_1_pre_call_kwargs["to_be_published"], version2)
self.assertEqual(version_2_post_call_kwargs["unpublished"], [version1])


def test_unpublish_signals_fired(self):
"""
When a version is changed to unpublished the correct signals are fired!
Expand Down

0 comments on commit 5a41f0e

Please sign in to comment.