Add publish & unpublish page hooks

* Add `before_unpublish_page` and `before_unpublish_page` hooks
* Add `before_publish_page` and `before_publish_page` hooks
* Resolves #4590
pull/4922/head
Jonatas Baldin 2018-06-08 00:40:05 +02:00 zatwierdzone przez LB
rodzic b98e6d7549
commit a7f58821a7
8 zmienionych plików z 210 dodań i 0 usunięć

Wyświetl plik

@ -14,6 +14,7 @@ Changelog
* Add `pre_page_move` and `post_page_move` signals (Andy Babic)
* Add ability to sort search promotions on listing page (Chris Ranjana, LB (Ben Johnston))
* Upgrade internal JS tooling to Gulp v4 & Node v10 (Jim Jazwiecki, Kim LaRocca)
* Add `after_publish_page`, `before_publish_page`, `after_unpublish_page` & `before_unpublish_page` hooks (Jonatas Baldin, Coen van der Kamp)
* Fix: Support IPv6 domain (Alex Gleason, Coen van der Kamp)
* Fix: Ensure link to add a new user works when no users are visible in the users list (LB (Ben Johnston))
* Fix: `AbstractEmailForm` saved submission fields are now aligned with the email content fields, `form.cleaned_data` will be used instead of `form.fields` (Haydn Greatnews)

Wyświetl plik

@ -454,6 +454,7 @@ Contributors
* François Poulain
* Jim Jazwiecki
* Kim LaRocca
* Jonatas Baldin
Translators
===========

Wyświetl plik

@ -505,6 +505,46 @@ Hooks for customising the way users are directed through the process of creating
Uses the same behaviour as ``before_create_page``.
.. _after_publish_page:
``after_publish_page``
~~~~~~~~~~~~~~~~~~~~~~~~
Do something with a ``Page`` object after it has been published via page create view or page edit view.
The function does not have to return anything, but if an object with a ``status_code`` property is returned, Wagtail will use it as a response object and skip the rest of the view.
.. _before_publish_page:
``before_publish_page``
~~~~~~~~~~~~~~~~~~~~~~~~~
Do something with a ``Page`` object before it has been published via page create view or page edit view.
The function does not have to return anything, but if an object with a ``status_code`` property is returned, Wagtail will use it as a response object and skip the rest of the view.
.. _after_unpublish_page:
``after_unpublish_page``
~~~~~~~~~~~~~~~~~~~~~~~~
Called after unpublish action in "unpublish" view passing in the request and the page object.
The function does not have to return anything, but if an object with a ``status_code`` property is returned, Wagtail will use it as a response object and skip the rest of the view.
.. _before_unpublish_page:
``before_unpublish_page``
~~~~~~~~~~~~~~~~~~~~~~~~~
Called before unpublish action in "unpublish" view passing in the request and the page object.
The function does not have to return anything, but if an object with a ``status_code`` property is returned, Wagtail will use it as a response object and skip the rest of the view.
.. _after_copy_page:
``after_copy_page``

Wyświetl plik

@ -23,6 +23,7 @@ Other features
* Add ``pre_page_move`` and ``post_page_move`` signals. (Andy Babic)
* Add ability to sort search promotions on listing page (Chris Ranjana, LB (Ben Johnston))
* Upgrade internal JS tooling to Gulp v4 & Node v10 (Jim Jazwiecki, Kim LaRocca)
* Add ``after_publish_page``, ``before_publish_page``, ``after_unpublish_page`` & ``before_unpublish_page`` hooks (Jonatas Baldin, Coen van der Kamp)
Bug fixes

Wyświetl plik

