diff --git a/machines/forms.py b/machines/forms.py index ee84adfc..863a4d6f 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -59,6 +59,7 @@ class EditInterfaceForm(ModelForm): self.fields['mac_address'].label = 'Adresse mac' self.fields['type'].label = 'Type de machine' self.fields['type'].empty_label = "Séléctionner un type de machine" + self.fields['port_lists'].label = "Configuration des ports" if "machine" in self.fields: self.fields['machine'].queryset = Machine.objects.all().select_related('user') @@ -231,68 +232,13 @@ class VlanForm(ModelForm): class DelVlanForm(Form): vlan = forms.ModelMultipleChoiceField(queryset=Vlan.objects.all(), label="Vlan actuels", widget=forms.CheckboxSelectMultiple) +class EditPortForm(ModelForm): + class Meta: + model = Port + fields = '__all__' + class EditPortListForm(ModelForm): - tcp_ports_in = forms.CharField(required=False, label="Ports TCP (entrée)") - udp_ports_in = forms.CharField(required=False, label="Ports UDP (entrée)") - tcp_ports_out = forms.CharField(required=False, label="Ports TCP (sortie)") - udp_ports_out = forms.CharField(required=False, label="Ports UDP (sortie)") class Meta: model = PortList - fields = ['name'] - - def __init__(self, *args, **kwargs): - super(EditPortListForm, self).__init__(*args, **kwargs) - self.fields['name'].label = "Nom de la liste" - if 'instance' in kwargs.keys(): - p = kwargs['instance'] - self.fields['tcp_ports_in'].initial = ', '.join(map(str, p.tcp_ports_in())) - self.fields['tcp_ports_out'].initial = ', '.join(map(str, p.tcp_ports_out())) - self.fields['udp_ports_in'].initial = ', '.join(map(str, p.udp_ports_in())) - self.fields['udp_ports_out'].initial = ', '.join(map(str, p.udp_ports_out())) - - def save(self, commit=False): - """ - Sauvegarde l'instance. Le commit est obligatoire à cause des ForeignKey. - """ - instance = super(EditPortListForm, self).save(commit=False) - - # Suppression des anciens ports. - for port in instance.port_set.all(): - port.delete() - - split = r',\s+' - ip_range = r'\d+-\d+' - if instance.pk == None: # On ne peut pas créer de ForeignKey sur des objets sans pk - instance.save() - def add_port(string, protocole, mode): - for p in re.split(split, string): - if not p: - continue - if re.match(ip_range, p): - a,b = p.split('-') - a,b = int(a), int(b) - begin,end = min(a,b),max(a,b) - else: - begin = end = int(p.strip()) - port = Port() - port.begin = begin - port.end = end - port.port_list = instance - port.protocole = protocole - port.io = mode - port.save() - - # Ajout des ports TCP en entrée - add_port(self.cleaned_data['tcp_ports_in'], Port.TCP, Port.IN) - # Ajout des ports TCP en sortie - add_port(self.cleaned_data['tcp_ports_out'], Port.TCP, Port.OUT) - # Ajout des ports UDP en entrée - add_port(self.cleaned_data['tcp_ports_in'], Port.UDP, Port.IN) - # Ajout des ports UDP en sortie - add_port(self.cleaned_data['tcp_ports_in'], Port.UDP, Port.OUT) - - if commit: - instance.save() - - return instance + fields = '__all__' diff --git a/machines/models.py b/machines/models.py index 949d9608..7c13e8eb 100644 --- a/machines/models.py +++ b/machines/models.py @@ -223,7 +223,7 @@ class Interface(models.Model): machine = models.ForeignKey('Machine', on_delete=models.CASCADE) type = models.ForeignKey('MachineType', on_delete=models.PROTECT) details = models.CharField(max_length=255, blank=True) - has_public_ip = False + port_lists = models.ManyToManyField('PortList', blank=True) @cached_property def is_active(self): @@ -411,11 +411,10 @@ class Service_link(models.Model): class PortList(models.Model): """Liste des ports ouverts sur une interface.""" - interfaces = models.ManyToManyField('Interface') name = models.CharField(help_text="Nom de la configuration des ports.", max_length=255) def __str__(self): - return ', '.join(map(str, self.port_set.all())) + return self.name def tcp_ports_in(self): return self.port_set.filter(protocole=Port.TCP, io=Port.IN) diff --git a/machines/templates/machines/edit_portlist.html b/machines/templates/machines/edit_portlist.html new file mode 100644 index 00000000..21cc46f2 --- /dev/null +++ b/machines/templates/machines/edit_portlist.html @@ -0,0 +1,69 @@ +{% extends "machines/sidebar.html" %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} + +{% block title %}Création et modification de machines{% endblock %} + +{% block content %} +{% bootstrap_form_errors port_list %} + + +
+ {% csrf_token %} + {% bootstrap_form port_list %} + {{ ports.management_form }} +
+ {% for form in ports.forms %} +
+

