From e13b42cd134f4c35e42c1def45846a400a7f61bb Mon Sep 17 00:00:00 2001 From: Daniel Roschka Date: Sat, 5 Sep 2015 19:03:21 +0200 Subject: [PATCH] Refactors the views used to add and delete records. Notable changes are: * Refactored views, utilizing more of Djangos features, resulting in simpler code. * URLs are now the same when initially filling out a form and when editing a submitted form which contained errors. * Instead of a result page showing the response from the DNS server (which is now logged using Djangos "logging" functionality) the user is now redirected back to the record listing of the current zone when the action was successful or stays on the form page when an error occured. Proper success/error messages are shown in both cases by utilizing Djangos "messages" functionality. --- binder/exceptions.py | 2 +- binder/forms.py | 35 ++- binder/helpers.py | 61 +++-- binder/settings.py | 33 +++ binder/templates/base.html | 27 +- .../bcommon/add_cname_record_form.html | 24 +- binder/templates/bcommon/add_record_form.html | 30 ++- ...record_initial.html => delete_record.html} | 8 +- binder/templates/bcommon/list_zone.html | 11 +- binder/templates/bcommon/response_result.html | 18 -- binder/tests/testViews.py | 38 +-- binder/urls.py | 7 +- binder/views.py | 237 ++++++++---------- 13 files changed, 257 insertions(+), 274 deletions(-) rename binder/templates/bcommon/{delete_record_initial.html => delete_record.html} (85%) delete mode 100644 binder/templates/bcommon/response_result.html diff --git a/binder/exceptions.py b/binder/exceptions.py index f05272d..1d8e420 100644 --- a/binder/exceptions.py +++ b/binder/exceptions.py @@ -17,7 +17,7 @@ class ZoneException(Exception): class RecordException(Exception): - """Thrown when there is an issue dealign with a Record. + """Thrown when there is an issue dealing with a Record. * Adding or deleting. """ diff --git a/binder/forms.py b/binder/forms.py index 53fd31c..42e0f2b 100644 --- a/binder/forms.py +++ b/binder/forms.py @@ -17,7 +17,8 @@ class CustomUnicodeListField(forms.CharField): try: string_list = [str(cur_rr) for cur_rr in eval(value)] except: - raise ValidationError("Error in converting Unicode list to list of Strings: %r" % value) + raise ValidationError("Error in converting Unicode list to list " + "of strings: %r" % value) return string_list @@ -37,7 +38,8 @@ class CustomStringPeriodSuffix(forms.CharField): if new_string[-1] != ".": new_string += "." except: - raise ValidationError("Unable to stick a period on the end of your input: %r" % value) + raise ValidationError("Unable to stick a period on the end of " + "your input: %r" % value) return new_string @@ -50,13 +52,17 @@ class FormAddForwardRecord(forms.Form): record_name = forms.RegexField(max_length=100, regex="^[a-zA-Z0-9-_]+$", required=False) - record_type = forms.ChoiceField(choices=settings.RECORD_TYPE_CHOICES) + record_type = forms.ChoiceField(choices=settings.RECORD_TYPE_CHOICES, + widget=forms.RadioSelect) zone_name = forms.CharField(max_length=100) record_data = forms.GenericIPAddressField() - ttl = forms.ChoiceField(choices=settings.TTL_CHOICES) + ttl = forms.ChoiceField(choices=settings.TTL_CHOICES, + widget=forms.RadioSelect) create_reverse = forms.BooleanField(required=False) key_name = forms.ModelChoiceField(queryset=Key.objects.all(), - required=False) + required=False, + widget=forms.RadioSelect, + empty_label=None) class FormAddReverseRecord(forms.Form): @@ -66,12 +72,16 @@ class FormAddReverseRecord(forms.Form): dns_server = forms.CharField(max_length=100) record_name = forms.IntegerField(min_value=0, max_value=255) record_type = forms.RegexField(regex=r"^PTR$", - error_messages={"invalid": "The only valid choice here is PTR."}) + error_messages={ + "invalid": "The only valid choice here " + "is PTR."}) zone_name = forms.CharField(max_length=100) record_data = CustomStringPeriodSuffix(required=True) ttl = forms.ChoiceField(choices=settings.TTL_CHOICES) key_name = forms.ModelChoiceField(queryset=Key.objects.all(), - required=False) + required=False, + widget=forms.RadioSelect, + empty_label=None) create_reverse = forms.BooleanField(required=False) @@ -83,9 +93,12 @@ class FormAddCnameRecord(forms.Form): originating_record = forms.CharField(max_length=100) cname = forms.RegexField(max_length=100, regex="^[a-zA-Z0-9-_]+$") zone_name = forms.CharField(max_length=256) - ttl = forms.ChoiceField(choices=settings.TTL_CHOICES) + ttl = forms.ChoiceField(choices=settings.TTL_CHOICES, + widget=forms.RadioSelect) key_name = forms.ModelChoiceField(queryset=Key.objects.all(), - required=False) + required=False, + widget=forms.RadioSelect, + empty_label=None) class FormDeleteRecord(forms.Form): @@ -96,4 +109,6 @@ class FormDeleteRecord(forms.Form): zone_name = forms.CharField(max_length=256) rr_list = CustomUnicodeListField() key_name = forms.ModelChoiceField(queryset=Key.objects.all(), - required=False) + required=False, + widget=forms.RadioSelect, + empty_label=None) diff --git a/binder/helpers.py b/binder/helpers.py index 45ea517..8c8114b 100644 --- a/binder/helpers.py +++ b/binder/helpers.py @@ -1,11 +1,13 @@ # Binder Helpers # Standard Imports +import logging import re import socket # 3rd Party import dns.query +import dns.rcode import dns.reversename import dns.tsig import dns.tsigkeyring @@ -13,6 +15,7 @@ import dns.update # App Imports from binder import models +from binder.exceptions import KeyringException, RecordException def add_record(dns_server, zone_name, record_name, record_type, record_data, @@ -89,11 +92,13 @@ def delete_record(dns_server, rr_list, key_name): """Delete a list of DNS records passed as strings in rr_items.""" server = models.BindServer.objects.get(hostname=dns_server) + logger = logging.getLogger('binder.helpers') try: transfer_key = models.Key.objects.get(name=key_name) - except models.Key.DoesNotExist: - keyring = None - algorithm = None + except models.Key.DoesNotExist as exc: + logger.error(exc) + raise KeyringException("The specified TSIG key %s does not exist in " + "binders configuration." % key_name) else: keyring = transfer_key.create_keyring() algorithm = transfer_key.algorithm @@ -107,13 +112,19 @@ def delete_record(dns_server, rr_list, key_name): keyring=keyring, keyalgorithm=algorithm) dns_update.delete(record) - output = send_dns_update(dns_update, - dns_server, - server.dns_port, - key_name) - - delete_response.append({"description": "Delete Record: %s" % current_rr, - "output": output}) + try: + output = send_dns_update(dns_update, + dns_server, + server.dns_port, + key_name) + except (KeyringException, RecordException) as exc: + delete_response.append({"description": exc, + "record": current_rr, + "success": False}) + else: + delete_response.append({"description": output, + "record": current_rr, + "success": True}) return delete_response @@ -123,11 +134,13 @@ def create_update(dns_server, zone_name, record_name, record_type, record_data, """Update/Create DNS record of name and type with passed data and ttl.""" server = models.BindServer.objects.get(hostname=dns_server) + logger = logging.getLogger('binder.helpers') try: transfer_key = models.Key.objects.get(name=key_name) - except models.Key.DoesNotExist: - keyring = None - algorithm = None + except models.Key.DoesNotExist as exc: + logger.error(exc) + raise KeyringException("The specified TSIG key %s does not exist in " + "binders configuration." % key_name) else: keyring = transfer_key.create_keyring() algorithm = transfer_key.algorithm @@ -174,13 +187,21 @@ def send_dns_update(dns_message, dns_server, port, key_name): Returns: String output """ + logger = logging.getLogger('binder.helpers') try: output = dns.query.tcp(dns_message, dns_server, port=port) - except dns.tsig.PeerBadKey: - output = ("DNS server %s is not configured for TSIG key: %s." % - (dns_server, key_name)) - except dns.tsig.PeerBadSignature: - output = ("DNS server %s did like the TSIG signature we sent. Check " - "key %s for correctness." % (dns_server, key_name)) - + except dns.tsig.PeerBadKey as exc: + logger.error(exc) + raise KeyringException("DNS server %s is not configured for TSIG key: %s." % + (dns_server, key_name)) + except dns.tsig.PeerBadSignature as exc: + logger.error(exc) + raise KeyringException("DNS server %s didn't like the TSIG signature " + "we sent. Check key %s for correctness." % + (dns_server, key_name)) + logger.debug(output) + return_code = output.rcode() + if return_code != dns.rcode.NOERROR: + raise RecordException('Error when requesting DNS server %s: %s' % + (dns_server, dns.rcode.to_text(return_code))) return output diff --git a/binder/settings.py b/binder/settings.py index a23da1a..d0ecfaa 100644 --- a/binder/settings.py +++ b/binder/settings.py @@ -1,5 +1,6 @@ # Django settings for binder project. import os +from django.contrib.messages import constants as messages SITE_ROOT = os.path.dirname(os.path.realpath(__file__)) DEBUG = True @@ -88,6 +89,38 @@ INSTALLED_APPS = ( TEST_RUNNER = 'django.test.runner.DiscoverRunner' +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'verbose': { + 'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s", + 'datefmt' : "%d/%b/%Y %H:%M:%S" + } + }, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + 'formatter': 'verbose' + }, + }, + 'loggers': { + 'django': { + 'handlers': ['console'], + 'propagate': True, + 'level': 'INFO' + }, + 'binder': { + 'handlers': ['console'], + 'level': 'DEBUG' + } + } +} + +MESSAGE_TAGS = { + messages.ERROR: 'danger' +} + TTL_CHOICES = ((300, "5 minutes"), (1800, "30 minutes"), (3600, "1 hour"), diff --git a/binder/templates/base.html b/binder/templates/base.html index d9a6ef6..4d191fa 100644 --- a/binder/templates/base.html +++ b/binder/templates/base.html @@ -10,7 +10,6 @@ {% endblock header %} - @@ -35,6 +34,8 @@ + +
@@ -44,23 +45,17 @@
- {% block errors %} - {% if errors %} -
- Errors were encountered: -
- {{ errors }} -
- {% endif %} - {% endblock errors %} - - {% block body %} - {% endblock body %} + {% if messages %} +
    + {% for message in messages %} + + {% endfor %} +