@ -9,6 +9,7 @@ from django.test import TestCase
from django.test.utils import override_settings
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from wagtail.admin.tests.pages.timestamps import submittable_timestamp
from wagtail.core.models import GroupPagePermission, Page, PageRevision
@ -667,6 +668,54 @@ class TestPageCreation(TestCase, WagtailTestUtils):
# page should be created
self.assertTrue(Page.objects.filter(title="New page!").exists())
def test_after_publish_page(self):
def hook_func(request, page):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(page.title, "New page!")
return HttpResponse("Overridden!")
with self.register_hook("after_publish_page", hook_func):
post_data = {
"title": "New page!",
"content": "Some content",
"slug": "hello-world",
"action-publish": "Publish",
}
response = self.client.post(
reverse("wagtailadmin_pages:add", args=("tests", "simplepage", self.root_page.id)),
post_data
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
self.root_page.refresh_from_db()
self.assertEqual(self.root_page.get_children()[0].status_string, _("live"))
def test_before_publish_page(self):
def hook_func(request, page):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(page.title, "New page!")
return HttpResponse("Overridden!")
with self.register_hook("before_publish_page", hook_func):
post_data = {
"title": "New page!",
"content": "Some content",
"slug": "hello-world",
"action-publish": "Publish",
}
response = self.client.post(
reverse("wagtailadmin_pages:add", args=("tests", "simplepage", self.root_page.id)),
post_data
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
self.root_page.refresh_from_db()
self.assertEqual(self.root_page.get_children()[0].status_string, _("live + draft"))
def test_display_moderation_button_by_default(self):
"""
Tests that by default the "Submit for Moderation" button is shown in the action menu.

Wyświetl plik

@ -11,6 +11,7 @@ from django.http import HttpRequest, HttpResponse
from django.test import TestCase, modify_settings, override_settings
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from wagtail.admin.tests.pages.timestamps import submittable_timestamp
from wagtail.core.models import Page, PageRevision, Site
@ -884,6 +885,52 @@ class TestPageEdit(TestCase, WagtailTestUtils):
# page should be edited
self.assertEqual(Page.objects.get(id=self.child_page.id).title, "I've been edited!")
def test_after_publish_page(self):
def hook_func(request, page):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(page.id, self.child_page.id)
return HttpResponse("Overridden!")
with self.register_hook("after_publish_page", hook_func):
post_data = {
'title': "I've been edited!",
'content': "Some content",
'slug': 'hello-world-new',
'action-publish': "Publish",
}
response = self.client.post(
reverse('wagtailadmin_pages:edit', args=(self.child_page.id, )), post_data
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
self.child_page.refresh_from_db()
self.assertEqual(self.child_page.status_string, _("live"))
def test_before_publish_page(self):
def hook_func(request, page):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(page.id, self.child_page.id)
return HttpResponse("Overridden!")
with self.register_hook("before_publish_page", hook_func):
post_data = {
'title': "I've been edited!",
'content': "Some content",
'slug': 'hello-world-new',
'action-publish': "Publish",
}
response = self.client.post(
reverse('wagtailadmin_pages:edit', args=(self.child_page.id, )), post_data
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
self.child_page.refresh_from_db()
self.assertEqual(self.child_page.status_string, _("live + draft"))
def test_override_default_action_menu_item(self):
def hook_func(menu_items, request, context):
for (index, item) in enumerate(menu_items):

Wyświetl plik

@ -1,8 +1,10 @@
from unittest import mock
from django.contrib.auth.models import Permission
from django.http import HttpRequest, HttpResponse
from django.test import TestCase
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from wagtail.core.models import Page
from wagtail.core.signals import page_unpublished
@ -87,6 +89,45 @@ class TestPageUnpublish(TestCase, WagtailTestUtils):
self.assertEqual(mock_call['instance'], self.page)
self.assertIsInstance(mock_call['instance'], self.page.specific_class)
def test_after_unpublish_page(self):
def hook_func(request, page):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(page.id, self.page.id)
return HttpResponse("Overridden!")
with self.register_hook('after_unpublish_page', hook_func):
post_data = {}
response = self.client.post(
reverse('wagtailadmin_pages:unpublish', args=(self.page.id, )), post_data
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
self.page.refresh_from_db()
self.assertEqual(self.page.status_string, _("draft"))
def test_before_unpublish_page(self):
def hook_func(request, page):
self.assertIsInstance(request, HttpRequest)
self.assertEqual(page.id, self.page.id)
return HttpResponse("Overridden!")
with self.register_hook('before_unpublish_page', hook_func):
post_data = {}
response = self.client.post(
reverse('wagtailadmin_pages:unpublish', args=(self.page.id, )), post_data
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"Overridden!")
# The hook response is served before unpublish is called.
self.page.refresh_from_db()
self.assertEqual(self.page.status_string, _("live"))
def test_unpublish_descendants_view(self):
"""
This tests that the unpublish view responds with an unpublish confirm page that does not contain the form field 'include_descendants'

Wyświetl plik

@ -243,8 +243,18 @@ def create(request, content_type_app_name, content_type_model_name, parent_page_
# Publish
if is_publishing:
for fn in hooks.get_hooks('before_publish_page'):
result = fn(request, page)
if hasattr(result, 'status_code'):
return result
revision.publish()
for fn in hooks.get_hooks('after_publish_page'):
result = fn(request, page)
if hasattr(result, 'status_code'):
return result
# Notifications
if is_publishing:
if page.go_live_at and page.go_live_at > timezone.now():
@ -399,11 +409,21 @@ def edit(request, page_id):
# Publish
if is_publishing:
for fn in hooks.get_hooks('before_publish_page'):
result = fn(request, page)
if hasattr(result, 'status_code'):
return result
revision.publish()
# Need to reload the page because the URL may have changed, and we
# need the up-to-date URL for the "View Live" button.
page = page.specific_class.objects.get(pk=page.pk)
for fn in hooks.get_hooks('after_publish_page'):
result = fn(request, page)
if hasattr(result, 'status_code'):
return result
# Notifications
if is_publishing:
if go_live_at and go_live_at > timezone.now():
@ -738,6 +758,11 @@ def unpublish(request, page_id):
if request.method == 'POST':
include_descendants = request.POST.get("include_descendants", False)
for fn in hooks.get_hooks('before_unpublish_page'):
result = fn(request, page)
if hasattr(result, 'status_code'):
return result
page.unpublish()
if include_descendants:
@ -746,6 +771,11 @@ def unpublish(request, page_id):
if user_perms.for_page(live_descendant_page).can_unpublish():
live_descendant_page.unpublish()
for fn in hooks.get_hooks('after_unpublish_page'):
result = fn(request, page)
if hasattr(result, 'status_code'):
return result
messages.success(request, _("Page '{0}' unpublished.").format(page.get_admin_display_title()), buttons=[
messages.button(reverse('wagtailadmin_pages:edit', args=(page.id,)), _('Edit'))
])