From 9fbd6088370fd520d6a0492f3da3c86d79514605 Mon Sep 17 00:00:00 2001
From: Jan Dittberner <jan@dittberner.info>
Date: Mon, 17 Apr 2023 19:41:42 +0200
Subject: [PATCH] Use signals for website celery tasks

---
 gnuviechadmin/managemails/apps.py    |   2 +-
 gnuviechadmin/managemails/signals.py |  16 +--
 gnuviechadmin/websites/apps.py       |   8 ++
 gnuviechadmin/websites/models.py     |  39 +-------
 gnuviechadmin/websites/signals.py    | 140 +++++++++++++++++++++++++++
 5 files changed, 158 insertions(+), 47 deletions(-)
 create mode 100644 gnuviechadmin/websites/signals.py

diff --git a/gnuviechadmin/managemails/apps.py b/gnuviechadmin/managemails/apps.py
index 328a964..6ef7ce8 100644
--- a/gnuviechadmin/managemails/apps.py
+++ b/gnuviechadmin/managemails/apps.py
@@ -18,7 +18,7 @@ class ManageMailsAppConfig(AppConfig):
 
     def ready(self):
         """
-        Takes care of importing the signal handlers of the :py:mod:`userdbs`
+        Takes care of importing the signal handlers of the :py:mod:`managemails`
         app.
 
         """
diff --git a/gnuviechadmin/managemails/signals.py b/gnuviechadmin/managemails/signals.py
index 2c3bb87..d30d5e9 100644
--- a/gnuviechadmin/managemails/signals.py
+++ b/gnuviechadmin/managemails/signals.py
@@ -31,14 +31,16 @@ def handle_mailbox_created(sender, instance, created, **kwargs):
 
     """
     if created:
-        taskresult = TaskResult.objects.create_task_result(
+        task_result = TaskResult.objects.create_task_result(
             "handle_mailbox_created",
             create_file_mailbox.s(instance.osuser.username, instance.username),
         )
         _LOGGER.info(
-            "Mailbox creation has been requested in task %s", taskresult.task_id
+            "Mailbox creation has been requested in task %s", task_result.task_id
         )
-    _LOGGER.debug("mailbox %s has been %s", instance, created and "created" or "updated")
+    _LOGGER.debug(
+        "mailbox %s has been %s", instance, created and "created" or "updated"
+    )
 
 
 @receiver(post_delete, sender=Mailbox)
@@ -53,10 +55,8 @@ def handle_mailbox_deleted(sender, instance, **kwargs):
     This signal handler starts a Celery_ task.
 
     """