+ {% endif %} + {% block body %}{% endblock body %}
+{% block footer %}{% endblock footer %} - -{% block footer %} -{% endblock footer %} diff --git a/binder/templates/bcommon/add_cname_record_form.html b/binder/templates/bcommon/add_cname_record_form.html index ed70b51..149c975 100644 --- a/binder/templates/bcommon/add_cname_record_form.html +++ b/binder/templates/bcommon/add_cname_record_form.html @@ -1,9 +1,9 @@ {% extends "base.html" %} -{% block pageheader %}Add CNAME record for {{ originating_record }}{% endblock pageheader %} +{% block pageheader %}Add CNAME record for {{ form.originating_record.value }}.{{ form.zone_name.value }}{% endblock pageheader %} {% block body %} -
{% csrf_token %} +{% csrf_token %} Create CNAME record
@@ -24,7 +24,7 @@
- +
{% if form.originating_record.errors %}
@@ -41,8 +41,8 @@
- .{{zone_name}} - + .{{ form.zone_name.value }} +
{% if form.cname.errors %} @@ -58,10 +58,8 @@
@@ -79,10 +77,10 @@
@@ -100,7 +98,7 @@
- Cancel + Cancel
diff --git a/binder/templates/bcommon/add_record_form.html b/binder/templates/bcommon/add_record_form.html index 4607429..48e3969 100644 --- a/binder/templates/bcommon/add_record_form.html +++ b/binder/templates/bcommon/add_record_form.html @@ -1,9 +1,9 @@ {% extends "base.html" %} -{% block pageheader %}Add record in {{ zone_name }}{% endblock pageheader %} +{% block pageheader %}Add record in {{ form.zone_name.value }}{% endblock pageheader %} {% block body %} -
{% csrf_token %} +{% csrf_token %} Create Record
@@ -26,8 +26,8 @@
- .{{zone_name}} - + .{{ form.zone_name.value }} +
{% if form.record_name.errors %} @@ -43,9 +43,9 @@
- {% for ttl, description in ttl_choices %} - + {% for choice in form.ttl %} + {% endfor %}
@@ -97,7 +95,7 @@ {% endif %}
- {% if "in-addr.arpa" not in zone_name and "ip.arpa" not in zone_name %} + {% if "in-addr.arpa" not in form.zone_name.value and "ip.arpa" not in form.zone_name.value %}
@@ -110,10 +108,10 @@
@@ -131,7 +129,7 @@
- Cancel + Cancel
diff --git a/binder/templates/bcommon/delete_record_initial.html b/binder/templates/bcommon/delete_record.html similarity index 85% rename from binder/templates/bcommon/delete_record_initial.html rename to binder/templates/bcommon/delete_record.html index 3d252d1..a6eb60e 100644 --- a/binder/templates/bcommon/delete_record_initial.html +++ b/binder/templates/bcommon/delete_record.html @@ -3,7 +3,7 @@ {% block pageheader %}Delete record(s) in {{ zone_name }}{% endblock pageheader %} {% block body %} -
{% csrf_token %} +{% csrf_token %} Delete Record
@@ -39,10 +39,10 @@
diff --git a/binder/templates/bcommon/list_zone.html b/binder/templates/bcommon/list_zone.html index 9c77109..a72cd95 100644 --- a/binder/templates/bcommon/list_zone.html +++ b/binder/templates/bcommon/list_zone.html @@ -3,13 +3,9 @@ {% block pageheader %}Zone listing for {{ zone_name }} on {{ dns_server.hostname }}{% endblock pageheader %} {% block body %} -{% if not errors %} -Add Record +

