mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Merge pull request #915 from bearstech/mx_ui
improve mx UI; move valid-mx parameters to UI too
This commit is contained in:
@@ -61,6 +61,17 @@ class AdminParametersForm(parameters.AdminParametersForm):
|
||||
)
|
||||
)
|
||||
|
||||
valid_mxs = forms.CharField(
|
||||
label=ugettext_lazy("Valid MXs"),
|
||||
initial="",
|
||||
help_text=ugettext_lazy(
|
||||
"IP(s) or network(s) "
|
||||
"of the MX that should match with domains' MX records. "
|
||||
"On per line."
|
||||
),
|
||||
widget=forms.Textarea
|
||||
)
|
||||
|
||||
enable_dnsbl_checks = YesNoField(
|
||||
label=ugettext_lazy("Enable DNSBL checks"),
|
||||
initial="yes",
|
||||
|
||||
@@ -38,12 +38,15 @@ class CheckMXRecords(BaseCommand):
|
||||
"""Return sender address for notifications."""
|
||||
return parameters.get_admin("SENDER_ADDRESS", app="core")
|
||||
|
||||
@cached_property
|
||||
def valid_mxs(self):
|
||||
"""Return valid MXs set in admin."""
|
||||
valid_mxs = parameters.get_admin("VALID_MXS", app="admin")
|
||||
return [ipaddress.ip_network(u"{}".format(v.strip()))
|
||||
for v in valid_mxs.split() if v.strip()]
|
||||
|
||||
def add_arguments(self, parser):
|
||||
"""Add extra arguments to command."""
|
||||
parser.add_argument(
|
||||
"--valid-mx", type=str, action="append", default=[],
|
||||
help="Valid MX ip(s) or subnet(s) used to check that domain's MX "
|
||||
"are your own.")
|
||||
parser.add_argument(
|
||||
"--no-dnsbl", action="store_true", default=False,
|
||||
help="Skip DNSBL queries.")
|
||||
@@ -158,7 +161,7 @@ class CheckMXRecords(BaseCommand):
|
||||
if not status:
|
||||
print(msg)
|
||||
|
||||
def check_valid_mx(self, domain, mx_list, valid_mx=None, **options):
|
||||
def check_valid_mx(self, domain, mx_list, **options):
|
||||
"""Check that domain's MX record exist.
|
||||
|
||||
If `valid_mx` is provided, retrieved MX records must be
|
||||
@@ -166,14 +169,17 @@ class CheckMXRecords(BaseCommand):
|
||||
"""
|
||||
alerts = []
|
||||
check = False
|
||||
mxs = [ipaddress.ip_address(u"%s" % mx.address) for mx in mx_list]
|
||||
mxs = [(mx, ipaddress.ip_address(u"%s" % mx.address))
|
||||
for mx in mx_list]
|
||||
valid_mxs = self.valid_mxs
|
||||
if not mxs:
|
||||
alerts.append(_("Domain {} as no MX record").format(domain))
|
||||
elif valid_mx:
|
||||
for subnet in valid_mx:
|
||||
check = True in [mx in subnet for mx in mxs]
|
||||
if check is True:
|
||||
break
|
||||
elif valid_mxs:
|
||||
for subnet in valid_mxs:
|
||||
for mx, addr in mxs:
|
||||
if addr in subnet:
|
||||
mx.managed = check = True
|
||||
mx.save()
|
||||
if check is False:
|
||||
mx_names = [
|
||||
"{0.name} ({0.address})".format(mx) for mx in mx_list]
|
||||
@@ -192,7 +198,7 @@ class CheckMXRecords(BaseCommand):
|
||||
return
|
||||
content = render_to_string(
|
||||
"admin/notifications/domain_invalid_mx.html", {
|
||||
"domain": domain, "valid_mx": valid_mx, "alerts": alerts
|
||||
"domain": domain, "alerts": alerts
|
||||
})
|
||||
subject = _("[modoboa] MX issue(s) for domain {}").format(
|
||||
domain.name)
|
||||
@@ -227,11 +233,6 @@ class CheckMXRecords(BaseCommand):
|
||||
|
||||
def handle(self, *args, **options):
|
||||
"""Command entry point."""
|
||||
# Check that user provide valid network addresses
|
||||
valid_mx = options["valid_mx"]
|
||||
options["valid_mx"] = [
|
||||
ipaddress.ip_network(u"{}".format(v)) for v in valid_mx]
|
||||
|
||||
# Remove deprecated records first
|
||||
models.DNSBLResult.objects.exclude(
|
||||
provider__in=self.providers).delete()
|
||||
|
||||
@@ -224,6 +224,17 @@ class Domain(AdminObject):
|
||||
reversion.register(Domain)
|
||||
|
||||
|
||||
class MXQuerySet(models.QuerySet):
|
||||
"""Custom manager for MXRecord."""
|
||||
|
||||
def has_valids(self):
|
||||
"""Return managed results."""
|
||||
if parameters.get_admin("ENABLE_MX_CHECKS"):
|
||||
if parameters.get_admin("VALID_MXS", app="admin").strip():
|
||||
return self.filter(managed=True).exists()
|
||||
return self.exists()
|
||||
|
||||
|
||||
class MXRecord(models.Model):
|
||||
"""A model used to store MX records for Domain."""
|
||||
|
||||
@@ -233,6 +244,13 @@ class MXRecord(models.Model):
|
||||
managed = models.BooleanField(default=False)
|
||||
updated = models.DateTimeField()
|
||||
|
||||
objects = models.Manager.from_queryset(MXQuerySet)()
|
||||
|
||||
def is_managed(self):
|
||||
if not parameters.get_admin("ENABLE_MX_CHECKS"):
|
||||
return False
|
||||
return bool(parameters.get_admin("VALID_MXS", app="admin").strip())
|
||||
|
||||
def __unicode__(self):
|
||||
return u'{0.name} ({0.address}) for {0.domain} '.format(self)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<span class="title">{% trans "DNS status" %}</span>
|
||||
<span class="label label-mini label-{% if not domain.mxrecord_set.exists %}danger{% else %}success{% endif %}"><a href="{% url 'admin:mx_domain_detail' domain.pk %}" data-toggle="ajaxmodal">MX</a></span>
|
||||
<span class="label label-mini label-{% if not domain.mxrecord_set.has_valids %}danger{% else %}success{% endif %}"><a href="{% url 'admin:mx_domain_detail' domain.pk %}" data-toggle="ajaxmodal">MX</a></span>
|
||||
<span class="label label-{{ domain.dnsbl_status_color }}"><a href="{% url 'admin:dnsbl_domain_detail' domain.pk %}" data-toggle="ajaxmodal">DNSBL</a></span>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
@@ -15,14 +15,27 @@
|
||||
{% for mx in domain.mxrecord_set.all %}
|
||||
<tr>
|
||||
<td>{{ mx.name }}</td>
|
||||
<td>{{ mx.address }}</td>
|
||||
<td>
|
||||
{% if mx.is_managed %}
|
||||
{% if not mx.managed %}
|
||||
<a class="label label-danger help"
|
||||
rel="popover"
|
||||
data-content="{% trans 'This IP does not match any of the valid MXs defined in parameters' %}"
|
||||
>{{ mx.address }}</a>
|
||||
{% else %}
|
||||
<span class="label label-success">{{ mx.address }}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ mx.address }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ mx.updated|date:"SHORT_DATETIME_FORMAT" }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="3">{% trans "No MX record found for this domain." %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
||||
@@ -5,6 +5,7 @@ from django.core.urlresolvers import reverse
|
||||
from django.test import override_settings
|
||||
|
||||
from modoboa.lib.tests import ModoTestCase
|
||||
from modoboa.lib import parameters
|
||||
|
||||
from .. import factories
|
||||
from .. import models
|
||||
@@ -19,28 +20,26 @@ class MXTestCase(ModoTestCase):
|
||||
super(MXTestCase, cls).setUpTestData()
|
||||
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')
|
||||
|
||||
def test_management_command(self):
|
||||
"""Check that command works fine."""
|
||||
self.assertEqual(models.MXRecord.objects.count(), 0)
|
||||
management.call_command("modo", "check_mx", "--no-dnsbl",
|
||||
"--valid-mx=127.0.0.1", "--ttl=0")
|
||||
management.call_command("modo", "check_mx", "--no-dnsbl", "--ttl=0")
|
||||
self.assertTrue(
|
||||
models.MXRecord.objects.filter(domain=self.domain).exists())
|
||||
|
||||
# we passed a ttl to 0. this will reset the cache this time
|
||||
qs = models.MXRecord.objects.filter(domain=self.domain)
|
||||
id = qs[0].id
|
||||
management.call_command("modo", "check_mx", "--no-dnsbl",
|
||||
"--valid-mx=127.0.0.1", "--ttl=7200")
|
||||
management.call_command("modo", "check_mx", "--no-dnsbl", "--ttl=7200")
|
||||
qs = models.MXRecord.objects.filter(domain=self.domain)
|
||||
self.assertNotEqual(id, qs[0].id)
|
||||
id = qs[0].id
|
||||
|
||||
# assume that mxrecords ids are the same. means that we taking care of
|
||||
# ttl
|
||||
management.call_command("modo", "check_mx", "--no-dnsbl",
|
||||
"--valid-mx=127.0.0.1")
|
||||
management.call_command("modo", "check_mx", "--no-dnsbl")
|
||||
qs = models.MXRecord.objects.filter(domain=self.domain)
|
||||
self.assertEqual(id, qs[0].id)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user