Skip to content

Commit

Permalink
✨(domains) send email when domain status changes
Browse files Browse the repository at this point in the history
Send email notification to owners and admins of a domain
when its status changes to failed or enabled.
  • Loading branch information
sdemagny committed Jan 27, 2025
1 parent 099f029 commit 89466e5
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to

### Added

- ✨(domains) add notification when domain status changes
- ✨(domains) add periodic tasks to fetch domain status
- 🧑‍💻(docker) add celery beat to manage periodic tasks
- ✨(dimail) management command to fetch domain status
Expand Down
11 changes: 11 additions & 0 deletions src/backend/mailbox_manager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ def get_abilities(self, user):
"manage_accesses": is_owner_or_admin,
}

def send_notification(self, subject, message):
"""
Notify owners and admins of the domain
"""
for access in self.accesses.filter(
role__in=[MailDomainRoleChoices.OWNER, MailDomainRoleChoices.ADMIN]
).all():
access.user.email_user(
subject=subject, message=message, from_email=settings.DEFAULT_FROM_EMAIL
)


class MailDomainAccess(BaseModel):
"""Allow to manage users' accesses to mail domains."""
Expand Down
12 changes: 12 additions & 0 deletions src/backend/mailbox_manager/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ def fetch_domains_status():
else:
if old_status != domain.status:
update_count += 1
# Send notification to owners and admins of the domain
# when its status changes to failed or enabled
if domain.status == MailDomainStatusChoices.FAILED:
domain.send_notification(
subject="Domain status changed",
message=f"Domain {domain.name} is down",
)
elif domain.status == MailDomainStatusChoices.ENABLED:
domain.send_notification(
subject="Domain status changed",
message=f"Domain {domain.name} is up",
)
else:
check_count += 1
return f"Domains processed: {update_count} updated, {check_count} checked"
48 changes: 46 additions & 2 deletions src/backend/mailbox_manager/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

import json
import re
from unittest import mock

from django.conf import settings

import pytest
import responses
Expand All @@ -21,13 +24,24 @@ def test_fetch_domain_status_task_success(): # pylint: disable=too-many-locals

domain_enabled1 = factories.MailDomainEnabledFactory()
domain_enabled2 = factories.MailDomainEnabledFactory()
owner_domain_enabled2 = factories.MailDomainAccessFactory(
domain=domain_enabled2, role=enums.MailDomainRoleChoices.OWNER
).user
admin_domain_enabled2 = factories.MailDomainAccessFactory(
domain=domain_enabled2, role=enums.MailDomainRoleChoices.ADMIN
).user
domain_disabled = factories.MailDomainFactory(
status=enums.MailDomainStatusChoices.DISABLED
)
domain_failed = factories.MailDomainFactory(
status=enums.MailDomainStatusChoices.FAILED
)

owner_domain_failed = factories.MailDomainAccessFactory(
domain=domain_failed, role=enums.MailDomainRoleChoices.OWNER
).user
admin_domain_failed = factories.MailDomainAccessFactory(
domain=domain_failed, role=enums.MailDomainRoleChoices.ADMIN
).user
body_content_ok1 = CHECK_DOMAIN_OK.copy()
body_content_ok1["name"] = domain_enabled1.name

Expand All @@ -52,7 +66,8 @@ def test_fetch_domain_status_task_success(): # pylint: disable=too-many-locals
status=200,
content_type="application/json",
)
tasks.fetch_domains_status()
with mock.patch("django.core.mail.send_mail") as mock_send:
tasks.fetch_domains_status()
domain_enabled1.refresh_from_db()
domain_enabled2.refresh_from_db()
domain_disabled.refresh_from_db()
Expand All @@ -63,6 +78,35 @@ def test_fetch_domain_status_task_success(): # pylint: disable=too-many-locals
assert domain_enabled2.status == enums.MailDomainStatusChoices.FAILED
# Status of the failed domain has changed to enabled
assert domain_failed.status == enums.MailDomainStatusChoices.ENABLED
# Check notification was sent to owners and admins
assert mock_send.call_count == 4
calls = [
mock.call(
"Domain status changed",
f"Domain {domain_enabled2.name} is down",
settings.DEFAULT_FROM_EMAIL,
[owner_domain_enabled2.email],
),
mock.call(
"Domain status changed",
f"Domain {domain_enabled2.name} is down",
settings.DEFAULT_FROM_EMAIL,
[admin_domain_enabled2.email],
),
mock.call(
"Domain status changed",
f"Domain {domain_failed.name} is up",
settings.DEFAULT_FROM_EMAIL,
[owner_domain_failed.email],
),
mock.call(
"Domain status changed",
f"Domain {domain_failed.name} is up",
settings.DEFAULT_FROM_EMAIL,
[admin_domain_failed.email],
),
]
mock_send.assert_has_calls(calls, any_order=True)
# Disabled domain was excluded
assert domain_disabled.status == enums.MailDomainStatusChoices.DISABLED

Expand Down

0 comments on commit 89466e5

Please sign in to comment.