diff --git a/gnuviechadmin/managemails/apps.py b/gnuviechadmin/managemails/apps.py index 1cf2135..328a964 100644 --- a/gnuviechadmin/managemails/apps.py +++ b/gnuviechadmin/managemails/apps.py @@ -15,3 +15,11 @@ class ManageMailsAppConfig(AppConfig): name = "managemails" verbose_name = _("Mailboxes and Mail Addresses") + + def ready(self): + """ + Takes care of importing the signal handlers of the :py:mod:`userdbs` + app. + + """ + import managemails.signals # NOQA diff --git a/gnuviechadmin/managemails/models.py b/gnuviechadmin/managemails/models.py index 9b303f1..cef5cf4 100644 --- a/gnuviechadmin/managemails/models.py +++ b/gnuviechadmin/managemails/models.py @@ -8,7 +8,6 @@ from model_utils.models import TimeStampedModel from passlib.handlers.sha2_crypt import sha512_crypt from domains.models import MailDomain -from fileservertasks.tasks import create_file_mailbox, delete_file_mailbox from osusers.models import User as OsUser @@ -123,16 +122,6 @@ class Mailbox(ActivateAbleMixin, TimeStampedModel): """ self.password = sha512_crypt.hash(password) - def save(self, *args, **kwargs): - # TODO: refactor to use signals - create_file_mailbox.delay(self.osuser.username, self.username).get() - super(Mailbox, self).save(*args, **kwargs) - - def delete(self, *args, **kwargs): - # TODO: refactor to use signals - delete_file_mailbox.delay(self.osuser.username, self.username).get() - super(Mailbox, self).delete(*args, **kwargs) - def get_mailaddresses(self): """ Get a list of mail addresses assigned to this mailbox. diff --git a/gnuviechadmin/managemails/signals.py b/gnuviechadmin/managemails/signals.py new file mode 100644 index 0000000..2c3bb87 --- /dev/null +++ b/gnuviechadmin/managemails/signals.py @@ -0,0 +1,62 @@ +""" +This module contains the signal handlers of the :py:mod:`managemails` 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_mailbox, delete_file_mailbox +from managemails.models import Mailbox +from taskresults.models import TaskResult + +_LOGGER = logging.getLogger(__name__) + + +@receiver(post_save, sender=Mailbox) +def handle_mailbox_created(sender, instance, created, **kwargs): + """ + Handles post creation actions on :py:class:`Mailbox ` instances. + + :param sender: sender of the signal + :param instance: Mailbox instance + :param created: whether the instance has just been created + + This signal handler starts a Celery_ task. + + """ + if created: + taskresult = 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 + ) + _LOGGER.debug("mailbox %s has been %s", instance, created and "created" or "updated") + + +@receiver(post_delete, sender=Mailbox) +def handle_mailbox_deleted(sender, instance, **kwargs): + """ + Handles cleanup actions to be done after deletion of a + :py:class:`Mailbox ` instance. + + :param sender: sender of the signal + :param instance: Mailbox instance + + This signal handler starts a Celery_ task. + + """ + taskresult = 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 + ) diff --git a/gnuviechadmin/managemails/tests/test_models.py b/gnuviechadmin/managemails/tests/test_models.py index 21ff892..18562d3 100644 --- a/gnuviechadmin/managemails/tests/test_models.py +++ b/gnuviechadmin/managemails/tests/test_models.py @@ -1,24 +1,20 @@ """ This module contains tests for :py:mod:`managemails.models` """ -from unittest.mock import patch - from django.contrib.auth import get_user_model from django.test import TestCase, TransactionTestCase from django.test.utils import override_settings -from passlib.hash import sha512_crypt +from passlib.handlers.sha2_crypt import sha512_crypt from domains.models import MailDomain from managemails.models import MailAddress, Mailbox from osusers.models import User +from taskresults.tests.testutils import TestCaseWithCeleryTasks Customer = get_user_model() -@override_settings( - CELERY_ALWAYS_EAGER=True, CELERY_CACHE_BACKEND="memory", BROKER_BACKEND="memory" -) -class MailboxTest(TestCase): +class MailboxTest(TestCaseWithCeleryTasks): def setUp(self): super(MailboxTest, self).setUp() self.customer = Customer.objects.create_user("test") @@ -35,22 +31,32 @@ class MailboxTest(TestCase): mb.set_password("test") self.assertEqual(str(mb), "test") - @patch("managemails.models.create_file_mailbox") - def test_save(self, create_file_mailbox_task): + def test_save(self): user = User.objects.create_user(self.customer) + + self.resetCeleryTasks() + mb = Mailbox.objects.create_mailbox(user) self.assertIsNotNone(mb.pk) - create_file_mailbox_task.delay.assert_called_with(user.username, mb.username) - @patch("managemails.models.delete_file_mailbox") - def test_delete(self, delete_file_mailbox_task): + self.assertCeleryTasksRun([ + (1, "handle_mailbox_created"), + ]) + + def test_delete(self): user = User.objects.create_user(self.customer) mb = Mailbox.objects.create_mailbox(user) + + self.resetCeleryTasks() + mb.delete() self.assertIsNone(mb.pk) - delete_file_mailbox_task.delay.assert_called_with(user.username, mb.username) - def test_get_mailaddresses(self): + self.assertCeleryTasksRun([ + (1, "handle_mailbox_deleted"), + ]) + + def test_get_mail_addresses(self): user = User.objects.create_user(self.customer) mb = Mailbox.objects.create_mailbox(user) md = MailDomain.objects.create(domain="example.org") @@ -61,10 +67,7 @@ class MailboxTest(TestCase): self.assertIn(address, mailaddresses) -@override_settings( - CELERY_ALWAYS_EAGER=True, CELERY_CACHE_BACKEND="memory", BROKER_BACKEND="memory" -) -class MailAddressTest(TransactionTestCase): +class MailAddressTest(TestCaseWithCeleryTasks): def test__str__(self): md = MailDomain.objects.create(domain="example.org") ma = MailAddress.objects.create(localpart="test", domain=md) @@ -214,10 +217,7 @@ class MailAddressTest(TransactionTestCase): self.assertEqual(mafwds[0].target, "test2@example.org") -@override_settings( - CELERY_ALWAYS_EAGER=True, CELERY_CACHE_BACKEND="memory", BROKER_BACKEND="memory" -) -class MailboxManagerTest(TransactionTestCase): +class MailboxManagerTest(TestCaseWithCeleryTasks): def setUp(self): super(MailboxManagerTest, self).setUp() self.customer = Customer.objects.create_user("test") @@ -302,10 +302,7 @@ class MailboxManagerTest(TransactionTestCase): self.assertTrue(sha512_crypt.verify("test", mailbox.password)) -@override_settings( - CELERY_ALWAYS_EAGER=True, CELERY_CACHE_BACKEND="memory", BROKER_BACKEND="memory" -) -class MailAddressMailboxTest(TestCase): +class MailAddressMailboxTest(TestCaseWithCeleryTasks): def setUp(self): super(MailAddressMailboxTest, self).setUp() self.customer = Customer.objects.create_user("test") diff --git a/gnuviechadmin/taskresults/tests/testutils.py b/gnuviechadmin/taskresults/tests/testutils.py new file mode 100644 index 0000000..3bfdcb7 --- /dev/null +++ b/gnuviechadmin/taskresults/tests/testutils.py @@ -0,0 +1,21 @@ +from django.test import TestCase +from django.test.utils import override_settings + +from taskresults.models import TaskResult + + +@override_settings( + CELERY_ALWAYS_EAGER=True, CELERY_CACHE_BACKEND="memory", BROKER_BACKEND="memory" +) +class TestCaseWithCeleryTasks(TestCase): + def resetCeleryTasks(self): + TaskResult.objects.all().delete() + + def assertCeleryTasksRun(self, tasks): + task_results = TaskResult.objects.all() + + self.assertEqual(task_results.count(), sum([t[0] for t in tasks])) + + creators = [r.creator for r in task_results] + for t_count, t_creator in tasks: + self.assertEqual(creators.count(t_creator), t_count)