# -*- mode: python; coding: utf-8 -*- # Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il # se veut agnostique au réseau considéré, de manière à être installable en # quelques clics. # # Copyright © 2017 Gabriel Détraz # Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2017 Maël Kervella # # 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. """ Forms to create, edit and delete: * machines * interfaces * domains (machine names) * aliases (CNAME) * services (DHCP, DNS...) * NS records (DNS server) * MX records (mail serveur) * open ports and ports opening for interfaces """ from __future__ import unicode_literals from django import forms from django.forms import Form, ModelForm from django.utils.translation import ugettext_lazy as _ from re2o.field_permissions import FieldPermissionFormMixin from re2o.mixins import FormRevMixin from re2o.widgets import (AutocompleteModelWidget, AutocompleteMultipleModelWidget) from .models import (SOA, DName, Domain, Extension, Interface, IpList, IpType, Ipv6List, Machine, MachineType, Mx, Nas, Ns, OuverturePortList, Role, Service, Srv, SshFp, Txt, Vlan) class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Form used to edit a machine.""" class Meta: model = Machine fields = "__all__" widgets = {"user": AutocompleteModelWidget(url="/users/user-autocomplete")} def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditMachineForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields["name"].label = _("Machine name") class NewMachineForm(EditMachineForm): """Form used to create a machine.""" class Meta(EditMachineForm.Meta): fields = ["name"] class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Form used to edit an interface.""" class Meta: model = Interface fields = ["machine", "machine_type", "ipv4", "mac_address", "details"] widgets = { "machine": AutocompleteModelWidget(url="/machines/machine-autocomplete"), "machine_type": AutocompleteModelWidget( url="/machines/machinetype-autocomplete" ), "ipv4": AutocompleteModelWidget( url="/machines/iplist-autocomplete", forward=["machine_type"], attrs={ "data-placeholder": "Automatic assigment. Type to choose specific ip." }, ), } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) user = kwargs.get("user") super(EditInterfaceForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields["mac_address"].label = _("MAC address") self.fields["machine_type"].label = _("Machine type") self.fields["machine_type"].empty_label = _("Select a machine type") if "ipv4" in self.fields: self.fields["ipv4"].empty_label = _("Automatic IPv4 assignment") self.fields["ipv4"].queryset = IpList.objects.filter(interface__isnull=True) can_use_all_iptype, _reason, _permissions = IpType.can_use_all(user) if not can_use_all_iptype: self.fields["ipv4"].queryset = IpList.objects.filter( interface__isnull=True ).filter(ip_type__in=IpType.objects.filter(need_infra=False)) else: self.fields["ipv4"].queryset = IpList.objects.filter( interface__isnull=True ) # Add it's own address self.fields["ipv4"].queryset |= IpList.objects.filter( interface=self.instance ) if "machine" in self.fields: self.fields["machine"].queryset = Machine.objects.all().select_related( "user" ) can_use_all_machinetype, _reason, _permissions = MachineType.can_use_all(user) if not can_use_all_machinetype: self.fields["machine_type"].queryset = MachineType.objects.filter( ip_type__in=IpType.objects.filter(need_infra=False) ) class AddInterfaceForm(EditInterfaceForm): """Form used to add an interface to a machine.""" class Meta(EditInterfaceForm.Meta): fields = ["machine_type", "ipv4", "mac_address", "details"] class AliasForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Form used to add and edit an alias (CNAME).""" class Meta: model = Domain fields = ["name", "extension", "ttl"] widgets = { "extension": AutocompleteModelWidget(url="/machines/extension-autocomplete") } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) user = kwargs["user"] super(AliasForm, self).__init__(*args, prefix=prefix, **kwargs) can_use_all, _reason, _permissions = Extension.can_use_all(user) if not can_use_all: self.fields["extension"].queryset = Extension.objects.filter( need_infra=False ) class DomainForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Form used to add and edit a domain record, related to an interface. """ class Meta: model = Domain fields = ["name", "ttl"] def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(DomainForm, self).__init__(*args, prefix=prefix, **kwargs) class DelAliasForm(FormRevMixin, Form): """Form used to delete one or several aliases.""" alias = forms.ModelMultipleChoiceField( queryset=Domain.objects.all(), label=_("Current aliases"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): interface = kwargs.pop("interface") super(DelAliasForm, self).__init__(*args, **kwargs) self.fields["alias"].queryset = Domain.objects.filter( cname__in=Domain.objects.filter(interface_parent=interface) ) class MachineTypeForm(FormRevMixin, ModelForm): """Form used to add and edit a machine type, related to an IP type.""" class Meta: model = MachineType fields = ["name", "ip_type"] widgets = { "ip_type": AutocompleteModelWidget(url="/machines/iptype-autocomplete") } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(MachineTypeForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields["name"].label = _("Machine type to add") self.fields["ip_type"].label = _("Related IP type") class DelMachineTypeForm(FormRevMixin, Form): """Form used to delete one or several machines types.""" machinetypes = forms.ModelMultipleChoiceField( queryset=MachineType.objects.none(), label=_("Current machine types"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelMachineTypeForm, self).__init__(*args, **kwargs) if instances: self.fields["machinetypes"].queryset = instances else: self.fields["machinetypes"].queryset = MachineType.objects.all() class IpTypeForm(FormRevMixin, ModelForm): """Form used to add an IP type. The start and stop IP addresses cannot be changed afterwards. """ class Meta: model = IpType fields = "__all__" widgets = { "vlan": AutocompleteModelWidget(url="/machines/vlan-autocomplete"), "extension": AutocompleteModelWidget( url="/machines/extension-autocomplete" ), "ouverture_ports": AutocompleteModelWidget( url="/machines/ouvertureportlist-autocomplete" ), } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(IpTypeForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields["name"].label = _("IP type to add") class EditIpTypeForm(IpTypeForm): """Form used to edit an IP type. The start and stop IP addresses cannot be changed. """ class Meta(IpTypeForm.Meta): fields = [ "extension", "name", "need_infra", "domaine_ip_network", "domaine_ip_netmask", "prefix_v6", "prefix_v6_length", "vlan", "reverse_v4", "reverse_v6", "ouverture_ports", ] class DelIpTypeForm(FormRevMixin, Form): """Form used to delete one or several IP types.""" iptypes = forms.ModelMultipleChoiceField( queryset=IpType.objects.none(), label=_("Current IP types"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelIpTypeForm, self).__init__(*args, **kwargs) if instances: self.fields["iptypes"].queryset = instances else: self.fields["iptypes"].queryset = IpType.objects.all() class ExtensionForm(FormRevMixin, ModelForm): """Form used to add and edit extensions.""" class Meta: model = Extension fields = "__all__" def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(ExtensionForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields["name"].label = _("Extension to add") self.fields["origin"].label = _("A record origin") self.fields["origin_v6"].label = _("AAAA record origin") self.fields["soa"].label = _("SOA record to use") self.fields["dnssec"].label = _("Sign with DNSSEC") class DelExtensionForm(FormRevMixin, Form): """Form used to delete one or several extensions.""" extensions = forms.ModelMultipleChoiceField( queryset=Extension.objects.none(), label=_("Current extensions"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelExtensionForm, self).__init__(*args, **kwargs) if instances: self.fields["extensions"].queryset = instances else: self.fields["extensions"].queryset = Extension.objects.all() class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Form used to manage lists of IPv6 addresses.""" class Meta: model = Ipv6List fields = ["ipv6", "slaac_ip", "active"] def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(Ipv6ListForm, self).__init__(*args, prefix=prefix, **kwargs) class SOAForm(FormRevMixin, ModelForm): """Form used to add and edit SOA records.""" class Meta: model = SOA fields = "__all__" def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(SOAForm, self).__init__(*args, prefix=prefix, **kwargs) class DelSOAForm(FormRevMixin, Form): """Form used to delete one or several SOA records.""" soa = forms.ModelMultipleChoiceField( queryset=SOA.objects.none(), label=_("Current SOA records"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelSOAForm, self).__init__(*args, **kwargs) if instances: self.fields["soa"].queryset = instances else: self.fields["soa"].queryset = SOA.objects.all() class MxForm(FormRevMixin, ModelForm): """Form used to add and edit MX records.""" class Meta: model = Mx fields = ["zone", "priority", "name", "ttl"] widgets = { "zone": AutocompleteModelWidget(url="/machines/extension-autocomplete"), "name": AutocompleteModelWidget(url="/machines/domain-autocomplete"), } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(MxForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields["name"].queryset = Domain.objects.exclude( interface_parent=None ).select_related("extension") class DelMxForm(FormRevMixin, Form): """Form used to delete one or several MX records.""" mx = forms.ModelMultipleChoiceField( queryset=Mx.objects.none(), label=_("Current MX records"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelMxForm, self).__init__(*args, **kwargs) if instances: self.fields["mx"].queryset = instances else: self.fields["mx"].queryset = Mx.objects.all() class NsForm(FormRevMixin, ModelForm): """Form used to add and edit NS records. Only interface names are available because CNAME aliases should not be used in the records. """ class Meta: model = Ns fields = ["zone", "ns", "ttl"] widgets = { "zone": AutocompleteModelWidget(url="/machines/extension-autocomplete"), "ns": AutocompleteModelWidget(url="/machines/domain-autocomplete"), } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(NsForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields["ns"].queryset = Domain.objects.exclude( interface_parent=None ).select_related("extension") class DelNsForm(FormRevMixin, Form): """Form used to delete one or several NS records.""" nss = forms.ModelMultipleChoiceField( queryset=Ns.objects.none(), label=_("Current NS records"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelNsForm, self).__init__(*args, **kwargs) if instances: self.fields["nss"].queryset = instances else: self.fields["nss"].queryset = Ns.objects.all() class TxtForm(FormRevMixin, ModelForm): """Form used to add and edit TXT records.""" class Meta: model = Txt fields = "__all__" widgets = { "zone": AutocompleteModelWidget(url="/machines/extension-autocomplete") } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(TxtForm, self).__init__(*args, prefix=prefix, **kwargs) class DelTxtForm(FormRevMixin, Form): """Form used to delete one or several TXT records.""" txt = forms.ModelMultipleChoiceField( queryset=Txt.objects.none(), label=_("Current TXT records"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelTxtForm, self).__init__(*args, **kwargs) if instances: self.fields["txt"].queryset = instances else: self.fields["txt"].queryset = Txt.objects.all() class DNameForm(FormRevMixin, ModelForm): """Form used to add and edit DNAME records.""" class Meta: model = DName fields = "__all__" widgets = { "zone": AutocompleteModelWidget(url="/machines/extension-autocomplete") } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(DNameForm, self).__init__(*args, prefix=prefix, **kwargs) class DelDNameForm(FormRevMixin, Form): """Form used to delete one or several DNAME records.""" dnames = forms.ModelMultipleChoiceField( queryset=Txt.objects.none(), label=_("Current DNAME records"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelDNameForm, self).__init__(*args, **kwargs) if instances: self.fields["dnames"].queryset = instances else: self.fields["dnames"].queryset = DName.objects.all() class SrvForm(FormRevMixin, ModelForm): """Form used to add and edit SRV records.""" class Meta: model = Srv fields = "__all__" widgets = { "extension": AutocompleteModelWidget( url="/machines/extension-autocomplete" ), "target": AutocompleteModelWidget(url="/machines/domain-autocomplete"), } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(SrvForm, self).__init__(*args, prefix=prefix, **kwargs) class DelSrvForm(FormRevMixin, Form): """Form used to delete one or several SRV records.""" srv = forms.ModelMultipleChoiceField( queryset=Srv.objects.none(), label=_("Current SRV records"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelSrvForm, self).__init__(*args, **kwargs) if instances: self.fields["srv"].queryset = instances else: self.fields["srv"].queryset = Srv.objects.all() class NasForm(FormRevMixin, ModelForm): """Form used to create and edit NAS devices.""" class Meta: model = Nas fields = "__all__" widgets = { "nas_type": AutocompleteModelWidget( url="/machines/machinetype-autocomplete" ), "machine_type": AutocompleteModelWidget( url="/machines/machinetype-autocomplete" ), } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(NasForm, self).__init__(*args, prefix=prefix, **kwargs) class DelNasForm(FormRevMixin, Form): """Form used to delete one or several NAS devices.""" nas = forms.ModelMultipleChoiceField( queryset=Nas.objects.none(), label=_("Current NAS devices"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelNasForm, self).__init__(*args, **kwargs) if instances: self.fields["nas"].queryset = instances else: self.fields["nas"].queryset = Nas.objects.all() class RoleForm(FormRevMixin, ModelForm): """Form used to add and edit roles.""" class Meta: model = Role fields = "__all__" widgets = { "servers": AutocompleteMultipleModelWidget( url="/machines/interface-autocomplete" ) } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(RoleForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields["servers"].queryset = Interface.objects.all().select_related( "domain__extension" ) class DelRoleForm(FormRevMixin, Form): """Form used to delete one or several roles.""" role = forms.ModelMultipleChoiceField( queryset=Role.objects.none(), label=_("Current roles"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelRoleForm, self).__init__(*args, **kwargs) if instances: self.fields["role"].queryset = instances else: self.fields["role"].queryset = Role.objects.all() class ServiceForm(FormRevMixin, ModelForm): """Form to add and edit services (DHCP, DNS etc.).""" class Meta: model = Service fields = "__all__" widgets = { "servers": AutocompleteMultipleModelWidget( url="/machines/interface-autocomplete" ) } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(ServiceForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields["servers"].queryset = Interface.objects.all().select_related( "domain__extension" ) def save(self, commit=True): # TODO : None of the parents of ServiceForm use the commit # parameter in .save() instance = super(ServiceForm, self).save(commit=False) if commit: instance.save() instance.process_link(self.cleaned_data.get("servers")) return instance class DelServiceForm(FormRevMixin, Form): """Form used to delete one or several services.""" service = forms.ModelMultipleChoiceField( queryset=Service.objects.none(), label=_("Current services"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelServiceForm, self).__init__(*args, **kwargs) if instances: self.fields["service"].queryset = instances else: self.fields["service"].queryset = Service.objects.all() class VlanForm(FormRevMixin, ModelForm): """Form used to add and edit VLANs.""" class Meta: model = Vlan fields = ["vlan_id", "name", "comment"] def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(VlanForm, self).__init__(*args, prefix=prefix, **kwargs) class EditOptionVlanForm(FormRevMixin, ModelForm): """Form used to edit the options of a VLAN.""" class Meta: model = Vlan fields = ["dhcp_snooping", "dhcpv6_snooping", "arp_protect", "igmp", "mld"] def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditOptionVlanForm, self).__init__(*args, prefix=prefix, **kwargs) class DelVlanForm(FormRevMixin, Form): """Form used to delete one or several VLANs.""" vlan = forms.ModelMultipleChoiceField( queryset=Vlan.objects.none(), label=_("Current VLANs"), widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): instances = kwargs.pop("instances", None) super(DelVlanForm, self).__init__(*args, **kwargs) if instances: self.fields["vlan"].queryset = instances else: self.fields["vlan"].queryset = Vlan.objects.all() class EditOuverturePortConfigForm(FormRevMixin, ModelForm): """Form to edit the ports opening list of an interface.""" class Meta: model = Interface fields = ["port_lists"] widgets = { "port_lists": AutocompleteMultipleModelWidget( url="/machines/ouvertureportlist-autocomplete" ) } def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditOuverturePortConfigForm, self).__init__( *args, prefix=prefix, **kwargs ) class EditOuverturePortListForm(FormRevMixin, ModelForm): """Form used to add and edit ports opening lists.""" class Meta: model = OuverturePortList fields = "__all__" def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditOuverturePortListForm, self).__init__(*args, prefix=prefix, **kwargs) class SshFpForm(FormRevMixin, ModelForm): """Form used to add and edit SSHFP records.""" class Meta: model = SshFp exclude = ("machine",) def __init__(self, *args, **kwargs): prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(SshFpForm, self).__init__(*args, prefix=prefix, **kwargs)