1. George Notaras
  2. django-powerdns-manager

Commits

George Notaras  committed 0855b0b

Added view for zone cloning. The admin action also redirects to this view.

  • Participants
  • Parent commits c241479
  • Branches default

Comments (0)

Files changed (5)

File src/powerdns_manager/actions.py

View file
  • Ignore whitespace
     
     Accepts only one selected zone.
     
-    Clones:
-    
-      - Resource Records
-      - Dynamic setting
-      - Domain Metadata
-    
-    This action first displays a page which provides an input box to enter
-    the origin of the new zone.
-    
-    It checks if the user has add & change permissions.
-    
-    It checks if a zone with the name that has been entered as new exists in
-    the database.
-    
-    Based on: https://github.com/django/django/blob/1.4.2/django/contrib/admin/actions.py
-    
-    Important
-    ---------
-    In order to work requires some special form fields (see the template).
-    
     """
-    opts = modeladmin.model._meta
-    app_label = opts.app_label
-    
-    Domain = cache.get_model('powerdns_manager', 'Domain')
-    Record = cache.get_model('powerdns_manager', 'Record')
-    DynamicZone = cache.get_model('powerdns_manager', 'DynamicZone')
-    DomainMetadata = cache.get_model('powerdns_manager', 'DomainMetadata')
-    
-    # Check the number of selected zones. This action can work on a single zone.
-    
     n = queryset.count()
     if n != 1:
         messages.error(request, 'Only one zone may be selected for cloning.')
-        return None
-    
-    # Check permissions
-        
-    perm_domain_add = '%s.%s' % (opts.app_label, opts.get_add_permission())
-    perm_domain_change = '%s.%s' % (opts.app_label, opts.get_change_permission())
-    perm_record_add = '%s.add_record' % opts.app_label
-    perm_record_change = '%s.change_record' % opts.app_label
-    
-    if not request.user.has_perms(
-            [perm_domain_add, perm_domain_change, perm_record_add, perm_record_change]):
-        raise PermissionDenied
+        return HttpResponseRedirect(reverse('admin:powerdns_manager_domain_changelist'))
     
     # Check that the user has change permission for the add and change modeladmin forms
     if not modeladmin.has_add_permission(request):
     if not modeladmin.has_change_permission(request):
         raise PermissionDenied
     
-    # The user has set a domain name for the clone through the forms.ClonedZoneDomainForm form.
-    #if request.method == 'POST':
-    if request.POST.get('post'):
-        form = ClonedZoneDomainForm(request.POST)
-        if form.is_valid():
-            
-            # Store Data from the form
-            
-            # Store the new domain name for the clone.
-            clone_domain_name = form.cleaned_data['clone_domain_name']
-            
-            if not clone_domain_name:
-                return None # Should never happen
-
-            option_clone_dynamic = form.cleaned_data['option_clone_dynamic']
-            option_clone_metadata = form.cleaned_data['option_clone_metadata']
-            
-            # Clone base zone
-            
-            # At this point queryset contain exactly one object. Checked above.
-            domain_obj = queryset[0]
-            
-            # Create the clone (Check for uniqueness takes place in forms.ClonedZoneDomainForm 
-            clone_obj = Domain.objects.create(
-                name = clone_domain_name,
-                master = domain_obj.master,
-                #last_check = domain_obj.last_check,
-                type = domain_obj.type,
-                #notified_serial = domain_obj.notified_serial,
-                account = domain_obj.account,
-                created_by = request.user   # We deliberately do not use the domain_obj.created_by
-            )
-            modeladmin.log_addition(request, clone_obj)
-            
-            # Clone Resource Records
-            
-            # Find all resource records of this domain (also clones empty non-terminals)
-            domain_rr_qs = Record.objects.filter(domain=domain_obj)
-            
-            # Create the clone's RRs
-            for rr in domain_rr_qs:
-                
-                # Construct RR name with interchanged domain
-                clone_rr_name = interchange_domain(rr.name, domain_obj.name, clone_domain_name)
-                
-                # Special treatment to the content of SOA and SRV RRs
-                if rr.type == 'SOA':
-                    content_parts = rr.content.split()
-                    # primary
-                    content_parts[0] = interchange_domain(content_parts[0], domain_obj.name, clone_domain_name)
-                    # hostmaster
-                    content_parts[1] = interchange_domain(content_parts[1], domain_obj.name, clone_domain_name)
-                    # Serial. Set new serial
-                    content_parts[2] = generate_serial()
-                    clone_rr_content = ' '.join(content_parts)
-                elif rr.type == 'SRV':
-                    content_parts = rr.content.split()
-                    # target
-                    content_parts[2] = interchange_domain(content_parts[2], domain_obj.name, clone_domain_name)
-                    clone_rr_content = ' '.join(content_parts)
-                else:
-                    clone_rr_content = interchange_domain(rr.content, domain_obj.name, clone_domain_name)
-                
-                # Create and save the cloned record.
-                clone_rr = Record(
-                    domain = clone_obj,
-                    name = clone_rr_name,
-                    type = rr.type,
-                    content = clone_rr_content,
-                    ttl = rr.ttl,
-                    prio = rr.prio,
-                    auth = rr.auth,
-                    ordername = rr.ordername
-                )
-                clone_rr.save()
-                #modeladmin.log_addition(request, clone_rr)
-            
-            # Clone Dynamic Zone setting
-            
-            if option_clone_dynamic:
-                
-                # Get the base domain's dynamic zone.
-                # There is only one Dynamic Zone object for each zone.
-                try:
-                    domain_dynzone_obj = DynamicZone.objects.get(domain=domain_obj)
-                except DynamicZone.DoesNotExist:
-                    pass
-                else:
-                    # Create and save the dynamic zone object for the clone.
-                    clone_dynzone_obj = DynamicZone(
-                        domain = clone_obj,
-                        is_dynamic = domain_dynzone_obj.is_dynamic
-                        )
-                    clone_dynzone_obj.save()
-            
-            # Clone the zone's metadata
-            
-            if option_clone_metadata:
-                
-                # Get the base domain's metadata object.
-                # There is only one metadata object for each zone.
-                try:
-                    domain_metadata_obj = DomainMetadata.objects.get(domain=domain_obj)
-                except DomainMetadata.DoesNotExist:
-                    pass
-                else:
-                    # Create and save the metadata object for the clone.
-                    clone_metadata_obj = DomainMetadata(
-                        domain = clone_obj,
-                        kind = domain_metadata_obj.kind,
-                        content = domain_metadata_obj.content
-                        )
-                    clone_metadata_obj.save()
-            
-            messages.info(request, 'Successfully cloned %s zone to %s' % \
-                (domain_obj.name, clone_domain_name))
-            
-            # Redirect to the new zone's change form.
-            return HttpResponseRedirect(reverse('admin:%s_domain_change' % app_label, args=(clone_obj.id,)))
-    
-    else:
-        form = ClonedZoneDomainForm()
-    
-    info_dict = {
-        'form': form,
-        'queryset': queryset,
-        'opts': opts,
-        'app_label': app_label,
-        'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
-    }
-    return render_to_response(
-        'powerdns_manager/actions/clone_zone.html', info_dict, context_instance=RequestContext(request))
+    return HttpResponseRedirect(reverse('zone_clone', args=(queryset[0].id,)))
 clone_zone.short_description = "Clone the selected zone"
 
 
 
 def transfer_zone_to_user(modeladmin, request, queryset):
     """Action that transfers the zone to another user."""
+    # Check that the user has change permission for the change modeladmin form.
+    if not modeladmin.has_change_permission(request):
+        raise PermissionDenied
     selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)
     return HttpResponseRedirect(reverse('zone_transfer', args=(','.join(selected),)))
 transfer_zone_to_user.short_description = 'Transfer zone to another user'

File src/powerdns_manager/admin.py

View file
  • Ignore whitespace
         
         if "_transfer" in request.POST:
             return HttpResponseRedirect(reverse('zone_transfer', args=(obj.id,)))
+        elif "_clone" in request.POST:
+            return HttpResponseRedirect(reverse('zone_clone', args=(obj.id,)))
 
-#         elif "_saveasnew" in request.POST:
-#             msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict
-#             self.message_user(request, msg, messages.SUCCESS)
-#             redirect_url = reverse('admin:%s_%s_change' %
-#                                    (opts.app_label, opts.model_name),
-#                                    args=(pk_value,),
-#                                    current_app=self.admin_site.name)
-#             redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url)
-#             return HttpResponseRedirect(redirect_url)
+        return super(DomainAdmin, self).response_change(request, obj)
 
 admin.site.register(cache.get_model('powerdns_manager', 'Domain'), DomainAdmin)
 

File src/powerdns_manager/templates/powerdns_manager/zone/clone.html

View file
  • Ignore whitespace
+{% extends "admin/base_site.html" %}
+{% load i18n l10n static %}
+{% load url from future %}
+{% load admin_urls %}
+
+{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %}
+
+{% block breadcrumbs %}
+    <div class="breadcrumbs">
+        <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+        &rsaquo; <a href="{% url 'admin:app_list' app_label="powerdns_manager" %}">{% trans "PowerDNS Manager" %}</a>
+        &rsaquo; <a href="{% url 'admin:powerdns_manager_domain_changelist' %}">{% trans "Zone list" %}</a>
+        {% if id_list|length == 1 %}
+            &rsaquo; <a href="{% url 'admin:powerdns_manager_domain_change' id_list|first %}">{% trans "Zone change form" %}</a>
+        {% endif %}
+        &rsaquo; {% trans 'Clone zone' %}
+    </div>
+{% endblock %}
+
+{% block title %}{% trans 'Set the domain name of the cloned zone' %}{% endblock %}
+
+{% block content %}
+    <div id="content-main">
+        
+        <form action="" method="post">{% csrf_token %}
+        <div>
+            {% if form.errors %}
+                <p class="errornote">
+                {% blocktrans count counter=form.errors.items|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
+                </p>
+            {% endif %}
+
+            <h1>{% trans 'Set the domain name of the cloned zone' %}</h1>
+            <p>{% trans "Enter a domain name for the cloned zone." %}</p>
+            
+            <fieldset class="module aligned">
+    
+                <div class="form-row">
+                    {{ form.clone_domain_name.errors }}
+                    <label for="id_clone_domain_name" class="">{% trans 'Domain Name' %}:</label>{{ form.clone_domain_name }}
+                    <p>{{ form.clone_domain_name.help_text }}</p>
+                </div>
+                
+                <div class="form-row">
+                    {{ form.option_clone_dynamic.errors }}
+                    <label for="id_option_clone_dynamic" class="">{% trans 'Clone dynamic setting' %}:</label>{{ form.option_clone_dynamic }}
+                    <p>{{ form.option_clone_dynamic.help_text }}</p>
+                </div>
+                
+                <div class="form-row">
+                    {{ form.option_clone_metadata.errors }}
+                    <label for="id_option_clone_metadata" class="">{% trans 'Clone zone metadata' %}:</label>{{ form.option_clone_metadata }}
+                    <p>{{ form.option_clone_metadata.help_text }}</p>
+                </div>
+                
+            </fieldset>
+
+            <div class="submit-row">
+                <input type="submit" value="{% trans 'Clone' %}" class="default" />
+            </div>
+
+            <script type="text/javascript">document.getElementById("id_clone_domain_name").focus();</script>
+        </div>
+        </form>
+
+    </div> <!-- content-main -->
+{% endblock %}

File src/powerdns_manager/urls.py

View file
  • Ignore whitespace
     url(r'^import/axfr/$', 'import_axfr_view', name='import_axfr'),
     url(r'^export/(?P<origin>[/.\-_\w]+)/$', 'export_zone_view', name='export_zone'),
     url(r'^update/$', 'dynamic_ip_update_view', name='dynamic_ip_update'),
+    url(r'^zone/clone/(?P<zone_id>[0-9]+)/$', 'zone_clone_view', name='zone_clone'),
     url(r'^zone/transfer/(?P<id_list>[0-9,]+)/$', 'zone_transfer_view', name='zone_transfer'),
 )

File src/powerdns_manager/views.py

View file
  • Ignore whitespace
 from powerdns_manager.forms import AxfrImportForm
 from powerdns_manager.forms import DynamicIPUpdateForm
 from powerdns_manager.forms import ZoneTransferForm
+from powerdns_manager.forms import ClonedZoneDomainForm
 from powerdns_manager.utils import process_zone_file
 from powerdns_manager.utils import process_axfr_response
 from powerdns_manager.utils import generate_zone_file
+from powerdns_manager.utils import interchange_domain
+from powerdns_manager.utils import generate_serial
 
 
 
 
 
 
+@login_required
+@csrf_protect
+def zone_clone_view(request, zone_id):
+    """Clones zone.
+    
+    Accepts a single Domain object ID.
+    
+    An intermediate page asking for the origin of the new zone.
 
