diff --git a/docs/reference/hooks.rst b/docs/reference/hooks.rst index 26241d770e..6cd06c272b 100644 --- a/docs/reference/hooks.rst +++ b/docs/reference/hooks.rst @@ -614,6 +614,31 @@ Hooks for customising the way users are directed through the process of creating Uses the same behaviour as ``before_create_page``. + +.. _before_convert_alias_page: + +``before_convert_alias_page`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Called at the beginning of the ``convert_alias`` view, which is responsible for converting alias pages into normal Wagtail pages. + + The request and the page being converted are passed in as arguments to the hook. + + 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_convert_alias_page: + +``after_convert_alias_page`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Do something with a ``Page`` object after it has been converted from an alias. + + The request and the page that was just converted are passed in as arguments to the hook. + + 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. + + .. _register_page_action_menu_item: ``register_page_action_menu_item`` diff --git a/wagtail/admin/templates/wagtailadmin/pages/confirm_convert_alias.html b/wagtail/admin/templates/wagtailadmin/pages/confirm_convert_alias.html new file mode 100644 index 0000000000..8af778c9b3 --- /dev/null +++ b/wagtail/admin/templates/wagtailadmin/pages/confirm_convert_alias.html @@ -0,0 +1,25 @@ +{% extends "wagtailadmin/base.html" %} +{% load i18n wagtailadmin_tags %} +{% block titletag %}{% blocktrans with title=page.get_admin_display_title %}Convert alias {{ title }}{% endblocktrans %}{% endblock %} + +{% block content %} + {% trans "Convert alias" as del_str %} + {% include "wagtailadmin/shared/header.html" with title=del_str subtitle=page.get_admin_display_title icon="doc-empty-inverse" %} + +
+ {% trans 'Are you sure you want to convert this alias into a regular page?' %} +
+ ++ {% trans 'This action cannot be undone.' %} +
+ + +{% trans "Edit original page" %} - {% trans "Edit this page only (remove alias)" %} + + {% url 'wagtailadmin_pages:edit' page.id as this_url %} + {% trans "Convert this alias into a regular page" %}
{% endblock %} diff --git a/wagtail/admin/tests/pages/test_convert_alias.py b/wagtail/admin/tests/pages/test_convert_alias.py new file mode 100644 index 0000000000..ee9d0a01a8 --- /dev/null +++ b/wagtail/admin/tests/pages/test_convert_alias.py @@ -0,0 +1,69 @@ +import json + +from django.contrib.auth.models import Permission +from django.test import TestCase +from django.urls import reverse + +from wagtail.core.models import Page, PageLogEntry +from wagtail.tests.testapp.models import SimplePage +from wagtail.tests.utils import WagtailTestUtils + + +class TestConvertAlias(TestCase, WagtailTestUtils): + def setUp(self): + # Find root page + self.root_page = Page.objects.get(id=2) + + # Add child page + self.child_page = SimplePage(title="Hello world!", slug="hello-world", content="hello") + self.root_page.add_child(instance=self.child_page) + + # Add alias page + self.alias_page = self.child_page.create_alias(update_slug='alias-page') + + # Login + self.user = self.login() + + def test_convert_alias(self): + response = self.client.get(reverse('wagtailadmin_pages:convert_alias', args=[self.alias_page.id])) + self.assertEqual(response.status_code, 200) + + def test_convert_alias_not_alias(self): + response = self.client.get(reverse('wagtailadmin_pages:convert_alias', args=[self.child_page.id])) + self.assertEqual(response.status_code, 404) + + def test_convert_alias_bad_permission(self): + # Remove privileges from user + self.user.is_superuser = False + self.user.user_permissions.add( + Permission.objects.get(content_type__app_label='wagtailadmin', codename='access_admin') + ) + self.user.save() + + response = self.client.get(reverse('wagtailadmin_pages:convert_alias', args=[self.alias_page.id])) + + # Check that the user received a 403 response + self.assertEqual(response.status_code, 403) + + def test_post_convert_alias(self): + response = self.client.post(reverse('wagtailadmin_pages:convert_alias', args=[self.alias_page.id])) + + # User should be redirected to the edit view of the converted page + self.assertRedirects(response, reverse('wagtailadmin_pages:edit', args=[self.alias_page.id])) + + # Check the page was converted + self.alias_page.refresh_from_db() + self.assertIsNone(self.alias_page.alias_of) + + # Check that a revision was created + revision = self.alias_page.revisions.get() + self.assertEqual(revision.user, self.user) + self.assertEqual(self.alias_page.live_revision, revision) + + # Check audit log + log = PageLogEntry.objects.get(action='wagtail.convert_alias') + self.assertFalse(log.content_changed) + self.assertEqual(json.loads(log.data_json), {"page": {"id": self.alias_page.id, "title": self.alias_page.get_admin_display_title()}}) + self.assertEqual(log.page, self.alias_page.page_ptr) + self.assertEqual(log.revision, revision) + self.assertEqual(log.user, self.user) diff --git a/wagtail/admin/urls/pages.py b/wagtail/admin/urls/pages.py index c8ab1a719e..388b010288 100644 --- a/wagtail/admin/urls/pages.py +++ b/wagtail/admin/urls/pages.py @@ -2,9 +2,8 @@ from django.urls import path, re_path from wagtail.admin.views import page_privacy from wagtail.admin.views.pages import ( - copy, create, delete, edit, history, lock, moderation, move, ordering, preview, - revisions, search, unpublish, usage, workflow -) + convert_alias, copy, create, delete, edit, history, lock, moderation, move, ordering, preview, + revisions, search, unpublish, usage, workflow) app_name = 'wagtailadmin_pages' urlpatterns = [ @@ -19,6 +18,7 @@ urlpatterns = [ path('