Add Record

-{% csrf_token %} - - - +{% csrf_token %} @@ -48,7 +44,6 @@ {% endfor %}
- +

-{% endif %} {% endblock body %} diff --git a/binder/templates/bcommon/response_result.html b/binder/templates/bcommon/response_result.html deleted file mode 100644 index f52cbbd..0000000 --- a/binder/templates/bcommon/response_result.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "base.html" %} - -{% block pageheader %}Record Result{% endblock pageheader %} - -{% block body %} - -{% for current_response in response %} - - - - - - - - -{% endfor %} -
RecordOutput
{{ current_response.description }}
{{ current_response.output }}
-{% endblock body %} diff --git a/binder/tests/testViews.py b/binder/tests/testViews.py index 8eb3b95..c19709b 100644 --- a/binder/tests/testViews.py +++ b/binder/tests/testViews.py @@ -27,18 +27,6 @@ class GetTests(TestCase): response = self.client.get(reverse("server_list")) self.assertEqual(response.status_code, 200) - def test_GetResultRedirects(self): - """GETing a /result/ URL should always redirect to /.""" - response = self.client.get(reverse("add_record_result"), follow=True) - self.assertRedirects(response, reverse("index")) - self.assertEqual(response.status_code, 200) - response = self.client.get(reverse("delete_record_result"), follow=True) - self.assertRedirects(response, reverse("index")) - self.assertEqual(response.status_code, 200) - response = self.client.get(reverse("add_cname_result"), follow=True) - self.assertRedirects(response, reverse("index")) - self.assertEqual(response.status_code, 200) - def test_GetInvalidServer(self): """Get a zone list for a server not in the database.""" server_name = "unconfigured.server.net" @@ -64,20 +52,18 @@ class PostTests(TestCase): def test_DeleteRecordInitial_Empty(self): """Ensure the initial deletion form works as expected with no RR list.""" + dns_server = "testserver.test.net" + zone_name = "testzone1.test.net" response = self.client.post(reverse("delete_record"), - {"dns_server": "testserver.test.net", - "zone_name": "testzone1.test.net", - "rr_list": []}) - - self.assertContains(response, - '', - html=True) - self.assertContains(response, - '', - html=True) - self.assertContains(response, - '', - html=True) + {"dns_server": dns_server, + "zone_name": zone_name, + "rr_list": []}, follow=True) + self.assertRedirects(response, + reverse("zone_list", + kwargs={'dns_server': dns_server, + 'zone_name': zone_name})) + self.assertEqual(response.status_code, 200) + self.assertContains(response, "Select at least one record for deletion.") def test_DeleteRecordInitial(self): @@ -86,6 +72,8 @@ class PostTests(TestCase): "zone_name": "testzone1.test.net", "rr_list": ["testrecord1.testzone1.test.net", "testrecord2.testzone1.test.net"]}) + + self.assertEqual(response.status_code, 200) self.assertContains(response, '', html=True) self.assertContains(response, diff --git a/binder/urls.py b/binder/urls.py index 7e08d4e..379b84a 100644 --- a/binder/urls.py +++ b/binder/urls.py @@ -15,11 +15,6 @@ urlpatterns = patterns('', url(r'^info/(?P[a-zA-Z0-9.-]+)/(?P[a-zA-Z0-9.-]+)/$', 'binder.views.view_zone_records', name="zone_list"), url(r'^add_record/(?P[a-zA-Z0-9.-]+)/(?P[a-zA-Z0-9.-]+)/$', 'binder.views.view_add_record', name="add_record"), - url(r'^add_record/result/$', 'binder.views.view_add_record_result', name="add_record_result"), - - url(r'^delete_record/$', 'binder.views.view_delete_record', name="delete_record"), - url(r'^delete_record/result/$', 'binder.views.view_delete_result', name="delete_record_result"), - url(r'^add_cname/(?P[a-zA-Z0-9.-]+)/(?P[a-zA-Z0-9.-]+)/(?P.*?)/$', 'binder.views.view_add_cname_record', name="add_cname"), - url(r'^add_cname_record/result/$', 'binder.views.view_add_cname_result', name="add_cname_result"), + url(r'^delete_record/(?P[a-zA-Z0-9.-]+)/(?P[a-zA-Z0-9.-]+)/$', 'binder.views.view_delete_record', name="delete_record"), ) diff --git a/binder/views.py b/binder/views.py index 5b85639..86b9b38 100644 --- a/binder/views.py +++ b/binder/views.py @@ -1,12 +1,12 @@ # Binder VIews # 3rd Party -from django.conf import settings +from django.contrib import messages from django.shortcuts import get_object_or_404, redirect, render # App Imports -from binder import exceptions, forms, helpers, models - +from binder import forms, helpers, models +from binder.exceptions import KeyringException, RecordException, TransferException, ZoneException def home_index(request): """List the main index page for Binder.""" @@ -27,184 +27,147 @@ def view_server_list(request): def view_server_zones(request, dns_server): """Display the list of DNS zones a particular DNS host provides.""" - errors = "" zone_array = {} this_server = get_object_or_404(models.BindServer, hostname=dns_server) try: zone_array = this_server.list_zones() - except exceptions.ZoneException, err: - errors = "Unable to list server zones. Error: %s" % err + except ZoneException as exc: + messages.error(request, "Unable to list server zones. Error: %s" % exc) return render(request, "bcommon/list_server_zones.html", - {"errors": errors, - "dns_server": this_server, + {"dns_server": this_server, "zone_array": zone_array}) def view_zone_records(request, dns_server, zone_name): """Display the list of records for a particular zone.""" - errors = "" zone_array = {} this_server = get_object_or_404(models.BindServer, hostname=dns_server) try: zone_array = this_server.list_zone_records(zone_name) - except exceptions.TransferException, err: + except TransferException as exc: return render(request, "bcommon/list_zone.html", - {"errors": err, - "zone_name": zone_name, + {"zone_name": zone_name, "dns_server": this_server}) return render(request, "bcommon/list_zone.html", {"zone_array": zone_array, "dns_server": this_server, - "zone_name": zone_name, - "errors": errors}) + "zone_name": zone_name}) def view_add_record(request, dns_server, zone_name): - """View to provide form to add a DNS record.""" + """View to allow to add A records.""" this_server = get_object_or_404(models.BindServer, hostname=dns_server) + if request.method == 'POST': + form = forms.FormAddForwardRecord(request.POST) + if form.is_valid(): + form_cleaned = form.cleaned_data + try: + helpers.add_record(form_cleaned["dns_server"], + str(form_cleaned["zone_name"]), + str(form_cleaned["record_name"]), + str(form_cleaned["record_type"]), + str(form_cleaned["record_data"]), + form_cleaned["ttl"], + form_cleaned["key_name"], + form_cleaned["create_reverse"]) + except (KeyringException, RecordException) as exc: + messages.error(request, "Adding %s.%s failed: %s" % + (form_cleaned["record_name"], zone_name, exc)) + else: + messages.success(request, "%s.%s was added successfully." % + (form_cleaned["record_name"], zone_name)) + return redirect('zone_list', + dns_server=dns_server, + zone_name=zone_name) + else: + form = forms.FormAddForwardRecord(initial={'zone_name': zone_name}) + return render(request, "bcommon/add_record_form.html", {"dns_server": this_server, - "zone_name": zone_name, - "tsig_keys": models.Key.objects.all(), - "ttl_choices": settings.TTL_CHOICES, - "record_type_choices": settings.RECORD_TYPE_CHOICES}) - - -def view_add_record_result(request): - """Process the input given to add a DNS record.""" - errors = "" - if request.method == "GET": - return redirect("/") - - if "HTTP_REFERER" in request.META: - incoming_zone = request.META["HTTP_REFERER"].split("/")[-2] - if ("in-addr.arpa" in incoming_zone) or ("ip6.arpa" in incoming_zone): - form = forms.FormAddReverseRecord(request.POST) - else: - form = forms.FormAddForwardRecord(request.POST) - else: - form = forms.FormAddForwardRecord(request.POST) - - if form.is_valid(): - form_cleaned = form.cleaned_data - try: - response = helpers.add_record(form_cleaned["dns_server"], - str(form_cleaned["zone_name"]), - str(form_cleaned["record_name"]), - str(form_cleaned["record_type"]), - str(form_cleaned["record_data"]), - form_cleaned["ttl"], - form_cleaned["key_name"], - form_cleaned["create_reverse"]) - except exceptions.RecordException, err: - # TODO: Start using this exception. - # What would cause this? - errors = err - - return render(request, "bcommon/response_result.html", - {"errors": errors, - "response": response}) - - dns_server = models.BindServer.objects.get(hostname=request.POST["dns_server"]) - - return render(request, "bcommon/add_record_form.html", - {"dns_server": dns_server, - "zone_name": request.POST["zone_name"], - "tsig_keys": models.Key.objects.all(), - "ttl_choices": settings.TTL_CHOICES, - "record_type_choices": settings.RECORD_TYPE_CHOICES, "form": form}) def view_add_cname_record(request, dns_server, zone_name, record_name): - """Process given input to add a CNAME pointer.""" + """View to allow to add CNAME records.""" this_server = get_object_or_404(models.BindServer, hostname=dns_server) + if request.method == 'POST': + form = forms.FormAddCnameRecord(request.POST) + if form.is_valid(): + form_cleaned = form.cleaned_data + try: + helpers.add_cname_record(form_cleaned["dns_server"], + str(form_cleaned["zone_name"]), + str(form_cleaned["cname"]), + '%s.%s' % (str(form_cleaned["originating_record"]), + str(form_cleaned["zone_name"])), + form_cleaned["ttl"], + form_cleaned["key_name"]) + except (KeyringException, RecordException) as exc: + messages.error(request, "Adding %s.%s failed: %s" % + (form_cleaned["record_name"], zone_name, exc)) + else: + messages.success(request, "%s.%s was added successfully." % + (form_cleaned["record_name"], zone_name)) + return redirect('zone_list', + dns_server=dns_server, + zone_name=zone_name) + else: + form = forms.FormAddCnameRecord(initial={'originating_record': record_name, + 'zone_name': zone_name}) + return render(request, "bcommon/add_cname_record_form.html", {"dns_server": this_server, - "originating_record": "%s.%s" % (record_name, zone_name), - "zone_name": zone_name, - "ttl_choices": settings.TTL_CHOICES, - "tsig_keys": models.Key.objects.all()}) - - -def view_add_cname_result(request): - """Process input on the CNAME form and provide a response.""" - if request.method == "GET": - return redirect("/") - - errors = "" - add_cname_response = "" - form = forms.FormAddCnameRecord(request.POST) - if form.is_valid(): - form_cleaned = form.cleaned_data - try: - add_cname_response = helpers.add_cname_record( - form_cleaned["dns_server"], - form_cleaned["zone_name"], - form_cleaned["cname"], - str(form_cleaned["originating_record"]), - form_cleaned["ttl"], - form_cleaned["key_name"]) - except exceptions.RecordException, err: - errors = err - - return render(request, "bcommon/response_result.html", - {"response": add_cname_response, - "errors": errors}) - - dns_server = models.BindServer.objects.get(hostname=request.POST["dns_server"]) - - return render(request, "bcommon/add_cname_record_form.html", - {"dns_server": dns_server, - "zone_name": request.POST["zone_name"], - "record_name": request.POST["cname"], - "originating_record": request.POST["originating_record"], - "ttl_choices": settings.TTL_CHOICES, - "tsig_keys": models.Key.objects.all(), "form": form}) -def view_delete_record(request): - """Provide the initial form for deleting records.""" - if request.method == "GET": - return redirect("/") - - dns_server = models.BindServer.objects.get(hostname=request.POST["dns_server"]) - zone_name = request.POST["zone_name"] +def view_delete_record(request, dns_server, zone_name): + """View to handle the deletion of records.""" + dns_server = models.BindServer.objects.get(hostname=dns_server) rr_list = request.POST.getlist("rr_list") - return render(request, "bcommon/delete_record_initial.html", + if len(rr_list) == 0: + messages.error(request, "Select at least one record for deletion.") + return redirect('zone_list', + dns_server=dns_server, + zone_name=zone_name) + + if request.method == 'POST': + form = forms.FormDeleteRecord(request.POST) + if form.is_valid(): + form_cleaned = form.cleaned_data + rr_list = form_cleaned["rr_list"] + try: + response = helpers.delete_record(form_cleaned["dns_server"], + rr_list, + form_cleaned["key_name"]) + except KeyringException as exc: + for record in rr_list: + messages.error(request, "Deleting %s.%s failed: %s" % + (record, zone_name, exc)) + else: + for record in response: + if record['success'] == True: + messages.success(request, "%s.%s was removed successfully." % + (record['record'], zone_name)) + else: + messages.error(request, "Deleting %s.%s failed: %s" % + (record['record'], zone_name, record['description'])) + return redirect('zone_list', + dns_server=dns_server, + zone_name=zone_name) + else: + form = forms.FormDeleteRecord(initial={'zone_name': zone_name}) + + return render(request, "bcommon/delete_record.html", {"dns_server": dns_server, "zone_name": zone_name, - "rr_list": rr_list, - "tsig_keys": models.Key.objects.all()}) - - -def view_delete_result(request): - """View that deletes records and returns the response.""" - if request.method == "GET": - return redirect("/") - - form = forms.FormDeleteRecord(request.POST) - - if form.is_valid(): - clean_form = form.cleaned_data - else: - # TODO: What situations would cause this form - # not to validate? - print "in view_delete_result, form errors: %r" % form.errors - - delete_result = helpers.delete_record(clean_form["dns_server"], - clean_form["rr_list"], - clean_form["key_name"]) - - return render(request, "bcommon/response_result.html", - {"response": delete_result}) + "rr_list": rr_list, + "form": form})