Skip to content

Commit 6fe8ff3

Browse files
authored
Fixed django-cms#5900 -- Don't assume a published page has public translation (django-cms#5908)
1 parent 0a34a9a commit 6fe8ff3

File tree

5 files changed

+118
-28
lines changed

5 files changed

+118
-28
lines changed

CHANGELOG.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* Fixed an IntegrityError raised when publishing a page with no public version and whose publisher
1616
state is pending.
1717
* Fixed an issue with JS not being able to determine correct path to async bundle
18+
* Fixed a ``DoesNotExist`` db error raised when moving a page marked as published but whose public
19+
translation does not exist.
1820

1921

2022
=== 3.4.3 (2017-04-24) ===

cms/models/pagemodel.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -819,9 +819,11 @@ def unpublish(self, language):
819819
return True
820820

821821
def mark_as_pending(self, language):
822+
assert self.publisher_is_draft
823+
822824
public = self.get_public_object()
823825

824-
if public:
826+
if public and public.get_title_obj(language, fallback=False):
825827
state = public.get_publisher_state(language)
826828
# keep the same state
827829
# only set the page as unpublished
@@ -831,25 +833,21 @@ def mark_as_pending(self, language):
831833
published=False
832834
)
833835

834-
draft = self.get_draft_object()
835-
836-
if draft and draft.is_published(language) and draft.get_publisher_state(
837-
language) == PUBLISHER_STATE_DEFAULT:
836+
if self.is_published(language) and self.get_publisher_state(language) == PUBLISHER_STATE_DEFAULT:
838837
# Only change the state if the draft page is published
839838
# and it's state is the default (0)
840-
draft.set_publisher_state(language, state=PUBLISHER_STATE_PENDING)
839+
self.set_publisher_state(language, state=PUBLISHER_STATE_PENDING)
841840

842841
def mark_descendants_pending(self, language):
843842
assert self.publisher_is_draft
844843

845-
# Go through all children of our public instance
846-
public_page = self.publisher_public
847-
848-
if public_page:
849-
descendants = public_page.get_descendants().filter(title_set__language=language)
844+
descendants = self.get_descendants().filter(
845+
publisher_public__isnull=False,
846+
title_set__language=language,
847+
)
850848

851-
for child in descendants:
852-
child.mark_as_pending(language)
849+
for child in descendants.iterator():
850+
child.mark_as_pending(language)
853851

854852
def mark_as_published(self, language):
855853
from cms.models import Title

cms/models/titlemodels.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
# -*- coding: utf-8 -*-
2-
from datetime import timedelta
3-
42
from django.db import models
53
from django.utils import timezone
64
from django.utils.encoding import python_2_unicode_compatible
@@ -91,11 +89,6 @@ def save_base(self, *args, **kwargs):
9189
"""
9290
keep_state = getattr(self, '_publisher_keep_state', None)
9391

94-
# Published pages should always have a publication date
95-
# if the page is published we set the publish date if not set yet.
96-
if self.page.publication_date is None and self.published:
97-
self.page.publication_date = timezone.now() - timedelta(seconds=5)
98-
9992
if self.publisher_is_draft and not keep_state and self.is_new_dirty():
10093
self.publisher_state = PUBLISHER_STATE_DIRTY
10194

@@ -128,11 +121,8 @@ def is_new_dirty(self):
128121

129122

130123
class EmptyTitle(object):
131-
132-
def __init__(self, language):
133-
self.language = language
134-
135-
"""Empty title object, can be returned from Page.get_title_obj() if required
124+
"""
125+
Empty title object, can be returned from Page.get_title_obj() if required
136126
title object doesn't exists.
137127
"""
138128
title = ""
@@ -146,6 +136,17 @@ def __init__(self, language):
146136
page_title = ""
147137
published = False
148138

139+
def __init__(self, language):
140+
self.language = language
141+
142+
def __nonzero__(self):
143+
# Python 2 compatibility
144+
return False
145+
146+
def __bool__(self):
147+
# Python 3 compatibility
148+
return False
149+
149150
@property
150151
def overwrite_url(self):
151152
return None

cms/tests/test_page_admin.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616
from cms.admin.forms import AdvancedSettingsForm
1717
from cms.admin.pageadmin import PageAdmin
1818
from cms.api import create_page, add_plugin, create_title
19-
from cms.constants import PUBLISHER_STATE_DEFAULT, PUBLISHER_STATE_PENDING, PUBLISHER_STATE_DIRTY
19+
from cms.constants import (
20+
PUBLISHER_STATE_DEFAULT,
21+
PUBLISHER_STATE_DIRTY,
22+
PUBLISHER_STATE_PENDING,
23+
)
2024
from cms.middleware.user import CurrentUserMiddleware
2125
from cms.models.pagemodel import Page
2226
from cms.models.permissionmodels import PagePermission
@@ -798,6 +802,86 @@ def test_publish_with_pending_unpublished_descendants(self):
798802
PUBLISHER_STATE_DEFAULT
799803
)
800804

