Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Sync with source page when converting back to alias
Browse files Browse the repository at this point in the history
zerolab committed Feb 11, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent acad31d commit 7d97ecd
Showing 2 changed files with 123 additions and 19 deletions.
10 changes: 10 additions & 0 deletions wagtail_localize/tests/test_convert_to_alias.py
Original file line number Diff line number Diff line change
@@ -161,6 +161,16 @@ def test_convert(self):
self.fr_page.refresh_from_db()
self.assertEqual(self.fr_page.alias_of_id, self.page.id)

def test_convert_syncs_alias_with_source(self):
# update the source page
self.page.title = "Updated title"
self.page.save()
self.page.save_revision().publish()

self.client.post(self.convert_url)
self.fr_page.refresh_from_db()
self.assertEqual(self.fr_page.title, "Updated title")

def test_convert_adds_entry_to_audit_log(self):
self.assertFalse(
PageLogEntry.objects.filter(
132 changes: 113 additions & 19 deletions wagtail_localize/views/convert.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
from django.core.exceptions import PermissionDenied
from django.db import transaction
from django.db.models import Q
from django.http import Http404
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from django.utils.translation import gettext as _
from wagtail.admin import messages
from wagtail.admin.views.pages.utils import get_valid_next_url_from_request
from wagtail.core.models import Page, PageLogEntry
from wagtail.core.models import (
Page,
PageLogEntry,
TranslatableMixin,
_copy_m2m_relations,
)
from wagtail.core.signals import page_published

from wagtail_localize.models import TranslationSource

@@ -18,39 +23,49 @@ def convert_to_alias(request, page_id):
raise PermissionDenied

try:
# Attempt to get the source page id, if it exists
source_page = Page.objects.get(
~Q(pk=page.pk),
translation_key=page.translation_key,
locale_id=TranslationSource.objects.get(
object_id=page.translation_key,
specific_content_type=page.content_type_id,
).locale_id,
translation_source = TranslationSource.objects.get(
object_id=page.translation_key,
specific_content_type=page.content_type_id,
)

source_page = translation_source.get_source_instance()
except (Page.DoesNotExist, TranslationSource.DoesNotExist):
raise Http404

# prevent self-aliasing
if source_page.id == page_id:
raise Http404

page_to_alias = page.specific

with transaction.atomic():
next_url = get_valid_next_url_from_request(request)

if request.method == "POST":
page.alias_of_id = source_page.id
page.save(update_fields=["alias_of_id"], clean=False)
# Sync with source page
sync_alias(
source_page, page_to_alias, revision=source_page.get_latest_revision()
)

# mark the page as an alias
page_to_alias.alias_of_id = source_page.id
page_to_alias.save(update_fields=["alias_of_id"], clean=False)

page_title = page.specific_deferred.get_admin_display_title()
# note, this logs the page title from before the sync
page_title = page_to_alias.get_admin_display_title()
PageLogEntry.objects.log_action(
instance=page,
revision=page.get_latest_revision(),
instance=page_to_alias,
revision=page_to_alias.get_latest_revision(),
action="wagtail_localize.convert_to_alias",
user=request.user,
data={
"page": {
"id": page.id,
"id": page_to_alias.id,
"title": page_title,
},
"source": {
"id": source_page.id,
"title": source_page.specific_deferred.get_admin_display_title(),
"title": source_page.get_admin_display_title(),
},
},
)
@@ -62,14 +77,93 @@ def convert_to_alias(request, page_id):

if next_url:
return redirect(next_url)
return redirect("wagtailadmin_pages:edit", page.id)
return redirect("wagtailadmin_pages:edit", page_to_alias.id)

return TemplateResponse(
request,
"wagtail_localize/admin/confirm_convert_to_alias.html",
{
"page": page,
"page": page_to_alias,
"source_page": source_page,
"next": next_url,
},
)


def sync_alias(source_page, alias_page, revision=None, _content_json=None):
"""
Updates the page converted to an alias to be up-to-date with the source page.
It will also update all aliases that follow this page with the latest content from this page.
Note: this is
"""
source_page = source_page.specific

# Only compute this if necessary since it's quite a heavy operation
if _content_json is None:
_content_json = source_page.to_json()

# FIXME: update when core adds better mechanism for the exclusions
exclude_fields = [
"id",
"path",
"depth",
"numchild",
"url_path",
"path",
"index_entries",
"postgres_index_entries",
]

# Copy field content
alias_updated = alias_page.with_content_json(_content_json)

# Mirror the publishing status of the status page
alias_updated.live = source_page.live
alias_updated.has_unpublished_changes = False

# Copy child relations
child_object_map = source_page.copy_all_child_relations(
target=alias_updated, exclude=exclude_fields
)

# Process child objects
if child_object_map:

def process_child_object(child_object):
if isinstance(child_object, TranslatableMixin):
# Child object's locale must always match the page
child_object.locale = alias_updated.locale

for (_rel, previous_id), child_objects in child_object_map.items():
if previous_id is None:
for child_object in child_objects:
process_child_object(child_object)
else:
process_child_object(child_objects)

# Copy M2M relations
_copy_m2m_relations(source_page, alias_updated, exclude_fields=exclude_fields)

# Don't change the aliases slug
# Aliases can have their own slugs so they can be siblings of the original
alias_updated.slug = alias_page.slug
alias_updated.set_url_path(alias_updated.get_parent())

# Technically, aliases don't have revisions, and in Page.update_aliases() fields that
# would normally be updated by save_revision get updated. Let's mirror that.
alias_updated.draft_title = alias_updated.title
alias_updated.latest_revision_created_at = source_page.latest_revision_created_at

alias_updated.save(clean=False)

# question: should we sent the published alias?
if alias_updated.live and not alias_page.live:
page_published.send(
sender=alias_updated.specific_class,
instance=alias_updated,
revision=revision,
alias=True,
)

# Update any aliases of that alias
alias_page.update_aliases(revision=revision, _content_json=_content_json)

0 comments on commit 7d97ecd

Please sign in to comment.