aboutsummaryrefslogtreecommitdiff
path: root/rpkid/rpki/gui/app/views.py
diff options
context:
space:
mode:
Diffstat (limited to 'rpkid/rpki/gui/app/views.py')
-rw-r--r--rpkid/rpki/gui/app/views.py568
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),
+ })