diff options
-rw-r--r-- | rpkid/portal-gui/Makefile.in | 2 | ||||
-rw-r--r-- | rpkid/portal-gui/settings.py.in | 9 | ||||
-rw-r--r-- | rpkid/rpki/gui/app/forms.py | 54 | ||||
-rw-r--r-- | rpkid/rpki/gui/app/urls.py | 12 | ||||
-rw-r--r-- | rpkid/rpki/gui/app/views.py | 161 |
5 files changed, 106 insertions, 132 deletions
diff --git a/rpkid/portal-gui/Makefile.in b/rpkid/portal-gui/Makefile.in index e1b8d41c..a453552b 100644 --- a/rpkid/portal-gui/Makefile.in +++ b/rpkid/portal-gui/Makefile.in @@ -42,6 +42,7 @@ apache.conf: $(srcdir)/apache.conf.in Makefile install: $(BUILD) if test -d $(SYSCONFDIR); then :; else ${INSTALL} -d $(SYSCONFDIR); fi if test -d $(INSTDIR)/media/css; then :; else ${INSTALL} -d $(INSTDIR)/media/css; fi + if test -d $(INSTDIR)/media/img; then :; else ${INSTALL} -d $(INSTDIR)/media/img; fi if test -d $(INSTDIR)/media/js; then :; else ${INSTALL} -d $(INSTDIR)/media/js; fi if test -d $(INSTDIR)/wsgi; then :; else ${INSTALL} -d $(INSTDIR)/wsgi; fi ${INSTALL} -m 644 apache.conf $(SYSCONFDIR)/apache.conf @@ -49,6 +50,7 @@ install: $(BUILD) ${INSTALL} -m 644 $(srcdir)/media/js/jquery-1.8.3.min.js $(INSTDIR)/media/js/jquery.min.js ${INSTALL} -m 644 rpki.wsgi $(INSTDIR)/wsgi/rpki.wsgi ${INSTALL} -m 644 settings.py ${SYSCONFDIR} + ${INSTALL} -m 644 -t $(INSTDIR)/media/img $(srcdir)/media/img/* deinstall uninstall: rm -rf $(INSTDIR) diff --git a/rpkid/portal-gui/settings.py.in b/rpkid/portal-gui/settings.py.in index b03ba284..0c939c28 100644 --- a/rpkid/portal-gui/settings.py.in +++ b/rpkid/portal-gui/settings.py.in @@ -1,6 +1,6 @@ # # Sample Django settings.py for running the RPKI portal gui. This -# template was written for Django 1.2. +# template was written for Django 1.3. # # DO NOT EDIT! This file is automatically generated from # settings.py.in @@ -86,8 +86,8 @@ INSTALLED_APPS = ( #'django.contrib.admin', #'django.contrib.admindocs', 'django.contrib.contenttypes', - 'django.contrib.formtools', 'django.contrib.sessions', + 'django.contrib.staticfiles', 'rpki.irdb', 'rpki.gui.app', 'rpki.gui.cacheview', @@ -102,5 +102,8 @@ TEMPLATE_CONTEXT_PROCESSORS = ( "django.core.context_processors.i18n", "django.core.context_processors.media", "django.contrib.messages.context_processors.messages", - "django.core.context_processors.request" + "django.core.context_processors.request", + "django.core.context_processors.static" ) + +STATIC_URL = '/static/' diff --git a/rpkid/rpki/gui/app/forms.py b/rpkid/rpki/gui/app/forms.py index f6b9547d..e7050284 100644 --- a/rpkid/rpki/gui/app/forms.py +++ b/rpkid/rpki/gui/app/forms.py @@ -288,41 +288,43 @@ class ROARequestConfirm(forms.Form): return self.cleaned_data -def AddASNForm(child): +class AddASNForm(forms.Form): """ Returns a forms.Form subclass which verifies that the entered ASN range does not overlap with a previous allocation to the specified child, and that the ASN range is within the range allocated to the parent. """ - class _wrapped(forms.Form): - asns = forms.CharField( - label='ASNs', - help_text='single ASN or range', - widget=forms.TextInput(attrs={'autofocus': 'true'}) - ) - def clean_asns(self): - try: - r = resource_range_as.parse_str(self.cleaned_data.get('asns')) - except: - raise forms.ValidationError('invalid AS or range') - - if not models.ResourceRangeAS.objects.filter( - cert__conf=child.issuer, - min__lte=r.min, - max__gte=r.max).exists(): - raise forms.ValidationError('AS or range is not delegated to you') - - # determine if the entered range overlaps with any AS already - # allocated to this child - if child.asns.filter(end_as__gte=r.min, start_as__lte=r.max).exists(): - raise forms.ValidationError( - 'Overlap with previous allocation to this child') + asns = forms.CharField( + label='ASNs', + help_text='single ASN or range', + widget=forms.TextInput(attrs={'autofocus': 'true'}) + ) - return str(r) + def __init__(self, *args, **kwargs): + self.child = kwargs.pop('child') + super(AddASNForm, self).__init__(*args, **kwargs) - return _wrapped + def clean_asns(self): + try: + r = resource_range_as.parse_str(self.cleaned_data.get('asns')) + except: + raise forms.ValidationError('invalid AS or range') + + if not models.ResourceRangeAS.objects.filter( + cert__conf=self.child.issuer, + min__lte=r.min, + max__gte=r.max).exists(): + raise forms.ValidationError('AS or range is not delegated to you') + + # determine if the entered range overlaps with any AS already + # allocated to this child + if self.child.asns.filter(end_as__gte=r.min, start_as__lte=r.max).exists(): + raise forms.ValidationError( + 'Overlap with previous allocation to this child') + + return str(r) def AddNetForm(child): diff --git a/rpkid/rpki/gui/app/urls.py b/rpkid/rpki/gui/app/urls.py index aa6a9043..aeab2d04 100644 --- a/rpkid/rpki/gui/app/urls.py +++ b/rpkid/rpki/gui/app/urls.py @@ -29,9 +29,15 @@ urlpatterns = patterns('', (r'^parent/(?P<pk>\d+)/export$', views.parent_export), (r'^child/import$', views.child_import), (r'^child/(?P<pk>\d+)/$', views.child_view), - (r'^child/(?P<pk>\d+)/add_asn/$', views.child_add_asn), - (r'^child/(?P<pk>\d+)/add_address/$', views.child_add_address), - (r'^child/(?P<pk>\d+)/delete$', views.child_delete), + url(r'^child/(?P<pk>\d+)/add_asn/$', + views.handle_required(views.ChildAddASN.as_view()), + name='child-add-asn'), + url(r'^child/(?P<pk>\d+)/add_address/$', + views.handle_required(views.ChildAddPrefix.as_view()), + name='child-add-prefix'), + url(r'^child/(?P<pk>\d+)/delete$', + views.handle_required(views.ChildDeleteView.as_view()), + name='child-delete'), (r'^child/(?P<pk>\d+)/edit$', views.child_edit), (r'^child/(?P<pk>\d+)/export$', views.child_response), url(r'^gbr/create$', diff --git a/rpkid/rpki/gui/app/views.py b/rpkid/rpki/gui/app/views.py index 1d825000..3778e361 100644 --- a/rpkid/rpki/gui/app/views.py +++ b/rpkid/rpki/gui/app/views.py @@ -32,9 +32,9 @@ from django import http from django.views.generic.list_detail import object_detail from django.core.urlresolvers import reverse, reverse_lazy from django.contrib.auth.models import User -from django.contrib.formtools.preview import FormPreview from django.views.generic import (DetailView, ListView, CreateView, UpdateView, - DeleteView) + DeleteView, FormView) +from django.views.generic.detail import SingleObjectMixin from rpki.irdb import Zookeeper, ChildASN, ChildNet from rpki.gui.app import models, forms, glue, range_list @@ -296,56 +296,23 @@ def child_import(request): return generic_import(request, conf.children, Zookeeper.configure_child) -class ObjectActionPreview(FormPreview): - """Generic base class for confirming an action of an object. - - Subclasses should define: - - template_name - - """ - - 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.form_object = kwargs.pop('form_object') - self.logstream = kwargs.pop('logstream') - # use the same template for both form edit and preview - self.form_template = self.template_name - self.preview_template = self.template_name - super(ObjectActionPreview, 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(ObjectActionPreview, self).get_context(*args, **kwargs) - d['object'] = self.form_object - d['form_label'] = self.form_label - 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 ChildAddPrefix(FormView, SingleObjectMixin): + form_class = forms.AddNetForm + template_name = 'app/app_form.html' -class ChildAddResourcePreview(ObjectActionPreview): - """ - Base class for handling preview of AS/Prefix additions to a child. - Subclasses implement the 'done' method to perform actual work on IRDB. + def get_queryset(self): + return self.request.session['handle'].children - """ - template_name = 'app/child_detail.html' - form_label = 'Add Resource' + def get_form_kwargs(self): + kwargs = super(ChildAddPrefix, self).get_form_kwargs() + kwargs['child'] = self.get_object() + return kwargs + # FormMixin + def form_valid(self, form): + r = super(ChildAddPrefix, self).form_valid(form) -class ChildAddPrefixPreview(ChildAddResourcePreview): - def done(self, request, cleaned_data): - address_range = cleaned_data.get('address_range') + address_range = form.cleaned_data.get('address_range') if ':' in address_range: r = resource_range_ipv6.parse_str(address_range) version = 'IPv6' @@ -355,33 +322,35 @@ class ChildAddPrefixPreview(ChildAddResourcePreview): 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()) + return r -@handle_required -def child_add_address(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, form_object=child, logstream=logstream) - return preview(request) -class ChildAddASNPreview(ChildAddResourcePreview): - def done(self, request, cleaned_data): - asns = cleaned_data.get('asns') + +class ChildAddASN(FormView, SingleObjectMixin): + form_class = forms.AddASNForm + template_name = 'app/app_form.html' + + def get_queryset(self): + return self.request.session['handle'].children + + def get_form_kwargs(self): + kwargs = super(ChildAddASN, self).get_form_kwargs() + kwargs['child'] = self.get_object() + return kwargs + + # FormMixin + def form_valid(self, form): + resp = super(ChildAddASN, self).form_valid(form) + + asns = form.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()) + self.get_object().asns.create(start_as=r.min, end_as=r.max) + + return resp + + def get_success_url(self): + return self.get_object().get_absolute_url() -@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, form_object=child, logstream=logstream) - return preview(request) @handle_required def child_view(request, pk): @@ -434,30 +403,30 @@ def child_response(request, pk): return resp -class ChildDeletePreview(ObjectActionPreview): - template_name = 'app/child_detail.html' - form_label = 'Delete Child' +class GenericDeleteView(DeleteView): + """Subclasses should implement the get_queryset() method. + + """ + template_name = 'app/object_confirm_delete.html' + success_url = reverse_lazy(dashboard) + + def get_context_data(self, **kwargs): + context = super(GenericDeleteView, self).get_context_data(**kwargs) + context['parent_template'] = 'app/%s_detail.html' % self.object.__class__.__name__.lower() + return context + - def __init__(self, *args, **kwargs): - self.conf = kwargs.pop('conf') - super(ChildDeletePreview, self).__init__(*args, **kwargs) +class ChildDeleteView(GenericDeleteView): + def get_queryset(self): + return self.request.session['handle'].children - def done(self, request, cleaned_data): - z = Zookeeper(handle=self.conf.handle) - z.delete_child(self.form_object.handle) + # override DeletionMixin.delete() + def delete(self, request, *args, **kwargs): + z = Zookeeper(handle=request.session['handle']) + z.delete_child(self.get_object().handle) z.synchronize() - return http.HttpResponseRedirect(reverse(dashboard)) + return http.HttpResponseRedirect(self.get_success_url()) -@handle_required -def child_delete(request, pk): - log = request.META['wsgi.errors'] - 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 - preview = ChildDeletePreview(form_class, conf=conf, form_object=obj, - logstream=log) - return preview(request) @handle_required def roa_create(request): @@ -609,18 +578,10 @@ class GhostbusterDetailView(DetailView): return self.request.session['handle'].ghostbusters -class GhostbusterDeleteView(DeleteView): - template_name = 'app/object_confirm_delete.html' - success_url = reverse_lazy(dashboard) - +class GhostbusterDeleteView(GenericDeleteView): def get_queryset(self): return self.request.session['handle'].ghostbusters - def get_context_data(self, **kwargs): - context = super(GhostbusterDeleteView, self).get_context_data(**kwargs) - context['parent_template'] = 'app/ghostbusterrequest_detail.html' - return context - class GhostbusterCreateView(CreateView): form_class = forms.GhostbusterRequestForm |