Repository: django-cms/django-cms

Issue:
'NoneType' object has no attribute 'is_published'
/home/nine-dev/app/local/lib/python2.7/site-packages/django/db/transaction.py in inner
                return func(_args, *_kwargs) ...
▶ Local vars
/home/nine-dev/app/local/lib/python2.7/site-packages/reversion/revisions.py in do_revision_context
                    return func(_args, *_kwargs) ...
▶ Local vars
/home/nine-dev/app/local/lib/python2.7/site-packages/cms/admin/pageadmin.py in publish_page
            published = page.publish(language) ...
▶ Local vars
/home/nine-dev/app/local/lib/python2.7/site-packages/cms/models/pagemodel.py in publish
                if page.publisher_public.parent.is_published(language): ...
▶ Local vars



Discussion:

Resolving patch:
diff --git a/cms/models/pagemodel.py b/cms/models/pagemodel.py
--- a/cms/models/pagemodel.py
+++ b/cms/models/pagemodel.py
@@ -174,7 +174,6 @@ def move_page(self, target, position='first-child'):
 
         # make sure move_page does not break when using INHERIT template
         # and moving to a top level position
-
         if (position in ('left', 'right') and not target.parent and is_inherited_template):
             self.template = self.get_template()
         self.move_to(target, position)
@@ -610,6 +609,9 @@ def publish(self, language):
                                                     title_set__language=language).select_related('publisher_public')
         for page in publish_set:
             if page.publisher_public:
+                if not page.publisher_public.parent_id:
+                    page.publisher_public.parent = page.parent.publisher_public
+                    page.publisher_public.save()
                 if page.publisher_public.parent.is_published(language):
                     from cms.models import Title
                     try:


Test patch:
diff --git a/cms/tests/publisher.py b/cms/tests/publisher.py
--- a/cms/tests/publisher.py
+++ b/cms/tests/publisher.py
@@ -598,6 +598,32 @@ def test_unpublish_with_dirty_descendants(self):
         self.assertFalse(child.publisher_public.is_published('en'))
         self.assertFalse(gchild.publisher_public.is_published('en'))
 
+    def test_prepublish_descendants(self):
+        page = self.create_page("Page", published=True)
+        child = self.create_page("Child", parent=page, published=False)
+        gchild2 = self.create_page("Grandchild2", parent=child, published=False)
+        self.create_page("Grandchild3", parent=child, published=False)
+        gchild = self.create_page("Grandchild", published=True)
+        gchild.move_page(target=child, position='last-child')
+
+        gchild.publish('en')
+        self.assertFalse(child.is_published('en'))
+        self.assertTrue(gchild.is_published('en'))
+        self.assertEqual(gchild.get_publisher_state('en'), PUBLISHER_STATE_PENDING)
+        child = child.reload()
+        child.publish('en')
+        gchild2 = gchild2.reload()
+        gchild2.publish('en')
+        self.assertTrue(child.is_published("en"))
+        self.assertTrue(gchild.is_published("en"))
+        self.assertEqual(gchild.get_publisher_state('en', force_reload=True), PUBLISHER_STATE_DEFAULT)
+        gchild = gchild.reload()
+        gchild2 = gchild2.reload()
+        self.assertEqual(gchild.lft, gchild.publisher_public.lft)
+        self.assertEqual(gchild.rght, gchild.publisher_public.rght)
+
+
+
     def test_republish_multiple_root(self):
         # TODO: The paths do not match expected behaviour
         home = self.create_page("Page", published=True)