diff options
Diffstat (limited to 'rpkid/rpki/gui/app/views.py')
-rw-r--r-- | rpkid/rpki/gui/app/views.py | 568 |
1 files changed, 225 insertions, 343 deletions
diff --git a/rpkid/rpki/gui/app/views.py b/rpkid/rpki/gui/app/views.py index 7969159c..fc1e9cce 100644 --- a/rpkid/rpki/gui/app/views.py +++ b/rpkid/rpki/gui/app/views.py @@ -26,14 +26,12 @@ import os.path from tempfile import NamedTemporaryFile from django.contrib.auth.decorators import login_required -from django.shortcuts import get_object_or_404, render_to_response +from django.shortcuts import get_object_or_404, render from django.utils.http import urlquote -from django.template import RequestContext from django import http -from django.views.generic.list_detail import object_list, object_detail from django.core.urlresolvers import reverse from django.contrib.auth.models import User -from django.contrib.formtools.preview import FormPreview +from django.views.generic import DetailView from rpki.irdb import Zookeeper, ChildASN, ChildNet from rpki.gui.app import models, forms, glue, range_list @@ -41,7 +39,8 @@ from rpki.resource_set import (resource_range_as, resource_range_ipv4, resource_range_ipv6, roa_prefix_ipv4) from rpki import sundial -from rpki.gui.cacheview.models import ROAPrefixV4, ROAPrefixV6, ROA +from rpki.gui.cacheview.models import ROAPrefixV4, ROA +from rpki.gui.routeview.models import RouteOrigin def superuser_required(f): @@ -57,17 +56,6 @@ def superuser_required(f): return _wrapped -# FIXME This method is included in Django 1.3 and can be removed when Django -# 1.2 is out of its support window. -def render(request, template, context): - """ - https://docs.djangoproject.com/en/1.3/topics/http/shortcuts/#render - - """ - return render_to_response(template, context, - context_instance=RequestContext(request)) - - def handle_required(f): """Decorator for view functions which require the user to be logged in and a resource handle selected for the session. @@ -89,7 +77,7 @@ def handle_required(f): # Should reverse the view for this instead of hardcoding # the URL. url = '%s?next=%s' % (reverse(conf_list), - urlquote(request.get_full_path())) + urlquote(request.get_full_path())) return http.HttpResponseRedirect(url) return f(request, *args, **kwargs) @@ -98,7 +86,7 @@ def handle_required(f): @handle_required def generic_import(request, queryset, configure, form_class=None, - template_name=None, post_import_redirect=None): + post_import_redirect=None): """ Generic view function for importing XML files used in the setup process. @@ -113,11 +101,6 @@ def generic_import(request, queryset, configure, form_class=None, specifies the form to use for import. If None, uses the generic forms.ImportForm. - template_name - path to the html template to use to render the form. If None, defaults - to "app/<model>_import_form.html", where <model> is introspected from - the "queryset" argument. - post_import_redirect if None (default), the user will be redirected to the detail page for the imported object. Otherwise, the user will be redirected to the @@ -125,8 +108,6 @@ def generic_import(request, queryset, configure, form_class=None, """ conf = request.session['handle'] - if template_name is None: - template_name = 'app/%s_import_form.html' % queryset.model.__name__.lower() if form_class is None: form_class = forms.ImportForm if request.method == 'POST': @@ -159,12 +140,14 @@ def generic_import(request, queryset, configure, form_class=None, else: form = form_class() - return render(request, template_name, {'form': form}) + return render(request, 'app/app_form.html', { + 'form': form, + 'form_title': 'Import ' + queryset.model._meta.verbose_name.capitalize(), + }) @handle_required def dashboard(request): - log = request.META['wsgi.errors'] conf = request.session['handle'] used_asns = range_list.RangeList() @@ -214,6 +197,8 @@ def dashboard(request): unused_prefixes = my_prefixes.difference(used_prefixes) unused_prefixes_v6 = my_prefixes_v6.difference(used_prefixes_v6) + clients = models.Client.objects.all() if request.user.is_superuser else None + return render(request, 'app/dashboard.html', { 'conf': conf, 'unused_asns': unused_asns, @@ -221,17 +206,16 @@ def dashboard(request): 'unused_prefixes_v6': unused_prefixes_v6, 'asns': asns, 'prefixes': prefixes, - 'prefixes_v6': prefixes_v6}) - + 'prefixes_v6': prefixes_v6, + 'clients': clients, + }) + @superuser_required -def conf_list(request): +def conf_list(request, **kwargs): """Allow the user to select a handle.""" - queryset = models.Conf.objects.all() - return object_list(request, queryset, - template_name='app/conf_list.html', - template_object_name='conf', - extra_context={'select_url': reverse(conf_select)}) + return render(request, 'app/conf_list.html', + {'conf_list': models.Conf.objects.all()}) @superuser_required @@ -277,19 +261,9 @@ def parent_import(request): @handle_required -def parent_list(request): - """List view for parent objects.""" - conf = request.session['handle'] - return object_list(request, queryset=conf.parents.all(), - extra_context={'create_url': reverse(parent_import), - 'create_label': 'Import'}) - - -@handle_required def parent_detail(request, pk): - """Detail view for a particular parent.""" - conf = request.session['handle'] - return object_detail(request, conf.parents.all(), object_id=pk) + return render(request, 'app/parent_detail.html', { + 'object': get_object_or_404(request.session['handle'].parents, pk=pk)}) @handle_required @@ -297,18 +271,20 @@ def parent_delete(request, pk): conf = request.session['handle'] obj = get_object_or_404(conf.parents, pk=pk) # confirm permission log = request.META['wsgi.errors'] - form_class = forms.UserDeleteForm if request.method == 'POST': - form = form_class(request.POST, request.FILES) + form = forms.Empty(request.POST, request.FILES) if form.is_valid(): z = Zookeeper(handle=conf.handle, logstream=log) z.delete_parent(obj.handle) - z.synchronize() - return http.HttpResponseRedirect(reverse(parent_list)) + z.synchronize(conf.handle) + return http.HttpResponseRedirect(reverse(dashboard)) else: - form = form_class() - return render(request, 'app/parent_detail.html', - {'object': obj, 'form': form, 'confirm_delete': True}) + form = forms.Empty() + return render(request, 'app/object_confirm_delete.html', { + 'object': obj, + 'form': form, + 'parent_template': 'app/parent_detail.html' + }) @handle_required @@ -328,99 +304,53 @@ def child_import(request): @handle_required -def child_list(request): - """List of children for current user.""" - conf = request.session['handle'] - return object_list(request, queryset=conf.children.all(), - template_name='app/child_list.html', - extra_context={ - 'create_url': reverse(child_import), - 'create_label': 'Import'}) - - -class ChildAddResourcePreview(FormPreview): - """ - Base class for handling preview of AS/Prefix additions to a child. - Subclasses implement the 'done' method to perform actual work on IRDB. - - """ - - form_template = 'app/child_detail.html' - preview_template = 'app/child_detail.html' - - def __init__(self, *args, **kwargs): - """ - The docstring for FormPreview says we should not redefine this method, but - I don't see how we can set extra information in this class otherwise. - - """ - self.child = kwargs.pop('child') - self.logstream = kwargs.pop('logstream') - super(ChildAddResourcePreview, self).__init__(*args, **kwargs) - - def get_context(self, *args, **kwargs): - """" - Override the superclass method to add context variables needed by the - form template. - - """ - d = super(ChildAddResourcePreview, self).get_context(*args, **kwargs) - d['object'] = self.child - d['form_label'] = 'Add Resource' - return d - - def process_preview(self, request, form, context): - # set a boolean flag so that the template knows this is a preview - context['is_preview'] = True - - -class ChildAddPrefixPreview(ChildAddResourcePreview): - def done(self, request, cleaned_data): - address_range = cleaned_data.get('address_range') - if ':' in address_range: - r = resource_range_ipv6.parse_str(address_range) - version = 'IPv6' - else: - r = resource_range_ipv4.parse_str(address_range) - version = 'IPv4' - self.child.address_ranges.create(start_ip=str(r.min), end_ip=str(r.max), - version=version) - Zookeeper(handle=self.child.issuer.handle, logstream=self.logstream).run_rpkid_now() - return http.HttpResponseRedirect(self.child.get_absolute_url()) - -@handle_required -def child_add_address(request, pk): +def child_add_prefix(request, pk): logstream = request.META['wsgi.errors'] conf = request.session['handle'] - child = get_object_or_404(models.Child, issuer=conf, pk=pk) - form = forms.AddNetForm(child) - preview = ChildAddPrefixPreview(form, child=child, logstream=logstream) - return preview(request) - -class ChildAddASNPreview(ChildAddResourcePreview): - def done(self, request, cleaned_data): - asns = cleaned_data.get('asns') - r = resource_range_as.parse_str(asns) - self.child.asns.create(start_as=r.min, end_as=r.max) - Zookeeper(handle=self.child.issuer.handle, logstream=self.logstream).run_rpkid_now() - return http.HttpResponseRedirect(self.child.get_absolute_url()) + child = get_object_or_404(conf.children, pk=pk) + if request.method == 'POST': + form = forms.AddNetForm(request.POST, child=child) + if form.is_valid(): + address_range = form.cleaned_data.get('address_range') + if ':' in address_range: + r = resource_range_ipv6.parse_str(address_range) + version = 'IPv6' + else: + r = resource_range_ipv4.parse_str(address_range) + version = 'IPv4' + child.address_ranges.create(start_ip=str(r.min), end_ip=str(r.max), + version=version) + Zookeeper(handle=conf.handle, logstream=logstream).run_rpkid_now() + return http.HttpResponseRedirect(child.get_absolute_url()) + else: + form = forms.AddNetForm(child=child) + return render(request, 'app/app_form.html', + {'object': child, 'form': form, 'form_title': 'Add Prefix'}) + @handle_required def child_add_asn(request, pk): logstream = request.META['wsgi.errors'] conf = request.session['handle'] - child = get_object_or_404(models.Child, issuer=conf, pk=pk) - form = forms.AddASNForm(child) - preview = ChildAddASNPreview(form, child=child, logstream=logstream) - return preview(request) + child = get_object_or_404(conf.children, pk=pk) + if request.method == 'POST': + form = forms.AddASNForm(request.POST, child=child) + if form.is_valid(): + asns = form.cleaned_data.get('asns') + r = resource_range_as.parse_str(asns) + child.asns.create(start_as=r.min, end_as=r.max) + Zookeeper(handle=conf.handle, logstream=logstream).run_rpkid_now() + return http.HttpResponseRedirect(child.get_absolute_url()) + else: + form = forms.AddASNForm(child=child) + return render(request, 'app/app_form.html', + {'object': child, 'form': form, 'form_title': 'Add ASN'}) + @handle_required -def child_view(request, pk): - """Detail view of child for the currently selected handle.""" - conf = request.session['handle'] - child = get_object_or_404(conf.children.all(), pk=pk) - return render(request, 'app/child_detail.html', - {'object': child, 'can_edit': True}) +def child_detail(request, pk): + child = get_object_or_404(request.session['handle'].children, pk=pk) + return render(request, 'app/child_detail.html', {'object': child}) @handle_required @@ -445,11 +375,63 @@ def child_edit(request, pk): 'as_ranges': child.asns.all(), 'address_ranges': child.address_ranges.all()}) - return render(request, 'app/child_form.html', - {'object': child, 'form': form}) + return render(request, 'app/app_form.html', { + 'object': child, + 'form': form, + 'form_title': 'Edit Child: ' + child.handle, + }) + + +@handle_required +def child_response(request, pk): + """ + Export the XML file containing the output of the configure_child + to send back to the client. + + """ + conf = request.session['handle'] + child = get_object_or_404(models.Child, issuer=conf, pk=pk) + z = Zookeeper(handle=conf.handle) + xml = z.generate_parental_response(child) + resp = serve_xml(str(xml), child.handle) + return resp + + +@handle_required +def child_delete(request, pk): + logstream = request.META['wsgi.errors'] + conf = request.session['handle'] + child = get_object_or_404(conf.children, pk=pk) + if request.method == 'POST': + form = forms.Empty(request.POST) + if form.is_valid(): + z = Zookeeper(handle=conf.handle, logstream=logstream) + z.delete_child(child.handle) + z.synchronize(conf.handle) + return http.HttpResponseRedirect(reverse(dashboard)) + else: + form = forms.Empty() + return render(request, 'app/object_confirm_delete.html', { + 'object': child, + 'form': form, + 'parent_template': 'app/child_detail.html' + }) @handle_required +def roa_detail(request, pk): + conf = request.session['handle'] + obj = get_object_or_404(conf.roas, pk=pk) + pfx = obj.prefixes.all()[0].as_resource_range() + routes = RouteOrigin.objects.filter(prefix_min__gte=pfx.min, + prefix_max__lte=pfx.max) + return render(request, 'app/roa_detail.html', { + 'object': obj, + 'routes': routes, + }) + + +@handle_required def roa_create(request): """Present the user with a form to create a ROA. @@ -481,16 +463,16 @@ def roa_create(request): # if the AS matches, it is valid, otherwise invalid if (route.asn != 0 and route.asn == asn and route.prefixlen() <= max_prefixlen): route.status = 'valid' - route.status_label = 'success' + route.status_label = 'label-success' else: route.status = 'invalid' - route.status_label = 'important' + route.status_label = 'label-important' elif route.status == 'invalid': # if the route was previously invalid, but this new ROA # matches the ASN, it is now valid if route.asn != 0 and route.asn == asn and route.prefixlen() <= max_prefixlen: route.status = 'valid' - route.status_label = 'success' + route.status_label = 'label-success' routes.append(route) @@ -533,42 +515,15 @@ def roa_create_confirm(request): prefixlen=rng.prefixlen(), max_prefixlen=max_prefixlen) Zookeeper(handle=conf.handle, logstream=log).run_rpkid_now() - return http.HttpResponseRedirect(reverse(roa_list)) + return http.HttpResponseRedirect(reverse(dashboard)) # What should happen when the submission form isn't valid? For now # just fall through and redirect back to the ROA creation form return http.HttpResponseRedirect(reverse(roa_create)) @handle_required -def roa_list(request): - """ - Display a list of ROARequestPrefix objects for the current resource - handle. - - """ - - conf = request.session['handle'] - qs = models.ROARequestPrefix.objects.filter(roa_request__issuer=conf).order_by('prefix') - return object_list(request, queryset=qs, - template_name='app/roa_request_list.html', - extra_context={'create_url': reverse(roa_create)}) - - -@handle_required -def roa_detail(request, pk): - """Not implemented. - - This is a placeholder so that - models.ROARequestPrefix.get_absolute_url works. The only reason it - exist is so that the /delete URL works. - - """ - pass - - -@handle_required def roa_delete(request, pk): - """Handles deletion of a single ROARequestPrefix object. + """Handles deletion of a single ROARequest object. Uses a form for double confirmation, displaying how the route validation status may change as a result. @@ -576,23 +531,16 @@ def roa_delete(request, pk): """ conf = request.session['handle'] - obj = get_object_or_404(models.ROARequestPrefix.objects, - roa_request__issuer=conf, pk=pk) - + roa = get_object_or_404(conf.roas, pk=pk) if request.method == 'POST': - roa = obj.roa_request - obj.delete() - # if this was the last prefix on the ROA, delete the ROA request - if not roa.prefixes.exists(): - roa.delete() + roa.delete() Zookeeper(handle=conf.handle).run_rpkid_now() - return http.HttpResponseRedirect(reverse(roa_list)) + return http.HttpResponseRedirect(reverse(dashboard)) ### Process GET ### - - match = roa_match(obj.as_resource_range()) - + obj = roa.prefixes.all()[0] roa_pfx = obj.as_roa_prefix() + match = roa_match(obj.as_resource_range()) pfx = 'prefixes' if isinstance(roa_pfx, roa_prefix_ipv4) else 'prefixes_v6' args = {'%s__prefix_min' % pfx: roa_pfx.min(), @@ -602,98 +550,76 @@ def roa_delete(request, pk): # exclude ROAs which seem to match this request and display the result routes = [] for route, roas in match: - qs = roas.exclude(asid=obj.roa_request.asn, **args) + qs = roas.exclude(asid=roa.asn, **args) validate_route(route, qs) routes.append(route) - return render(request, 'app/roa_request_confirm_delete.html', - {'object': obj, 'routes': routes}) + return render(request, 'app/roarequest_confirm_delete.html', + {'object': roa, 'routes': routes}) -@handle_required -def ghostbuster_list(request): - """ - Display a list of all ghostbuster requests for the current Conf. - - """ - conf = request.session['handle'] - qs = models.GhostbusterRequest.objects.filter(issuer=conf) - return object_list(request, queryset=qs) - - -@handle_required -def ghostbuster_view(request, pk): - """ - Display an individual ghostbuster request. - - """ - conf = request.session['handle'] - qs = models.GhostbusterRequest.objects.filter(issuer=conf) - return object_detail(request, queryset=qs, object_id=pk, - extra_context={'can_edit': True}) +class GhostbusterDetailView(DetailView): + def get_queryset(self): + return self.request.session['handle'].ghostbusters @handle_required def ghostbuster_delete(request, pk): - """ - Handle deletion of a GhostbusterRequest object. - - """ conf = request.session['handle'] - log = request.META['wsgi.errors'] - form_class = forms.UserDeleteForm # FIXME - # Ensure the GhosbusterRequest object belongs to the current user. - obj = get_object_or_404(models.GhostbusterRequest, issuer=conf, pk=pk) + logstream = request.META['wsgi.errors'] + obj = get_object_or_404(conf.ghostbusters, pk=pk) if request.method == 'POST': - form = form_class(request.POST, request.FILES) + form = forms.Empty(request.POST, request.FILES) if form.is_valid(): obj.delete() - Zookeeper(handle=conf.handle, logstream=log).run_rpkid_now() - return http.HttpResponseRedirect(reverse(ghostbuster_list)) + Zookeeper(handle=conf.handle, logstream=logstream).run_rpkid_now() + return http.HttpResponseRedirect(reverse(dashboard)) else: - form = form_class() - return render(request, 'app/ghostbusterrequest_detail.html', - {'object': obj, 'form': form, 'confirm_delete': True}) + form = forms.Empty(request.POST, request.FILES) + return render(request, 'app/object_confirm_delete.html', { + 'object': obj, + 'form': form, + 'parent_template': 'app/ghostbusterrequest_detail.html' + }) -def _ghostbuster_edit(request, obj=None): - """ - Common code for create/edit. - - """ +@handle_required +def ghostbuster_create(request): conf = request.session['handle'] - form_class = forms.GhostbusterRequestForm + logstream = request.META['wsgi.errors'] if request.method == 'POST': - form = form_class(conf, request.POST, request.FILES, instance=obj) + form = forms.GhostbusterRequestForm(request.POST, request.FILES, + conf=conf) if form.is_valid(): - # use commit=False for the creation case, otherwise form.save() - # will fail due to schema constraint violation because conf is - # NULL obj = form.save(commit=False) - obj.issuer = conf obj.vcard = glue.ghostbuster_to_vcard(obj) obj.save() - Zookeeper(handle=conf.handle).run_rpkid_now() - return http.HttpResponseRedirect(obj.get_absolute_url()) + Zookeeper(handle=conf.handle, logstream=logstream).run_rpkid_now() + return http.HttpResponseRedirect(reverse(dashboard)) else: - form = form_class(conf, instance=obj) - return render(request, 'app/ghostbuster_form.html', - {'form': form, 'object': obj}) + form = forms.GhostbusterRequestForm(conf=conf) + return render(request, 'app/app_form.html', + {'form': form, 'form_title': 'New Ghostbuster Request'}) @handle_required def ghostbuster_edit(request, pk): conf = request.session['handle'] - - # verify that the object is owned by this conf - obj = get_object_or_404(models.GhostbusterRequest, pk=pk, issuer=conf) - - return _ghostbuster_edit(request, obj) - - -@handle_required -def ghostbuster_create(request): - return _ghostbuster_edit(request) + obj = get_object_or_404(conf.ghostbusters, pk=pk) + logstream = request.META['wsgi.errors'] + if request.method == 'POST': + form = forms.GhostbusterRequestForm(request.POST, request.FILES, + conf=conf, instance=obj) + if form.is_valid(): + obj = form.save(commit=False) + obj.vcard = glue.ghostbuster_to_vcard(obj) + obj.save() + Zookeeper(handle=conf.handle, logstream=logstream).run_rpkid_now() + return http.HttpResponseRedirect(reverse(dashboard)) + else: + form = forms.GhostbusterRequestForm(conf=conf, instance=obj) + return render(request, 'app/app_form.html', + {'form': form, 'form_title': 'Edit Ghostbuster Request'}) @handle_required @@ -706,40 +632,6 @@ def refresh(request): request.session['handle']) return http.HttpResponseRedirect(reverse(dashboard)) - -@handle_required -def child_response(request, pk): - """ - Export the XML file containing the output of the configure_child - to send back to the client. - - """ - conf = request.session['handle'] - child = get_object_or_404(models.Child, issuer=conf, pk=pk) - z = Zookeeper(handle=conf.handle) - xml = z.generate_parental_response(child) - resp = serve_xml(str(xml), child.handle) - return resp - - -@handle_required -def child_delete(request, pk): - conf = request.session['handle'] - # verify this child belongs to the current user - obj = get_object_or_404(conf.children, pk=pk) - form_class = forms.UserDeleteForm # FIXME - if request.method == 'POST': - form = form_class(request.POST, request.FILES) - if form.is_valid(): - z = Zookeeper(handle=conf.handle) - z.delete_child(obj.handle) - z.synchronize() - return http.HttpResponseRedirect(reverse(child_list)) - else: - form = form_class() - return render(request, 'app/child_detail.html', - {'object': obj, 'form': form, 'confirm_delete': True}) - def roa_match(rng): """Return a list of tuples of matching routes and roas.""" @@ -751,7 +643,9 @@ def roa_match(rng): pfx = 'prefixes' rv = [] - for obj in route_manager.filter(prefix_min__gte=rng.min, prefix_max__lte=rng.max): + # return a max of 50 routes + for obj in route_manager.filter(prefix_min__gte=rng.min, + prefix_max__lte=rng.max)[:50]: # This is a bit of a gross hack, since the foreign keys for v4 and v6 # prefixes have different names. args = {'%s__prefix_min__lte' % pfx: obj.prefix_min, @@ -777,17 +671,17 @@ def validate_route(route, roas): # 2. if the candidate ROA set is empty, end with unknown if not roas.exists(): route.status = 'unknown' - route.status_label = 'warning' + route.status_label = 'label-warning' # 3. if any candidate roa matches the origin AS and max_length, end with # valid # # AS0 is always invalid. elif route.asn != 0 and roas.filter(**args).exists(): - route.status_label = 'success' + route.status_label = 'label-success' route.status = 'valid' # 4. otherwise the route is invalid else: - route.status_label = 'important' + route.status_label = 'label-important' route.status = 'invalid' return route @@ -819,35 +713,24 @@ def route_view(request): def route_detail(request, pk): - pass - - -def route_roa_list(request, pk): """Show a list of ROAs that match a given route.""" - object = get_object_or_404(models.RouteOrigin, pk=pk) + # FIXME only supports IPv4 routes + route = get_object_or_404(models.RouteOrigin, pk=pk) # select accepted ROAs which cover this route - qs = ROAPrefixV4.objects.filter(prefix_min__lte=object.prefix_min, - prefix_max__gte=object.prefix_max).select_related() - return object_list(request, qs, template_name='app/route_roa_list.html') + # The rpki.net tool only generates a single prefix per ROA, but other tools + # may not, so we generate the list by roa prefix instead + qs = ROAPrefixV4.objects.filter(prefix_min__lte=route.prefix_min, + prefix_max__gte=route.prefix_max).select_related() + return render(request, 'app/route_detail.html', + {'object': route, 'roa_prefixes': qs}) @handle_required -def repository_list(request): - conf = request.session['handle'] - qs = models.Repository.objects.filter(issuer=conf) - return object_list(request, queryset=qs, - template_name='app/repository_list.html', - extra_context={ - 'create_url': reverse(repository_import), - 'create_label': u'Import'}) - - -@handle_required def repository_detail(request, pk): conf = request.session['handle'] - qs = models.Repository.objects.filter(issuer=conf) - return object_detail(request, queryset=qs, object_id=pk, - template_name='app/repository_detail.html') + return render(request, + 'app/repository_detail.html', + {'object': get_object_or_404(conf.repositories, pk=pk)}) @handle_required @@ -856,18 +739,21 @@ def repository_delete(request, pk): conf = request.session['handle'] # Ensure the repository being deleted belongs to the current user. obj = get_object_or_404(models.Repository, issuer=conf, pk=pk) - form_class = forms.UserDeleteForm # FIXME if request.method == 'POST': - form = form_class(request.POST, request.FILES) + form = forms.Empty(request.POST, request.FILES) if form.is_valid(): z = Zookeeper(handle=conf.handle, logstream=log) z.delete_repository(obj.handle) - z.synchronize() - return http.HttpResponseRedirect(reverse(repository_list)) + z.synchronize(conf.handle) + return http.HttpResponseRedirect(reverse(dashboard)) else: - form = form_class() - return render(request, 'app/repository_detail.html', - {'object': obj, 'form': form, 'confirm_delete': True}) + form = forms.Empty() + return render(request, 'app/object_confirm_delete.html', { + 'object': obj, + 'form': form, + 'parent_template': + 'app/repository_detail.html', + }) @handle_required @@ -877,38 +763,33 @@ def repository_import(request): models.Repository.objects, Zookeeper.configure_repository, form_class=forms.ImportRepositoryForm, - post_import_redirect=reverse(repository_list)) + post_import_redirect=reverse(dashboard)) @superuser_required -def client_list(request): - return object_list(request, queryset=models.Client.objects.all(), - extra_context={ - 'create_url': reverse(client_import), - 'create_label': u'Import'}) - - -@superuser_required def client_detail(request, pk): - return object_detail(request, queryset=models.Client.objects, object_id=pk) + return render(request, 'app/client_detail.html', + {'object': get_object_or_404(models.Client, pk=pk)}) @superuser_required def client_delete(request, pk): log = request.META['wsgi.errors'] obj = get_object_or_404(models.Client, pk=pk) - form_class = forms.UserDeleteForm # FIXME if request.method == 'POST': - form = form_class(request.POST, request.FILES) + form = forms.Empty(request.POST, request.FILES) if form.is_valid(): z = Zookeeper(logstream=log) z.delete_publication_client(obj.handle) z.synchronize() - return http.HttpResponseRedirect(reverse(client_list)) + return http.HttpResponseRedirect(reverse(dashboard)) else: - form = form_class() - return render(request, 'app/client_detail.html', - {'object': obj, 'form': form, 'confirm_delete': True}) + form = forms.Empty() + return render(request, 'app/object_confirm_delete.html', { + 'object': obj, + 'form': form, + 'parent_template': 'app/client_detail.html' + }) @superuser_required @@ -916,7 +797,7 @@ def client_import(request): return generic_import(request, models.Client.objects, Zookeeper.configure_publication_client, form_class=forms.ImportClientForm, - post_import_redirect=reverse(client_list)) + post_import_redirect=reverse(dashboard)) @superuser_required @@ -946,17 +827,11 @@ def user_list(request): @superuser_required -def user_detail(request): - """Placeholder for Conf.get_absolute_url().""" - pass - - -@superuser_required def user_delete(request, pk): conf = models.Conf.objects.get(pk=pk) log = request.META['wsgi.errors'] if request.method == 'POST': - form = forms.UserDeleteForm(request.POST) + form = forms.Empty(request.POST) if form.is_valid(): User.objects.filter(username=conf.handle).delete() z = Zookeeper(handle=conf.handle, logstream=log) @@ -964,7 +839,7 @@ def user_delete(request, pk): z.synchronize() return http.HttpResponseRedirect(reverse(user_list)) else: - form = forms.UserDeleteForm() + form = forms.Empty() return render(request, 'app/user_confirm_delete.html', {'object': conf, 'form': form}) @@ -990,8 +865,11 @@ def user_edit(request, pk): return http.HttpResponseRedirect(reverse(user_list)) else: form = forms.UserEditForm(initial={'email': user.email}) - return render(request, 'app/user_edit_form.html', - {'object': user, 'form': form}) + return render(request, 'app/app_form.html', { + 'object': user, + 'form': form, + 'form_title': 'Edit User: ' + user.username, + }) @handle_required @@ -1038,4 +916,8 @@ def user_create(request): conf = request.session['handle'] form = forms.UserCreateForm(initial={'parent': conf}) - return render(request, 'app/user_create_form.html', {'form': form}) + return render(request, 'app/app_form.html', { + 'form': form, + 'form_title': 'Create User', + 'cancel_url': reverse(user_list), + }) |