✨(domains) store last check domain results
Store results of last dimail check on a domain.
This commit is contained in:
@@ -10,6 +10,7 @@ and this project adheres to
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- ✨(domains) store last health check details on MailDomain
|
||||||
- ✨(domains) add support email field on domain
|
- ✨(domains) add support email field on domain
|
||||||
|
|
||||||
## [1.11.0] - 2025-02-07
|
## [1.11.0] - 2025-02-07
|
||||||
|
|||||||
Binary file not shown.
@@ -591,39 +591,47 @@ msgstr "Désactivé"
|
|||||||
msgid "Action required"
|
msgid "Action required"
|
||||||
msgstr "Action requise"
|
msgstr "Action requise"
|
||||||
|
|
||||||
#: mailbox_manager/models.py:35
|
#: mailbox_manager/models.py:33
|
||||||
|
msgid "last check details"
|
||||||
|
msgstr "détails de la dernière vérification"
|
||||||
|
|
||||||
|
#: mailbox_manager/models.py:34
|
||||||
|
msgid "A JSON object containing the last health check details"
|
||||||
|
msgstr "Un objet JSON contenant les détails de la dernière vérification"
|
||||||
|
|
||||||
|
#: mailbox_manager/models.py:39
|
||||||
msgid "Mail domain"
|
msgid "Mail domain"
|
||||||
msgstr "Domaine de messagerie"
|
msgstr "Domaine de messagerie"
|
||||||
|
|
||||||
#: mailbox_manager/models.py:36
|
#: mailbox_manager/models.py:40
|
||||||
msgid "Mail domains"
|
msgid "Mail domains"
|
||||||
msgstr "Domaines de messagerie"
|
msgstr "Domaines de messagerie"
|
||||||
|
|
||||||
#: mailbox_manager/models.py:102
|
#: mailbox_manager/models.py:106
|
||||||
msgid "User/mail domain relation"
|
msgid "User/mail domain relation"
|
||||||
msgstr "Relation entre un utilisateur et un domaine de mail"
|
msgstr "Relation entre un utilisateur et un domaine de mail"
|
||||||
|
|
||||||
#: mailbox_manager/models.py:103
|
#: mailbox_manager/models.py:107
|
||||||
msgid "User/mail domain relations"
|
msgid "User/mail domain relations"
|
||||||
msgstr "Relations entre un utilisateur et un domaine de mail"
|
msgstr "Relations entre un utilisateur et un domaine de mail"
|
||||||
|
|
||||||
#: mailbox_manager/models.py:175
|
#: mailbox_manager/models.py:179
|
||||||
msgid "local_part"
|
msgid "local_part"
|
||||||
msgstr "local_part"
|
msgstr "local_part"
|
||||||
|
|
||||||
#: mailbox_manager/models.py:189
|
#: mailbox_manager/models.py:193
|
||||||
msgid "secondary email address"
|
msgid "secondary email address"
|
||||||
msgstr "adresse email secondaire"
|
msgstr "adresse email secondaire"
|
||||||
|
|
||||||
#: mailbox_manager/models.py:199
|
#: mailbox_manager/models.py:203
|
||||||
msgid "Mailbox"
|
msgid "Mailbox"
|
||||||
msgstr "Boîte mail"
|
msgstr "Boîte mail"
|
||||||
|
|
||||||
#: mailbox_manager/models.py:200
|
#: mailbox_manager/models.py:204
|
||||||
msgid "Mailboxes"
|
msgid "Mailboxes"
|
||||||
msgstr "Boîtes mails"
|
msgstr "Boîtes mails"
|
||||||
|
|
||||||
#: mailbox_manager/models.py:224
|
#: mailbox_manager/models.py:228
|
||||||
msgid "You can't create or update a mailbox for a disabled domain."
|
msgid "You can't create or update a mailbox for a disabled domain."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vous ne pouvez pas créer ou modifier une boîte mail pour un domain désactivé."
|
"Vous ne pouvez pas créer ou modifier une boîte mail pour un domain désactivé."
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.5 on 2025-02-07 20:39
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mailbox_manager', '0018_maildomain_support_email'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='maildomain',
|
||||||
|
name='last_check_details',
|
||||||
|
field=models.JSONField(blank=True, help_text='A JSON object containing the last health check details', null=True, verbose_name='last check details'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -30,6 +30,12 @@ class MailDomain(BaseModel):
|
|||||||
choices=MailDomainStatusChoices.choices,
|
choices=MailDomainStatusChoices.choices,
|
||||||
)
|
)
|
||||||
support_email = models.EmailField(_("support email"), null=False, blank=False)
|
support_email = models.EmailField(_("support email"), null=False, blank=False)
|
||||||
|
last_check_details = models.JSONField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
verbose_name=_("last check details"),
|
||||||
|
help_text=_("A JSON object containing the last health check details"),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "people_mail_domain"
|
db_table = "people_mail_domain"
|
||||||
|
|||||||
@@ -194,11 +194,13 @@ def test_dimail__fetch_domain_status__switch_to_enabled(domain_status):
|
|||||||
dimail_client.fetch_domain_status(domain)
|
dimail_client.fetch_domain_status(domain)
|
||||||
domain.refresh_from_db()
|
domain.refresh_from_db()
|
||||||
assert domain.status == enums.MailDomainStatusChoices.ENABLED
|
assert domain.status == enums.MailDomainStatusChoices.ENABLED
|
||||||
|
assert domain.last_check_details == body_content
|
||||||
|
|
||||||
# call again, should be ok
|
# call again, should be ok
|
||||||
dimail_client.fetch_domain_status(domain)
|
dimail_client.fetch_domain_status(domain)
|
||||||
domain.refresh_from_db()
|
domain.refresh_from_db()
|
||||||
assert domain.status == enums.MailDomainStatusChoices.ENABLED
|
assert domain.status == enums.MailDomainStatusChoices.ENABLED
|
||||||
|
assert domain.last_check_details == body_content
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@@ -217,12 +219,12 @@ def test_dimail__fetch_domain_status__switch_to_action_required(
|
|||||||
"""Domains should be in status action required when dimail check
|
"""Domains should be in status action required when dimail check
|
||||||
returns broken status for external checks."""
|
returns broken status for external checks."""
|
||||||
domain = factories.MailDomainFactory(status=domain_status)
|
domain = factories.MailDomainFactory(status=domain_status)
|
||||||
body_content = CHECK_DOMAIN_BROKEN_EXTERNAL.copy()
|
body_domain_broken = CHECK_DOMAIN_BROKEN_EXTERNAL.copy()
|
||||||
body_content["name"] = domain.name
|
body_domain_broken["name"] = domain.name
|
||||||
responses.add(
|
responses.add(
|
||||||
responses.GET,
|
responses.GET,
|
||||||
re.compile(rf".*/domains/{domain.name}/check/"),
|
re.compile(rf".*/domains/{domain.name}/check/"),
|
||||||
body=json.dumps(body_content),
|
body=json.dumps(body_domain_broken),
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
)
|
)
|
||||||
@@ -230,21 +232,23 @@ def test_dimail__fetch_domain_status__switch_to_action_required(
|
|||||||
dimail_client.fetch_domain_status(domain)
|
dimail_client.fetch_domain_status(domain)
|
||||||
domain.refresh_from_db()
|
domain.refresh_from_db()
|
||||||
assert domain.status == enums.MailDomainStatusChoices.ACTION_REQUIRED
|
assert domain.status == enums.MailDomainStatusChoices.ACTION_REQUIRED
|
||||||
|
assert domain.last_check_details == body_domain_broken
|
||||||
|
|
||||||
# Support team fixes their part of the problem
|
# Support team fixes their part of the problem
|
||||||
# Now domain is OK again
|
# Now domain is OK again
|
||||||
body_content = CHECK_DOMAIN_OK.copy()
|
body_domain_ok = CHECK_DOMAIN_OK.copy()
|
||||||
body_content["name"] = domain.name
|
body_domain_ok["name"] = domain.name
|
||||||
responses.add(
|
responses.add(
|
||||||
responses.GET,
|
responses.GET,
|
||||||
re.compile(rf".*/domains/{domain.name}/check/"),
|
re.compile(rf".*/domains/{domain.name}/check/"),
|
||||||
body=json.dumps(body_content),
|
body=json.dumps(body_domain_ok),
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
)
|
)
|
||||||
dimail_client.fetch_domain_status(domain)
|
dimail_client.fetch_domain_status(domain)
|
||||||
domain.refresh_from_db()
|
domain.refresh_from_db()
|
||||||
assert domain.status == enums.MailDomainStatusChoices.ENABLED
|
assert domain.status == enums.MailDomainStatusChoices.ENABLED
|
||||||
|
assert domain.last_check_details == body_domain_ok
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@@ -261,12 +265,12 @@ def test_dimail__fetch_domain_status__switch_to_failed(domain_status):
|
|||||||
for only internal checks dispite a fix call."""
|
for only internal checks dispite a fix call."""
|
||||||
domain = factories.MailDomainFactory(status=domain_status)
|
domain = factories.MailDomainFactory(status=domain_status)
|
||||||
# nothing can be done by support team, domain should be in failed
|
# nothing can be done by support team, domain should be in failed
|
||||||
body_content = CHECK_DOMAIN_BROKEN_INTERNAL.copy()
|
body_domain_broken = CHECK_DOMAIN_BROKEN_INTERNAL.copy()
|
||||||
body_content["name"] = domain.name
|
body_domain_broken["name"] = domain.name
|
||||||
responses.add(
|
responses.add(
|
||||||
responses.GET,
|
responses.GET,
|
||||||
re.compile(rf".*/domains/{domain.name}/check/"),
|
re.compile(rf".*/domains/{domain.name}/check/"),
|
||||||
body=json.dumps(body_content),
|
body=json.dumps(body_domain_broken),
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
)
|
)
|
||||||
@@ -274,7 +278,7 @@ def test_dimail__fetch_domain_status__switch_to_failed(domain_status):
|
|||||||
responses.add(
|
responses.add(
|
||||||
responses.GET,
|
responses.GET,
|
||||||
re.compile(rf".*/domains/{domain.name}/fix/"),
|
re.compile(rf".*/domains/{domain.name}/fix/"),
|
||||||
body=json.dumps(body_content),
|
body=json.dumps(body_domain_broken),
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
)
|
)
|
||||||
@@ -282,6 +286,7 @@ def test_dimail__fetch_domain_status__switch_to_failed(domain_status):
|
|||||||
dimail_client.fetch_domain_status(domain)
|
dimail_client.fetch_domain_status(domain)
|
||||||
domain.refresh_from_db()
|
domain.refresh_from_db()
|
||||||
assert domain.status == enums.MailDomainStatusChoices.FAILED
|
assert domain.status == enums.MailDomainStatusChoices.FAILED
|
||||||
|
assert domain.last_check_details == body_domain_broken
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@@ -298,12 +303,12 @@ def test_dimail__fetch_domain_status__full_fix_scenario(domain_status):
|
|||||||
after a fix call."""
|
after a fix call."""
|
||||||
domain = factories.MailDomainFactory(status=domain_status)
|
domain = factories.MailDomainFactory(status=domain_status)
|
||||||
# with all checks KO, domain should be in action required
|
# with all checks KO, domain should be in action required
|
||||||
body_content = CHECK_DOMAIN_BROKEN.copy()
|
body_domain_broken = CHECK_DOMAIN_BROKEN.copy()
|
||||||
body_content["name"] = domain.name
|
body_domain_broken["name"] = domain.name
|
||||||
responses.add(
|
responses.add(
|
||||||
responses.GET,
|
responses.GET,
|
||||||
re.compile(rf".*/domains/{domain.name}/check/"),
|
re.compile(rf".*/domains/{domain.name}/check/"),
|
||||||
body=json.dumps(body_content),
|
body=json.dumps(body_domain_broken),
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
)
|
)
|
||||||
@@ -311,27 +316,28 @@ def test_dimail__fetch_domain_status__full_fix_scenario(domain_status):
|
|||||||
dimail_client.fetch_domain_status(domain)
|
dimail_client.fetch_domain_status(domain)
|
||||||
domain.refresh_from_db()
|
domain.refresh_from_db()
|
||||||
assert domain.status == enums.MailDomainStatusChoices.ACTION_REQUIRED
|
assert domain.status == enums.MailDomainStatusChoices.ACTION_REQUIRED
|
||||||
|
assert domain.last_check_details == body_domain_broken
|
||||||
|
|
||||||
# We assume that the support has fixed their part.
|
# We assume that the support has fixed their part.
|
||||||
# So now dimail returns OK for external checks but still KO for internal checks.
|
# So now dimail returns OK for external checks but still KO for internal checks.
|
||||||
# A call to dimail fix endpoint is necessary and will be done by
|
# A call to dimail fix endpoint is necessary and will be done by
|
||||||
# the fetch_domain_status call
|
# the fetch_domain_status call
|
||||||
body_content = CHECK_DOMAIN_BROKEN_INTERNAL.copy()
|
body_domain_broken_internal = CHECK_DOMAIN_BROKEN_INTERNAL.copy()
|
||||||
body_content["name"] = domain.name
|
body_domain_broken_internal["name"] = domain.name
|
||||||
responses.add(
|
responses.add(
|
||||||
responses.GET,
|
responses.GET,
|
||||||
re.compile(rf".*/domains/{domain.name}/check/"),
|
re.compile(rf".*/domains/{domain.name}/check/"),
|
||||||
body=json.dumps(body_content),
|
body=json.dumps(body_domain_broken_internal),
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
)
|
)
|
||||||
# the endpoint fix is called and returns OK. Hooray!
|
# the endpoint fix is called and returns OK. Hooray!
|
||||||
body_content = CHECK_DOMAIN_OK.copy()
|
body_domain_ok = CHECK_DOMAIN_OK.copy()
|
||||||
body_content["name"] = domain.name
|
body_domain_ok["name"] = domain.name
|
||||||
responses.add(
|
responses.add(
|
||||||
responses.GET,
|
responses.GET,
|
||||||
re.compile(rf".*/domains/{domain.name}/fix/"),
|
re.compile(rf".*/domains/{domain.name}/fix/"),
|
||||||
body=json.dumps(body_content),
|
body=json.dumps(body_domain_ok),
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
)
|
)
|
||||||
@@ -339,6 +345,7 @@ def test_dimail__fetch_domain_status__full_fix_scenario(domain_status):
|
|||||||
dimail_client.fetch_domain_status(domain)
|
dimail_client.fetch_domain_status(domain)
|
||||||
domain.refresh_from_db()
|
domain.refresh_from_db()
|
||||||
assert domain.status == enums.MailDomainStatusChoices.ENABLED
|
assert domain.status == enums.MailDomainStatusChoices.ENABLED
|
||||||
|
assert domain.last_check_details == body_domain_ok
|
||||||
|
|
||||||
|
|
||||||
def test_dimail__enable_pending_mailboxes(caplog):
|
def test_dimail__enable_pending_mailboxes(caplog):
|
||||||
|
|||||||
@@ -456,6 +456,7 @@ class DimailAPIClient:
|
|||||||
):
|
):
|
||||||
self.enable_pending_mailboxes(domain)
|
self.enable_pending_mailboxes(domain)
|
||||||
domain.status = enums.MailDomainStatusChoices.ENABLED
|
domain.status = enums.MailDomainStatusChoices.ENABLED
|
||||||
|
domain.last_check_details = dimail_response
|
||||||
domain.save()
|
domain.save()
|
||||||
# if dimail returns broken status, we need to extract external and internal checks
|
# if dimail returns broken status, we need to extract external and internal checks
|
||||||
# and manage the case where the domain has to be fixed by support
|
# and manage the case where the domain has to be fixed by support
|
||||||
@@ -465,6 +466,7 @@ class DimailAPIClient:
|
|||||||
# manage the case where the domain has to be fixed by support
|
# manage the case where the domain has to be fixed by support
|
||||||
if not all(external_checks.values()):
|
if not all(external_checks.values()):
|
||||||
domain.status = enums.MailDomainStatusChoices.ACTION_REQUIRED
|
domain.status = enums.MailDomainStatusChoices.ACTION_REQUIRED
|
||||||
|
domain.last_check_details = dimail_response
|
||||||
domain.save()
|
domain.save()
|
||||||
# if all external checks are ok but not internal checks, we need to fix internal checks
|
# if all external checks are ok but not internal checks, we need to fix internal checks
|
||||||
elif all(external_checks.values()) and not all(internal_checks.values()):
|
elif all(external_checks.values()) and not all(internal_checks.values()):
|
||||||
@@ -479,12 +481,20 @@ class DimailAPIClient:
|
|||||||
)
|
)
|
||||||
if all(external_checks.values()) and all(internal_checks.values()):
|
if all(external_checks.values()) and all(internal_checks.values()):
|
||||||
domain.status = enums.MailDomainStatusChoices.ENABLED
|
domain.status = enums.MailDomainStatusChoices.ENABLED
|
||||||
|
domain.last_check_details = dimail_response
|
||||||
domain.save()
|
domain.save()
|
||||||
elif all(external_checks.values()) and not all(
|
elif all(external_checks.values()) and not all(
|
||||||
internal_checks.values()
|
internal_checks.values()
|
||||||
):
|
):
|
||||||
domain.status = enums.MailDomainStatusChoices.FAILED
|
domain.status = enums.MailDomainStatusChoices.FAILED
|
||||||
|
domain.last_check_details = dimail_response
|
||||||
domain.save()
|
domain.save()
|
||||||
|
|
||||||
|
# if no health check data is stored on the domain, we store it now
|
||||||
|
if not domain.last_check_details:
|
||||||
|
domain.last_check_details = dimail_response
|
||||||
|
domain.save()
|
||||||
|
|
||||||
return dimail_response
|
return dimail_response
|
||||||
|
|
||||||
def _get_dimail_checks(self, dimail_response, internal: bool):
|
def _get_dimail_checks(self, dimail_response, internal: bool):
|
||||||
|
|||||||
Reference in New Issue
Block a user