+ {{ form }} +

+
+ {% endfor %} +
+ +

+ +

+ + {% bootstrap_button "Créer ou modifier" button_type="submit" icon="star" %} +
+ +{% endblock %} diff --git a/machines/views.py b/machines/views.py index eed0e4c8..b02d2198 100644 --- a/machines/views.py +++ b/machines/views.py @@ -35,7 +35,7 @@ from django.template import Context, RequestContext, loader from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required from django.db.models import ProtectedError -from django.forms import ValidationError +from django.forms import ValidationError, formset_factory, modelformset_factory from django.db import transaction from django.contrib.auth import authenticate, login from django.views.decorators.csrf import csrf_exempt @@ -48,8 +48,8 @@ from reversion.models import Version import re from .forms import NewMachineForm, EditMachineForm, EditInterfaceForm, AddInterfaceForm, MachineTypeForm, DelMachineTypeForm, ExtensionForm, DelExtensionForm, BaseEditInterfaceForm, BaseEditMachineForm from .forms import EditIpTypeForm, IpTypeForm, DelIpTypeForm, DomainForm, AliasForm, DelAliasForm, NsForm, DelNsForm, TextForm, DelTextForm, MxForm, DelMxForm, VlanForm, DelVlanForm, ServiceForm, DelServiceForm, NasForm, DelNasForm -from .forms import EditPortListForm -from .models import IpType, Machine, Interface, IpList, MachineType, Extension, Mx, Ns, Domain, Service, Service_link, Vlan, Nas, Text, PortList +from .forms import EditPortListForm, EditPortForm +from .models import IpType, Machine, Interface, IpList, MachineType, Extension, Mx, Ns, Domain, Service, Service_link, Vlan, Nas, Text, PortList, Port from users.models import User from users.models import all_has_access from preferences.models import GeneralOption, OptionalMachine @@ -928,11 +928,23 @@ def edit_portlist(request, pk): messages.error(request, "Liste de ports inexistante") return redirect("/machines/index_portlist/") port_list = EditPortListForm(request.POST or None, instance=port_list_instance) - if port_list.is_valid(): - port_list.save() + port_formset = modelformset_factory( + Port, + fields=('begin','end','protocole','io'), + extra=0, + can_delete=True + )(request.POST or None, queryset=port_list_instance.port_set.all()) + if port_list.is_valid() and port_formset.is_valid(): + pl = port_list.save() + instances = port_formset.save(commit=False) + for to_delete in port_formset.deleted_objects: + to_delete.delete() + for port in instances: + port.port_list = pl + port.save() messages.success(request, "Liste de ports modifiée") return redirect("/machines/index_portlist/") - return form({'machineform' : port_list}, 'machines/machine.html', request) + return form({'port_list' : port_list, 'ports' : port_formset}, 'machines/edit_portlist.html', request) @login_required @permission_required('bureau')