From b7894062efbf15709c39d14b9eb66512cd9f9efa Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Mon, 2 Oct 2017 18:10:24 +0200 Subject: [PATCH 01/27] OUverture et non config --- machines/templates/machines/sidebar.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machines/templates/machines/sidebar.html b/machines/templates/machines/sidebar.html index e635d69a..6ca3a07f 100644 --- a/machines/templates/machines/sidebar.html +++ b/machines/templates/machines/sidebar.html @@ -58,7 +58,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if is_cableur %} - Configuration de ports + Ouverture de ports {%endif%} {% endblock %} From 9b925f389cd3c1e80796bd800dd1c7196218f0ed Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Tue, 3 Oct 2017 18:27:06 +0200 Subject: [PATCH 02/27] =?UTF-8?q?Politique=20d'ouverture=20des=20ports=20p?= =?UTF-8?q?ar=20d=C3=A9faut=20associ=C3=A9e=20=C3=A0=20un=20range=20d'IP.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- machines/forms.py | 4 ++-- .../migrations/0060_iptype_ouverture_ports.py | 21 +++++++++++++++++++ machines/models.py | 1 + machines/serializers.py | 5 +++-- 4 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 machines/migrations/0060_iptype_ouverture_ports.py diff --git a/machines/forms.py b/machines/forms.py index 18631651..7922654a 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -145,7 +145,7 @@ class DelMachineTypeForm(Form): class IpTypeForm(ModelForm): class Meta: model = IpType - fields = ['type','extension','need_infra','domaine_ip_start','domaine_ip_stop', 'prefix_v6', 'vlan'] + fields = ['type','extension','need_infra','domaine_ip_start','domaine_ip_stop', 'prefix_v6', 'vlan', 'ouverture_ports'] def __init__(self, *args, **kwargs): @@ -154,7 +154,7 @@ class IpTypeForm(ModelForm): class EditIpTypeForm(IpTypeForm): class Meta(IpTypeForm.Meta): - fields = ['extension','type','need_infra', 'prefix_v6', 'vlan'] + fields = ['extension','type','need_infra', 'prefix_v6', 'vlan', 'ouverture_ports'] class DelIpTypeForm(Form): iptypes = forms.ModelMultipleChoiceField(queryset=IpType.objects.all(), label="Types d'ip actuelles", widget=forms.CheckboxSelectMultiple) diff --git a/machines/migrations/0060_iptype_ouverture_ports.py b/machines/migrations/0060_iptype_ouverture_ports.py new file mode 100644 index 00000000..e35f398f --- /dev/null +++ b/machines/migrations/0060_iptype_ouverture_ports.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-03 16:08 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0059_iptype_prefix_v6'), + ] + + operations = [ + migrations.AddField( + model_name='iptype', + name='ouverture_ports', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='machines.OuverturePortList'), + ), + ] diff --git a/machines/models.py b/machines/models.py index 8e7b1c3c..5d08038e 100644 --- a/machines/models.py +++ b/machines/models.py @@ -72,6 +72,7 @@ class IpType(models.Model): domaine_ip_stop = models.GenericIPAddressField(protocol='IPv4') prefix_v6 = models.GenericIPAddressField(protocol='IPv6', null=True, blank=True) vlan = models.ForeignKey('Vlan', on_delete=models.PROTECT, blank=True, null=True) + ouverture_ports = models.ForeignKey('OuverturePortList', blank=True, null=True) @cached_property def ip_range(self): diff --git a/machines/serializers.py b/machines/serializers.py index 51daa4b5..6561bba9 100644 --- a/machines/serializers.py +++ b/machines/serializers.py @@ -80,10 +80,10 @@ class ExtensionNameField(serializers.RelatedField): class TypeSerializer(serializers.ModelSerializer): extension = ExtensionNameField(read_only=True) - + class Meta: model = IpType - fields = ('type', 'extension', 'domaine_ip_start', 'domaine_ip_stop') + fields = ('type', 'extension', 'domaine_ip_start', 'domaine_ip_stop', 'ouverture_ports') class ExtensionSerializer(serializers.ModelSerializer): origin = serializers.SerializerMethodField('get_origin_ip') @@ -184,3 +184,4 @@ class ServiceServersSerializer(serializers.ModelSerializer): def get_regen_status(self, obj): return obj.need_regen() + From 6084b8622a17756885b51f109d9df9995ddf8e65 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Tue, 3 Oct 2017 19:07:53 +0200 Subject: [PATCH 03/27] =?UTF-8?q?Serialisation=20des=20ouvertures=20associ?= =?UTF-8?q?=C3=A9es=20=C3=A0=20une=20range=20d'IP.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- machines/serializers.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/machines/serializers.py b/machines/serializers.py index 6561bba9..6adc22cc 100644 --- a/machines/serializers.py +++ b/machines/serializers.py @@ -23,7 +23,7 @@ #Augustin Lemesle from rest_framework import serializers -from machines.models import Interface, IpType, Extension, IpList, MachineType, Domain, Text, Mx, Service_link, Ns +from machines.models import Interface, IpType, Extension, IpList, MachineType, Domain, Text, Mx, Service_link, Ns, OuverturePortList, OuverturePort class IpTypeField(serializers.RelatedField): def to_representation(self, value): @@ -80,10 +80,31 @@ class ExtensionNameField(serializers.RelatedField): class TypeSerializer(serializers.ModelSerializer): extension = ExtensionNameField(read_only=True) - + ouverture_ports_tcp_in = serializers.SerializerMethodField('get_port_policy_input_tcp') + ouverture_ports_tcp_out = serializers.SerializerMethodField('get_port_policy_output_tcp') + ouverture_ports_udp_in = serializers.SerializerMethodField('get_port_policy_input_udp') + ouverture_ports_udp_out = serializers.SerializerMethodField('get_port_policy_output_udp') + class Meta: model = IpType - fields = ('type', 'extension', 'domaine_ip_start', 'domaine_ip_stop', 'ouverture_ports') + fields = ('type', 'extension', 'domaine_ip_start', 'domaine_ip_stop', 'ouverture_ports_tcp_in', 'ouverture_ports_tcp_out', 'ouverture_ports_udp_in', 'ouverture_ports_udp_out', ) + + def get_port_policy(self, obj, protocole, io): + if not obj.ouverture_ports: + return [] + return [str(port) for port in obj.ouverture_ports.ouvertureport_set.filter(protocole=protocole).filter(io=io)] + + def get_port_policy_input_tcp(self, obj): + return self.get_port_policy(obj, OuverturePort.TCP, OuverturePort.IN) + + def get_port_policy_output_tcp(self, obj): + return self.get_port_policy(obj, OuverturePort.TCP, OuverturePort.OUT) + + def get_port_policy_input_udp(self, obj): + return self.get_port_policy(obj, OuverturePort.UDP, OuverturePort.IN) + + def get_port_policy_output_udp(self, obj): + return self.get_port_policy(obj, OuverturePort.UDP, OuverturePort.OUT) class ExtensionSerializer(serializers.ModelSerializer): origin = serializers.SerializerMethodField('get_origin_ip') From 06d72042be282d13616e374316d40b269198d4e9 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Wed, 4 Oct 2017 22:03:26 +0200 Subject: [PATCH 04/27] =?UTF-8?q?Affichage=20REST=20des=20r=C3=A8gles=20pa?= =?UTF-8?q?rticuli=C3=A8res=20des=20machines.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- machines/serializers.py | 25 +++++++++++++++++++++++++ machines/urls.py | 1 + machines/views.py | 26 +++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/machines/serializers.py b/machines/serializers.py index 6adc22cc..34716cd8 100644 --- a/machines/serializers.py +++ b/machines/serializers.py @@ -206,3 +206,28 @@ class ServiceServersSerializer(serializers.ModelSerializer): def get_regen_status(self, obj): return obj.need_regen() +class OuverturePortsSerializer(serializers.Serializer): + ipv4 = serializers.SerializerMethodField() + ipv6 = serializers.SerializerMethodField() + + def get_ipv4(): + return {i.ipv4.ipv4: + { + "tcp_in":[j.tcp_ports_in() for j in i.port_lists.all()], + "tcp_out":[j.tcp_ports_out()for j in i.port_lists.all()], + "udp_in":[j.udp_ports_in() for j in i.port_lists.all()], + "udp_out":[j.udp_ports_out() for j in i.port_lists.all()], + } + for i in Interface.objects.all() if i.ipv4 + } + + def get_ipv6(): + return {i.ipv6: + { + "tcp_in":[j.tcp_ports_in() for j in i.port_lists.all()], + "tcp_out":[j.tcp_ports_out()for j in i.port_lists.all()], + "udp_in":[j.udp_ports_in() for j in i.port_lists.all()], + "udp_out":[j.udp_ports_out() for j in i.port_lists.all()], + } + for i in Interface.objects.all() if i.ipv6 + } diff --git a/machines/urls.py b/machines/urls.py index 62576a4e..e0ff1e77 100644 --- a/machines/urls.py +++ b/machines/urls.py @@ -92,6 +92,7 @@ urlpatterns = [ url(r'^rest/text/$', views.text, name='text'), url(r'^rest/zones/$', views.zones, name='zones'), url(r'^rest/service_servers/$', views.service_servers, name='service-servers'), + url(r'^rest/ouverture_ports/$', views.ouverture_ports, name='ouverture-ports'), url(r'index_portlist/$', views.index_portlist, name='index-portlist'), url(r'^edit_portlist/(?P[0-9]+)$', views.edit_portlist, name='edit-portlist'), url(r'^del_portlist/(?P[0-9]+)$', views.del_portlist, name='del-portlist'), diff --git a/machines/views.py b/machines/views.py index 4be86c03..b286db75 100644 --- a/machines/views.py +++ b/machines/views.py @@ -41,7 +41,7 @@ from django.contrib.auth import authenticate, login from django.views.decorators.csrf import csrf_exempt from rest_framework.renderers import JSONRenderer -from machines.serializers import FullInterfaceSerializer, InterfaceSerializer, TypeSerializer, DomainSerializer, TextSerializer, MxSerializer, ExtensionSerializer, ServiceServersSerializer, NsSerializer +from machines.serializers import FullInterfaceSerializer, InterfaceSerializer, TypeSerializer, DomainSerializer, TextSerializer, MxSerializer, ExtensionSerializer, ServiceServersSerializer, NsSerializer, OuverturePortsSerializer from reversion import revisions as reversion from reversion.models import Version @@ -1108,6 +1108,30 @@ def service_servers(request): @csrf_exempt @login_required @permission_required('serveur') +def ouverture_ports(request): + r = {'ipv4':{}, 'ipv6':{}} + for i in Interface.objects.all(): + if not i.may_have_port_open(): + continue + if i.ipv4: + r['ipv4'][i.ipv4.ipv4] = {"tcp_in":[],"tcp_out":[],"udp_in":[],"udp_out":[]} + if i.ipv6: + r['ipv6'][i.ipv6] = {"tcp_in":[],"tcp_out":[],"udp_in":[],"udp_out":[]} + for j in i.port_lists.all(): + if i.ipv4: + r['ipv4'][i.ipv4.ipv4]["tcp_in"].extend(j.tcp_ports_in()) + r['ipv4'][i.ipv4.ipv4]["tcp_out"].extend(j.tcp_ports_out()) + r['ipv4'][i.ipv4.ipv4]["udp_in"].extend(j.udp_ports_in()) + r['ipv4'][i.ipv4.ipv4]["udp_out"].extend(j.udp_ports_out()) + if i.ipv6: + r['ipv6'][i.ipv6]["tcp_in"].extend(j.tcp_ports_in()) + r['ipv6'][i.ipv6]["tcp_out"].extend(j.tcp_ports_out()) + r['ipv6'][i.ipv6]["udp_in"].extend(j.udp_ports_in()) + r['ipv6'][i.ipv6]["udp_out"].extend(j.udp_ports_out()) + return JSONResponse(r) +@csrf_exempt +@login_required +@permission_required('serveur') def regen_achieved(request): obj = Service_link.objects.filter(service__in=Service.objects.filter(service_type=request.POST['service']), server__in=Interface.objects.filter(domain__in=Domain.objects.filter(name=request.POST['server']))) if obj: From 025396078225831e1800a838a4310429e14055d1 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Thu, 5 Oct 2017 00:09:23 +0200 Subject: [PATCH 05/27] =?UTF-8?q?Fix=20de=20la=20d=C3=A9tection=20d'ipv6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- machines/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machines/views.py b/machines/views.py index 580ad4d8..c98936dc 100644 --- a/machines/views.py +++ b/machines/views.py @@ -1114,7 +1114,7 @@ def ouverture_ports(request): continue if i.ipv4: r['ipv4'][i.ipv4.ipv4] = {"tcp_in":[],"tcp_out":[],"udp_in":[],"udp_out":[]} - if i.ipv6: + if i.ipv6_object: r['ipv6'][i.ipv6] = {"tcp_in":[],"tcp_out":[],"udp_in":[],"udp_out":[]} for j in i.port_lists.all(): if i.ipv4: @@ -1122,7 +1122,7 @@ def ouverture_ports(request): r['ipv4'][i.ipv4.ipv4]["tcp_out"].extend(j.tcp_ports_out()) r['ipv4'][i.ipv4.ipv4]["udp_in"].extend(j.udp_ports_in()) r['ipv4'][i.ipv4.ipv4]["udp_out"].extend(j.udp_ports_out()) - if i.ipv6: + if i.ipv6_object: r['ipv6'][i.ipv6]["tcp_in"].extend(j.tcp_ports_in()) r['ipv6'][i.ipv6]["tcp_out"].extend(j.tcp_ports_out()) r['ipv6'][i.ipv6]["udp_in"].extend(j.udp_ports_in()) From 448d2a44e5cf823656d9cd340307269578ff38eb Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Mon, 9 Oct 2017 23:59:25 +0200 Subject: [PATCH 06/27] Politique par default d'ouverture --- machines/templates/machines/aff_iptype.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/machines/templates/machines/aff_iptype.html b/machines/templates/machines/aff_iptype.html index aafc4c1d..454b169d 100644 --- a/machines/templates/machines/aff_iptype.html +++ b/machines/templates/machines/aff_iptype.html @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., Fin Préfixe v6 Sur vlan + Ouverture ports par défault @@ -45,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ type.domaine_ip_stop }} {{ type.prefix_v6 }} {{ type.vlan }} + {{ type.ouverture_ports }} {% if is_infra %} {% include 'buttons/edit.html' with href='machines:edit-iptype' id=type.id %} From 22efb9770d01f38e483fab4b021d6741796c4307 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Thu, 12 Oct 2017 20:03:12 +0200 Subject: [PATCH 07/27] Graph re2o sources dia (archi) --- docs_utils/re2o-archi.dia | Bin 0 -> 3922 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs_utils/re2o-archi.dia diff --git a/docs_utils/re2o-archi.dia b/docs_utils/re2o-archi.dia new file mode 100644 index 0000000000000000000000000000000000000000..1137480ea6238a12368de3b4a47c1e06d1323a36 GIT binary patch literal 3922 zcmV-Y53TSYiwFP!000021MOYia@)8SzRy!=v^VXH4CCM*t4(&Ylijv6nRdI`PA@&Q zMBD7rl9rIcp~FEuo6M)l?EK~MU%&ozWQO0rdhy*fiN3|(=UH?)z)#GU?$yiTMV>FdJwCp^ zz9#9-GRo%}Ns|>>#>fAQ(lk28i;jn{UJM4?H<(6w_CU{AHvpBe<;y&)rt!p+{E%Bn+`KxbUi*MGCw0YzHUS$tj36ft%*?BTM z#KFEv*B!x#VT@sCNNX(BLc?vJJRR<|U%0eixU65eWO=ffXL%MS`61-#e4fV9Y>k>{ ztGGGNauTID#2#u^i&mT^c|L#S`Ol(sS*HQ(x9?`#Q)ljZmP{X>xI0%=+~qo%<`*aL zJ$2Xm?l+$9ew8ef(=;x7`ec@OcKe%dZomKS6zqNf@s^`ueYZ;UFg3A^<`6`*l z%SVRU?ll#6y4YNH{8+E=Ustzd)^F_@>jEN;ZsKfn``1~PeEcJej}~b(8xA(#@rHB; z(IiiFGX7hK-44=V^S8B-TjMDm7+`a5-W?m~4g` zr}5>o=xNIv8GW1bo~RuQUC?472Gb3ROrlm3HvmR<;DE^q(mn_E&`r{vWTYBT>)^= zXIygkC0W!poN2CYGo(CzpAR2l`MqnZdZv)YJJ;C1&Qc zybRO5KRAmnlk^53Et)NdgJpi>SQ5!?{n5Y1=~bL3lW3dIpZ){~ld1IUGIaMxv;*Cx z-7;oE>a$kq5f}nscsscLDOEYGC~XIXy7zo`8JB;j@oaTjB3T|1EoFAMN;@3iTgf_R z^N0ES5|arXm`puF>%}}9OX)yBIzuVsh$9Jmwv%mIRntP+ogbeTk`p7hr!$Bz%0ix< z?M~%qX(8q3ZxMfZ^JehwpKk|$y1ZHbo*pmG@y|a8+vwdkGD4C64B;%;#V+jPJG3s- zD4U{Le4EV5TuIi}F0S>ADqK2`rV($i1S>p8$mNt9*t>wSp(Ilx%!o1did?EGPaEZc)T zYV?~%E@o3-eROwge?4>$(N+Jr*@u%H>1cT{E^q&5aDfE2v4Hu!2z?Fi{}-pk;dCtd zFl;^yyB}tUfxx{ddaCbH9kS!C{SQhs(|TlymJ+N_FN6}M*GLqR#^|Y9CDjNdk)o-f zuIY|+(a3sE2^ejeRGbQ{m}J7EQzD7xh#`Stf8yVYhp=4;+qHI5ethp1JqN%1`0m#i zQ)I4>AL8X;8D|NK(xrP592VaW3kYHu=nOUUj0+ zAEy)9mQFaj{g#W7CI&3^NheI87Pknbg%NCwz~IQmk%{)qC6$dV34=&NxmAHn0++Pm z64-b4c?&Y>)7e+82?ggjcg9$erm@Xhbi#`)8HY0lKp%+0h%wKpIUTgEj)$)aI@@t(h}h*Zpujs&61*bqYLX>U{O{lH8+87oGdP~~|6Qxk62NNyEz z%oWj_RmJAWHLXk+jjUs2tc%oa&pV$+Mi4E-9;dL!>B*My?VHy>2b1XAB;ICCNaD8b zi(nGFHi^}~7qs5<%Te;8&~<)^Hq`n&Cj+6FSwk6)P=#R>To%q3Z;V}YNxqYI*7Uy= z)rx`!t*y4gc=f;7?#^Qq{I9;P%)gW0l3-=LTNzFya2OqNV);&-A($EOW~TKPTCNH3 zE$;VeW;CIg_%*tx0&gro%PI&gnKh%KxnUK26kpUXTi+$ZD#(Ga@j163FrNeSE<8rpaZY&}EMO*`ut z8cD1XTONkz^(3m1mnrtEG1dYLhNgEz^Y{6Dn#RGIq4n0< zyEQ-{K9h0X@pvxD)xjvMq)S#X+>AK77{+@tZh0e1uCqid({jn_6Q+l`Z66^$?31TI z*~)a$8fV_@Z=&ld*A&|Cs=W|Ff~SOAqz18E(OLjr&PDJgj0k& zz9w)=;FNZp!aC#>-WR8|-hg=Pssd5X&vvUvDaxJm!HPM}!0<6bGr%_-r8GXnu0Ewy zHME3LitL5JD1lMhF$(XHQG|zmAIn7=-E6T6+_FmRt#(HYC!3Po1+gWg%qOoP7Nf?f z0!t&-m=lK6R~HUZbMVVJj~)xmPLoOQb1k5weyq0`z{O6wk@1@MYj=(up{xZT*3JRG ztEX2H`0`S&yqB)0kK;y^K)E3Df+4i`d3?#!+mh2#qT;^w&`dv^to*F=3=r4 zi#EO&ZBPuL8>!u@jS-TC^H3jMwW%6mX|g!Em}kj1Rhbrm$^~b#by#D31E?9vHTJXCWF2&3kYquU z1xfaNCD|+-Q14xl9Z^C-xB#JIV%uZ{K^6qrXCTN}`%>0|2qsMt-Z6f|WC+DIFQ626 zQ8KW^6xcxEc}K~*>BY}Zkx3$;Gm#V&Sx{tOv?BW{$>QrMO@l1+UN=a)@nKw`Oz99P z3%aa7T~?zcEOemB4ApjY#E4`}bH9f&Tf2d>V9eNIYYn5LqKcse@O>_GWm`+GWrV8r zvuUA}Vxclh$ct!n9_C(ZgMQL^nEKOXgtPV=<=qxSx4t9@-CbYuP#FanTW@p)kj9Rs zI}2DB*-w%y=DpfdWm6BY#YbbDZnjn`%LA(fR%w)NW%h`HwxN~2s<*M$+oGAQrXUGN?`;9Z>pgJqkQ#@vbS>$pp{Ue zJ!Wt+(ZOj8>)HU)ZBaFT4_n|CX~ZFcHSVkh>W~>F0-7R!4q@p|y0BhUTJA)pHS>F9 ztL*|TM5RMi`YVV^XK|cG(_|IW1^PI3gMm@5&JOJGZ3s(;uyk+f0@a0eS^Gl;fKa0f zsYF5fOy6`!+#$J=-AatPaa-aFQD&f(mU;Z3#V#6IugI>V+eLP%^}3kvPQP-;Xd^Fz zGEEP43`KUsiC$a!;`J)OAd8zIF1#O7EQqnRDB?$rfgmpWIns-%&TOXls*g+&CTvl8 z5sAc(5gE84K;iW+*PL^0VR}M-)DwaHnSw{loKX}9pOhbmm!%W_$$ry_E$?8_42V(NbR7vU||4eKO9z}H-WH)we8+w9O4=Uk3Jk#P1w=L-H;HxCXICwcoV z{ft=mwK3GK+Gi1wJ0M1cW^xSZ^a*gdP3zM3$sh0H>?&SmgDhtAuZ&CFLJi}Lfd%~j zs1?>bl~jz$FM&&Fe~D37#UoV<0^aQo*D8u?y~9-!S%~H%m&>b-Pp{w(3jbjw2N$7d z+Eup`L^j9no2gvXa*%!eu#BVC*T+`Upb%k}DawUq+BaKO56{3?&ylZK2ep)RQI1m+ zA^h^y9h4zVQsgT^2@d-Ln+f(D_{yb(;V4YbkRDt_DyS>}_3JB!XW*;PnXf7qaX9aQ zuLO#1OStq)Roq&{F~kb4$K0Z&w#wmZD#3r%x5GA;T!s%tEw~F=<-Nk3fznY`5e+ee_wt4BafGZXq8`twPWugiIO21f)UR# zc&a;Kr}fTlO+53{Eev)1B#AZvqatnU^XI1@-!JA_KA6UXDXNr@A3~0LFC0}eFat|H zN0u@jl(wgZ!SWn5y~8ocO9f4VQAK$28L-q_Y|AQ(k3W8xWQqG%ASv%>3YCw`z*3)- grPi<0=qAoyy;#4%-{)C$`Rc|00m;~+5(4W002iUCga7~l literal 0 HcmV?d00001 From a2686bbf9755e39c2f43dc363c76052774d29434 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Thu, 12 Oct 2017 21:02:19 +0200 Subject: [PATCH 08/27] Optimisation de l'export REST --- machines/views.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/machines/views.py b/machines/views.py index c103a080..d83b8d92 100644 --- a/machines/views.py +++ b/machines/views.py @@ -1205,24 +1205,28 @@ def service_servers(request): @permission_required('serveur') def ouverture_ports(request): r = {'ipv4':{}, 'ipv6':{}} - for i in Interface.objects.all(): - if not i.may_have_port_open(): - continue - if i.ipv4: - r['ipv4'][i.ipv4.ipv4] = {"tcp_in":[],"tcp_out":[],"udp_in":[],"udp_out":[]} - if i.ipv6_object: - r['ipv6'][i.ipv6] = {"tcp_in":[],"tcp_out":[],"udp_in":[],"udp_out":[]} - for j in i.port_lists.all(): - if i.ipv4: - r['ipv4'][i.ipv4.ipv4]["tcp_in"].extend(j.tcp_ports_in()) - r['ipv4'][i.ipv4.ipv4]["tcp_out"].extend(j.tcp_ports_out()) - r['ipv4'][i.ipv4.ipv4]["udp_in"].extend(j.udp_ports_in()) - r['ipv4'][i.ipv4.ipv4]["udp_out"].extend(j.udp_ports_out()) + for o in OuverturePortList.objects.all().prefetch_related('ouvertureport_set'): + pl = { + "tcp_in":set(map(str,o.tcp_ports_in())), + "tcp_out":set(map(str,o.tcp_ports_out())), + "udp_in":set(map(str,o.udp_ports_in())), + "udp_out":set(map(str,o.udp_ports_out())), + } + for i in o.interface_set.filter(machine__in=Machine.objects.filter(user__in=all_has_access()).filter(active=True)).select_related('domain').select_related('machine').select_related('type').select_related('ipv4').select_related('domain__extension').select_related('ipv4__ip_type').distinct(): + if i.may_have_port_open(): + d = r['ipv4'].get(i.ipv4.ipv4, {}) + d["tcp_in"] = d.get("tcp_in",set()).union(pl["tcp_in"]) + d["tcp_out"] = d.get("tcp_out",set()).union(pl["tcp_out"]) + d["udp_in"] = d.get("udp_in",set()).union(pl["udp_in"]) + d["udp_out"] = d.get("udp_out",set()).union(pl["udp_out"]) + r['ipv4'][i.ipv4.ipv4] = d if i.ipv6_object: - r['ipv6'][i.ipv6]["tcp_in"].extend(j.tcp_ports_in()) - r['ipv6'][i.ipv6]["tcp_out"].extend(j.tcp_ports_out()) - r['ipv6'][i.ipv6]["udp_in"].extend(j.udp_ports_in()) - r['ipv6'][i.ipv6]["udp_out"].extend(j.udp_ports_out()) + d = r['ipv6'].get(i.ipv6, {}) + d["tcp_in"] = d.get("tcp_in",set()).union(pl["tcp_in"]) + d["tcp_out"] = d.get("tcp_out",set()).union(pl["tcp_out"]) + d["udp_in"] = d.get("udp_in",set()).union(pl["udp_in"]) + d["udp_out"] = d.get("udp_out",set()).union(pl["udp_out"]) + r['ipv6'][i.ipv6] = d return JSONResponse(r) @csrf_exempt @login_required From a3aae41a4c302c53ce571e2f404a01d52d3a3553 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Thu, 12 Oct 2017 23:25:05 +0200 Subject: [PATCH 09/27] Prefetch des interfaces. --- machines/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machines/views.py b/machines/views.py index d83b8d92..5c9e31e6 100644 --- a/machines/views.py +++ b/machines/views.py @@ -1205,7 +1205,7 @@ def service_servers(request): @permission_required('serveur') def ouverture_ports(request): r = {'ipv4':{}, 'ipv6':{}} - for o in OuverturePortList.objects.all().prefetch_related('ouvertureport_set'): + for o in OuverturePortList.objects.all().prefetch_related('ouvertureport_set').prefetch_related('interface_set'): pl = { "tcp_in":set(map(str,o.tcp_ports_in())), "tcp_out":set(map(str,o.tcp_ports_out())), From c1c9c5eddc9b818c496e7bfe335d7dba8c515a37 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Thu, 12 Oct 2017 23:54:50 +0200 Subject: [PATCH 10/27] map c'est mieux que faire un for, lalala --- machines/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machines/serializers.py b/machines/serializers.py index 5ecf439a..b18bbfb0 100644 --- a/machines/serializers.py +++ b/machines/serializers.py @@ -91,9 +91,9 @@ class TypeSerializer(serializers.ModelSerializer): fields = ('type', 'extension', 'domaine_ip_start', 'domaine_ip_stop', 'ouverture_ports_tcp_in', 'ouverture_ports_tcp_out', 'ouverture_ports_udp_in', 'ouverture_ports_udp_out', ) def get_port_policy(self, obj, protocole, io): - if not obj.ouverture_ports: + if obj.ouverture_ports is None: return [] - return [str(port) for port in obj.ouverture_ports.ouvertureport_set.filter(protocole=protocole).filter(io=io)] + return map(str, obj.ouverture_ports.ouvertureport_set.filter(protocole=protocole).filter(io=io)) def get_port_policy_input_tcp(self, obj): return self.get_port_policy(obj, OuverturePort.TCP, OuverturePort.IN) From bde104bc387e5b569fc9fb4edbe69df659f97e3f Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Sat, 14 Oct 2017 12:40:22 +0200 Subject: [PATCH 11/27] Factorisation de code. --- machines/views.py | 113 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 96 insertions(+), 17 deletions(-) diff --git a/machines/views.py b/machines/views.py index 5c9e31e6..7ac2bb63 100644 --- a/machines/views.py +++ b/machines/views.py @@ -43,31 +43,107 @@ from django.contrib.auth import authenticate, login from django.views.decorators.csrf import csrf_exempt from rest_framework.renderers import JSONRenderer -from machines.serializers import FullInterfaceSerializer, InterfaceSerializer, TypeSerializer, DomainSerializer, TextSerializer, MxSerializer, ExtensionSerializer, ServiceServersSerializer, NsSerializer, OuverturePortsSerializer +from machines.serializers import ( FullInterfaceSerializer, + InterfaceSerializer, + TypeSerializer, + DomainSerializer, + TextSerializer, + MxSerializer, + ExtensionSerializer, + ServiceServersSerializer, + NsSerializer, + OuverturePortsSerializer +) from reversion import revisions as reversion 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 ( + 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 EditOuverturePortListForm, EditOuverturePortConfigForm -from .models import IpType, Machine, Interface, IpList, MachineType, Extension, Mx, Ns, Domain, Service, Service_link, Vlan, Nas, Text, OuverturePortList, OuverturePort +from .models import ( + IpType, + Machine, + Interface, + IpList, + MachineType, + Extension, + Mx, + Ns, + Domain, + Service, + Service_link, + Vlan, + Nas, + Text, + OuverturePortList, + OuverturePort +) from users.models import User from users.models import all_has_access from preferences.models import GeneralOption, OptionalMachine from .templatetags.bootstrap_form_typeahead import hidden_id, input_id +def filter_active_interfaces(q): + """Filtre les machines autorisées à sortir sur internet dans une requête""" + return q.filter( + machine__in=Machine.objects.filter( + user__in=all_has_access() + ).filter(active=True)) \ + .select_related('domain') \ + .select_related('machine') \ + .select_related('type') \ + .select_related('ipv4') \ + .select_related('domain__extension') \ + .select_related('ipv4__ip_type').distinct() + def all_active_interfaces(): """Renvoie l'ensemble des machines autorisées à sortir sur internet """ - return Interface.objects.filter(machine__in=Machine.objects.filter(user__in=all_has_access()).filter(active=True)).select_related('domain').select_related('machine').select_related('type').select_related('ipv4').select_related('domain__extension').select_related('ipv4__ip_type').distinct() + return filter_active_interfaces(Interface.objects) def all_active_assigned_interfaces(): - """ Renvoie l'ensemble des machines qui ont une ipv4 assignées et disposant de l'accès internet""" + """ + Renvoie l'ensemble des machines qui ont une ipv4 assignées et disposant de + l'accès internet + """ return all_active_interfaces().filter(ipv4__isnull=False) def all_active_interfaces_count(): """ Version light seulement pour compter""" - return Interface.objects.filter(machine__in=Machine.objects.filter(user__in=all_has_access()).filter(active=True)) + return Interface.objects.filter( + machine__in=Machine.objects.filter(user__in=all_has_access())\ + .filter(active=True) + ) def all_active_assigned_interfaces_count(): """ Version light seulement pour compter""" @@ -92,7 +168,8 @@ def generate_ipv4_choices( form ) : choices = '{"":[{key:"",value:"Choisissez d\'abord un type de machine"},' mtype_id = -1 - for ip in f_ipv4.queryset.annotate(mtype_id=F('ip_type__machinetype__id')).order_by('mtype_id', 'id') : + for ip in f_ipv4.queryset.annotate(mtype_id=F('ip_type__machinetype__id'))\ + .order_by('mtype_id', 'id') : if mtype_id != ip.mtype_id : mtype_id = ip.mtype_id used_mtype_id.append(mtype_id) @@ -159,8 +236,8 @@ def generate_ipv4_bft_param( form, is_type_tt ): @login_required def new_machine(request, userid): - """ Fonction de creation d'une machine. Cree l'objet machine, le sous objet interface et l'objet domain - à partir de model forms. + """ Fonction de creation d'une machine. Cree l'objet machine, + le sous objet interface et l'objet domain à partir de model forms. Trop complexe, devrait être simplifié""" try: user = User.objects.get(pk=userid) @@ -171,7 +248,9 @@ def new_machine(request, userid): max_lambdauser_interfaces = options.max_lambdauser_interfaces if not request.user.has_perms(('cableur',)): if user != request.user: - messages.error(request, "Vous ne pouvez pas ajouter une machine à un autre user que vous sans droit") + messages.error( + request, + "Vous ne pouvez pas ajouter une machine à un autre user que vous sans droit") return redirect("/users/profil/" + str(request.user.id)) if user.user_interfaces().count() >= max_lambdauser_interfaces: messages.error(request, "Vous avez atteint le maximum d'interfaces autorisées que vous pouvez créer vous même (%s) " % max_lambdauser_interfaces) @@ -1205,14 +1284,14 @@ def service_servers(request): @permission_required('serveur') def ouverture_ports(request): r = {'ipv4':{}, 'ipv6':{}} - for o in OuverturePortList.objects.all().prefetch_related('ouvertureport_set').prefetch_related('interface_set'): + for o in OuverturePortList.objects.all().prefetch_related('ouvertureport_set').prefetch_related('interface_set', 'interface_set__ipv4'): pl = { - "tcp_in":set(map(str,o.tcp_ports_in())), - "tcp_out":set(map(str,o.tcp_ports_out())), - "udp_in":set(map(str,o.udp_ports_in())), - "udp_out":set(map(str,o.udp_ports_out())), + "tcp_in":set(map(str,o.ouvertureport_set.filter(protocole=OuverturePort.TCP, io=OuverturePort.IN))), + "tcp_out":set(map(str,o.ouvertureport_set.filter(protocole=OuverturePort.TCP, io=OuverturePort.OUT))), + "udp_in":set(map(str,o.ouvertureport_set.filter(protocole=OuverturePort.UDP, io=OuverturePort.IN))), + "udp_out":set(map(str,o.ouvertureport_set.filter(protocole=OuverturePort.UDP, io=OuverturePort.OUT))), } - for i in o.interface_set.filter(machine__in=Machine.objects.filter(user__in=all_has_access()).filter(active=True)).select_related('domain').select_related('machine').select_related('type').select_related('ipv4').select_related('domain__extension').select_related('ipv4__ip_type').distinct(): + for i in filter_active_interfaces(o.interface_set): if i.may_have_port_open(): d = r['ipv4'].get(i.ipv4.ipv4, {}) d["tcp_in"] = d.get("tcp_in",set()).union(pl["tcp_in"]) From 0eeb9685e51e789f6d969acc44def322de37d067 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 15 Oct 2017 20:37:21 +0200 Subject: [PATCH 12/27] =?UTF-8?q?Borde=20un=20certain=20nombre=20d'integer?= =?UTF-8?q?=20qui=20ont=20des=20range=20de=20valeur=20d=C3=A9fini=20dans?= =?UTF-8?q?=20les=20RFC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0024_auto_20171015_2033.py | 26 ++++++++++++ cotisations/models.py | 4 +- .../migrations/0061_auto_20171015_2033.py | 36 +++++++++++++++++ machines/models.py | 13 +++--- .../migrations/0031_auto_20171015_2033.py | 40 +++++++++++++++++++ topologie/models.py | 10 ++--- users/migrations/0056_auto_20171015_2033.py | 37 +++++++++++++++++ users/models.py | 6 +-- 8 files changed, 157 insertions(+), 15 deletions(-) create mode 100644 cotisations/migrations/0024_auto_20171015_2033.py create mode 100644 machines/migrations/0061_auto_20171015_2033.py create mode 100644 topologie/migrations/0031_auto_20171015_2033.py create mode 100644 users/migrations/0056_auto_20171015_2033.py diff --git a/cotisations/migrations/0024_auto_20171015_2033.py b/cotisations/migrations/0024_auto_20171015_2033.py new file mode 100644 index 00000000..b52dad62 --- /dev/null +++ b/cotisations/migrations/0024_auto_20171015_2033.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-15 18:33 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cotisations', '0023_auto_20170902_1303'), + ] + + operations = [ + migrations.AlterField( + model_name='article', + name='duration', + field=models.PositiveIntegerField(blank=True, help_text='Durée exprimée en mois entiers', null=True, validators=[django.core.validators.MinValueValidator(0)]), + ), + migrations.AlterField( + model_name='vente', + name='duration', + field=models.PositiveIntegerField(blank=True, help_text='Durée exprimée en mois entiers', null=True), + ), + ] diff --git a/cotisations/models.py b/cotisations/models.py index 54843076..0b3aef35 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -132,7 +132,7 @@ class Vente(models.Model): name = models.CharField(max_length=255) prix = models.DecimalField(max_digits=5, decimal_places=2) iscotisation = models.BooleanField() - duration = models.IntegerField( + duration = models.PositiveIntegerField( help_text="Durée exprimée en mois entiers", blank=True, null=True) @@ -222,7 +222,7 @@ class Article(models.Model): name = models.CharField(max_length=255, unique=True) prix = models.DecimalField(max_digits=5, decimal_places=2) iscotisation = models.BooleanField() - duration = models.IntegerField( + duration = models.PositiveIntegerField( help_text="Durée exprimée en mois entiers", blank=True, null=True, diff --git a/machines/migrations/0061_auto_20171015_2033.py b/machines/migrations/0061_auto_20171015_2033.py new file mode 100644 index 00000000..6153bbd0 --- /dev/null +++ b/machines/migrations/0061_auto_20171015_2033.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-15 18:33 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0060_iptype_ouverture_ports'), + ] + + operations = [ + migrations.AlterField( + model_name='mx', + name='priority', + field=models.PositiveIntegerField(unique=True), + ), + migrations.AlterField( + model_name='ouvertureport', + name='begin', + field=models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(65535)]), + ), + migrations.AlterField( + model_name='ouvertureport', + name='end', + field=models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(65535)]), + ), + migrations.AlterField( + model_name='vlan', + name='vlan_id', + field=models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(4095)]), + ), + ] diff --git a/machines/models.py b/machines/models.py index 7444996c..0c1686ba 100644 --- a/machines/models.py +++ b/machines/models.py @@ -151,10 +151,11 @@ class IpType(models.Model): return self.type class Vlan(models.Model): - """ Un vlan : vlan_id et nom""" + """ Un vlan : vlan_id et nom + On limite le vlan id entre 0 et 4096, comme défini par la norme""" PRETTY_NAME = "Vlans" - vlan_id = models.IntegerField() + vlan_id = models.PositiveIntegerField(validators=[MaxValueValidator(4095)]) name = models.CharField(max_length=256) comment = models.CharField(max_length=256, blank=True) @@ -205,7 +206,7 @@ class Mx(models.Model): PRETTY_NAME = "Enregistrements MX" zone = models.ForeignKey('Extension', on_delete=models.PROTECT) - priority = models.IntegerField(unique=True) + priority = models.PositiveIntegerField(unique=True) name = models.OneToOneField('Domain', on_delete=models.PROTECT) @cached_property @@ -512,13 +513,15 @@ class OuverturePort(models.Model): Les ports de la plage sont compris entre begin et en inclus. Si begin == end alors on ne représente qu'un seul port. + + On limite les ports entre 0 et 65535, tels que défini par la RFC """ TCP = 'T' UDP = 'U' IN = 'I' OUT = 'O' - begin = models.IntegerField() - end = models.IntegerField() + begin = models.PositiveIntegerField(validators=[MaxValueValidator(65535)]) + end = models.PositiveIntegerField(validators=[MaxValueValidator(65535)]) port_list = models.ForeignKey('OuverturePortList', on_delete=models.CASCADE) protocole = models.CharField( max_length=1, diff --git a/topologie/migrations/0031_auto_20171015_2033.py b/topologie/migrations/0031_auto_20171015_2033.py new file mode 100644 index 00000000..674af6c6 --- /dev/null +++ b/topologie/migrations/0031_auto_20171015_2033.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-15 18:33 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('topologie', '0030_auto_20171004_0235'), + ] + + operations = [ + migrations.AlterField( + model_name='port', + name='port', + field=models.PositiveIntegerField(), + ), + migrations.AlterField( + model_name='stack', + name='member_id_max', + field=models.PositiveIntegerField(), + ), + migrations.AlterField( + model_name='stack', + name='member_id_min', + field=models.PositiveIntegerField(), + ), + migrations.AlterField( + model_name='switch', + name='number', + field=models.PositiveIntegerField(), + ), + migrations.AlterField( + model_name='switch', + name='stack_member_id', + field=models.PositiveIntegerField(blank=True, null=True), + ), + ] diff --git a/topologie/models.py b/topologie/models.py index 086e0aff..66c8fe94 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -52,8 +52,8 @@ class Stack(models.Model): name = models.CharField(max_length=32, blank=True, null=True) stack_id = models.CharField(max_length=32, unique=True) details = models.CharField(max_length=255, blank=True, null=True) - member_id_min = models.IntegerField() - member_id_max = models.IntegerField() + member_id_min = models.PositiveIntegerField() + member_id_max = models.PositiveIntegerField() def __str__(self): return " ".join([self.name, self.stack_id]) @@ -90,7 +90,7 @@ class Switch(models.Model): on_delete=models.CASCADE ) location = models.CharField(max_length=255) - number = models.IntegerField() + number = models.PositiveIntegerField() details = models.CharField(max_length=255, blank=True) stack = models.ForeignKey( Stack, @@ -98,7 +98,7 @@ class Switch(models.Model): null=True, on_delete=models.SET_NULL ) - stack_member_id = models.IntegerField(blank=True, null=True) + stack_member_id = models.PositiveIntegerField(blank=True, null=True) class Meta: unique_together = ('stack', 'stack_member_id') @@ -146,7 +146,7 @@ class Port(models.Model): ) switch = models.ForeignKey('Switch', related_name="ports") - port = models.IntegerField() + port = models.PositiveIntegerField() room = models.ForeignKey( 'Room', on_delete=models.PROTECT, diff --git a/users/migrations/0056_auto_20171015_2033.py b/users/migrations/0056_auto_20171015_2033.py new file mode 100644 index 00000000..a47aca6a --- /dev/null +++ b/users/migrations/0056_auto_20171015_2033.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-15 18:33 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models +import users.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0055_auto_20171003_0556'), + ] + + operations = [ + migrations.AlterField( + model_name='listright', + name='gid', + field=models.PositiveIntegerField(null=True, unique=True), + ), + migrations.AlterField( + model_name='listright', + name='listright', + field=models.CharField(max_length=255, unique=True, validators=[django.core.validators.RegexValidator('^[a-z]+$', message='Les groupes unix ne peuvent contenir que des lettres minuscules')]), + ), + migrations.AlterField( + model_name='user', + name='rezo_rez_uid', + field=models.PositiveIntegerField(blank=True, null=True, unique=True), + ), + migrations.AlterField( + model_name='user', + name='uid_number', + field=models.PositiveIntegerField(default=users.models.User.auto_uid, unique=True), + ), + ] diff --git a/users/models.py b/users/models.py index 2f8f888f..550bc770 100644 --- a/users/models.py +++ b/users/models.py @@ -243,8 +243,8 @@ class User(AbstractBaseUser): state = models.IntegerField(choices=STATES, default=STATE_ACTIVE) registered = models.DateTimeField(auto_now_add=True) telephone = models.CharField(max_length=15, blank=True, null=True) - uid_number = models.IntegerField(default=auto_uid, unique=True) - rezo_rez_uid = models.IntegerField(unique=True, blank=True, null=True) + uid_number = models.PositiveIntegerField(default=auto_uid, unique=True) + rezo_rez_uid = models.PositiveIntegerField(unique=True, blank=True, null=True) USERNAME_FIELD = 'pseudo' REQUIRED_FIELDS = ['name', 'surname', 'email'] @@ -840,7 +840,7 @@ class ListRight(models.Model): que des lettres minuscules" )] ) - gid = models.IntegerField(unique=True, null=True) + gid = models.PositiveIntegerField(unique=True, null=True) details = models.CharField( help_text="Description", max_length=255, From 22072ad6416625fee4953d06004399d0fc67a9e4 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 15 Oct 2017 21:09:41 +0200 Subject: [PATCH 13/27] =?UTF-8?q?Simplify,=20requ=C3=A8te=20inutile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- freeradius_utils/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index e3e272c9..2d1ebfe2 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -292,7 +292,7 @@ def decide_vlan_and_register_switch(nas, nas_type, port_number, mac_address): if not port.room: return (sw_name, u'Chambre inconnue', VLAN_NOK) - room_user = User.objects.filter(room=Room.objects.filter(name=port.room)) + room_user = User.objects.filter(room=port.room) if not room_user: return (sw_name, u'Chambre non cotisante', VLAN_NOK) elif not room_user.first().has_access(): From 4c9477aa93324516dc053ff6cbb63af477b95be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Kervella?= Date: Sun, 15 Oct 2017 19:40:26 +0000 Subject: [PATCH 14/27] Permet de retirer un droit sans JS --- users/templates/users/del_right.html | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/users/templates/users/del_right.html b/users/templates/users/del_right.html index 30edf666..57e706a7 100644 --- a/users/templates/users/del_right.html +++ b/users/templates/users/del_right.html @@ -34,19 +34,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% csrf_token %} - +
{% for key, values in userform.items %}
- {{ key }} ( {{values.rights|length }} users )
-
+
    {% for user in values.rights %}
  • {{ user }}
  • @@ -58,9 +58,18 @@ with this program; if not, write to the Free Software Foundation, Inc., {% endfor %}
