Repository: django-cms/django-cms

Issue:
Unpublishing a page creates server error
Here is the traceback

Traceback (most recent call last):  File "/srv/env-cms3/lib/python2.6/site-packages/django/contrib/staticfiles/handlers.py", line 72, in **call**    return self.application(environ, start_response)  File "/srv/env-cms3/lib/python2.6/site-packages/django/core/handlers/wsgi.py", line 255, in **call**    response = self.get_response(request)  File "/srv/env-cms3/lib/python2.6/site-packages/django/core/handlers/base.py", line 178, in get_response    response = self.handle_uncaught_exception(request, resolver, sys.exc_info())  File "/srv/env-cms3/lib/python2.6/site-packages/django/core/handlers/base.py", line 217, in handle_uncaught_exception    return debug.technical_500_response(request, _exc_info)  File "/srv/env-cms3/lib/python2.6/site-packages/django_extensions/management/technical_response.py", line 5, in null_technical_500_response    six.reraise(exc_type, exc_value, tb)  File "/srv/env-cms3/lib/python2.6/site-packages/django/core/handlers/base.py", line 115, in get_response    response = callback(request, *callback_args, *_callback_kwargs)  File "/srv/env-cms3/lib/python2.6/site-packages/django/utils/decorators.py", line 91, in _wrapped_view    response = view_func(request, _args, *_kwargs)  File "/srv/env-cms3/lib/python2.6/site-packages/django/views/decorators/cache.py", line 89, in _wrapped_view_func    response = view_func(request, _args, *_kwargs)  File "/srv/env-cms3/lib/python2.6/site-packages/django/contrib/admin/sites.py", line 202, in inner    return view(request, _args, *_kwargs)  File "/srv/env-cms3/lib/python2.6/site-packages/django/utils/decorators.py", line 25, in _wrapper    return bound_func(_args, *_kwargs)  File "/srv/env-cms3/lib/python2.6/site-packages/django/views/decorators/http.py", line 41, in inner    return func(request, _args, *_kwargs)  File "/srv/env-cms3/lib/python2.6/site-packages/django/utils/decorators.py", line 21, in bound_func    return func(self, _args2, *_kwargs2)  File "/srv/env-cms3/src/django-cms/cms/admin/pageadmin.py", line 1024, in unpublish    page.unpublish(language)  File "/srv/env-cms3/src/django-cms/cms/models/pagemodel.py", line 572, in unpublish    published_languages.remove(language)ValueError: list.remove(x): x not in list



Discussion:

Resolving patch:
diff --git a/cms/migrations/0054_new_publisher_data.py b/cms/migrations/0054_new_publisher_data.py
--- a/cms/migrations/0054_new_publisher_data.py
+++ b/cms/migrations/0054_new_publisher_data.py
@@ -25,15 +25,19 @@ def forwards(self, orm):
                 title.publisher_state = page.publisher_state
                 languages.append(title.language)
                 title.save()
+            pub_languages = []
             for title in pub_titles:
                 title.published = pub_page.published
                 title.publisher_is_draft = pub_page.publisher_is_draft
                 title.publisher_state = pub_page.publisher_state
                 title.save()
+                pub_languages.append(title.language)
             if page.published:
                 page.published_languages = ",".join(languages)
             page.languages = ",".join(languages)
             page.save()
+            pub_page.languages = ",".join(pub_languages)
+            pub_page.save()
 
 
     def backwards(self, orm):
diff --git a/cms/models/pagemodel.py b/cms/models/pagemodel.py
--- a/cms/models/pagemodel.py
+++ b/cms/models/pagemodel.py
@@ -83,7 +83,6 @@ class Page(with_metaclass(PageMetaClass, MPTTModel)):
     publisher_is_draft = models.BooleanField(default=True, editable=False, db_index=True)
     # This is misnamed - the one-to-one relation is populated on both ends
     publisher_public = models.OneToOneField('self', related_name='publisher_draft', null=True, editable=False)
