Repository: wagtail/wagtail

Issue:
Draft state is not removed from page aliases when the source page is published 
### Issue Summary

There’s an issue with page aliases, which are used by wagtail-localize. When a source page goes to draft state at one point then gets published, the page aliases (used for each locale until there is an actual translation) remain in draft state with no way to publish them. Wagtail should propagate the publish state to the page aliases as well.

cc @kaedroho 

### Steps to Reproduce

1. Set up wagtail-localize
2. Add at least one locale to Settings > Locales
3. Save a new page as draft or Unpublish an existing page
4. Publish the page again

At step 3, the `Draft` state gets propagated to the page alias in the French tree. (works as expected)
At step 4, the `Draft` state is NOT removed from the page alias (broken)

* I have confirmed that this issue can be reproduced as described on a fresh Wagtail project: No, but I’ve reproduced locally with a test DB.


### Technical details

* Python version: 3.7.8
* Django version: 2.2.13
* Wagtail version: 2.11.2
* Wagtail-localize version: 0.9.3



Discussion:

Resolving patch:
diff --git a/wagtail/core/models.py b/wagtail/core/models.py
--- a/wagtail/core/models.py
+++ b/wagtail/core/models.py
@@ -1469,6 +1469,10 @@ def update_aliases(self, *, revision=None, user=None, _content_json=None, _updat
             # Copy field content
             alias_updated = alias.with_content_json(_content_json)
 
+            # Publish the alias if it's currently in draft
+            alias_updated.live = True
+            alias_updated.has_unpublished_changes = False
+
             # Copy child relations
             child_object_map = specific_self.copy_all_child_relations(target=alias_updated, exclude=exclude_fields)
 


Test patch:
diff --git a/wagtail/core/tests/test_page_model.py b/wagtail/core/tests/test_page_model.py
--- a/wagtail/core/tests/test_page_model.py
+++ b/wagtail/core/tests/test_page_model.py
@@ -2062,6 +2062,45 @@ def test_update_aliases(self):
         self.assertTrue(PageLogEntry.objects.filter(page=alias, action='wagtail.publish').exists())
         self.assertTrue(PageLogEntry.objects.filter(page=alias_alias, action='wagtail.publish').exists())
 
+    def test_update_aliases_publishes_drafts(self):
+        event_page = EventPage.objects.get(url_path='/home/events/christmas/')
+
+        # Unpublish the event page so that the aliases will be created in draft
+        event_page.live = False
+        event_page.has_unpublished_changes = True
+        event_page.save(clean=False)
+
+        alias = event_page.create_alias(update_slug='new-event-page')
+        alias_alias = alias.create_alias(update_slug='new-event-page-2')
+
+        self.assertFalse(alias.live)
+        self.assertFalse(alias_alias.live)
+
+        # Publish the event page
+        event_page.live = True
+        event_page.has_unpublished_changes = False
+        event_page.save(clean=False)
+
+        # Nothing should've happened yet
+        alias.refresh_from_db()
+        alias_alias.refresh_from_db()
+        self.assertFalse(alias.live)
+        self.assertFalse(alias_alias.live)
+
+        PageLogEntry.objects.all().delete()
+
+        event_page.update_aliases()
+
+        # Check that the aliases have been updated
+        alias.refresh_from_db()
+        alias_alias.refresh_from_db()
+        self.assertTrue(alias.live)
+        self.assertTrue(alias_alias.live)
+
+        # Check log entries were created
+        self.assertTrue(PageLogEntry.objects.filter(page=alias, action='wagtail.publish').exists())
+        self.assertTrue(PageLogEntry.objects.filter(page=alias_alias, action='wagtail.publish').exists())
+
 
 class TestCopyForTranslation(TestCase):
     fixtures = ['test.json']