+    Clones:
+    
+      - Resource Records
+      - Dynamic setting
+      - Domain Metadata
+      
+    """
+    # Permission check on models.
+    if not request.user.has_perms([
+            'powerdns_manager.add_domain',
+            'powerdns_manager.change_domain',
+            'powerdns_manager.add_record',
+            'powerdns_manager.change_record',
+            'powerdns_manager.add_domainmetadata',
+            'powerdns_manager.change_domainmetadata',
+            'powerdns_manager.add_dynamiczone',
+            'powerdns_manager.change_dynamiczone',
+        ]):
+        messages.error(request, 'Insufficient permissions for this action.')
+        return HttpResponseRedirect(reverse('admin:powerdns_manager_domain_changelist'))
+    
+    if request.method == 'POST':
+        form = ClonedZoneDomainForm(request.POST)
+        if form.is_valid():
+            
+            # Store Data from the form
+            
+            # Store the new domain name for the clone.
+            clone_domain_name = form.cleaned_data['clone_domain_name']
+            
+            option_clone_dynamic = form.cleaned_data['option_clone_dynamic']
+            option_clone_metadata = form.cleaned_data['option_clone_metadata']
+            
+            # Get the models
+            Domain = cache.get_model('powerdns_manager', 'Domain')
+            Record = cache.get_model('powerdns_manager', 'Record')
+            DynamicZone = cache.get_model('powerdns_manager', 'DynamicZone')
+            DomainMetadata = cache.get_model('powerdns_manager', 'DomainMetadata')
+            
+            # Clone base zone
+            
+            # Get the Domain object which will be cloned.
+            domain_obj = Domain.objects.get(id=zone_id)
+            
+            # Check domain object permissions
+            if not request.user.has_perms([
+                'powerdns_manager.add_domain', 'powerdns_manager.change_domain'], domain_obj):
+                messages.error(request, "Insufficient permissions to clone domain '%'" % force_unicode(domain_obj))
+                return HttpResponseRedirect(reverse('admin:powerdns_manager_domain_changelist'))
+            
+            # Create the clone (Check for uniqueness takes place in forms.ClonedZoneDomainForm 
+            clone_obj = Domain.objects.create(
+                name = clone_domain_name,
+                master = domain_obj.master,
+                #last_check = domain_obj.last_check,
+                type = domain_obj.type,
+                #notified_serial = domain_obj.notified_serial,
+                account = domain_obj.account,
+                created_by = request.user   # We deliberately do not use the domain_obj.created_by
+            )
+            #modeladmin.log_addition(request, clone_obj)
+            
+            # Clone Resource Records
+            
+            # Find all resource records of this domain (also clones empty non-terminals)
+            domain_rr_qs = Record.objects.filter(domain=domain_obj)
+            
+            # Create the clone's RRs
+            for rr in domain_rr_qs:
+                
+                # Construct RR name with interchanged domain
+                clone_rr_name = interchange_domain(rr.name, domain_obj.name, clone_domain_name)
+                
+                # Special treatment to the content of SOA and SRV RRs
+                if rr.type == 'SOA':
+                    content_parts = rr.content.split()
+                    # primary
+                    content_parts[0] = interchange_domain(content_parts[0], domain_obj.name, clone_domain_name)
+                    # hostmaster
+                    content_parts[1] = interchange_domain(content_parts[1], domain_obj.name, clone_domain_name)
+                    # Serial. Set new serial
+                    content_parts[2] = generate_serial()
+                    clone_rr_content = ' '.join(content_parts)
+                elif rr.type == 'SRV':
+                    content_parts = rr.content.split()
+                    # target
+                    content_parts[2] = interchange_domain(content_parts[2], domain_obj.name, clone_domain_name)
+                    clone_rr_content = ' '.join(content_parts)
+                else:
+                    clone_rr_content = interchange_domain(rr.content, domain_obj.name, clone_domain_name)
+                
+                # Create and save the cloned record.
+                clone_rr = Record(
+                    domain = clone_obj,
+                    name = clone_rr_name,
+                    type = rr.type,
+                    content = clone_rr_content,
+                    ttl = rr.ttl,
+                    prio = rr.prio,
+                    auth = rr.auth,
+                    ordername = rr.ordername
+                )
+                clone_rr.save()
+                #modeladmin.log_addition(request, clone_rr)
+            
+            # Clone Dynamic Zone setting
+            
+            if option_clone_dynamic:
+                
+                # Get the base domain's dynamic zone.
+                # There is only one Dynamic Zone object for each zone.
+                try:
+                    domain_dynzone_obj = DynamicZone.objects.get(domain=domain_obj)
+                except DynamicZone.DoesNotExist:
+                    pass
+                else:
+                    # Create and save the dynamic zone object for the clone.
+                    clone_dynzone_obj = DynamicZone(
+                        domain = clone_obj,
+                        is_dynamic = domain_dynzone_obj.is_dynamic
+                        )
+                    clone_dynzone_obj.save()
+            
+            # Clone the zone's metadata
+            
+            if option_clone_metadata:
+                
+                # Get the base domain's metadata object.
+                # There is only one metadata object for each zone.
+                try:
+                    domain_metadata_obj = DomainMetadata.objects.get(domain=domain_obj)
+                except DomainMetadata.DoesNotExist:
+                    pass
+                else:
+                    # Create and save the metadata object for the clone.
+                    clone_metadata_obj = DomainMetadata(
+                        domain = clone_obj,
+                        kind = domain_metadata_obj.kind,
+                        content = domain_metadata_obj.content
+                        )
+                    clone_metadata_obj.save()
+            
+            messages.info(request, 'Successfully cloned %s zone to %s' % \
+                (domain_obj.name, clone_domain_name))
+            
+            # Redirect to the new zone's change form.
+            return HttpResponseRedirect(reverse('admin:powerdns_manager_domain_change', args=(clone_obj.id,)))
+
+    else:
+        form = ClonedZoneDomainForm()
+    
+        info_dict = {
+            'form': form,
+            'zone_id': zone_id,
+        }
+        return render_to_response(
+            'powerdns_manager/zone/clone.html', info_dict, context_instance=RequestContext(request))
+    
+    
 
 @login_required
 @csrf_protect