- {% bootstrap_button "Modifier" button_type="submit" icon="star" %} + {% bootstrap_button "Supprimer" button_type="submit" icon="star" %}
+ +


From 289eb20393b900d8f26e135a252625cb7479a2e8 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 15 Oct 2017 22:10:33 +0200 Subject: [PATCH 15/27] Pep8 et nettoyage --- machines/models.py | 392 +++++++++++++++++++++++++++++++++------------ 1 file changed, 286 insertions(+), 106 deletions(-) diff --git a/machines/models.py b/machines/models.py index 0c1686ba..c1d8ca80 100644 --- a/machines/models.py +++ b/machines/models.py @@ -23,44 +23,59 @@ from __future__ import unicode_literals +from datetime import timedelta +import re +from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress + from django.db import models -from django.db.models.signals import post_save, pre_delete, post_delete +from django.db.models.signals import post_save, post_delete from django.dispatch import receiver from django.forms import ValidationError from django.utils.functional import cached_property from django.utils import timezone +from django.core.validators import MaxValueValidator + from macaddress.fields import MACAddressField -from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress -from django.core.validators import MinValueValidator,MaxValueValidator -import re -from reversion import revisions as reversion -from datetime import timedelta class Machine(models.Model): - """ Class définissant une machine, object parent user, objets fils interfaces""" + """ Class définissant une machine, object parent user, objets fils + interfaces""" PRETTY_NAME = "Machine" - + user = models.ForeignKey('users.User', on_delete=models.PROTECT) - name = models.CharField(max_length=255, help_text="Optionnel", blank=True, null=True) + name = models.CharField( + max_length=255, + help_text="Optionnel", + blank=True, + null=True + ) active = models.BooleanField(default=True) def __str__(self): - return str(self.user) + ' - ' + str(self.id) + ' - ' + str(self.name) + return str(self.user) + ' - ' + str(self.id) + ' - ' + str(self.name) + class MachineType(models.Model): """ Type de machine, relié à un type d'ip, affecté aux interfaces""" PRETTY_NAME = "Type de machine" type = models.CharField(max_length=255) - ip_type = models.ForeignKey('IpType', on_delete=models.PROTECT, blank=True, null=True) + ip_type = models.ForeignKey( + 'IpType', + on_delete=models.PROTECT, + blank=True, + null=True + ) def all_interfaces(self): - """ Renvoie toutes les interfaces (cartes réseaux) de type machinetype""" + """ Renvoie toutes les interfaces (cartes réseaux) de type + machinetype""" return Interface.objects.filter(type=self) def __str__(self): - return self.type + return self.type + class IpType(models.Model): """ Type d'ip, définissant un range d'ip, affecté aux machine types""" @@ -71,14 +86,27 @@ class IpType(models.Model): need_infra = models.BooleanField(default=False) domaine_ip_start = models.GenericIPAddressField(protocol='IPv4') domaine_ip_stop = models.GenericIPAddressField(protocol='IPv4') - prefix_v6 = models.GenericIPAddressField(protocol='IPv6', null=True, blank=True) - vlan = models.ForeignKey('Vlan', on_delete=models.PROTECT, blank=True, null=True) - ouverture_ports = models.ForeignKey('OuverturePortList', blank=True, null=True) + prefix_v6 = models.GenericIPAddressField( + protocol='IPv6', + null=True, + blank=True + ) + vlan = models.ForeignKey( + 'Vlan', + on_delete=models.PROTECT, + blank=True, + null=True + ) + ouverture_ports = models.ForeignKey( + 'OuverturePortList', + blank=True, + null=True + ) @cached_property def ip_range(self): - """ Renvoie un objet IPRange à partir de l'objet IpType""" - return IPRange(self.domaine_ip_start, end=self.domaine_ip_stop) + """ Renvoie un objet IPRange à partir de l'objet IpType""" + return IPRange(self.domaine_ip_start, end=self.domaine_ip_stop) @cached_property def ip_set(self): @@ -96,18 +124,22 @@ class IpType(models.Model): def free_ip(self): """ Renvoie toutes les ip libres associées au type donné (self)""" - return IpList.objects.filter(interface__isnull=True).filter(ip_type=self) + return IpList.objects.filter( + interface__isnull=True + ).filter(ip_type=self) def gen_ip_range(self): - """ Cree les IpList associées au type self. Parcours pédestrement et crée - les ip une par une. Si elles existent déjà, met à jour le type associé - à l'ip""" + """ Cree les IpList associées au type self. Parcours pédestrement et + crée les ip une par une. Si elles existent déjà, met à jour le type + associé à l'ip""" # Creation du range d'ip dans les objets iplist networks = [] for net in self.ip_range.cidrs(): networks += net.iter_hosts() ip_obj = [IpList(ip_type=self, ipv4=str(ip)) for ip in networks] - listes_ip = IpList.objects.filter(ipv4__in=[str(ip) for ip in networks]) + listes_ip = IpList.objects.filter( + ipv4__in=[str(ip) for ip in networks] + ) # Si il n'y a pas d'ip, on les crée if not listes_ip: IpList.objects.bulk_create(ip_obj) @@ -117,9 +149,11 @@ class IpType(models.Model): return def del_ip_range(self): - """ Methode dépréciée, IpList est en mode cascade et supprimé automatiquement""" + """ Methode dépréciée, IpList est en mode cascade et supprimé + automatiquement""" if Interface.objects.filter(ipv4__in=self.ip_objects()): - raise ValidationError("Une ou plusieurs ip du range sont affectées, impossible de supprimer le range") + raise ValidationError("Une ou plusieurs ip du range sont\ + affectées, impossible de supprimer le range") for ip in self.ip_objects(): ip.delete() @@ -133,11 +167,13 @@ class IpType(models.Model): raise ValidationError("Domaine end doit être après start...") # On ne crée pas plus grand qu'un /16 if self.ip_range.size > 65536: - raise ValidationError("Le range est trop gros, vous ne devez pas créer plus grand qu'un /16") + raise ValidationError("Le range est trop gros, vous ne devez\ + pas créer plus grand qu'un /16") # On check que les / ne se recoupent pas for element in IpType.objects.all().exclude(pk=self.pk): if not self.ip_set.isdisjoint(element.ip_set): - raise ValidationError("Le range indiqué n'est pas disjoint des ranges existants") + raise ValidationError("Le range indiqué n'est pas disjoint\ + des ranges existants") # On formate le prefix v6 if self.prefix_v6: self.prefix_v6 = str(IPNetwork(self.prefix_v6 + '/64').network) @@ -150,6 +186,7 @@ class IpType(models.Model): def __str__(self): return self.type + class Vlan(models.Model): """ Un vlan : vlan_id et nom On limite le vlan id entre 0 et 4096, comme défini par la norme""" @@ -162,8 +199,9 @@ class Vlan(models.Model): def __str__(self): return self.name + class Nas(models.Model): - """ Les nas. Associé à un machine_type. + """ Les nas. Associé à un machine_type. Permet aussi de régler le port_access_mode (802.1X ou mac-address) pour le radius. Champ autocapture de la mac à true ou false""" PRETTY_NAME = "Correspondance entre les nas et les machines connectées" @@ -175,33 +213,53 @@ class Nas(models.Model): ) name = models.CharField(max_length=255, unique=True) - nas_type = models.ForeignKey('MachineType', on_delete=models.PROTECT, related_name='nas_type') - machine_type = models.ForeignKey('MachineType', on_delete=models.PROTECT, related_name='machinetype_on_nas') - port_access_mode = models.CharField(choices=AUTH, default=default_mode, max_length=32) + nas_type = models.ForeignKey( + 'MachineType', + on_delete=models.PROTECT, + related_name='nas_type' + ) + machine_type = models.ForeignKey( + 'MachineType', + on_delete=models.PROTECT, + related_name='machinetype_on_nas' + ) + port_access_mode = models.CharField( + choices=AUTH, + default=default_mode, + max_length=32 + ) autocapture_mac = models.BooleanField(default=False) def __str__(self): return self.name + class Extension(models.Model): - """ Extension dns type example.org. Précise si tout le monde peut l'utiliser, - associé à un origin (ip d'origine)""" + """ Extension dns type example.org. Précise si tout le monde peut + l'utiliser, associé à un origin (ip d'origine)""" PRETTY_NAME = "Extensions dns" name = models.CharField(max_length=255, unique=True) need_infra = models.BooleanField(default=False) - origin = models.OneToOneField('IpList', on_delete=models.PROTECT, blank=True, null=True) + origin = models.OneToOneField( + 'IpList', + on_delete=models.PROTECT, + blank=True, + null=True + ) @cached_property def dns_entry(self): """ Une entrée DNS A""" - return "@ IN A " + str(self.origin) + return "@ IN A " + str(self.origin) def __str__(self): return self.name + class Mx(models.Model): - """ Entrées des MX. Enregistre la zone (extension) associée et la priorité + """ Entrées des MX. Enregistre la zone (extension) associée et la + priorité Todo : pouvoir associer un MX à une interface """ PRETTY_NAME = "Enregistrements MX" @@ -211,12 +269,16 @@ class Mx(models.Model): @cached_property def dns_entry(self): - return "@ IN MX " + str(self.priority) + " " + str(self.name) + """Renvoie l'entrée DNS complète pour un MX à mettre dans les + fichiers de zones""" + return "@ IN MX " + str(self.priority) + " " + str(self.name) def __str__(self): return str(self.zone) + ' ' + str(self.priority) + ' ' + str(self.name) + class Ns(models.Model): + """Liste des enregistrements name servers par zone considéérée""" PRETTY_NAME = "Enregistrements NS" zone = models.ForeignKey('Extension', on_delete=models.PROTECT) @@ -224,11 +286,13 @@ class Ns(models.Model): @cached_property def dns_entry(self): - return "@ IN NS " + str(self.ns) + """Renvoie un enregistrement NS complet pour les filezones""" + return "@ IN NS " + str(self.ns) def __str__(self): return str(self.zone) + ' ' + str(self.ns) + class Text(models.Model): """ Un enregistrement TXT associé à une extension""" PRETTY_NAME = "Enregistrement text" @@ -236,24 +300,33 @@ class Text(models.Model): zone = models.ForeignKey('Extension', on_delete=models.PROTECT) field1 = models.CharField(max_length=255) field2 = models.CharField(max_length=255) - + def __str__(self): - return str(self.zone) + " : " + str(self.field1) + " " + str(self.field2) + return str(self.zone) + " : " + str(self.field1) + " " +\ + str(self.field2) @cached_property def dns_entry(self): + """Renvoie l'enregistrement TXT complet pour le fichier de zone""" return str(self.field1) + " IN TXT " + str(self.field2) + class Interface(models.Model): - """ Une interface. Objet clef de l'application machine : - - une address mac unique. Possibilité de la rendre unique avec le typemachine + """ Une interface. Objet clef de l'application machine : + - une address mac unique. Possibilité de la rendre unique avec le + typemachine - une onetoone vers IpList pour attribution ipv4 - le type parent associé au range ip et à l'extension - un objet domain associé contenant son nom - la liste des ports oiuvert""" PRETTY_NAME = "Interface" - ipv4 = models.OneToOneField('IpList', on_delete=models.PROTECT, blank=True, null=True) + ipv4 = models.OneToOneField( + 'IpList', + on_delete=models.PROTECT, + blank=True, + null=True + ) mac_address = MACAddressField(integer=False, unique=True) machine = models.ForeignKey('Machine', on_delete=models.CASCADE) type = models.ForeignKey('MachineType', on_delete=models.PROTECT) @@ -267,12 +340,14 @@ class Interface(models.Model): user = self.machine.user return machine.active and user.has_access() - @cached_property def ipv6_object(self): - """ Renvoie un objet type ipv6 à partir du prefix associé à l'iptype parent""" + """ Renvoie un objet type ipv6 à partir du prefix associé à + l'iptype parent""" if self.type.ip_type.prefix_v6: - return EUI(self.mac_address).ipv6(IPNetwork(self.type.ip_type.prefix_v6).network) + return EUI(self.mac_address).ipv6( + IPNetwork(self.type.ip_type.prefix_v6).network + ) else: return None @@ -286,10 +361,11 @@ class Interface(models.Model): return str(EUI(self.mac_address, dialect=mac_bare)).lower() def filter_macaddress(self): - """ Tente un formatage mac_bare, si échoue, lève une erreur de validation""" + """ Tente un formatage mac_bare, si échoue, lève une erreur de + validation""" try: self.mac_address = str(EUI(self.mac_address)) - except : + except: raise ValidationError("La mac donnée est invalide") def clean(self, *args, **kwargs): @@ -307,7 +383,8 @@ class Interface(models.Model): if free_ips: self.ipv4 = free_ips[0] else: - raise ValidationError("Il n'y a plus d'ip disponibles dans le slash") + raise ValidationError("Il n'y a plus d'ip disponibles\ + dans le slash") return def unassign_ipv4(self): @@ -323,7 +400,8 @@ class Interface(models.Model): self.filter_macaddress() # On verifie la cohérence en forçant l'extension par la méthode if self.type.ip_type != self.ipv4.ip_type: - raise ValidationError("L'ipv4 et le type de la machine ne correspondent pas") + raise ValidationError("L'ipv4 et le type de la machine ne\ + correspondent pas") super(Interface, self).save(*args, **kwargs) def __str__(self): @@ -342,18 +420,34 @@ class Interface(models.Model): def may_have_port_open(self): """ True si l'interface a une ip et une ip publique. - Permet de ne pas exporter des ouvertures sur des ip privées (useless)""" + Permet de ne pas exporter des ouvertures sur des ip privées + (useless)""" return self.ipv4 and not self.has_private_ip() + class Domain(models.Model): - """ Objet domain. Enregistrement A et CNAME en même temps : permet de stocker les - alias et les nom de machines, suivant si interface_parent ou cname sont remplis""" + """ Objet domain. Enregistrement A et CNAME en même temps : permet de + stocker les alias et les nom de machines, suivant si interface_parent + ou cname sont remplis""" PRETTY_NAME = "Domaine dns" - interface_parent = models.OneToOneField('Interface', on_delete=models.CASCADE, blank=True, null=True) - name = models.CharField(help_text="Obligatoire et unique, ne doit pas comporter de points", max_length=255) + interface_parent = models.OneToOneField( + 'Interface', + on_delete=models.CASCADE, + blank=True, + null=True + ) + name = models.CharField( + help_text="Obligatoire et unique, ne doit pas comporter de points", + max_length=255 + ) extension = models.ForeignKey('Extension', on_delete=models.PROTECT) - cname = models.ForeignKey('self', null=True, blank=True, related_name='related_domain') + cname = models.ForeignKey( + 'self', + null=True, + blank=True, + related_name='related_domain' + ) class Meta: unique_together = (("name", "extension"),) @@ -363,30 +457,35 @@ class Domain(models.Model): Retourne l'extension propre si c'est un cname, renvoie None sinon""" if self.interface_parent: return self.interface_parent.type.ip_type.extension - elif hasattr(self,'extension'): + elif hasattr(self, 'extension'): return self.extension else: return None def clean(self): - """ Validation : + """ Validation : - l'objet est bien soit A soit CNAME - le cname est pas pointé sur lui-même - - le nom contient bien les caractères autorisés par la norme dns et moins de 63 caractères au total + - le nom contient bien les caractères autorisés par la norme + dns et moins de 63 caractères au total - le couple nom/extension est bien unique""" if self.get_extension(): - self.extension=self.get_extension() - """ Validation du nom de domaine, extensions dans type de machine, prefixe pas plus long que 63 caractères """ + self.extension = self.get_extension() if self.interface_parent and self.cname: raise ValidationError("On ne peut créer à la fois A et CNAME") - if self.cname==self: + if self.cname == self: raise ValidationError("On ne peut créer un cname sur lui même") - HOSTNAME_LABEL_PATTERN = re.compile("(?!-)[A-Z\d-]+(? 63: - raise ValidationError("Le nom de domaine %s est trop long (maximum de 63 caractères)." % dns) + raise ValidationError("Le nom de domaine %s est trop long\ + (maximum de 63 caractères)." % dns) if not HOSTNAME_LABEL_PATTERN.match(dns): - raise ValidationError("Ce nom de domaine %s contient des carractères interdits." % dns) + raise ValidationError("Ce nom de domaine %s contient des\ + carractères interdits." % dns) self.validate_unique() super(Domain, self).clean() @@ -394,10 +493,11 @@ class Domain(models.Model): def dns_entry(self): """ Une entrée DNS""" if self.cname: - return str(self.name) + " IN CNAME " + str(self.cname) + "." + return str(self.name) + " IN CNAME " + str(self.cname) + "." def save(self, *args, **kwargs): - """ Empèche le save sans extension valide. Force à avoir appellé clean avant""" + """ Empèche le save sans extension valide. + Force à avoir appellé clean avant""" if not self.get_extension(): raise ValidationError("Extension invalide") self.full_clean() @@ -406,6 +506,7 @@ class Domain(models.Model): def __str__(self): return str(self.name) + str(self.extension) + class IpList(models.Model): PRETTY_NAME = "Addresses ipv4" @@ -414,13 +515,15 @@ class IpList(models.Model): @cached_property def need_infra(self): - """ Permet de savoir si un user basique peut assigner cette ip ou non""" + """ Permet de savoir si un user basique peut assigner cette ip ou + non""" return self.ip_type.need_infra def clean(self): """ Erreur si l'ip_type est incorrect""" if not str(self.ipv4) in self.ip_type.ip_set_as_str: - raise ValidationError("L'ipv4 et le range de l'iptype ne correspondent pas!") + raise ValidationError("L'ipv4 et le range de l'iptype ne\ + correspondent pas!") return def save(self, *args, **kwargs): @@ -430,24 +533,36 @@ class IpList(models.Model): def __str__(self): return self.ipv4 + class Service(models.Model): """ Definition d'un service (dhcp, dns, etc)""" service_type = models.CharField(max_length=255, blank=True, unique=True) - min_time_regen = models.DurationField(default=timedelta(minutes=1), help_text="Temps minimal avant nouvelle génération du service") - regular_time_regen = models.DurationField(default=timedelta(hours=1), help_text="Temps maximal avant nouvelle génération du service") + min_time_regen = models.DurationField( + default=timedelta(minutes=1), + help_text="Temps minimal avant nouvelle génération du service" + ) + regular_time_regen = models.DurationField( + default=timedelta(hours=1), + help_text="Temps maximal avant nouvelle génération du service" + ) servers = models.ManyToManyField('Interface', through='Service_link') def ask_regen(self): """ Marque à True la demande de régénération pour un service x """ - Service_link.objects.filter(service=self).exclude(asked_regen=True).update(asked_regen=True) + Service_link.objects.filter(service=self).exclude(asked_regen=True)\ + .update(asked_regen=True) return def process_link(self, servers): - """ Django ne peut créer lui meme les relations manytomany avec table intermediaire explicite""" - for serv in servers.exclude(pk__in=Interface.objects.filter(service=self)): + """ Django ne peut créer lui meme les relations manytomany avec table + intermediaire explicite""" + for serv in servers.exclude( + pk__in=Interface.objects.filter(service=self) + ): link = Service_link(service=self, server=serv) link.save() - Service_link.objects.filter(service=self).exclude(server__in=servers).delete() + Service_link.objects.filter(service=self).exclude(server__in=servers)\ + .delete() return def save(self, *args, **kwargs): @@ -456,13 +571,16 @@ class Service(models.Model): def __str__(self): return str(self.service_type) + def regen(service): - """ Fonction externe pour régérération d'un service, prend un objet service en arg""" + """ Fonction externe pour régérération d'un service, prend un objet service + en arg""" obj = Service.objects.filter(service_type=service) if obj: obj[0].ask_regen() return + class Service_link(models.Model): """ Definition du lien entre serveurs et services""" service = models.ForeignKey('Service', on_delete=models.CASCADE) @@ -477,11 +595,16 @@ class Service_link(models.Model): self.save() def need_regen(self): - """ Décide si le temps minimal écoulé est suffisant pour provoquer une régénération de service""" - if (self.asked_regen and (self.last_regen + self.service.min_time_regen) < timezone.now()) or (self.last_regen + self.service.regular_time_regen) < timezone.now(): - return True - else: - return False + """ Décide si le temps minimal écoulé est suffisant pour provoquer une + régénération de service""" + return bool( + (self.asked_regen and ( + self.last_regen + self.service.min_time_regen + ) < timezone.now() + ) or ( + self.last_regen + self.service.regular_time_regen + ) < timezone.now() + ) def __str__(self): return str(self.server) + " " + str(self.service) @@ -489,29 +612,48 @@ class Service_link(models.Model): class OuverturePortList(models.Model): """Liste des ports ouverts sur une interface.""" - name = models.CharField(help_text="Nom de la configuration des ports.", max_length=255) + name = models.CharField( + help_text="Nom de la configuration des ports.", + max_length=255 + ) def __str__(self): return self.name def tcp_ports_in(self): - return self.ouvertureport_set.filter(protocole=OuverturePort.TCP, io=OuverturePort.IN) - + """Renvoie la liste des ports ouverts en TCP IN pour ce profil""" + return self.ouvertureport_set.filter( + protocole=OuverturePort.TCP, + io=OuverturePort.IN + ) + def udp_ports_in(self): - return self.ouvertureport_set.filter(protocole=OuverturePort.UDP, io=OuverturePort.IN) + """Renvoie la liste des ports ouverts en UDP IN pour ce profil""" + return self.ouvertureport_set.filter( + protocole=OuverturePort.UDP, + io=OuverturePort.IN + ) def tcp_ports_out(self): - return self.ouvertureport_set.filter(protocole=OuverturePort.TCP, io=OuverturePort.OUT) - + """Renvoie la liste des ports ouverts en TCP OUT pour ce profil""" + return self.ouvertureport_set.filter( + protocole=OuverturePort.TCP, + io=OuverturePort.OUT + ) + def udp_ports_out(self): - return self.ouvertureport_set.filter(protocole=OuverturePort.UDP, io=OuverturePort.OUT) + """Renvoie la liste des ports ouverts en UDP OUT pour ce profil""" + return self.ouvertureport_set.filter( + protocole=OuverturePort.UDP, + io=OuverturePort.OUT + ) class OuverturePort(models.Model): """ Représente un simple port ou une plage de ports. - - Les ports de la plage sont compris entre begin et en inclus. + + Les ports de la plage sont compris entre begin et en inclus. Si begin == end alors on ne représente qu'un seul port. On limite les ports entre 0 et 65535, tels que défini par la RFC @@ -522,112 +664,150 @@ class OuverturePort(models.Model): OUT = 'O' begin = models.PositiveIntegerField(validators=[MaxValueValidator(65535)]) end = models.PositiveIntegerField(validators=[MaxValueValidator(65535)]) - port_list = models.ForeignKey('OuverturePortList', on_delete=models.CASCADE) + port_list = models.ForeignKey( + 'OuverturePortList', + on_delete=models.CASCADE + ) protocole = models.CharField( - max_length=1, - choices=( - (TCP, 'TCP'), - (UDP, 'UDP'), - ), - default=TCP, + max_length=1, + choices=( + (TCP, 'TCP'), + (UDP, 'UDP'), + ), + default=TCP, ) io = models.CharField( - max_length=1, - choices=( - (IN, 'IN'), - (OUT, 'OUT'), - ), - default=OUT, + max_length=1, + choices=( + (IN, 'IN'), + (OUT, 'OUT'), + ), + default=OUT, ) def __str__(self): - if self.begin == self.end : + if self.begin == self.end: return str(self.begin) return '-'.join([str(self.begin), str(self.end)]) def show_port(self): + """Formatage plus joli, alias pour str""" return str(self) @receiver(post_save, sender=Machine) def machine_post_save(sender, **kwargs): + """Synchronisation ldap et régen parefeu/dhcp lors de la modification + d'une machine""" user = kwargs['instance'].user user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) regen('dhcp') regen('mac_ip_list') + @receiver(post_delete, sender=Machine) def machine_post_delete(sender, **kwargs): + """Synchronisation ldap et régen parefeu/dhcp lors de la suppression + d'une machine""" machine = kwargs['instance'] user = machine.user user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) regen('dhcp') regen('mac_ip_list') + @receiver(post_save, sender=Interface) def interface_post_save(sender, **kwargs): + """Synchronisation ldap et régen parefeu/dhcp lors de la modification + d'une interface""" interface = kwargs['instance'] user = interface.machine.user user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) - if not interface.may_have_port_open() and interface.port_lists.all(): - interface.port_lists.clear() # Regen services regen('dhcp') regen('mac_ip_list') + @receiver(post_delete, sender=Interface) def interface_post_delete(sender, **kwargs): + """Synchronisation ldap et régen parefeu/dhcp lors de la suppression + d'une interface""" interface = kwargs['instance'] user = interface.machine.user user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) + @receiver(post_save, sender=IpType) def iptype_post_save(sender, **kwargs): + """Generation des objets ip après modification d'un range ip""" iptype = kwargs['instance'] iptype.gen_ip_range() + @receiver(post_save, sender=MachineType) def machine_post_save(sender, **kwargs): + """Mise à jour des interfaces lorsque changement d'attribution + d'une machinetype (changement iptype parent)""" machinetype = kwargs['instance'] for interface in machinetype.all_interfaces(): interface.update_type() + @receiver(post_save, sender=Domain) def domain_post_save(sender, **kwargs): + """Regeneration dns après modification d'un domain object""" regen('dns') + @receiver(post_delete, sender=Domain) def domain_post_delete(sender, **kwargs): + """Regeneration dns après suppression d'un domain object""" regen('dns') + @receiver(post_save, sender=Extension) def extension_post_save(sender, **kwargs): + """Regeneration dns après modification d'une extension""" regen('dns') + @receiver(post_delete, sender=Extension) def extension_post_selete(sender, **kwargs): + """Regeneration dns après suppression d'une extension""" regen('dns') + @receiver(post_save, sender=Mx) def mx_post_save(sender, **kwargs): + """Regeneration dns après modification d'un MX""" regen('dns') + @receiver(post_delete, sender=Mx) def mx_post_delete(sender, **kwargs): + """Regeneration dns après suppresson d'un MX""" regen('dns') + @receiver(post_save, sender=Ns) def ns_post_save(sender, **kwargs): + """Regeneration dns après modification d'un NS""" regen('dns') + @receiver(post_delete, sender=Ns) def ns_post_delete(sender, **kwargs): + """Regeneration dns après modification d'un NS""" regen('dns') + @receiver(post_save, sender=Text) def text_post_save(sender, **kwargs): + """Regeneration dns après modification d'un TXT""" regen('dns') + @receiver(post_delete, sender=Text) def text_post_delete(sender, **kwargs): + """Regeneration dns après modification d'un TX""" regen('dns') From fccda699a958f43ca938837b66a94535beec8fa9 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Mon, 16 Oct 2017 02:41:21 +0200 Subject: [PATCH 16/27] Doc --- machines/admin.py | 16 +++ machines/forms.py | 267 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 232 insertions(+), 51 deletions(-) diff --git a/machines/admin.py b/machines/admin.py index 49b02a7e..e0256fe0 100644 --- a/machines/admin.py +++ b/machines/admin.py @@ -30,51 +30,67 @@ from .models import IpType, Machine, MachineType, Domain, IpList, Interface from .models import Extension, Mx, Ns, Vlan, Text, Nas, Service, OuverturePort from .models import OuverturePortList + class MachineAdmin(VersionAdmin): pass + class IpTypeAdmin(VersionAdmin): pass + class MachineTypeAdmin(VersionAdmin): pass + class VlanAdmin(VersionAdmin): pass + class ExtensionAdmin(VersionAdmin): pass + class MxAdmin(VersionAdmin): pass + class NsAdmin(VersionAdmin): pass + class TextAdmin(VersionAdmin): pass + class NasAdmin(VersionAdmin): pass + class IpListAdmin(VersionAdmin): pass + class OuverturePortAdmin(VersionAdmin): pass + class OuverturePortListAdmin(VersionAdmin): pass + class InterfaceAdmin(VersionAdmin): list_display = ('machine','type','mac_address','ipv4','details') + class DomainAdmin(VersionAdmin): list_display = ('interface_parent', 'name', 'extension', 'cname') + class ServiceAdmin(VersionAdmin): list_display = ('service_type', 'min_time_regen', 'regular_time_regen') + admin.site.register(Machine, MachineAdmin) admin.site.register(MachineType, MachineTypeAdmin) admin.site.register(IpType, IpTypeAdmin) diff --git a/machines/forms.py b/machines/forms.py index eb16e2c9..9820fbdc 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -21,20 +21,43 @@ # 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. +""" +Formulaires d'ajout, edition et suppressions de : + - machines + - interfaces + - domain (noms de machine) + - alias (cname) + - service (dhcp, dns..) + - ns (serveur dns) + - mx (serveur mail) + - ports ouverts et profils d'ouverture par interface +""" from __future__ import unicode_literals -import re - -from django.forms import ModelForm, Form, ValidationError +from django.forms import ModelForm, Form from django import forms -from .models import Domain, Machine, Interface, IpList, MachineType, Extension, Mx, Text, Ns, Service, Vlan, Nas, IpType, OuverturePortList, OuverturePort -from django.db.models import Q -from django.core.validators import validate_email -from users.models import User +from .models import ( + Domain, + Machine, + Interface, + IpList, + MachineType, + Extension, + Mx, + Text, + Ns, + Service, + Vlan, + Nas, + IpType, + OuverturePortList, +) + class EditMachineForm(ModelForm): + """Formulaire d'édition d'une machine""" class Meta: model = Machine fields = '__all__' @@ -44,15 +67,22 @@ class EditMachineForm(ModelForm): super(EditMachineForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields['name'].label = 'Nom de la machine' + class NewMachineForm(EditMachineForm): + """Creation d'une machine, ne renseigne que le nom""" class Meta(EditMachineForm.Meta): fields = ['name'] + class BaseEditMachineForm(EditMachineForm): + """Edition basique, ne permet que de changer le nom et le statut. + Réservé aux users sans droits spécifiques""" class Meta(EditMachineForm.Meta): - fields = ['name','active'] + fields = ['name', 'active'] + class EditInterfaceForm(ModelForm): + """Edition d'une interface. Edition complète""" class Meta: model = Interface fields = ['machine', 'type', 'ipv4', 'mac_address', 'details'] @@ -64,85 +94,126 @@ class EditInterfaceForm(ModelForm): self.fields['type'].label = 'Type de machine' self.fields['type'].empty_label = "Séléctionner un type de machine" if "ipv4" in self.fields: - self.fields['ipv4'].empty_label = "Assignation automatique de l'ipv4" - self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True) + self.fields['ipv4'].empty_label = "Assignation automatique\ + de l'ipv4" + 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) + 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') + self.fields['machine'].queryset = Machine.objects.all()\ + .select_related('user') + class AddInterfaceForm(EditInterfaceForm): + """Ajout d'une interface à une machine. En fonction des droits, + affiche ou non l'ensemble des ip disponibles""" class Meta(EditInterfaceForm.Meta): - fields = ['type','ipv4','mac_address','details'] + fields = ['type', 'ipv4', 'mac_address', 'details'] def __init__(self, *args, **kwargs): infra = kwargs.pop('infra') super(AddInterfaceForm, self).__init__(*args, **kwargs) self.fields['ipv4'].empty_label = "Assignation automatique de l'ipv4" if not infra: - self.fields['type'].queryset = MachineType.objects.filter(ip_type__in=IpType.objects.filter(need_infra=False)) - self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True).filter(ip_type__in=IpType.objects.filter(need_infra=False)) + self.fields['type'].queryset = MachineType.objects.filter( + ip_type__in=IpType.objects.filter(need_infra=False) + ) + 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) + self.fields['ipv4'].queryset = IpList.objects.filter( + interface__isnull=True + ) + class NewInterfaceForm(EditInterfaceForm): + """Formulaire light, sans choix de l'ipv4; d'ajout d'une interface""" class Meta(EditInterfaceForm.Meta): - fields = ['type','mac_address','details'] + fields = ['type', 'mac_address', 'details'] + class BaseEditInterfaceForm(EditInterfaceForm): + """Edition basique d'une interface. En fonction des droits, + ajoute ou non l'ensemble des ipv4 disponibles (infra)""" class Meta(EditInterfaceForm.Meta): - fields = ['type','ipv4','mac_address','details'] + fields = ['type', 'ipv4', 'mac_address', 'details'] def __init__(self, *args, **kwargs): infra = kwargs.pop('infra') super(BaseEditInterfaceForm, self).__init__(*args, **kwargs) self.fields['ipv4'].empty_label = "Assignation automatique de l'ipv4" if not infra: - self.fields['type'].queryset = MachineType.objects.filter(ip_type__in=IpType.objects.filter(need_infra=False)) - self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True).filter(ip_type__in=IpType.objects.filter(need_infra=False)) + self.fields['type'].queryset = MachineType.objects.filter( + ip_type__in=IpType.objects.filter(need_infra=False) + ) + self.fields['ipv4'].queryset = IpList.objects.filter( + interface__isnull=True + ).filter(ip_type__in=IpType.objects.filter(need_infra=False)) # Add it's own address - self.fields['ipv4'].queryset |= IpList.objects.filter(interface=self.instance) + self.fields['ipv4'].queryset |= IpList.objects.filter( + interface=self.instance + ) else: - self.fields['ipv4'].queryset = IpList.objects.filter(interface__isnull=True) - self.fields['ipv4'].queryset |= IpList.objects.filter(interface=self.instance) + self.fields['ipv4'].queryset = IpList.objects.filter( + interface__isnull=True + ) + self.fields['ipv4'].queryset |= IpList.objects.filter( + interface=self.instance + ) + class AliasForm(ModelForm): + """Ajout d'un alias (et edition), CNAME, contenant nom et extension""" class Meta: model = Domain - fields = ['name','extension'] + fields = ['name', 'extension'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) - if 'infra' in kwargs: - infra = kwargs.pop('infra') super(AliasForm, self).__init__(*args, prefix=prefix, **kwargs) + class DomainForm(AliasForm): + """Ajout et edition d'un enregistrement de nom, relié à interface""" class Meta(AliasForm.Meta): fields = ['name'] def __init__(self, *args, **kwargs): if 'user' in kwargs: user = kwargs.pop('user') - nb_machine = kwargs.pop('nb_machine') initial = kwargs.get('initial', {}) initial['name'] = user.get_next_domain_name() - kwargs['initial'] = initial + kwargs['initial'] = initial prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(DomainForm, self).__init__(*args, prefix=prefix, **kwargs) - + + class DelAliasForm(Form): - alias = forms.ModelMultipleChoiceField(queryset=Domain.objects.all(), label="Alias actuels", widget=forms.CheckboxSelectMultiple) + """Suppression d'un ou plusieurs objets alias""" + alias = forms.ModelMultipleChoiceField( + queryset=Domain.objects.all(), + label="Alias actuels", + 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)) + self.fields['alias'].queryset = Domain.objects.filter( + cname__in=Domain.objects.filter(interface_parent=interface) + ) + class MachineTypeForm(ModelForm): + """Ajout et edition d'un machinetype, relié à un iptype""" class Meta: model = MachineType - fields = ['type','ip_type'] + fields = ['type', 'ip_type'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) @@ -150,27 +221,49 @@ class MachineTypeForm(ModelForm): self.fields['type'].label = 'Type de machine à ajouter' self.fields['ip_type'].label = "Type d'ip relié" + class DelMachineTypeForm(Form): - machinetypes = forms.ModelMultipleChoiceField(queryset=MachineType.objects.all(), label="Types de machines actuelles", widget=forms.CheckboxSelectMultiple) + """Suppression d'un ou plusieurs machinetype""" + machinetypes = forms.ModelMultipleChoiceField( + queryset=MachineType.objects.all(), + label="Types de machines actuelles", + widget=forms.CheckboxSelectMultiple + ) + class IpTypeForm(ModelForm): + """Formulaire d'ajout d'un iptype. Pas d'edition de l'ip de start et de + stop après creation""" class Meta: model = IpType - fields = ['type','extension','need_infra','domaine_ip_start','domaine_ip_stop', 'prefix_v6', 'vlan', 'ouverture_ports'] - + fields = ['type', 'extension', 'need_infra', 'domaine_ip_start', + 'domaine_ip_stop', 'prefix_v6', 'vlan', 'ouverture_ports'] + def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(IpTypeForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields['type'].label = 'Type ip à ajouter' + class EditIpTypeForm(IpTypeForm): + """Edition d'un iptype. Pas d'edition du rangev4 possible, car il faudrait + synchroniser les objets iplist""" class Meta(IpTypeForm.Meta): - fields = ['extension','type','need_infra', 'prefix_v6', 'vlan', 'ouverture_ports'] + fields = ['extension', 'type', 'need_infra', 'prefix_v6', 'vlan', + 'ouverture_ports'] + class DelIpTypeForm(Form): - iptypes = forms.ModelMultipleChoiceField(queryset=IpType.objects.all(), label="Types d'ip actuelles", widget=forms.CheckboxSelectMultiple) + """Suppression d'un ou plusieurs iptype""" + iptypes = forms.ModelMultipleChoiceField( + queryset=IpType.objects.all(), + label="Types d'ip actuelles", + widget=forms.CheckboxSelectMultiple + ) + class ExtensionForm(ModelForm): + """Formulaire d'ajout et edition d'une extension""" class Meta: model = Extension fields = ['name', 'need_infra', 'origin'] @@ -181,23 +274,41 @@ class ExtensionForm(ModelForm): self.fields['name'].label = 'Extension à ajouter' self.fields['origin'].label = 'Enregistrement A origin' + class DelExtensionForm(Form): - extensions = forms.ModelMultipleChoiceField(queryset=Extension.objects.all(), label="Extensions actuelles", widget=forms.CheckboxSelectMultiple) + """Suppression d'une ou plusieurs extensions""" + extensions = forms.ModelMultipleChoiceField( + queryset=Extension.objects.all(), + label="Extensions actuelles", + widget=forms.CheckboxSelectMultiple + ) + class MxForm(ModelForm): + """Ajout et edition d'un MX""" class Meta: model = Mx fields = ['zone', 'priority', 'name'] - + 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) - + self.fields['name'].queryset = Domain.objects.exclude( + interface_parent=None + ) + + class DelMxForm(Form): - mx = forms.ModelMultipleChoiceField(queryset=Mx.objects.all(), label="MX actuels", widget=forms.CheckboxSelectMultiple) + """Suppression d'un ou plusieurs MX""" + mx = forms.ModelMultipleChoiceField( + queryset=Mx.objects.all(), + label="MX actuels", + widget=forms.CheckboxSelectMultiple + ) + class NsForm(ModelForm): + """Ajout d'un NS pour une zone""" class Meta: model = Ns fields = ['zone', 'ns'] @@ -205,12 +316,22 @@ class NsForm(ModelForm): 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) + self.fields['ns'].queryset = Domain.objects.exclude( + interface_parent=None + ) + class DelNsForm(Form): - ns = forms.ModelMultipleChoiceField(queryset=Ns.objects.all(), label="Enregistrements NS actuels", widget=forms.CheckboxSelectMultiple) + """Suppresion d'un ou plusieurs NS""" + ns = forms.ModelMultipleChoiceField( + queryset=Ns.objects.all(), + label="Enregistrements NS actuels", + widget=forms.CheckboxSelectMultiple + ) + class TxtForm(ModelForm): + """Ajout d'un txt pour une zone""" class Meta: model = Text fields = '__all__' @@ -219,10 +340,19 @@ class TxtForm(ModelForm): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(TxtForm, self).__init__(*args, prefix=prefix, **kwargs) + class DelTxtForm(Form): - txt = forms.ModelMultipleChoiceField(queryset=Text.objects.all(), label="Enregistrements Txt actuels", widget=forms.CheckboxSelectMultiple) + """Suppression d'un ou plusieurs TXT""" + txt = forms.ModelMultipleChoiceField( + queryset=Text.objects.all(), + label="Enregistrements Txt actuels", + widget=forms.CheckboxSelectMultiple + ) + class NasForm(ModelForm): + """Ajout d'un type de nas (machine d'authentification, + swicths, bornes...)""" class Meta: model = Nas fields = '__all__' @@ -231,10 +361,18 @@ class NasForm(ModelForm): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(NasForm, self).__init__(*args, prefix=prefix, **kwargs) + class DelNasForm(Form): - nas = forms.ModelMultipleChoiceField(queryset=Nas.objects.all(), label="Enregistrements Nas actuels", widget=forms.CheckboxSelectMultiple) + """Suppression d'un ou plusieurs nas""" + nas = forms.ModelMultipleChoiceField( + queryset=Nas.objects.all(), + label="Enregistrements Nas actuels", + widget=forms.CheckboxSelectMultiple + ) + class ServiceForm(ModelForm): + """Ajout et edition d'une classe de service : dns, dhcp, etc""" class Meta: model = Service fields = '__all__' @@ -250,10 +388,18 @@ class ServiceForm(ModelForm): instance.process_link(self.cleaned_data.get('servers')) return instance + class DelServiceForm(Form): - service = forms.ModelMultipleChoiceField(queryset=Service.objects.all(), label="Services actuels", widget=forms.CheckboxSelectMultiple) + """Suppression d'un ou plusieurs service""" + service = forms.ModelMultipleChoiceField( + queryset=Service.objects.all(), + label="Services actuels", + widget=forms.CheckboxSelectMultiple + ) + class VlanForm(ModelForm): + """Ajout d'un vlan : id, nom""" class Meta: model = Vlan fields = '__all__' @@ -262,24 +408,43 @@ class VlanForm(ModelForm): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(VlanForm, self).__init__(*args, prefix=prefix, **kwargs) + class DelVlanForm(Form): - vlan = forms.ModelMultipleChoiceField(queryset=Vlan.objects.all(), label="Vlan actuels", widget=forms.CheckboxSelectMultiple) + """Suppression d'un ou plusieurs vlans""" + vlan = forms.ModelMultipleChoiceField( + queryset=Vlan.objects.all(), + label="Vlan actuels", + widget=forms.CheckboxSelectMultiple + ) + class EditOuverturePortConfigForm(ModelForm): + """Edition de la liste des profils d'ouverture de ports + pour l'interface""" class Meta: model = Interface fields = ['port_lists'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditOuverturePortConfigForm, self).__init__(*args, prefix=prefix, **kwargs) + super(EditOuverturePortConfigForm, self).__init__( + *args, + prefix=prefix, + **kwargs + ) + class EditOuverturePortListForm(ModelForm): + """Edition de la liste des ports et profils d'ouverture + des ports""" 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) - + super(EditOuverturePortListForm, self).__init__( + *args, + prefix=prefix, + **kwargs + ) From fb940d1cd38d123bbcd254eb439ea9c8f34ddaf1 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Mon, 16 Oct 2017 03:02:33 +0200 Subject: [PATCH 17/27] Some doc --- machines/serializers.py | 114 +++++++++++++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 25 deletions(-) diff --git a/machines/serializers.py b/machines/serializers.py index b18bbfb0..6e0ca4e3 100644 --- a/machines/serializers.py +++ b/machines/serializers.py @@ -24,20 +24,42 @@ #Augustin Lemesle from rest_framework import serializers -from machines.models import Interface, IpType, Extension, IpList, MachineType, Domain, Text, Mx, Service_link, Ns, OuverturePortList, OuverturePort +from machines.models import ( + Interface, + IpType, + Extension, + IpList, + MachineType, + Domain, + Text, + Mx, + Service_link, + Ns, + OuverturePortList, + OuverturePort +) + class IpTypeField(serializers.RelatedField): + """Serialisation d'une iptype, renvoie son evaluation str""" def to_representation(self, value): return value.type + class IpListSerializer(serializers.ModelSerializer): + """Serialisation d'une iplist, ip_type etant une foreign_key, + on evalue sa methode str""" ip_type = IpTypeField(read_only=True) class Meta: model = IpList fields = ('ipv4', 'ip_type') + class InterfaceSerializer(serializers.ModelSerializer): + """Serialisation d'une interface, ipv4, domain et extension sont + des foreign_key, on les override et on les evalue avec des fonctions + get_...""" ipv4 = IpListSerializer(read_only=True) mac_address = serializers.SerializerMethodField('get_macaddress') domain = serializers.SerializerMethodField('get_dns') @@ -56,7 +78,9 @@ class InterfaceSerializer(serializers.ModelSerializer): def get_macaddress(self, obj): return str(obj.mac_address) + class FullInterfaceSerializer(serializers.ModelSerializer): + """Serialisation complete d'une interface avec l'ipv6 en plus""" ipv4 = IpListSerializer(read_only=True) mac_address = serializers.SerializerMethodField('get_macaddress') domain = serializers.SerializerMethodField('get_dns') @@ -75,39 +99,63 @@ class FullInterfaceSerializer(serializers.ModelSerializer): def get_macaddress(self, obj): return str(obj.mac_address) + class ExtensionNameField(serializers.RelatedField): + """Evaluation str d'un objet extension (.example.org)""" def to_representation(self, value): return value.name + class TypeSerializer(serializers.ModelSerializer): + """Serialisation d'un iptype : extension et la liste des + ouvertures de port son evalués en get_... etant des + foreign_key ou des relations manytomany""" extension = ExtensionNameField(read_only=True) - ouverture_ports_tcp_in = serializers.SerializerMethodField('get_port_policy_input_tcp') - ouverture_ports_tcp_out = serializers.SerializerMethodField('get_port_policy_output_tcp') - ouverture_ports_udp_in = serializers.SerializerMethodField('get_port_policy_input_udp') - ouverture_ports_udp_out = serializers.SerializerMethodField('get_port_policy_output_udp') + ouverture_ports_tcp_in = serializers\ + .SerializerMethodField('get_port_policy_input_tcp') + ouverture_ports_tcp_out = serializers\ + .SerializerMethodField('get_port_policy_output_tcp') + ouverture_ports_udp_in = serializers\ + .SerializerMethodField('get_port_policy_input_udp') + ouverture_ports_udp_out = serializers\ + .SerializerMethodField('get_port_policy_output_udp') class Meta: model = IpType - fields = ('type', 'extension', 'domaine_ip_start', 'domaine_ip_stop', 'ouverture_ports_tcp_in', 'ouverture_ports_tcp_out', 'ouverture_ports_udp_in', 'ouverture_ports_udp_out', ) + fields = ('type', 'extension', 'domaine_ip_start', 'domaine_ip_stop', + 'ouverture_ports_tcp_in', 'ouverture_ports_tcp_out', + 'ouverture_ports_udp_in', 'ouverture_ports_udp_out',) def get_port_policy(self, obj, protocole, io): if obj.ouverture_ports is None: return [] - return map(str, obj.ouverture_ports.ouvertureport_set.filter(protocole=protocole).filter(io=io)) + return map( + str, + obj.ouverture_ports.ouvertureport_set.filter( + protocole=protocole + ).filter(io=io) + ) def get_port_policy_input_tcp(self, obj): + """Renvoie la liste des ports ouverts en entrée tcp""" return self.get_port_policy(obj, OuverturePort.TCP, OuverturePort.IN) def get_port_policy_output_tcp(self, obj): + """Renvoie la liste des ports ouverts en sortie tcp""" return self.get_port_policy(obj, OuverturePort.TCP, OuverturePort.OUT) def get_port_policy_input_udp(self, obj): + """Renvoie la liste des ports ouverts en entrée udp""" return self.get_port_policy(obj, OuverturePort.UDP, OuverturePort.IN) def get_port_policy_output_udp(self, obj): + """Renvoie la liste des ports ouverts en sortie udp""" return self.get_port_policy(obj, OuverturePort.UDP, OuverturePort.OUT) + class ExtensionSerializer(serializers.ModelSerializer): + """Serialisation d'une extension : origin_ip et la zone sont + des foreign_key donc evalués en get_...""" origin = serializers.SerializerMethodField('get_origin_ip') zone_entry = serializers.SerializerMethodField('get_zone_name') @@ -121,7 +169,10 @@ class ExtensionSerializer(serializers.ModelSerializer): def get_zone_name(self, obj): return str(obj.dns_entry) + class MxSerializer(serializers.ModelSerializer): + """Serialisation d'un MX, evaluation du nom, de la zone + et du serveur cible, etant des foreign_key""" name = serializers.SerializerMethodField('get_entry_name') zone = serializers.SerializerMethodField('get_zone_name') mx_entry = serializers.SerializerMethodField('get_mx_name') @@ -139,13 +190,16 @@ class MxSerializer(serializers.ModelSerializer): def get_mx_name(self, obj): return str(obj.dns_entry) + class TextSerializer(serializers.ModelSerializer): + """Serialisation d'un txt : zone cible et l'entrée txt + sont evaluées à part""" zone = serializers.SerializerMethodField('get_zone_name') text_entry = serializers.SerializerMethodField('get_text_name') class Meta: model = Text - fields = ('zone','text_entry','field1', 'field2') + fields = ('zone', 'text_entry', 'field1', 'field2') def get_zone_name(self, obj): return str(obj.zone.name) @@ -153,10 +207,13 @@ class TextSerializer(serializers.ModelSerializer): def get_text_name(self, obj): return str(obj.dns_entry) + class NsSerializer(serializers.ModelSerializer): + """Serialisation d'un NS : la zone, l'entrée ns complète et le serveur + ns sont évalués à part""" zone = serializers.SerializerMethodField('get_zone_name') ns = serializers.SerializerMethodField('get_domain_name') - ns_entry = serializers.SerializerMethodField('get_text_name') + ns_entry = serializers.SerializerMethodField('get_text_name') class Meta: model = Ns @@ -171,10 +228,13 @@ class NsSerializer(serializers.ModelSerializer): def get_text_name(self, obj): return str(obj.dns_entry) + class DomainSerializer(serializers.ModelSerializer): + """Serialisation d'un domain, extension, cname sont des foreign_key, + et l'entrée complète, sont évalués à part""" extension = serializers.SerializerMethodField('get_zone_name') cname = serializers.SerializerMethodField('get_alias_name') - cname_entry = serializers.SerializerMethodField('get_cname_name') + cname_entry = serializers.SerializerMethodField('get_cname_name') class Meta: model = Domain @@ -189,7 +249,9 @@ class DomainSerializer(serializers.ModelSerializer): def get_cname_name(self, obj): return str(obj.dns_entry) + class ServiceServersSerializer(serializers.ModelSerializer): + """Evaluation d'un Service, et serialisation""" server = serializers.SerializerMethodField('get_server_name') service = serializers.SerializerMethodField('get_service_name') need_regen = serializers.SerializerMethodField('get_regen_status') @@ -207,28 +269,30 @@ class ServiceServersSerializer(serializers.ModelSerializer): def get_regen_status(self, obj): return obj.need_regen() + class OuverturePortsSerializer(serializers.Serializer): + """Serialisation de l'ouverture des ports""" ipv4 = serializers.SerializerMethodField() ipv6 = serializers.SerializerMethodField() def get_ipv4(): return {i.ipv4.ipv4: - { - "tcp_in":[j.tcp_ports_in() for j in i.port_lists.all()], - "tcp_out":[j.tcp_ports_out()for j in i.port_lists.all()], - "udp_in":[j.udp_ports_in() for j in i.port_lists.all()], - "udp_out":[j.udp_ports_out() for j in i.port_lists.all()], - } - for i in Interface.objects.all() if i.ipv4 + { + "tcp_in":[j.tcp_ports_in() for j in i.port_lists.all()], + "tcp_out":[j.tcp_ports_out()for j in i.port_lists.all()], + "udp_in":[j.udp_ports_in() for j in i.port_lists.all()], + "udp_out":[j.udp_ports_out() for j in i.port_lists.all()], + } + for i in Interface.objects.all() if i.ipv4 } - + def get_ipv6(): return {i.ipv6: - { - "tcp_in":[j.tcp_ports_in() for j in i.port_lists.all()], - "tcp_out":[j.tcp_ports_out()for j in i.port_lists.all()], - "udp_in":[j.udp_ports_in() for j in i.port_lists.all()], - "udp_out":[j.udp_ports_out() for j in i.port_lists.all()], - } - for i in Interface.objects.all() if i.ipv6 + { + "tcp_in":[j.tcp_ports_in() for j in i.port_lists.all()], + "tcp_out":[j.tcp_ports_out()for j in i.port_lists.all()], + "udp_in":[j.udp_ports_in() for j in i.port_lists.all()], + "udp_out":[j.udp_ports_out() for j in i.port_lists.all()], + } + for i in Interface.objects.all() if i.ipv6 } From a181ad341994a59c9e17413af9643ca2717c7f0b Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Tue, 17 Oct 2017 20:10:51 +0200 Subject: [PATCH 18/27] Fix #16 . --- topologie/templates/topologie/aff_switch.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/topologie/templates/topologie/aff_switch.html b/topologie/templates/topologie/aff_switch.html index 7096909b..bb5b274b 100644 --- a/topologie/templates/topologie/aff_switch.html +++ b/topologie/templates/topologie/aff_switch.html @@ -52,6 +52,8 @@ with this program; if not, write to the Free Software Foundation, Inc., + {% include 'buttons/edit.html' with href='topologie:edit-switch' id=switch.pk %} + {% endfor %} From 6e26d73e7dd248e2a608c6857d422a48e670c149 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Tue, 17 Oct 2017 20:20:29 +0200 Subject: [PATCH 19/27] Ajout d'un bouton pour supprimer un switch. --- topologie/templates/topologie/aff_switch.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/topologie/templates/topologie/aff_switch.html b/topologie/templates/topologie/aff_switch.html index bb5b274b..611e6c39 100644 --- a/topologie/templates/topologie/aff_switch.html +++ b/topologie/templates/topologie/aff_switch.html @@ -51,8 +51,9 @@ with this program; if not, write to the Free Software Foundation, Inc., - - {% include 'buttons/edit.html' with href='topologie:edit-switch' id=switch.pk %} + + {% include 'buttons/edit.html' with href='topologie:edit-switch' id=switch.pk %} + {% include 'buttons/suppr.html' with href='machines:del-interface' id=switch.switch_interface.id %} From f554efda8742e20a680607557a684fb5cec3dfb8 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 18 Oct 2017 02:27:42 +0200 Subject: [PATCH 20/27] Fix bugs sur infra et nb_machines --- machines/views.py | 3 +-- topologie/models.py | 6 +++++- topologie/views.py | 8 +++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/machines/views.py b/machines/views.py index 48adf44b..41cea7b9 100644 --- a/machines/views.py +++ b/machines/views.py @@ -223,8 +223,7 @@ def new_machine(request, userid): return redirect("/users/profil/" + str(request.user.id)) machine = NewMachineForm(request.POST or None) interface = AddInterfaceForm(request.POST or None, infra=request.user.has_perms(('infra',))) - nb_machine = Interface.objects.filter(machine__user=userid).count() - domain = DomainForm(request.POST or None, user=user, nb_machine=nb_machine) + domain = DomainForm(request.POST or None, user=user) if machine.is_valid() and interface.is_valid(): new_machine = machine.save(commit=False) new_machine.user = user diff --git a/topologie/models.py b/topologie/models.py index 66c8fe94..adcc7a57 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -145,7 +145,11 @@ class Port(models.Model): ('COMMON', 'COMMON'), ) - switch = models.ForeignKey('Switch', related_name="ports") + switch = models.ForeignKey( + 'Switch', + related_name="ports", + on_delete=models.CASCADE + ) port = models.PositiveIntegerField() room = models.ForeignKey( 'Room', diff --git a/topologie/views.py b/topologie/views.py index f1e8740c..686685e9 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -50,7 +50,7 @@ from topologie.forms import EditPortForm, NewSwitchForm, EditSwitchForm from topologie.forms import AddPortForm, EditRoomForm, StackForm from users.views import form -from machines.forms import AliasForm, NewMachineForm, EditMachineForm, EditInterfaceForm, AddInterfaceForm +from machines.forms import DomainForm, NewMachineForm, EditMachineForm, EditInterfaceForm, AddInterfaceForm from machines.views import generate_ipv4_mbf_param from preferences.models import AssoOption, GeneralOption @@ -344,9 +344,8 @@ def new_switch(request): request.POST or None, infra=request.user.has_perms(('infra',)) ) - domain = AliasForm( + domain = DomainForm( request.POST or None, - infra=request.user.has_perms(('infra',)) ) if switch.is_valid() and machine.is_valid() and interface.is_valid(): options, _created = AssoOption.objects.get_or_create() @@ -410,9 +409,8 @@ def edit_switch(request, switch_id): request.POST or None, instance=switch.switch_interface ) - domain_form = AliasForm( + domain_form = DomainForm( request.POST or None, - infra=request.user.has_perms(('infra',)), instance=switch.switch_interface.domain ) if switch_form.is_valid() and machine_form.is_valid()\ From ac0a76272d2de9c89e430093201c762e80924bc1 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 18 Oct 2017 02:58:17 +0200 Subject: [PATCH 21/27] =?UTF-8?q?Opti=20les=20requ=C3=A8tes=20sur=20charge?= =?UTF-8?q?ment=20de=20l'edition=20d'un=20switch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- topologie/forms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/topologie/forms.py b/topologie/forms.py index 267d64b0..5f5993a4 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -105,6 +105,8 @@ class EditSwitchForm(ModelForm): def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(EditSwitchForm, self).__init__(*args, prefix=prefix, **kwargs) + self.fields['switch_interface'].queryset = Interface.objects.all()\ + .select_related('domain__extension') self.fields['location'].label = 'Localisation' self.fields['number'].label = 'Nombre de ports' From ae42a06d1c2f310989633b17be25703a66c42d1e Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 18 Oct 2017 03:09:47 +0200 Subject: [PATCH 22/27] Opti l'ajout de port --- topologie/forms.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/topologie/forms.py b/topologie/forms.py index 5f5993a4..c8e39d6a 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -82,6 +82,11 @@ class AddPortForm(ModelForm): def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(AddPortForm, self).__init__(*args, prefix=prefix, **kwargs) + self.fields['machine_interface'].queryset = Interface.objects.all()\ + .select_related('domain__extension') + self.fields['related'].queryset = Port.objects.all()\ + .select_related('switch__switch_interface__domain__extension')\ + .order_by('switch', 'port') class StackForm(ModelForm): From ff22704262a35b8f48c48f7f42a2520808cf0511 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 18 Oct 2017 03:50:33 +0200 Subject: [PATCH 23/27] Fix bug sur infra + optimisation avec selec_related sur le chargement pages --- cotisations/urls.py | 8 ++++---- cotisations/views.py | 10 +++++----- machines/views.py | 2 +- .../migrations/0021_auto_20171015_1741.py | 20 +++++++++++++++++++ .../migrations/0022_auto_20171015_1758.py | 20 +++++++++++++++++++ .../migrations/0023_auto_20171015_2033.py | 20 +++++++++++++++++++ preferences/urls.py | 2 +- topologie/urls.py | 8 ++++---- topologie/views.py | 3 ++- users/forms.py | 5 +++-- users/urls.py | 12 +++++------ 11 files changed, 86 insertions(+), 24 deletions(-) create mode 100644 preferences/migrations/0021_auto_20171015_1741.py create mode 100644 preferences/migrations/0022_auto_20171015_1758.py create mode 100644 preferences/migrations/0023_auto_20171015_2033.py diff --git a/cotisations/urls.py b/cotisations/urls.py index f59fd678..d3e56f36 100644 --- a/cotisations/urls.py +++ b/cotisations/urls.py @@ -99,18 +99,18 @@ urlpatterns = [ views.index_paiement, name='index-paiement' ), - url(r'^history/(?Pfacture)/(?P[0-9]+)$', + url(r'^history/(?Pfacture)/(?P[0-9]+)$', views.history, name='history' ), - url(r'^history/(?Particle)/(?P[0-9]+)$', + url(r'^history/(?Particle)/(?P[0-9]+)$', views.history, name='history' ), - url(r'^history/(?Ppaiement)/(?P[0-9]+)$', + url(r'^history/(?Ppaiement)/(?P[0-9]+)$', views.history, name='history'), - url(r'^history/(?Pbanque)/(?P[0-9]+)$', + url(r'^history/(?Pbanque)/(?P[0-9]+)$', views.history, name='history' ), diff --git a/cotisations/views.py b/cotisations/views.py index e44eee65..fc4469aa 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -603,9 +603,9 @@ def index(request): @login_required -def history(request, object, object_id): +def history(request, object_name, object_id): """Affiche l'historique de chaque objet""" - if object == 'facture': + if object_name == 'facture': try: object_instance = Facture.objects.get(pk=object_id) except Facture.DoesNotExist: @@ -616,19 +616,19 @@ def history(request, object, object_id): messages.error(request, "Vous ne pouvez pas afficher l'historique\ d'une facture d'un autre user que vous sans droit cableur") return redirect("/users/profil/" + str(request.user.id)) - elif object == 'paiement' and request.user.has_perms(('cableur',)): + elif object_name == 'paiement' and request.user.has_perms(('cableur',)): try: object_instance = Paiement.objects.get(pk=object_id) except Paiement.DoesNotExist: messages.error(request, "Paiement inexistant") return redirect("/cotisations/") - elif object == 'article' and request.user.has_perms(('cableur',)): + elif object_name == 'article' and request.user.has_perms(('cableur',)): try: object_instance = Article.objects.get(pk=object_id) except Article.DoesNotExist: messages.error(request, "Article inexistante") return redirect("/cotisations/") - elif object == 'banque' and request.user.has_perms(('cableur',)): + elif object_name == 'banque' and request.user.has_perms(('cableur',)): try: object_instance = Banque.objects.get(pk=object_id) except Banque.DoesNotExist: diff --git a/machines/views.py b/machines/views.py index 41cea7b9..dc3e0406 100644 --- a/machines/views.py +++ b/machines/views.py @@ -1056,7 +1056,7 @@ def history(request, object, id): @login_required @permission_required('cableur') def index_portlist(request): - port_list = OuverturePortList.objects.prefetch_related('ouvertureport_set').prefetch_related('interface_set').order_by('name') + port_list = OuverturePortList.objects.prefetch_related('ouvertureport_set').prefetch_related('interface_set__domain__extension').prefetch_related('interface_set__machine__user').order_by('name') return render(request, "machines/index_portlist.html", {'port_list':port_list}) @login_required diff --git a/preferences/migrations/0021_auto_20171015_1741.py b/preferences/migrations/0021_auto_20171015_1741.py new file mode 100644 index 00000000..cc94720a --- /dev/null +++ b/preferences/migrations/0021_auto_20171015_1741.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-15 15:41 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0020_optionalmachine_ipv6'), + ] + + operations = [ + migrations.AlterField( + model_name='optionaltopologie', + name='radius_general_policy', + field=models.CharField(choices=[('MACHINE', 'Sur le vlan de la plage ip machine'), ('DEFINED', 'Prédéfini dans "Vlan où placer les machines après acceptation RADIUS"')], default='DEFINED', max_length=32), + ), + ] diff --git a/preferences/migrations/0022_auto_20171015_1758.py b/preferences/migrations/0022_auto_20171015_1758.py new file mode 100644 index 00000000..ea389a32 --- /dev/null +++ b/preferences/migrations/0022_auto_20171015_1758.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-15 15:58 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0021_auto_20171015_1741'), + ] + + operations = [ + migrations.AlterField( + model_name='optionaltopologie', + name='radius_general_policy', + field=models.CharField(choices=[('MACHINE', 'Sur le vlan de la plage ip machine'), ('DEFINED', 'Prédéfini dans "Vlan où placer les machines après acceptation RADIUS"')], default='DEFINED', max_length=32), + ), + ] diff --git a/preferences/migrations/0023_auto_20171015_2033.py b/preferences/migrations/0023_auto_20171015_2033.py new file mode 100644 index 00000000..3235e49f --- /dev/null +++ b/preferences/migrations/0023_auto_20171015_2033.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-15 18:33 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0022_auto_20171015_1758'), + ] + + operations = [ + migrations.AlterField( + model_name='optionaltopologie', + name='radius_general_policy', + field=models.CharField(choices=[('MACHINE', 'Sur le vlan de la plage ip machine'), ('DEFINED', 'Prédéfini dans "Vlan où placer les machines après acceptation RADIUS"')], default='DEFINED', max_length=32), + ), + ] diff --git a/preferences/urls.py b/preferences/urls.py index 2169f83c..f10d25a0 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -69,7 +69,7 @@ urlpatterns = [ ), url(r'^del_services/$', views.del_services, name='del-services'), url( - r'^history/(?Pservice)/(?P[0-9]+)$', + r'^history/(?Pservice)/(?P[0-9]+)$', views.history, name='history' ), diff --git a/topologie/urls.py b/topologie/urls.py index 4d0a6779..77a78b97 100644 --- a/topologie/urls.py +++ b/topologie/urls.py @@ -42,16 +42,16 @@ urlpatterns = [ url(r'^switch/(?P[0-9]+)$', views.index_port, name='index-port'), - url(r'^history/(?Pswitch)/(?P[0-9]+)$', + url(r'^history/(?Pswitch)/(?P[0-9]+)$', views.history, name='history'), - url(r'^history/(?Pport)/(?P[0-9]+)$', + url(r'^history/(?Pport)/(?P[0-9]+)$', views.history, name='history'), - url(r'^history/(?Proom)/(?P[0-9]+)$', + url(r'^history/(?Proom)/(?P[0-9]+)$', views.history, name='history'), - url(r'^history/(?Pstack)/(?P[0-9]+)$', + url(r'^history/(?Pstack)/(?P[0-9]+)$', views.history, name='history'), url(r'^edit_port/(?P[0-9]+)$', views.edit_port, name='edit-port'), diff --git a/topologie/views.py b/topologie/views.py index 686685e9..5eb2de74 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -135,7 +135,8 @@ def index_port(request, switch_id): port_list = Port.objects.filter(switch=switch)\ .select_related('room')\ .select_related('machine_interface__domain__extension')\ - .select_related('related')\ + .select_related('machine_interface__machine__user')\ + .select_related('related__switch__switch_interface__domain__extension')\ .select_related('switch')\ .order_by('port') return render(request, 'topologie/index_p.html', { diff --git a/users/forms.py b/users/forms.py index fd81b426..93ef35b5 100644 --- a/users/forms.py +++ b/users/forms.py @@ -452,13 +452,14 @@ class RightForm(ModelForm): class DelRightForm(Form): """Suppression d'un droit d'un user""" rights = forms.ModelMultipleChoiceField( - queryset=Right.objects.all(), + queryset=Right.objects.select_related('user'), widget=forms.CheckboxSelectMultiple ) def __init__(self, right, *args, **kwargs): super(DelRightForm, self).__init__(*args, **kwargs) - self.fields['rights'].queryset = Right.objects.filter(right=right) + self.fields['rights'].queryset = Right.objects.select_related('user')\ + .select_related('right').filter(right=right) class BanForm(ModelForm): diff --git a/users/urls.py b/users/urls.py index 531e0826..201568cd 100644 --- a/users/urls.py +++ b/users/urls.py @@ -88,32 +88,32 @@ urlpatterns = [ url(r'^reset_password/$', views.reset_password, name='reset-password'), url(r'^mass_archive/$', views.mass_archive, name='mass-archive'), url( - r'^history/(?Puser)/(?P[0-9]+)$', + r'^history/(?Puser)/(?P[0-9]+)$', views.history, name='history' ), url( - r'^history/(?Pban)/(?P[0-9]+)$', + r'^history/(?Pban)/(?P[0-9]+)$', views.history, name='history' ), url( - r'^history/(?Pwhitelist)/(?P[0-9]+)$', + r'^history/(?Pwhitelist)/(?P[0-9]+)$', views.history, name='history' ), url( - r'^history/(?Pschool)/(?P[0-9]+)$', + r'^history/(?Pschool)/(?P[0-9]+)$', views.history, name='history' ), url( - r'^history/(?Plistright)/(?P[0-9]+)$', + r'^history/(?Plistright)/(?P[0-9]+)$', views.history, name='history' ), url( - r'^history/(?Pserviceuser)/(?P[0-9]+)$', + r'^history/(?Pserviceuser)/(?P[0-9]+)$', views.history, name='history' ), From 76e22268010919e4b7691229529eb99c7cea390b Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 18 Oct 2017 04:11:27 +0200 Subject: [PATCH 24/27] Fix et optimisation select_related --- cotisations/views.py | 3 ++- machines/forms.py | 2 ++ machines/views.py | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cotisations/views.py b/cotisations/views.py index fc4469aa..4e2c5304 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -533,7 +533,8 @@ def control(request): facture_list = paginator.page(1) except EmptyPage: facture_list = paginator.page(paginator.num.pages) - page_query = Facture.objects.order_by('date').reverse().filter( + page_query = Facture.objects.order_by('date').select_related('user')\ + .select_related('paiement').reverse().filter( id__in=[facture.id for facture in facture_list] ) controlform = controlform_set(request.POST or None, queryset=page_query) diff --git a/machines/forms.py b/machines/forms.py index 9820fbdc..0086c3d6 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -380,6 +380,8 @@ class ServiceForm(ModelForm): 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): instance = super(ServiceForm, self).save(commit=False) diff --git a/machines/views.py b/machines/views.py index dc3e0406..85c19dde 100644 --- a/machines/views.py +++ b/machines/views.py @@ -1056,7 +1056,9 @@ def history(request, object, id): @login_required @permission_required('cableur') def index_portlist(request): - port_list = OuverturePortList.objects.prefetch_related('ouvertureport_set').prefetch_related('interface_set__domain__extension').prefetch_related('interface_set__machine__user').order_by('name') + port_list = OuverturePortList.objects.prefetch_related('ouvertureport_set')\ + .prefetch_related('interface_set__domain__extension')\ + .prefetch_related('interface_set__machine__user').order_by('name') return render(request, "machines/index_portlist.html", {'port_list':port_list}) @login_required From 7bd02c6c36f9cc7043997595ccd7e29d1ec93004 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 18 Oct 2017 16:27:48 +0200 Subject: [PATCH 25/27] Support des enregistrements AAAA sur le @ de la zone --- machines/forms.py | 3 ++- .../migrations/0062_extension_origin_v6.py | 20 +++++++++++++++++++ machines/models.py | 16 +++++++++++++-- machines/serializers.py | 2 +- .../templates/machines/aff_extension.html | 4 +++- 5 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 machines/migrations/0062_extension_origin_v6.py diff --git a/machines/forms.py b/machines/forms.py index 0086c3d6..34d3a2bc 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -266,13 +266,14 @@ class ExtensionForm(ModelForm): """Formulaire d'ajout et edition d'une extension""" class Meta: model = Extension - fields = ['name', 'need_infra', 'origin'] + 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 à ajouter' self.fields['origin'].label = 'Enregistrement A origin' + self.fields['origin_v6'].label = 'Enregistrement AAAA origin' class DelExtensionForm(Form): diff --git a/machines/migrations/0062_extension_origin_v6.py b/machines/migrations/0062_extension_origin_v6.py new file mode 100644 index 00000000..1c3d869a --- /dev/null +++ b/machines/migrations/0062_extension_origin_v6.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-18 14:08 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0061_auto_20171015_2033'), + ] + + operations = [ + migrations.AddField( + model_name='extension', + name='origin_v6', + field=models.GenericIPAddressField(blank=True, null=True, protocol='IPv6'), + ), + ] diff --git a/machines/models.py b/machines/models.py index c1d8ca80..a782b7a9 100644 --- a/machines/models.py +++ b/machines/models.py @@ -247,11 +247,23 @@ class Extension(models.Model): blank=True, null=True ) + origin_v6 = models.GenericIPAddressField( + protocol='IPv6', + null=True, + blank=True + ) @cached_property def dns_entry(self): - """ Une entrée DNS A""" - return "@ IN A " + str(self.origin) + """ Une entrée DNS A et AAAA sur origin (zone self)""" + entry = "" + if self.origin: + entry += "@ IN A " + str(self.origin) + if self.origin_v6: + if entry: + entry += "\n" + entry += "@ IN AAAA " + str(self.origin_v6) + return entry def __str__(self): return self.name diff --git a/machines/serializers.py b/machines/serializers.py index 6e0ca4e3..7d222ef0 100644 --- a/machines/serializers.py +++ b/machines/serializers.py @@ -161,7 +161,7 @@ class ExtensionSerializer(serializers.ModelSerializer): class Meta: model = Extension - fields = ('name', 'origin', 'zone_entry') + fields = ('name', 'origin', 'origin_v6', 'zone_entry') def get_origin_ip(self, obj): return obj.origin.ipv4 diff --git a/machines/templates/machines/aff_extension.html b/machines/templates/machines/aff_extension.html index 18fd7c4b..069f545a 100644 --- a/machines/templates/machines/aff_extension.html +++ b/machines/templates/machines/aff_extension.html @@ -28,7 +28,8 @@ with this program; if not, write to the Free Software Foundation, Inc., Extension Autorisation infra pour utiliser l'extension Enregistrement A origin - + Enregistrement AAAA origin + {% for extension in extension_list %} @@ -36,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ extension.name }} {{ extension.need_infra }} {{ extension.origin }} + {{ extension.origin_v6 }} {% if is_infra %} {% include 'buttons/edit.html' with href='machines:edit-extension' id=extension.id %} From 42c1fe4e614f58624049ab2ad21af7a2ed792972 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 18 Oct 2017 17:19:51 +0200 Subject: [PATCH 26/27] Optimisations de chargement --- machines/forms.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/machines/forms.py b/machines/forms.py index 34d3a2bc..80df9215 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -296,7 +296,7 @@ class MxForm(ModelForm): super(MxForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields['name'].queryset = Domain.objects.exclude( interface_parent=None - ) + ).select_related('extension') class DelMxForm(Form): @@ -309,7 +309,9 @@ class DelMxForm(Form): class NsForm(ModelForm): - """Ajout d'un NS pour une zone""" + """Ajout d'un NS pour une zone + On exclue les CNAME dans les objets domain (interdit par la rfc) + donc on prend uniquemet """ class Meta: model = Ns fields = ['zone', 'ns'] @@ -319,7 +321,7 @@ class NsForm(ModelForm): super(NsForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields['ns'].queryset = Domain.objects.exclude( interface_parent=None - ) + ).select_related('extension') class DelNsForm(Form): From 54de126384ca2d93e665ed3b5f867ddb7518ba9b Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Thu, 19 Oct 2017 07:08:10 +0200 Subject: [PATCH 27/27] Le check ne doit etre fait que si il y a une ip --- machines/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/machines/models.py b/machines/models.py index a782b7a9..e3c14ea4 100644 --- a/machines/models.py +++ b/machines/models.py @@ -411,9 +411,10 @@ class Interface(models.Model): def save(self, *args, **kwargs): self.filter_macaddress() # On verifie la cohérence en forçant l'extension par la méthode - if self.type.ip_type != self.ipv4.ip_type: - raise ValidationError("L'ipv4 et le type de la machine ne\ - correspondent pas") + if self.ipv4: + if self.type.ip_type != self.ipv4.ip_type: + raise ValidationError("L'ipv4 et le type de la machine ne\ + correspondent pas") super(Interface, self).save(*args, **kwargs) def __str__(self):