From da067679cdd7999c256c8916f78c82f7641d51cd Mon Sep 17 00:00:00 2001
From: Mike Dingjan <mike@mikedingjan.nl>
Date: Fri, 10 Feb 2017 17:02:45 +0100
Subject: [PATCH] Move signal_handlers to separate files (#3356)

* Move signal_handlers to separate files

In preparation for implementing a swappable page register
the signal handlers in the ``django.apps.AppConf.ready`` method.

* Remove unused imports

* Missing empty line

* Import sorting
---
 wagtail/wagtailcore/__init__.py          |  2 ++
 wagtail/wagtailcore/apps.py              |  4 +++
 wagtail/wagtailcore/models.py            | 26 ----------------
 wagtail/wagtailcore/signal_handlers.py   | 38 ++++++++++++++++++++++++
 wagtail/wagtaildocs/apps.py              |  4 +++
 wagtail/wagtaildocs/models.py            |  9 ------
 wagtail/wagtaildocs/signal_handlers.py   | 15 ++++++++++
 wagtail/wagtailimages/apps.py            |  4 +++
 wagtail/wagtailimages/models.py          | 26 ----------------
 wagtail/wagtailimages/signal_handlers.py | 25 ++++++++++++++++
 10 files changed, 92 insertions(+), 61 deletions(-)
 create mode 100644 wagtail/wagtailcore/signal_handlers.py
 create mode 100644 wagtail/wagtaildocs/signal_handlers.py
 create mode 100644 wagtail/wagtailimages/signal_handlers.py

diff --git a/wagtail/wagtailcore/__init__.py b/wagtail/wagtailcore/__init__.py
index f4fcf20719..4bfc307b9a 100644
--- a/wagtail/wagtailcore/__init__.py
+++ b/wagtail/wagtailcore/__init__.py
@@ -3,6 +3,8 @@ from __future__ import absolute_import, unicode_literals
 # Imported for historical reasons
 from wagtail import __semver__, __version__  # noqa
 
+default_app_config = 'wagtail.wagtailcore.apps.WagtailCoreAppConfig'
+
 
 def setup():
     import warnings
diff --git a/wagtail/wagtailcore/apps.py b/wagtail/wagtailcore/apps.py
index 9be2b08a8a..75eb832ce8 100644
--- a/wagtail/wagtailcore/apps.py
+++ b/wagtail/wagtailcore/apps.py
@@ -7,3 +7,7 @@ class WagtailCoreAppConfig(AppConfig):
     name = 'wagtail.wagtailcore'
     label = 'wagtailcore'
     verbose_name = "Wagtail core"
+
+    def ready(self):
+        from wagtail.wagtailcore.signal_handlers import register_signal_handlers
+        register_signal_handlers()
diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py
index 5137106b29..07768d6693 100644
--- a/wagtail/wagtailcore/models.py
+++ b/wagtail/wagtailcore/models.py
@@ -16,8 +16,6 @@ from django.core.handlers.wsgi import WSGIRequest
 from django.core.urlresolvers import reverse
 from django.db import connection, models, transaction
 from django.db.models import Case, IntegerField, Q, When
-from django.db.models.signals import post_delete, post_save, pre_delete
-from django.dispatch.dispatcher import receiver
 from django.http import Http404
 from django.template.response import TemplateResponse
 # Must be imported from Django so we get the new implementation of with_metaclass
@@ -216,17 +214,6 @@ class Site(models.Model):
         return result
 
 
-# Clear the wagtail_site_root_paths from the cache whenever Site records are updated
-@receiver(post_save, sender=Site)
-def clear_site_root_paths_on_save(sender, instance, **kwargs):
-    cache.delete('wagtail_site_root_paths')
-
-
-@receiver(post_delete, sender=Site)
-def clear_site_root_paths_on_delete(sender, instance, **kwargs):
-    cache.delete('wagtail_site_root_paths')
-
-
 PAGE_MODEL_CLASSES = []
 
 
@@ -1385,19 +1372,6 @@ class Page(six.with_metaclass(PageBase, AbstractPage, index.Indexed, Clusterable
         verbose_name_plural = _('pages')
 
 
-@receiver(pre_delete, sender=Page)
-def unpublish_page_before_delete(sender, instance, **kwargs):
-    # Make sure pages are unpublished before deleting
-    if instance.live:
-        # Don't bother to save, this page is just about to be deleted!
-        instance.unpublish(commit=False)
-
-
-@receiver(post_delete, sender=Page)
-def log_page_deletion(sender, instance, **kwargs):
-    logger.info("Page deleted: \"%s\" id=%d", instance.title, instance.id)
-
-
 class Orderable(models.Model):
     sort_order = models.IntegerField(null=True, blank=True, editable=False)
     sort_order_field = 'sort_order'
diff --git a/wagtail/wagtailcore/signal_handlers.py b/wagtail/wagtailcore/signal_handlers.py
new file mode 100644
index 0000000000..80cf69e879
--- /dev/null
+++ b/wagtail/wagtailcore/signal_handlers.py
@@ -0,0 +1,38 @@
+from __future__ import absolute_import, unicode_literals
+
+import logging
+
+from django.core.cache import cache
+from django.db.models.signals import post_delete, post_save, pre_delete
+
+from wagtail.wagtailcore.models import Page, Site
+
+logger = logging.getLogger('wagtail.core')
+
+
+# Clear the wagtail_site_root_paths from the cache whenever Site records are updated.
+def post_save_site_signal_handler(instance, update_fields=None, **kwargs):
+    cache.delete('wagtail_site_root_paths')
+
+
+def post_delete_site_signal_handler(instance, **kwargs):
+    cache.delete('wagtail_site_root_paths')
+
+
+def pre_delete_page_unpublish(sender, instance, **kwargs):
+    # Make sure pages are unpublished before deleting
+    if instance.live:
+        # Don't bother to save, this page is just about to be deleted!
+        instance.unpublish(commit=False)
+
+
+def post_delete_page_log_deletion(sender, instance, **kwargs):
+    logger.info("Page deleted: \"%s\" id=%d", instance.title, instance.id)
+
+
+def register_signal_handlers():
+    post_save.connect(post_save_site_signal_handler, sender=Site)
+    post_delete.connect(post_delete_site_signal_handler, sender=Site)
+
+    pre_delete.connect(pre_delete_page_unpublish, sender=Page)
+    post_delete.connect(post_delete_page_log_deletion, sender=Page)
diff --git a/wagtail/wagtaildocs/apps.py b/wagtail/wagtaildocs/apps.py
index 255817073f..8ad92cec7c 100644
--- a/wagtail/wagtaildocs/apps.py
+++ b/wagtail/wagtaildocs/apps.py
@@ -7,3 +7,7 @@ class WagtailDocsAppConfig(AppConfig):
     name = 'wagtail.wagtaildocs'
     label = 'wagtaildocs'
     verbose_name = "Wagtail documents"
+
+    def ready(self):
+        from wagtail.wagtaildocs.signal_handlers import register_signal_handlers
+        register_signal_handlers()
diff --git a/wagtail/wagtaildocs/models.py b/wagtail/wagtaildocs/models.py
index 7e54f03ed5..42a2369f4b 100644
--- a/wagtail/wagtaildocs/models.py
+++ b/wagtail/wagtaildocs/models.py
@@ -6,9 +6,7 @@ from django.conf import settings
 from django.core.exceptions import ImproperlyConfigured
 from django.core.urlresolvers import reverse
 from django.db import models
-from django.db.models.signals import post_delete
 from django.dispatch import Signal
-from django.dispatch.dispatcher import receiver
 from django.utils.encoding import python_2_unicode_compatible
 from django.utils.translation import ugettext_lazy as _
 from taggit.managers import TaggableManager
@@ -110,11 +108,4 @@ def get_document_model():
     return document_model
 
 
-# Receive the post_delete signal and delete the file associated with the model instance.
-@receiver(post_delete, sender=Document)
-def document_delete(sender, instance, **kwargs):
-    # Pass false so FileField doesn't save the model.
-    instance.file.delete(False)
-
-
 document_served = Signal(providing_args=['request'])
diff --git a/wagtail/wagtaildocs/signal_handlers.py b/wagtail/wagtaildocs/signal_handlers.py
new file mode 100644
index 0000000000..ac65db3403
--- /dev/null
+++ b/wagtail/wagtaildocs/signal_handlers.py
@@ -0,0 +1,15 @@
+from __future__ import absolute_import, unicode_literals
+
+from django.db.models.signals import post_delete
+
+from wagtail.wagtaildocs.models import Document
+
+
+# Receive the post_delete signal and delete the file associated with the model instance.
+def post_delete_document_file_cleanup(sender, instance, **kwargs):
+    # Pass false so FileField doesn't save the model.
+    instance.file.delete(False)
+
+
+def register_signal_handlers():
+    post_delete.connect(post_delete_document_file_cleanup, sender=Document)
diff --git a/wagtail/wagtailimages/apps.py b/wagtail/wagtailimages/apps.py
index ca42df0bf6..3332191eec 100644
--- a/wagtail/wagtailimages/apps.py
+++ b/wagtail/wagtailimages/apps.py
@@ -9,3 +9,7 @@ class WagtailImagesAppConfig(AppConfig):
     name = 'wagtail.wagtailimages'
     label = 'wagtailimages'
     verbose_name = "Wagtail images"
+
+    def ready(self):
+        from wagtail.wagtailimages.signal_handlers import register_signal_handlers
+        register_signal_handlers()
diff --git a/wagtail/wagtailimages/models.py b/wagtail/wagtailimages/models.py
index 9fc8a03d05..3ae20314b8 100644
--- a/wagtail/wagtailimages/models.py
+++ b/wagtail/wagtailimages/models.py
@@ -11,8 +11,6 @@ from django.core import checks
 from django.core.files import File
 from django.core.urlresolvers import reverse
 from django.db import models
-from django.db.models.signals import post_delete, pre_save
-from django.dispatch.dispatcher import receiver
 from django.forms.widgets import flatatt
 from django.utils.encoding import python_2_unicode_compatible
 from django.utils.functional import cached_property
@@ -337,23 +335,6 @@ class Image(AbstractImage):
     )
 
 
-# Do smartcropping calculations when user saves an image without a focal point
-@receiver(pre_save, sender=Image)
-def image_feature_detection(sender, instance, **kwargs):
-    if getattr(settings, 'WAGTAILIMAGES_FEATURE_DETECTION_ENABLED', False):
-        # Make sure the image doesn't already have a focal point
-        if not instance.has_focal_point():
-            # Set the focal point
-            instance.set_focal_point(instance.get_suggested_focal_point())
-
-
-# Receive the post_delete signal and delete the file associated with the model instance.
-@receiver(post_delete, sender=Image)
-def image_delete(sender, instance, **kwargs):
-    # Pass false so FileField doesn't save the model.
-    instance.file.delete(False)
-
-
 class Filter(object):
     """
     Represents one or more operations that can be applied to an Image to produce a rendition
@@ -535,10 +516,3 @@ class Rendition(AbstractRendition):
         unique_together = (
             ('image', 'filter_spec', 'focal_point_key'),
         )
-
-
-# Receive the post_delete signal and delete the file associated with the model instance.
-@receiver(post_delete, sender=Rendition)
-def rendition_delete(sender, instance, **kwargs):
-    # Pass false so FileField doesn't save the model.
-    instance.file.delete(False)
diff --git a/wagtail/wagtailimages/signal_handlers.py b/wagtail/wagtailimages/signal_handlers.py
new file mode 100644
index 0000000000..2db689a0ec
--- /dev/null
+++ b/wagtail/wagtailimages/signal_handlers.py
@@ -0,0 +1,25 @@
+from __future__ import absolute_import, unicode_literals
+
+from django.conf import settings
+from django.db.models.signals import post_delete, pre_save
+
+from wagtail.wagtailimages.models import Image, Rendition
+
+
+def post_delete_file_cleanup(instance, **kwargs):
+    # Pass false so FileField doesn't save the model.
+    instance.file.delete(False)
+
+
+def pre_save_image_feature_detection(instance, **kwargs):
+    if getattr(settings, 'WAGTAILIMAGES_FEATURE_DETECTION_ENABLED', False):
+        # Make sure the image doesn't already have a focal point
+        if not instance.has_focal_point():
+            # Set the focal point
+            instance.set_focal_point(instance.get_suggested_focal_point())
+
+
+def register_signal_handlers():
+    pre_save.connect(pre_save_image_feature_detection, sender=Image)
+    post_delete.connect(post_delete_file_cleanup, sender=Image)
+    post_delete.connect(post_delete_file_cleanup, sender=Rendition)