-    taskresult = TaskResult.objects.create_task_result(
+    task_result = TaskResult.objects.create_task_result(
         "handle_mailbox_deleted",
-        delete_file_mailbox.s(instance.osuser.username, instance.username)
-    )
-    _LOGGER.info(
-        "Mailbox deletion has been requested in task %s", taskresult.task_id
+        delete_file_mailbox.s(instance.osuser.username, instance.username),
     )
+    _LOGGER.info("Mailbox deletion has been requested in task %s", task_result.task_id)
diff --git a/gnuviechadmin/websites/apps.py b/gnuviechadmin/websites/apps.py
index a5fd48b..9b7c95e 100644
--- a/gnuviechadmin/websites/apps.py
+++ b/gnuviechadmin/websites/apps.py
@@ -15,3 +15,11 @@ class WebsitesAppConfig(AppConfig):
 
     name = "websites"
     verbose_name = _("Websites")
+
+    def ready(self):
+        """
+        Takes care of importing the signal handlers of the :py:mod:`websites`
+        app.
+
+        """
+        import websites.signals  # NOQA
diff --git a/gnuviechadmin/websites/models.py b/gnuviechadmin/websites/models.py
index 44b5f84..95d5902 100644
--- a/gnuviechadmin/websites/models.py
+++ b/gnuviechadmin/websites/models.py
@@ -4,23 +4,11 @@ This module defines the database models for website handling.
 """
 from __future__ import absolute_import
 
-from django.db import models, transaction
+from django.db import models
 from django.utils.translation import gettext as _
 
 from domains.models import HostingDomain
-from fileservertasks.tasks import (
-    create_file_website_hierarchy,
-    delete_file_website_hierarchy,
-)
 from osusers.models import User as OsUser
-from webtasks.tasks import (
-    create_web_php_fpm_pool_config,
-    create_web_vhost_config,
-    delete_web_php_fpm_pool_config,
-    delete_web_vhost_config,
-    disable_web_vhost,
-    enable_web_vhost,
-)
 
 
 class Website(models.Model):
@@ -48,28 +36,3 @@ class Website(models.Model):
         return "{subdomain}.{domain}".format(
             subdomain=self.subdomain, domain=self.domain.domain
         )
-
-    @transaction.atomic
-    def save(self, *args, **kwargs):
-        if not self.pk:
-            fqdn = self.get_fqdn()
-            if not Website.objects.filter(osuser=self.osuser).exists():
-                create_web_php_fpm_pool_config.delay(self.osuser.username).get()
-            create_file_website_hierarchy.delay(self.osuser.username, fqdn).get()
-            create_web_vhost_config.delay(
-                self.osuser.username, fqdn, self.wildcard
-            ).get()
-            enable_web_vhost.delay(fqdn).get()
-        return super(Website, self).save(*args, **kwargs)
-
-    @transaction.atomic
-    def delete(self, *args, **kwargs):
-        fqdn = self.get_fqdn()
-        osuser = self.osuser
-        disable_web_vhost.delay(fqdn).get()
-        delete_web_vhost_config.delay(fqdn).get()
-        delete_file_website_hierarchy.delay(osuser.username, fqdn).get()
-        deleted = super(Website, self).delete(*args, **kwargs)
-        if not Website.objects.filter(osuser=osuser):
-            delete_web_php_fpm_pool_config.delay(osuser.username).get()
-        return deleted
diff --git a/gnuviechadmin/websites/signals.py b/gnuviechadmin/websites/signals.py
new file mode 100644
index 0000000..113eaba
--- /dev/null
+++ b/gnuviechadmin/websites/signals.py
@@ -0,0 +1,140 @@
+"""
+This module contains the signal handlers of the :py:mod:`websites` app.
+
+The module starts Celery_ tasks.
+
+.. _Celery: https://www.celeryproject.org/
+
+"""
+import logging
+
+from django.db.models.signals import post_delete, post_save
+from django.dispatch import receiver
+
+from fileservertasks.tasks import (
+    create_file_website_hierarchy,
+    delete_file_website_hierarchy,
+)
+from taskresults.models import TaskResult
+from websites.models import Website
+from webtasks.tasks import (
+    create_web_php_fpm_pool_config,
+    create_web_vhost_config,
+    delete_web_php_fpm_pool_config,
+    delete_web_vhost_config,
+    disable_web_vhost,
+    enable_web_vhost,
+)
+
+_LOGGER = logging.getLogger(__name__)
+
+
+@receiver(post_save, sender=Website)
+def handle_website_created(sender, instance, created, **kwargs):
+    """
+    Handles post creation actions on :py:class:`Website <websites.models.Website>` instances.
+
+    :param sender: sender of the signal
+    :param instance: Website instance
+    :param created: whether the instance has just been created
+
+    This signal handler starts multiple Celery_ tasks.
+
+    """
+    if created:
+        task_result = TaskResult.objects.create_task_result(
+            "create_web_php_fpm_pool_config",
+            create_web_php_fpm_pool_config.s(instance.osuser.username),
+        )
+        _LOGGER.info(
+            "PHP FPM configuration creation has been requested in task %s",
+            task_result.task_id,
+        )
+
+        fqdn = instance.get_fqdn()
+        task_result = TaskResult.objects.create_task_result(
+            "create_file_website_hierarchy",
+            create_file_website_hierarchy.s(instance.osuser.username, fqdn),
+        )
+        _LOGGER.info(
+            "website file hierarchy creation for %s has been requested in task %s",
+            fqdn,
+            task_result.task_id,
+        )
+
+        task_result = TaskResult.objects.create_task_result(
+            "create_web_vhost_config",
+            create_web_vhost_config.s(
+                instance.osuser.username, fqdn, instance.wildcard
+            ),
+        )
+        _LOGGER.info(
+            "virtual host configuration for %s has been requested in task %s",
+            fqdn,
+            task_result.task_id,
+        )
+
+        task_result = TaskResult.objects.create_task_result(
+            "enable_web_vhost", enable_web_vhost.s(fqdn)
+        )
+        _LOGGER.info(
+            "virtual host enabling has been requested in task %s", task_result.task_id
+        )
+
+    _LOGGER.debug(
+        "website %s has been %s", instance, created and "created" or "updated"
+    )
+
+
+@receiver(post_delete, sender=Website)
+def handle_website_deleted(sender, instance, **kwargs):
+    """
+    Handles cleanup actions to be done after deletion of a :py:class:`Website <websites.models.Website>` instance.
+
+    :param sender: sender of the signal
+    :param instance: Mailbox instance
+
+    This signal handler starts multiple Celery_ tasks.
+
+    """
+    fqdn = instance.get_fqdn()
+    os_user = instance.osuser
+
+    task_result = TaskResult.objects.create_task_result(
+        "disable_web_vhost", disable_web_vhost.s(fqdn)
+    )
+    _LOGGER.info(
+        "virtual host disabling for %s has been requested in task %s",
+        fqdn,
+        task_result.task_id,
+    )
+
+    task_result = TaskResult.objects.create_task_result(
+        "delete_web_vhost_config", delete_web_vhost_config.s(fqdn)
+    )
+    _LOGGER.info(
+        "virtual host configuration deletion for %s has been requested in task %s",
+        fqdn,
+        task_result.task_id,
+    )
+
+    task_result = TaskResult.objects.create_task_result(
+        "delete_file_website_hierarchy",
+        delete_file_website_hierarchy.s(os_user.username, fqdn),
+    )
+    _LOGGER.info(
+        "website file hierarchy deletion for %s has been requested in task %s",
+        fqdn,
+        task_result.task_id,
+    )
+
+    if not Website.objects.filter(osuser=os_user):
+        task_result = TaskResult.objects.create_task_result(
+            "delete_web_php_fpm_pool_config",
+            delete_web_php_fpm_pool_config.s(os_user.username),
+        )
+        _LOGGER.info(
+            "PHP FPM configuration deletion for OS user %s has been requested in task %s",
+            os_user.username,
+            task_result.task_id,
+        )