805+
def test_move_page_regression_5900(self):
806+
# ref: https://github.com/divio/django-cms/issues/5900
807+
superuser = self.get_superuser()
808+
with self.login_user_context(superuser):
809+
page_home = self.get_new_page_data()
810+
self.client.post(URL_CMS_PAGE_ADD, page_home)
811+
812+
# Create parent page
813+
page_root = create_page("Parent", 'col_three.html', "de", published=False)
814+
815+
# Create english translation
816+
create_title(
817+
"en",
818+
"parent-en",
819+
page=page_root,
820+
slug="parent-en"
821+
)
822+
823+
# Create child pages
824+
page_child_1 = create_page(
825+
"Child 1",
826+
template=constants.TEMPLATE_INHERITANCE_MAGIC,
827+
language="de",
828+
parent=page_root,
829+
published=False
830+
)
831+
832+
# Create english translation
833+
create_title(
834+
"en",
835+
"child-1-en",
836+
page=page_child_1,
837+
slug="child-1-en"
838+
)
839+
840+
# Try to publish child english translation
841+
publish_endpoint = self.get_admin_url(Page, 'publish_page', page_child_1.pk, 'en')
842+
843+
self.client.post(publish_endpoint)
844+
845+
self.assertEqual(
846+
page_child_1.get_publisher_state("en"),
847+
PUBLISHER_STATE_PENDING,
848+
)
849+
850+
# Publish the german translations for both the parent and child pages.
851+
# This will create the public versions for both.
852+
page_root.publish('de')
853+
page_child_1.publish('de')
854+
855+
# Move page_child_1 to the root
856+
data = {
857+
"id": page_child_1.pk,
858+
"position": "2",
859+
}
860+
861+
response = self.client.post(
862+
URL_CMS_PAGE_MOVE % page_child_1.pk,
863+
data,
864+
)
865+
self.assertEqual(response.status_code, 200)
866+
867+
# Ensure move worked
868+
self.assertEqual(page_root.reload().get_descendants().count(), 0)
869+
870+
# Move page_child_1 under its old parent
871+
# page_child_1 does not have a public version of its english translation
872+
data = {
873+
"id": page_child_1.pk,
874+
"target": page_root.pk,
875+
"position": "0",
876+
}
877+
response = self.client.post(
878+
URL_CMS_PAGE_MOVE % page_child_1.pk,
879+
data,
880+
)
881+
self.assertEqual(response.status_code, 200)
882+
883+
# Ensure move worked
884+
self.assertEqual(page_root.reload().get_descendants().count(), 1)
801885

802886
def test_edit_page_other_site_and_language(self):
803887
"""

cms/tests/test_publisher.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ def test_delete_title_unpublish(self):
579579
page = self.create_page('test', published=True)
580580
sub_page = self.create_page('test2', published=True, parent=page)
581581
self.assertTrue(sub_page.publisher_public.is_published('en'))
582-
page.title_set.all().delete()
582+
page.reload().title_set.all().delete()
583583
self.assertFalse(sub_page.publisher_public.is_published('en', force_reload=True))
584584

585585
def test_modify_child_while_pending(self):
@@ -686,9 +686,14 @@ def test_republish_with_unpublished_child(self):
686686
self.assertFalse(gc1.publisher_public_id)
687687
self.assertTrue(gc1.is_published('en'))
688688
self.assertTrue(gc2.is_published('en'))
689+
690+
home = self.reload(home)
689691
home.unpublish('en')
692+
690693
unpub1 = self.reload(unpub1)
694+
unpub2 = self.reload(unpub2)
691695
unpub2.unpublish('en') # Just marks this as not published
696+
692697
for page in (unpub1, unpub2):
693698
self.assertFalse(page.is_published('en'), page)
694699
self.assertEqual(page.get_publisher_state("en"), PUBLISHER_STATE_DIRTY)
@@ -770,7 +775,7 @@ def test_unpublish_with_dirty_descendants(self):
770775
self.assertTrue(child.publisher_public.is_published('en'))
771776
self.assertTrue(gchild.publisher_public.is_published('en'))
772777

773-
page.unpublish('en')
778+
page.reload().unpublish('en')
774779
child = self.reload(child)
775780
gchild = self.reload(gchild)
776781
# Descendants become dirty after unpublish

0 commit comments

Comments
 (0)