From c44800a045b661b0f98652ba1567c40b232d1adc Mon Sep 17 00:00:00 2001 From: Gael Pasgrimaud Date: Mon, 19 Sep 2016 13:02:34 +0200 Subject: [PATCH 1/5] improve mx search --- .../management/commands/subcommands/_mx.py | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/modoboa/admin/management/commands/subcommands/_mx.py b/modoboa/admin/management/commands/subcommands/_mx.py index 935933f7f..a3b874d1d 100644 --- a/modoboa/admin/management/commands/subcommands/_mx.py +++ b/modoboa/admin/management/commands/subcommands/_mx.py @@ -57,6 +57,9 @@ class CheckMXRecords(BaseCommand): "--skip-admin-emails", action="store_true", default=False, help="Skip domain's admins email notification.") + parser.add_argument( + "--domain", type=str, action="append", default=[], + help="Domain name or id to update.") parser.add_argument( "--timeout", type=int, default=3, help="Timeout used for queries.") @@ -86,22 +89,22 @@ class CheckMXRecords(BaseCommand): delta = timedelta(seconds=ttl) for answer in answers: - address = None try: - ipaddress.ip_address(str(answer.exchange)) - except ValueError: - try: - address = socket.gethostbyname(str(answer.exchange)) - except socket.gaierror: - pass + # work if .exchange is a name or IP + address = socket.gethostbyname(str(answer.exchange)) + except socket.gaierror: + pass else: - address = str(answer.exchange) - finally: - if address is not None: + try: + # we must have a valid IP + address = ipaddress.ip_address(u'{}'.format(address)) + except ValueError: + pass + else: record = models.MXRecord.objects.create( domain=domain, - name=str(answer.exchange).strip("."), - address=address, + name=u'{}'.format(str(answer.exchange).strip(".")), + address=u'{}'.format(address), updated=now + delta) yield record @@ -237,5 +240,17 @@ class CheckMXRecords(BaseCommand): models.DNSBLResult.objects.exclude( provider__in=self.providers).delete() - for domain in models.Domain.objects.filter(enabled=True): + if options['domain']: + domains = [] + for domain in options['domain']: + if domain.isdigit(): + domains.append(models.Domain.objects.get(domain)) + else: + domains.append(models.Domain.objects.filter(name=domain)) + else: + domains = models.Domain.objects.filter(enabled=True) + + options.pop('domain') + + for domain in domains: self.check_domain(domain, **options) From 9d4d515bfb4eaa151a44f898572284183f146f77 Mon Sep 17 00:00:00 2001 From: Gael Pasgrimaud Date: Mon, 19 Sep 2016 14:27:21 +0200 Subject: [PATCH 2/5] update post_save hook --- modoboa/admin/handlers.py | 10 ++++++++-- modoboa/admin/management/commands/subcommands/_mx.py | 7 +++++-- modoboa/admin/tests/test_mx.py | 2 ++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/modoboa/admin/handlers.py b/modoboa/admin/handlers.py index cc0f679b1..cccff63e6 100644 --- a/modoboa/admin/handlers.py +++ b/modoboa/admin/handlers.py @@ -1,5 +1,6 @@ """Django signal handlers for admin.""" +from django.core import management from django.db.models import signals from django.dispatch import receiver @@ -7,9 +8,14 @@ from . import models @receiver(signals.post_save, sender=models.Domain) -def update_domain_mailboxes(sender, instance, **kwargs): - """Update associated mailboxes.""" +def update_domain_mxs_and_mailboxes(sender, instance, **kwargs): + """Update associated MXs and mailboxes.""" if kwargs.get("created"): + management.call_command( + 'modo', 'check_mx', + domain=[instance], + skip_admin_emails=True, + ) return instance.mailbox_set.filter(use_domain_quota=True).update( quota=instance.quota) diff --git a/modoboa/admin/management/commands/subcommands/_mx.py b/modoboa/admin/management/commands/subcommands/_mx.py index a3b874d1d..483ca4c16 100644 --- a/modoboa/admin/management/commands/subcommands/_mx.py +++ b/modoboa/admin/management/commands/subcommands/_mx.py @@ -83,7 +83,8 @@ class CheckMXRecords(BaseCommand): models.MXRecord.objects.filter(domain=domain).delete() try: answers = dns.resolver.query(domain.name, "MX") - except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN): + except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN, + dns.resolver.NoNameservers): raise StopIteration() delta = timedelta(seconds=ttl) @@ -243,7 +244,9 @@ class CheckMXRecords(BaseCommand): if options['domain']: domains = [] for domain in options['domain']: - if domain.isdigit(): + if isinstance(domain, models.Domain): + domains.append(domain) + elif domain.isdigit(): domains.append(models.Domain.objects.get(domain)) else: domains.append(models.Domain.objects.filter(name=domain)) diff --git a/modoboa/admin/tests/test_mx.py b/modoboa/admin/tests/test_mx.py index 7b958aa71..73812a7a4 100644 --- a/modoboa/admin/tests/test_mx.py +++ b/modoboa/admin/tests/test_mx.py @@ -21,6 +21,7 @@ class MXTestCase(ModoTestCase): cls.domain = factories.DomainFactory(name="modoboa.org") factories.DomainFactory(name="pouet.com") # should not exist parameters.save_admin('VALID_MXS', '127.0.0.1', app='admin') + models.MXRecord.objects.all().delete() def test_management_command(self): """Check that command works fine.""" @@ -53,6 +54,7 @@ class DNSBLTestCase(ModoTestCase): super(DNSBLTestCase, cls).setUpTestData() cls.domain = factories.DomainFactory(name="modoboa.org") factories.DomainFactory(name="pouet.com") # should not exist + models.DNSBLResult.objects.all().delete() @override_settings(DNSBL_PROVIDERS=["zen.spamhaus.org"]) def test_management_command(self): From e0f2f345232734c699cb19a9f86708e74b7ddafe Mon Sep 17 00:00:00 2001 From: Gael Pasgrimaud Date: Mon, 19 Sep 2016 15:37:37 +0200 Subject: [PATCH 3/5] take care of creation date while showing DNS status --- modoboa/admin/handlers.py | 6 ------ modoboa/admin/models/domain.py | 17 +++++++++++++++-- .../admin/templates/admin/domain_detail.html | 14 +++++++++----- .../admin/templates/admin/domains_table.html | 14 +++++++++----- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/modoboa/admin/handlers.py b/modoboa/admin/handlers.py index cccff63e6..b6fbae762 100644 --- a/modoboa/admin/handlers.py +++ b/modoboa/admin/handlers.py @@ -1,6 +1,5 @@ """Django signal handlers for admin.""" -from django.core import management from django.db.models import signals from django.dispatch import receiver @@ -11,11 +10,6 @@ from . import models def update_domain_mxs_and_mailboxes(sender, instance, **kwargs): """Update associated MXs and mailboxes.""" if kwargs.get("created"): - management.call_command( - 'modo', 'check_mx', - domain=[instance], - skip_admin_emails=True, - ) return instance.mailbox_set.filter(use_domain_quota=True).update( quota=instance.quota) diff --git a/modoboa/admin/models/domain.py b/modoboa/admin/models/domain.py index d90b00099..eb89380e6 100644 --- a/modoboa/admin/models/domain.py +++ b/modoboa/admin/models/domain.py @@ -1,7 +1,10 @@ """Models related to domains management.""" +import datetime + from django.db import models from django.db.models.manager import Manager +from django.utils import timezone from django.utils.encoding import python_2_unicode_compatible, smart_text from django.utils.functional import cached_property from django.utils.translation import ugettext as _, ugettext_lazy @@ -103,8 +106,18 @@ class Domain(AdminObject): return self.domainalias_set @property - def mx_records(self): - self.mxrecord_set + def just_created(self): + """return true if the domain was created in the latest 24h""" + now = timezone.now() + delta = datetime.timedelta(days=1) + return bool(self.creation + delta > now) + + def awaiting_checks(self): + """return true if the domain has no valid MX records and was created + in the latest 24h""" + if (not self.mxrecord_set.has_valids()) and self.just_created: + return True + return False @cached_property def dnsbl_status_color(self): diff --git a/modoboa/admin/templates/admin/domain_detail.html b/modoboa/admin/templates/admin/domain_detail.html index ab79891ad..578f48fd9 100644 --- a/modoboa/admin/templates/admin/domain_detail.html +++ b/modoboa/admin/templates/admin/domain_detail.html @@ -24,11 +24,15 @@ {% if enable_mx_checks == "yes" or enable_dnsbl_checks == "yes" %}
{% trans "DNS status" %} - {% if enable_mx_checks == "yes" %} - MX - {% endif %} - {% if enable_dnsbl_checks == "yes" %} - DNSBL + {% if domain.awaiting_checks %} + {% trans "Awaiting checks" %} + {% else %} + {% if enable_mx_checks == "yes" %} + MX + {% endif %} + {% if enable_dnsbl_checks == "yes" %} + DNSBL + {% endif %} {% endif %}
{% endif %} diff --git a/modoboa/admin/templates/admin/domains_table.html b/modoboa/admin/templates/admin/domains_table.html index da4587af4..84086aec8 100644 --- a/modoboa/admin/templates/admin/domains_table.html +++ b/modoboa/admin/templates/admin/domains_table.html @@ -8,11 +8,15 @@ {% if enable_mx_checks == "yes" or enable_dnsbl_checks == "yes" %} - {% if enable_mx_checks == "yes" %} - MX - {% endif %} - {% if enable_dnsbl_checks == "yes" %} - DNSBL + {% if domain.awaiting_checks %} + {% trans "awaiting checks" %} + {% else %} + {% if enable_mx_checks == "yes" %} + MX + {% endif %} + {% if enable_dnsbl_checks == "yes" %} + DNSBL + {% endif %} {% endif %} From 0d83741a3d868f97b59a6b234a8906520bccf05f Mon Sep 17 00:00:00 2001 From: Gael Pasgrimaud Date: Mon, 19 Sep 2016 18:05:41 +0200 Subject: [PATCH 4/5] typo --- modoboa/admin/templates/admin/domains_table.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modoboa/admin/templates/admin/domains_table.html b/modoboa/admin/templates/admin/domains_table.html index 84086aec8..5278c1829 100644 --- a/modoboa/admin/templates/admin/domains_table.html +++ b/modoboa/admin/templates/admin/domains_table.html @@ -9,7 +9,7 @@ {% if domain.awaiting_checks %} - {% trans "awaiting checks" %} + {% trans "Awaiting checks" %} {% else %} {% if enable_mx_checks == "yes" %} MX From 2e1515f855476e42efdbb0f67ff98bd9d5372b1c Mon Sep 17 00:00:00 2001 From: Gael Pasgrimaud Date: Mon, 19 Sep 2016 18:06:10 +0200 Subject: [PATCH 5/5] remove bool even if I like it --- modoboa/admin/models/domain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modoboa/admin/models/domain.py b/modoboa/admin/models/domain.py index eb89380e6..12ea14b0b 100644 --- a/modoboa/admin/models/domain.py +++ b/modoboa/admin/models/domain.py @@ -110,7 +110,7 @@ class Domain(AdminObject): """return true if the domain was created in the latest 24h""" now = timezone.now() delta = datetime.timedelta(days=1) - return bool(self.creation + delta > now) + return self.creation + delta > now def awaiting_checks(self): """return true if the domain has no valid MX records and was created