-    published_languages = models.CharField(max_length=255, editable=False, blank=True, null=True)
     languages = models.CharField(max_length=255, editable=False, blank=True, null=True)
 
     # If the draft is loaded from a reversion version save the revision id here.
@@ -425,10 +424,10 @@ def save_base(self, *args, **kwargs):
         ret = super(Page, self).save_base(*args, **kwargs)
         return ret
 
-    def is_published(self, language):
+    def is_published(self, language, force_reload=False):
         from cms.models import Title
         try:
-            return self.get_title_obj(language, False).published
+            return self.get_title_obj(language, False, force_reload=force_reload).published
         except Title.DoesNotExist:
             return False
 
@@ -510,13 +509,7 @@ def publish(self, language):
         else:
             # Nothing left to do
             pass
-        if published:
-            if not self.published_languages or not "|%s|" % language in self.published_languages:
-                if self.published_languages:
-                    self.published_languages += "%s|" % language
-                else:
-                    self.published_languages = "|%s|" % language
-        else:
+        if not published:
             self.set_publisher_state(language, PUBLISHER_STATE_PENDING, published=True)
         self._publisher_keep_state = True
         self.save()
@@ -584,12 +577,8 @@ def unpublish(self, language):
         public_title.save()
         public_page = self.publisher_public
         public_placeholders = public_page.placeholders.all()
-        published_languages = self.published_languages.split("|")
-        published_languages.remove(language)
-        self.published_languages = "|".join(published_languages)
         for pl in public_placeholders:
             pl.cmsplugin_set.filter(language=language).delete()
-        public_page.published_languages = self.published_languages
         public_page.save()
         # trigger update home
         self.save()
diff --git a/cms/signals.py b/cms/signals.py
--- a/cms/signals.py
+++ b/cms/signals.py
@@ -54,10 +54,10 @@ def update_home(instance, **kwargs):
         try:
             home_pk = qs.filter(title_set__published=True).distinct().get_home(instance.site).pk
         except NoHomeFound:
-            if instance.publisher_is_draft and not instance.published_languages:
+            if instance.publisher_is_draft and instance.title_set.filter(published=True, publisher_public__published=True).count():
                 return
             home_pk = instance.pk
-            instance.is_home = True
+            #instance.is_home = True
         for page in qs.filter(site=instance.site, is_home=True).exclude(pk=home_pk):
             if instance.pk == page.pk:
                 instance.is_home = False


Test patch:
diff --git a/cms/tests/api.py b/cms/tests/api.py
--- a/cms/tests/api.py
+++ b/cms/tests/api.py
@@ -178,8 +178,12 @@ def test_assign_user_to_page_all(self):
         self.assertTrue(page.has_add_permission(request))
 
     def test_page_overwrite_url_default(self):
-        home = create_page('home', 'nav_playground.html', 'en')
+        self.assertEqual(Page.objects.all().count(), 0)
+        home = create_page('home', 'nav_playground.html', 'en', published=True)
+        self.assertTrue(home.is_published('en', True))
+        self.assertTrue(home.is_home)
         page = create_page(**self._get_default_create_page_arguments())
+        self.assertFalse(page.is_home)
         self.assertFalse(page.get_title_obj_attribute('has_url_overwrite'))
         self.assertEqual(page.get_title_obj_attribute('path'), 'test')
 
diff --git a/cms/tests/page.py b/cms/tests/page.py
--- a/cms/tests/page.py
+++ b/cms/tests/page.py
@@ -222,7 +222,7 @@ def test_moderator_edit_page_redirect(self):
         """
         Test that a page can be edited multiple times with moderator
         """
-        home = api.create_page("home", "nav_playground.html", "en")
+        home = api.create_page("home", "nav_playground.html", "en", published=True)
         superuser = self.get_superuser()
         with self.login_user_context(superuser):
             page_data = self.get_new_page_data()