From 9b05f8fa98317411229ba81dc6c888b86c24f27d Mon Sep 17 00:00:00 2001 From: Grizzly Date: Thu, 24 Jan 2019 18:00:20 +0000 Subject: [PATCH 001/228] =?UTF-8?q?Texte=20et=20couleur=20pour=20les=20mac?= =?UTF-8?q?hines=20d=C3=A9sactiv=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- machines/templates/machines/aff_machines.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html index 4363cd6e..70b83d0a 100644 --- a/machines/templates/machines/aff_machines.html +++ b/machines/templates/machines/aff_machines.html @@ -52,7 +52,12 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "No name" as tr_no_name %} {% trans "View the profile" as tr_view_the_profile %} - {{ machine.get_name|default:tr_no_name }} + {% if machine.active %} + + {% else %} + Deactivated: + {% endif %} + {{ machine.get_name|default:tr_no_name }} {{ machine.user }} From ee7c1272b16b5809248e8d8df07b0a4a49fe3287 Mon Sep 17 00:00:00 2001 From: klafyvel Date: Sat, 26 Jan 2019 13:08:59 +0100 Subject: [PATCH 002/228] Translation for deactivated --- machines/templates/machines/aff_machines.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html index 70b83d0a..02ec3c91 100644 --- a/machines/templates/machines/aff_machines.html +++ b/machines/templates/machines/aff_machines.html @@ -55,7 +55,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if machine.active %} {% else %} - Deactivated: + {% trans "Deactivated" %}: {% endif %} {{ machine.get_name|default:tr_no_name }} From e1fa749039778f7522ff3027d0a01faa454c57d6 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sun, 27 Jan 2019 09:39:18 +0000 Subject: [PATCH 003/228] Determine et affiche le vendeur de la mac (wip sur le except) --- machines/models.py | 10 +++++++++ machines/templates/machines/aff_machines.html | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/machines/models.py b/machines/models.py index cdc6d830..d02ee0f7 100644 --- a/machines/models.py +++ b/machines/models.py @@ -1044,6 +1044,16 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): IPv6Address(prefix_v6).exploded[:20] + IPv6Address(self.id).exploded[20:] ) + @cached_property + def get_vendor(self): + """Retourne le vendeur associé à la mac de l'interface""" + mac = EUI(self.mac_address) + try: + oui = mac.oui + vendor = oui.registration().org + except: + vendor = "Unknown vendor" + return(vendor) def sync_ipv6_dhcpv6(self): """Affecte une ipv6 dhcpv6 calculée à partir de l'id de la machine""" diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html index 02ec3c91..6001f7ce 100644 --- a/machines/templates/machines/aff_machines.html +++ b/machines/templates/machines/aff_machines.html @@ -92,6 +92,11 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ interface.mac_address }} + IPv4 {{ interface.ipv4 }} @@ -163,6 +168,17 @@ with this program; if not, write to the Free Software Foundation, Inc., + + +
+
    +
  • + {{ interface.get_vendor }} +
  • +
+
+ + {% if ipv6_enabled and interface.ipv6 != 'None' %} @@ -217,6 +233,12 @@ with this program; if not, write to the Free Software Foundation, Inc., ipv6_div[i].collapse('hide'); } }); + $("#machines_table").ready(function () { + var vendor_div = [{% for machine in machines_list %}{% for interface in machine.interface_set.all %}{% if interface.get_vendor %}$("#collapseVendor_{{ interface.id }}"), {% endif %}{% endfor %}{% endfor %}]; + for (var i = 0; i < vendor_div.length; i++) { + vendor_div[i].collapse('hide'); + } + }); {% if machines_list.paginator %} From e02456072943bf623b5597180874e5d95f480f30 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sun, 27 Jan 2019 10:38:43 +0000 Subject: [PATCH 004/228] Meilleur gestion d'erreur --- machines/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machines/models.py b/machines/models.py index d02ee0f7..75da1317 100644 --- a/machines/models.py +++ b/machines/models.py @@ -44,7 +44,7 @@ from django.utils import timezone from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from macaddress.fields import MACAddressField, default_dialect -from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress +from netaddr import mac_bare, EUI, NotRegisteredError, IPSet, IPRange, IPNetwork, IPAddress import preferences.models import users.models @@ -1051,7 +1051,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): try: oui = mac.oui vendor = oui.registration().org - except: + except NotRegisteredError: vendor = "Unknown vendor" return(vendor) From 6780b91fe28cee768256a00d4d14696f128e3537 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Sat, 12 Jan 2019 08:18:57 +0100 Subject: [PATCH 005/228] Make 'Manage the club' panel hover like other panels --- users/templates/users/profil.html | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index 7f560d06..7361d2b7 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -308,17 +308,18 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if users.is_class_club %}
-
+

- {% trans " Manage the club" %} + {% trans " Manage the club" %}

- + - {% trans "Manage the admins and members" %} - + {% trans "Manage the admins and members" %} +

{% trans "Club admins" %}

From 0d4b86f5c19cc01ca907888a4001ce94045754d3 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Sat, 12 Jan 2019 09:07:37 +0100 Subject: [PATCH 006/228] Make alternatives for favicon Make alternatives for favicon to support a wider range of device. It includes favicon for iOS, Android, MacOS touchbar. It also fixes the favicon on Chromium/Chrome variants. --- static/favicon/android-chrome-192x192.png | Bin 0 -> 2527 bytes static/favicon/android-chrome-512x512.png | Bin 0 -> 5893 bytes static/favicon/apple-touch-icon.png | Bin 0 -> 1511 bytes static/favicon/favicon-16x16.png | Bin 0 -> 461 bytes static/favicon/favicon-32x32.png | Bin 0 -> 678 bytes static/favicon/favicon.ico | Bin 0 -> 15086 bytes static/favicon/safari-pinned-tab.svg | 1 + static/favicon/site.webmanifest | 19 +++++++++++++++++++ templates/base.html | 15 +++++++++++++-- 9 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 static/favicon/android-chrome-192x192.png create mode 100644 static/favicon/android-chrome-512x512.png create mode 100644 static/favicon/apple-touch-icon.png create mode 100644 static/favicon/favicon-16x16.png create mode 100644 static/favicon/favicon-32x32.png create mode 100644 static/favicon/favicon.ico create mode 100644 static/favicon/safari-pinned-tab.svg create mode 100644 static/favicon/site.webmanifest diff --git a/static/favicon/android-chrome-192x192.png b/static/favicon/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..8d469d28abc74b72248edd2836a62512799e06bb GIT binary patch literal 2527 zcmXw5dpOkD8$aKf!3={L!e|Dgk&$J@BFbf43Oh`0g~c>Bl!#G65~Ey3D)(~DrOQSM zMagwUOS!c>+QsIwQX=e-J7a#cPtWgt&ilTf&*y!gbIx=AId7^n-A-C^wAqAF` zwMdM1c62}N7!0(p6P8)dtu>BR4% zs47^P*dDmH)$F}J-o066C>X0=ZL9uPk;Bi7T8QK(5xW;j{qP4&7u98Ztf3R^jM?S^H)<7;PoX~6G7)$PDXl!aFm)^fj z>fFewRvR~>JTlX}wrAjnm;)VlM3cn$g-TEJHUvDgn7k{a?x-SFeFB1z~jo1)I{N_TC1$;d!(y!H$X#*mEe)z)_4=%FkEmG zoA*VzR9R*uyl4^%QIsRC=Rb$el>M@69q;JizmIeJ>wqK1O9~bWKQU>QYr&;Y+E6M{ zJ`OUv%aFfCPH4zMEWQ(L_QYzni+LiiQc)1|YQ8V~7K*7(l!mD(6VJk@FznpR;Dvc+ zGUOcYIzNm6nq}`Rck$lAl$bk9UC*$fH3Y`iC5Ed%Qe5Za^3scw0`Wbd#8{^HZ<4;C zCUaeZ_>OTju3Edp0qRBSAUU{>3STf3@}#C!6$6+S?!%1CRM4BEZ7*{!Ffuy>On^Z7 z6|>2ufwr?(uzMZ;(9;6=>oftfVMh*mC zJ%3HIXMzvnqc1sX8NPRx?T9QtU?yXrZS?Bq|XhILn4!#0*k#} znR9e{<#mhuQ$!F z`Jxg_y>{iM@HXxGe>MM=bGZXF7rb`jX)IoDoiEa;*m_T4&5#;&^H;mR{hYx|Q0V{d zGo(6skztoamu-K_kjj;t$D6voJDYI;YNTC1hzh;^vw+uVhqE?80p<2w|K*0`-Bv;a zju*&e4o{mOt)*U|bxXtRP-g^d!78S=3j($uKnxL+4R#v-ip5DpYd&1Dtg8P+R5kX7 z*3}yVhr^{aTId8KFhhpg@`PXx!O9Qu=df%p*& zA`UnMA>y2&G<YA9iWKII4}c0c_F*dqx4-2iI{7xFe6O@CnlK`PG%#=%#^?}Np~-(#>loQ%rYbU2MB(fD%UaK+G3b6PC)H~qa1&*f zC&JASc!WLpga==BzUji76*{hI9f6Q59SmQ`mR=*lbO4!jN?x1_$2B(5o_%WL0o?PJOTC=(-=w5V zjiJ~hQJTZ9F87lqF#arZ`8J)d2dRSd<)jG3!4EUDBr1Y=yMbP#Z_>0cSVbS2UBqS4 z();eaib2{`mF_9T`VQ?zjGGTwWzM+#B|M>b{{nUb#{Zgk@Fgc#%D4VZTrIQ?mwiiR zig|mqR0c$VIF<9`X)Nu(qkg)CERABkM1y6U(^@rp+Ge=9Re*PH(eu{ZO5F;;u}1^8DFO@C^puX4 z?WPK*P_QF_j~j9yUsn6}Nm?*29_D;qf(t7+5zi^-Z_pq3U2%aLUlSlXwyEfaP9jc& z2S`3ZV~MalbuMDRHCvK-1t@U=WWZfV41t3Pi;}F)T6u&#!WnBuF`8v`cS?NO%OTZP zxZ)hqrG*ol(fP@SvhU4so0vw>tbDM2C98f*dw$6^>77{3VlC>H53e%gg~n_%br6-& z>x_z995|sk@#Lpsuz=2HkM5g~o~QkOtU{jq4T}m5G4-u%)J`G-o@TV>#Ex48t9oJMWkYbF6s(!+r`oXkmKkBWYe}>4p=d2egp0+` z8#!qN4Ap~F=7M^%`LFPnoV*q=zEg-(&DPsYXDZ3bKLiVfD<4zm67K=C1SfHDeIJa9 zxR~U#Bx7kzy%ddR3Jf~~cMpMzFIMc<<2qPu6G)AAmJ0ez+{74D58b!I7a(s`>A zm`Iy^|G98(XcRR%%rM+I<%5f+!YN*9zt3crX1x>$2|333VfU1ohPUk87!pzxyVI8d zhK8d~2u{VypDoc6NTWc_2Y2?e0Ql=Sq5@ zTdwE(W2sw5rv@~g-u+16%NvY(oSeVt@|Wq?nx^YsbbUG^6TvB8f-BVGiBPmlUmBL9E zbt+p&(GBUQ6jM=dMN$YezwP(=ynnoZy#KxHGqcwBS?gJA?X}i-J>R|e1p0faDC#K! zfXaMt&maJtfjDporugriSuInLf4MJk2lyvTX>=8fv9b6duQ^asH?fm3xUt?L@c=Vc zjQ=rRG>-w`8|b%quHU*i`Tt4Z^o*DvV=;NYx)zfwDvr;2_wL={Q(9mA1xyWNG7h6n zS4O(u4d2-@Qa<-v+RE72*z)r7{l~h;hgC@k@?QjRql&7W9Ktnv-*|1?Y9AT^pj|WH z(|vLB+n)EG*UwznU53h8Y_SSpx1+#&dS%oQ=6F%m@EpdNP_QxBq zlSLs%%@eime=YqP)94arY_i+=XX2|}rWbUjmREb)Cb$utqj_WBH>DY2$~IFPJKu;C zh!^Q|?+hztdIycRolgC+4I0((sfA%1R-SEBJ*o~F5a)aEr=jaRslG7pFF%9W)zmTPcs9>>bu*!(DbR$Hpot7er|gwsuk zy%LFUSd&ty^W+k7;W4|xkl6Q`o)YBhj|!pV%$bIz=HQBUQC-nQ$Bc9>R}{%_A{T+) zaVo=*n$UcVC2dnhE4Z}DP%-C;HMD>4NZ~e_*0_;9YxA-EP~0ix1WUvjnyD0hNew%p zgXVE-g=Ds(@G@r4l7!$w(z_135Qs(OAT3KQ1J^i(H&|iZop3WsIKheNFi`jml)k>) zi+*K^>z<=Nx(m0fie3{!R-+^KP_=mo^BClt5}scpe=sIlnPh#{)fFgpT)@nM-NclHYo-5aYWNe!L{wK zR5BT%j5%?5o!CdP{xOM{B6z=$vUMSF)W^&AsYi|*;1_kvm`dfAg%E%+6fA4q0N|a^ z{;P4h0BTFHJuawmNWfeWaKEZx(O3hHmhQlt38{LX3X*JvKy19}kMRs@G0u7w64hcN zl|n-LY@ramaVw_2FD`aF1c^%&XqK@CwApdXD@-_lZ=b@260R0Y`fN$nP||r0eBTDC zc9aep(i5d+@lvPn(?A1yvG%QaoQ5Bl`rZ9O`#Kc@#dDH4Wqb^f7PACV+;O1|RtRf) zd8?-4BCdobm_-J^o5J^nDX9L=J@Z+pii6A%pR#BoVvB>-AUUo);+O(UA!pEJC=Laj{ z-tX(uZ!H4>`jGRujeEuaIQ8-*7)z&!?AX#Ddq8f{_XhTE%Ro!@n|!ed2W(0sv+KxoaDO36VWSKF#$jv1pR5Jz+i^664 zhG2}YbAv&uC3KbZ%Cw1wP?q9?Wb4#M_V6xrjgOAPEqBQqnPr>X7EFI8L}BJzhYND# z9ju;qxcV6mIW}0!HGdfWi!KY$bu>Iz^7EJcmfRiIsgMxXZ5?{OAl4NR_O$wbs4 zr#CxAG;%Nc|9;vkJE+v;OLSaIPtna?E3r-y51iH_D-7_p1m6n3mfr7W=cKZxvcfPY z14&`PGJQryl~1hmPsPf_!K{_Y2$pVMx^IW=#W-!*m5^WH5X1Q zS)VjYfIIx)glf%Y(0q7B9vYBnkv2d_P4x47UU0Vfr7C_Dm)H^(>_cCkwhBZu;T!wP zy56z+r*6ig`Cy@yv9{k>v;DcshIOj;BlX4yJ0 zoyTd!)Psto9 z{q-a4zf^33>&R2LQ1&4$n0R~VO}u29vpfKw34N72LvY*b&R&gLK=SENc(G>#YdXQw0R1K>(%@#zwFB z*#x+uU8vYg1zqC;ErCisx`-?UDNs|WlyWS=5rbGvbmaF^82U^Be{Xd$x9lYeG=^T3 zbIWEboC8{ouEFUgIEWJPp^?l}Bv4i?=@MK6L~Q8>EO`n(3HtE9YtWYi&@t~@6qbAh zO#~;butf(g<1$CANquZJmRfeqa0h-5ysaOd7MTGJd!Bq!rJoTX(KO6LHsJzL-jB}S z0P8M801pFc&lKoC1HidR+};8p#A;o8VZaq2VPdgqrBiz+qx0JYHAq*%DwaD1E% znRdGi^jP5GLA7sIpr>tXf}s||$7TAy38>dqLdO%wu%R(2y>}Gr2VoPD>Z;V3oFtq9 zrS%zg$y=P<(2Gw~%gn?{4zMp&`{SS7WF3b1!PuIX1L@|&91eU6m+Ue}rvNC*T(X*Z zso@23rQ?M^_k71D3OEWC*@V9}R6bJ^MR%x!wDN&k9$@!n9ztAH4b!0*T7 ziwBrnSyOZG?Qs?93h-unl+G+0_>-uxzApesb4-7fg;A658#6c>ZwyD#(a^^97_^Yo zr>Q_8!}@!CNqYd4_x@%j9`-D-zHJ)c9s-hO2xUgFBB2Ht9QU$Q*4}0*J>h zMM+o4e!5RmU?v+acds+)%aauy5SOz6J+-HokS*_9FOAl#100P)r#Pv%D%TAcFsqJi zrWQ78I8_!`&K^F-z1K6wQ3Ipc#=nYa~z(R+O1!i ztJopy8yrbAXkH%qEl%E^bf<-&V~uisC5`*Vua`Vk^}u?KWOwU+f9@`L9~I35$!i70 z6(_hYqw&R+C(u{Z!Q-9ci02D=mMF=nLbt3ot@~-1nS7DMDl^d{%hplxU0ZhVN#11S zuYG=b`a*+_HI?3tFS`o1!$^~hau1EVzQix- zYAL8~sRu=WDoUg|9W~F()*?=AP4~uat!G^+QIzVozbKEr;s^Ryv8)i`HsK(Du+lLl1?D!|Ni+f>lrtg$LQcx_WYw~ zJ9}%=9$1Lh!Aa#V@9x^@`K4!MU)$XDkD)*DTQA6Ea9S?#?ou-?P^f=|D_*LzoD zGEkoxB0S*&9Amg`7+y<50A`q+RTgvfNfkspMw5)67vwRu;IBIYd-YN0Qx`(<;-h|Fun8|FKFa5l?FW?S! z*dl!lT%rZ^a@mRI7!S&xh@C>w4?e^^yIJzx=FG!L1n44Qv-?Z)3|=mL0~qM0AWiIt zY{T=O$#Xq`HEt7FfZorrAL)nGQNF8a8fMq{DMlT8s6gKV%ztc|%EH7Et^@=zYE7PW zX0YtCqu>oxv{Lk1x#c18ah04z*kI-3M2_}sru;$;Tdi{Cq^gN~U`HM#? z%f?#ggF0j>ae^lsRLG~{!RZHrn5DnT7Uk{YQx``xZ z&!yM!vH?|u8Yce3r7M(pfb57@&;CY76GbY}1lcyzq$X@1pdCr!Q1IF2EDRatw*az;*k>rfU=e#wB6>IxAer&&g6Q$MR`L}Oyb_hJ^RGk$%9OD~ zGjJz{#7uy$y1~xh#n2)cLWV?cDIDkX}ZRN!35&&Z+ z*;_dPZwLuSV-PqBjKQc{B>a&ES|BL(-3wO%sUuaOu<-^q#UX)DOl9N9BO15sh-@jA z>O1?YBEQa6f$4Q@0`gJBcg;5lx)d^1|qO%V5#skeYySn9~C|r z?8BCKAFZ2senkm4Lm}HuS!zfq+wS>rg1A`&MfxUXN`(rNwW`>ouO;4*`1u-ix?Kg+ zyKp!M;6-Mhkh#Dy=k{R!XG+4!6%>9>ukSz<~N-m4+GkptKlP${`HXmN%lSP(l&fM zT+f;}>`9STU@U1n2+y~8QV}p_z1tVhSw@oBfHCsIUG5t04-o`%L%Nyhl9O0?oS(sqYLXuv4GEQ=AnzM!q z%2X;$`(CBhir+dm)Ko=JBi0&@3FPbE(m|x7y{I#7vOr$MOHaps8j$A}z3tD69j!k^ z-W8MuHVn4BO|6i>NfotGgJ#Mv{{xSgH4p#* literal 0 HcmV?d00001 diff --git a/static/favicon/apple-touch-icon.png b/static/favicon/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e104c1f2a328710e1738108584a938dd2794212d GIT binary patch literal 1511 zcmVPx#KTu3mMgRZ*`||JeZEpSK(g6Vh@Gmp*RayC=6z&=y z=T0E|xKY{J+4#M-^qrATPEPA)Ks7Zr{obzp&WQ4cc9@u$$Vj3O000EzNkl|8m5D=V!d~I-&zF-YMCTwoN>k(XPj}y8KDHRAt)wr ze<>ev>EnR2m-yjk(UD_d_vLEbLN?#ZGCK98+>A?fc@8+&eOcKutKei_YzLX*)z#MX3y zneymhbbyOX5#chffF_f1C=Ny&U7DsxqkDr*Kz=k@X}i^2XOkXT1{XzchgR9xw%OJ3 zfh0*Q^!~BOG<7st=3Jfd+y=d0AVYD`HAAQ=w?Xe7i_usd8AQ#k&~(`|-?I#)mNw|k zx*nIpm)X5~y+D-F>xb(7-0WVR+M$P4=CZP;P@82ywXj7G*}lDR6y2uljpmwVNHw!Z z|J{-6`{zBmrp-RXt=b8C_6KCE;Z&WwM*C2^M|)5M(0DZh4Oc_ZXf*~6R)f%3H3|(? z!_b@RpwU1z5RFqK(J-|YT1rk9YT`n6U0v5*Dh2a}9`C^xg7d$NQXk*lchqgd9n z=p^@se%>;D{?Hsf9eymMrG!Mi5*_!8e(RHO>LJamWOX(i{h@9W*45k5Q3&X{dRP&8 zy&D}10sX(a-6@S%@DR{%^^j*-e-9A?`lW7^%wKcu2mMet-|G1lEClqVzAKx*%ptze zqnfBwMb~K%=%l$TOdM)u?GHU%ZfKb6E)cZTLGPv7BbsTM_fqWE; zph?rbQy>1&To=7vAO6r%8!e7UcfWy_$D_5)+au8%n*9j6J~M5CrWnx%15ut+o)J2Y zad8nbUVE?@uky5uTE@6@;pZOFbT^(xxEt3?btvZ^TALT1+`~YVPNJLf1U>+?#^#od z&#JaTpp~aR{`U-J8w6T$1`*GD2W=2&r6X$jzDv`FfKDh?$TMBDJ+*iA_qyi)n^)Bb zp!esHjxF!;wn3m1+FoS@&7ZwqRUd*LR&=>Vrj>_++jVrF=ebYxz!uASq!W~Urg=@B zr{eW=3^6X!+!K0orw@47J)hBOG8Og8Pf1VcN2cZtoD9|K;R3z?qy<0?L8H|eG*}Hn zW7Q}$R1HHT)i^Xz4MgMANHk0hMWfVMG)N6bW7Mndpc1sYZJt+J?^p9|(G07;PUO#* zAnnjRL8_21+60jkGCNy~1Th4WW1zofaJPSX?0Y=cCGnexc%is)!@!Hz`GGLG%~DNI%u zmEA3JC>EGYQ*eQh{!Fd7TN3_?+Rb+BudZRq{@A)OM~R+(Yiu?Fh|lwroAuOjM8x=M zlQ=&j6X)l8Hr0I+bj0`xswB#feNERP@qJb;dES$Y>jQRYoN>k(XPj|{di(=~6@SQr zX_l7&0038dR9JLUVRs;Ka&Km7Y-J#Hd2nSQX>fF7004NL=J6w-V1uWN zV~E7%*z=KmhZT5S19vAJ@bO%pu<3uRSkQ!w_s=Klyk^w)->}R@X|b#=!YX+mN|}>R)b^ zKjNOW`_wPhiB>%mZgKH{m@&bkYsLJhPekh(-n`@7v2@*&$3VA)SA|5B1SOU$6cpvB zW#*(RlvEa^Dr6RvBr`Bn%z6BYhodk|L*tbH=`)^BgBX~Vx%HB{g_VW9CyOu(E4Vb6 y98O_Y-W;NE`o@(LN6s9PIl_Lr!DE4!9>Xhf!IDo-rc;4dFnGH9xvX!lvI6;x#X;^) z4C~IxyaaOU0(?STeKHF_NXh?sa}g-O%F6mdQt990o$sXN-%2Th$kL!c`;-5^I{i*k z{`c!=U)Ie83ciz+`~Bg~&#R}8OlbK3;m)sh=0LswKRz%v(tmxV^G<8-&vOTX>Oq1( zz7}M}ypfUler7*V@pXtwQ$eg1_qn_kI0VzGbz_Uy~~NUC(v`m2(z&L>4nJFqeTaW9`+ZGeDoo zd%8G=Se$OXk~`Z)L4@tWV$WvH_d0CGyS;z>uP@-{y?DlMeoXlG;8n~F0*Wfl-xVvb zmzsYmlQ~(a$i?t|#)XNjyHrIQ{>llzQm|=!&8C*JO2M&gwqs~g!5ZEB6L&K?IQd+i z9KT`TFAqiy4Oi9Yf4s%7ai4f_+S5WR;L${tkDNQ!B!1I5c14;^zk~mQ);yWW0NF59D>V3py-t=sJ5K-u|=QDO*#956p($)BEOZ zm&g$_`p&?zGQ0lX*RpcG>J4+fS2J__En3ndrY~?X&}Ow~X){Y+%6sM=Yo_I$2wTwJ z*=?aaeWpZX2K%kt1%{zFm{%Kaao$+s{BL3U(i11!*PTBS@3`kbyW~>)-v8xUoxt!5 zuL_AM2}&$iC@9KL%gjktD5)$+RmdzTNoHWEnDh7(4@Y5`hQ=xX(`P)N1~D)zbL%B@ z3o8qIPZnVoR&Z%BIh?|*yg5YS^o=Vgj+{9nbA>L=r-y0jd$!4x~$f)UvX zBr4HQO^n1C+GwhnSO^Wqgb#J(NtM{3p@cRez(PZJyUcC}+RE&9JJ<7j@12)Bci(&S zX6MZ;^(JS}yYJn5|NnFDx#!)vZ;cr<<7W46Bf4gunl|QUV@$0U*LN86rrg^hn&*43 zGUg}J;5um|UCg~A+z-oCq^^X&AAH!kec_`0{h14$lkc3j3ux-r+UiG{zwrA6JdZ7O zns@$X&3^XaY9iFJrP;PW`l#9f_s5Q}w_V=;^`TcUu4dUVSzDQ%sx6-svBMUyTt5;s z_}%B5R%agkSemRY-!*K`?)c!j{E6`!p6ZU7H16CZmY6HI|5SDPpYHg>zMkCG?8+$k zG>dQAeeCVxUt4Yso3lH*A)f!Q{?^`oZ;%@`KJqlNM!s_G&xxN!56kUV#`V=Q$Z-+-r$4_K=9WC} zydV7B1BopDex9ani6!AKW7?fNcZN1F4}LDCj^E+VdiObG@t>+SXZ*G$)w{UEU*-Eh zc<2=Cfi((eG<82_Tpro{yVsf9XMpQW?lNXWgy&)L-?Mt(*CXU#n7hw0uUW5pGWfr7dhI(ey}J7RbHRtN?Ek}scM-0+_t#^m_6bawXGABl9$z;^Cox056Fz%1 z@3GgIs;zuIFP99$A3wwK{zuQYr|&pp)8xC4pI+bptHWWA@%VRfmuL8rcTCzIxW)6d zvRVFc$H%wavzW@;wS_k1c=DuhKpG;6-{m?iqvVg@i*Q#vXv;hZ(T2zd?iesC{=|D; z%qVAH6HD=WfbNDeD*pK1=T@{%-wnj$8>8Y++!y8Rx1;Y?@@L(WAAMd$>-3c|Htb`t zX%zmy()r`3D>;7Pf2FTqa^Pn2=Y#uOD?RqYqj>*@dokWc{l33WyuS8F<}a&^VEu;N z1wZ-CRKy0_{Oh&VSF-Ys+B0PS33vFb4a`GcED- zGb7HDyx&aNFf{HM9-UPd;}7><-)#6^fDJPA(7DII-4~1apP0e#dFPG#jCqJ-DakXM zW259I(gxL#D(wO^zk zG2`Jl51R_wwm()4b*pMaEyP3J5Tf$DB_2UH#v)xGw?f>QdL{Ccsnm^;daf3`>l4zh zD&tI8DPmtW(yh5j^M6`3k*|p)|EIM>DqB#Fzkca^FPym?Jo{GXKgfw@=a-|R@$%B8 zL-!qB|G<6sedX}lW%#%prfTPIl>c*ix`cOzgm_fmdf(pZV=E6hxPB-J+sZgEDgM9T z>l{|RG|gOSTd})cg6-fxtz+WjG+ezmB>cpF=3cSVv>O8{_O~Xh%Rj!hwmjXhVE^{* z+duxLn{Gb(vta3B8a8pkx=>&F_+aa^el^(A=ZJ{Cd++RJp99$V#vRwkXFa&ji(b3f z;3N2fSj69G)`dTwkB`s&HofX;*wP0-^ep}2zq@qli_9OwbryDfzchTXo;Z9Vxa*;% z|LXS~t{?uzv2&lBx-Rs$fT52lHohb;ggGYC3qGMD_Ji%>D!yumLxK%Xh~Ir?lH^F` zQ3M~m6)Q`_LG9MD%fRntyYj(5=gwc=rP$~)@QE|U$kR7`W5K$4<^KhLtNl+*5nFk_ z=NU2T&V3pFkK_3W>pO4#f$hg$ANVadM-a30RcyHoa|;~s13ZW|gzGHqqWHA)i;peO zle~tVnt#)5cE>8R{@nIl=VAM8d)15J^G?)vB=2V4nKEu_KJSI+KM(h|Ir%qjkIbHd zy+h2QE1&!0_o}m(k^JtS110&NIn3H4!vR0Ua}noJ*{8EtFDNm#|Nqkoey=^MyH5(& zN4FiWP5oRa`0Rnx_J?|}YmZva?-O_y#wR9qeoM38`HjGDAbty}y{;xM+`XdUF9>($ za`PhCn%mSaeC%^b+aqiHVQBn7EU5VJ@L^ywrkoZ8B60>(k$-yIp2**9XDqPmBJE0G zTXTV(w?TU>2wLMoFkeZR#zYX*tAVZ9pfh0uIg<$LGa_^LF>|jOPej1#F)-&8981(h zl5>iyq%vUn-Kk68-uJ@#@dsX9fA;y4YoBL0iJOBW`Rla0JWKoAo>_ZeW05i9{=I)A z?^?MVZ0(DNM^}Hrs8$z0l_lG@Z9BB@U~q=M@L)W*KmDku75d73D>?H?`l;=-728Ap zZhxN7{(R-}Z`PZ?o&LhD&uL%UOo=VB=4RS+wy?)O#v<>@5 zzD{zD-ydAYX{ox8{#lC&-(u(>kmB07`pYTlm%ot!I+BXZI=gf)rjWx|T z6d#{{8k6_``si8u(q>onz0afx^A^W?=zn6+jY-A}=eO5-h~E{g0qqYDY>6?5sXRG| zakOU)c!0gZ;2t;Zs+@W5j^x1G#vJ&EF;B`l=x?qu<_VQA%lYaLjXAw)%uhu=ITpzQ H*+u;ii5#UA literal 0 HcmV?d00001 diff --git a/static/favicon/safari-pinned-tab.svg b/static/favicon/safari-pinned-tab.svg new file mode 100644 index 00000000..04988f3a --- /dev/null +++ b/static/favicon/safari-pinned-tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/favicon/site.webmanifest b/static/favicon/site.webmanifest new file mode 100644 index 00000000..78fcc75f --- /dev/null +++ b/static/favicon/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/static/favicon/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/static/favicon/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/templates/base.html b/templates/base.html index 401ece70..e58950ab 100644 --- a/templates/base.html +++ b/templates/base.html @@ -33,7 +33,8 @@ with this program; if not, write to the Free Software Foundation, Inc., - + {# Open Graph for social media #} + @@ -54,8 +55,18 @@ with this program; if not, write to the Free Software Foundation, Inc., + {# Favicon with iOS, Android, touchbar support #} + + + + + + + + + {# Do not allow zooming on devices #} - + {{ name_website }} : {% block title %}{% trans "Home" %}{% endblock %} From 56ec7a2df5bb8d1747ecd0e76759f162e1e519be Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Tue, 12 Feb 2019 09:12:45 +0100 Subject: [PATCH 007/228] Update translation files --- api/locale/fr/LC_MESSAGES/django.po | 6 +- cotisations/locale/fr/LC_MESSAGES/django.po | 542 ++++++------ logs/locale/fr/LC_MESSAGES/django.po | 167 ++-- machines/locale/fr/LC_MESSAGES/django.po | 905 ++++++++++---------- preferences/locale/fr/LC_MESSAGES/django.po | 706 ++++++++------- re2o/locale/fr/LC_MESSAGES/django.po | 96 +-- search/locale/fr/LC_MESSAGES/django.po | 68 +- templates/locale/fr/LC_MESSAGES/django.po | 129 +-- topologie/locale/fr/LC_MESSAGES/django.po | 535 ++++++------ users/locale/fr/LC_MESSAGES/django.po | 743 ++++++++-------- 10 files changed, 2068 insertions(+), 1829 deletions(-) diff --git a/api/locale/fr/LC_MESSAGES/django.po b/api/locale/fr/LC_MESSAGES/django.po index f2d6755e..7bafa61a 100644 --- a/api/locale/fr/LC_MESSAGES/django.po +++ b/api/locale/fr/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: 2.5\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-08 23:06+0100\n" +"POT-Creation-Date: 2019-02-12 08:58+0100\n" "PO-Revision-Date: 2019-01-07 01:37+0100\n" "Last-Translator: Laouen Fernet \n" "Language-Team: \n" @@ -31,10 +31,10 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: acl.py:74 +#: api/acl.py:74 msgid "You don't have the right to see this application." msgstr "Vous n'avez pas le droit de voir cette application." -#: authentication.py:49 +#: api/authentication.py:49 msgid "The token has expired." msgstr "Le jeton a expiré." diff --git a/cotisations/locale/fr/LC_MESSAGES/django.po b/cotisations/locale/fr/LC_MESSAGES/django.po index 2c29dc8d..325752d9 100644 --- a/cotisations/locale/fr/LC_MESSAGES/django.po +++ b/cotisations/locale/fr/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: 2.5\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-12 16:50+0100\n" +"POT-Creation-Date: 2019-02-12 08:58+0100\n" "PO-Revision-Date: 2018-03-31 16:09+0002\n" "Last-Translator: Laouen Fernet \n" "Language: fr_FR\n" @@ -29,92 +29,95 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: acl.py:45 +#: cotisations/acl.py:45 msgid "You don't have the right to view this application." msgstr "Vous n'avez pas le droit de voir cette application." -#: forms.py:66 forms.py:299 +#: cotisations/forms.py:66 cotisations/forms.py:299 msgid "Select a payment method" msgstr "Sélectionnez un moyen de paiement" -#: forms.py:69 models.py:579 +#: cotisations/forms.py:69 cotisations/models.py:602 msgid "Member" msgstr "Adhérent" -#: forms.py:71 +#: cotisations/forms.py:71 msgid "Select the proprietary member" msgstr "Sélectionnez l'adhérent propriétaire" -#: forms.py:72 +#: cotisations/forms.py:72 msgid "Validated invoice" msgstr "Facture validée" -#: forms.py:85 +#: cotisations/forms.py:85 msgid "A payment method must be specified." msgstr "Un moyen de paiement doit être renseigné." -#: forms.py:97 templates/cotisations/aff_article.html:33 -#: templates/cotisations/facture.html:67 +#: cotisations/forms.py:97 +#: cotisations/templates/cotisations/aff_article.html:33 +#: cotisations/templates/cotisations/facture.html:67 msgid "Article" msgstr "Article" -#: forms.py:101 templates/cotisations/edit_facture.html:50 +#: cotisations/forms.py:101 +#: cotisations/templates/cotisations/edit_facture.html:50 msgid "Quantity" msgstr "Quantité" -#: forms.py:119 +#: cotisations/forms.py:119 msgid "Discount is on percentage." msgstr "La réduction est en pourcentage." -#: forms.py:123 templates/cotisations/facture.html:78 +#: cotisations/forms.py:123 cotisations/templates/cotisations/facture.html:78 msgid "Discount" msgstr "Réduction" -#: forms.py:140 +#: cotisations/forms.py:140 #, python-format msgid "{}% discount" msgstr "{}% de réduction" -#: forms.py:140 +#: cotisations/forms.py:140 msgid "{}€ discount" msgstr "{}€ de réduction" -#: forms.py:179 +#: cotisations/forms.py:179 msgid "Article name" msgstr "Nom de l'article" -#: forms.py:189 templates/cotisations/sidebar.html:55 +#: cotisations/forms.py:189 cotisations/templates/cotisations/sidebar.html:55 msgid "Available articles" msgstr "Articles disponibles" -#: forms.py:217 +#: cotisations/forms.py:217 msgid "Payment method name" msgstr "Nom du moyen de paiement" -#: forms.py:229 +#: cotisations/forms.py:229 msgid "Available payment methods" msgstr "Moyens de paiement disponibles" -#: forms.py:255 +#: cotisations/forms.py:255 msgid "Bank name" msgstr "Nom de la banque" -#: forms.py:267 +#: cotisations/forms.py:267 msgid "Available banks" msgstr "Banques disponibles" -#: forms.py:286 +#: cotisations/forms.py:286 msgid "Amount" msgstr "Montant" -#: forms.py:292 templates/cotisations/aff_cost_estimate.html:42 -#: templates/cotisations/aff_cotisations.html:44 -#: templates/cotisations/aff_custom_invoice.html:42 -#: templates/cotisations/control.html:66 +#: cotisations/forms.py:292 +#: cotisations/templates/cotisations/aff_cost_estimate.html:42 +#: cotisations/templates/cotisations/aff_cotisations.html:44 +#: cotisations/templates/cotisations/aff_custom_invoice.html:42 +#: cotisations/templates/cotisations/control.html:66 msgid "Payment method" msgstr "Moyen de paiement" -#: forms.py:313 +#: cotisations/forms.py:313 #, python-format msgid "" "Requested amount is too high. Your balance can't exceed " @@ -123,54 +126,55 @@ msgstr "" "Le montant demandé est trop grand. Votre solde ne peut excéder " "%(max_online_balance)s €." -#: models.py:60 templates/cotisations/aff_cost_estimate.html:46 -#: templates/cotisations/aff_cotisations.html:48 -#: templates/cotisations/aff_custom_invoice.html:46 -#: templates/cotisations/control.html:70 +#: cotisations/models.py:63 +#: cotisations/templates/cotisations/aff_cost_estimate.html:46 +#: cotisations/templates/cotisations/aff_cotisations.html:48 +#: cotisations/templates/cotisations/aff_custom_invoice.html:46 +#: cotisations/templates/cotisations/control.html:70 msgid "Date" msgstr "Date" -#: models.py:136 +#: cotisations/models.py:139 msgid "cheque number" msgstr "numéro de chèque" -#: models.py:141 +#: cotisations/models.py:144 msgid "validated" msgstr "validée" -#: models.py:146 +#: cotisations/models.py:149 msgid "controlled" msgstr "contrôlée" -#: models.py:154 +#: cotisations/models.py:157 msgid "Can edit the \"controlled\" state" msgstr "Peut modifier l'état \"contrôlé\"" -#: models.py:156 +#: cotisations/models.py:159 msgid "Can view an invoice object" msgstr "Peut voir un objet facture" -#: models.py:158 +#: cotisations/models.py:161 msgid "Can edit all the previous invoices" msgstr "Peut modifier toutes les factures précédentes" -#: models.py:160 models.py:373 +#: cotisations/models.py:163 cotisations/models.py:396 msgid "invoice" msgstr "facture" -#: models.py:161 +#: cotisations/models.py:164 msgid "invoices" msgstr "factures" -#: models.py:170 +#: cotisations/models.py:173 msgid "You don't have the right to edit an invoice." msgstr "Vous n'avez pas le droit de modifier une facture." -#: models.py:173 +#: cotisations/models.py:176 msgid "You don't have the right to edit this user's invoices." msgstr "Vous n'avez pas le droit de modifier les factures de cet utilisateur." -#: models.py:177 +#: cotisations/models.py:180 msgid "" "You don't have the right to edit an invoice already controlled or " "invalidated." @@ -178,15 +182,15 @@ msgstr "" "Vous n'avez pas le droit de modifier une facture précédemment contrôlée ou " "invalidée." -#: models.py:184 +#: cotisations/models.py:187 msgid "You don't have the right to delete an invoice." msgstr "Vous n'avez pas le droit de supprimer une facture." -#: models.py:187 +#: cotisations/models.py:190 msgid "You don't have the right to delete this user's invoices." msgstr "Vous n'avez pas le droit de supprimer les factures de cet utilisateur." -#: models.py:191 +#: cotisations/models.py:194 msgid "" "You don't have the right to delete an invoice already controlled or " "invalidated." @@ -194,130 +198,137 @@ msgstr "" "Vous n'avez pas le droit de supprimer une facture précédemment contrôlée ou " "invalidée." -#: models.py:199 +#: cotisations/models.py:202 msgid "You don't have the right to view someone else's invoices history." msgstr "" "Vous n'avez pas le droit de voir l'historique des factures d'un autre " "utilisateur." -#: models.py:202 +#: cotisations/models.py:205 msgid "The invoice has been invalidated." msgstr "La facture a été invalidée." -#: models.py:214 +#: cotisations/models.py:217 msgid "You don't have the right to edit the \"controlled\" state." msgstr "Vous n'avez pas le droit de modifier le statut \"contrôlé\"." -#: models.py:228 +#: cotisations/models.py:231 msgid "There are no payment method which you can use." msgstr "Il n'y a pas de moyen de paiement que vous puissiez utiliser." -#: models.py:230 +#: cotisations/models.py:233 msgid "There are no article that you can buy." msgstr "Il n'y a pas d'article que vous puissiez acheter." -#: models.py:272 +#: cotisations/models.py:295 msgid "Can view a custom invoice object" msgstr "Peut voir un objet facture personnalisée" -#: models.py:276 templates/cotisations/aff_cost_estimate.html:36 -#: templates/cotisations/aff_custom_invoice.html:36 +#: cotisations/models.py:299 +#: cotisations/templates/cotisations/aff_cost_estimate.html:36 +#: cotisations/templates/cotisations/aff_custom_invoice.html:36 msgid "Recipient" msgstr "Destinataire" -#: models.py:280 templates/cotisations/aff_paiement.html:33 +#: cotisations/models.py:303 +#: cotisations/templates/cotisations/aff_paiement.html:33 msgid "Payment type" msgstr "Type de paiement" -#: models.py:284 +#: cotisations/models.py:307 msgid "Address" msgstr "Adresse" -#: models.py:287 templates/cotisations/aff_custom_invoice.html:54 +#: cotisations/models.py:310 +#: cotisations/templates/cotisations/aff_custom_invoice.html:54 msgid "Paid" msgstr "Payé" -#: models.py:291 +#: cotisations/models.py:314 msgid "Remark" msgstr "Remarque" -#: models.py:300 +#: cotisations/models.py:323 msgid "Can view a cost estimate object" msgstr "Peut voir un objet devis" -#: models.py:303 +#: cotisations/models.py:326 msgid "Period of validity" msgstr "Période de validité" -#: models.py:340 +#: cotisations/models.py:363 msgid "You don't have the right to delete a cost estimate." msgstr "Vous n'avez pas le droit de supprimer un devis." -#: models.py:343 +#: cotisations/models.py:366 msgid "The cost estimate has an invoice and can't be deleted." msgstr "Le devis a une facture et ne peut pas être supprimé." -#: models.py:364 models.py:585 models.py:852 +#: cotisations/models.py:387 cotisations/models.py:608 +#: cotisations/models.py:875 msgid "Connection" msgstr "Connexion" -#: models.py:365 models.py:586 models.py:853 +#: cotisations/models.py:388 cotisations/models.py:609 +#: cotisations/models.py:876 msgid "Membership" msgstr "Adhésion" -#: models.py:366 models.py:581 models.py:587 models.py:854 +#: cotisations/models.py:389 cotisations/models.py:604 +#: cotisations/models.py:610 cotisations/models.py:877 msgid "Both of them" msgstr "Les deux" -#: models.py:378 +#: cotisations/models.py:401 msgid "amount" msgstr "montant" -#: models.py:383 +#: cotisations/models.py:406 msgid "article" msgstr "article" -#: models.py:390 +#: cotisations/models.py:413 msgid "price" msgstr "prix" -#: models.py:395 models.py:604 +#: cotisations/models.py:418 cotisations/models.py:627 msgid "duration (in months)" msgstr "durée (en mois)" -#: models.py:403 models.py:618 models.py:868 +#: cotisations/models.py:426 cotisations/models.py:641 +#: cotisations/models.py:891 msgid "subscription type" msgstr "type de cotisation" -#: models.py:408 +#: cotisations/models.py:431 msgid "Can view a purchase object" msgstr "Peut voir un objet achat" -#: models.py:409 +#: cotisations/models.py:432 msgid "Can edit all the previous purchases" msgstr "Peut modifier tous les achats précédents" -#: models.py:411 models.py:862 +#: cotisations/models.py:434 cotisations/models.py:885 msgid "purchase" msgstr "achat" -#: models.py:412 +#: cotisations/models.py:435 msgid "purchases" msgstr "achats" -#: models.py:479 models.py:642 +#: cotisations/models.py:502 cotisations/models.py:665 msgid "Duration must be specified for a subscription." msgstr "La durée de la cotisation doit être indiquée." -#: models.py:486 +#: cotisations/models.py:509 msgid "You don't have the right to edit the purchases." msgstr "Vous n'avez pas le droit de modifier les achats." -#: models.py:491 +#: cotisations/models.py:514 msgid "You don't have the right to edit this user's purchases." msgstr "Vous n'avez pas le droit de modifier les achats de cet utilisateur." -#: models.py:495 +#: cotisations/models.py:518 msgid "" "You don't have the right to edit a purchase already controlled or " "invalidated." @@ -325,15 +336,15 @@ msgstr "" "Vous n'avez pas le droit de modifier un achat précédemment contrôlé ou " "invalidé." -#: models.py:502 +#: cotisations/models.py:525 msgid "You don't have the right to delete a purchase." msgstr "Vous n'avez pas le droit de supprimer un achat." -#: models.py:504 +#: cotisations/models.py:527 msgid "You don't have the right to delete this user's purchases." msgstr "Vous n'avez pas le droit de supprimer les achats de cet utilisateur." -#: models.py:507 +#: cotisations/models.py:530 msgid "" "You don't have the right to delete a purchase already controlled or " "invalidated." @@ -341,134 +352,134 @@ msgstr "" "Vous n'avez pas le droit de supprimer un achat précédemment contrôlé ou " "invalidé." -#: models.py:515 +#: cotisations/models.py:538 msgid "You don't have the right to view someone else's purchase history." msgstr "" "Vous n'avez pas le droit de voir l'historique des achats d'un autre " "utilisateur." -#: models.py:580 +#: cotisations/models.py:603 msgid "Club" msgstr "Club" -#: models.py:592 +#: cotisations/models.py:615 msgid "designation" msgstr "désignation" -#: models.py:598 +#: cotisations/models.py:621 msgid "unit price" msgstr "prix unitaire" -#: models.py:610 +#: cotisations/models.py:633 msgid "type of users concerned" msgstr "type d'utilisateurs concernés" -#: models.py:622 models.py:733 +#: cotisations/models.py:645 cotisations/models.py:756 msgid "is available for every user" msgstr "est disponible pour chaque utilisateur" -#: models.py:629 +#: cotisations/models.py:652 msgid "Can view an article object" msgstr "Peut voir un objet article" -#: models.py:630 +#: cotisations/models.py:653 msgid "Can buy every article" msgstr "Peut acheter chaque article" -#: models.py:638 +#: cotisations/models.py:661 msgid "Balance is a reserved article name." msgstr "Solde est un nom d'article réservé." -#: models.py:663 +#: cotisations/models.py:686 msgid "You can't buy this article." msgstr "Vous ne pouvez pas acheter cet article." -#: models.py:708 +#: cotisations/models.py:731 msgid "Can view a bank object" msgstr "Peut voir un objet banque" -#: models.py:710 +#: cotisations/models.py:733 msgid "bank" msgstr "banque" -#: models.py:711 +#: cotisations/models.py:734 msgid "banks" msgstr "banques" -#: models.py:729 +#: cotisations/models.py:752 msgid "method" msgstr "moyen" -#: models.py:738 +#: cotisations/models.py:761 msgid "is user balance" msgstr "est solde utilisateur" -#: models.py:739 +#: cotisations/models.py:762 msgid "There should be only one balance payment method." msgstr "Il ne devrait y avoir qu'un moyen de paiement solde." -#: models.py:745 +#: cotisations/models.py:768 msgid "Can view a payment method object" msgstr "Peut voir un objet moyen de paiement" -#: models.py:746 +#: cotisations/models.py:769 msgid "Can use every payment method" msgstr "Peut utiliser chaque moyen de paiement" -#: models.py:748 +#: cotisations/models.py:771 msgid "payment method" msgstr "moyen de paiement" -#: models.py:749 +#: cotisations/models.py:772 msgid "payment methods" msgstr "moyens de paiement" -#: models.py:787 payment_methods/comnpay/views.py:63 +#: cotisations/models.py:810 cotisations/payment_methods/comnpay/views.py:63 #, python-format msgid "The subscription of %(member_name)s was extended to %(end_date)s." msgstr "La cotisation de %(member_name)s a été étendue au %(end_date)s." -#: models.py:797 +#: cotisations/models.py:820 msgid "The invoice was created." msgstr "La facture a été créée." -#: models.py:818 +#: cotisations/models.py:841 msgid "You can't use this payment method." msgstr "Vous ne pouvez pas utiliser ce moyen de paiement." -#: models.py:836 +#: cotisations/models.py:859 msgid "No custom payment method." msgstr "Pas de moyen de paiement personnalisé." -#: models.py:871 +#: cotisations/models.py:894 msgid "start date" msgstr "date de début" -#: models.py:874 +#: cotisations/models.py:897 msgid "end date" msgstr "date de fin" -#: models.py:879 +#: cotisations/models.py:902 msgid "Can view a subscription object" msgstr "Peut voir un objet cotisation" -#: models.py:880 +#: cotisations/models.py:903 msgid "Can edit the previous subscriptions" msgstr "Peut modifier les cotisations précédentes" -#: models.py:882 +#: cotisations/models.py:905 msgid "subscription" msgstr "cotisation" -#: models.py:883 +#: cotisations/models.py:906 msgid "subscriptions" msgstr "cotisations" -#: models.py:887 +#: cotisations/models.py:910 msgid "You don't have the right to edit a subscription." msgstr "Vous n'avez pas le droit de modifier une cotisation." -#: models.py:891 +#: cotisations/models.py:914 msgid "" "You don't have the right to edit a subscription already controlled or " "invalidated." @@ -476,11 +487,11 @@ msgstr "" "Vous n'avez pas le droit de modifier une cotisation précédemment contrôlée " "ou invalidée." -#: models.py:898 +#: cotisations/models.py:921 msgid "You don't have the right to delete a subscription." msgstr "Vous n'avez pas le droit de supprimer une cotisation." -#: models.py:901 +#: cotisations/models.py:924 msgid "" "You don't have the right to delete a subscription already controlled or " "invalidated." @@ -488,21 +499,21 @@ msgstr "" "Vous n'avez pas le droit de supprimer une cotisation précédemment contrôlée " "ou invalidée." -#: models.py:909 +#: cotisations/models.py:932 msgid "You don't have the right to view someone else's subscription history." msgstr "" "Vous n'avez pas le droit de voir l'historique des cotisations d'un autre " "utilisateur." -#: payment_methods/balance/models.py:38 +#: cotisations/payment_methods/balance/models.py:38 msgid "user balance" msgstr "solde utilisateur" -#: payment_methods/balance/models.py:47 +#: cotisations/payment_methods/balance/models.py:47 msgid "Minimum balance" msgstr "Solde minimum" -#: payment_methods/balance/models.py:48 +#: cotisations/payment_methods/balance/models.py:48 msgid "" "The minimal amount of money allowed for the balance at the end of a payment. " "You can specify negative amount." @@ -510,84 +521,86 @@ msgstr "" "Le montant minimal d'argent autorisé pour le solde à la fin d'un paiement. " "Vous pouvez renseigner un montant négatif." -#: payment_methods/balance/models.py:57 +#: cotisations/payment_methods/balance/models.py:57 msgid "Maximum balance" msgstr "Solde maximum" -#: payment_methods/balance/models.py:58 +#: cotisations/payment_methods/balance/models.py:58 msgid "The maximal amount of money allowed for the balance." msgstr "Le montant maximal d'argent autorisé pour le solde." -#: payment_methods/balance/models.py:66 +#: cotisations/payment_methods/balance/models.py:66 msgid "Allow user to credit their balance" msgstr "Autorise l'utilisateur à créditer son solde" -#: payment_methods/balance/models.py:79 payment_methods/balance/models.py:110 +#: cotisations/payment_methods/balance/models.py:79 +#: cotisations/payment_methods/balance/models.py:110 msgid "Your balance is too low for this operation." msgstr "Votre solde est trop bas pour cette opération." -#: payment_methods/balance/models.py:97 validators.py:20 +#: cotisations/payment_methods/balance/models.py:97 +#: cotisations/validators.py:20 msgid "There is already a payment method for user balance." msgstr "Il y a déjà un moyen de paiement pour le solde utilisateur." -#: payment_methods/cheque/models.py:36 +#: cotisations/payment_methods/cheque/models.py:36 msgid "Cheque" msgstr "Chèque" -#: payment_methods/cheque/views.py:47 +#: cotisations/payment_methods/cheque/views.py:47 msgid "You can't pay this invoice with a cheque." msgstr "Vous ne pouvez pas payer cette facture avec un chèque." -#: payment_methods/comnpay/models.py:39 +#: cotisations/payment_methods/comnpay/models.py:39 msgid "ComNpay" msgstr "ComNpay" -#: payment_methods/comnpay/models.py:51 +#: cotisations/payment_methods/comnpay/models.py:51 msgid "ComNpay VAT Number" msgstr "Numéro de TVA de ComNpay" -#: payment_methods/comnpay/models.py:57 +#: cotisations/payment_methods/comnpay/models.py:57 msgid "ComNpay secret key" msgstr "Clé secrète de ComNpay" -#: payment_methods/comnpay/models.py:60 +#: cotisations/payment_methods/comnpay/models.py:60 msgid "Minimum payment" msgstr "Paiement minimum" -#: payment_methods/comnpay/models.py:61 +#: cotisations/payment_methods/comnpay/models.py:61 msgid "The minimal amount of money you have to use when paying with ComNpay" msgstr "" "Le montant minimal d'agent que vous devez utiliser en payant avec ComNpay" -#: payment_methods/comnpay/models.py:69 +#: cotisations/payment_methods/comnpay/models.py:69 msgid "Production mode enabled (production URL, instead of homologation)" msgstr "Mode production activé (URL de production, au lieu d'homologation)" -#: payment_methods/comnpay/models.py:102 +#: cotisations/payment_methods/comnpay/models.py:102 msgid "Pay invoice number " msgstr "Payer la facture numéro " -#: payment_methods/comnpay/models.py:114 +#: cotisations/payment_methods/comnpay/models.py:114 msgid "" "In order to pay your invoice with ComNpay, the price must be greater than {} " "€." msgstr "" "Pour payer votre facture avec ComNpay, le prix doit être plus grand que {} €." -#: payment_methods/comnpay/views.py:53 +#: cotisations/payment_methods/comnpay/views.py:53 #, python-format msgid "The payment of %(amount)s € was accepted." msgstr "Le paiement de %(amount)s € a été accepté." -#: payment_methods/comnpay/views.py:84 +#: cotisations/payment_methods/comnpay/views.py:84 msgid "The payment was refused." msgstr "Le paiment a été refusé." -#: payment_methods/forms.py:60 +#: cotisations/payment_methods/forms.py:60 msgid "Special payment method" msgstr "Moyen de paiement spécial" -#: payment_methods/forms.py:61 +#: cotisations/payment_methods/forms.py:61 msgid "" "Warning: you will not be able to change the payment method later. But you " "will be allowed to edit the other options." @@ -595,159 +608,163 @@ msgstr "" "Attention : vous ne pourrez pas changer le moyen de paiement plus tard. Mais " "vous pourrez modifier les autres options." -#: payment_methods/forms.py:72 +#: cotisations/payment_methods/forms.py:72 msgid "no" msgstr "non" -#: payment_methods/note_kfet/forms.py:32 +#: cotisations/payment_methods/note_kfet/forms.py:32 msgid "pseudo note" msgstr "pseudo note" -#: payment_methods/note_kfet/forms.py:35 +#: cotisations/payment_methods/note_kfet/forms.py:35 msgid "Password" msgstr "Mot de passe" -#: payment_methods/note_kfet/models.py:40 +#: cotisations/payment_methods/note_kfet/models.py:40 msgid "NoteKfet" msgstr "NoteKfet" -#: payment_methods/note_kfet/models.py:50 +#: cotisations/payment_methods/note_kfet/models.py:50 msgid "server" msgstr "serveur" -#: payment_methods/note_kfet/views.py:60 +#: cotisations/payment_methods/note_kfet/views.py:60 msgid "Unknown error." msgstr "Erreur inconnue." -#: payment_methods/note_kfet/views.py:88 +#: cotisations/payment_methods/note_kfet/views.py:88 msgid "The payment with note was done." msgstr "Le paiement par note a été effectué." -#: templates/cotisations/aff_article.html:34 +#: cotisations/templates/cotisations/aff_article.html:34 msgid "Price" msgstr "Prix" -#: templates/cotisations/aff_article.html:35 +#: cotisations/templates/cotisations/aff_article.html:35 msgid "Subscription type" msgstr "Type de cotisation" -#: templates/cotisations/aff_article.html:36 +#: cotisations/templates/cotisations/aff_article.html:36 msgid "Duration (in months)" msgstr "Durée (en mois)" -#: templates/cotisations/aff_article.html:37 +#: cotisations/templates/cotisations/aff_article.html:37 msgid "Concerned users" msgstr "Utilisateurs concernés" -#: templates/cotisations/aff_article.html:38 +#: cotisations/templates/cotisations/aff_article.html:38 msgid "Available for everyone" msgstr "Disponible pour tous" -#: templates/cotisations/aff_banque.html:32 +#: cotisations/templates/cotisations/aff_banque.html:32 msgid "Bank" msgstr "Banque" -#: templates/cotisations/aff_cost_estimate.html:39 -#: templates/cotisations/aff_cotisations.html:41 -#: templates/cotisations/aff_custom_invoice.html:39 -#: templates/cotisations/control.html:63 -#: templates/cotisations/edit_facture.html:49 +#: cotisations/templates/cotisations/aff_cost_estimate.html:39 +#: cotisations/templates/cotisations/aff_cotisations.html:41 +#: cotisations/templates/cotisations/aff_custom_invoice.html:39 +#: cotisations/templates/cotisations/control.html:63 +#: cotisations/templates/cotisations/edit_facture.html:49 msgid "Designation" msgstr "Désignation" -#: templates/cotisations/aff_cost_estimate.html:40 -#: templates/cotisations/aff_cotisations.html:42 -#: templates/cotisations/aff_custom_invoice.html:40 -#: templates/cotisations/control.html:64 +#: cotisations/templates/cotisations/aff_cost_estimate.html:40 +#: cotisations/templates/cotisations/aff_cotisations.html:42 +#: cotisations/templates/cotisations/aff_custom_invoice.html:40 +#: cotisations/templates/cotisations/control.html:64 msgid "Total price" msgstr "Prix total" -#: templates/cotisations/aff_cost_estimate.html:50 +#: cotisations/templates/cotisations/aff_cost_estimate.html:50 msgid "Validity" msgstr "Validité" -#: templates/cotisations/aff_cost_estimate.html:54 +#: cotisations/templates/cotisations/aff_cost_estimate.html:54 msgid "Cost estimate ID" msgstr "ID devis" -#: templates/cotisations/aff_cost_estimate.html:58 +#: cotisations/templates/cotisations/aff_cost_estimate.html:58 msgid "Invoice created" msgstr "Facture créée" -#: templates/cotisations/aff_cost_estimate.html:91 -#: templates/cotisations/aff_cotisations.html:81 -#: templates/cotisations/aff_custom_invoice.html:79 +#: cotisations/templates/cotisations/aff_cost_estimate.html:91 +#: cotisations/templates/cotisations/aff_cotisations.html:81 +#: cotisations/templates/cotisations/aff_custom_invoice.html:79 msgid "PDF" msgstr "PDF" -#: templates/cotisations/aff_cotisations.html:38 +#: cotisations/templates/cotisations/aff_cotisations.html:38 msgid "User" msgstr "Utilisateur" -#: templates/cotisations/aff_cotisations.html:52 -#: templates/cotisations/aff_custom_invoice.html:50 -#: templates/cotisations/control.html:56 +#: cotisations/templates/cotisations/aff_cotisations.html:52 +#: cotisations/templates/cotisations/aff_custom_invoice.html:50 +#: cotisations/templates/cotisations/control.html:56 msgid "Invoice ID" msgstr "ID facture" -#: templates/cotisations/aff_cotisations.html:71 +#: cotisations/templates/cotisations/aff_cotisations.html:71 msgid "Controlled invoice" msgstr "Facture contrôlée" -#: templates/cotisations/aff_cotisations.html:84 +#: cotisations/templates/cotisations/aff_cotisations.html:84 msgid "Invalidated invoice" msgstr "Facture invalidée" -#: templates/cotisations/aff_paiement.html:34 +#: cotisations/templates/cotisations/aff_cotisations.html:88 +msgid "Voucher" +msgstr "" + +#: cotisations/templates/cotisations/aff_paiement.html:34 msgid "Is available for everyone" msgstr "Est disponible pour tous" -#: templates/cotisations/aff_paiement.html:35 +#: cotisations/templates/cotisations/aff_paiement.html:35 msgid "Custom payment method" msgstr "Moyen de paiement personnalisé" -#: templates/cotisations/control.html:30 +#: cotisations/templates/cotisations/control.html:30 msgid "Invoice control" msgstr "Contrôle des factures" -#: templates/cotisations/control.html:34 +#: cotisations/templates/cotisations/control.html:34 msgid "Invoice control and validation" msgstr "Contrôle et validation des factures" -#: templates/cotisations/control.html:46 +#: cotisations/templates/cotisations/control.html:46 msgid "Profile" msgstr "Profil" -#: templates/cotisations/control.html:48 +#: cotisations/templates/cotisations/control.html:48 msgid "Last name" msgstr "Nom" -#: templates/cotisations/control.html:52 +#: cotisations/templates/cotisations/control.html:52 msgid "First name" msgstr "Prénom" -#: templates/cotisations/control.html:60 +#: cotisations/templates/cotisations/control.html:60 msgid "User ID" msgstr "ID utilisateur" -#: templates/cotisations/control.html:74 +#: cotisations/templates/cotisations/control.html:74 msgid "Validated" msgstr "Validé" -#: templates/cotisations/control.html:78 +#: cotisations/templates/cotisations/control.html:78 msgid "Controlled" msgstr "Contrôlé" -#: templates/cotisations/control.html:107 views.py:642 views.py:729 -#: views.py:809 +#: cotisations/templates/cotisations/control.html:107 cotisations/views.py:642 +#: cotisations/views.py:729 cotisations/views.py:809 msgid "Edit" msgstr "Modifier" -#: templates/cotisations/delete.html:29 +#: cotisations/templates/cotisations/delete.html:29 msgid "Deletion of subscriptions" msgstr "Suppression de cotisations" -#: templates/cotisations/delete.html:36 +#: cotisations/templates/cotisations/delete.html:36 #, python-format msgid "" "Warning: are you sure you really want to delete this %(object_name)s object " @@ -756,240 +773,241 @@ msgstr "" "Attention: voulez-vous vraiment supprimer cet objet %(object_name)s " "( %(objet)s ) ?" -#: templates/cotisations/delete.html:38 -#: templates/cotisations/edit_facture.html:64 views.py:178 views.py:228 -#: views.py:280 +#: cotisations/templates/cotisations/delete.html:38 +#: cotisations/templates/cotisations/edit_facture.html:64 +#: cotisations/views.py:178 cotisations/views.py:229 cotisations/views.py:281 msgid "Confirm" msgstr "Confirmer" -#: templates/cotisations/edit_facture.html:31 -#: templates/cotisations/facture.html:30 +#: cotisations/templates/cotisations/edit_facture.html:31 +#: cotisations/templates/cotisations/facture.html:30 msgid "Creation and editing of invoices" msgstr "Création et modification de factures" -#: templates/cotisations/edit_facture.html:41 +#: cotisations/templates/cotisations/edit_facture.html:41 msgid "Edit invoice" msgstr "Modifier la facture" -#: templates/cotisations/edit_facture.html:45 -#: templates/cotisations/facture.html:62 -#: templates/cotisations/index_article.html:30 +#: cotisations/templates/cotisations/edit_facture.html:45 +#: cotisations/templates/cotisations/facture.html:62 +#: cotisations/templates/cotisations/index_article.html:30 msgid "Articles" msgstr "Articles" -#: templates/cotisations/facture.html:37 +#: cotisations/templates/cotisations/facture.html:37 msgid "Buy" msgstr "Acheter" -#: templates/cotisations/facture.html:40 +#: cotisations/templates/cotisations/facture.html:40 #, python-format msgid "Maximum allowed balance: %(max_balance)s €" msgstr "Solde maximum autorisé : %(max_balance)s €" -#: templates/cotisations/facture.html:44 +#: cotisations/templates/cotisations/facture.html:44 #, python-format msgid "Current balance: %(balance)s €" msgstr "Solde actuel : %(balance)s €" -#: templates/cotisations/facture.html:76 +#: cotisations/templates/cotisations/facture.html:76 msgid "Add an extra article" msgstr "Ajouter un article supplémentaire" -#: templates/cotisations/facture.html:82 +#: cotisations/templates/cotisations/facture.html:82 msgid "Total price: 0,00 €" msgstr "Prix total : 0,00 €" -#: templates/cotisations/index.html:29 templates/cotisations/sidebar.html:40 +#: cotisations/templates/cotisations/index.html:29 +#: cotisations/templates/cotisations/sidebar.html:40 msgid "Invoices" msgstr "Factures" -#: templates/cotisations/index.html:32 +#: cotisations/templates/cotisations/index.html:32 msgid "Subscriptions" msgstr "Cotisations" -#: templates/cotisations/index_article.html:33 +#: cotisations/templates/cotisations/index_article.html:33 msgid "List of article types" msgstr "Liste des types d'article" -#: templates/cotisations/index_article.html:36 +#: cotisations/templates/cotisations/index_article.html:36 msgid "Add an article type" msgstr "Ajouter un type d'article" -#: templates/cotisations/index_article.html:40 +#: cotisations/templates/cotisations/index_article.html:40 msgid "Delete one or several article types" msgstr "Supprimer un ou plusieurs types d'article" -#: templates/cotisations/index_banque.html:30 -#: templates/cotisations/sidebar.html:60 +#: cotisations/templates/cotisations/index_banque.html:30 +#: cotisations/templates/cotisations/sidebar.html:60 msgid "Banks" msgstr "Banques" -#: templates/cotisations/index_banque.html:33 +#: cotisations/templates/cotisations/index_banque.html:33 msgid "List of banks" msgstr "Liste des banques" -#: templates/cotisations/index_banque.html:36 +#: cotisations/templates/cotisations/index_banque.html:36 msgid "Add a bank" msgstr "Ajouter une banque" -#: templates/cotisations/index_banque.html:40 +#: cotisations/templates/cotisations/index_banque.html:40 msgid "Delete one or several banks" msgstr "Supprimer une ou plusieurs banques" -#: templates/cotisations/index_cost_estimate.html:28 -#: templates/cotisations/sidebar.html:50 +#: cotisations/templates/cotisations/index_cost_estimate.html:28 +#: cotisations/templates/cotisations/sidebar.html:50 msgid "Cost estimates" msgstr "Devis" -#: templates/cotisations/index_cost_estimate.html:31 +#: cotisations/templates/cotisations/index_cost_estimate.html:31 msgid "List of cost estimates" msgstr "Liste des devis" -#: templates/cotisations/index_custom_invoice.html:28 -#: templates/cotisations/sidebar.html:45 +#: cotisations/templates/cotisations/index_custom_invoice.html:28 +#: cotisations/templates/cotisations/sidebar.html:45 msgid "Custom invoices" msgstr "Factures personnalisées" -#: templates/cotisations/index_custom_invoice.html:31 +#: cotisations/templates/cotisations/index_custom_invoice.html:31 msgid "List of custom invoices" msgstr "Liste des factures personnalisées" -#: templates/cotisations/index_paiement.html:30 -#: templates/cotisations/sidebar.html:65 +#: cotisations/templates/cotisations/index_paiement.html:30 +#: cotisations/templates/cotisations/sidebar.html:65 msgid "Payment methods" msgstr "Moyens de paiement" -#: templates/cotisations/index_paiement.html:33 +#: cotisations/templates/cotisations/index_paiement.html:33 msgid "List of payment methods" msgstr "Liste des moyens de paiement" -#: templates/cotisations/index_paiement.html:36 +#: cotisations/templates/cotisations/index_paiement.html:36 msgid "Add a payment method" msgstr "Ajouter un moyen de paiement" -#: templates/cotisations/index_paiement.html:40 +#: cotisations/templates/cotisations/index_paiement.html:40 msgid "Delete one or several payment methods" msgstr "Supprimer un ou plusieurs moyens de paiement" -#: templates/cotisations/payment.html:30 +#: cotisations/templates/cotisations/payment.html:30 msgid "Balance refill" msgstr "Rechargement de solde" -#: templates/cotisations/payment.html:34 +#: cotisations/templates/cotisations/payment.html:34 #, python-format msgid "Pay %(amount)s €" msgstr "Payer %(amount)s €" -#: templates/cotisations/payment.html:42 views.py:1049 +#: cotisations/templates/cotisations/payment.html:42 cotisations/views.py:1051 msgid "Pay" msgstr "Payer" -#: templates/cotisations/sidebar.html:32 +#: cotisations/templates/cotisations/sidebar.html:32 msgid "Create an invoice" msgstr "Créer une facture" -#: templates/cotisations/sidebar.html:35 +#: cotisations/templates/cotisations/sidebar.html:35 msgid "Control the invoices" msgstr "Contrôler les factures" -#: views.py:164 +#: cotisations/views.py:164 msgid "You need to choose at least one article." msgstr "Vous devez choisir au moins un article." -#: views.py:222 +#: cotisations/views.py:223 msgid "The cost estimate was created." msgstr "Le devis a été créé." -#: views.py:232 views.py:534 +#: cotisations/views.py:233 cotisations/views.py:534 msgid "Cost estimate" msgstr "Devis" -#: views.py:274 +#: cotisations/views.py:275 msgid "The custom invoice was created." msgstr "La facture personnalisée a été créée." -#: views.py:363 views.py:466 +#: cotisations/views.py:364 cotisations/views.py:467 msgid "The invoice was edited." msgstr "La facture a été modifiée." -#: views.py:383 views.py:589 +#: cotisations/views.py:384 cotisations/views.py:589 msgid "The invoice was deleted." msgstr "La facture a été supprimée." -#: views.py:388 views.py:594 +#: cotisations/views.py:389 cotisations/views.py:594 msgid "Invoice" msgstr "Facture" -#: views.py:417 +#: cotisations/views.py:418 msgid "The cost estimate was edited." msgstr "Le devis a été modifié." -#: views.py:424 +#: cotisations/views.py:425 msgid "Edit cost estimate" msgstr "Modifier le devis" -#: views.py:436 +#: cotisations/views.py:437 msgid "An invoice was successfully created from your cost estimate." msgstr "Une facture a bien été créée à partir de votre devis." -#: views.py:529 +#: cotisations/views.py:529 msgid "The cost estimate was deleted." msgstr "Le devis a été supprimé." -#: views.py:615 +#: cotisations/views.py:615 msgid "The article was created." msgstr "L'article a été créé." -#: views.py:620 views.py:693 views.py:786 +#: cotisations/views.py:620 cotisations/views.py:693 cotisations/views.py:786 msgid "Add" msgstr "Ajouter" -#: views.py:621 +#: cotisations/views.py:621 msgid "New article" msgstr "Nouvel article" -#: views.py:637 +#: cotisations/views.py:637 msgid "The article was edited." msgstr "L'article a été modifié." -#: views.py:643 +#: cotisations/views.py:643 msgid "Edit article" msgstr "Modifier l'article" -#: views.py:659 +#: cotisations/views.py:659 msgid "The articles were deleted." msgstr "Les articles ont été supprimés." -#: views.py:664 views.py:764 views.py:844 +#: cotisations/views.py:664 cotisations/views.py:764 cotisations/views.py:844 msgid "Delete" msgstr "Supprimer" -#: views.py:665 +#: cotisations/views.py:665 msgid "Delete article" msgstr "Supprimer l'article" -#: views.py:687 +#: cotisations/views.py:687 msgid "The payment method was created." msgstr "Le moyen de paiment a été créé." -#: views.py:694 +#: cotisations/views.py:694 msgid "New payment method" msgstr "Nouveau moyen de paiement" -#: views.py:723 +#: cotisations/views.py:723 msgid "The payment method was edited." msgstr "Le moyen de paiment a été modifié." -#: views.py:730 +#: cotisations/views.py:730 msgid "Edit payment method" msgstr "Modifier le moyen de paiement" -#: views.py:749 +#: cotisations/views.py:749 #, python-format msgid "The payment method %(method_name)s was deleted." msgstr "Le moyen de paiement %(method_name)s a été supprimé." -#: views.py:756 +#: cotisations/views.py:756 #, python-format msgid "" "The payment method %(method_name)s can't be deleted " @@ -998,32 +1016,32 @@ msgstr "" "Le moyen de paiement %(method_name)s ne peut pas être supprimé car il y a " "des factures qui l'utilisent." -#: views.py:765 +#: cotisations/views.py:765 msgid "Delete payment method" msgstr "Supprimer le moyen de paiement" -#: views.py:781 +#: cotisations/views.py:781 msgid "The bank was created." msgstr "La banque a été créée." -#: views.py:787 +#: cotisations/views.py:787 msgid "New bank" msgstr "Nouvelle banque" -#: views.py:804 +#: cotisations/views.py:804 msgid "The bank was edited." msgstr "La banque a été modifiée." -#: views.py:810 +#: cotisations/views.py:810 msgid "Edit bank" msgstr "Modifier la banque" -#: views.py:829 +#: cotisations/views.py:829 #, python-format msgid "The bank %(bank_name)s was deleted." msgstr "La banque %(bank_name)s a été supprimée." -#: views.py:836 +#: cotisations/views.py:836 #, python-format msgid "" "The bank %(bank_name)s can't be deleted because there are invoices using it." @@ -1031,18 +1049,22 @@ msgstr "" "La banque %(bank_name)s ne peut pas être supprimée car il y a des factures " "qui l'utilisent." -#: views.py:845 +#: cotisations/views.py:845 msgid "Delete bank" msgstr "Supprimer la banque" -#: views.py:881 +#: cotisations/views.py:881 msgid "Your changes have been properly taken into account." msgstr "Vos modifications ont correctement été prises en compte." -#: views.py:1016 +#: cotisations/views.py:1017 msgid "You are not allowed to credit your balance." msgstr "Vous n'êtes pas autorisés à créditer votre solde." -#: views.py:1048 +#: cotisations/views.py:1050 msgid "Refill your balance" msgstr "Recharger votre solde" + +#: cotisations/views.py:1068 +msgid "Could not find a voucher for that invoice." +msgstr "" diff --git a/logs/locale/fr/LC_MESSAGES/django.po b/logs/locale/fr/LC_MESSAGES/django.po index 807bda76..1448c6bf 100644 --- a/logs/locale/fr/LC_MESSAGES/django.po +++ b/logs/locale/fr/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: 2.5\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-08 23:16+0100\n" +"POT-Creation-Date: 2019-02-12 08:58+0100\n" "PO-Revision-Date: 2018-06-23 16:01+0200\n" "Last-Translator: Laouen Fernet \n" "Language-Team: \n" @@ -30,111 +30,115 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: acl.py:42 +#: logs/acl.py:42 msgid "You don't have the right to view this application." msgstr "Vous n'avez pas le droit de voir cette application." -#: templates/logs/aff_stats_logs.html:36 +#: logs/templates/logs/aff_stats_logs.html:36 msgid "Edited object" msgstr "Objet modifié" -#: templates/logs/aff_stats_logs.html:37 -#: templates/logs/aff_stats_models.html:32 +#: logs/templates/logs/aff_stats_logs.html:37 +#: logs/templates/logs/aff_stats_models.html:32 msgid "Object type" msgstr "Type d'objet" -#: templates/logs/aff_stats_logs.html:38 +#: logs/templates/logs/aff_stats_logs.html:38 msgid "Edited by" msgstr "Modifié par" -#: templates/logs/aff_stats_logs.html:40 +#: logs/templates/logs/aff_stats_logs.html:40 msgid "Date of editing" msgstr "Date de modification" -#: templates/logs/aff_stats_logs.html:42 +#: logs/templates/logs/aff_stats_logs.html:42 msgid "Comment" msgstr "Commentaire" -#: templates/logs/aff_stats_logs.html:58 templates/logs/aff_summary.html:62 -#: templates/logs/aff_summary.html:85 templates/logs/aff_summary.html:104 -#: templates/logs/aff_summary.html:128 templates/logs/aff_summary.html:147 +#: logs/templates/logs/aff_stats_logs.html:58 +#: logs/templates/logs/aff_summary.html:62 +#: logs/templates/logs/aff_summary.html:85 +#: logs/templates/logs/aff_summary.html:104 +#: logs/templates/logs/aff_summary.html:128 +#: logs/templates/logs/aff_summary.html:147 msgid "Cancel" msgstr "Annuler" -#: templates/logs/aff_stats_models.html:29 +#: logs/templates/logs/aff_stats_models.html:29 #, python-format msgid "Statistics of the set %(key)s" msgstr "Statistiques de l'ensemble %(key)s" -#: templates/logs/aff_stats_models.html:33 +#: logs/templates/logs/aff_stats_models.html:33 msgid "Number of stored entries" msgstr "Nombre d'entrées enregistrées" -#: templates/logs/aff_stats_users.html:31 +#: logs/templates/logs/aff_stats_users.html:31 #, python-format msgid "Statistics per %(key_dict)s of %(key)s" msgstr "Statistiques par %(key_dict)s de %(key)s" -#: templates/logs/aff_stats_users.html:34 +#: logs/templates/logs/aff_stats_users.html:34 #, python-format msgid "Number of %(key)s per %(key_dict)s" msgstr "Nombre de %(key)s par %(key_dict)s" -#: templates/logs/aff_stats_users.html:35 +#: logs/templates/logs/aff_stats_users.html:35 msgid "Rank" msgstr "Rang" -#: templates/logs/aff_summary.html:37 +#: logs/templates/logs/aff_summary.html:37 msgid "Date" msgstr "Date" -#: templates/logs/aff_summary.html:39 +#: logs/templates/logs/aff_summary.html:39 msgid "Editing" msgstr "Modification" -#: templates/logs/aff_summary.html:48 +#: logs/templates/logs/aff_summary.html:48 #, python-format msgid "%(username)s has banned" msgstr "%(username)s a banni" -#: templates/logs/aff_summary.html:52 templates/logs/aff_summary.html:75 +#: logs/templates/logs/aff_summary.html:52 +#: logs/templates/logs/aff_summary.html:75 msgid "No reason" msgstr "Aucun motif" -#: templates/logs/aff_summary.html:71 +#: logs/templates/logs/aff_summary.html:71 #, python-format msgid "%(username)s has graciously authorised" msgstr "%(username)s a autorisé gracieusement" -#: templates/logs/aff_summary.html:94 +#: logs/templates/logs/aff_summary.html:94 #, python-format msgid "%(username)s has updated" msgstr "%(username)s a mis à jour" -#: templates/logs/aff_summary.html:113 +#: logs/templates/logs/aff_summary.html:113 #, python-format msgid "%(username)s has sold %(number)sx %(name)s" msgstr "%(username)s a vendu %(number)sx %(name)s" -#: templates/logs/aff_summary.html:116 +#: logs/templates/logs/aff_summary.html:116 msgid " to" msgstr " à" -#: templates/logs/aff_summary.html:119 +#: logs/templates/logs/aff_summary.html:119 #, python-format msgid "+%(duration)s months" msgstr "+%(duration)s mois" -#: templates/logs/aff_summary.html:137 +#: logs/templates/logs/aff_summary.html:137 #, python-format msgid "%(username)s has edited an interface of" msgstr "%(username)s a modifié une interface de" -#: templates/logs/delete.html:29 +#: logs/templates/logs/delete.html:29 msgid "Deletion of actions" msgstr "Suppression d'actions" -#: templates/logs/delete.html:35 +#: logs/templates/logs/delete.html:35 #, python-format msgid "" "Warning: are you sure you want to delete this action %(objet_name)s " @@ -143,204 +147,207 @@ msgstr "" "Attention: voulez-vous vraiment supprimer cette action %(objet_name)s " "( %(objet)s ) ?" -#: templates/logs/delete.html:36 +#: logs/templates/logs/delete.html:36 msgid "Confirm" msgstr "Confirmer" -#: templates/logs/index.html:29 templates/logs/stats_general.html:29 -#: templates/logs/stats_logs.html:29 templates/logs/stats_models.html:29 -#: templates/logs/stats_users.html:29 +#: logs/templates/logs/index.html:29 logs/templates/logs/stats_general.html:29 +#: logs/templates/logs/stats_logs.html:29 +#: logs/templates/logs/stats_models.html:29 +#: logs/templates/logs/stats_users.html:29 msgid "Statistics" msgstr "Statistiques" -#: templates/logs/index.html:32 templates/logs/stats_logs.html:32 views.py:414 +#: logs/templates/logs/index.html:32 logs/templates/logs/stats_logs.html:32 +#: logs/views.py:414 msgid "Actions performed" msgstr "Actions effectuées" -#: templates/logs/sidebar.html:33 +#: logs/templates/logs/sidebar.html:33 msgid "Summary" msgstr "Résumé" -#: templates/logs/sidebar.html:37 +#: logs/templates/logs/sidebar.html:37 msgid "Events" msgstr "Évènements" -#: templates/logs/sidebar.html:41 +#: logs/templates/logs/sidebar.html:41 msgid "General" msgstr "Général" -#: templates/logs/sidebar.html:45 +#: logs/templates/logs/sidebar.html:45 msgid "Database" msgstr "Base de données" -#: templates/logs/sidebar.html:49 +#: logs/templates/logs/sidebar.html:49 msgid "Wiring actions" msgstr "Actions de câblage" -#: templates/logs/sidebar.html:53 views.py:336 +#: logs/templates/logs/sidebar.html:53 logs/views.py:336 msgid "Users" msgstr "Utilisateurs" -#: templates/logs/stats_general.html:32 +#: logs/templates/logs/stats_general.html:32 msgid "General statistics" msgstr "Statistiques générales" -#: templates/logs/stats_models.html:32 +#: logs/templates/logs/stats_models.html:32 msgid "Database statistics" msgstr "Statistiques sur la base de données" -#: templates/logs/stats_users.html:32 +#: logs/templates/logs/stats_users.html:32 msgid "Statistics about users" msgstr "Statistiques sur les utilisateurs" -#: views.py:194 +#: logs/views.py:194 msgid "Nonexistent revision." msgstr "Révision inexistante." -#: views.py:197 +#: logs/views.py:197 msgid "The action was deleted." msgstr "L'action a été supprimée." -#: views.py:230 +#: logs/views.py:230 msgid "Category" msgstr "Catégorie" -#: views.py:231 +#: logs/views.py:231 msgid "Number of users (members and clubs)" msgstr "Nombre d'utilisateurs (adhérents et clubs)" -#: views.py:232 +#: logs/views.py:232 msgid "Number of members" msgstr "Nombre d'adhérents" -#: views.py:233 +#: logs/views.py:233 msgid "Number of clubs" msgstr "Nombre de clubs" -#: views.py:237 +#: logs/views.py:237 msgid "Activated users" msgstr "Utilisateurs activés" -#: views.py:245 +#: logs/views.py:245 msgid "Disabled users" msgstr "Utilisateurs désactivés" -#: views.py:253 +#: logs/views.py:253 msgid "Archived users" msgstr "Utilisateurs archivés" -#: views.py:261 +#: logs/views.py:261 msgid "Not yet active users" msgstr "Utilisateurs pas encore actifs" -#: views.py:269 +#: logs/views.py:269 msgid "Contributing members" msgstr "Adhérents cotisants" -#: views.py:275 +#: logs/views.py:275 msgid "Users benefiting from a connection" msgstr "Utilisateurs bénéficiant d'une connexion" -#: views.py:281 +#: logs/views.py:281 msgid "Banned users" msgstr "Utilisateurs bannis" -#: views.py:287 +#: logs/views.py:287 msgid "Users benefiting from a free connection" msgstr "Utilisateurs bénéficiant d'une connexion gratuite" -#: views.py:293 +#: logs/views.py:293 msgid "Active interfaces (with access to the network)" msgstr "Interfaces actives (ayant accès au réseau)" -#: views.py:303 +#: logs/views.py:303 msgid "Active interfaces assigned IPv4" msgstr "Interfaces actives assignées IPv4" -#: views.py:316 +#: logs/views.py:316 msgid "IP range" msgstr "Plage d'IP" -#: views.py:317 +#: logs/views.py:317 msgid "VLAN" msgstr "VLAN" -#: views.py:318 +#: logs/views.py:318 msgid "Total number of IP addresses" msgstr "Nombre total d'adresses IP" -#: views.py:319 +#: logs/views.py:319 msgid "Number of assigned IP addresses" msgstr "Nombre d'adresses IP non assignées" -#: views.py:320 +#: logs/views.py:320 msgid "Number of IP address assigned to an activated machine" msgstr "Nombre d'adresses IP assignées à une machine activée" -#: views.py:321 +#: logs/views.py:321 msgid "Number of nonassigned IP addresses" msgstr "Nombre d'adresses IP non assignées" -#: views.py:348 +#: logs/views.py:348 msgid "Subscriptions" msgstr "Cotisations" -#: views.py:370 views.py:431 +#: logs/views.py:370 logs/views.py:431 msgid "Machines" msgstr "Machines" -#: views.py:397 +#: logs/views.py:397 msgid "Topology" msgstr "Topologie" -#: views.py:416 +#: logs/views.py:416 msgid "Number of actions" msgstr "Nombre d'actions" -#: views.py:430 views.py:448 views.py:453 views.py:458 views.py:473 +#: logs/views.py:430 logs/views.py:448 logs/views.py:453 logs/views.py:458 +#: logs/views.py:473 msgid "User" msgstr "Utilisateur" -#: views.py:434 +#: logs/views.py:434 msgid "Invoice" msgstr "Facture" -#: views.py:437 +#: logs/views.py:437 msgid "Ban" msgstr "Bannissement" -#: views.py:440 +#: logs/views.py:440 msgid "Whitelist" msgstr "Accès gracieux" -#: views.py:443 +#: logs/views.py:443 msgid "Rights" msgstr "Droits" -#: views.py:447 +#: logs/views.py:447 msgid "School" msgstr "Établissement" -#: views.py:452 +#: logs/views.py:452 msgid "Payment method" msgstr "Moyen de paiement" -#: views.py:457 +#: logs/views.py:457 msgid "Bank" msgstr "Banque" -#: views.py:474 +#: logs/views.py:474 msgid "Action" msgstr "Action" -#: views.py:505 +#: logs/views.py:505 msgid "No model found." msgstr "Aucun modèle trouvé." -#: views.py:511 +#: logs/views.py:511 msgid "Nonexistent entry." msgstr "Entrée inexistante." -#: views.py:518 +#: logs/views.py:518 msgid "You don't have the right to access this menu." msgstr "Vous n'avez pas le droit d'accéder à ce menu." diff --git a/machines/locale/fr/LC_MESSAGES/django.po b/machines/locale/fr/LC_MESSAGES/django.po index bd36fb61..3078604b 100644 --- a/machines/locale/fr/LC_MESSAGES/django.po +++ b/machines/locale/fr/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: 2.5\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-12 16:43+0100\n" +"POT-Creation-Date: 2019-02-12 08:58+0100\n" "PO-Revision-Date: 2018-06-23 16:35+0200\n" "Last-Translator: Laouen Fernet \n" "Language-Team: \n" @@ -30,160 +30,160 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: acl.py:42 +#: machines/acl.py:42 msgid "You don't have the right to view this application." msgstr "Vous n'avez pas le droit de voir cette application." -#: forms.py:78 +#: machines/forms.py:78 msgid "Machine name" msgstr "Nom de la machine" -#: forms.py:99 templates/machines/aff_machines.html:46 +#: machines/forms.py:99 machines/templates/machines/aff_machines.html:46 msgid "MAC address" msgstr "Adresse MAC" -#: forms.py:100 templates/machines/aff_machinetype.html:32 -#: templates/machines/machine.html:112 +#: machines/forms.py:100 machines/templates/machines/aff_machinetype.html:32 +#: machines/templates/machines/machine.html:112 msgid "Machine type" msgstr "Type de machine" -#: forms.py:101 +#: machines/forms.py:101 msgid "Select a machine type" msgstr "Sélectionnez un type de machine" -#: forms.py:103 +#: machines/forms.py:103 msgid "Automatic IPv4 assignment" msgstr "Assignation automatique IPv4" -#: forms.py:177 +#: machines/forms.py:177 msgid "Current aliases" msgstr "Alias actuels" -#: forms.py:199 +#: machines/forms.py:199 msgid "Machine type to add" msgstr "Type de machine à ajouter" -#: forms.py:200 +#: machines/forms.py:200 msgid "Related IP type" msgstr "Type d'IP relié" -#: forms.py:207 +#: machines/forms.py:207 msgid "Current machine types" msgstr "Types de machines actuels" -#: forms.py:231 +#: machines/forms.py:231 msgid "IP type to add" msgstr "Type d'IP à ajouter" -#: forms.py:249 +#: machines/forms.py:249 msgid "Current IP types" msgstr "Types d'IP actuels" -#: forms.py:272 +#: machines/forms.py:272 msgid "Extension to add" msgstr "Extension à ajouter" -#: forms.py:273 templates/machines/aff_extension.html:37 +#: machines/forms.py:273 machines/templates/machines/aff_extension.html:37 msgid "A record origin" msgstr "Enregistrement A origin" -#: forms.py:274 templates/machines/aff_extension.html:39 +#: machines/forms.py:274 machines/templates/machines/aff_extension.html:39 msgid "AAAA record origin" msgstr "Enregistrement AAAA origin" -#: forms.py:275 +#: machines/forms.py:275 msgid "SOA record to use" msgstr "Enregistrement SOA à utiliser" -#: forms.py:276 +#: machines/forms.py:276 msgid "Sign with DNSSEC" msgstr "Signer avec DNSSEC" -#: forms.py:283 +#: machines/forms.py:283 msgid "Current extensions" msgstr "Extensions actuelles" -#: forms.py:324 +#: machines/forms.py:324 msgid "Current SOA records" msgstr "Enregistrements SOA actuels" -#: forms.py:356 +#: machines/forms.py:356 msgid "Current MX records" msgstr "Enregistrements MX actuels" -#: forms.py:390 +#: machines/forms.py:390 msgid "Current NS records" msgstr "Enregistrements NS actuels" -#: forms.py:419 +#: machines/forms.py:419 msgid "Current TXT records" msgstr "Enregistrements TXT actuels" -#: forms.py:448 +#: machines/forms.py:448 msgid "Current DNAME records" msgstr "Enregistrements DNAME actuels" -#: forms.py:477 +#: machines/forms.py:477 msgid "Current SRV records" msgstr "Enregistrements SRV actuels" -#: forms.py:507 +#: machines/forms.py:507 msgid "Current NAS devices" msgstr "Dispositifs NAS actuels" -#: forms.py:540 +#: machines/forms.py:540 msgid "Current roles" msgstr "Rôles actuels" -#: forms.py:582 +#: machines/forms.py:582 msgid "Current services" msgstr "Services actuels" -#: forms.py:622 +#: machines/forms.py:622 msgid "Current VLANs" msgstr "VLANs actuels" -#: models.py:61 +#: machines/models.py:61 msgid "Optional" msgstr "Optionnel" -#: models.py:69 +#: machines/models.py:69 msgid "Can view a machine object" msgstr "Peut voir un objet machine" -#: models.py:71 +#: machines/models.py:71 msgid "Can change the user of a machine" msgstr "Peut changer l'utilisateur d'une machine" -#: models.py:73 +#: machines/models.py:73 msgid "machine" msgstr "machine" -#: models.py:74 +#: machines/models.py:74 msgid "machines" msgstr "machines" -#: models.py:107 +#: machines/models.py:107 msgid "You don't have the right to change the machine's user." msgstr "Vous n'avez pas le droit de changer l'utilisateur de la machine." -#: models.py:116 +#: machines/models.py:116 msgid "You don't have the right to view all the machines." msgstr "Vous n'avez pas le droit de voir toutes les machines." -#: models.py:130 +#: machines/models.py:130 msgid "Nonexistent user." msgstr "Utilisateur inexistant." -#: models.py:138 +#: machines/models.py:138 msgid "You don't have the right to add a machine." msgstr "Vous n'avez pas le droit d'ajouter une machine." -#: models.py:140 +#: machines/models.py:140 msgid "You don't have the right to add a machine to another user." msgstr "Vous n'avez pas le droit d'ajouter une machine à un autre utilisateur." -#: models.py:143 models.py:1182 +#: machines/models.py:143 machines/models.py:1212 #, python-format msgid "" "You reached the maximum number of interfaces that you are allowed to create " @@ -192,78 +192,79 @@ msgstr "" "Vous avez atteint le nombre maximal d'interfaces que vous pouvez créer vous-" "même (%s)." -#: models.py:162 models.py:1207 models.py:1224 models.py:1326 models.py:1343 +#: machines/models.py:162 machines/models.py:1237 machines/models.py:1254 +#: machines/models.py:1343 machines/models.py:1360 msgid "You don't have the right to edit a machine of another user." msgstr "" "Vous n'avez pas le droit de modifier une machine d'un autre utilisateur." -#: models.py:180 +#: machines/models.py:180 msgid "You don't have the right to delete a machine of another user." msgstr "" "Vous n'avez pas le droit de supprimer une machine d'une autre utilisateur." -#: models.py:192 +#: machines/models.py:192 msgid "You don't have the right to view other machines than yours." msgstr "Vous n'avez pas le droit de voir d'autres machines que les vôtres." -#: models.py:204 templates/machines/aff_machines.html:53 +#: machines/models.py:204 machines/templates/machines/aff_machines.html:53 msgid "No name" msgstr "Sans nom" -#: models.py:254 +#: machines/models.py:254 msgid "Can view a machine type object" msgstr "Peut voir un objet type de machine" -#: models.py:255 +#: machines/models.py:255 msgid "Can use all machine types" msgstr "Peut utiliser tous les types de machine" -#: models.py:257 +#: machines/models.py:257 msgid "machine type" msgstr "type de machine" -#: models.py:258 +#: machines/models.py:258 msgid "machine types" msgstr "types de machine" -#: models.py:276 +#: machines/models.py:276 msgid "You don't have the right to use all machine types." msgstr "Vous n'avez pas le droit d'utiliser tous les types de machine." -#: models.py:295 +#: machines/models.py:295 msgid "Network containing the domain's IPv4 range (optional)" msgstr "Réseau contenant la plage IPv4 du domaine (optionnel)" -#: models.py:303 +#: machines/models.py:303 msgid "Netmask for the domain's IPv4 range" msgstr "Masque de sous-réseau pour la plage IPv4 du domaine" -#: models.py:307 +#: machines/models.py:307 msgid "Enable reverse DNS for IPv4" msgstr "Activer DNS inverse pour IPv4" -#: models.py:323 +#: machines/models.py:323 msgid "Enable reverse DNS for IPv6" msgstr "Activer DNS inverse pour IPv6" -#: models.py:339 +#: machines/models.py:339 msgid "Can view an IP type object" msgstr "Peut voir un objet type d'IP" -#: models.py:340 +#: machines/models.py:340 msgid "Can use all IP types" msgstr "Peut utiliser tous les types d'IP" -#: models.py:342 templates/machines/aff_iptype.html:35 -#: templates/machines/machine.html:108 +#: machines/models.py:342 machines/templates/machines/aff_iptype.html:35 +#: machines/templates/machines/machine.html:108 msgid "IP type" msgstr "type d'IP" -#: models.py:343 +#: machines/models.py:343 msgid "IP types" msgstr "types d'IP" -#: models.py:446 +#: machines/models.py:446 msgid "" "One or several IP addresses from the range are affected, impossible to " "delete the range." @@ -271,21 +272,21 @@ msgstr "" "Une ou plusieurs adresses IP de la plage sont affectées, impossible de " "supprimer la plage." -#: models.py:488 +#: machines/models.py:488 msgid "Range end must be after range start..." msgstr "La fin de la plage doit être après le début..." -#: models.py:491 +#: machines/models.py:491 msgid "The range is too large, you can't create a larger one than a /16." msgstr "" "La plage est trop grande, vous ne pouvez pas en créer une plus grande " "qu'un /16." -#: models.py:496 +#: machines/models.py:496 msgid "The specified range is not disjoint from existing ranges." msgstr "La plage renseignée n'est pas disjointe des plages existantes." -#: models.py:504 +#: machines/models.py:504 msgid "" "If you specify a domain network or netmask, it must contain the domain's IP " "range." @@ -293,47 +294,47 @@ msgstr "" "Si vous renseignez un réseau ou masque de sous-réseau, il doit contenir la " "plage IP du domaine." -#: models.py:537 +#: machines/models.py:537 msgid "v4 multicast management" msgstr "gestion de multidiffusion v4" -#: models.py:541 +#: machines/models.py:541 msgid "v6 multicast management" msgstr "gestion de multidiffusion v6" -#: models.py:546 +#: machines/models.py:546 msgid "Can view a VLAN object" msgstr "Peut voir un objet VLAN" -#: models.py:548 templates/machines/machine.html:160 +#: machines/models.py:548 machines/templates/machines/machine.html:160 msgid "VLAN" msgstr "VLAN" -#: models.py:549 templates/machines/sidebar.html:57 +#: machines/models.py:549 machines/templates/machines/sidebar.html:57 msgid "VLANs" msgstr "VLANs" -#: models.py:562 +#: machines/models.py:562 msgid "MAC-address" msgstr "MAC-address" -#: models.py:585 +#: machines/models.py:585 msgid "Can view a NAS device object" msgstr "Peut voir un objet dispositif NAS" -#: models.py:587 templates/machines/machine.html:164 +#: machines/models.py:587 machines/templates/machines/machine.html:164 msgid "NAS device" msgstr "dispositif NAS" -#: models.py:588 templates/machines/sidebar.html:63 +#: machines/models.py:588 machines/templates/machines/sidebar.html:63 msgid "NAS devices" msgstr "dispositifs NAS" -#: models.py:602 +#: machines/models.py:602 msgid "Contact email address for the zone" msgstr "Adresse mail de contact pour la zone" -#: models.py:606 +#: machines/models.py:606 msgid "" "Seconds before the secondary DNS have to ask the primary DNS serial to " "detect a modification" @@ -341,7 +342,7 @@ msgstr "" "Secondes avant que le DNS secondaire demande au DNS primaire le serial pour " "détecter une modification" -#: models.py:611 +#: machines/models.py:611 msgid "" "Seconds before the secondary DNS ask the serial again in case of a primary " "DNS timeout" @@ -349,7 +350,7 @@ msgstr "" "Secondes avant que le DNS secondaire demande le serial de nouveau dans le " "cas d'un délai d'attente du DNS primaire" -#: models.py:616 +#: machines/models.py:616 msgid "" "Seconds before the secondary DNS stop answering requests in case of primary " "DNS timeout" @@ -357,112 +358,112 @@ msgstr "" "Secondes avant que le DNS secondaire arrête de répondre aux requêtes dans le " "cas d'un délai d'attente du DNS primaire" -#: models.py:621 models.py:878 +#: machines/models.py:621 machines/models.py:878 msgid "Time to Live" msgstr "Temps de vie" -#: models.py:626 +#: machines/models.py:626 msgid "Can view an SOA record object" msgstr "Peut voir un objet enregistrement SOA" -#: models.py:628 templates/machines/aff_extension.html:36 -#: templates/machines/machine.html:120 +#: machines/models.py:628 machines/templates/machines/aff_extension.html:36 +#: machines/templates/machines/machine.html:120 msgid "SOA record" msgstr "enregistrement SOA" -#: models.py:629 +#: machines/models.py:629 msgid "SOA records" msgstr "enregistrements SOA" -#: models.py:668 +#: machines/models.py:668 msgid "SOA to edit" msgstr "SOA à modifier" -#: models.py:679 +#: machines/models.py:679 msgid "Zone name, must begin with a dot (.example.org)" msgstr "Nom de zone, doit commencer par un point (.example.org)" -#: models.py:687 +#: machines/models.py:687 msgid "A record associated with the zone" msgstr "Enregistrement A associé à la zone" -#: models.py:693 +#: machines/models.py:693 msgid "AAAA record associated with the zone" msgstr "Enregristrement AAAA associé avec la zone" -#: models.py:701 +#: machines/models.py:701 msgid "Should the zone be signed with DNSSEC" msgstr "La zone doit-elle être signée avec DNSSEC" -#: models.py:706 +#: machines/models.py:706 msgid "Can view an extension object" msgstr "Peut voir un objet extension" -#: models.py:707 +#: machines/models.py:707 msgid "Can use all extensions" msgstr "Peut utiliser toutes les extensions" -#: models.py:709 +#: machines/models.py:709 msgid "DNS extension" msgstr "extension DNS" -#: models.py:710 +#: machines/models.py:710 msgid "DNS extensions" msgstr "extensions DNS" -#: models.py:764 +#: machines/models.py:764 msgid "An extension must begin with a dot." msgstr "Une extension doit commencer par un point." -#: models.py:778 +#: machines/models.py:778 msgid "Can view an MX record object" msgstr "Peut voir un objet enregistrement MX" -#: models.py:780 templates/machines/machine.html:124 +#: machines/models.py:780 machines/templates/machines/machine.html:124 msgid "MX record" msgstr "enregistrement MX" -#: models.py:781 +#: machines/models.py:781 msgid "MX records" msgstr "enregistrements MX" -#: models.py:803 +#: machines/models.py:803 msgid "Can view an NS record object" msgstr "Peut voir un objet enregistrement NS" -#: models.py:805 templates/machines/machine.html:128 +#: machines/models.py:805 machines/templates/machines/machine.html:128 msgid "NS record" msgstr "enregistrement NS" -#: models.py:806 +#: machines/models.py:806 msgid "NS records" msgstr "enregistrements NS" -#: models.py:825 +#: machines/models.py:825 msgid "Can view a TXT record object" msgstr "Peut voir un objet enregistrement TXT" -#: models.py:827 templates/machines/machine.html:132 +#: machines/models.py:827 machines/templates/machines/machine.html:132 msgid "TXT record" msgstr "enregistrement TXT" -#: models.py:828 +#: machines/models.py:828 msgid "TXT records" msgstr "enregistrements TXT" -#: models.py:847 +#: machines/models.py:847 msgid "Can view a DNAME record object" msgstr "Peut voir un objet enregistrement DNAME" -#: models.py:849 templates/machines/machine.html:136 +#: machines/models.py:849 machines/templates/machines/machine.html:136 msgid "DNAME record" msgstr "enregistrement DNAME" -#: models.py:850 +#: machines/models.py:850 msgid "DNAME records" msgstr "enregistrements DNAME" -#: models.py:883 +#: machines/models.py:883 msgid "" "Priority of the target server (positive integer value, the lower it is, the " "more the server will be used if available)" @@ -470,7 +471,7 @@ msgstr "" "Priorité du serveur cible (entier positif, plus il est bas, plus le serveur " "sera utilisé si disponible)" -#: models.py:890 +#: machines/models.py:890 msgid "" "Relative weight for records with the same priority (integer value between 0 " "and 65535)" @@ -478,137 +479,141 @@ msgstr "" "Poids relatif des enregistrements avec la même priorité (entier entre 0 et " "65535)" -#: models.py:895 +#: machines/models.py:895 msgid "TCP/UDP port" msgstr "Port TCP/UDP" -#: models.py:900 +#: machines/models.py:900 msgid "Target server" msgstr "Serveur cible" -#: models.py:905 +#: machines/models.py:905 msgid "Can view an SRV record object" msgstr "Peut voir un objet enregistrement SRV" -#: models.py:907 templates/machines/machine.html:140 +#: machines/models.py:907 machines/templates/machines/machine.html:140 msgid "SRV record" msgstr "enregistrement SRV" -#: models.py:908 +#: machines/models.py:908 msgid "SRV records" msgstr "enregistrements SRV" -#: models.py:937 templates/machines/aff_sshfp.html:31 +#: machines/models.py:937 machines/templates/machines/aff_sshfp.html:31 msgid "SSH public key" msgstr "Clé publique SSH" -#: models.py:945 templates/machines/aff_sshfp.html:33 -#: templates/machines/aff_vlan.html:35 +#: machines/models.py:945 machines/templates/machines/aff_sshfp.html:33 +#: machines/templates/machines/aff_vlan.html:35 msgid "Comment" msgstr "Commentaire" -#: models.py:972 +#: machines/models.py:972 msgid "Can view an SSHFP record object" msgstr "Peut voir un objet enregistrement SSHFP" -#: models.py:974 templates/machines/machine.html:144 +#: machines/models.py:974 machines/templates/machines/machine.html:144 msgid "SSHFP record" msgstr "enregistrement SSHFP" -#: models.py:975 +#: machines/models.py:975 msgid "SSHFP records" msgstr "enregistrements SSHFP" -#: models.py:1012 +#: machines/models.py:1012 msgid "Can view an interface object" msgstr "Peut voir un objet interface" -#: models.py:1014 +#: machines/models.py:1014 msgid "Can change the owner of an interface" msgstr "Peut changer l'utilisateur d'une interface" -#: models.py:1016 +#: machines/models.py:1016 msgid "interface" msgstr "interface" -#: models.py:1017 +#: machines/models.py:1017 msgid "interfaces" msgstr "interfaces" -#: models.py:1111 +#: machines/models.py:1121 msgid "The given MAC address is invalid." msgstr "L'adresse MAC indiquée est invalide." -#: models.py:1124 -msgid "The selected IP type is invalid." -msgstr "Le type d'IP sélectionné est invalide." - -#: models.py:1136 +#: machines/models.py:1129 msgid "There is no IP address available in the slash." msgstr "Il n'y a pas d'adresse IP disponible dans le slash." -#: models.py:1154 +#: machines/models.py:1166 +msgid "The selected IP type is invalid." +msgstr "Le type d'IP sélectionné est invalide." + +#: machines/models.py:1176 +msgid "Mac address already registered in this Machine Type/Subnet" +msgstr "" + +#: machines/models.py:1183 msgid "The IPv4 address and the machine type don't match." msgstr "L'adresse IPv4 et le type de machine ne correspondent pas." -#: models.py:1168 +#: machines/models.py:1198 msgid "Nonexistent machine." msgstr "Machine inexistante." -#: models.py:1172 +#: machines/models.py:1202 msgid "You can't add a machine." msgstr "Vous ne pouvez pas ajouter une machine." -#: models.py:1178 +#: machines/models.py:1208 msgid "" "You don't have the right to add an interface to a machine of another user." msgstr "" "Vous n'avez pas le droit d'ajouter une interface à une machine d'un autre " "utilisateur." -#: models.py:1192 +#: machines/models.py:1222 msgid "Permission required to edit the machine." msgstr "Permission requise pour modifier la machine." -#: models.py:1236 models.py:1355 models.py:1565 +#: machines/models.py:1266 machines/models.py:1372 machines/models.py:1582 msgid "You don't have the right to view machines other than yours." msgstr "Vous n'avez pas le droit de voir d'autres machines que les vôtres." -#: models.py:1282 +#: machines/models.py:1299 msgid "Can view an IPv6 addresses list object" msgstr "Peut voir un objet list d'adresses IPv6" -#: models.py:1283 +#: machines/models.py:1300 msgid "Can change the SLAAC value of an IPv6 addresses list" msgstr "Peut modifier la valeur SLAAC d'une liste d'adresses IPv6" -#: models.py:1286 +#: machines/models.py:1303 msgid "IPv6 addresses list" msgstr "Liste d'adresses IPv6" -#: models.py:1287 +#: machines/models.py:1304 msgid "IPv6 addresses lists" msgstr "Listes d'adresses IPv6" -#: models.py:1299 models.py:1513 +#: machines/models.py:1316 machines/models.py:1530 msgid "Nonexistent interface." msgstr "Interface inexistante." -#: models.py:1302 models.py:1520 +#: machines/models.py:1319 machines/models.py:1537 msgid "You don't have the right to add an alias to a machine of another user." msgstr "" "Vous n'avez pas le droit d'ajouter un alias à une machine d'un autre " "utilisateur." -#: models.py:1310 +#: machines/models.py:1327 msgid "Permission required to change the SLAAC value of an IPv6 address" msgstr "Permission requise pour changer la valeur SLAAC d'une adresse IPv6." -#: models.py:1382 +#: machines/models.py:1399 msgid "A SLAAC IP address is already registered." msgstr "Une adresse IP SLAAC est déjà enregistrée." -#: models.py:1390 +#: machines/models.py:1407 msgid "" "The v6 prefix is incorrect and doesn't match the type associated with the " "machine." @@ -616,45 +621,45 @@ msgstr "" "Le préfixe v6 est incorrect et ne correspond pas au type associé à la " "machine." -#: models.py:1416 +#: machines/models.py:1433 msgid "Mandatory and unique, must not contain dots." msgstr "Obligatoire et unique, ne doit pas contenir de points." -#: models.py:1430 +#: machines/models.py:1447 msgid "Can view a domain object" msgstr "Peut voir un objet domaine" -#: models.py:1432 +#: machines/models.py:1449 msgid "domain" msgstr "domaine" -#: models.py:1433 +#: machines/models.py:1450 msgid "domains" msgstr "domaines" -#: models.py:1455 +#: machines/models.py:1472 msgid "You can't create a both A and CNAME record." msgstr "Vous ne pouvez pas créer un enregistrement à la fois A et CNAME." -#: models.py:1458 +#: machines/models.py:1475 msgid "You can't create a CNAME record pointing to itself." msgstr "Vous ne pouvez pas créer un enregistrement CNAME vers lui-même." -#: models.py:1466 +#: machines/models.py:1483 #, python-format msgid "The domain name %s is too long (over 63 characters)." msgstr "Le nom de domaine %s est trop long (plus de 63 caractères)." -#: models.py:1469 +#: machines/models.py:1486 #, python-format msgid "The domain name %s contains forbidden characters." msgstr "Le nom de domaine %s contient des caractères interdits." -#: models.py:1487 +#: machines/models.py:1504 msgid "Invalid extension." msgstr "Extension invalide." -#: models.py:1528 +#: machines/models.py:1545 #, python-format msgid "" "You reached the maximum number of alias that you are allowed to create " @@ -663,416 +668,432 @@ msgstr "" "Vous avez atteint le nombre maximal d'alias que vous pouvez créer vous-même " "(%s)." -#: models.py:1541 +#: machines/models.py:1558 msgid "You don't have the right to edit an alias of a machine of another user." msgstr "" "Vous n'avez pas le droit de modifier un alias d'une machine d'un autre " "utilisateur." -#: models.py:1553 +#: machines/models.py:1570 msgid "" "You don't have the right to delete an alias of a machine of another user." msgstr "" "Vous n'avez pas le droit de supprimer un alias d'une machine d'un autre " "utilisateur." -#: models.py:1581 +#: machines/models.py:1598 msgid "Can view an IPv4 addresses list object" msgstr "Peut voir un object liste d'adresses IPv4" -#: models.py:1583 +#: machines/models.py:1600 msgid "IPv4 addresses list" msgstr "Liste d'adresses IPv4" -#: models.py:1584 +#: machines/models.py:1601 msgid "IPv4 addresses lists" msgstr "Listes d'adresses IPv4" -#: models.py:1595 +#: machines/models.py:1612 msgid "The IPv4 address and the range of the IP type don't match." msgstr "L'adresse IPv4 et la plage du type d'IP ne correspondent pas." -#: models.py:1613 +#: machines/models.py:1630 msgid "DHCP server" msgstr "Serveur DHCP" -#: models.py:1614 +#: machines/models.py:1631 msgid "Switches configuration server" msgstr "Serveur de configuration des commutateurs réseau" -#: models.py:1615 +#: machines/models.py:1632 msgid "Recursive DNS server" msgstr "Serveur DNS récursif" -#: models.py:1616 +#: machines/models.py:1633 msgid "NTP server" msgstr "Serveur NTP" -#: models.py:1617 +#: machines/models.py:1634 msgid "RADIUS server" msgstr "Serveur RADIUS" -#: models.py:1618 +#: machines/models.py:1635 msgid "Log server" msgstr "Serveur log" -#: models.py:1619 +#: machines/models.py:1636 msgid "LDAP master server" msgstr "Serveur LDAP maître" -#: models.py:1620 +#: machines/models.py:1637 msgid "LDAP backup server" msgstr "Serveur LDAP de secours" -#: models.py:1621 +#: machines/models.py:1638 msgid "SMTP server" msgstr "Serveur SMTP" -#: models.py:1622 +#: machines/models.py:1639 msgid "postgreSQL server" msgstr "Serveur postgreSQL" -#: models.py:1623 +#: machines/models.py:1640 msgid "mySQL server" msgstr "Serveur mySQL" -#: models.py:1624 +#: machines/models.py:1641 msgid "SQL client" msgstr "Client SQL" -#: models.py:1625 +#: machines/models.py:1642 msgid "Gateway" msgstr "Passerelle" -#: models.py:1639 +#: machines/models.py:1656 msgid "Can view a role object" msgstr "Peut voir un objet rôle" -#: models.py:1641 +#: machines/models.py:1658 msgid "server role" msgstr "rôle de serveur" -#: models.py:1642 +#: machines/models.py:1659 msgid "server roles" msgstr "rôles de serveur" -#: models.py:1676 +#: machines/models.py:1693 msgid "Minimal time before regeneration of the service." msgstr "Temps minimal avant régénération du service." -#: models.py:1680 +#: machines/models.py:1697 msgid "Maximal time before regeneration of the service." msgstr "Temps maximal avant régénération du service." -#: models.py:1686 +#: machines/models.py:1703 msgid "Can view a service object" msgstr "Peut voir un objet service" -#: models.py:1688 +#: machines/models.py:1705 msgid "service to generate (DHCP, DNS, ...)" msgstr "service à générer (DHCP, DNS, ...)" -#: models.py:1689 +#: machines/models.py:1706 msgid "services to generate (DHCP, DNS, ...)" msgstr "services à générer (DHCP, DNS, ...)" -#: models.py:1735 +#: machines/models.py:1752 msgid "Can view a service server link object" msgstr "Peut voir un objet lien service serveur" -#: models.py:1737 +#: machines/models.py:1754 msgid "link between service and server" msgstr "lien entre service et serveur" -#: models.py:1738 +#: machines/models.py:1755 msgid "links between service and server" msgstr "liens entre service et serveur" -#: models.py:1780 +#: machines/models.py:1797 msgid "Name of the ports configuration" msgstr "Nom de la configuration de ports" -#: models.py:1786 +#: machines/models.py:1803 msgid "Can view a ports opening list object" msgstr "Peut voir un objet liste d'ouverture de ports" -#: models.py:1789 +#: machines/models.py:1806 msgid "ports opening list" msgstr "liste d'ouverture de ports" -#: models.py:1790 +#: machines/models.py:1807 msgid "ports opening lists" msgstr "listes d'ouverture de ports" -#: models.py:1799 +#: machines/models.py:1816 msgid "You don't have the right to delete a ports opening list." msgstr "Vous n'avez pas le droit de supprimer une liste d'ouverture de ports." -#: models.py:1802 +#: machines/models.py:1819 msgid "This ports opening list is used." msgstr "Cette liste d'ouverture de ports est utilisée." -#: models.py:1875 +#: machines/models.py:1892 msgid "ports opening" msgstr "ouverture de ports" -#: models.py:1876 +#: machines/models.py:1893 msgid "ports openings" msgstr "ouvertures de ports" -#: templates/machines/aff_alias.html:32 +#: machines/templates/machines/aff_alias.html:32 msgid "Aliases" msgstr "Alias" -#: templates/machines/aff_dname.html:30 +#: machines/templates/machines/aff_dname.html:30 msgid "Target zone" msgstr "Cible" -#: templates/machines/aff_dname.html:31 templates/machines/aff_mx.html:34 -#: templates/machines/aff_txt.html:33 +#: machines/templates/machines/aff_dname.html:31 +#: machines/templates/machines/aff_mx.html:34 +#: machines/templates/machines/aff_txt.html:33 msgid "Record" msgstr "Enregistrement" -#: templates/machines/aff_extension.html:34 -#: templates/machines/aff_iptype.html:36 templates/machines/aff_srv.html:34 -#: templates/machines/machine.html:116 +#: machines/templates/machines/aff_extension.html:34 +#: machines/templates/machines/aff_iptype.html:36 +#: machines/templates/machines/aff_srv.html:34 +#: machines/templates/machines/machine.html:116 msgid "Extension" msgstr "Extension" -#: templates/machines/aff_extension.html:35 -#: templates/machines/aff_iptype.html:37 +#: machines/templates/machines/aff_extension.html:35 +#: machines/templates/machines/aff_iptype.html:37 msgid "'infra' right required" msgstr "droit 'infra' requis" -#: templates/machines/aff_extension.html:41 +#: machines/templates/machines/aff_extension.html:41 msgid "DNSSEC" msgstr "DNSSEC" -#: templates/machines/aff_iptype.html:38 +#: machines/templates/machines/aff_iptype.html:38 msgid "IPv4 range" msgstr "Plage IPv4" -#: templates/machines/aff_iptype.html:39 +#: machines/templates/machines/aff_iptype.html:39 msgid "v6 prefix" msgstr "Préfixe v6" -#: templates/machines/aff_iptype.html:40 +#: machines/templates/machines/aff_iptype.html:40 msgid "DNSSEC reverse v4/v6" msgstr "DNSSEC inverse v4/v6" -#: templates/machines/aff_iptype.html:41 +#: machines/templates/machines/aff_iptype.html:41 msgid "On VLAN(s)" msgstr "Sur VLAN(s)" -#: templates/machines/aff_iptype.html:42 +#: machines/templates/machines/aff_iptype.html:42 msgid "Default ports opening" msgstr "Ouverture de ports par défaut" -#: templates/machines/aff_ipv6.html:32 +#: machines/templates/machines/aff_ipv6.html:32 msgid "IPv6 addresses" msgstr "Adresses IPv6" -#: templates/machines/aff_ipv6.html:33 +#: machines/templates/machines/aff_ipv6.html:33 msgid "SLAAC" msgstr "SLAAC" -#: templates/machines/aff_machines.html:43 +#: machines/templates/machines/aff_machines.html:43 msgid "DNS name" msgstr "Nom DNS" -#: templates/machines/aff_machines.html:45 +#: machines/templates/machines/aff_machines.html:45 msgid "Type" msgstr "Type" -#: templates/machines/aff_machines.html:47 +#: machines/templates/machines/aff_machines.html:47 msgid "IP address" msgstr "Adresse IP" -#: templates/machines/aff_machines.html:48 +#: machines/templates/machines/aff_machines.html:48 msgid "Actions" msgstr "Actions" -#: templates/machines/aff_machines.html:54 +#: machines/templates/machines/aff_machines.html:54 msgid "View the profile" msgstr "Voir le profil" -#: templates/machines/aff_machines.html:62 views.py:374 +#: machines/templates/machines/aff_machines.html:58 +msgid "Deactivated" +msgstr "Désactivée" + +#: machines/templates/machines/aff_machines.html:67 machines/views.py:374 msgid "Create an interface" msgstr "Créer une interface" -#: templates/machines/aff_machines.html:79 +#: machines/templates/machines/aff_machines.html:84 msgid "Display the aliases" msgstr "Afficher les alias" -#: templates/machines/aff_machines.html:99 +#: machines/templates/machines/aff_machines.html:98 +msgid "Display the vendor" +msgstr "Afficher le constructeur" + +#: machines/templates/machines/aff_machines.html:109 msgid "Display the IPv6 address" msgstr "Afficher les adresses IPv6" -#: templates/machines/aff_machines.html:116 +#: machines/templates/machines/aff_machines.html:126 msgid " Edit" msgstr " Modifier" -#: templates/machines/aff_machines.html:124 +#: machines/templates/machines/aff_machines.html:134 msgid " Manage the aliases" msgstr " Gérer les alias" -#: templates/machines/aff_machines.html:132 +#: machines/templates/machines/aff_machines.html:142 msgid " Manage the IPv6 addresses" msgstr " Gérer les adresses IPv6" -#: templates/machines/aff_machines.html:140 +#: machines/templates/machines/aff_machines.html:150 msgid " Manage the SSH fingerprints" msgstr " Gérer les empreintes SSH" -#: templates/machines/aff_machines.html:148 +#: machines/templates/machines/aff_machines.html:158 msgid " Manage the ports configuration" msgstr " Gérer les configuration de ports" -#: templates/machines/aff_machinetype.html:33 +#: machines/templates/machines/aff_machinetype.html:33 msgid "Matching IP type" msgstr "Type d'IP correspondant" -#: templates/machines/aff_mx.html:32 templates/machines/aff_ns.html:32 -#: templates/machines/aff_txt.html:32 +#: machines/templates/machines/aff_mx.html:32 +#: machines/templates/machines/aff_ns.html:32 +#: machines/templates/machines/aff_txt.html:32 msgid "Concerned zone" msgstr "Zone concernée" -#: templates/machines/aff_mx.html:33 templates/machines/aff_srv.html:36 +#: machines/templates/machines/aff_mx.html:33 +#: machines/templates/machines/aff_srv.html:36 msgid "Priority" msgstr "Priorité" -#: templates/machines/aff_nas.html:33 templates/machines/aff_soa.html:32 -#: templates/machines/aff_vlan.html:34 -#: templates/machines/index_portlist.html:20 +#: machines/templates/machines/aff_nas.html:33 +#: machines/templates/machines/aff_soa.html:32 +#: machines/templates/machines/aff_vlan.html:34 +#: machines/templates/machines/index_portlist.html:20 msgid "Name" msgstr "Nom" -#: templates/machines/aff_nas.html:34 +#: machines/templates/machines/aff_nas.html:34 msgid "NAS device type" msgstr "Type de dispositif NAS" -#: templates/machines/aff_nas.html:35 +#: machines/templates/machines/aff_nas.html:35 msgid "Machine type linked to the NAS device" msgstr "Type de machine lié au dispositif NAS" -#: templates/machines/aff_nas.html:36 +#: machines/templates/machines/aff_nas.html:36 msgid "Access mode" msgstr "Mode d'accès" -#: templates/machines/aff_nas.html:37 +#: machines/templates/machines/aff_nas.html:37 msgid "MAC address auto capture" msgstr "Capture automatique de l'adresse MAC" -#: templates/machines/aff_ns.html:33 +#: machines/templates/machines/aff_ns.html:33 msgid "Authoritarian interface for the concerned zone" msgstr "Interface authoritaire pour la zone concernée" -#: templates/machines/aff_role.html:33 +#: machines/templates/machines/aff_role.html:33 msgid "Role name" msgstr "Nom du rôle" -#: templates/machines/aff_role.html:34 +#: machines/templates/machines/aff_role.html:34 msgid "Specific role" msgstr "Rôle spécifique" -#: templates/machines/aff_role.html:35 +#: machines/templates/machines/aff_role.html:35 msgid "Servers" msgstr "Serveurs" -#: templates/machines/aff_servers.html:31 -#: templates/machines/aff_service.html:32 +#: machines/templates/machines/aff_servers.html:31 +#: machines/templates/machines/aff_service.html:32 msgid "Service name" msgstr "Nom du service" -#: templates/machines/aff_servers.html:32 +#: machines/templates/machines/aff_servers.html:32 msgid "Server" msgstr "Serveur" -#: templates/machines/aff_servers.html:33 +#: machines/templates/machines/aff_servers.html:33 msgid "Last regeneration" msgstr "Dernière régénération" -#: templates/machines/aff_servers.html:34 +#: machines/templates/machines/aff_servers.html:34 msgid "Regeneration required" msgstr "Régénération requise" -#: templates/machines/aff_servers.html:35 +#: machines/templates/machines/aff_servers.html:35 msgid "Regeneration activated" msgstr "Régénération activée" -#: templates/machines/aff_service.html:33 +#: machines/templates/machines/aff_service.html:33 msgid "Minimal time before regeneration" msgstr "Temps minimal avant régénération" -#: templates/machines/aff_service.html:34 +#: machines/templates/machines/aff_service.html:34 msgid "Maximal time before regeneration" msgstr "Temps maximal avant régénération" -#: templates/machines/aff_service.html:35 +#: machines/templates/machines/aff_service.html:35 msgid "Included servers" msgstr "Serveurs inclus" -#: templates/machines/aff_service.html:36 +#: machines/templates/machines/aff_service.html:36 msgid "Ask for regeneration" msgstr "Demander la régénération" -#: templates/machines/aff_soa.html:33 +#: machines/templates/machines/aff_soa.html:33 msgid "Mail" msgstr "Mail" -#: templates/machines/aff_soa.html:34 +#: machines/templates/machines/aff_soa.html:34 msgid "Refresh" msgstr "Rafraichissement" -#: templates/machines/aff_soa.html:35 +#: machines/templates/machines/aff_soa.html:35 msgid "Retry" msgstr "Relance" -#: templates/machines/aff_soa.html:36 +#: machines/templates/machines/aff_soa.html:36 msgid "Expire" msgstr "Expiration" -#: templates/machines/aff_soa.html:37 templates/machines/aff_srv.html:35 +#: machines/templates/machines/aff_soa.html:37 +#: machines/templates/machines/aff_srv.html:35 msgid "TTL" msgstr "Temps de vie" -#: templates/machines/aff_srv.html:32 templates/machines/machine.html:152 +#: machines/templates/machines/aff_srv.html:32 +#: machines/templates/machines/machine.html:152 msgid "Service" msgstr "Service" -#: templates/machines/aff_srv.html:33 +#: machines/templates/machines/aff_srv.html:33 msgid "Protocol" msgstr "Protocole" -#: templates/machines/aff_srv.html:37 +#: machines/templates/machines/aff_srv.html:37 msgid "Weight" msgstr "Poids" -#: templates/machines/aff_srv.html:38 +#: machines/templates/machines/aff_srv.html:38 msgid "Port" msgstr "Port" -#: templates/machines/aff_srv.html:39 +#: machines/templates/machines/aff_srv.html:39 msgid "Target" msgstr "Cible" -#: templates/machines/aff_sshfp.html:32 +#: machines/templates/machines/aff_sshfp.html:32 msgid "Algorithm used" msgstr "Algorithme utilisé" -#: templates/machines/aff_vlan.html:33 +#: machines/templates/machines/aff_vlan.html:33 msgid "ID" msgstr "ID" -#: templates/machines/aff_vlan.html:36 templates/machines/sidebar.html:51 +#: machines/templates/machines/aff_vlan.html:36 +#: machines/templates/machines/sidebar.html:51 msgid "IP ranges" msgstr "Plages d'IP" -#: templates/machines/delete.html:29 +#: machines/templates/machines/delete.html:29 msgid "Deletion of machines" msgstr "Suppression de machines" -#: templates/machines/delete.html:35 +#: machines/templates/machines/delete.html:35 #, python-format msgid "" "Warning: are you sure you want to delete this object %(objet_name)s " @@ -1081,167 +1102,171 @@ msgstr "" "Attention : voulez-vous vraiment supprimer cet objet %(objet_name)s " "( %(objet)s ) ?" -#: templates/machines/delete.html:36 +#: machines/templates/machines/delete.html:36 msgid "Confirm" msgstr "Confirmer" -#: templates/machines/edit_portlist.html:29 templates/machines/index.html:29 -#: templates/machines/index.html:32 templates/machines/index_alias.html:29 -#: templates/machines/index_extension.html:30 -#: templates/machines/index_iptype.html:30 -#: templates/machines/index_ipv6.html:30 -#: templates/machines/index_machinetype.html:31 -#: templates/machines/index_nas.html:31 -#: templates/machines/index_portlist.html:8 -#: templates/machines/index_portlist.html:25 -#: templates/machines/index_role.html:30 -#: templates/machines/index_service.html:30 -#: templates/machines/index_sshfp.html:28 templates/machines/index_vlan.html:30 -#: templates/machines/machine.html:31 templates/machines/sidebar.html:33 +#: machines/templates/machines/edit_portlist.html:29 +#: machines/templates/machines/index.html:29 +#: machines/templates/machines/index.html:32 +#: machines/templates/machines/index_alias.html:29 +#: machines/templates/machines/index_extension.html:30 +#: machines/templates/machines/index_iptype.html:30 +#: machines/templates/machines/index_ipv6.html:30 +#: machines/templates/machines/index_machinetype.html:31 +#: machines/templates/machines/index_nas.html:31 +#: machines/templates/machines/index_portlist.html:8 +#: machines/templates/machines/index_portlist.html:25 +#: machines/templates/machines/index_role.html:30 +#: machines/templates/machines/index_service.html:30 +#: machines/templates/machines/index_sshfp.html:28 +#: machines/templates/machines/index_vlan.html:30 +#: machines/templates/machines/machine.html:31 +#: machines/templates/machines/sidebar.html:33 msgid "Machines" msgstr "Machines" -#: templates/machines/edit_portlist.html:50 +#: machines/templates/machines/edit_portlist.html:50 msgid "Add a port" msgstr "Ajouter un port" -#: templates/machines/edit_portlist.html:53 +#: machines/templates/machines/edit_portlist.html:53 msgid "Create or edit" msgstr "Créer ou modifier" -#: templates/machines/index_alias.html:32 +#: machines/templates/machines/index_alias.html:32 msgid "List of the aliases of the interface" msgstr "Liste des alias de l'interface" -#: templates/machines/index_alias.html:34 +#: machines/templates/machines/index_alias.html:34 msgid " Add an alias" msgstr " Ajouter un alias" -#: templates/machines/index_alias.html:36 +#: machines/templates/machines/index_alias.html:36 msgid " Delete one or several aliases" msgstr " Supprimer un ou plusieurs alias" -#: templates/machines/index_extension.html:33 +#: machines/templates/machines/index_extension.html:33 msgid "List of extensions" msgstr "Liste des extensions" -#: templates/machines/index_extension.html:37 +#: machines/templates/machines/index_extension.html:37 msgid " Add an extension" msgstr " Ajouter une extension" -#: templates/machines/index_extension.html:40 +#: machines/templates/machines/index_extension.html:40 msgid " Delete one or several extensions" msgstr " Supprimer une ou plusieurs extensions" -#: templates/machines/index_extension.html:44 +#: machines/templates/machines/index_extension.html:44 msgid "List of SOA records" msgstr "Liste des enregistrements SOA" -#: templates/machines/index_extension.html:47 +#: machines/templates/machines/index_extension.html:47 msgid " Add an SOA record" msgstr " Ajouter un enregistrement SOA" -#: templates/machines/index_extension.html:51 +#: machines/templates/machines/index_extension.html:51 msgid " Delete one or several SOA records" msgstr " Supprimer un ou plusieurs enregistrements SOA" -#: templates/machines/index_extension.html:55 +#: machines/templates/machines/index_extension.html:55 msgid "List of MX records" msgstr "Liste des enregistrements MX" -#: templates/machines/index_extension.html:58 +#: machines/templates/machines/index_extension.html:58 msgid " Add an MX record" msgstr " Ajouter un enregistrement MX" -#: templates/machines/index_extension.html:62 +#: machines/templates/machines/index_extension.html:62 msgid " Delete one or several MX records" msgstr " Supprimer un ou plusieurs enregistrements MX" -#: templates/machines/index_extension.html:66 +#: machines/templates/machines/index_extension.html:66 msgid "List of NS records" msgstr "Liste des enregistrements NS" -#: templates/machines/index_extension.html:69 +#: machines/templates/machines/index_extension.html:69 msgid " Add an NS record" msgstr " Ajouter un enregistrement NS" -#: templates/machines/index_extension.html:73 +#: machines/templates/machines/index_extension.html:73 msgid " Delete one or several NS records" msgstr " Supprimer un ou plusieurs enregistrements NS" -#: templates/machines/index_extension.html:77 +#: machines/templates/machines/index_extension.html:77 msgid "List of TXT records" msgstr "Liste des enregistrements TXT" -#: templates/machines/index_extension.html:80 +#: machines/templates/machines/index_extension.html:80 msgid " Add a TXT record" msgstr " Ajouter un enregistrement TXT" -#: templates/machines/index_extension.html:84 +#: machines/templates/machines/index_extension.html:84 msgid " Delete one or several TXT records" msgstr " Supprimer un ou plusieurs enregistrements TXT" -#: templates/machines/index_extension.html:88 +#: machines/templates/machines/index_extension.html:88 msgid "List of DNAME records" msgstr "Liste des enregistrements DNAME" -#: templates/machines/index_extension.html:91 +#: machines/templates/machines/index_extension.html:91 msgid " Add a DNAME record" msgstr " Ajouter un enregistrement DNAME" -#: templates/machines/index_extension.html:95 +#: machines/templates/machines/index_extension.html:95 msgid " Delete one or several DNAME records" msgstr " Supprimer un ou plusieurs enregistrements DNAME" -#: templates/machines/index_extension.html:99 +#: machines/templates/machines/index_extension.html:99 msgid "List of SRV records" msgstr "Liste des enregistrements SRV" -#: templates/machines/index_extension.html:102 +#: machines/templates/machines/index_extension.html:102 msgid " Add an SRV record" msgstr " Ajouter un enregistrement SRV" -#: templates/machines/index_extension.html:106 +#: machines/templates/machines/index_extension.html:106 msgid " Delete one or several SRV records" msgstr " Supprimer un ou plusieurs enregistrements SRV" -#: templates/machines/index_iptype.html:33 +#: machines/templates/machines/index_iptype.html:33 msgid "List of IP types" msgstr "Liste des types d'IP" -#: templates/machines/index_iptype.html:36 +#: machines/templates/machines/index_iptype.html:36 msgid " Add an IP type" msgstr " Ajouter un type d'IP" -#: templates/machines/index_iptype.html:40 +#: machines/templates/machines/index_iptype.html:40 msgid " Delete one or several IP types" msgstr " Supprimer un ou plusieurs types d'IP" -#: templates/machines/index_ipv6.html:33 +#: machines/templates/machines/index_ipv6.html:33 msgid "List of the IPv6 addresses of the interface" msgstr "Liste des adresses IPv6 de l'interface" -#: templates/machines/index_ipv6.html:36 +#: machines/templates/machines/index_ipv6.html:36 msgid " Add an IPv6 address" msgstr " Ajouter une adresse IPv6" -#: templates/machines/index_machinetype.html:34 +#: machines/templates/machines/index_machinetype.html:34 msgid "List of machine types" msgstr "Liste des types de machine" -#: templates/machines/index_machinetype.html:37 +#: machines/templates/machines/index_machinetype.html:37 msgid " Add a machine type" msgstr " Ajouter un type de machine" -#: templates/machines/index_machinetype.html:41 +#: machines/templates/machines/index_machinetype.html:41 msgid " Delete one or several machine types" msgstr " Supprimer un ou plusieurs types de machine" -#: templates/machines/index_nas.html:34 +#: machines/templates/machines/index_nas.html:34 msgid "List of NAS devices" msgstr "Liste des dispositifs NAS" -#: templates/machines/index_nas.html:35 +#: machines/templates/machines/index_nas.html:35 msgid "" "The NAS device type and machine type are linked. It is useful for MAC " "address auto capture by RADIUS, and allows to choose the machine type to " @@ -1252,210 +1277,212 @@ msgstr "" "type de machine à assigner aux machines en fonction du type de dispositif " "NAS." -#: templates/machines/index_nas.html:38 +#: machines/templates/machines/index_nas.html:38 msgid " Add a NAS device type" msgstr " Ajouter un type de dispositif NAS" -#: templates/machines/index_nas.html:42 +#: machines/templates/machines/index_nas.html:42 msgid " Delete one or several NAS device types" msgstr " Supprimer un ou plusieurs types de dispositif NAS" -#: templates/machines/index_portlist.html:11 +#: machines/templates/machines/index_portlist.html:11 msgid "List of ports configurations" msgstr "Liste des configurations de ports" -#: templates/machines/index_portlist.html:14 +#: machines/templates/machines/index_portlist.html:14 msgid " Add a configuration" msgstr " Ajouter une configuration" -#: templates/machines/index_portlist.html:21 +#: machines/templates/machines/index_portlist.html:21 msgid "TCP (input)" msgstr "TCP (entrée)" -#: templates/machines/index_portlist.html:22 +#: machines/templates/machines/index_portlist.html:22 msgid "TCP (output)" msgstr "TCP (sortie)" -#: templates/machines/index_portlist.html:23 +#: machines/templates/machines/index_portlist.html:23 msgid "UDP (input)" msgstr "UDP (entrée)" -#: templates/machines/index_portlist.html:24 +#: machines/templates/machines/index_portlist.html:24 msgid "UDP (output)" msgstr "UDP (sortie)" -#: templates/machines/index_role.html:33 +#: machines/templates/machines/index_role.html:33 msgid "List of roles" msgstr "Liste des rôles" -#: templates/machines/index_role.html:36 +#: machines/templates/machines/index_role.html:36 msgid " Add a role" msgstr " Ajouter un rôle" -#: templates/machines/index_role.html:39 +#: machines/templates/machines/index_role.html:39 msgid " Delete one or several roles" msgstr " Supprimer un ou plusieurs rôles" -#: templates/machines/index_service.html:33 +#: machines/templates/machines/index_service.html:33 msgid "List of services" msgstr "Liste des services" -#: templates/machines/index_service.html:36 +#: machines/templates/machines/index_service.html:36 msgid " Add a service" msgstr " Ajouter un service" -#: templates/machines/index_service.html:39 +#: machines/templates/machines/index_service.html:39 msgid " Delete one or several services" msgstr " Supprimer un ou plusieurs services" -#: templates/machines/index_service.html:42 +#: machines/templates/machines/index_service.html:42 msgid "States of servers" msgstr "États des serveurs" -#: templates/machines/index_sshfp.html:31 +#: machines/templates/machines/index_sshfp.html:31 msgid "SSH fingerprints" msgstr "Empreintes SSH" -#: templates/machines/index_sshfp.html:34 +#: machines/templates/machines/index_sshfp.html:34 msgid " Add an SSH fingerprint" msgstr " Ajouter une empreinte SSH" -#: templates/machines/index_vlan.html:33 +#: machines/templates/machines/index_vlan.html:33 msgid "List of VLANs" msgstr "Liste des VLANs" -#: templates/machines/index_vlan.html:36 +#: machines/templates/machines/index_vlan.html:36 msgid " Add a VLAN" msgstr " Ajouter un VLAN" -#: templates/machines/index_vlan.html:39 +#: machines/templates/machines/index_vlan.html:39 msgid " Delete one or several VLANs" msgstr " Supprimer un ou plusieurs VLANs" -#: templates/machines/machine.html:92 +#: machines/templates/machines/machine.html:92 msgid "Machine" msgstr "Machine" -#: templates/machines/machine.html:96 +#: machines/templates/machines/machine.html:96 msgid "Interface" msgstr "Interface" -#: templates/machines/machine.html:104 +#: machines/templates/machines/machine.html:104 msgid "Domain" msgstr "Domaine" -#: templates/machines/machine.html:148 +#: machines/templates/machines/machine.html:148 msgid "Alias" msgstr "Alias" -#: templates/machines/machine.html:168 +#: machines/templates/machines/machine.html:168 msgid "IPv6 address" msgstr "Adresse IPv6" -#: templates/machines/sidebar.html:39 +#: machines/templates/machines/sidebar.html:39 msgid "Machine types" msgstr "Types de machine" -#: templates/machines/sidebar.html:45 +#: machines/templates/machines/sidebar.html:45 msgid "Extensions and zones" msgstr "Extensions et zones" -#: templates/machines/sidebar.html:69 +#: machines/templates/machines/sidebar.html:69 msgid "Services (DHCP, DNS, ...)" msgstr "Services (DHCP, DNS, ...)" -#: templates/machines/sidebar.html:75 +#: machines/templates/machines/sidebar.html:75 msgid "Server roles" msgstr "Rôles de serveur" -#: templates/machines/sidebar.html:81 +#: machines/templates/machines/sidebar.html:81 msgid "Ports openings" msgstr "Ouvertures de ports" -#: views.py:155 +#: machines/views.py:155 msgid "Select a machine type first." msgstr "Sélectionnez un type de machine d'abord." -#: views.py:257 +#: machines/views.py:257 msgid "The machine was created." msgstr "La machine a été créée." -#: views.py:269 +#: machines/views.py:269 msgid "Create a machine" msgstr "Créer une machine" -#: views.py:309 +#: machines/views.py:309 msgid "The machine was edited." msgstr "La machine a été modifiée." -#: views.py:321 views.py:445 views.py:511 views.py:567 views.py:629 -#: views.py:690 views.py:748 views.py:805 views.py:862 views.py:919 -#: views.py:977 views.py:1034 views.py:1106 views.py:1169 views.py:1226 -#: views.py:1292 views.py:1349 +#: machines/views.py:321 machines/views.py:445 machines/views.py:511 +#: machines/views.py:567 machines/views.py:629 machines/views.py:690 +#: machines/views.py:748 machines/views.py:805 machines/views.py:862 +#: machines/views.py:919 machines/views.py:977 machines/views.py:1034 +#: machines/views.py:1106 machines/views.py:1169 machines/views.py:1226 +#: machines/views.py:1292 machines/views.py:1349 msgid "Edit" msgstr "Modifier" -#: views.py:334 +#: machines/views.py:334 msgid "The machine was deleted." msgstr "La machine a été supprimée." -#: views.py:363 +#: machines/views.py:363 msgid "The interface was created." msgstr "L'interface a été créée." -#: views.py:390 +#: machines/views.py:390 msgid "The interface was deleted." msgstr "L'interface a été supprimée." -#: views.py:415 +#: machines/views.py:415 msgid "The IPv6 addresses list was created." msgstr "La liste d'adresses IPv6 a été créée." -#: views.py:421 +#: machines/views.py:421 msgid "Create an IPv6 addresses list" msgstr "Créer une liste d'adresses IPv6" -#: views.py:439 +#: machines/views.py:439 msgid "The IPv6 addresses list was edited." msgstr "La liste d'adresses IPv6 a été modifiée." -#: views.py:458 +#: machines/views.py:458 msgid "The IPv6 addresses list was deleted." msgstr "La liste d'adresses IPv6 a été supprimée." -#: views.py:482 +#: machines/views.py:482 msgid "The SSHFP record was created." msgstr "L'enregistrement SSHFP a été créé." -#: views.py:488 +#: machines/views.py:488 msgid "Create a SSHFP record" msgstr "Créer un enregistrement SSHFP" -#: views.py:505 +#: machines/views.py:505 msgid "The SSHFP record was edited." msgstr "L'enregistrement SSHFP a été modifié." -#: views.py:524 +#: machines/views.py:524 msgid "The SSHFP record was deleted." msgstr "L'enregistrement SSHFP a été supprimé." -#: views.py:545 +#: machines/views.py:545 msgid "The IP type was created." msgstr "Le type d'IP a été créé." -#: views.py:548 +#: machines/views.py:548 msgid "Create an IP type" msgstr "Créer un type d'IP" -#: views.py:564 +#: machines/views.py:564 msgid "The IP type was edited." msgstr "Le type d'IP a été modifié." -#: views.py:583 +#: machines/views.py:583 msgid "The IP type was deleted." msgstr "Le type d'IP a été supprimé." -#: views.py:587 +#: machines/views.py:587 #, python-format msgid "" "The IP type %s is assigned to at least one machine, you can't delete it." @@ -1463,29 +1490,31 @@ msgstr "" "Le type d'IP %s est assigné à au moins une machine, vous ne pouvez pas le " "supprimer." -#: views.py:592 views.py:654 views.py:715 views.py:772 views.py:829 -#: views.py:886 views.py:944 views.py:1001 views.py:1058 views.py:1136 -#: views.py:1193 views.py:1250 views.py:1316 views.py:1373 +#: machines/views.py:592 machines/views.py:654 machines/views.py:715 +#: machines/views.py:772 machines/views.py:829 machines/views.py:886 +#: machines/views.py:944 machines/views.py:1001 machines/views.py:1058 +#: machines/views.py:1136 machines/views.py:1193 machines/views.py:1250 +#: machines/views.py:1316 machines/views.py:1373 msgid "Delete" msgstr "Supprimer" -#: views.py:605 +#: machines/views.py:605 msgid "The machine type was created." msgstr "Le type de machine a été créé." -#: views.py:608 +#: machines/views.py:608 msgid "Create a machine type" msgstr "Créer un type de machine" -#: views.py:626 +#: machines/views.py:626 msgid "The machine type was edited." msgstr "Le type de machine a été modifié." -#: views.py:645 +#: machines/views.py:645 msgid "The machine type was deleted." msgstr "Le type de machine a été supprimé." -#: views.py:649 +#: machines/views.py:649 #, python-format msgid "" "The machine type %s is assigned to at least one machine, you can't delete it." @@ -1493,23 +1522,23 @@ msgstr "" "Le type de machine %s est assigné à au moins un machine, vous ne pouvez pas " "le supprimer." -#: views.py:667 +#: machines/views.py:667 msgid "The extension was created." msgstr "L'extension a été créée." -#: views.py:670 +#: machines/views.py:670 msgid "Create an extension" msgstr "Créer une extension" -#: views.py:687 +#: machines/views.py:687 msgid "The extension was edited." msgstr "L'extension a été modifiée." -#: views.py:706 +#: machines/views.py:706 msgid "The extension was deleted." msgstr "L'extension a été supprimée." -#: views.py:710 +#: machines/views.py:710 #, python-format msgid "" "The extension %s is assigned to at least one machine type, you can't delete " @@ -1518,260 +1547,260 @@ msgstr "" "L'extension %s est assignée à au moins un type de machine, vous ne pouvez " "pas le supprimer." -#: views.py:728 +#: machines/views.py:728 msgid "The SOA record was created." msgstr "L'enregistrement SOA a été créé." -#: views.py:731 +#: machines/views.py:731 msgid "Create an SOA record" msgstr "Créer un enregistrement SOA" -#: views.py:745 +#: machines/views.py:745 msgid "The SOA record was edited." msgstr "L'enregistrement SOA a été modifié." -#: views.py:764 +#: machines/views.py:764 msgid "The SOA record was deleted." msgstr "L'enregistrement SOA a été supprimé." -#: views.py:768 +#: machines/views.py:768 #, python-format msgid "Error: the SOA record %s can't be deleted." msgstr "Erreur : l'enregistrement SOA %s ne peut pas être supprimé." -#: views.py:785 +#: machines/views.py:785 msgid "The MX record was created." msgstr "L'enregistrement MX a été créé." -#: views.py:788 +#: machines/views.py:788 msgid "Create an MX record" msgstr "Créer un enregistrement MX" -#: views.py:802 +#: machines/views.py:802 msgid "The MX record was edited." msgstr "L'enregistrement MX a été modifié." -#: views.py:821 +#: machines/views.py:821 msgid "The MX record was deleted." msgstr "L'enregistrement MX a été supprimé." -#: views.py:825 +#: machines/views.py:825 #, python-format msgid "Error: the MX record %s can't be deleted." msgstr "Erreur : l'enregistrement MX %s ne peut pas être supprimé." -#: views.py:842 +#: machines/views.py:842 msgid "The NS record was created." msgstr "L'enregistrement NS a été créé." -#: views.py:845 +#: machines/views.py:845 msgid "Create an NS record" msgstr "Créer un enregistrement NS" -#: views.py:859 +#: machines/views.py:859 msgid "The NS record was edited." msgstr "L'enregistrement NS a été modifié." -#: views.py:878 +#: machines/views.py:878 msgid "The NS record was deleted." msgstr "L'enregistrement NS a été supprimé." -#: views.py:882 +#: machines/views.py:882 #, python-format msgid "Error: the NS record %s can't be deleted." msgstr "Erreur : l'enregistrement NS %s ne peut pas être supprimé." -#: views.py:899 +#: machines/views.py:899 msgid "The DNAME record was created." msgstr "L'enregistrement DNAME a été créé." -#: views.py:902 +#: machines/views.py:902 msgid "Create a DNAME record" msgstr "Créer un enregistrement DNAME" -#: views.py:916 +#: machines/views.py:916 msgid "The DNAME record was edited." msgstr "L'enregistrement DNAME a été modifié." -#: views.py:935 +#: machines/views.py:935 msgid "The DNAME record was deleted." msgstr "L'enregistrement DNAME a été supprimé." -#: views.py:939 +#: machines/views.py:939 #, python-format msgid "Error: the DNAME record %s can't be deleted." msgstr "Erreur : l'enregistrement DNAME %s ne peut pas être supprimé." -#: views.py:957 +#: machines/views.py:957 msgid "The TXT record was created." msgstr "L'enregistrement TXT a été créé." -#: views.py:960 +#: machines/views.py:960 msgid "Create a TXT record" msgstr "Créer un enregistrement TXT" -#: views.py:974 +#: machines/views.py:974 msgid "The TXT record was edited." msgstr "L'enregistrement TXT a été modifié." -#: views.py:993 +#: machines/views.py:993 msgid "The TXT record was deleted." msgstr "L'enregistrement TXT a été supprimé." -#: views.py:997 +#: machines/views.py:997 #, python-format msgid "Error: the TXT record %s can't be deleted." msgstr "Erreur : l'enregistrement %s ne peut pas être supprimé." -#: views.py:1014 +#: machines/views.py:1014 msgid "The SRV record was created." msgstr "L'enregistrement SRV a été créé." -#: views.py:1017 +#: machines/views.py:1017 msgid "Create an SRV record" msgstr "Créer un enregistrement SRV" -#: views.py:1031 +#: machines/views.py:1031 msgid "The SRV record was edited." msgstr "L'enregistrement SRV a été modifié." -#: views.py:1050 +#: machines/views.py:1050 msgid "The SRV record was deleted." msgstr "L'enregistrement SRV a été supprimé." -#: views.py:1054 +#: machines/views.py:1054 #, python-format msgid "Error: the SRV record %s can't be deleted." msgstr "Erreur : l'enregistrement SRV %s ne peut pas être supprimé." -#: views.py:1074 +#: machines/views.py:1074 msgid "The alias was created." msgstr "L'alias a été créé." -#: views.py:1080 +#: machines/views.py:1080 msgid "Create an alias" msgstr "Créer un alias" -#: views.py:1098 +#: machines/views.py:1098 msgid "The alias was edited." msgstr "L'alias a été modifié." -#: views.py:1124 +#: machines/views.py:1124 #, python-format msgid "The alias %s was deleted." msgstr "L'alias %s a été supprimé." -#: views.py:1129 +#: machines/views.py:1129 #, python-format msgid "Error: the alias %s can't be deleted." msgstr "Erreur : l'alias %s ne peut pas être supprimé." -#: views.py:1149 +#: machines/views.py:1149 msgid "The role was created." msgstr "Le rôle a été créé." -#: views.py:1152 +#: machines/views.py:1152 msgid "Create a role" msgstr "Créer un rôle" -#: views.py:1166 +#: machines/views.py:1166 msgid "The role was edited." msgstr "Le rôle a été modifié." -#: views.py:1185 +#: machines/views.py:1185 msgid "The role was deleted." msgstr "Le rôle a été supprimé." -#: views.py:1189 +#: machines/views.py:1189 #, python-format msgid "Error: the role %s can't be deleted." msgstr "Erreur : le rôle %s ne peut pas être supprimé." -#: views.py:1206 +#: machines/views.py:1206 msgid "The service was created." msgstr "Le service a été créé." -#: views.py:1209 +#: machines/views.py:1209 msgid "Create a service" msgstr "Créer un service" -#: views.py:1223 +#: machines/views.py:1223 msgid "The service was edited." msgstr "Le service a été modifié." -#: views.py:1242 +#: machines/views.py:1242 msgid "The service was deleted." msgstr "Le service a été supprimé." -#: views.py:1246 +#: machines/views.py:1246 #, python-format msgid "Error: the service %s can't be deleted." msgstr "Erreur : le service %s ne peut pas être supprimé." -#: views.py:1272 +#: machines/views.py:1272 msgid "The VLAN was created." msgstr "Le VLAN a été créé." -#: views.py:1275 +#: machines/views.py:1275 msgid "Create a VLAN" msgstr "Créer un VLAN" -#: views.py:1289 +#: machines/views.py:1289 msgid "The VLAN was edited." msgstr "Le VLAN a été modifié." -#: views.py:1308 +#: machines/views.py:1308 msgid "The VLAN was deleted." msgstr "Le VLAN a été supprimé." -#: views.py:1312 +#: machines/views.py:1312 #, python-format msgid "Error: the VLAN %s can't be deleted." msgstr "Erreur : le VLAN %s ne peut pas être supprimé." -#: views.py:1329 +#: machines/views.py:1329 msgid "The NAS device was created." msgstr "Le dispositif NAS a été créé." -#: views.py:1332 +#: machines/views.py:1332 msgid "Create a NAS device" msgstr "Créer un dispositif NAS" -#: views.py:1346 +#: machines/views.py:1346 msgid "The NAS device was edited." msgstr "Le dispositif NAS a été modifié." -#: views.py:1365 +#: machines/views.py:1365 msgid "The NAS device was deleted." msgstr "Le dispositif NAS a été supprimé." -#: views.py:1369 +#: machines/views.py:1369 #, python-format msgid "Error: the NAS device %s can't be deleted." msgstr "Erreur : le dispositif NAS %s ne peut pas être supprimé." -#: views.py:1625 +#: machines/views.py:1625 msgid "The ports list was edited." msgstr "La liste de ports a été modifiée." -#: views.py:1639 +#: machines/views.py:1639 msgid "The ports list was deleted." msgstr "La liste de ports a été supprimée." -#: views.py:1664 +#: machines/views.py:1664 msgid "The ports list was created." msgstr "La liste de ports a été créée." -#: views.py:1682 +#: machines/views.py:1682 msgid "Warning: the IPv4 isn't public, the opening won't have effect in v4." msgstr "" "Attention : l'adresse IPv4 n'est pas publique, l'ouverture n'aura pas " "d'effet en v4." -#: views.py:1692 +#: machines/views.py:1692 msgid "The ports configuration was edited." msgstr "La configuration de ports a été modifiée." -#: views.py:1695 +#: machines/views.py:1695 msgid "Edit the configuration" msgstr "Modifier la configuration" diff --git a/preferences/locale/fr/LC_MESSAGES/django.po b/preferences/locale/fr/LC_MESSAGES/django.po index 3528330e..3382892f 100644 --- a/preferences/locale/fr/LC_MESSAGES/django.po +++ b/preferences/locale/fr/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: 2.5\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-12 15:13+0100\n" +"POT-Creation-Date: 2019-02-12 08:58+0100\n" "PO-Revision-Date: 2018-06-24 15:54+0200\n" "Last-Translator: Laouen Fernet \n" "Language-Team: \n" @@ -30,235 +30,245 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: acl.py:42 +#: preferences/acl.py:42 msgid "You don't have the right to view this application." msgstr "Vous n'avez pas le droit de voir cette application." -#: forms.py:63 templates/preferences/display_preferences.html:142 +#: preferences/forms.py:66 +#: preferences/templates/preferences/display_preferences.html:142 msgid "Telephone number required" msgstr "Numéro de téléphone requis" -#: forms.py:65 +#: preferences/forms.py:68 msgid "GPG fingerprint" msgstr "Empreinte GPG" -#: forms.py:66 +#: preferences/forms.py:69 msgid "All can create a club" msgstr "Tous peuvent créer un club" -#: forms.py:67 +#: preferences/forms.py:70 msgid "All can create a member" msgstr "Tous peuvent créer un adhérent" -#: forms.py:68 templates/preferences/display_preferences.html:120 +#: preferences/forms.py:71 +#: preferences/templates/preferences/display_preferences.html:120 msgid "Self registration" msgstr "Autoinscription" -#: forms.py:69 +#: preferences/forms.py:72 msgid "Default shell" msgstr "Interface en ligne de commande par défaut" -#: forms.py:85 +#: preferences/forms.py:88 msgid "Possibility to set a password per machine" msgstr "Possibilité de mettre un mot de passe par machine" -#: forms.py:87 templates/preferences/display_preferences.html:172 +#: preferences/forms.py:90 +#: preferences/templates/preferences/display_preferences.html:172 msgid "Maximum number of interfaces allowed for a standard user" msgstr "Nombre maximum d'interfaces autorisé pour un utilisateur standard" -#: forms.py:91 templates/preferences/display_preferences.html:176 +#: preferences/forms.py:94 +#: preferences/templates/preferences/display_preferences.html:176 msgid "Maximum number of DNS aliases allowed for a standard user" msgstr "Nombre maximum d'alias DNS autorisé pour un utilisateur standard" -#: forms.py:94 +#: preferences/forms.py:97 msgid "IPv6 mode" msgstr "Mode IPv6" -#: forms.py:95 +#: preferences/forms.py:98 msgid "Can create a machine" msgstr "Peut créer une machine" -#: forms.py:141 +#: preferences/forms.py:144 msgid "General message in French" msgstr "Message général en français" -#: forms.py:142 +#: preferences/forms.py:145 msgid "General message in English" msgstr "Message général en anglais" -#: forms.py:143 templates/preferences/display_preferences.html:58 +#: preferences/forms.py:146 +#: preferences/templates/preferences/display_preferences.html:58 msgid "Number of results displayed when searching" msgstr "Nombre de résultats affichés lors de la recherche" -#: forms.py:146 +#: preferences/forms.py:149 msgid "Number of items per page, standard size (e.g. users)" msgstr "Nombre d'éléments par page, taille standard (ex : utilisateurs)" -#: forms.py:149 +#: preferences/forms.py:152 msgid "Number of items per page, large size (e.g. machines)" msgstr "Nombre d'éléments par page, taille importante (ex : machines)" -#: forms.py:152 templates/preferences/display_preferences.html:66 +#: preferences/forms.py:155 +#: preferences/templates/preferences/display_preferences.html:66 msgid "Time before expiration of the reset password link (in hours)" msgstr "" "Temps avant expiration du lien de réinitialisation de mot de passe (en " "heures)" -#: forms.py:155 templates/preferences/display_preferences.html:52 +#: preferences/forms.py:158 +#: preferences/templates/preferences/display_preferences.html:52 msgid "Website name" msgstr "Nom du site" -#: forms.py:156 templates/preferences/display_preferences.html:54 +#: preferences/forms.py:159 +#: preferences/templates/preferences/display_preferences.html:54 msgid "Email address for automatic emailing" msgstr "Adresse mail pour les mails automatiques" -#: forms.py:158 templates/preferences/display_preferences.html:76 +#: preferences/forms.py:161 +#: preferences/templates/preferences/display_preferences.html:76 msgid "Summary of the General Terms of Use" msgstr "Résumé des Conditions Générales d'Utilisation" -#: forms.py:160 templates/preferences/display_preferences.html:78 +#: preferences/forms.py:163 +#: preferences/templates/preferences/display_preferences.html:78 msgid "General Terms of Use" msgstr "Conditions Générales d'Utilisation" -#: forms.py:176 +#: preferences/forms.py:179 msgid "Organisation name" msgstr "Nom de l'association" -#: forms.py:177 templates/preferences/display_preferences.html:323 +#: preferences/forms.py:180 +#: preferences/templates/preferences/display_preferences.html:323 msgid "SIRET number" msgstr "Numéro SIRET" -#: forms.py:178 +#: preferences/forms.py:181 msgid "Address (line 1)" msgstr "Adresse (ligne 1)" -#: forms.py:179 +#: preferences/forms.py:182 msgid "Address (line 2)" msgstr "Adresse (ligne 2)" -#: forms.py:180 models.py:476 -#: templates/preferences/display_preferences.html:331 +#: preferences/forms.py:183 preferences/models.py:477 +#: preferences/templates/preferences/display_preferences.html:331 msgid "Contact email address" msgstr "Adresse mail de contact" -#: forms.py:181 templates/preferences/display_preferences.html:335 +#: preferences/forms.py:184 +#: preferences/templates/preferences/display_preferences.html:335 msgid "Telephone number" msgstr "Numéro de téléphone" -#: forms.py:182 templates/preferences/display_preferences.html:337 +#: preferences/forms.py:185 +#: preferences/templates/preferences/display_preferences.html:337 msgid "Usual name" msgstr "Nom d'usage" -#: forms.py:183 +#: preferences/forms.py:186 msgid "Account used for editing from /admin" msgstr "Compte utilisé pour les modifications depuis /admin" -#: forms.py:185 -msgid "Payment" -msgstr "Paiement" - -#: forms.py:186 -msgid "Payment ID" -msgstr "ID de paiement" - -#: forms.py:187 -msgid "Payment password" -msgstr "Mot de passe de paiement" - -#: forms.py:188 forms.py:267 templates/preferences/aff_service.html:33 +#: preferences/forms.py:188 preferences/forms.py:274 +#: preferences/templates/preferences/aff_service.html:33 msgid "Description" msgstr "Description" -#: forms.py:204 +#: preferences/forms.py:204 msgid "Message for the French welcome email" msgstr "Message pour le mail de bienvenue en français" -#: forms.py:206 +#: preferences/forms.py:206 msgid "Message for the English welcome email" msgstr "Message pour le mail de bienvenue en anglais" -#: forms.py:223 +#: preferences/forms.py:223 msgid "Facebook URL" msgstr "URL du compte Facebook" -#: forms.py:224 +#: preferences/forms.py:224 msgid "Twitter URL" msgstr "URL du compte Twitter" -#: forms.py:225 templates/preferences/display_preferences.html:445 +#: preferences/forms.py:225 +#: preferences/templates/preferences/display_preferences.html:495 msgid "Twitter account name" msgstr "Nom du compte Twitter" -#: forms.py:247 +#: preferences/forms.py:247 msgid "You chose to set vlan but did not set any VLAN." msgstr "" "Vous avez choisi de paramétrer vlan mais vous n'avez indiqué aucun VLAN." -#: forms.py:251 +#: preferences/forms.py:251 msgid "Please, choose a VLAN." msgstr "Veuillez choisir un VLAN." -#: forms.py:265 templates/preferences/aff_service.html:31 -#: templates/preferences/display_preferences.html:321 +#: preferences/forms.py:272 +#: preferences/templates/preferences/aff_service.html:31 +#: preferences/templates/preferences/display_preferences.html:321 msgid "Name" msgstr "Nom" -#: forms.py:266 templates/preferences/aff_service.html:32 +#: preferences/forms.py:273 +#: preferences/templates/preferences/aff_service.html:32 msgid "URL" msgstr "URL" -#: forms.py:268 templates/preferences/aff_service.html:34 +#: preferences/forms.py:275 +#: preferences/templates/preferences/aff_service.html:34 msgid "Image" msgstr "Image" -#: forms.py:275 +#: preferences/forms.py:282 msgid "Current services" msgstr "Services actuels" -#: forms.py:362 +#: preferences/forms.py:369 msgid "Current email addresses" msgstr "Adresses mail actuelles" -#: models.py:76 +#: preferences/forms.py:403 +msgid "Available document templates" +msgstr "" + +#: preferences/models.py:77 msgid "Users can create a club." msgstr "Les utilisateurs peuvent créer un club." -#: models.py:80 +#: preferences/models.py:81 msgid "Users can create a member." msgstr "Les utilisateurs peuvent créer un adhérent." -#: models.py:91 +#: preferences/models.py:92 msgid "Users can edit their shell." msgstr "Les utilisateurs peuvent modifier leur interface en ligne de commande." -#: models.py:95 +#: preferences/models.py:96 msgid "Users can edit their room." msgstr "Les utilisateurs peuvent modifier leur chambre." -#: models.py:99 +#: preferences/models.py:100 msgid "Enable local email accounts for users." msgstr "Activer les comptes mail locaux pour les utilisateurs." -#: models.py:104 +#: preferences/models.py:105 msgid "Domain to use for local email accounts" msgstr "Domaine à utiliser pour les comptes mail locaux" -#: models.py:108 +#: preferences/models.py:109 msgid "Maximum number of local email addresses for a standard user." msgstr "" "Nombre maximum d'adresses mail locales autorisé pour un utilisateur standard." -#: models.py:113 +#: preferences/models.py:114 msgid "Not yet active users will be deleted after this number of days." msgstr "" "Les utilisateurs n'ayant jamais adhéré seront supprimés après ce nombre de " "jours." -#: models.py:118 +#: preferences/models.py:119 msgid "A new user can create their account on Re2o." msgstr "Un nouvel utilisateur peut créer son compte sur Re2o." -#: models.py:122 +#: preferences/models.py:123 msgid "" "If True, all new created and connected users are active. If False, only when " "a valid registration has been paid." @@ -266,154 +276,160 @@ msgstr "" "Si True, tous les nouveaux utilisations créés et connectés sont actifs. Si " "False, seulement quand une inscription validée a été payée." -#: models.py:128 +#: preferences/models.py:129 msgid "Can view the user options" msgstr "Peut voir les options d'utilisateur" -#: models.py:130 +#: preferences/models.py:131 msgid "user options" msgstr "options d'utilisateur" -#: models.py:137 +#: preferences/models.py:138 msgid "Email domain must begin with @" msgstr "Un domaine mail doit commencer par @" -#: models.py:155 +#: preferences/models.py:156 msgid "Autoconfiguration by RA" msgstr "Configuration automatique par RA" -#: models.py:156 +#: preferences/models.py:157 msgid "IP addresses assigning by DHCPv6" msgstr "Attribution d'adresses IP par DHCPv6" -#: models.py:157 +#: preferences/models.py:158 msgid "Disabled" msgstr "Désactivé" -#: models.py:179 +#: preferences/models.py:180 msgid "Can view the machine options" msgstr "Peut voir les options de machine" -#: models.py:181 +#: preferences/models.py:182 msgid "machine options" msgstr "options de machine" -#: models.py:200 models.py:592 +#: preferences/models.py:201 preferences/models.py:599 msgid "On the IP range's VLAN of the machine" msgstr "Sur le VLAN de la plage d'IP de la machine" -#: models.py:201 models.py:593 +#: preferences/models.py:202 preferences/models.py:600 msgid "Preset in 'VLAN for machines accepted by RADIUS'" msgstr "Prédéfinie dans 'VLAN pour les machines acceptées par RADIUS'" -#: models.py:210 templates/preferences/display_preferences.html:246 +#: preferences/models.py:211 +#: preferences/templates/preferences/display_preferences.html:246 msgid "Web management, activated in case of automatic provision" msgstr "Gestion web, activée en cas de provision automatique" -#: models.py:214 +#: preferences/models.py:215 msgid "" "SSL web management, make sure that a certificate is installed on the switch" msgstr "" "Gestion web SSL, vérifiez qu'un certificat est installé sur le commutateur " "réseau" -#: models.py:219 templates/preferences/display_preferences.html:248 +#: preferences/models.py:220 +#: preferences/templates/preferences/display_preferences.html:248 msgid "REST management, activated in case of automatic provision" msgstr "Gestion REST, activée en cas de provision automatique" -#: models.py:226 templates/preferences/display_preferences.html:262 +#: preferences/models.py:227 +#: preferences/templates/preferences/display_preferences.html:262 msgid "IP range for the management of switches" msgstr "Plage d'IP pour la gestion des commutateurs réseau" -#: models.py:232 templates/preferences/display_preferences.html:270 +#: preferences/models.py:233 +#: preferences/templates/preferences/display_preferences.html:270 msgid "Provision of configuration mode for switches" msgstr "Mode de provision de configuration pour les commutateurs réseau" -#: models.py:238 +#: preferences/models.py:239 msgid "SFTP login for switches" msgstr "Identifiant SFTP pour les commutateurs réseau" -#: models.py:244 +#: preferences/models.py:245 msgid "SFTP password" msgstr "Mot de passe SFTP" -#: models.py:303 +#: preferences/models.py:304 msgid "Can view the topology options" msgstr "Peut voir les options de topologie" -#: models.py:305 +#: preferences/models.py:306 msgid "topology options" msgstr "options de topologie" -#: models.py:319 models.py:337 +#: preferences/models.py:320 preferences/models.py:338 msgid "RADIUS key" msgstr "Clé RADIUS" -#: models.py:325 +#: preferences/models.py:326 msgid "Comment for this key" msgstr "Commentaire pour cette clé" -#: models.py:330 +#: preferences/models.py:331 msgid "Default key for switches" msgstr "Clé par défaut pour les commutateurs réseau" -#: models.py:335 +#: preferences/models.py:336 msgid "Can view a RADIUS key object" msgstr "Peut voir un objet clé RADIUS" -#: models.py:338 templates/preferences/display_preferences.html:221 +#: preferences/models.py:339 +#: preferences/templates/preferences/display_preferences.html:221 msgid "RADIUS keys" msgstr "clés RADIUS" -#: models.py:341 +#: preferences/models.py:342 msgid "RADIUS key " msgstr "clé RADIUS " -#: models.py:348 templates/preferences/aff_switchmanagementcred.html:31 +#: preferences/models.py:349 +#: preferences/templates/preferences/aff_switchmanagementcred.html:31 msgid "Switch login" msgstr "Identifiant du commutateur réseau" -#: models.py:352 +#: preferences/models.py:353 msgid "Password" msgstr "Mot de passe" -#: models.py:357 +#: preferences/models.py:358 msgid "Default credentials for switches" msgstr "Identifiants par défaut pour les commutateurs réseau" -#: models.py:362 +#: preferences/models.py:363 msgid "Can view a switch management credentials object" msgstr "Peut voir un objet identifiants de gestion de commutateur réseau" -#: models.py:365 +#: preferences/models.py:366 msgid "switch management credentials" msgstr "identifiants de gestion de commutateur réseau" -#: models.py:368 +#: preferences/models.py:369 msgid "Switch login " msgstr "Identifiant du commutateur réseau " -#: models.py:380 +#: preferences/models.py:381 msgid "Delay between the email and the membership's end" msgstr "Délai entre le mail et la fin d'adhésion" -#: models.py:387 +#: preferences/models.py:388 msgid "Message displayed specifically for this reminder" msgstr "Message affiché spécifiquement pour ce rappel" -#: models.py:392 +#: preferences/models.py:393 msgid "Can view a reminder object" msgstr "Peut voir un objet rappel" -#: models.py:394 +#: preferences/models.py:395 msgid "reminder" msgstr "rappel" -#: models.py:395 +#: preferences/models.py:396 msgid "reminders" msgstr "rappels" -#: models.py:412 +#: preferences/models.py:413 msgid "" "General message displayed on the French version of the website (e.g. in case " "of maintenance)" @@ -421,7 +437,7 @@ msgstr "" "Message général affiché sur la version française du site (ex : en cas de " "maintenance)" -#: models.py:418 +#: preferences/models.py:419 msgid "" "General message displayed on the English version of the website (e.g. in " "case of maintenance)" @@ -429,131 +445,140 @@ msgstr "" "Message général affiché sur la version anglaise du site (ex : en cas de " "maintenance)" -#: models.py:441 +#: preferences/models.py:442 msgid "Can view the general options" msgstr "Peut voir les options générales" -#: models.py:443 +#: preferences/models.py:444 msgid "general options" msgstr "options générales" -#: models.py:463 +#: preferences/models.py:464 msgid "Can view the service options" msgstr "Peut voir les options de service" -#: models.py:465 +#: preferences/models.py:466 msgid "service" msgstr "service" -#: models.py:466 +#: preferences/models.py:467 msgid "services" msgstr "services" -#: models.py:482 +#: preferences/models.py:483 msgid "Description of the associated email address." msgstr "Description de l'adresse mail associée." -#: models.py:492 +#: preferences/models.py:493 msgid "Can view a contact email address object" msgstr "Peut voir un objet adresse mail de contact" -#: models.py:494 +#: preferences/models.py:495 msgid "contact email address" msgstr "adresse mail de contact" -#: models.py:495 +#: preferences/models.py:496 msgid "contact email addresses" msgstr "adresses mail de contact" -#: models.py:505 +#: preferences/models.py:506 msgid "Networking organisation school Something" msgstr "Association de réseau de l'école Machin" -#: models.py:509 +#: preferences/models.py:510 msgid "Threadneedle Street" msgstr "1 rue de la Vrillière" -#: models.py:510 +#: preferences/models.py:511 msgid "London EC2R 8AH" msgstr "75001 Paris" -#: models.py:513 +#: preferences/models.py:514 msgid "Organisation" msgstr "Association" -#: models.py:527 +#: preferences/models.py:528 +#: preferences/templates/preferences/display_preferences.html:347 +msgid "President of the association" +msgstr "Président de l'association" + +#: preferences/models.py:529 +msgid "Displayed on subscription vouchers" +msgstr "" + +#: preferences/models.py:534 msgid "Can view the organisation options" msgstr "Peut voir les options d'association" -#: models.py:529 +#: preferences/models.py:536 msgid "organisation options" msgstr "options d'association" -#: models.py:558 +#: preferences/models.py:565 msgid "Can view the homepage options" msgstr "Peut voir les options de page d'accueil" -#: models.py:560 +#: preferences/models.py:567 msgid "homepage options" msgstr "options de page d'accueil" -#: models.py:573 +#: preferences/models.py:580 msgid "Welcome email in French" msgstr "Mail de bienvenue en français" -#: models.py:574 +#: preferences/models.py:581 msgid "Welcome email in English" msgstr "Mail de bienvenue en anglais" -#: models.py:578 +#: preferences/models.py:585 msgid "Can view the email message options" msgstr "Peut voir les options de message pour les mails" -#: models.py:581 +#: preferences/models.py:588 msgid "email message options" msgstr "options de messages pour les mails" -#: models.py:586 +#: preferences/models.py:593 msgid "RADIUS policy" msgstr "Politique de RADIUS" -#: models.py:587 +#: preferences/models.py:594 msgid "RADIUS policies" msgstr "Politiques de RADIUS" -#: models.py:598 +#: preferences/models.py:605 msgid "Reject the machine" msgstr "Rejeter la machine" -#: models.py:599 +#: preferences/models.py:606 msgid "Place the machine on the VLAN" msgstr "Placer la machine sur le VLAN" -#: models.py:610 +#: preferences/models.py:617 msgid "Policy for unknown machines" msgstr "Politique pour les machines inconnues" -#: models.py:618 +#: preferences/models.py:625 msgid "Unknown machines VLAN" msgstr "VLAN pour les machines inconnues" -#: models.py:619 +#: preferences/models.py:626 msgid "VLAN for unknown machines if not rejected" msgstr "VLAN pour les machines inconnues si non rejeté" -#: models.py:625 +#: preferences/models.py:632 msgid "Policy for unknown ports" msgstr "Politique pour les ports inconnus" -#: models.py:633 +#: preferences/models.py:640 msgid "Unknown ports VLAN" msgstr "VLAN pour les ports inconnus" -#: models.py:634 +#: preferences/models.py:641 msgid "VLAN for unknown ports if not rejected" msgstr "VLAN pour les ports inconnus si non rejeté" -#: models.py:640 +#: preferences/models.py:647 msgid "" "Policy for machines connecting from unregistered rooms (relevant on ports " "with STRICT RADIUS mode)" @@ -561,67 +586,107 @@ msgstr "" "Politique pour les machines se connectant depuis des chambre non " "enregistrées (pertinent pour les ports avec le mode de RADIUS STRICT)" -#: models.py:649 +#: preferences/models.py:656 msgid "Unknown rooms VLAN" msgstr "VLAN pour les chambres inconnues" -#: models.py:650 +#: preferences/models.py:657 msgid "VLAN for unknown rooms if not rejected" msgstr "VLAN pour les chambres inconnues si non rejeté" -#: models.py:656 +#: preferences/models.py:663 msgid "Policy for non members" msgstr "Politique pour les non adhérents" -#: models.py:664 +#: preferences/models.py:671 msgid "Non members VLAN" msgstr "VLAN pour les non adhérents" -#: models.py:665 +#: preferences/models.py:672 msgid "VLAN for non members if not rejected" msgstr "VLAN pour les non adhérents si non rejeté" -#: models.py:671 +#: preferences/models.py:678 msgid "Policy for banned users" msgstr "Politique pour les utilisateurs bannis" -#: models.py:679 +#: preferences/models.py:686 msgid "Banned users VLAN" msgstr "VLAN pour les utilisateurs bannis" -#: models.py:680 +#: preferences/models.py:687 msgid "VLAN for banned users if not rejected" msgstr "VLAN pour les utilisateurs bannis si non rejeté" -#: templates/preferences/aff_mailcontact.html:31 -#: templates/preferences/display_preferences.html:327 +#: preferences/models.py:716 +msgid "cotisations options" +msgstr "options de cotisation" + +#: preferences/models.py:720 +msgid "Template for invoices" +msgstr "" + +#: preferences/models.py:727 +msgid "Template for subscription voucher" +msgstr "" + +#: preferences/models.py:733 +msgid "Send voucher by email when the invoice is controlled." +msgstr "" + +#: preferences/models.py:744 +msgid "template" +msgstr "" + +#: preferences/models.py:748 +msgid "name" +msgstr "" + +#: preferences/models.py:753 +msgid "document template" +msgstr "" + +#: preferences/models.py:754 +msgid "document templates" +msgstr "" + +#: preferences/templates/preferences/aff_document_template.html:32 +msgid "Document template" +msgstr "" + +#: preferences/templates/preferences/aff_document_template.html:33 +msgid "File" +msgstr "" + +#: preferences/templates/preferences/aff_mailcontact.html:31 +#: preferences/templates/preferences/display_preferences.html:327 msgid "Address" msgstr "Adresse" -#: templates/preferences/aff_mailcontact.html:32 -#: templates/preferences/aff_radiuskey.html:32 +#: preferences/templates/preferences/aff_mailcontact.html:32 +#: preferences/templates/preferences/aff_radiuskey.html:32 msgid "Comment" msgstr "Commentaire" -#: templates/preferences/aff_radiuskey.html:31 +#: preferences/templates/preferences/aff_radiuskey.html:31 msgid "RADIUS key ID" msgstr "ID de la clé RADIUS" -#: templates/preferences/aff_radiuskey.html:33 +#: preferences/templates/preferences/aff_radiuskey.html:33 msgid "Default RADIUS key for switches" msgstr "Clé RADIUS par défaut pour les commutateurs réseau" -#: templates/preferences/aff_radiuskey.html:34 +#: preferences/templates/preferences/aff_radiuskey.html:34 msgid "RADIUS key used by the swithes" msgstr "Clé RADIUS utilisée par les commutateurs réseau" -#: templates/preferences/aff_radiusoptions.html:28 -#: templates/preferences/display_preferences.html:204 +#: preferences/templates/preferences/aff_radiusoptions.html:28 +#: preferences/templates/preferences/display_preferences.html:204 msgid "General policy for VLAN setting" msgstr "Politique générale pour le placement sur un VLAN" -#: templates/preferences/aff_radiusoptions.html:30 -#: templates/preferences/display_preferences.html:206 +#: preferences/templates/preferences/aff_radiusoptions.html:30 +#: preferences/templates/preferences/display_preferences.html:206 msgid "" "This setting defines the VLAN policy after acceptance by RADIUS: either on " "the IP range's VLAN of the machine, or a VLAN preset in 'VLAN for machines " @@ -631,98 +696,98 @@ msgstr "" "par RADIUS: soit sur le VLAN de la plage d'IP de la machine, soit sur le " "VLAN prédéfini dans 'VLAN pour les machines acceptées par RADIUS'" -#: templates/preferences/aff_radiusoptions.html:33 -#: templates/preferences/display_preferences.html:210 +#: preferences/templates/preferences/aff_radiusoptions.html:33 +#: preferences/templates/preferences/display_preferences.html:210 msgid "VLAN for machines accepted by RADIUS" msgstr "VLAN pour les machines acceptées par RADIUS" -#: templates/preferences/aff_radiusoptions.html:34 +#: preferences/templates/preferences/aff_radiusoptions.html:34 #, python-format msgid "VLAN %(vlan_decision_ok)s" msgstr "VLAN %(vlan_decision_ok)s" -#: templates/preferences/aff_radiusoptions.html:41 +#: preferences/templates/preferences/aff_radiusoptions.html:41 msgid "Situation" msgstr "Situation" -#: templates/preferences/aff_radiusoptions.html:42 +#: preferences/templates/preferences/aff_radiusoptions.html:42 msgid "Behaviour" msgstr "Comportement" -#: templates/preferences/aff_radiusoptions.html:46 +#: preferences/templates/preferences/aff_radiusoptions.html:46 msgid "Unknown machine" msgstr "Machine inconnue" -#: templates/preferences/aff_radiusoptions.html:49 -#: templates/preferences/aff_radiusoptions.html:59 -#: templates/preferences/aff_radiusoptions.html:69 -#: templates/preferences/aff_radiusoptions.html:79 -#: templates/preferences/aff_radiusoptions.html:89 +#: preferences/templates/preferences/aff_radiusoptions.html:49 +#: preferences/templates/preferences/aff_radiusoptions.html:59 +#: preferences/templates/preferences/aff_radiusoptions.html:69 +#: preferences/templates/preferences/aff_radiusoptions.html:79 +#: preferences/templates/preferences/aff_radiusoptions.html:89 msgid "Reject" msgstr "Rejeter" -#: templates/preferences/aff_radiusoptions.html:51 +#: preferences/templates/preferences/aff_radiusoptions.html:51 #, python-format msgid "VLAN %(unknown_machine_vlan)s" msgstr "VLAN %(unknown_machine_vlan)s" -#: templates/preferences/aff_radiusoptions.html:56 +#: preferences/templates/preferences/aff_radiusoptions.html:56 msgid "Unknown port" msgstr "Port inconnu" -#: templates/preferences/aff_radiusoptions.html:61 +#: preferences/templates/preferences/aff_radiusoptions.html:61 #, python-format msgid "VLAN %(unknown_port_vlan)s" msgstr "VLAN %(unknown_port_vlan)s" -#: templates/preferences/aff_radiusoptions.html:66 +#: preferences/templates/preferences/aff_radiusoptions.html:66 msgid "Unknown room" msgstr "Chambre inconnue" -#: templates/preferences/aff_radiusoptions.html:71 +#: preferences/templates/preferences/aff_radiusoptions.html:71 #, python-format msgid "VLAN %(unknown_room_vlan)s" msgstr "VLAN %(unknown_room_vlan)s" -#: templates/preferences/aff_radiusoptions.html:76 +#: preferences/templates/preferences/aff_radiusoptions.html:76 msgid "Non member" msgstr "Non adhérent" -#: templates/preferences/aff_radiusoptions.html:81 +#: preferences/templates/preferences/aff_radiusoptions.html:81 #, python-format msgid "VLAN %(non_member_vlan)s" msgstr "VLAN %(non_member_vlan)s" -#: templates/preferences/aff_radiusoptions.html:86 +#: preferences/templates/preferences/aff_radiusoptions.html:86 msgid "Banned user" msgstr "Utilisateur banni" -#: templates/preferences/aff_radiusoptions.html:91 +#: preferences/templates/preferences/aff_radiusoptions.html:91 #, python-format msgid "VLAN %(banned_vlan)s" msgstr "VLAN %(banned_vlan)s" -#: templates/preferences/aff_reminder.html:31 +#: preferences/templates/preferences/aff_reminder.html:31 msgid "Number of days before the reminder" msgstr "Nombre de jours avant le rappel" -#: templates/preferences/aff_reminder.html:32 +#: preferences/templates/preferences/aff_reminder.html:32 msgid "Message for this reminder" msgstr "Message pour ce rappel" -#: templates/preferences/aff_switchmanagementcred.html:32 +#: preferences/templates/preferences/aff_switchmanagementcred.html:32 msgid "Default switch management credentials" msgstr "Identifiants de gestion de commutateur réseau par défaut" -#: templates/preferences/aff_switchmanagementcred.html:33 +#: preferences/templates/preferences/aff_switchmanagementcred.html:33 msgid "Management credentials used by the switches" msgstr "Identifiants de gestion utilisés par les commutateurs réseau" -#: templates/preferences/delete.html:29 +#: preferences/templates/preferences/delete.html:29 msgid "Deletion of preferences" msgstr "Suppression de préférences" -#: templates/preferences/delete.html:35 +#: preferences/templates/preferences/delete.html:35 #, python-format msgid "" "Warning: are you sure you want to delete this %(objet_name)s object " @@ -731,346 +796,375 @@ msgstr "" "Attention : voulez-vous vraiment supprimer cet objet %(objet_name)s " "( %(objet)s ) ?" -#: templates/preferences/delete.html:36 +#: preferences/templates/preferences/delete.html:36 msgid "Confirm" msgstr "Confirmer" -#: templates/preferences/display_preferences.html:31 -#: templates/preferences/edit_preferences.html:30 -#: templates/preferences/preferences.html:30 +#: preferences/templates/preferences/display_preferences.html:31 +#: preferences/templates/preferences/edit_preferences.html:30 +#: preferences/templates/preferences/preferences.html:30 msgid "Preferences" msgstr "Préférences" -#: templates/preferences/display_preferences.html:39 +#: preferences/templates/preferences/display_preferences.html:39 msgid "General preferences" msgstr "Préférences générales" -#: templates/preferences/display_preferences.html:46 -#: templates/preferences/display_preferences.html:108 -#: templates/preferences/display_preferences.html:165 -#: templates/preferences/display_preferences.html:199 -#: templates/preferences/display_preferences.html:240 -#: templates/preferences/display_preferences.html:301 -#: templates/preferences/display_preferences.html:316 -#: templates/preferences/display_preferences.html:360 -#: templates/preferences/display_preferences.html:438 -#: templates/preferences/edit_preferences.html:46 views.py:178 views.py:226 -#: views.py:272 views.py:321 views.py:381 +#: preferences/templates/preferences/display_preferences.html:46 +#: preferences/templates/preferences/display_preferences.html:108 +#: preferences/templates/preferences/display_preferences.html:165 +#: preferences/templates/preferences/display_preferences.html:199 +#: preferences/templates/preferences/display_preferences.html:240 +#: preferences/templates/preferences/display_preferences.html:301 +#: preferences/templates/preferences/display_preferences.html:316 +#: preferences/templates/preferences/display_preferences.html:410 +#: preferences/templates/preferences/display_preferences.html:488 +#: preferences/templates/preferences/edit_preferences.html:46 +#: preferences/views.py:186 preferences/views.py:234 preferences/views.py:280 +#: preferences/views.py:329 preferences/views.py:389 preferences/views.py:461 msgid "Edit" msgstr "Modifier" -#: templates/preferences/display_preferences.html:60 +#: preferences/templates/preferences/display_preferences.html:60 msgid "Number of items per page (standard size)" msgstr "Nombre d'éléments par page (taille standard)" -#: templates/preferences/display_preferences.html:64 +#: preferences/templates/preferences/display_preferences.html:64 msgid "Number of items per page (large size)" msgstr "Nombre d'éléments par page (taille importante)" -#: templates/preferences/display_preferences.html:70 +#: preferences/templates/preferences/display_preferences.html:70 msgid "General message displayed on the website" msgstr "Message général affiché sur le site" -#: templates/preferences/display_preferences.html:72 +#: preferences/templates/preferences/display_preferences.html:72 msgid "Main site URL" msgstr "URL du site principal" -#: templates/preferences/display_preferences.html:84 +#: preferences/templates/preferences/display_preferences.html:84 msgid "Local email accounts enabled" msgstr "Comptes mail locaux activés" -#: templates/preferences/display_preferences.html:86 +#: preferences/templates/preferences/display_preferences.html:86 msgid "Local email domain" msgstr "Domaine de mail local" -#: templates/preferences/display_preferences.html:90 +#: preferences/templates/preferences/display_preferences.html:90 msgid "Maximum number of email aliases allowed" msgstr "Nombre maximum d'alias mail autorisé pour un utilisateur standard" -#: templates/preferences/display_preferences.html:100 +#: preferences/templates/preferences/display_preferences.html:100 msgid "User preferences" msgstr "Préférences d'utilisateur" -#: templates/preferences/display_preferences.html:114 +#: preferences/templates/preferences/display_preferences.html:114 msgid "Creation of members by everyone" msgstr "Création d'adhérents par tous" -#: templates/preferences/display_preferences.html:116 +#: preferences/templates/preferences/display_preferences.html:116 msgid "Creation of clubs by everyone" msgstr "Création de clubs par tous" -#: templates/preferences/display_preferences.html:122 +#: preferences/templates/preferences/display_preferences.html:122 msgid "Delete not yet active users after" msgstr "Suppression des utilisateurs n'ayant jamais adhéré après" -#: templates/preferences/display_preferences.html:123 +#: preferences/templates/preferences/display_preferences.html:123 #, python-format msgid "%(delete_notyetactive)s days" msgstr "%(delete_notyetactive)s jours" -#: templates/preferences/display_preferences.html:126 +#: preferences/templates/preferences/display_preferences.html:126 msgid "All users are active by default" msgstr "Tous les utilisateurs sont actifs par défault" -#: templates/preferences/display_preferences.html:131 +#: preferences/templates/preferences/display_preferences.html:131 msgid "Users general permissions" msgstr "Permissions générales des utilisateurs" -#: templates/preferences/display_preferences.html:134 +#: preferences/templates/preferences/display_preferences.html:134 msgid "Default shell for users" msgstr "Interface en ligne de commande par défaut pour les utilisateurs" -#: templates/preferences/display_preferences.html:136 +#: preferences/templates/preferences/display_preferences.html:136 msgid "Users can edit their shell" msgstr "Les utilisateurs peuvent modifier leur interface en ligne de commande" -#: templates/preferences/display_preferences.html:140 +#: preferences/templates/preferences/display_preferences.html:140 msgid "Users can edit their room" msgstr "Les utilisateurs peuvent modifier leur chambre" -#: templates/preferences/display_preferences.html:146 +#: preferences/templates/preferences/display_preferences.html:146 msgid "GPG fingerprint field" msgstr "Champ empreinte GPG" -#: templates/preferences/display_preferences.html:157 +#: preferences/templates/preferences/display_preferences.html:157 msgid "Machines preferences" msgstr "Préférences de machines" -#: templates/preferences/display_preferences.html:170 +#: preferences/templates/preferences/display_preferences.html:170 msgid "Password per machine" msgstr "Mot de passe par machine" -#: templates/preferences/display_preferences.html:178 +#: preferences/templates/preferences/display_preferences.html:178 msgid "IPv6 support" msgstr "Support de l'IPv6" -#: templates/preferences/display_preferences.html:182 +#: preferences/templates/preferences/display_preferences.html:182 msgid "Creation of machines" msgstr "Création de machines" -#: templates/preferences/display_preferences.html:192 +#: preferences/templates/preferences/display_preferences.html:192 msgid "Topology preferences" msgstr "Préférences de topologie" -#: templates/preferences/display_preferences.html:212 +#: preferences/templates/preferences/display_preferences.html:212 msgid "VLAN for machines rejected by RADIUS" msgstr "VLAN pour les machines rejetées par RADIUS" -#: templates/preferences/display_preferences.html:216 +#: preferences/templates/preferences/display_preferences.html:216 msgid "VLAN for non members machines" msgstr "VLAN pour les machines des non adhérents" -#: templates/preferences/display_preferences.html:223 +#: preferences/templates/preferences/display_preferences.html:223 msgid " Add a RADIUS key" msgstr " Ajouter une clé RADIUS" -#: templates/preferences/display_preferences.html:233 +#: preferences/templates/preferences/display_preferences.html:233 msgid "Configuration of switches" msgstr "Configuration de commutateurs réseau" -#: templates/preferences/display_preferences.html:255 +#: preferences/templates/preferences/display_preferences.html:255 msgid "Provision of configuration for switches" msgstr "Provision de configuration pour les commutateurs réseau" -#: templates/preferences/display_preferences.html:258 +#: preferences/templates/preferences/display_preferences.html:258 msgid "Switches with automatic provision" msgstr "Commutateurs réseau avec provision automatique" -#: templates/preferences/display_preferences.html:259 -#: templates/preferences/display_preferences.html:263 -#: templates/preferences/display_preferences.html:267 -#: templates/preferences/display_preferences.html:275 -#: templates/preferences/display_preferences.html:279 -#: templates/preferences/display_preferences.html:289 +#: preferences/templates/preferences/display_preferences.html:259 +#: preferences/templates/preferences/display_preferences.html:263 +#: preferences/templates/preferences/display_preferences.html:267 +#: preferences/templates/preferences/display_preferences.html:275 +#: preferences/templates/preferences/display_preferences.html:279 +#: preferences/templates/preferences/display_preferences.html:289 msgid "OK" msgstr "OK" -#: templates/preferences/display_preferences.html:259 -#: templates/preferences/display_preferences.html:263 -#: templates/preferences/display_preferences.html:267 -#: templates/preferences/display_preferences.html:289 +#: preferences/templates/preferences/display_preferences.html:259 +#: preferences/templates/preferences/display_preferences.html:263 +#: preferences/templates/preferences/display_preferences.html:267 +#: preferences/templates/preferences/display_preferences.html:289 msgid "Missing" msgstr "Manquant" -#: templates/preferences/display_preferences.html:266 +#: preferences/templates/preferences/display_preferences.html:266 msgid "Server for the configuration of switches" msgstr "Serveur pour la configuration des commutateurs réseau" -#: templates/preferences/display_preferences.html:274 +#: preferences/templates/preferences/display_preferences.html:274 msgid "TFTP mode" msgstr "Mode TFTP" -#: templates/preferences/display_preferences.html:278 +#: preferences/templates/preferences/display_preferences.html:278 msgid "SFTP mode" msgstr "Mode SFTP" -#: templates/preferences/display_preferences.html:279 +#: preferences/templates/preferences/display_preferences.html:279 msgid "Missing credentials" msgstr "Identifiants manquants" -#: templates/preferences/display_preferences.html:283 +#: preferences/templates/preferences/display_preferences.html:283 msgid "Switch management credentials" msgstr "Identifiants de gestion de commutateur réseau" -#: templates/preferences/display_preferences.html:285 +#: preferences/templates/preferences/display_preferences.html:285 msgid " Add switch management credentials" msgstr " Ajouter des identifiants de gestion de commutateur réseau" -#: templates/preferences/display_preferences.html:296 +#: preferences/templates/preferences/display_preferences.html:296 msgid "RADIUS preferences" msgstr "Préférences RADIUS" -#: templates/preferences/display_preferences.html:310 +#: preferences/templates/preferences/display_preferences.html:310 msgid "Information about the organisation" msgstr "Informations sur l'association" -#: templates/preferences/display_preferences.html:341 +#: preferences/templates/preferences/display_preferences.html:341 msgid "User object of the organisation" msgstr "Objet utilisateur de l'association" -#: templates/preferences/display_preferences.html:343 +#: preferences/templates/preferences/display_preferences.html:343 msgid "Description of the organisation" msgstr "Description de l'association" -#: templates/preferences/display_preferences.html:353 +#: preferences/templates/preferences/display_preferences.html:356 +msgid "Document templates" +msgstr "" + +#: preferences/templates/preferences/display_preferences.html:362 +msgid "Add a document template" +msgstr "Ajouter un modèle de document" + +#: preferences/templates/preferences/display_preferences.html:366 +msgid "Delete one or several document templates" +msgstr " Supprimer un ou plusieurs modèles de document" + +#: preferences/templates/preferences/display_preferences.html:375 +msgid "Cotisation's options" +msgstr "options de cotisation" + +#: preferences/templates/preferences/display_preferences.html:384 +msgid "Send voucher by email" +msgstr "" + +#: preferences/templates/preferences/display_preferences.html:388 +msgid "Invoices' template" +msgstr "" + +#: preferences/templates/preferences/display_preferences.html:392 +msgid "Vouchers' template" +msgstr "" + +#: preferences/templates/preferences/display_preferences.html:403 msgid "Message for emails" msgstr "Message pour les mails" -#: templates/preferences/display_preferences.html:366 +#: preferences/templates/preferences/display_preferences.html:416 msgid "Welcome email (in French)" msgstr "Mail de bienvenue (en français)" -#: templates/preferences/display_preferences.html:370 +#: preferences/templates/preferences/display_preferences.html:420 msgid "Welcome email (in English)" msgstr "Mail de bienvenue (en anglais)" -#: templates/preferences/display_preferences.html:380 +#: preferences/templates/preferences/display_preferences.html:430 msgid "Options for the membership's end email" msgstr "Options pour le mail de fin d'adhésion" -#: templates/preferences/display_preferences.html:386 +#: preferences/templates/preferences/display_preferences.html:436 msgid " Add a reminder" msgstr " Ajouter un rappel" -#: templates/preferences/display_preferences.html:397 +#: preferences/templates/preferences/display_preferences.html:447 msgid "List of services and homepage preferences" msgstr "Liste des services et préférences de page d'accueil" -#: templates/preferences/display_preferences.html:403 +#: preferences/templates/preferences/display_preferences.html:453 msgid " Add a service" msgstr " Ajouter un service" -#: templates/preferences/display_preferences.html:414 +#: preferences/templates/preferences/display_preferences.html:464 msgid "List of contact email addresses" msgstr "Liste des adresses mail de contact" -#: templates/preferences/display_preferences.html:420 +#: preferences/templates/preferences/display_preferences.html:470 msgid " Add an address" msgstr " Ajouter une adresse" -#: templates/preferences/display_preferences.html:422 +#: preferences/templates/preferences/display_preferences.html:472 msgid " Delete one or several addresses" msgstr " Supprimer une ou plusieurs adresses" -#: templates/preferences/display_preferences.html:431 +#: preferences/templates/preferences/display_preferences.html:481 msgid "Social networks" msgstr "Réseaux sociaux" -#: templates/preferences/display_preferences.html:443 +#: preferences/templates/preferences/display_preferences.html:493 msgid "Twitter account URL" msgstr "URL du compte Twitter" -#: templates/preferences/display_preferences.html:449 +#: preferences/templates/preferences/display_preferences.html:499 msgid "Facebook account URL" msgstr "URL du compte Facebook" -#: templates/preferences/edit_preferences.html:35 +#: preferences/templates/preferences/edit_preferences.html:35 msgid "Editing of preferences" msgstr "Modification des préférences" -#: views.py:114 +#: preferences/views.py:122 msgid "Unknown object." msgstr "Objet inconnu." -#: views.py:120 +#: preferences/views.py:128 msgid "You don't have the right to edit this option." msgstr "Vous n'avez pas le droit de modifier cette option." -#: views.py:137 +#: preferences/views.py:145 msgid "The preferences were edited." msgstr "Les préférences ont été modifiées." -#: views.py:155 +#: preferences/views.py:163 msgid "The service was added." msgstr "Le service a été ajouté." -#: views.py:158 +#: preferences/views.py:166 msgid "Add a service" msgstr "Ajouter un service" -#: views.py:175 +#: preferences/views.py:183 msgid "The service was edited." msgstr "Le service a été modifié." -#: views.py:189 +#: preferences/views.py:197 msgid "The service was deleted." msgstr "Le service a été supprimé." -#: views.py:204 +#: preferences/views.py:212 msgid "The reminder was added." msgstr "Le rappel a été ajouté." -#: views.py:207 +#: preferences/views.py:215 msgid "Add a reminder" msgstr "Ajouter un rappel" -#: views.py:223 +#: preferences/views.py:231 msgid "The reminder was edited." msgstr "Le rappel a été modifié." -#: views.py:239 +#: preferences/views.py:247 msgid "The reminder was deleted." msgstr "Le rappel a été supprimé." -#: views.py:255 +#: preferences/views.py:263 msgid "The RADIUS key was added." msgstr "La clé RADIUS a été ajoutée." -#: views.py:258 +#: preferences/views.py:266 msgid "Add a RADIUS key" msgstr "Ajouter une clé RADIUS" -#: views.py:269 +#: preferences/views.py:277 msgid "The RADIUS key was edited." msgstr "La clé RADIUS a été modifiée." -#: views.py:285 +#: preferences/views.py:293 msgid "The RADIUS key was deleted." msgstr "La clé RADIUS a été supprimée." -#: views.py:287 +#: preferences/views.py:295 msgid "The RADIUS key is assigned to at least one switch, you can't delete it." msgstr "" "La clé RADIUS est assignée a au moins un commutateur réseau, vous ne pouvez " "pas la supprimer." -#: views.py:304 +#: preferences/views.py:312 msgid "The switch management credentials were added." msgstr "Les identifiants de gestion de commutateur réseay ont été ajoutés." -#: views.py:307 +#: preferences/views.py:315 msgid "Add switch management credentials" msgstr "Ajouter des identifiants de gestion de commutateur réseau" -#: views.py:318 +#: preferences/views.py:326 msgid "The switch management credentials were edited." msgstr "Les identifiants de gestion de commutateur réseau ont été modifiés." -#: views.py:334 +#: preferences/views.py:342 msgid "The switch management credentials were deleted." msgstr "Les identifiants de gestion de commutateur réseau ont été supprimés." -#: views.py:336 +#: preferences/views.py:344 msgid "" "The switch management credentials are assigned to at least one switch, you " "can't delete them." @@ -1078,22 +1172,58 @@ msgstr "" "Les identifiants de gestion de commutateur réseau sont assignés à au moins " "un commutateur réseau , vous ne pouvez pas les supprimer." -#: views.py:357 +#: preferences/views.py:365 msgid "The contact email address was created." msgstr "L'adresse mail de contact a été supprimée." -#: views.py:361 +#: preferences/views.py:369 msgid "Add a contact email address" msgstr "Ajouter une adresse mail de contact" -#: views.py:378 +#: preferences/views.py:386 msgid "The contact email address was edited." msgstr "L'adresse mail de contact a été modifiée." -#: views.py:400 +#: preferences/views.py:408 msgid "The contact email adress was deleted." msgstr "L'adresse mail de contact a été supprimée." -#: views.py:403 +#: preferences/views.py:411 preferences/views.py:496 msgid "Delete" msgstr "Supprimer" + +#: preferences/views.py:431 +msgid "The document template was created." +msgstr "Le modèle de document a été créé." + +#: preferences/views.py:436 +msgid "Add" +msgstr "Ajouter" + +#: preferences/views.py:437 +msgid "New document template" +msgstr "Nouveau modèle de document" + +#: preferences/views.py:456 +msgid "The document template was edited." +msgstr "Le modèle de document a été édité." + +#: preferences/views.py:462 +msgid "Edit document template" +msgstr "Modifier le modèle de document" + +#: preferences/views.py:481 +#, python-format +msgid "The document template %(document_template)s was deleted." +msgstr "Le modèle de document %(document_template)s a été supprimé." + +#: preferences/views.py:488 +#, python-format +msgid "" +"The document template %(document_template)s can't be " +"deleted because it is currently being used." +msgstr "" + +#: preferences/views.py:497 +msgid "Delete document template" +msgstr "Supprimer le modèle de document" diff --git a/re2o/locale/fr/LC_MESSAGES/django.po b/re2o/locale/fr/LC_MESSAGES/django.po index 2f634fed..95c321cc 100644 --- a/re2o/locale/fr/LC_MESSAGES/django.po +++ b/re2o/locale/fr/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: 2.5\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-12 16:48+0100\n" +"POT-Creation-Date: 2019-02-12 08:58+0100\n" "PO-Revision-Date: 2018-03-31 16:09+0002\n" "Last-Translator: Laouen Fernet \n" "Language-Team: \n" @@ -30,69 +30,69 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: acl.py:142 +#: re2o/acl.py:142 msgid "Nonexistent entry." msgstr "Entrée inexistante." -#: acl.py:159 acl.py:224 +#: re2o/acl.py:159 re2o/acl.py:224 msgid "You don't have the right to access this menu." msgstr "Vous n'avez pas le droit d'accéder à ce menu." -#: acl.py:274 +#: re2o/acl.py:274 msgid "You don't have the right to edit the history." msgstr "Vous n'avez pas le droit de modifier l'historique." -#: base.py:76 +#: re2o/base.py:76 msgid "This domain is already taken." msgstr "Ce domaine est déjà pris." -#: base.py:78 +#: re2o/base.py:78 msgid "SMTP unreachable." msgstr "SMTP injoignable." -#: mixins.py:111 +#: re2o/mixins.py:111 #, python-format msgid "You don't have the right to create a %s object." msgstr "Vous n'avez pas le droit de créer un objet %s." -#: mixins.py:125 +#: re2o/mixins.py:125 #, python-format msgid "You don't have the right to edit a %s object." msgstr "Vous n'avez pas le droit de modifier un objet %s." -#: mixins.py:139 +#: re2o/mixins.py:139 #, python-format msgid "You don't have the right to delete a %s object." msgstr "Vous n'avez pas le droit de supprimer un objet %s." -#: mixins.py:153 +#: re2o/mixins.py:153 #, python-format msgid "You don't have the right to view every %s object." msgstr "Vous n'avez pas le droit de voir tous les objets %s." -#: mixins.py:167 +#: re2o/mixins.py:167 #, python-format msgid "You don't have the right to view a %s object." msgstr "Vous n'avez pas le droit de voir un objet %s." -#: settings.py:155 +#: re2o/settings.py:156 msgid "English" msgstr "Anglais" -#: settings.py:156 +#: re2o/settings.py:157 msgid "French" msgstr "Français" -#: templates/re2o/about.html:29 templates/re2o/about.html:35 +#: re2o/templates/re2o/about.html:29 re2o/templates/re2o/about.html:35 msgid "About Re2o" msgstr "À propos de Re2o" -#: templates/re2o/about.html:32 +#: re2o/templates/re2o/about.html:32 #, python-format msgid "About %(AssoName)s" msgstr "À propos de %(AssoName)s" -#: templates/re2o/about.html:36 +#: re2o/templates/re2o/about.html:36 msgid "" "Re2o is an administration tool initiated by Rezo Metz and a few members of other Remote URL: %(git_info_remote)s" msgstr "URL distante : %(git_info_remote)s" -#: templates/re2o/about.html:69 +#: re2o/templates/re2o/about.html:69 #, python-format msgid "Branch: %(git_info_branch)s" msgstr "Branche : %(git_info_branch)s" -#: templates/re2o/about.html:72 +#: re2o/templates/re2o/about.html:72 #, python-format msgid "Commit: %(git_info_commit)s" msgstr "Commit : %(git_info_commit)s" -#: templates/re2o/about.html:75 +#: re2o/templates/re2o/about.html:75 #, python-format msgid "Commit date: %(git_info_commit_date)s" msgstr "Date du commit : %(git_info_commit_date)s" -#: templates/re2o/about.html:80 +#: re2o/templates/re2o/about.html:80 msgid "Dependencies" msgstr "Dépendances" -#: templates/re2o/aff_history.html:30 +#: re2o/templates/re2o/aff_history.html:30 msgid "Next" msgstr "Suivant" -#: templates/re2o/aff_history.html:37 +#: re2o/templates/re2o/aff_history.html:37 msgid "Previous" msgstr "Précédent" -#: templates/re2o/aff_history.html:45 +#: re2o/templates/re2o/aff_history.html:45 msgid "Date" msgstr "Date" -#: templates/re2o/aff_history.html:46 +#: re2o/templates/re2o/aff_history.html:46 msgid "Performed by" msgstr "Effectuée par" -#: templates/re2o/aff_history.html:47 +#: re2o/templates/re2o/aff_history.html:47 msgid "Comment" msgstr "Commentaire" -#: templates/re2o/contact.html:29 +#: re2o/templates/re2o/contact.html:29 msgid "Contact" msgstr "Contact" -#: templates/re2o/contact.html:32 +#: re2o/templates/re2o/contact.html:32 #, python-format msgid "Contact the organisation %(asso_name)s" msgstr "Contacter l'association %(asso_name)s" -#: templates/re2o/history.html:29 +#: re2o/templates/re2o/history.html:29 msgid "History" msgstr "Historique" -#: templates/re2o/history.html:32 +#: re2o/templates/re2o/history.html:32 #, python-format msgid "History of %(object)s" msgstr "Historique de %(object)s" -#: templates/re2o/index.html:30 +#: re2o/templates/re2o/index.html:30 msgid "Home" msgstr "Accueil" -#: templates/re2o/index.html:34 +#: re2o/templates/re2o/index.html:34 #, python-format msgid "Welcome to %(name_website)s" msgstr "Bienvenue sur %(name_website)s" -#: templates/re2o/index.html:43 +#: re2o/templates/re2o/index.html:43 msgid "Registration" msgstr "Inscription" -#: templates/re2o/index.html:44 +#: re2o/templates/re2o/index.html:44 msgid "" "If you don't have an account yet and you want to access the Internet and the " "organisation's services, create your own personal account." @@ -210,15 +210,15 @@ msgstr "" "Si vous n'avez pas encore de compte et que vous voulez accéder à Internet et " "aux services de l'association, créez votre espace personnel." -#: templates/re2o/index.html:45 +#: re2o/templates/re2o/index.html:45 msgid "Sign up" msgstr "S'inscrire" -#: templates/re2o/index.html:55 +#: re2o/templates/re2o/index.html:55 msgid "Logging in" msgstr "Identification" -#: templates/re2o/index.html:56 +#: re2o/templates/re2o/index.html:56 msgid "" "If you already have an account, log in. You can manage your subscriptions to " "the organisation, your machines and all your services." @@ -226,15 +226,15 @@ msgstr "" "Si vous avez déjà un compte, identifiez-vous. Vous pouvez gérer vos " "cotisations à l'association, vos machines et tous vos services." -#: templates/re2o/index.html:57 +#: re2o/templates/re2o/index.html:57 msgid "Log in" msgstr "Se connecter" -#: templates/re2o/index.html:68 +#: re2o/templates/re2o/index.html:68 msgid "My profile" msgstr "Mon profil" -#: templates/re2o/index.html:69 +#: re2o/templates/re2o/index.html:69 msgid "" "To manage your subscriptions, your machines and all your services, access " "your profile." @@ -242,28 +242,28 @@ msgstr "" "Pour gérer vos cotisations, vos machines et tous vos services, accéder à " "votre profil." -#: templates/re2o/index.html:70 +#: re2o/templates/re2o/index.html:70 msgid "Access my profile" msgstr "Accéder à mon profil" -#: templates/re2o/index.html:79 +#: re2o/templates/re2o/index.html:79 msgid "Services of the organisation" msgstr "Services de l'association" -#: templates/re2o/index.html:93 +#: re2o/templates/re2o/index.html:93 msgid "Go there" msgstr "Accéder" -#: templates/re2o/sidebar.html:47 +#: re2o/templates/re2o/sidebar.html:47 #, python-format msgid "Tweets from @%(twitter_account_name)s" msgstr "Tweets de @%(twitter_account_name)s" -#: templates/re2o/sidebar.html:50 +#: re2o/templates/re2o/sidebar.html:50 #, python-format msgid "Follow @%(twitter_account_name)s" msgstr "Suivre @%(twitter_account_name)s" -#: views.py:87 +#: re2o/views.py:87 msgid "Unable to get the information." msgstr "Impossible d'obtenir l'information." diff --git a/search/locale/fr/LC_MESSAGES/django.po b/search/locale/fr/LC_MESSAGES/django.po index be2a79cc..21c6d0d8 100644 --- a/search/locale/fr/LC_MESSAGES/django.po +++ b/search/locale/fr/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: 2.5\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-08 23:56+0100\n" +"POT-Creation-Date: 2019-02-12 08:58+0100\n" "PO-Revision-Date: 2018-06-24 20:10+0200\n" "Last-Translator: Laouen Fernet \n" "Language-Team: \n" @@ -30,60 +30,60 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: forms.py:33 +#: search/forms.py:33 msgid "Active" msgstr "Actifs" -#: forms.py:34 +#: search/forms.py:34 msgid "Disabled" msgstr "Désactivés" -#: forms.py:35 +#: search/forms.py:35 msgid "Archived" msgstr "Archivés" -#: forms.py:36 +#: search/forms.py:36 msgid "Not yet active" msgstr "Pas encore adhéré" -#: forms.py:40 +#: search/forms.py:40 msgid "Users" msgstr "Utilisateurs" -#: forms.py:41 +#: search/forms.py:41 msgid "Machines" msgstr "Machines" -#: forms.py:42 +#: search/forms.py:42 msgid "Invoices" msgstr "Factures" -#: forms.py:43 +#: search/forms.py:43 msgid "Bans" msgstr "Bannissements" -#: forms.py:44 +#: search/forms.py:44 msgid "Whitelists" msgstr "Accès gracieux" -#: forms.py:45 +#: search/forms.py:45 msgid "Rooms" msgstr "Chambres" -#: forms.py:46 +#: search/forms.py:46 msgid "Ports" msgstr "Ports" -#: forms.py:47 +#: search/forms.py:47 msgid "Switches" msgstr "Commutateurs réseau" -#: forms.py:60 forms.py:72 templates/search/search.html:29 -#: templates/search/search.html:48 +#: search/forms.py:60 search/forms.py:72 search/templates/search/search.html:29 +#: search/templates/search/search.html:48 msgid "Search" msgstr "Rechercher" -#: forms.py:62 forms.py:74 +#: search/forms.py:62 search/forms.py:74 msgid "" "Use « » and «,» to specify distinct words, «\"query\"» for an exact search " "and «\\» to escape a character." @@ -91,77 +91,77 @@ msgstr "" "Utilisez « » et «,» pour spécifier différents mots, «\"query\"» pour une " "recherche exacte et «\\» pour échapper un caractère." -#: forms.py:81 +#: search/forms.py:81 msgid "Users filter" msgstr "Filtre utilisateurs" -#: forms.py:88 +#: search/forms.py:88 msgid "Display filter" msgstr "Filtre affichage" -#: forms.py:96 +#: search/forms.py:96 msgid "Start date" msgstr "Date de début" -#: forms.py:100 +#: search/forms.py:100 msgid "End date" msgstr "Date de fin" -#: templates/search/index.html:29 +#: search/templates/search/index.html:29 msgid "Search results" msgstr "Résultats de la recherche" -#: templates/search/index.html:33 +#: search/templates/search/index.html:33 msgid "Results among users:" msgstr "Résultats parmi les utilisateurs :" -#: templates/search/index.html:37 +#: search/templates/search/index.html:37 msgid "Results among clubs:" msgstr "Résultats parmi les clubs :" -#: templates/search/index.html:41 +#: search/templates/search/index.html:41 msgid "Results among machines:" msgstr "Résultats parmi les machines :" -#: templates/search/index.html:45 +#: search/templates/search/index.html:45 msgid "Results among invoices:" msgstr "Résultats parmi les factures :" -#: templates/search/index.html:49 +#: search/templates/search/index.html:49 msgid "Results among whitelists:" msgstr "Résultats parmi les accès à titre gracieux :" -#: templates/search/index.html:53 +#: search/templates/search/index.html:53 msgid "Results among bans:" msgstr "Résultats parmi les bannissements :" -#: templates/search/index.html:57 +#: search/templates/search/index.html:57 msgid "Results among rooms:" msgstr "Résultats parmi les chambres :" -#: templates/search/index.html:61 +#: search/templates/search/index.html:61 msgid "Results among ports:" msgstr "Résultats parmi les ports :" -#: templates/search/index.html:65 +#: search/templates/search/index.html:65 msgid "Results among switches:" msgstr "Résultats parmi les commutateurs réseau :" -#: templates/search/index.html:69 +#: search/templates/search/index.html:69 msgid "No result" msgstr "Pas de résultat" -#: templates/search/index.html:71 +#: search/templates/search/index.html:71 #, python-format msgid "(Only the first %(max_result)s results are displayed in each category)" msgstr "" "(Seulement les %(max_result)s premiers résultats sont affichés dans chaque " "catégorie)" -#: templates/search/sidebar.html:31 +#: search/templates/search/sidebar.html:31 msgid "Simple search" msgstr "Recherche simple" -#: templates/search/sidebar.html:35 +#: search/templates/search/sidebar.html:35 msgid "Advanced search" msgstr "Recherche avancée" diff --git a/templates/locale/fr/LC_MESSAGES/django.po b/templates/locale/fr/LC_MESSAGES/django.po index 2adc5854..f1c841ed 100644 --- a/templates/locale/fr/LC_MESSAGES/django.po +++ b/templates/locale/fr/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: 2.5\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-08 23:59+0100\n" +"POT-Creation-Date: 2019-02-12 08:58+0100\n" "PO-Revision-Date: 2018-03-31 16:09+0002\n" "Last-Translator: Laouen Fernet \n" "Language-Team: \n" @@ -30,160 +30,161 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: base.html:42 errors/404.html:35 +#: templates/base.html:43 templates/errors/404.html:35 msgid "Networking managing website endorsed by FedeRez." msgstr "Site de gestion de réseau soutenu par FedeRez." -#: base.html:59 +#: templates/base.html:70 msgid "Home" msgstr "Accueil" -#: base.html:80 +#: templates/base.html:91 msgid "Users" msgstr "Utilisateurs" -#: base.html:83 +#: templates/base.html:94 msgid "Manage the users" msgstr "Gérer les utilisateurs" -#: base.html:84 +#: templates/base.html:95 msgid "Manage the clubs" msgstr "Gérer les clubs" -#: base.html:87 +#: templates/base.html:98 msgid "Manage the machines" msgstr "Gérer les machines" -#: base.html:90 +#: templates/base.html:101 msgid "Manage the subscriptions" msgstr "Gérer les cotisations" -#: base.html:97 +#: templates/base.html:108 msgid "Topology" msgstr "Topologie" -#: base.html:99 +#: templates/base.html:110 msgid "Switches" msgstr "Commutateurs réseau" -#: base.html:100 +#: templates/base.html:111 msgid "Access points" msgstr "Points d'accès sans fil" -#: base.html:101 +#: templates/base.html:112 msgid "Rooms" msgstr "Chambres" -#: base.html:106 +#: templates/base.html:117 msgid "Statistics" msgstr "Statistiques" -#: base.html:111 +#: templates/base.html:122 msgid "Administration" msgstr "Administration" -#: base.html:118 +#: templates/base.html:129 msgid "More information" msgstr "Plus d'informations" -#: base.html:120 +#: templates/base.html:131 msgid "About" msgstr "À propos" -#: base.html:121 +#: templates/base.html:132 msgid "Contact" msgstr "Contact" -#: base.html:128 +#: templates/base.html:139 msgid "Sign up" msgstr "S'inscrire" -#: base.html:134 registration/login.html:29 registration/login.html:36 +#: templates/base.html:145 templates/registration/login.html:29 +#: templates/registration/login.html:36 msgid "Log in" msgstr "Se connecter" -#: base.html:142 +#: templates/base.html:153 msgid "Search" msgstr "Rechercher" -#: base.html:156 +#: templates/base.html:167 msgid "My profile" msgstr "Mon profil" -#: base.html:157 +#: templates/base.html:168 msgid "Log out" msgstr "Se déconnecter" -#: base.html:192 +#: templates/base.html:203 msgid "Username" msgstr "Pseudo" -#: base.html:196 +#: templates/base.html:207 msgid "Room" msgstr "Chambre" -#: base.html:200 +#: templates/base.html:211 msgid "Internet access" msgstr "Accès Internet" -#: base.html:203 +#: templates/base.html:214 #, python-format msgid "Until %(end_access_date)s" msgstr "Jusqu'au %(end_access_date)s" -#: base.html:205 +#: templates/base.html:216 msgid "Disabled" msgstr "Désactivé" -#: base.html:210 +#: templates/base.html:221 msgid "Membership" msgstr "Adhésion" -#: base.html:213 +#: templates/base.html:224 #, python-format msgid "Until %(end_adhesion_date)s" msgstr "Jusqu'au %(end_adhesion_date)s" -#: base.html:215 +#: templates/base.html:226 msgid "Non member" msgstr "Non adhérent" -#: base.html:223 +#: templates/base.html:234 msgid "View my profile" msgstr "Voir mon profil" -#: base.html:228 +#: templates/base.html:239 msgid "You are not logged in." msgstr "Vous n'êtes pas connecté." -#: base.html:235 +#: templates/base.html:246 #, python-format msgid "%(nb)s active machine" msgid_plural "%(nb)s active machines" msgstr[0] "%(nb)s machine active" msgstr[1] "%(nb)s machines actives" -#: base.html:244 +#: templates/base.html:255 msgid "View my machines" msgstr "Voir mes machines" -#: base.html:257 +#: templates/base.html:268 msgid "Back to top" msgstr "Retour en haut" -#: base.html:259 +#: templates/base.html:270 msgid "powered by" msgstr "propulsé par" -#: base.html:261 +#: templates/base.html:272 msgid "Brought to you with ." msgstr "Codé avec ." -#: base.html:264 +#: templates/base.html:275 msgid "About this website" msgstr "À propos de ce site" -#: base.html:267 +#: templates/base.html:278 msgid "" "This software is under the terms of the GPLv2 License." @@ -191,63 +192,63 @@ msgstr "" "Ce logiciel est sous les termes de la licence GPLv2." -#: buttons/add.html:27 +#: templates/buttons/add.html:27 msgid "Add" msgstr "Ajouter" -#: buttons/edit.html:27 +#: templates/buttons/edit.html:27 msgid "Edit" msgstr "Modifier" -#: buttons/history.html:26 buttons/history.html:27 +#: templates/buttons/history.html:26 templates/buttons/history.html:27 msgid "History" msgstr "Historique" -#: buttons/setlang.html:34 +#: templates/buttons/setlang.html:34 msgid "Translation in development" msgstr "Traduction en développement" -#: buttons/sort.html:35 +#: templates/buttons/sort.html:35 msgid "Ascending sort" msgstr "Tri croissant" -#: buttons/sort.html:36 +#: templates/buttons/sort.html:36 msgid "Descending sort" msgstr "Tri décroissant" -#: buttons/suppr.html:27 +#: templates/buttons/suppr.html:27 msgid "Delete" msgstr "Supprimer" -#: errors/404.html:39 +#: templates/errors/404.html:39 msgid "404 error: page not found" msgstr "Erreur 404 : page non trouvée" -#: errors/404.html:125 +#: templates/errors/404.html:125 msgid "Score: " msgstr "Score : " -#: errors/404.html:133 +#: templates/errors/404.html:133 msgid "YOU LOST" msgstr "VOUS AVEZ PERDU" -#: errors/404.html:220 +#: templates/errors/404.html:220 msgid "Yup, that's a 404 error." msgstr "Yep, c'est une erreur 404." -#: errors/404.html:220 +#: templates/errors/404.html:220 msgid "(Go back to a safe page)" msgstr "(Retourner à une page sécurisée)" -#: errors/404.html:222 +#: templates/errors/404.html:222 msgid "Your browser does not support the HTML5 canvas tag." msgstr "Votre navigateur ne supporte pas la balise HTML5 canvas." -#: errors/500.html:6 errors/500.html:31 +#: templates/errors/500.html:6 templates/errors/500.html:31 msgid "500 error: Re2o internal server error" msgstr "Erreur 500 : Erreur interne du serveur Re2o" -#: errors/500.html:34 +#: templates/errors/500.html:34 msgid "" "Congratulations! You have discovered a bug on Re2o and you've reached a page " "we try to hide, you can be proud of youself. We try to track those bugs down " @@ -260,7 +261,7 @@ msgstr "" "en avons raté un. Nous vous remercions sincèrement pour votre aide: ce n'est " "pas si facile de tous les attraper." -#: errors/500.html:40 +#: templates/errors/500.html:40 msgid "" "An email has been automatically sent to the site administrators. Please " "avoid spamming them by trigerring the same issue multiple times." @@ -269,7 +270,7 @@ msgstr "" "site. Veuillez éviter de déclencher la même erreur de multiples fois pour ne " "pas renvoyer de courrier électronique." -#: errors/500.html:41 +#: templates/errors/500.html:41 msgid "" "The mail should contains all the details necessary to understand what went " "wrong but if your help were needed, you will probably be contacted by them." @@ -278,7 +279,7 @@ msgstr "" "compréhension de ce qui s'est mal passé mais si votre aide était requise, " "vous serez probablement contacté par eux." -#: errors/500.html:46 +#: templates/errors/500.html:46 msgid "" "This issue will be fixed as soon as possible but please take into " "consideration the administrators may not be always available. If your " @@ -290,30 +291,30 @@ msgstr "" "temps disponibles. Si votre requête est vraiment urgente, informez votre " "association locale, elle vous aidra à corriger temporairement l'erreur." -#: errors/500.html:54 +#: templates/errors/500.html:54 msgid "If you have no idea what you've done:" msgstr "Si vous n'avez aucune idée de ce que vous avez fait :" -#: errors/500.html:55 +#: templates/errors/500.html:55 msgid "Go back to a safe page" msgstr "Retourner à une page sécurisée" -#: pagination.html:34 +#: templates/pagination.html:34 msgid "First" msgstr "Première page" -#: pagination.html:40 +#: templates/pagination.html:40 msgid "Previous" msgstr "Précédent" -#: pagination.html:60 +#: templates/pagination.html:60 msgid "Next" msgstr "Suivant" -#: pagination.html:66 +#: templates/pagination.html:66 msgid "Last" msgstr "Dernière page" -#: registration/login.html:40 +#: templates/registration/login.html:40 msgid "Forgotten password?" msgstr "Mot de passe oublié ?" diff --git a/topologie/locale/fr/LC_MESSAGES/django.po b/topologie/locale/fr/LC_MESSAGES/django.po index b6242bc0..a9424d33 100644 --- a/topologie/locale/fr/LC_MESSAGES/django.po +++ b/topologie/locale/fr/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: 2.5\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-09 00:01+0100\n" +"POT-Creation-Date: 2019-02-12 08:58+0100\n" "PO-Revision-Date: 2018-06-25 14:53+0200\n" "Last-Translator: Laouen Fernet \n" "Language-Team: \n" @@ -30,253 +30,254 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: acl.py:42 +#: topologie/acl.py:42 msgid "You don't have the right to view this application." msgstr "Vous n'avez pas le droit de voir cette application." -#: forms.py:181 +#: topologie/forms.py:181 msgid "Start:" msgstr "Début :" -#: forms.py:182 +#: topologie/forms.py:182 msgid "End:" msgstr "Fin :" -#: models.py:74 +#: topologie/models.py:74 msgid "Can view a stack object" msgstr "Peut voir un objet pile" -#: models.py:76 +#: topologie/models.py:76 msgid "switches stack" msgstr "pile de commutateurs réseau" -#: models.py:77 +#: topologie/models.py:77 msgid "switches stacks" msgstr "piles de commutateurs réseau" -#: models.py:92 +#: topologie/models.py:92 msgid "The maximum ID is less than the minimum ID." msgstr "L'ID maximum est inférieur l'ID minimum." -#: models.py:105 +#: topologie/models.py:105 msgid "Details about the AP's location" msgstr "Détails sur l'emplacement du point d'accès sans fil" -#: models.py:112 +#: topologie/models.py:112 msgid "Can view an access point object" msgstr "Peut voir un objet point d'accès sans fil" -#: models.py:114 +#: topologie/models.py:114 msgid "access point" msgstr "point d'accès sans fil" -#: models.py:115 +#: topologie/models.py:115 msgid "access points" msgstr "points d'accès sans fil" -#: models.py:211 +#: topologie/models.py:211 msgid "Number of ports" msgstr "Nombre de ports" -#: models.py:228 templates/topologie/aff_switch.html:48 -#: templates/topologie/index_p.html:38 views.py:843 +#: topologie/models.py:228 topologie/templates/topologie/aff_switch.html:48 +#: topologie/templates/topologie/index_p.html:38 topologie/views.py:843 msgid "Switch model" msgstr "Modèle de commutateur réseau" -#: models.py:241 +#: topologie/models.py:241 msgid "RADIUS key of the switch" msgstr "Clé RADIUS du commutateur réseau" -#: models.py:248 +#: topologie/models.py:248 msgid "Management credentials for the switch" msgstr "Identifiants de gestion du commutateur réseau" -#: models.py:252 +#: topologie/models.py:252 msgid "Automatic provision for the switch" msgstr "Provision automatique pour le commutateur réseau" -#: models.py:259 +#: topologie/models.py:259 msgid "Can view a switch object" msgstr "Peut voir un objet commutateur réseau" -#: models.py:261 +#: topologie/models.py:261 msgid "switch" msgstr "commutateur réseau" -#: models.py:262 +#: topologie/models.py:262 msgid "switches" msgstr "commutateurs réseau" -#: models.py:273 +#: topologie/models.py:273 msgid "The switch ID exceeds the limits allowed by the stack." msgstr "L'ID du commutateur réseau dépasse les bornes autorisées par la pile." -#: models.py:278 +#: topologie/models.py:278 msgid "The stack member ID can't be void." msgstr "L'ID de membre dans la pile ne peut-être vide." -#: models.py:286 +#: topologie/models.py:286 msgid "The end port is less than the start port." msgstr "Le port de fin est inférieur au port de début." -#: models.py:293 +#: topologie/models.py:293 msgid "This switch can't have that many ports." msgstr "Ce commutateur réseau ne peut pas avoir autant de ports." -#: models.py:295 +#: topologie/models.py:295 msgid "Creation" msgstr "Création" -#: models.py:406 +#: topologie/models.py:406 msgid "The switch model is modular." msgstr "Le modèle de commutateur réseau est modulaire." -#: models.py:410 +#: topologie/models.py:410 msgid "The switch is considered as a module." msgstr "Le commutateur réseau est considéré comme un module." -#: models.py:415 +#: topologie/models.py:415 msgid "Can view a switch model object" msgstr "Peut voir un objet modèle de commutateur réseau" -#: models.py:417 +#: topologie/models.py:417 msgid "switch model" msgstr "modèle de commutateur réseau" -#: models.py:418 +#: topologie/models.py:418 msgid "switch models" msgstr "modèles de commutateur réseau" -#: models.py:431 +#: topologie/models.py:431 msgid "Reference of a module" msgstr "Référence d'un module" -#: models.py:432 +#: topologie/models.py:432 msgid "Module reference" msgstr "Référence de module" -#: models.py:438 models.py:439 templates/topologie/aff_modules.html:37 +#: topologie/models.py:438 topologie/models.py:439 +#: topologie/templates/topologie/aff_modules.html:37 msgid "Comment" msgstr "Commentaire" -#: models.py:444 +#: topologie/models.py:444 msgid "Can view a switch module object" msgstr "Peut voir un objet module de commutateur réseau" -#: models.py:446 +#: topologie/models.py:446 msgid "switch module" msgstr "module de commutateur réseau" -#: models.py:447 +#: topologie/models.py:447 msgid "switch modules" msgstr "modules de commutateur réseau" -#: models.py:460 +#: topologie/models.py:460 msgid "Slot on switch" msgstr "Emplacement sur le commutateur réseau" -#: models.py:461 templates/topologie/aff_modules.html:48 -#: templates/topologie/aff_modules.html:82 +#: topologie/models.py:461 topologie/templates/topologie/aff_modules.html:48 +#: topologie/templates/topologie/aff_modules.html:82 msgid "Slot" msgstr "Emplacement" -#: models.py:466 +#: topologie/models.py:466 msgid "Can view a link between switch and module object" msgstr "Peut voir un objet lien entre commutateur réseau et module" -#: models.py:469 +#: topologie/models.py:469 msgid "link between switch and module" msgstr "lien entre commutateur réseau et module" -#: models.py:470 +#: topologie/models.py:470 msgid "links between switch and module" msgstr "liens entre commutateur réseau et module" -#: models.py:474 +#: topologie/models.py:474 msgid "On slot " msgstr "Sur l'emplacement " -#: models.py:474 +#: topologie/models.py:474 msgid " of " msgstr " de " -#: models.py:484 +#: topologie/models.py:484 msgid "Can view a switch constructor object" msgstr "Peut voir un objet constructeur de commutateur réseau" -#: models.py:487 +#: topologie/models.py:487 msgid "switch constructor" msgstr "constructeur de commutateur réseau" -#: models.py:510 +#: topologie/models.py:510 msgid "Can view a switch bay object" msgstr "Peut voir un objet baie de brassage" -#: models.py:512 +#: topologie/models.py:512 msgid "switch bay" msgstr "baie de brassage" -#: models.py:513 +#: topologie/models.py:513 msgid "switch bays" msgstr "baies de brassage" -#: models.py:526 +#: topologie/models.py:526 msgid "Can view a building object" msgstr "Peut voir un objet bâtiment" -#: models.py:528 +#: topologie/models.py:528 msgid "building" msgstr "bâtiment" -#: models.py:529 +#: topologie/models.py:529 msgid "buildings" msgstr "bâtiments" -#: models.py:588 models.py:589 +#: topologie/models.py:588 topologie/models.py:589 msgid "Port state Active" msgstr "État du port Actif" -#: models.py:596 +#: topologie/models.py:596 msgid "Can view a port object" msgstr "Peut voir un objet port" -#: models.py:598 +#: topologie/models.py:598 msgid "port" msgstr "port" -#: models.py:599 +#: topologie/models.py:599 msgid "ports" msgstr "ports" -#: models.py:605 +#: topologie/models.py:605 msgid "Uplink: " msgstr "Liaison montante : " -#: models.py:607 +#: topologie/models.py:607 msgid "Machine: " msgstr "Machine : " -#: models.py:609 +#: topologie/models.py:609 msgid "Room: " msgstr "Chambre : " -#: models.py:611 +#: topologie/models.py:611 msgid "Unknown" msgstr "Inconnu" -#: models.py:678 +#: topologie/models.py:678 msgid "The port can't exist, its number is too great." msgstr "Le port ne peut pas exister, son numéro est trop grand." -#: models.py:684 +#: topologie/models.py:684 msgid "Room, interface and related port are mutually exclusive." msgstr "Chambre, interface et port relié sont mutuellement exclusifs." -#: models.py:687 +#: topologie/models.py:687 msgid "A port can't be related to itself." msgstr "Un port ne peut être relié à lui-même." -#: models.py:691 +#: topologie/models.py:691 msgid "" "The related port is already used, please clear it before creating the " "relation." @@ -284,356 +285,371 @@ msgstr "" "Le port relié est déjà utilisé, veuillez le modifier avant de créer la " "relation." -#: models.py:712 +#: topologie/models.py:712 msgid "Can view a room object" msgstr "Peut voir un objet chambre" -#: models.py:714 +#: topologie/models.py:714 msgid "room" msgstr "chambre" -#: models.py:715 +#: topologie/models.py:715 msgid "rooms" msgstr "chambres" -#: models.py:726 +#: topologie/models.py:726 msgid "MAC-RADIUS" msgstr "MAC-RADIUS" -#: models.py:743 templates/topologie/aff_chambres.html:36 -#: templates/topologie/aff_port.html:38 views.py:784 +#: topologie/models.py:743 topologie/templates/topologie/aff_chambres.html:36 +#: topologie/templates/topologie/aff_port.html:38 topologie/views.py:784 msgid "Room" msgstr "Chambre" -#: models.py:744 templates/topologie/aff_ap.html:36 +#: topologie/models.py:744 topologie/templates/topologie/aff_ap.html:36 msgid "Access point" msgstr "Point d'accès sans fil" -#: models.py:745 +#: topologie/models.py:745 msgid "Uplink" msgstr "Liaison montante" -#: models.py:746 +#: topologie/models.py:746 msgid "Organisation machine" msgstr "Machine d'association" -#: models.py:747 +#: topologie/models.py:747 msgid "Nothing" msgstr "Rien" -#: models.py:749 templates/topologie/aff_port_profile.html:37 -#: templates/topologie/aff_vlanoptions.html:34 +#: topologie/models.py:749 +#: topologie/templates/topologie/aff_port_profile.html:37 +#: topologie/templates/topologie/aff_vlanoptions.html:34 msgid "Name" msgstr "Nom" -#: models.py:756 +#: topologie/models.py:756 msgid "Default profile" msgstr "Profil par défaut" -#: models.py:764 +#: topologie/models.py:764 msgid "VLAN untagged" msgstr "VLAN untagged" -#: models.py:770 +#: topologie/models.py:770 msgid "VLAN(s) tagged" msgstr "VLAN(s) tagged" -#: models.py:775 +#: topologie/models.py:775 msgid "Type of RADIUS authentication : inactive, MAC-address or 802.1X" msgstr "Type d'authentification RADIUS : inactive, MAC-address ou 802.1X" -#: models.py:777 +#: topologie/models.py:777 msgid "RADIUS type" msgstr "Type de RADIUS" -#: models.py:783 +#: topologie/models.py:783 msgid "In case of MAC-authentication : mode COMMON or STRICT on this port" msgstr "" "Dans le cas d'authentification par adresse MAC : mode COMMON ou STRICT sur " "ce port" -#: models.py:785 +#: topologie/models.py:785 msgid "RADIUS mode" msgstr "Mode de RADIUS" -#: models.py:791 +#: topologie/models.py:791 msgid "Port speed limit" msgstr "Limite de vitesse du port" -#: models.py:796 +#: topologie/models.py:796 msgid "Limit of MAC-address on this port" msgstr "Limite de MAC-address sur ce port" -#: models.py:797 +#: topologie/models.py:797 msgid "MAC limit" msgstr "Limite MAC" -#: models.py:801 +#: topologie/models.py:801 msgid "Flow control" msgstr "Contrôle du flux" -#: models.py:805 +#: topologie/models.py:805 msgid "Protect against rogue DHCP" msgstr "Protège contre les DHCP pirates" -#: models.py:806 templates/topologie/aff_vlanoptions.html:36 +#: topologie/models.py:806 +#: topologie/templates/topologie/aff_vlanoptions.html:36 msgid "DHCP snooping" msgstr "DHCP snooping" -#: models.py:810 +#: topologie/models.py:810 msgid "Protect against rogue DHCPv6" msgstr "Protège contre les DHCPv6 pirates" -#: models.py:811 templates/topologie/aff_vlanoptions.html:37 +#: topologie/models.py:811 +#: topologie/templates/topologie/aff_vlanoptions.html:37 msgid "DHCPv6 snooping" msgstr "DHCPv6 snooping" -#: models.py:815 +#: topologie/models.py:815 msgid "Check if IP adress is DHCP assigned" msgstr "Vérifie si l'adresse IP est attribuée par DHCP" -#: models.py:816 +#: topologie/models.py:816 msgid "ARP protection" msgstr "Protection ARP" -#: models.py:820 +#: topologie/models.py:820 msgid "Protect against rogue RA" msgstr "Protège contre les RA pirates" -#: models.py:821 +#: topologie/models.py:821 msgid "RA guard" msgstr "RA guard" -#: models.py:825 +#: topologie/models.py:825 msgid "Protect against loop" msgstr "Protège contre une boucle" -#: models.py:826 +#: topologie/models.py:826 msgid "Loop protection" msgstr "Protection contre une boucle" -#: models.py:831 +#: topologie/models.py:831 msgid "Can view a port profile object" msgstr "Peut voir un objet profil de port" -#: models.py:833 +#: topologie/models.py:833 msgid "port profile" msgstr "profil de port" -#: models.py:834 +#: topologie/models.py:834 msgid "port profiles" msgstr "profils de port" -#: templates/topologie/aff_ap.html:38 +#: topologie/templates/topologie/aff_ap.html:38 msgid "MAC address" msgstr "Adresse MAC" -#: templates/topologie/aff_ap.html:40 templates/topologie/aff_switch.html:39 +#: topologie/templates/topologie/aff_ap.html:40 +#: topologie/templates/topologie/aff_switch.html:39 msgid "IPv4 address" msgstr "Adresse IPv4" -#: templates/topologie/aff_ap.html:42 templates/topologie/aff_chambres.html:38 -#: templates/topologie/aff_port.html:46 templates/topologie/aff_stacks.html:36 -#: templates/topologie/aff_switch.html:49 -#: templates/topologie/edit_stack_sw.html:34 +#: topologie/templates/topologie/aff_ap.html:42 +#: topologie/templates/topologie/aff_chambres.html:38 +#: topologie/templates/topologie/aff_port.html:46 +#: topologie/templates/topologie/aff_stacks.html:36 +#: topologie/templates/topologie/aff_switch.html:49 +#: topologie/templates/topologie/edit_stack_sw.html:34 msgid "Details" msgstr "Détails" -#: templates/topologie/aff_ap.html:43 +#: topologie/templates/topologie/aff_ap.html:43 msgid "Location" msgstr "Emplacement" -#: templates/topologie/aff_building.html:36 -#: templates/topologie/aff_switch_bay.html:38 views.py:953 +#: topologie/templates/topologie/aff_building.html:36 +#: topologie/templates/topologie/aff_switch_bay.html:38 topologie/views.py:953 msgid "Building" msgstr "Bâtiment" -#: templates/topologie/aff_building.html:38 -#: templates/topologie/index_ap.html:33 templates/topologie/sidebar.html:47 +#: topologie/templates/topologie/aff_building.html:38 +#: topologie/templates/topologie/index_ap.html:33 +#: topologie/templates/topologie/sidebar.html:47 msgid "Access points" msgstr "Points d'accès sans fil" -#: templates/topologie/aff_constructor_switch.html:36 -#: templates/topologie/aff_model_switch.html:40 views.py:1013 +#: topologie/templates/topologie/aff_constructor_switch.html:36 +#: topologie/templates/topologie/aff_model_switch.html:40 +#: topologie/views.py:1013 msgid "Switch constructor" msgstr "Constructeur de commutateur réseau" -#: templates/topologie/aff_model_switch.html:36 -#: templates/topologie/aff_modules.html:36 -#: templates/topologie/aff_modules.html:81 +#: topologie/templates/topologie/aff_model_switch.html:36 +#: topologie/templates/topologie/aff_modules.html:36 +#: topologie/templates/topologie/aff_modules.html:81 msgid "Reference" msgstr "Référence" -#: templates/topologie/aff_model_switch.html:38 +#: topologie/templates/topologie/aff_model_switch.html:38 msgid "Commercial name" msgstr "Nom commercial" -#: templates/topologie/aff_model_switch.html:42 -#: templates/topologie/aff_modules.html:38 templates/topologie/index.html:66 -#: templates/topologie/sidebar.html:35 +#: topologie/templates/topologie/aff_model_switch.html:42 +#: topologie/templates/topologie/aff_modules.html:38 +#: topologie/templates/topologie/index.html:66 +#: topologie/templates/topologie/sidebar.html:35 msgid "Switches" msgstr "Commutateurs réseau" -#: templates/topologie/aff_modules.html:48 +#: topologie/templates/topologie/aff_modules.html:48 msgid "of" msgstr "de" -#: templates/topologie/aff_modules.html:76 +#: topologie/templates/topologie/aff_modules.html:76 msgid "All modular switchs" msgstr "Tous les commutateurs réseau modulaires" -#: templates/topologie/aff_modules.html:80 templates/topologie/aff_port.html:36 +#: topologie/templates/topologie/aff_modules.html:80 +#: topologie/templates/topologie/aff_port.html:36 msgid "Switch" msgstr "Commutateur réseau" -#: templates/topologie/aff_port.html:33 +#: topologie/templates/topologie/aff_port.html:33 msgid "Port" msgstr "Port" -#: templates/topologie/aff_port.html:40 +#: topologie/templates/topologie/aff_port.html:40 msgid "Interface" msgstr "Interface" -#: templates/topologie/aff_port.html:42 +#: topologie/templates/topologie/aff_port.html:42 msgid "Related port" msgstr "Port relié" -#: templates/topologie/aff_port.html:44 +#: topologie/templates/topologie/aff_port.html:44 msgid "Port state" msgstr "État du port" -#: templates/topologie/aff_port.html:45 views.py:1065 +#: topologie/templates/topologie/aff_port.html:45 topologie/views.py:1065 msgid "Port profile" msgstr "Profil de port" -#: templates/topologie/aff_port.html:85 +#: topologie/templates/topologie/aff_port.html:85 msgid "Active" msgstr "Actif" -#: templates/topologie/aff_port.html:87 +#: topologie/templates/topologie/aff_port.html:87 msgid "Disabled" msgstr "Désactivé" -#: templates/topologie/aff_port.html:92 +#: topologie/templates/topologie/aff_port.html:92 msgid "Default: " msgstr "Par défaut : " -#: templates/topologie/aff_port_profile.html:38 +#: topologie/templates/topologie/aff_port_profile.html:38 msgid "Default for" msgstr "Par défaut pour" -#: templates/topologie/aff_port_profile.html:39 +#: topologie/templates/topologie/aff_port_profile.html:39 msgid "VLANs" msgstr "VLANs" -#: templates/topologie/aff_port_profile.html:40 +#: topologie/templates/topologie/aff_port_profile.html:40 msgid "RADIUS settings" msgstr "Paramètres RADIUS" -#: templates/topologie/aff_port_profile.html:41 +#: topologie/templates/topologie/aff_port_profile.html:41 msgid "Speed limit" msgstr "Limite de vitesse" -#: templates/topologie/aff_port_profile.html:42 +#: topologie/templates/topologie/aff_port_profile.html:42 msgid "MAC address limit" msgstr "Limite d'adresse MAC" -#: templates/topologie/aff_port_profile.html:43 +#: topologie/templates/topologie/aff_port_profile.html:43 msgid "Security" msgstr "Sécurité" -#: templates/topologie/aff_port_profile.html:53 +#: topologie/templates/topologie/aff_port_profile.html:53 msgid "Untagged: " msgstr "Untagged :" -#: templates/topologie/aff_port_profile.html:57 +#: topologie/templates/topologie/aff_port_profile.html:57 msgid "Tagged: " msgstr "Tagged : " -#: templates/topologie/aff_port_profile.html:61 +#: topologie/templates/topologie/aff_port_profile.html:61 msgid "RADIUS type: " msgstr "Type de RADIUS : " -#: templates/topologie/aff_port_profile.html:64 +#: topologie/templates/topologie/aff_port_profile.html:64 msgid "RADIUS mode: " msgstr "Mode de RADIUS : " -#: templates/topologie/aff_repr_switch.html:67 -#: templates/topologie/aff_repr_switch.html:110 +#: topologie/templates/topologie/aff_repr_switch.html:67 +#: topologie/templates/topologie/aff_repr_switch.html:110 msgid "Empty" msgstr "Vide" -#: templates/topologie/aff_stacks.html:32 -#: templates/topologie/aff_switch.html:45 -#: templates/topologie/edit_stack_sw.html:32 -#: templates/topologie/index_p.html:39 +#: topologie/templates/topologie/aff_stacks.html:32 +#: topologie/templates/topologie/aff_switch.html:45 +#: topologie/templates/topologie/edit_stack_sw.html:32 +#: topologie/templates/topologie/index_p.html:39 msgid "Stack" msgstr "Pile" -#: templates/topologie/aff_stacks.html:34 -#: templates/topologie/aff_vlanoptions.html:33 +#: topologie/templates/topologie/aff_stacks.html:34 +#: topologie/templates/topologie/aff_vlanoptions.html:33 msgid "ID" msgstr "ID" -#: templates/topologie/aff_stacks.html:37 +#: topologie/templates/topologie/aff_stacks.html:37 msgid "Members" msgstr "Membres" -#: templates/topologie/aff_switch.html:37 templates/topologie/topo_more.html:56 +#: topologie/templates/topologie/aff_switch.html:37 +#: topologie/templates/topologie/topo_more.html:56 msgid "DNS name" msgstr "Nom DNS" -#: templates/topologie/aff_switch.html:41 -#: templates/topologie/aff_switch_bay.html:36 -#: templates/topologie/index_p.html:37 views.py:898 +#: topologie/templates/topologie/aff_switch.html:41 +#: topologie/templates/topologie/aff_switch_bay.html:36 +#: topologie/templates/topologie/index_p.html:37 topologie/views.py:898 msgid "Switch bay" msgstr "Baie de brassage" -#: templates/topologie/aff_switch.html:43 +#: topologie/templates/topologie/aff_switch.html:43 msgid "Ports" msgstr "Ports" -#: templates/topologie/aff_switch.html:47 -#: templates/topologie/edit_stack_sw.html:33 +#: topologie/templates/topologie/aff_switch.html:47 +#: topologie/templates/topologie/edit_stack_sw.html:33 msgid "Stack ID" msgstr "ID de la pile" -#: templates/topologie/aff_switch.html:76 +#: topologie/templates/topologie/aff_switch.html:76 msgid "Creation of ports" msgstr "Création de ports" -#: templates/topologie/aff_switch_bay.html:40 +#: topologie/templates/topologie/aff_switch_bay.html:40 msgid "Information" msgstr "Informations" -#: templates/topologie/aff_switch_bay.html:41 +#: topologie/templates/topologie/aff_switch_bay.html:41 msgid "Switches of the bay" msgstr "Commutateurs réseau de la baie" -#: templates/topologie/aff_vlanoptions.html:35 +#: topologie/templates/topologie/aff_vlanoptions.html:35 msgid "ARP protect" msgstr "Protection ARP" -#: templates/topologie/aff_vlanoptions.html:38 +#: topologie/templates/topologie/aff_vlanoptions.html:38 msgid "IGMP" msgstr "IGMP" -#: templates/topologie/aff_vlanoptions.html:39 +#: topologie/templates/topologie/aff_vlanoptions.html:39 msgid "MLD" msgstr "MLD" -#: templates/topologie/delete.html:29 templates/topologie/index.html:30 -#: templates/topologie/index_ap.html:30 -#: templates/topologie/index_model_switch.html:30 -#: templates/topologie/index_module.html:30 templates/topologie/index_p.html:30 -#: templates/topologie/index_physical_grouping.html:30 -#: templates/topologie/index_portprofile.html:29 -#: templates/topologie/index_room.html:30 templates/topologie/switch.html:30 -#: templates/topologie/topo.html:30 templates/topologie/topo_more.html:30 +#: topologie/templates/topologie/delete.html:29 +#: topologie/templates/topologie/index.html:30 +#: topologie/templates/topologie/index_ap.html:30 +#: topologie/templates/topologie/index_model_switch.html:30 +#: topologie/templates/topologie/index_module.html:30 +#: topologie/templates/topologie/index_p.html:30 +#: topologie/templates/topologie/index_physical_grouping.html:30 +#: topologie/templates/topologie/index_portprofile.html:29 +#: topologie/templates/topologie/index_room.html:30 +#: topologie/templates/topologie/switch.html:30 +#: topologie/templates/topologie/topo.html:30 +#: topologie/templates/topologie/topo_more.html:30 msgid "Topology" msgstr "Topologie" -#: templates/topologie/delete.html:35 +#: topologie/templates/topologie/delete.html:35 #, python-format msgid "" "Warning: are you sure you want to delete this %(objet_name)s object " @@ -642,188 +658,193 @@ msgstr "" "Attention : voulez-vous vraiment supprimer cet objet %(objet_name)s " "( %(objet)s ) ?" -#: templates/topologie/delete.html:36 +#: topologie/templates/topologie/delete.html:36 msgid "Confirm" msgstr "Confirmer" -#: templates/topologie/index.html:55 +#: topologie/templates/topologie/index.html:55 msgid "Topology of the switches" msgstr "Topologie des commutateurs réseau" -#: templates/topologie/index.html:68 +#: topologie/templates/topologie/index.html:68 msgid " Add a switch" msgstr " Ajouter un commutateur réseau" -#: templates/topologie/index_ap.html:35 +#: topologie/templates/topologie/index_ap.html:35 msgid " Add an access point" msgstr " Ajouter un point d'accès sans fil" -#: templates/topologie/index_model_switch.html:33 +#: topologie/templates/topologie/index_model_switch.html:33 msgid "Switch models" msgstr "Modèles de commutateur réseau" -#: templates/topologie/index_model_switch.html:36 +#: topologie/templates/topologie/index_model_switch.html:36 msgid " Add a switch model" msgstr " Ajouter un modèle de commutateur réseau" -#: templates/topologie/index_model_switch.html:42 +#: topologie/templates/topologie/index_model_switch.html:42 msgid "Switch constructors" msgstr "Constructeurs de commutateur réseau" -#: templates/topologie/index_model_switch.html:45 +#: topologie/templates/topologie/index_model_switch.html:45 msgid " Add a switch constructor" msgstr " Ajouter un constructeur de commutateur réseau" -#: templates/topologie/index_module.html:33 templates/topologie/sidebar.html:39 +#: topologie/templates/topologie/index_module.html:33 +#: topologie/templates/topologie/sidebar.html:39 msgid "Switch modules" msgstr "Modules de commutateur réseau" -#: templates/topologie/index_module.html:35 +#: topologie/templates/topologie/index_module.html:35 msgid " Add a module" msgstr " Ajouter un module" -#: templates/topologie/index_p.html:33 +#: topologie/templates/topologie/index_p.html:33 msgid "Switch:" msgstr "Commutateur réseau :" -#: templates/topologie/index_physical_grouping.html:33 +#: topologie/templates/topologie/index_physical_grouping.html:33 msgid "Stacks" msgstr "Piles" -#: templates/topologie/index_physical_grouping.html:36 +#: topologie/templates/topologie/index_physical_grouping.html:36 msgid " Add a stack" msgstr " Ajouter une pile" -#: templates/topologie/index_physical_grouping.html:41 +#: topologie/templates/topologie/index_physical_grouping.html:41 msgid "Switch bays" msgstr "Baies de brassage" -#: templates/topologie/index_physical_grouping.html:44 +#: topologie/templates/topologie/index_physical_grouping.html:44 msgid " Add a switch bay" msgstr " Ajouter une baie de brassage" -#: templates/topologie/index_physical_grouping.html:50 +#: topologie/templates/topologie/index_physical_grouping.html:50 msgid "Buildings" msgstr "Bâtiments" -#: templates/topologie/index_physical_grouping.html:53 +#: topologie/templates/topologie/index_physical_grouping.html:53 msgid " Add a building" msgstr " Ajouter un bâtiment" -#: templates/topologie/index_portprofile.html:34 -#: templates/topologie/sidebar.html:43 +#: topologie/templates/topologie/index_portprofile.html:34 +#: topologie/templates/topologie/sidebar.html:43 msgid "Port profiles" msgstr "Profils de port" -#: templates/topologie/index_portprofile.html:36 +#: topologie/templates/topologie/index_portprofile.html:36 msgid " Add a port profile" msgstr " Ajouter un profil de port" -#: templates/topologie/index_portprofile.html:42 +#: topologie/templates/topologie/index_portprofile.html:42 msgid "VLAN security" msgstr "Sécurité de VLAN" -#: templates/topologie/index_room.html:33 +#: topologie/templates/topologie/index_room.html:33 msgid "Rooms" msgstr "Chambres" -#: templates/topologie/index_room.html:35 +#: topologie/templates/topologie/index_room.html:35 msgid " Add a room" msgstr " Ajouter une chambre" -#: templates/topologie/sidebar.html:31 +#: topologie/templates/topologie/sidebar.html:31 msgid "Rooms and premises" msgstr "Chambres et locaux" -#: templates/topologie/sidebar.html:51 +#: topologie/templates/topologie/sidebar.html:51 msgid "Physical grouping" msgstr "Groupements physiques" -#: templates/topologie/sidebar.html:55 +#: topologie/templates/topologie/sidebar.html:55 msgid "Switch models and constructors" msgstr "Modèles et constructeurs de commutateur réseau" -#: templates/topologie/switch.html:39 templates/topologie/topo.html:36 +#: topologie/templates/topologie/switch.html:39 +#: topologie/templates/topologie/topo.html:36 msgid " Go to the ports list" msgstr " Aller à la liste des ports" -#: templates/topologie/switch.html:43 +#: topologie/templates/topologie/switch.html:43 msgid "Specific settings for the switch" msgstr "Réglages spécifiques pour le commutateur réseau" -#: templates/topologie/switch.html:46 views.py:441 views.py:745 views.py:800 -#: views.py:859 views.py:914 views.py:969 views.py:1027 views.py:1081 +#: topologie/templates/topologie/switch.html:46 topologie/views.py:441 +#: topologie/views.py:745 topologie/views.py:800 topologie/views.py:859 +#: topologie/views.py:914 topologie/views.py:969 topologie/views.py:1027 +#: topologie/views.py:1081 msgid "Create" msgstr "Créer" -#: templates/topologie/topo_more.html:48 +#: topologie/templates/topologie/topo_more.html:48 #, python-format msgid "Specific settings for the %(device)s object" msgstr "Réglages spécifiques pour l'objet %(device)s" -#: templates/topologie/topo_more.html:52 +#: topologie/templates/topologie/topo_more.html:52 #, python-format msgid "General settings for the machine linked to the %(device)s object" msgstr "Réglages généraux pour la machine liée à l'objet %(device)s" -#: templates/topologie/topo_more.html:59 +#: topologie/templates/topologie/topo_more.html:59 msgid "Create or edit" msgstr "Créer ou modifier" -#: views.py:347 +#: topologie/views.py:347 msgid "The VLAN was edited." msgstr "Le VLAN a été modifié." -#: views.py:350 views.py:403 views.py:457 views.py:762 views.py:821 -#: views.py:876 views.py:931 views.py:990 views.py:1045 views.py:1098 -#: views.py:1152 +#: topologie/views.py:350 topologie/views.py:403 topologie/views.py:457 +#: topologie/views.py:762 topologie/views.py:821 topologie/views.py:876 +#: topologie/views.py:931 topologie/views.py:990 topologie/views.py:1045 +#: topologie/views.py:1098 topologie/views.py:1152 msgid "Edit" msgstr "Modifier" -#: views.py:363 views.py:554 +#: topologie/views.py:363 topologie/views.py:554 msgid "Nonexistent switch." msgstr "Commutateur réseau inexistant." -#: views.py:371 +#: topologie/views.py:371 msgid "The port was added." msgstr "Le port a été ajouté." -#: views.py:373 +#: topologie/views.py:373 msgid "The port already exists." msgstr "Le port existe déjà." -#: views.py:379 views.py:1135 +#: topologie/views.py:379 topologie/views.py:1135 msgid "Add" msgstr "Ajouter" -#: views.py:394 +#: topologie/views.py:394 msgid "The port was edited." msgstr "Le port a été modifié." -#: views.py:417 +#: topologie/views.py:417 msgid "The port was deleted." msgstr "Le port a été supprimé." -#: views.py:421 +#: topologie/views.py:421 #, python-format msgid "The port %s is used by another object, impossible to delete it." msgstr "Le port %s est utilisé par un autre objet, impossible de le supprimer." -#: views.py:438 +#: topologie/views.py:438 msgid "The stack was created." msgstr "La pile a été créée." -#: views.py:470 +#: topologie/views.py:470 msgid "The stack was deleted." msgstr "La pile a été supprimée." -#: views.py:474 +#: topologie/views.py:474 #, python-format msgid "The stack %s is used by another object, impossible to deleted it." msgstr "" "La pile %s est utilisée par un autre objet, impossible de la supprimer." -#: views.py:516 views.py:651 views.py:706 +#: topologie/views.py:516 topologie/views.py:651 topologie/views.py:706 msgid "" "The organisation's user doesn't exist yet, please create or link it in the " "preferences." @@ -831,113 +852,113 @@ msgstr "" "L'utilisateur de l'association n'existe pas encore, veuillez le créer ou le " "relier dans les préférences." -#: views.py:531 +#: topologie/views.py:531 msgid "The switch was created." msgstr "Le commutateur réseau a été créé." -#: views.py:568 +#: topologie/views.py:568 msgid "The ports were created." msgstr "Les ports ont été créés." -#: views.py:612 +#: topologie/views.py:612 msgid "The switch was edited." msgstr "Le commutateur réseau a été modifié." -#: views.py:666 +#: topologie/views.py:666 msgid "The access point was created." msgstr "Le point d'accès sans fil a été créé." -#: views.py:719 +#: topologie/views.py:719 msgid "The access point was edited." msgstr "Le point d'accès sans fil a été modifié." -#: views.py:742 +#: topologie/views.py:742 msgid "The room was created." msgstr "La chambre a été créée." -#: views.py:759 +#: topologie/views.py:759 msgid "The room was edited." msgstr "La chambre a été modifiée." -#: views.py:775 +#: topologie/views.py:775 msgid "The room was deleted." msgstr "La chambre a été supprimée." -#: views.py:779 +#: topologie/views.py:779 #, python-format msgid "The room %s is used by another object, impossible to deleted it." msgstr "" "La chambre %s est utilisée par un autre objet, impossible de la supprimer." -#: views.py:797 +#: topologie/views.py:797 msgid "The switch model was created." msgstr "Le modèle de commutateur réseau a été créé." -#: views.py:818 +#: topologie/views.py:818 msgid "The switch model was edited." msgstr "Le modèle de commutateur réseau a été modifié." -#: views.py:834 +#: topologie/views.py:834 msgid "The switch model was deleted." msgstr "Le modèle de commutateur réseau a été supprimé." -#: views.py:838 +#: topologie/views.py:838 #, python-format msgid "The switch model %s is used by another object, impossible to delete it." msgstr "" "Le modèle de commutateur réseau %s est utilisé par un autre objet, " "impossible de le supprimer." -#: views.py:856 +#: topologie/views.py:856 msgid "The switch bay was created." msgstr "La baie de brassage a été créée." -#: views.py:873 +#: topologie/views.py:873 msgid "The switch bay was edited." msgstr "La baie de brassage a été modifiée." -#: views.py:889 +#: topologie/views.py:889 msgid "The switch bay was deleted." msgstr "La baie de brassage a été supprimée." -#: views.py:893 +#: topologie/views.py:893 #, python-format msgid "The switch bay %s is used by another object, impossible to delete it." msgstr "" "La baie de brassage %s est utilisée par un autre objet, impossible de la " "supprimer." -#: views.py:911 +#: topologie/views.py:911 msgid "The building was created." msgstr "Le bâtiment a été créé." -#: views.py:928 +#: topologie/views.py:928 msgid "The building was edited." msgstr "Le bâtiment a été modifié." -#: views.py:944 +#: topologie/views.py:944 msgid "The building was deleted." msgstr "Le bâtiment a été supprimé." -#: views.py:948 +#: topologie/views.py:948 #, python-format msgid "The building %s is used by another object, impossible to delete it." msgstr "" "Le bâtiment %s est utilisé par un autre objet, impossible de le supprimer." -#: views.py:966 +#: topologie/views.py:966 msgid "The switch constructor was created." msgstr "Le constructeur de commutateur réseau a été créé." -#: views.py:987 +#: topologie/views.py:987 msgid "The switch constructor was edited." msgstr "Le constructeur de commutateur réseau a été modifié." -#: views.py:1003 +#: topologie/views.py:1003 msgid "The switch constructor was deleted." msgstr "Le constructeur de commutateur réseau a été supprimé." -#: views.py:1007 +#: topologie/views.py:1007 #, python-format msgid "" "The switch constructor %s is used by another object, impossible to delete it." @@ -945,49 +966,49 @@ msgstr "" "Le constructeur de commutateur réseau %s est utilisé par un autre objet, " "impossible de le supprimer." -#: views.py:1024 +#: topologie/views.py:1024 msgid "The port profile was created." msgstr "Le profil de port a été créé." -#: views.py:1042 +#: topologie/views.py:1042 msgid "The port profile was edited." msgstr "Le profil de port a été modifié." -#: views.py:1059 +#: topologie/views.py:1059 msgid "The port profile was deleted." msgstr "Le profil de port a été supprimé." -#: views.py:1062 +#: topologie/views.py:1062 msgid "Impossible to delete the port profile." msgstr "Impossible de supprimer le profil de port." -#: views.py:1078 +#: topologie/views.py:1078 msgid "The module was created." msgstr "Le module a été créé." -#: views.py:1095 views.py:1149 +#: topologie/views.py:1095 topologie/views.py:1149 msgid "The module was edited." msgstr "Le module a été modifié." -#: views.py:1111 views.py:1165 +#: topologie/views.py:1111 topologie/views.py:1165 msgid "The module was deleted." msgstr "Le module a été supprimé." -#: views.py:1115 views.py:1169 +#: topologie/views.py:1115 topologie/views.py:1169 #, python-format msgid "The module %s is used by another object, impossible to deleted it." msgstr "" "Le module %s est utilisé par un autre objet, impossible de le supprimer." -#: views.py:1120 views.py:1174 +#: topologie/views.py:1120 topologie/views.py:1174 msgid "Module" msgstr "Module" -#: views.py:1132 +#: topologie/views.py:1132 msgid "The module was added." msgstr "Le module a été ajouté." -#: views.py:1291 +#: topologie/views.py:1291 msgid "" "The default Django template isn't used. This can lead to rendering errors. " "Check the parameters." diff --git a/users/locale/fr/LC_MESSAGES/django.po b/users/locale/fr/LC_MESSAGES/django.po index 965a1a8a..edc80bf8 100644 --- a/users/locale/fr/LC_MESSAGES/django.po +++ b/users/locale/fr/LC_MESSAGES/django.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: 2.5\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-01-09 00:27+0100\n" +"POT-Creation-Date: 2019-02-12 08:58+0100\n" "PO-Revision-Date: 2018-06-27 23:35+0200\n" "Last-Translator: Laouen Fernet \n" "Language-Team: \n" @@ -31,121 +31,128 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: acl.py:41 +#: users/acl.py:41 msgid "You don't have the right to view this application." msgstr "Vous n'avez pas le droit de voir cette application." -#: forms.py:76 +#: users/forms.py:76 msgid "Current password" msgstr "Mot de passe actuel" -#: forms.py:81 forms.py:507 forms.py:534 +#: users/forms.py:81 users/forms.py:507 users/forms.py:534 msgid "New password" msgstr "Nouveau mot de passe" -#: forms.py:87 +#: users/forms.py:87 msgid "New password confirmation" msgstr "Confirmation du nouveau mot de passe" -#: forms.py:104 +#: users/forms.py:104 msgid "The new passwords don't match." msgstr "Les nouveaux mots de passe ne correspondent pas." -#: forms.py:113 +#: users/forms.py:113 msgid "The current password is incorrect." msgstr "Le mot de passe actuel est incorrect." -#: forms.py:132 forms.py:185 models.py:1597 +#: users/forms.py:132 users/forms.py:185 users/models.py:1597 msgid "Password" msgstr "Mot de passe" -#: forms.py:138 forms.py:191 +#: users/forms.py:138 users/forms.py:191 msgid "Password confirmation" msgstr "Confirmation du mot de passe" -#: forms.py:143 forms.py:234 +#: users/forms.py:143 users/forms.py:234 msgid "Is admin" msgstr "Est admin" -#: forms.py:153 +#: users/forms.py:153 msgid "You can't use an internal address as your external address." msgstr "" "Vous ne pouvez pas utiliser une adresse interne pour votre adresse externe." -#: forms.py:166 forms.py:215 +#: users/forms.py:166 users/forms.py:215 msgid "The passwords don't match." msgstr "Les mots de passe ne correspondent pas." -#: forms.py:243 +#: users/forms.py:243 #, python-format msgid "User is admin: %s" msgstr "L'utilisateur est admin : %s" -#: forms.py:291 templates/users/aff_clubs.html:38 -#: templates/users/aff_listright.html:63 templates/users/aff_listright.html:168 -#: templates/users/aff_users.html:39 templates/users/profil.html:177 -#: templates/users/profil.html:331 templates/users/profil.html:350 +#: users/forms.py:291 users/templates/users/aff_clubs.html:38 +#: users/templates/users/aff_listright.html:63 +#: users/templates/users/aff_listright.html:168 +#: users/templates/users/aff_users.html:39 +#: users/templates/users/profil.html:177 users/templates/users/profil.html:332 +#: users/templates/users/profil.html:351 msgid "Username" msgstr "Pseudo" -#: forms.py:306 +#: users/forms.py:306 msgid "Impossible to archive users whose end access date is in the future." msgstr "" "Impossible d'archiver des utilisateurs dont la date de fin de connexion est " "dans le futur." -#: forms.py:318 templates/users/profil.html:166 templates/users/profil.html:330 -#: templates/users/profil.html:349 +#: users/forms.py:318 users/templates/users/profil.html:166 +#: users/templates/users/profil.html:331 users/templates/users/profil.html:350 msgid "First name" msgstr "Prénom" -#: forms.py:319 templates/users/aff_users.html:37 -#: templates/users/profil.html:172 templates/users/profil.html:329 -#: templates/users/profil.html:348 +#: users/forms.py:319 users/templates/users/aff_users.html:37 +#: users/templates/users/profil.html:172 users/templates/users/profil.html:330 +#: users/templates/users/profil.html:349 msgid "Surname" msgstr "Nom" -#: forms.py:320 forms.py:442 models.py:1598 -#: templates/users/aff_emailaddress.html:36 templates/users/profil.html:182 +#: users/forms.py:320 users/forms.py:442 users/models.py:1598 +#: users/templates/users/aff_emailaddress.html:36 +#: users/templates/users/profil.html:182 msgid "Email address" msgstr "Adresse mail" -#: forms.py:321 forms.py:440 forms.py:590 templates/users/aff_schools.html:37 -#: templates/users/profil.html:200 +#: users/forms.py:321 users/forms.py:440 users/forms.py:590 +#: users/templates/users/aff_schools.html:37 +#: users/templates/users/profil.html:200 msgid "School" msgstr "Établissement" -#: forms.py:322 forms.py:441 models.py:1251 -#: templates/users/aff_serviceusers.html:34 templates/users/profil.html:205 +#: users/forms.py:322 users/forms.py:441 users/models.py:1251 +#: users/templates/users/aff_serviceusers.html:34 +#: users/templates/users/profil.html:205 msgid "Comment" msgstr "Commentaire" -#: forms.py:324 forms.py:444 templates/users/aff_clubs.html:40 -#: templates/users/aff_users.html:41 templates/users/profil.html:187 +#: users/forms.py:324 users/forms.py:444 +#: users/templates/users/aff_clubs.html:40 +#: users/templates/users/aff_users.html:41 +#: users/templates/users/profil.html:187 msgid "Room" msgstr "Chambre" -#: forms.py:325 forms.py:445 +#: users/forms.py:325 users/forms.py:445 msgid "No room" msgstr "Pas de chambre" -#: forms.py:326 forms.py:446 +#: users/forms.py:326 users/forms.py:446 msgid "Select a school" msgstr "Sélectionnez un établissement" -#: forms.py:342 +#: users/forms.py:342 msgid "Force the move?" msgstr "Forcer le déménagement ?" -#: forms.py:352 forms.py:730 +#: users/forms.py:352 users/forms.py:730 msgid "You can't use a {} address." msgstr "Vous ne pouvez pas utiliser une adresse {}." -#: forms.py:361 forms.py:470 +#: users/forms.py:361 users/forms.py:470 msgid "A valid telephone number is required." msgstr "Un numéro de téléphone valide est requis." -#: forms.py:379 +#: users/forms.py:379 msgid "" "If you already have an account, please use it. If your lost access to it, " "please consider using the forgotten password button on the login page or " @@ -156,218 +163,219 @@ msgstr "" "passe oublié est à votre disposition. Si vous avez oublié votre login, " "contactez le support." -#: forms.py:384 +#: users/forms.py:384 msgid "I certify that I have not had an account before" msgstr "Je certifie sur l'honneur ne pas déjà avoir de compte" -#: forms.py:413 +#: users/forms.py:413 msgid "Leave empty if you don't have any GPG key." msgstr "Laissez vide si vous n'avez pas de clé GPG." -#: forms.py:415 +#: users/forms.py:415 msgid "Default shell" msgstr "Interface en ligne de commande par défaut" -#: forms.py:439 templates/users/aff_clubs.html:36 -#: templates/users/aff_serviceusers.html:32 +#: users/forms.py:439 users/templates/users/aff_clubs.html:36 +#: users/templates/users/aff_serviceusers.html:32 msgid "Name" msgstr "Nom" -#: forms.py:447 +#: users/forms.py:447 msgid "Use a mailing list" msgstr "Utiliser une liste de diffusion" -#: forms.py:578 templates/users/aff_listright.html:38 +#: users/forms.py:578 users/templates/users/aff_listright.html:38 msgid "Superuser" msgstr "Superutilisateur" -#: forms.py:602 +#: users/forms.py:602 msgid "Shell name" msgstr "Nom de l'interface en ligne de commande" -#: forms.py:621 +#: users/forms.py:621 msgid "Name of the group of rights" msgstr "Nom du groupe de droits" -#: forms.py:632 +#: users/forms.py:632 msgid "GID. Warning: this field must not be edited after creation." msgstr "GID. Attention : ce champ ne doit pas être modifié après création." -#: forms.py:640 +#: users/forms.py:640 msgid "Current groups of rights" msgstr "Groupes de droits actuels" -#: forms.py:657 +#: users/forms.py:657 msgid "Current schools" msgstr "Établissements actuels" -#: forms.py:675 forms.py:689 templates/users/aff_bans.html:41 -#: templates/users/aff_whitelists.html:41 +#: users/forms.py:675 users/forms.py:689 users/templates/users/aff_bans.html:41 +#: users/templates/users/aff_whitelists.html:41 msgid "End date" msgstr "Date de fin" -#: forms.py:703 models.py:1795 +#: users/forms.py:703 users/models.py:1795 msgid "Local part of the email address" msgstr "Partie locale de l'adresse mail" -#: forms.py:704 +#: users/forms.py:704 msgid "Can't contain @" msgstr "Ne peut pas contenir @" -#: forms.py:719 +#: users/forms.py:719 msgid "Main email address" msgstr "Adresse mail principale" -#: forms.py:721 +#: users/forms.py:721 msgid "Redirect local emails" msgstr "Rediriger les mails locaux" -#: forms.py:723 +#: users/forms.py:723 msgid "Use local emails" msgstr "Utiliser les mails locaux" -#: forms.py:763 +#: users/forms.py:763 msgid "This room is my room" msgstr "Il s'agit bien de ma chambre" -#: forms.py:767 +#: users/forms.py:767 msgid "This new connected device is mine" msgstr "Ce nouvel appareil connecté m'appartient" -#: models.py:106 +#: users/models.py:106 #, python-format msgid "The username '%(label)s' contains forbidden characters." msgstr "Le pseudo '%(label)s' contient des caractères interdits." -#: models.py:148 +#: users/models.py:148 msgid "Users must have an username." msgstr "Les utilisateurs doivent avoir un pseudo." -#: models.py:151 +#: users/models.py:151 msgid "Username should only contain [a-z0-9-]." msgstr "Le pseudo devrait seulement contenir [a-z0-9-]" -#: models.py:192 templates/users/aff_clubs.html:55 -#: templates/users/aff_users.html:57 templates/users/profil.html:249 +#: users/models.py:192 users/templates/users/aff_clubs.html:55 +#: users/templates/users/aff_users.html:57 +#: users/templates/users/profil.html:249 msgid "Active" msgstr "Actif" -#: models.py:193 templates/users/aff_clubs.html:57 -#: templates/users/aff_users.html:59 templates/users/profil.html:251 -#: templates/users/profil.html:265 +#: users/models.py:193 users/templates/users/aff_clubs.html:57 +#: users/templates/users/aff_users.html:59 +#: users/templates/users/profil.html:251 users/templates/users/profil.html:265 msgid "Disabled" msgstr "Désactivé" -#: models.py:194 templates/users/profil.html:253 +#: users/models.py:194 users/templates/users/profil.html:253 msgid "Archived" msgstr "Archivé" -#: models.py:195 +#: users/models.py:195 msgid "Not yet active" msgstr "Pas encore adhéré" -#: models.py:202 models.py:1242 +#: users/models.py:202 users/models.py:1242 msgid "Must only contain letters, numerals or dashes." msgstr "Doit seulement contenir des lettres, chiffres ou tirets." -#: models.py:208 +#: users/models.py:208 msgid "External email address allowing us to contact you." msgstr "Adresse mail externe nous permettant de vous contacter." -#: models.py:212 +#: users/models.py:212 msgid "" "Enable redirection of the local email messages to the main email address." msgstr "" "Activer la redirection des mails locaux vers l'adresse mail principale." -#: models.py:217 +#: users/models.py:217 msgid "Enable the local email account." msgstr "Activer le compte mail local" -#: models.py:232 +#: users/models.py:232 msgid "Comment, school year" msgstr "Commentaire, promotion" -#: models.py:258 +#: users/models.py:258 msgid "Can change the password of a user" msgstr "Peut changer le mot de passe d'un utilisateur" -#: models.py:259 +#: users/models.py:259 msgid "Can edit the state of a user" msgstr "Peut changer l'état d'un utilisateur" -#: models.py:260 +#: users/models.py:260 msgid "Can force the move" msgstr "Peut forcer le déménagement" -#: models.py:261 +#: users/models.py:261 msgid "Can edit the shell of a user" msgstr "Peut modifier l'interface en ligne de commande d'un utilisateur" -#: models.py:263 +#: users/models.py:263 msgid "Can edit the groups of rights of a user (critical permission)" msgstr "" "Peut modifier les groupes de droits d'un utilisateur (permission critique)" -#: models.py:266 +#: users/models.py:266 msgid "Can edit all users, including those with rights." msgstr "" "Peut modifier tous les utilisateurs, y compris ceux possédant des droits." -#: models.py:268 +#: users/models.py:268 msgid "Can view a user object" msgstr "Peut voir un objet utilisateur" -#: models.py:270 +#: users/models.py:270 msgid "user (member or club)" msgstr "utilisateur (adhérent ou club)" -#: models.py:271 +#: users/models.py:271 msgid "users (members or clubs)" msgstr "utilisateurs (adhérents ou clubs)" -#: models.py:289 models.py:313 +#: users/models.py:289 users/models.py:313 msgid "Unknown type." msgstr "Type inconnu." -#: models.py:309 templates/users/aff_listright.html:75 -#: templates/users/aff_listright.html:180 +#: users/models.py:309 users/templates/users/aff_listright.html:75 +#: users/templates/users/aff_listright.html:180 msgid "Member" msgstr "Adhérent" -#: models.py:311 +#: users/models.py:311 msgid "Club" msgstr "Club" -#: models.py:536 +#: users/models.py:536 msgid "IPv4 assigning" msgstr "Attribution de l'IPv4" -#: models.py:545 +#: users/models.py:545 msgid "IPv4 unassigning" msgstr "Désattribution de l'IPv4" -#: models.py:701 +#: users/models.py:701 msgid "Maximum number of registered machines reached." msgstr "Nombre maximum de machines enregistrées atteint." -#: models.py:703 +#: users/models.py:703 msgid "Re2o doesn't know wich machine type to assign." msgstr "Re2o ne sait pas quel type de machine attribuer." -#: models.py:726 templates/users/user_autocapture.html:64 +#: users/models.py:726 users/templates/users/user_autocapture.html:64 msgid "OK" msgstr "OK" -#: models.py:799 models.py:836 +#: users/models.py:799 users/models.py:836 msgid "You don't have the right to edit this club." msgstr "Vous n'avez pas le droit de modifier ce club." -#: models.py:807 +#: users/models.py:807 msgid "User with critical rights, can't be edited." msgstr "Utilisateur avec des droits critiques, ne peut être modifié." -#: models.py:810 +#: users/models.py:810 msgid "" "Impossible to edit the organisation's user without the 'change_all_users' " "right." @@ -375,60 +383,60 @@ msgstr "" "Impossible de modifier l'utilisateur de l'association sans le droit " "'change_all_users'." -#: models.py:818 models.py:847 +#: users/models.py:818 users/models.py:847 msgid "You don't have the right to edit another user." msgstr "Vous n'avez pas le droit de modifier un autre utilisateur." -#: models.py:865 +#: users/models.py:865 msgid "Permission required to change the room." msgstr "Permission requise pour changer la chambre." -#: models.py:879 +#: users/models.py:879 msgid "Permission required to change the state." msgstr "Permission requise pour changer l'état." -#: models.py:891 +#: users/models.py:891 msgid "Permission required to change the shell." msgstr "Permission requise pour changer l'interface en ligne de commande." -#: models.py:905 models.py:918 +#: users/models.py:905 users/models.py:918 msgid "Local email accounts must be enabled." msgstr "Les comptes mail locaux doivent être activés." -#: models.py:931 +#: users/models.py:931 msgid "Permission required to force the move." msgstr "Permission requise pour forcer le déménagement." -#: models.py:944 +#: users/models.py:944 msgid "Permission required to edit the user's groups of rights." msgstr "" "Permission requise pour modifier les groupes de droits de l'utilisateur." -#: models.py:956 +#: users/models.py:956 msgid "'superuser' right required to edit the superuser flag." msgstr "Droit 'superuser' requis pour modifier le signalement superuser." -#: models.py:974 +#: users/models.py:974 msgid "You don't have the right to view this club." msgstr "Vous n'avez pas le droit de voir ce club." -#: models.py:980 +#: users/models.py:980 msgid "You don't have the right to view another user." msgstr "Vous n'avez pas le droit de voir un autre utilisateur." -#: models.py:993 models.py:1174 +#: users/models.py:993 users/models.py:1174 msgid "You don't have the right to view the list of users." msgstr "Vous n'avez pas le droit de voir la liste des utilisateurs." -#: models.py:1006 +#: users/models.py:1006 msgid "You don't have the right to delete this user." msgstr "Vous n'avez pas le droit de supprimer cet utilisateur." -#: models.py:1027 +#: users/models.py:1027 msgid "This username is already used." msgstr "Ce pseudo est déjà utilisé." -#: models.py:1029 +#: users/models.py:1029 msgid "" "There is neither a local email address nor an external email address for " "this user." @@ -436,7 +444,7 @@ msgstr "" "Il n'y a pas d'adresse mail locale ni d'adresse mail externe pour cet " "utilisateur." -#: models.py:1033 +#: users/models.py:1033 msgid "" "You can't redirect your local emails if no external email address has been " "set." @@ -444,178 +452,179 @@ msgstr "" "Vous ne pouvez pas rediriger vos mails locaux si aucune adresse mail externe " "n'a été définie." -#: models.py:1059 +#: users/models.py:1059 msgid "member" msgstr "adhérent" -#: models.py:1060 +#: users/models.py:1060 msgid "members" msgstr "adhérents" -#: models.py:1071 +#: users/models.py:1071 msgid "A GPG fingerprint must contain 40 hexadecimal characters" msgstr "Une empreinte GPG doit contenir 40 caractères hexadécimaux" -#: models.py:1101 +#: users/models.py:1101 msgid "You don't have the right to create a user." msgstr "Vous n'avez pas le droit de créer un utilisateur." -#: models.py:1137 +#: users/models.py:1137 msgid "club" msgstr "club" -#: models.py:1138 +#: users/models.py:1138 msgid "clubs" msgstr "clubs" -#: models.py:1156 +#: users/models.py:1156 msgid "You don't have the right to create a club." msgstr "Vous n'avez pas le droit de créer un club." -#: models.py:1261 +#: users/models.py:1261 msgid "Can view a service user object" msgstr "Peut voir un objet utilisateur service" -#: models.py:1263 +#: users/models.py:1263 msgid "service user" msgstr "utilisateur service" -#: models.py:1264 +#: users/models.py:1264 msgid "service users" msgstr "utilisateurs service" -#: models.py:1268 +#: users/models.py:1268 #, python-brace-format msgid "Service user <{name}>" msgstr "Utilisateur service <{name}>" -#: models.py:1330 +#: users/models.py:1330 msgid "Can view a school object" msgstr "Peut voir un objet établissement" -#: models.py:1332 +#: users/models.py:1332 msgid "school" msgstr "établissement" -#: models.py:1333 +#: users/models.py:1333 msgid "schools" msgstr "établissements" -#: models.py:1351 +#: users/models.py:1351 msgid "UNIX groups can only contain lower case letters." msgstr "Les groupes UNIX peuvent seulement contenir des lettres minuscules." -#: models.py:1357 +#: users/models.py:1357 msgid "Description" msgstr "Description" -#: models.py:1364 +#: users/models.py:1364 msgid "Can view a group of rights object" msgstr "Peut voir un objet groupe de droits" -#: models.py:1366 +#: users/models.py:1366 msgid "group of rights" msgstr "groupe de droits" -#: models.py:1367 +#: users/models.py:1367 msgid "groups of rights" msgstr "groupes de droits" -#: models.py:1414 +#: users/models.py:1414 msgid "Can view a shell object" msgstr "Peut voir un objet interface en ligne de commande" -#: models.py:1416 +#: users/models.py:1416 msgid "shell" msgstr "interface en ligne de commande" -#: models.py:1417 +#: users/models.py:1417 msgid "shells" msgstr "interfaces en ligne de commande" -#: models.py:1436 +#: users/models.py:1436 msgid "HARD (no access)" msgstr "HARD (pas d'accès)" -#: models.py:1437 +#: users/models.py:1437 msgid "SOFT (local access only)" msgstr "SOFT (accès local uniquement)" -#: models.py:1438 +#: users/models.py:1438 msgid "RESTRICTED (speed limitation)" msgstr "RESTRICTED (limitation de vitesse)" -#: models.py:1449 +#: users/models.py:1449 msgid "Can view a ban object" msgstr "Peut voir un objet bannissement" -#: models.py:1451 +#: users/models.py:1451 msgid "ban" msgstr "bannissement" -#: models.py:1452 +#: users/models.py:1452 msgid "bans" msgstr "bannissements" -#: models.py:1486 +#: users/models.py:1486 msgid "You don't have the right to view bans other than yours." msgstr "" "Vous n'avez pas le droit de voir des bannissements autres que les vôtres." -#: models.py:1534 +#: users/models.py:1534 msgid "Can view a whitelist object" msgstr "Peut voir un objet accès gracieux" -#: models.py:1536 +#: users/models.py:1536 msgid "whitelist (free of charge access)" msgstr "Accès gracieux" -#: models.py:1537 +#: users/models.py:1537 msgid "whitelists (free of charge access)" msgstr "Accès gracieux" -#: models.py:1553 +#: users/models.py:1553 msgid "You don't have the right to view whitelists other than yours." msgstr "" "Vous n'avez pas le droit de voir des accès gracieux autres que les vôtres." -#: models.py:1790 +#: users/models.py:1790 msgid "User of the local email account" msgstr "Utilisateur du compte mail local" -#: models.py:1800 +#: users/models.py:1800 msgid "Can view a local email account object" msgstr "Peut voir un objet compte mail local" -#: models.py:1802 +#: users/models.py:1802 msgid "local email account" msgstr "compte mail local" -#: models.py:1803 +#: users/models.py:1803 msgid "local email accounts" msgstr "comptes mail locaux" -#: models.py:1827 models.py:1850 models.py:1872 models.py:1894 +#: users/models.py:1827 users/models.py:1850 users/models.py:1872 +#: users/models.py:1894 msgid "The local email accounts are not enabled." msgstr "Les comptes mail locaux ne sont pas activés." -#: models.py:1829 +#: users/models.py:1829 msgid "You don't have the right to add a local email account to another user." msgstr "" "Vous n'avez pas le droit d'ajouter un compte mail local à un autre " "utilisateur." -#: models.py:1832 +#: users/models.py:1832 msgid "You reached the limit of {} local email accounts." msgstr "Vous avez atteint la limite de {} comptes mail locaux." -#: models.py:1853 models.py:1897 +#: users/models.py:1853 users/models.py:1897 msgid "You don't have the right to edit another user's local email account." msgstr "" "Vous n'avez pas le droit de modifier le compte mail local d'un autre " "utilisateur." -#: models.py:1867 +#: users/models.py:1867 msgid "" "You can't delete a local email account whose local part is the same as the " "username." @@ -623,13 +632,13 @@ msgstr "" "Vous ne pouvez pas supprimer un compte mail local dont la partie locale est " "la même que le pseudo." -#: models.py:1875 +#: users/models.py:1875 msgid "You don't have the right to delete another user's local email account" msgstr "" "Vous n'avez pas le droit de supprimer le compte mail local d'un autre " "utilisateur." -#: models.py:1889 +#: users/models.py:1889 msgid "" "You can't edit a local email account whose local part is the same as the " "username." @@ -637,135 +646,154 @@ msgstr "" "Vous ne pouvez pas modifier un compte mail local dont la partie locale est " "la même que le pseudo." -#: models.py:1903 +#: users/models.py:1903 msgid "The local part must not contain @ or +." msgstr "La partie locale ne doit pas contenir @ ou +." -#: templates/users/aff_bans.html:36 templates/users/aff_whitelists.html:36 +#: users/templates/users/aff_bans.html:36 +#: users/templates/users/aff_whitelists.html:36 msgid "User" msgstr "Utilisateur" -#: templates/users/aff_bans.html:38 templates/users/aff_whitelists.html:38 +#: users/templates/users/aff_bans.html:38 +#: users/templates/users/aff_whitelists.html:38 msgid "Reason" msgstr "Raison" -#: templates/users/aff_bans.html:39 templates/users/aff_whitelists.html:39 +#: users/templates/users/aff_bans.html:39 +#: users/templates/users/aff_whitelists.html:39 msgid "Start date" msgstr "Date de début" -#: templates/users/aff_clubs.html:42 templates/users/aff_users.html:43 +#: users/templates/users/aff_clubs.html:42 +#: users/templates/users/aff_users.html:43 msgid "End of subscription on" msgstr "Fin de cotisation le" -#: templates/users/aff_clubs.html:43 templates/users/aff_users.html:44 -#: templates/users/profil.html:260 +#: users/templates/users/aff_clubs.html:43 +#: users/templates/users/aff_users.html:44 +#: users/templates/users/profil.html:260 msgid "Internet access" msgstr "Accès Internet" -#: templates/users/aff_clubs.html:44 templates/users/aff_users.html:45 -#: templates/users/profil.html:31 +#: users/templates/users/aff_clubs.html:44 +#: users/templates/users/aff_users.html:45 users/templates/users/profil.html:31 msgid "Profile" msgstr "Profil" -#: templates/users/aff_clubs.html:53 templates/users/aff_users.html:54 -#: templates/users/profil.html:224 +#: users/templates/users/aff_clubs.html:53 +#: users/templates/users/aff_users.html:54 +#: users/templates/users/profil.html:224 msgid "Not a member" msgstr "Non adhérent" -#: templates/users/aff_listright.html:40 +#: users/templates/users/aff_listright.html:40 msgid "Django's specific pre-defined right that supersed any other rights." msgstr "" "Droit prédéfini spécifique à Django qui outrepasse tous les autres droits." -#: templates/users/aff_listright.html:44 +#: users/templates/users/aff_listright.html:44 msgid "Total: all permissions" msgstr "Total: toutes les permissions" -#: templates/users/aff_listright.html:49 templates/users/aff_listright.html:56 +#: users/templates/users/aff_listright.html:49 +#: users/templates/users/aff_listright.html:56 msgid "Users in Superuser" msgstr "Utilisateurs dans Superuser" -#: templates/users/aff_listright.html:53 templates/users/aff_listright.html:154 -#: widgets.py:35 +#: users/templates/users/aff_listright.html:53 +#: users/templates/users/aff_listright.html:154 users/widgets.py:35 msgid "Close" msgstr "Fermer" -#: templates/users/aff_listright.html:64 templates/users/aff_listright.html:169 +#: users/templates/users/aff_listright.html:64 +#: users/templates/users/aff_listright.html:169 msgid "Membership" msgstr "Adhésion" -#: templates/users/aff_listright.html:65 templates/users/aff_listright.html:170 +#: users/templates/users/aff_listright.html:65 +#: users/templates/users/aff_listright.html:170 msgid "Last seen" msgstr "Dernière connexion" -#: templates/users/aff_listright.html:66 templates/users/aff_listright.html:171 +#: users/templates/users/aff_listright.html:66 +#: users/templates/users/aff_listright.html:171 msgid "Actions" msgstr "Actions" -#: templates/users/aff_listright.html:67 templates/users/aff_listright.html:172 +#: users/templates/users/aff_listright.html:67 +#: users/templates/users/aff_listright.html:172 msgid "Last action" msgstr "Dernière action" -#: templates/users/aff_listright.html:77 templates/users/aff_listright.html:182 +#: users/templates/users/aff_listright.html:77 +#: users/templates/users/aff_listright.html:182 msgid "No membership records" msgstr "Aucune adhésion enregistrée" -#: templates/users/aff_listright.html:80 templates/users/aff_listright.html:185 +#: users/templates/users/aff_listright.html:80 +#: users/templates/users/aff_listright.html:185 #, python-format msgid "Not since %(end_date)s" msgstr "Plus depuis %(end_date)s" -#: templates/users/aff_listright.html:88 templates/users/aff_listright.html:193 +#: users/templates/users/aff_listright.html:88 +#: users/templates/users/aff_listright.html:193 msgid "Never" msgstr "Jamais" -#: templates/users/aff_listright.html:123 +#: users/templates/users/aff_listright.html:123 #, python-format msgid "%(right_name)s (gid: %(right_gid)s)" msgstr "%(right_name)s (gid: %(right_gid)s)" -#: templates/users/aff_listright.html:132 +#: users/templates/users/aff_listright.html:132 #, python-format msgid "Total: %(perm_count)s permission" msgid_plural "Total: %(perm_count)s permissions" msgstr[0] "Total: %(perm_count)s permission" msgstr[1] "Total: %(perm_count)s permissions" -#: templates/users/aff_listright.html:150 templates/users/index.html:29 -#: templates/users/index.html:32 templates/users/index_ban.html:29 -#: templates/users/index_clubs.html:29 -#: templates/users/index_emailaddress.html:29 -#: templates/users/index_listright.html:30 templates/users/index_rights.html:29 -#: templates/users/index_schools.html:30 -#: templates/users/index_serviceusers.html:30 -#: templates/users/index_shell.html:30 templates/users/index_whitelist.html:29 -#: templates/users/plugin_out.html:31 templates/users/sidebar.html:52 -#: templates/users/user.html:30 templates/users/user_autocapture.html:30 +#: users/templates/users/aff_listright.html:150 +#: users/templates/users/index.html:29 users/templates/users/index.html:32 +#: users/templates/users/index_ban.html:29 +#: users/templates/users/index_clubs.html:29 +#: users/templates/users/index_emailaddress.html:29 +#: users/templates/users/index_listright.html:30 +#: users/templates/users/index_rights.html:29 +#: users/templates/users/index_schools.html:30 +#: users/templates/users/index_serviceusers.html:30 +#: users/templates/users/index_shell.html:30 +#: users/templates/users/index_whitelist.html:29 +#: users/templates/users/plugin_out.html:31 +#: users/templates/users/sidebar.html:52 users/templates/users/user.html:30 +#: users/templates/users/user_autocapture.html:30 msgid "Users" msgstr "Utilisateurs" -#: templates/users/aff_listright.html:158 +#: users/templates/users/aff_listright.html:158 #, python-format msgid "Users in %(right_name)s" msgstr "Utilisateurs dans %(right_name)s" -#: templates/users/aff_serviceusers.html:33 +#: users/templates/users/aff_serviceusers.html:33 msgid "Role" msgstr "Rôle" -#: templates/users/aff_shell.html:32 templates/users/profil.html:301 +#: users/templates/users/aff_shell.html:32 +#: users/templates/users/profil.html:301 msgid "Shell" msgstr "Interface en ligne de commande" -#: templates/users/aff_users.html:35 +#: users/templates/users/aff_users.html:35 msgid "Firt name" msgstr "Prénom" -#: templates/users/delete.html:29 +#: users/templates/users/delete.html:29 msgid "Deletion of users" msgstr "Suppression d'utilisateurs" -#: templates/users/delete.html:35 +#: users/templates/users/delete.html:35 #, python-format msgid "" "Warning: are you sure you want to delete this %(objet_name)s object " @@ -774,60 +802,61 @@ msgstr "" "Attention : voulez-vous vraiment supprimer cet objet %(objet_name)s " "( %(objet)s ) ?" -#: templates/users/delete.html:36 templates/users/mass_archive.html:36 +#: users/templates/users/delete.html:36 +#: users/templates/users/mass_archive.html:36 msgid "Confirm" msgstr "Confirmer" -#: templates/users/index_ban.html:32 templates/users/profil.html:427 -#: templates/users/sidebar.html:58 +#: users/templates/users/index_ban.html:32 +#: users/templates/users/profil.html:428 users/templates/users/sidebar.html:58 msgid "Bans" msgstr "Bannissements" -#: templates/users/index_clubs.html:32 +#: users/templates/users/index_clubs.html:32 msgid "Clubs" msgstr "Clubs" -#: templates/users/index_emailaddress.html:32 +#: users/templates/users/index_emailaddress.html:32 msgid "Local email accounts" msgstr "Comptes mail locaux" -#: templates/users/index_listright.html:33 +#: users/templates/users/index_listright.html:33 msgid "List of groups of rights" msgstr "Liste des groupes de droits" -#: templates/users/index_listright.html:35 +#: users/templates/users/index_listright.html:35 msgid " Add a group of rights" msgstr " Ajouter un groupe de droits" -#: templates/users/index_listright.html:37 +#: users/templates/users/index_listright.html:37 msgid " Delete one or several groups of rights" msgstr " Supprimer un ou plusieurs groupes de droits" -#: templates/users/index_rights.html:32 +#: users/templates/users/index_rights.html:32 msgid "Rights" msgstr "Droits" -#: templates/users/index_schools.html:33 +#: users/templates/users/index_schools.html:33 msgid "List of schools" msgstr "Liste des établissements" -#: templates/users/index_schools.html:34 +#: users/templates/users/index_schools.html:34 msgid "List of schools for created users" msgstr "Liste des établissements pour les utilisateurs créés" -#: templates/users/index_schools.html:36 +#: users/templates/users/index_schools.html:36 msgid " Add a school" msgstr " Ajouter un établissement" -#: templates/users/index_schools.html:38 +#: users/templates/users/index_schools.html:38 msgid " Delete one or several schools" msgstr " Supprimer un ou plusieurs établissements" -#: templates/users/index_serviceusers.html:33 +#: users/templates/users/index_serviceusers.html:33 msgid "List of LDAP service users" msgstr "Liste des utilisateurs service LDAP" -#: templates/users/index_serviceusers.html:34 +#: users/templates/users/index_serviceusers.html:34 msgid "" "The LDAP service users are special users having access only to the LDAP for " "authentication operations. It is recommended to create a service user with a " @@ -837,38 +866,38 @@ msgstr "" "seulement au LDAP pour des opérations d'authentification. Il est recommandé " "de créer un service utilisateur avec un indentifiant et un mot de passe." -#: templates/users/index_serviceusers.html:36 +#: users/templates/users/index_serviceusers.html:36 msgid " Add a service user" msgstr " Ajouter un utilisateur" -#: templates/users/index_shell.html:33 +#: users/templates/users/index_shell.html:33 msgid "List of shells" msgstr "Liste des interfaces en ligne de commande" -#: templates/users/index_shell.html:35 +#: users/templates/users/index_shell.html:35 msgid " Add a shell" msgstr " Ajouter une interface en ligne de commande" -#: templates/users/index_whitelist.html:32 templates/users/profil.html:452 -#: templates/users/sidebar.html:64 +#: users/templates/users/index_whitelist.html:32 +#: users/templates/users/profil.html:453 users/templates/users/sidebar.html:64 msgid "Whitelists" msgstr "Accès gracieux" -#: templates/users/mass_archive.html:29 +#: users/templates/users/mass_archive.html:29 msgid "Users to archive" msgstr "Utilisateurs à archiver" -#: templates/users/mass_archive.html:35 +#: users/templates/users/mass_archive.html:35 msgid "Search" msgstr "Rechercher" -#: templates/users/mass_archive.html:39 +#: users/templates/users/mass_archive.html:39 #, python-format msgid "The following users will be archived (%(to_archive_list|length)s):" msgstr "" "Les utilisateus suivants vont être archivés (%(to_archive_list|length)s) :" -#: templates/users/plugin_out.html:35 +#: users/templates/users/plugin_out.html:35 msgid "" "Your machine and your room were successfully registered. Please disconnect " "and reconnect your Ethernet cable to benefit from a wired connection." @@ -877,229 +906,229 @@ msgstr "" "débrancher et rebrancher votre câble Ethernet pour bénéficier d'une " "connexion filaire." -#: templates/users/profil.html:36 +#: users/templates/users/profil.html:36 #, python-format msgid "Welcome %(name)s %(surname)s" msgstr "Bienvenue %(name)s %(surname)s" -#: templates/users/profil.html:38 +#: users/templates/users/profil.html:38 #, python-format msgid "Profile of %(name)s %(surname)s" msgstr "Profil de %(name)s %(surname)s" -#: templates/users/profil.html:46 +#: users/templates/users/profil.html:46 msgid "Your account has been banned" msgstr "Votre compte a été banni" -#: templates/users/profil.html:48 +#: users/templates/users/profil.html:48 #, python-format msgid "End of the ban: %(end_ban_date)s" msgstr "Fin du bannissement : %(end_ban_date)s" -#: templates/users/profil.html:53 +#: users/templates/users/profil.html:53 msgid "No connection" msgstr "Pas de connexion" -#: templates/users/profil.html:57 +#: users/templates/users/profil.html:57 msgid "Pay for a connection" msgstr "Payer une connexion" -#: templates/users/profil.html:60 +#: users/templates/users/profil.html:60 msgid "Ask for someone with the appropriate rights to pay for a connection." msgstr "" "Demandez à quelqu'un ayant les droits appropriés de payer une connexion." -#: templates/users/profil.html:66 +#: users/templates/users/profil.html:66 #, python-format msgid "Connection (until %(end_connection_date)s )" msgstr "Connexion (jusqu'au %(end_connection_date)s)" -#: templates/users/profil.html:70 +#: users/templates/users/profil.html:70 msgid "Extend the connection period" msgstr "Étendre la durée de connexion" -#: templates/users/profil.html:86 +#: users/templates/users/profil.html:86 msgid "Refill the balance" msgstr "Recharger le solde" -#: templates/users/profil.html:97 +#: users/templates/users/profil.html:97 msgid " Machines" msgstr " Machines" -#: templates/users/profil.html:101 templates/users/profil.html:113 +#: users/templates/users/profil.html:101 users/templates/users/profil.html:113 msgid " Add a machine" msgstr " Ajouter une machine" -#: templates/users/profil.html:109 templates/users/profil.html:386 +#: users/templates/users/profil.html:109 users/templates/users/profil.html:387 msgid "No machine" msgstr "Pas de machine" -#: templates/users/profil.html:127 +#: users/templates/users/profil.html:127 msgid " Detailed information" msgstr " Informations détaillées" -#: templates/users/profil.html:134 +#: users/templates/users/profil.html:134 msgid "Edit" msgstr "Modifier" -#: templates/users/profil.html:138 views.py:286 views.py:1084 +#: users/templates/users/profil.html:138 users/views.py:286 users/views.py:1084 msgid "Change the password" msgstr "Changer le mot de passe" -#: templates/users/profil.html:143 +#: users/templates/users/profil.html:143 msgid "Change the state" msgstr "Changer l'état" -#: templates/users/profil.html:149 views.py:264 +#: users/templates/users/profil.html:149 users/views.py:264 msgid "Edit the groups" msgstr "Modifier les groupes" -#: templates/users/profil.html:159 +#: users/templates/users/profil.html:159 msgid "Mailing" msgstr "Envoi de mails" -#: templates/users/profil.html:163 +#: users/templates/users/profil.html:163 msgid "Mailing disabled" msgstr "Envoi de mails désactivé" -#: templates/users/profil.html:195 +#: users/templates/users/profil.html:195 msgid "Telephone number" msgstr "Numéro de téléphone" -#: templates/users/profil.html:210 +#: users/templates/users/profil.html:210 msgid "Registration date" msgstr "Date d'inscription" -#: templates/users/profil.html:215 +#: users/templates/users/profil.html:215 msgid "Last login" msgstr "Dernière connexion" -#: templates/users/profil.html:220 +#: users/templates/users/profil.html:220 msgid "End of membership" msgstr "Fin d'adhésion" -#: templates/users/profil.html:229 +#: users/templates/users/profil.html:229 msgid "Whitelist" msgstr "Accès gracieux" -#: templates/users/profil.html:233 templates/users/profil.html:274 +#: users/templates/users/profil.html:233 users/templates/users/profil.html:274 msgid "None" msgstr "Aucun" -#: templates/users/profil.html:238 +#: users/templates/users/profil.html:238 msgid "Ban" msgstr "Bannissement" -#: templates/users/profil.html:242 +#: users/templates/users/profil.html:242 msgid "Not banned" msgstr "Non banni" -#: templates/users/profil.html:247 +#: users/templates/users/profil.html:247 msgid "State" msgstr "État" -#: templates/users/profil.html:255 +#: users/templates/users/profil.html:255 msgid "Not yet member" msgstr "Pas encore adhérent" -#: templates/users/profil.html:263 +#: users/templates/users/profil.html:263 #, python-format msgid "Active (until %(end_access)s)" msgstr "Actif (jusqu'au %(end_access)s)" -#: templates/users/profil.html:270 templates/users/sidebar.html:82 +#: users/templates/users/profil.html:270 users/templates/users/sidebar.html:82 msgid "Groups of rights" msgstr "Groupes de droits" -#: templates/users/profil.html:279 +#: users/templates/users/profil.html:279 msgid "Balance" msgstr "Solde" -#: templates/users/profil.html:286 +#: users/templates/users/profil.html:286 msgid "Refill" msgstr "Recharger" -#: templates/users/profil.html:294 +#: users/templates/users/profil.html:294 msgid "GPG fingerprint" msgstr "Empreinte GPG" -#: templates/users/profil.html:313 +#: users/templates/users/profil.html:313 msgid " Manage the club" msgstr " Gérer le club" -#: templates/users/profil.html:320 +#: users/templates/users/profil.html:321 msgid "Manage the admins and members" msgstr "Gérer les admins et les membres" -#: templates/users/profil.html:324 +#: users/templates/users/profil.html:325 msgid "Club admins" msgstr "Admins du clubs" -#: templates/users/profil.html:343 +#: users/templates/users/profil.html:344 msgid "Members" msgstr "Adhérents" -#: templates/users/profil.html:371 +#: users/templates/users/profil.html:372 msgid "Machines" msgstr "Machines" -#: templates/users/profil.html:379 +#: users/templates/users/profil.html:380 msgid "Add a machine" msgstr "Ajouter une machine" -#: templates/users/profil.html:396 +#: users/templates/users/profil.html:397 msgid "Subscriptions" msgstr "Cotisations" -#: templates/users/profil.html:404 +#: users/templates/users/profil.html:405 msgid "Add a subscription" msgstr "Ajouter une cotisation" -#: templates/users/profil.html:409 +#: users/templates/users/profil.html:410 msgid "Edit the balance" msgstr "Modifier le solde" -#: templates/users/profil.html:418 +#: users/templates/users/profil.html:419 msgid "No invoice" msgstr "Pas de facture" -#: templates/users/profil.html:435 views.py:388 +#: users/templates/users/profil.html:436 users/views.py:388 msgid "Add a ban" msgstr "Ajouter un bannissement" -#: templates/users/profil.html:443 +#: users/templates/users/profil.html:444 msgid "No ban" msgstr "Pas de bannissement" -#: templates/users/profil.html:460 +#: users/templates/users/profil.html:461 msgid "Grant a whitelist" msgstr "Donner un accès gracieux" -#: templates/users/profil.html:468 +#: users/templates/users/profil.html:469 msgid "No whitelist" msgstr "Pas d'accès gracieux" -#: templates/users/profil.html:476 +#: users/templates/users/profil.html:477 msgid " Email settings" msgstr " Paramètres mail" -#: templates/users/profil.html:483 +#: users/templates/users/profil.html:484 msgid " Edit email settings" msgstr " Modifier les paramètres mail" -#: templates/users/profil.html:492 templates/users/profil.html:518 +#: users/templates/users/profil.html:493 users/templates/users/profil.html:519 msgid "Contact email address" msgstr "Adresse mail de contact" -#: templates/users/profil.html:496 +#: users/templates/users/profil.html:497 msgid "Enable the local email account" msgstr "Activer le compte mail local" -#: templates/users/profil.html:498 +#: users/templates/users/profil.html:499 msgid "Enable the local email redirection" msgstr "Activer la redirection mail locale" -#: templates/users/profil.html:502 +#: users/templates/users/profil.html:503 msgid "" "The contact email address is the email address where we send emails to " "contact you. If you would like to use your external email address for that, " @@ -1111,245 +1140,245 @@ msgstr "" "cela, vous pouvez soit désactiver votre adresse mail locale soit activer la " "redirection des mails locaux." -#: templates/users/profil.html:507 +#: users/templates/users/profil.html:508 msgid " Add an email address" msgstr " Ajouter une adresse mail" -#: templates/users/sidebar.html:33 +#: users/templates/users/sidebar.html:33 msgid "Create a club or organisation" msgstr "Créer un club ou une association" -#: templates/users/sidebar.html:39 +#: users/templates/users/sidebar.html:39 msgid "Create a user" msgstr "Créer un utilisateur" -#: templates/users/sidebar.html:46 +#: users/templates/users/sidebar.html:46 msgid "Clubs and organisations" msgstr "Clubs et associations" -#: templates/users/sidebar.html:70 +#: users/templates/users/sidebar.html:70 msgid "Schools" msgstr "Établissements" -#: templates/users/sidebar.html:76 +#: users/templates/users/sidebar.html:76 msgid "Shells" msgstr "Interfaces en ligne de commande" -#: templates/users/sidebar.html:88 +#: users/templates/users/sidebar.html:88 msgid "Service users" msgstr "Utilisateurs service" -#: templates/users/sidebar.html:94 +#: users/templates/users/sidebar.html:94 msgid "Massively archive" msgstr "Archiver en masse" -#: templates/users/user.html:45 +#: users/templates/users/user.html:45 msgid "Summary of the General Terms of Use" msgstr "Résumé des Conditions Générales d'Utilisation" -#: templates/users/user_autocapture.html:35 +#: users/templates/users/user_autocapture.html:35 msgid "Device and room register form" msgstr "Enregistrement de votre chambre et machine fixe" -#: templates/users/user_autocapture.html:44 +#: users/templates/users/user_autocapture.html:44 msgid "Connected from:" msgstr "Connecté depuis :" -#: templates/users/user_autocapture.html:46 +#: users/templates/users/user_autocapture.html:46 #, python-format msgid "Room %(room)s" msgstr "Chambre %(room)s" -#: templates/users/user_autocapture.html:47 +#: users/templates/users/user_autocapture.html:47 #, python-format msgid "Port %(port)s" msgstr "Port %(port)s" -#: templates/users/user_autocapture.html:54 +#: users/templates/users/user_autocapture.html:54 msgid "Connected with device:" msgstr "Connecté avec l'appareil :" -#: templates/users/user_autocapture.html:56 +#: users/templates/users/user_autocapture.html:56 #, python-format msgid "MAC address %(mac)s" msgstr "Adresse MAC %(mac)s" -#: views.py:126 +#: users/views.py:126 #, python-format msgid "The user %s was created, an email to set the password was sent." msgstr "" "L'utilisateur %s a été créé, un mail pour initialiser le mot de passe a été " "envoyé." -#: views.py:138 +#: users/views.py:138 msgid "Commit" msgstr "Valider" -#: views.py:155 +#: users/views.py:155 #, python-format msgid "The club %s was created, an email to set the password was sent." msgstr "" "Le club %s a été créé, un mail pour initialiser le mot de passe a été envoyé." -#: views.py:162 +#: users/views.py:162 msgid "Create a club" msgstr "Créer un club" -#: views.py:180 +#: users/views.py:180 msgid "The club was edited." msgstr "Le club a été modifié." -#: views.py:189 +#: users/views.py:189 msgid "Edit the admins and members" msgstr "Modifier les admins et les membres" -#: views.py:217 +#: users/views.py:217 msgid "The user was edited." msgstr "L'utilisateur a été modifié." -#: views.py:223 +#: users/views.py:223 msgid "Edit the user" msgstr "Modifier l'utilisateur" -#: views.py:237 +#: users/views.py:237 msgid "The state was edited." msgstr "L'état a été modifié." -#: views.py:243 +#: users/views.py:243 msgid "Edit the state" msgstr "Modifier l'état" -#: views.py:258 +#: users/views.py:258 msgid "The groups were edited." msgstr "Les groupes ont été modifiés." -#: views.py:280 views.py:1081 +#: users/views.py:280 users/views.py:1081 msgid "The password was changed." msgstr "Le mot de passe a été changé." -#: views.py:298 +#: users/views.py:298 #, python-format msgid "%s was removed from the group." msgstr "%s a été retiré du groupe." -#: views.py:308 +#: users/views.py:308 #, python-format msgid "%s is no longer superuser." msgstr "%s n'est plus superutilisateur." -#: views.py:321 +#: users/views.py:321 msgid "The service user was created." msgstr "L'utilisateur service a été créé." -#: views.py:325 +#: users/views.py:325 msgid "Create a service user" msgstr "Créer un utilisateur service" -#: views.py:342 +#: users/views.py:342 msgid "The service user was edited." msgstr "L'utilisateur service a été modifié." -#: views.py:345 +#: users/views.py:345 msgid "Edit a service user" msgstr "Modifier un utilisateur service" -#: views.py:357 +#: users/views.py:357 msgid "The service user was deleted." msgstr "L'utilisateur service a été supprimé." -#: views.py:377 +#: users/views.py:377 msgid "The ban was added." msgstr "Le bannissement a été ajouté." -#: views.py:385 +#: users/views.py:385 msgid "Warning: this user already has an active ban." msgstr "Attention : cet utilisateur a déjà un bannissement actif." -#: views.py:404 +#: users/views.py:404 msgid "The ban was edited." msgstr "Le bannissement a été modifié." -#: views.py:407 +#: users/views.py:407 msgid "Edit a ban" msgstr "Modifier un bannissement" -#: views.py:419 +#: users/views.py:419 msgid "The ban was deleted." msgstr "Le bannissement a été supprimé." -#: views.py:446 +#: users/views.py:446 msgid "The whitelist was added." msgstr "L'accès gracieux a été ajouté." -#: views.py:454 +#: users/views.py:454 msgid "Warning: this user already has an active whitelist." msgstr "Attention : cet utilisateur a déjà un accès gracieux actif." -#: views.py:457 +#: users/views.py:457 msgid "Add a whitelist" msgstr "Ajouter un accès gracieux" -#: views.py:477 +#: users/views.py:477 msgid "The whitelist was edited." msgstr "L'accès gracieux a été ajouté." -#: views.py:480 +#: users/views.py:480 msgid "Edit a whitelist" msgstr "Modifier un accès gracieux" -#: views.py:492 +#: users/views.py:492 msgid "The whitelist was deleted." msgstr "L'accès gracieux a été supprimé." -#: views.py:516 +#: users/views.py:516 msgid "The local email account was created." msgstr "Le compte mail local a été créé." -#: views.py:524 +#: users/views.py:524 msgid "Add a local email account" msgstr "Ajouter un compte mail local" -#: views.py:541 +#: users/views.py:541 msgid "The local email account was edited." msgstr "Le compte mail local a été modifié." -#: views.py:549 +#: users/views.py:549 msgid "Edit a local email account" msgstr "Modifier un compte mail local" -#: views.py:561 +#: users/views.py:561 msgid "The local email account was deleted." msgstr "Le compte mail local a été supprimé." -#: views.py:585 +#: users/views.py:585 msgid "The email settings were edited." msgstr "Les paramètres mail ont été modifiés." -#: views.py:594 +#: users/views.py:594 msgid "Edit the email settings" msgstr "Modifier les paramètres mail" -#: views.py:608 +#: users/views.py:608 msgid "The school was added." msgstr "L'établissement a été ajouté." -#: views.py:611 +#: users/views.py:611 msgid "Add a school" msgstr "Ajouter un établissement" -#: views.py:626 +#: users/views.py:626 msgid "The school was edited." msgstr "L'établissement a été modifié." -#: views.py:629 +#: users/views.py:629 msgid "Edit a school" msgstr "Modifier un établissement" -#: views.py:648 +#: users/views.py:648 msgid "The school was deleted." msgstr "L'établissement a été supprimé." -#: views.py:652 +#: users/views.py:652 #, python-format msgid "" "The school %s is assigned to at least one user, impossible to delete it." @@ -1357,51 +1386,51 @@ msgstr "" "L'établissement %s est assigné à au moins un utilisateur, impossible de le " "supprimer." -#: views.py:656 views.py:768 +#: users/views.py:656 users/views.py:768 msgid "Delete" msgstr "Supprimer" -#: views.py:669 +#: users/views.py:669 msgid "The shell was added." msgstr "L'interface en ligne de commande a été ajoutée." -#: views.py:672 +#: users/views.py:672 msgid "Add a shell" msgstr "Ajouter une interface en ligne de commande" -#: views.py:686 +#: users/views.py:686 msgid "The shell was edited." msgstr "L'interface en ligne de commande a été modifiée." -#: views.py:689 +#: users/views.py:689 msgid "Edit a shell" msgstr "Modifier une interface en ligne de commande" -#: views.py:701 +#: users/views.py:701 msgid "The shell was deleted." msgstr "L'interface en ligne de commande a été supprimée." -#: views.py:718 +#: users/views.py:718 msgid "The group of rights was added." msgstr "Le groupe de droits a été ajouté." -#: views.py:721 +#: users/views.py:721 msgid "Add a group of rights" msgstr "Ajouter un groupe de droits" -#: views.py:739 +#: users/views.py:739 msgid "The group of rights was edited." msgstr "Le groupe de droits a été modifié." -#: views.py:742 +#: users/views.py:742 msgid "Edit a group of rights" msgstr "Modifier un groupe de droits" -#: views.py:759 +#: users/views.py:759 msgid "The group of rights was deleted." msgstr "Le groupe de droits a été supprimé." -#: views.py:764 +#: users/views.py:764 #, python-format msgid "" "The group of rights %s is assigned to at least one user, impossible to " @@ -1410,40 +1439,40 @@ msgstr "" "Le groupe de droits %s est assigné à au moins un utilisateur, impossible de " "le supprimer." -#: views.py:792 +#: users/views.py:792 msgid "Archiving" msgstr "Archivage" -#: views.py:793 +#: users/views.py:793 #, python-format msgid "%s users were archived." msgstr "%s utilisateurs ont été archivés." -#: views.py:1043 +#: users/views.py:1043 msgid "The user doesn't exist." msgstr "L'utilisateur n'existe pas." -#: views.py:1045 views.py:1053 +#: users/views.py:1045 users/views.py:1053 msgid "Reset" msgstr "Réinitialiser" -#: views.py:1050 +#: users/views.py:1050 msgid "An email to reset the password was sent." msgstr "Un mail pour réinitialiser le mot de passe a été envoyé." -#: views.py:1067 +#: users/views.py:1067 msgid "Error: please contact an admin." msgstr "Erreur : veuillez contacter un admin." -#: views.py:1079 +#: users/views.py:1079 msgid "Password reset" msgstr "Réinitialisation du mot de passe" -#: views.py:1096 +#: users/views.py:1096 msgid "Incorrect URL, or already registered device." msgstr "URL incorrect, ou appareil déjà enregistré." -#: views.py:1104 +#: users/views.py:1104 msgid "" "Successful registration! Please disconnect and reconnect your Ethernet cable " "to get Internet access." @@ -1451,22 +1480,22 @@ msgstr "" "Enregistrement réussi ! Veuillez débrancher et rebrancher votre câble " "Ethernet pour avoir accès à Internet." -#: views.py:1148 views.py:1172 views.py:1187 +#: users/views.py:1148 users/views.py:1172 users/views.py:1187 msgid "The mailing list doesn't exist." msgstr "La liste de diffusion n'existe pas." -#: widgets.py:36 +#: users/widgets.py:36 msgid "Today" msgstr "Aujourd'hui" -#: widgets.py:44 +#: users/widgets.py:44 msgid "Next" msgstr "Suivant" -#: widgets.py:45 +#: users/widgets.py:45 msgid "Previous" msgstr "Précédent" -#: widgets.py:46 +#: users/widgets.py:46 msgid "Wk" msgstr "Wk" From 8d799ed92d8042fa6767d55a467769bee405cb41 Mon Sep 17 00:00:00 2001 From: detraz Date: Mon, 18 Feb 2019 21:11:51 +0100 Subject: [PATCH 008/228] Create dormitory with buildings --- re2o/base.py | 7 +- topologie/forms.py | 13 ++++ .../migrations/0070_auto_20190218_1743.py | 47 +++++++++++++ .../migrations/0071_auto_20190218_1936.py | 56 ++++++++++++++++ topologie/models.py | 45 +++++++++++-- .../templates/topologie/aff_chambres.html | 3 + .../templates/topologie/aff_dormitory.html | 62 +++++++++++++++++ .../topologie/index_physical_grouping.html | 10 +++ topologie/urls.py | 9 +++ topologie/views.py | 67 ++++++++++++++++++- 10 files changed, 313 insertions(+), 6 deletions(-) create mode 100644 topologie/migrations/0070_auto_20190218_1743.py create mode 100644 topologie/migrations/0071_auto_20190218_1936.py create mode 100644 topologie/templates/topologie/aff_dormitory.html diff --git a/re2o/base.py b/re2o/base.py index fff2278c..1397b1b0 100644 --- a/re2o/base.py +++ b/re2o/base.py @@ -194,12 +194,17 @@ class SortTable: } TOPOLOGIE_INDEX_ROOM = { 'room_name': ['name'], - 'default': ['name'] + 'building_name': ['building__name'], + 'default': ['building__name', 'name'] } TOPOLOGIE_INDEX_BUILDING = { 'building_name': ['name'], 'default': ['name'] } + TOPOLOGIE_INDEX_DORMITORY = { + 'dormitory_name': ['name'], + 'default': ['name'] + } TOPOLOGIE_INDEX_BORNE = { 'ap_name': ['interface__domain__name'], 'ap_ip': ['interface__ipv4__ipv4'], diff --git a/topologie/forms.py b/topologie/forms.py index ed6fa5b9..875fa567 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -54,6 +54,7 @@ from .models import ( AccessPoint, SwitchBay, Building, + Dormitory, PortProfile, ModuleSwitch, ModuleOnSwitch, @@ -259,6 +260,18 @@ class EditBuildingForm(FormRevMixin, ModelForm): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(EditBuildingForm, self).__init__(*args, prefix=prefix, **kwargs) + +class EditDormitoryForm(FormRevMixin, ModelForm): + """Permet d'éditer la residence""" + class Meta: + model = Dormitory + fields = '__all__' + + def __init__(self, *args, **kwargs): + prefix = kwargs.pop('prefix', self.Meta.model.__name__) + super(EditDormitoryForm, self).__init__(*args, prefix=prefix, **kwargs) + + class EditPortProfileForm(FormRevMixin, ModelForm): """Form to edit a port profile""" class Meta: diff --git a/topologie/migrations/0070_auto_20190218_1743.py b/topologie/migrations/0070_auto_20190218_1743.py new file mode 100644 index 00000000..bb0c6f5c --- /dev/null +++ b/topologie/migrations/0070_auto_20190218_1743.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-02-18 16:43 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import re2o.mixins + + +class Migration(migrations.Migration): + + dependencies = [ + ('topologie', '0069_auto_20190108_1439'), + ] + + def create_dormitory(apps, schema_editor): + db_alias = schema_editor.connection.alias + dormitory = apps.get_model("topologie", "Dormitory") + building = apps.get_model("topologie", "Building") + dorm = dormitory.objects.using(db_alias).create(name="Residence") + building.objects.using(db_alias).update(dormitory=dorm) + + def delete_dormitory(apps, schema_editor): + pass + + operations = [ + migrations.CreateModel( + name='Dormitory', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ], + options={ + 'verbose_name': 'dormitory', + 'permissions': (('view_dormitory', 'Can view a dormitory object'),), + 'verbose_name_plural': 'dormitories', + }, + bases=(re2o.mixins.AclMixin, re2o.mixins.RevMixin, models.Model), + ), + migrations.AddField( + model_name='building', + name='dormitory', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='topologie.Dormitory'), + preserve_default=False, + ), + migrations.RunPython(create_dormitory, delete_dormitory) + ] diff --git a/topologie/migrations/0071_auto_20190218_1936.py b/topologie/migrations/0071_auto_20190218_1936.py new file mode 100644 index 00000000..8c5e3c8d --- /dev/null +++ b/topologie/migrations/0071_auto_20190218_1936.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-02-18 18:36 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('topologie', '0070_auto_20190218_1743'), + ] + + def transfer_room(apps, schema_editor): + db_alias = schema_editor.connection.alias + room_obj = apps.get_model("topologie", "Room") + building_obj = apps.get_model("topologie", "Building") + dorm_obj = apps.get_model("topologie", "Dormitory") + dorm = dorm_obj.objects.using(db_alias).first() + for room in room_obj.objects.using(db_alias).all(): + building, created = building_obj.objects.using(db_alias).get_or_create(name=room.name[0].upper(), dormitory=dorm) + room.building = building + room.name = room.name[1:] + room.save() + + def untransfer_room(apps, schema_editor): + pass + + operations = [ + migrations.AlterField( + model_name='room', + name='name', + field=models.CharField(max_length=255), + ), + migrations.AddField( + model_name='room', + name='building', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='topologie.Building'), + ), + migrations.AlterUniqueTogether( + name='room', + unique_together=set([('name', 'building')]), + ), + migrations.AlterField( + model_name='building', + name='dormitory', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='topologie.Dormitory'), + ), + migrations.RunPython(transfer_room, untransfer_room), + migrations.AlterField( + model_name='room', + name='building', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='topologie.Building'), + ) + ] diff --git a/topologie/models.py b/topologie/models.py index 3e093b40..7e4f6499 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -516,10 +516,36 @@ class SwitchBay(AclMixin, RevMixin, models.Model): return self.name +class Dormitory(AclMixin, RevMixin, models.Model): + """Une résidence universitaire + A residence""" + + name = models.CharField(max_length=255) + + + class Meta: + permissions = ( + ("view_dormitory", _("Can view a dormitory object")), + ) + verbose_name = _("dormitory") + verbose_name_plural = _("dormitories") + + def all_ap_in(self): + """Returns all ap of the dorms""" + return AccessPoint.all_ap_in(self.building_set.all()) + + def __str__(self): + return self.name + + class Building(AclMixin, RevMixin, models.Model): """Un batiment""" name = models.CharField(max_length=255) + dormitory = models.ForeignKey( + 'Dormitory', + on_delete=models.PROTECT, + ) class Meta: permissions = ( @@ -533,7 +559,10 @@ class Building(AclMixin, RevMixin, models.Model): return AccessPoint.all_ap_in(self) def __str__(self): - return self.name + if Dormitory.objects.count() > 1: + return self.dormitory.name + " : " + self.name + else: + return self.name class Port(AclMixin, RevMixin, models.Model): @@ -703,19 +732,27 @@ class Port(AclMixin, RevMixin, models.Model): class Room(AclMixin, RevMixin, models.Model): """Une chambre/local contenant une prise murale""" - name = models.CharField(max_length=255, unique=True) + name = models.CharField(max_length=255) details = models.CharField(max_length=255, blank=True) + building = models.ForeignKey( + 'Building', + on_delete=models.PROTECT, + ) class Meta: - ordering = ['name'] + ordering = ['building__name'] permissions = ( ("view_room", _("Can view a room object")), ) verbose_name = _("room") verbose_name_plural = _("rooms") + unique_together = ('name', 'building') def __str__(self): - return self.name + if Dormitory.objects.count() > 1: + return self.building.dormitory.name + " : " + self.building.name + self.name + else: + return self.building.name + self.name class PortProfile(AclMixin, RevMixin, models.Model): diff --git a/topologie/templates/topologie/aff_chambres.html b/topologie/templates/topologie/aff_chambres.html index 6e2b181f..4a79efbd 100644 --- a/topologie/templates/topologie/aff_chambres.html +++ b/topologie/templates/topologie/aff_chambres.html @@ -34,6 +34,8 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Room" as tr_room %} + {% trans "Building" as tr_building %} + {% include 'buttons/sort.html' with prefix='building' col='name' text=tr_building %} {% include 'buttons/sort.html' with prefix='room' col='name' text=tr_room %} {% trans "Details" %} @@ -41,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% for room in room_list %} + {{ room.building }} {{ room.name }} {{ room.details }} diff --git a/topologie/templates/topologie/aff_dormitory.html b/topologie/templates/topologie/aff_dormitory.html new file mode 100644 index 00000000..35808bd5 --- /dev/null +++ b/topologie/templates/topologie/aff_dormitory.html @@ -0,0 +1,62 @@ +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load acl %} +{% load logs_extra %} +{% load i18n %} + +{% if dormitory_list.paginator %} + {% include 'pagination.html' with list=dormitory_list %} +{% endif %} + + + + + {% trans "Dormitory" as tr_dormitory %} + + + + + + {% for dormitory in dormitory_list %} + + + + + + {% endfor %} +
{% include 'buttons/sort.html' with prefix='dormitory' col='name' text=tr_dormitory %}{% trans "Building" %}
{{ dormitory.name }}{% for building in dormitory.building_set.all %} {{ building }} {% endfor %} + {% can_edit dormitory %} + {% include 'buttons/edit.html' with href='topologie:edit-dormitory' id=dormitory.id %} + {% acl_end %} + {% history_button dormitory %} + {% can_delete dormitory %} + {% include 'buttons/suppr.html' with href='topologie:del-dormitory' id=dormitory.id %} + {% acl_end %} +
+ +{% if dormitory_list.paginator %} + {% include 'pagination.html' with list=dormitory_list %} +{% endif %} + diff --git a/topologie/templates/topologie/index_physical_grouping.html b/topologie/templates/topologie/index_physical_grouping.html index d2defa0c..7b081439 100644 --- a/topologie/templates/topologie/index_physical_grouping.html +++ b/topologie/templates/topologie/index_physical_grouping.html @@ -55,5 +55,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% acl_end %} {% include 'topologie/aff_building.html' with building_list=building_list %} + + +

{% trans "Dormitories" %}

+ {% can_create Dormitory %} + + {% trans " Add a dormitory" %} + +
+ {% acl_end %} + {% include 'topologie/aff_dormitory.html' with dormitory_list=dormitory_list %} {% endblock %} diff --git a/topologie/urls.py b/topologie/urls.py index 70eae8e4..76cf089c 100644 --- a/topologie/urls.py +++ b/topologie/urls.py @@ -108,6 +108,15 @@ urlpatterns = [ url(r'^del_building/(?P[0-9]+)$', views.del_building, name='del-building'), + url(r'^new_dormitory/$', + views.new_dormitory, + name='new-dormitory'), + url(r'^edit_dormitory/(?P[0-9]+)$', + views.edit_dormitory, + name='edit-dormitory'), + url(r'^del_dormitory/(?P[0-9]+)$', + views.del_dormitory, + name='del-dormitory'), url(r'^index_port_profile/$', views.index_port_profile, name='index-port-profile'), diff --git a/topologie/views.py b/topologie/views.py index 2eeb3d55..7de8bcc1 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -84,6 +84,7 @@ from .models import ( AccessPoint, SwitchBay, Building, + Dormitory, Server, PortProfile, ModuleSwitch, @@ -103,6 +104,7 @@ from .forms import ( EditAccessPointForm, EditSwitchBayForm, EditBuildingForm, + EditDormitoryForm, EditPortProfileForm, EditModuleForm, EditSwitchModuleForm, @@ -254,7 +256,7 @@ def index_ap(request): @login_required -@can_view_all(Stack, Building, SwitchBay) +@can_view_all(Stack, Building, Dormitory, SwitchBay) def index_physical_grouping(request): """Affichage de la liste des stacks (affiche l'ensemble des switches)""" stack_list = (Stack.objects @@ -262,6 +264,7 @@ def index_physical_grouping(request): 'switch_set__interface_set__domain__extension' )) building_list = Building.objects.all() + dormitory_list = Dormitory.objects.all() switch_bay_list = SwitchBay.objects.select_related('building') stack_list = SortTable.sort( stack_list, @@ -275,6 +278,12 @@ def index_physical_grouping(request): request.GET.get('order'), SortTable.TOPOLOGIE_INDEX_BUILDING ) + dormitory_list = SortTable.sort( + dormitory_list, + request.GET.get('col'), + request.GET.get('order'), + SortTable.TOPOLOGIE_INDEX_DORMITORY + ) switch_bay_list = SortTable.sort( switch_bay_list, request.GET.get('col'), @@ -288,6 +297,7 @@ def index_physical_grouping(request): 'stack_list': stack_list, 'switch_bay_list': switch_bay_list, 'building_list': building_list, + 'dormitory_list': dormitory_list, } ) @@ -956,6 +966,61 @@ def del_building(request, building, **_kwargs): ) +@login_required +@can_create(Dormitory) +def new_dormitory(request): + """Nouvelle residence""" + dormitory = EditDormitoryForm(request.POST or None) + if dormitory.is_valid(): + dormitory.save() + messages.success(request, _("The dormitory was created.")) + return redirect(reverse('topologie:index-physical-grouping')) + return form( + {'topoform': dormitory, 'action_name': _("Create")}, + 'topologie/topo.html', + request + ) + + +@login_required +@can_edit(Dormitory) +def edit_dormitory(request, dormitory, **_kwargs): + """ Edition d'une residence""" + dormitory = EditDormitoryForm(request.POST or None, instance=dormitory) + if dormitory.is_valid(): + if dormitory.changed_data: + dormitory.save() + messages.success(request, _("The dormitory was edited.")) + return redirect(reverse('topologie:index-physical-grouping')) + return form( + {'topoform': dormitory, 'action_name': _("Edit")}, + 'topologie/topo.html', + request + ) + + +@login_required +@can_delete(Dormitory) +def del_dormitory(request, dormitory, **_kwargs): + """ Suppression d'une residence""" + if request.method == "POST": + try: + dormitory.delete() + messages.success(request, _("The dormitory was deleted.")) + except ProtectedError: + messages.error( + request, + (_("The dormitory %s is used by another object, impossible" + " to delete it.") % dormitory) + ) + return redirect(reverse('topologie:index-physical-grouping')) + return form( + {'objet': dormitory, 'objet_name': _("Dormitory")}, + 'topologie/delete.html', + request + ) + + @login_required @can_create(ConstructorSwitch) def new_constructor_switch(request): From 87730a3ad2bf15327ad5cf09f008b72943c8c792 Mon Sep 17 00:00:00 2001 From: detraz Date: Mon, 18 Feb 2019 22:13:34 +0100 Subject: [PATCH 009/228] Fix room_name problem with building --- topologie/admin.py | 8 ++++++++ topologie/models.py | 9 +++++---- topologie/templates/topologie/aff_dormitory.html | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/topologie/admin.py b/topologie/admin.py index d2a25461..d6fa318e 100644 --- a/topologie/admin.py +++ b/topologie/admin.py @@ -39,6 +39,7 @@ from .models import ( AccessPoint, SwitchBay, Building, + Dormitory, PortProfile, ) @@ -87,6 +88,12 @@ class BuildingAdmin(VersionAdmin): """Administration d'un batiment""" pass + +class DormitoryAdmin(VersionAdmin): + """Administration d'une residence""" + pass + + class PortProfileAdmin(VersionAdmin): """Administration of a port profile""" pass @@ -99,5 +106,6 @@ admin.site.register(Stack, StackAdmin) admin.site.register(ModelSwitch, ModelSwitchAdmin) admin.site.register(ConstructorSwitch, ConstructorSwitchAdmin) admin.site.register(Building, BuildingAdmin) +admin.site.register(Dormitory, DormitoryAdmin) admin.site.register(SwitchBay, SwitchBayAdmin) admin.site.register(PortProfile, PortProfileAdmin) diff --git a/topologie/models.py b/topologie/models.py index 7e4f6499..dbb168f3 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -558,6 +558,10 @@ class Building(AclMixin, RevMixin, models.Model): """Returns all ap of the building""" return AccessPoint.all_ap_in(self) + @cached_property + def cached_name(self): + return self.__str__() + def __str__(self): if Dormitory.objects.count() > 1: return self.dormitory.name + " : " + self.name @@ -749,10 +753,7 @@ class Room(AclMixin, RevMixin, models.Model): unique_together = ('name', 'building') def __str__(self): - if Dormitory.objects.count() > 1: - return self.building.dormitory.name + " : " + self.building.name + self.name - else: - return self.building.name + self.name + return self.building.cached_name + self.name class PortProfile(AclMixin, RevMixin, models.Model): diff --git a/topologie/templates/topologie/aff_dormitory.html b/topologie/templates/topologie/aff_dormitory.html index 35808bd5..758e5e2c 100644 --- a/topologie/templates/topologie/aff_dormitory.html +++ b/topologie/templates/topologie/aff_dormitory.html @@ -42,7 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% for dormitory in dormitory_list %} {{ dormitory.name }} - {% for building in dormitory.building_set.all %} {{ building }} {% endfor %} + {% for building in dormitory.building_set.all %} {{ building.name }} {% endfor %} {% can_edit dormitory %} {% include 'buttons/edit.html' with href='topologie:edit-dormitory' id=dormitory.id %} From c346ca531a04e906f2e1fc7635d4dd5927e3b5b6 Mon Sep 17 00:00:00 2001 From: detraz Date: Tue, 19 Feb 2019 00:54:11 +0100 Subject: [PATCH 010/228] Display residence if residence>1 --- topologie/templates/topologie/aff_building.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/topologie/templates/topologie/aff_building.html b/topologie/templates/topologie/aff_building.html index 9885f1c5..5775bb28 100644 --- a/topologie/templates/topologie/aff_building.html +++ b/topologie/templates/topologie/aff_building.html @@ -35,13 +35,13 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Building" as tr_building %} {% include 'buttons/sort.html' with prefix='building' col='name' text=tr_building %} - {% trans "Access points" %} + {% trans "Access points" %} {% for building in building_list %} - {{ building.name }} + {{ building.cached_name }} {% for ap in building.all_ap_in %} {{ ap.short_name }} {% endfor %} {% can_edit building %} From bd079b275628998f40c40028335a16e5d067f050 Mon Sep 17 00:00:00 2001 From: chirac Date: Wed, 20 Feb 2019 20:46:28 +0100 Subject: [PATCH 011/228] Doc in english dormitory views.py --- topologie/views.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/topologie/views.py b/topologie/views.py index 7de8bcc1..201c8eb4 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -914,7 +914,8 @@ def del_switch_bay(request, switch_bay, **_kwargs): @login_required @can_create(Building) def new_building(request): - """Nouveau batiment""" + """New Building of a dorm + Nouveau batiment""" building = EditBuildingForm(request.POST or None) if building.is_valid(): building.save() @@ -930,7 +931,8 @@ def new_building(request): @login_required @can_edit(Building) def edit_building(request, building, **_kwargs): - """ Edition d'un batiment""" + """Edit a building + Edition d'un batiment""" building = EditBuildingForm(request.POST or None, instance=building) if building.is_valid(): if building.changed_data: @@ -947,7 +949,8 @@ def edit_building(request, building, **_kwargs): @login_required @can_delete(Building) def del_building(request, building, **_kwargs): - """ Suppression d'un batiment""" + """Delete a building + Suppression d'un batiment""" if request.method == "POST": try: building.delete() @@ -969,7 +972,8 @@ def del_building(request, building, **_kwargs): @login_required @can_create(Dormitory) def new_dormitory(request): - """Nouvelle residence""" + """A new dormitory + Nouvelle residence""" dormitory = EditDormitoryForm(request.POST or None) if dormitory.is_valid(): dormitory.save() @@ -985,7 +989,8 @@ def new_dormitory(request): @login_required @can_edit(Dormitory) def edit_dormitory(request, dormitory, **_kwargs): - """ Edition d'une residence""" + """Edit a dormitory + Edition d'une residence""" dormitory = EditDormitoryForm(request.POST or None, instance=dormitory) if dormitory.is_valid(): if dormitory.changed_data: @@ -1002,7 +1007,8 @@ def edit_dormitory(request, dormitory, **_kwargs): @login_required @can_delete(Dormitory) def del_dormitory(request, dormitory, **_kwargs): - """ Suppression d'une residence""" + """Delete a dormitory + Suppression d'une residence""" if request.method == "POST": try: dormitory.delete() From c4571ab42538c8ec5efcc782bb52ee5123ee4cf6 Mon Sep 17 00:00:00 2001 From: chirac Date: Wed, 20 Feb 2019 20:49:34 +0100 Subject: [PATCH 012/228] Update, english doc models.py --- topologie/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/topologie/models.py b/topologie/models.py index dbb168f3..82a9c6a8 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -517,8 +517,8 @@ class SwitchBay(AclMixin, RevMixin, models.Model): class Dormitory(AclMixin, RevMixin, models.Model): - """Une résidence universitaire - A residence""" + """A student accomodation/dormitory + Une résidence universitaire""" name = models.CharField(max_length=255) @@ -539,7 +539,8 @@ class Dormitory(AclMixin, RevMixin, models.Model): class Building(AclMixin, RevMixin, models.Model): - """Un batiment""" + """A building of a dormitory + Un batiment""" name = models.CharField(max_length=255) dormitory = models.ForeignKey( From 4fcfbea0f49510f0b6c693ab06fe341ba9dcc5a4 Mon Sep 17 00:00:00 2001 From: klafyvel Date: Wed, 20 Feb 2019 23:25:15 +0100 Subject: [PATCH 013/228] Update forms.py --- topologie/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topologie/forms.py b/topologie/forms.py index 875fa567..bdc8ba4e 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -262,7 +262,7 @@ class EditBuildingForm(FormRevMixin, ModelForm): class EditDormitoryForm(FormRevMixin, ModelForm): - """Permet d'éditer la residence""" + """Enable dormitory edition""" class Meta: model = Dormitory fields = '__all__' From c9b84047d20a302667fcd5fcf2f072528c21e9e3 Mon Sep 17 00:00:00 2001 From: detraz Date: Sun, 3 Mar 2019 17:28:33 +0100 Subject: [PATCH 014/228] =?UTF-8?q?Change=20les=20variables=20type=20en=20?= =?UTF-8?q?name=20ou=20machine=5Ftype=20pour=20=C3=A9viter=20les=20confusi?= =?UTF-8?q?ons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/serializers.py | 12 ++--- freeradius_utils/auth.py | 8 ++-- machines/admin.py | 2 +- machines/forms.py | 18 ++++---- .../migrations/0102_auto_20190303_1611.py | 30 ++++++++++++ machines/models.py | 46 +++++++++---------- machines/templates/machines/aff_iptype.html | 2 +- machines/templates/machines/aff_machines.html | 2 +- .../templates/machines/aff_machinetype.html | 2 +- machines/views.py | 18 ++++---- re2o/utils.py | 2 +- topologie/models.py | 2 +- users/views.py | 2 +- 13 files changed, 88 insertions(+), 58 deletions(-) create mode 100644 machines/migrations/0102_auto_20190303_1611.py diff --git a/api/serializers.py b/api/serializers.py index 8c22ed21..eabcc73a 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -150,7 +150,7 @@ class MachineTypeSerializer(NamespacedHMSerializer): class Meta: model = machines.MachineType - fields = ('type', 'ip_type', 'api_url') + fields = ('name', 'ip_type', 'api_url') class IpTypeSerializer(NamespacedHMSerializer): @@ -159,7 +159,7 @@ class IpTypeSerializer(NamespacedHMSerializer): class Meta: model = machines.IpType - fields = ('type', 'extension', 'need_infra', 'domaine_ip_start', + fields = ('name', 'extension', 'need_infra', 'domaine_ip_start', 'domaine_ip_stop', 'prefix_v6', 'vlan', 'ouverture_ports', 'api_url') @@ -267,7 +267,7 @@ class InterfaceSerializer(NamespacedHMSerializer): class Meta: model = machines.Interface - fields = ('ipv4', 'mac_address', 'machine', 'type', 'details', + fields = ('ipv4', 'mac_address', 'machine', 'machine_type', 'details', 'port_lists', 'active', 'api_url') @@ -747,7 +747,7 @@ class InterfaceVlanSerializer(NamespacedHMSerializer): domain = serializers.CharField(read_only=True) ipv4 = serializers.CharField(read_only=True) ipv6 = Ipv6ListSerializer(read_only=True, many=True) - vlan_id = serializers.IntegerField(source='type.ip_type.vlan.vlan_id', read_only=True) + vlan_id = serializers.IntegerField(source='machine_type.ip_type.vlan.vlan_id', read_only=True) class Meta: model = machines.Interface @@ -865,7 +865,7 @@ class SubnetPortsOpenSerializer(serializers.ModelSerializer): class Meta: model = machines.IpType - fields = ('type', 'domaine_ip_start', 'domaine_ip_stop', 'complete_prefixv6', 'ouverture_ports') + fields = ('name', 'domaine_ip_start', 'domaine_ip_stop', 'complete_prefixv6', 'ouverture_ports') class InterfacePortsOpenSerializer(serializers.ModelSerializer): @@ -1080,7 +1080,7 @@ class DNSReverseZonesSerializer(serializers.ModelSerializer): class Meta: model = machines.IpType - fields = ('type', 'extension', 'soa', 'ns_records', 'mx_records', + fields = ('name', 'extension', 'soa', 'ns_records', 'mx_records', 'txt_records', 'ptr_records', 'ptr_v6_records', 'cidrs', 'prefix_v6', 'prefix_v6_length') diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index 54364dc1..7245013e 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -148,7 +148,7 @@ def authorize(data): # Toutes les reuquètes non proxifiées nas_type = None if nas_instance: - nas_type = Nas.objects.filter(nas_type=nas_instance.type).first() + nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first() if not nas_type or nas_type.port_access_mode == '802.1X': user = data.get('User-Name', '').decode('utf-8', errors='replace') user = user.split('@', 1)[0] @@ -193,7 +193,7 @@ def post_auth(data): if not nas_instance: logger.info(u"Requete proxifiee, nas inconnu".encode('utf-8')) return radiusd.RLM_MODULE_OK - nas_type = Nas.objects.filter(nas_type=nas_instance.type).first() + nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first() if not nas_type: logger.info( u"Type de nas non enregistre dans la bdd!".encode('utf-8') @@ -280,7 +280,7 @@ def find_nas_from_request(nas_id): Q(domain=Domain.objects.filter(name=nas_id)) | Q(ipv4=IpList.objects.filter(ipv4=nas_id)) ) - .select_related('type') + .select_related('machine_type') .select_related('machine__switch__stack')) return nas.first() @@ -531,7 +531,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, # Si on choisi de placer les machines sur le vlan # correspondant à leur type : if RadiusOption.get_cached_value('radius_general_policy') == 'MACHINE': - DECISION_VLAN = interface.type.ip_type.vlan.vlan_id + DECISION_VLAN = interface.machine_type.ip_type.vlan.vlan_id if not interface.ipv4: interface.assign_ipv4() return ( diff --git a/machines/admin.py b/machines/admin.py index bafebb80..099fa1ba 100644 --- a/machines/admin.py +++ b/machines/admin.py @@ -136,7 +136,7 @@ class OuverturePortListAdmin(VersionAdmin): class InterfaceAdmin(VersionAdmin): """ Admin view of a Interface object """ - list_display = ('machine', 'type', 'mac_address', 'ipv4', 'details') + list_display = ('machine', 'machine_type', 'mac_address', 'ipv4', 'details') class DomainAdmin(VersionAdmin): diff --git a/machines/forms.py b/machines/forms.py index 94b9293a..af05a48e 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -90,15 +90,15 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class Meta: model = Interface - fields = ['machine', 'type', 'ipv4', 'mac_address', 'details'] + fields = ['machine', 'machine_type', 'ipv4', 'mac_address', 'details'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) user = kwargs.get('user') super(EditInterfaceForm, self).__init__(*args, prefix=prefix, **kwargs) self.fields['mac_address'].label = _("MAC address") - self.fields['type'].label = _("Machine type") - self.fields['type'].empty_label = _("Select a machine type") + self.fields['machine_type'].label = _("Machine type") + self.fields['machine_type'].empty_label = _("Select a machine type") if "ipv4" in self.fields: self.fields['ipv4'].empty_label = _("Automatic IPv4 assignment") self.fields['ipv4'].queryset = IpList.objects.filter( @@ -122,7 +122,7 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): .select_related('user') can_use_all_machinetype, _reason = MachineType.can_use_all(user) if not can_use_all_machinetype: - self.fields['type'].queryset = MachineType.objects.filter( + self.fields['machine_type'].queryset = MachineType.objects.filter( ip_type__in=IpType.objects.filter(need_infra=False) ) @@ -132,7 +132,7 @@ class AddInterfaceForm(EditInterfaceForm): affiche ou non l'ensemble des ip disponibles""" class Meta(EditInterfaceForm.Meta): - fields = ['type', 'ipv4', 'mac_address', 'details'] + fields = ['machine_type', 'ipv4', 'mac_address', 'details'] class AliasForm(FormRevMixin, ModelForm): @@ -191,12 +191,12 @@ class MachineTypeForm(FormRevMixin, ModelForm): class Meta: model = MachineType - fields = ['type', 'ip_type'] + fields = ['name', 'ip_type'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(MachineTypeForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['type'].label = _("Machine type to add") + self.fields['name'].label = _("Machine type to add") self.fields['ip_type'].label = _("Related IP type") @@ -228,7 +228,7 @@ class IpTypeForm(FormRevMixin, ModelForm): 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 = _("IP type to add") + self.fields['name'].label = _("IP type to add") class EditIpTypeForm(IpTypeForm): @@ -236,7 +236,7 @@ class EditIpTypeForm(IpTypeForm): synchroniser les objets iplist""" class Meta(IpTypeForm.Meta): - fields = ['extension', 'type', 'need_infra', 'domaine_ip_network', 'domaine_ip_netmask', + fields = ['extension', 'name', 'need_infra', 'domaine_ip_network', 'domaine_ip_netmask', 'prefix_v6', 'prefix_v6_length', 'vlan', 'reverse_v4', 'reverse_v6', 'ouverture_ports'] diff --git a/machines/migrations/0102_auto_20190303_1611.py b/machines/migrations/0102_auto_20190303_1611.py new file mode 100644 index 00000000..3531fb11 --- /dev/null +++ b/machines/migrations/0102_auto_20190303_1611.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-03-03 15:11 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0101_auto_20190108_1623'), + ] + + operations = [ + migrations.RenameField( + model_name='interface', + old_name='type', + new_name='machine_type', + ), + migrations.RenameField( + model_name='iptype', + old_name='type', + new_name='name', + ), + migrations.RenameField( + model_name='machinetype', + old_name='type', + new_name='name', + ), + ] diff --git a/machines/models.py b/machines/models.py index 75da1317..a1ab5b6c 100644 --- a/machines/models.py +++ b/machines/models.py @@ -241,7 +241,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): class MachineType(RevMixin, AclMixin, models.Model): """ Type de machine, relié à un type d'ip, affecté aux interfaces""" - type = models.CharField(max_length=255) + name = models.CharField(max_length=255) ip_type = models.ForeignKey( 'IpType', on_delete=models.PROTECT, @@ -260,7 +260,7 @@ class MachineType(RevMixin, AclMixin, models.Model): def all_interfaces(self): """ Renvoie toutes les interfaces (cartes réseaux) de type machinetype""" - return Interface.objects.filter(type=self) + return Interface.objects.filter(machine_type=self) @staticmethod def can_use_all(user_request, *_args, **_kwargs): @@ -278,12 +278,12 @@ class MachineType(RevMixin, AclMixin, models.Model): return True, None def __str__(self): - return self.type + return self.name class IpType(RevMixin, AclMixin, models.Model): """ Type d'ip, définissant un range d'ip, affecté aux machine types""" - type = models.CharField(max_length=255) + name = models.CharField(max_length=255) extension = models.ForeignKey('Extension', on_delete=models.PROTECT) need_infra = models.BooleanField(default=False) domaine_ip_start = models.GenericIPAddressField(protocol='IPv4') @@ -456,7 +456,7 @@ class IpType(RevMixin, AclMixin, models.Model): else: for ipv6 in Ipv6List.objects.filter( interface__in=Interface.objects.filter( - type__in=MachineType.objects.filter(ip_type=self) + machine_type__in=MachineType.objects.filter(ip_type=self) ) ): ipv6.check_and_replace_prefix(prefix=self.prefix_v6) @@ -465,7 +465,7 @@ class IpType(RevMixin, AclMixin, models.Model): from re2o.utils import all_active_assigned_interfaces if self.reverse_v4: return (all_active_assigned_interfaces() - .filter(type__ip_type=self) + .filter(machine_type__ip_type=self) .filter(ipv4__isnull=False)) else: return None @@ -474,7 +474,7 @@ class IpType(RevMixin, AclMixin, models.Model): from re2o.utils import all_active_interfaces if self.reverse_v6: return (all_active_interfaces(full=True) - .filter(type__ip_type=self)) + .filter(machine_type__ip_type=self)) else: return None @@ -519,7 +519,7 @@ class IpType(RevMixin, AclMixin, models.Model): return user_request.has_perm('machines.use_all_iptype'), None def __str__(self): - return self.type + return self.name class Vlan(RevMixin, AclMixin, models.Model): @@ -724,19 +724,19 @@ class Extension(RevMixin, AclMixin, models.Model): def get_associated_sshfp_records(self): from re2o.utils import all_active_assigned_interfaces return (all_active_assigned_interfaces() - .filter(type__ip_type__extension=self) + .filter(machine_type__ip_type__extension=self) .filter(machine__id__in=SshFp.objects.values('machine'))) def get_associated_a_records(self): from re2o.utils import all_active_assigned_interfaces return (all_active_assigned_interfaces() - .filter(type__ip_type__extension=self) + .filter(machine_type__ip_type__extension=self) .filter(ipv4__isnull=False)) def get_associated_aaaa_records(self): from re2o.utils import all_active_interfaces return (all_active_interfaces(full=True) - .filter(type__ip_type__extension=self)) + .filter(machine_type__ip_type__extension=self)) def get_associated_cname_records(self): from re2o.utils import all_active_assigned_interfaces @@ -1003,7 +1003,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ) mac_address = MACAddressField(integer=False) machine = models.ForeignKey('Machine', on_delete=models.CASCADE) - type = models.ForeignKey('MachineType', on_delete=models.PROTECT) + machine_type = models.ForeignKey('MachineType', on_delete=models.PROTECT) details = models.CharField(max_length=255, blank=True) port_lists = models.ManyToManyField('OuverturePortList', blank=True) @@ -1027,9 +1027,9 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): def ipv6_slaac(self): """ Renvoie un objet type ipv6 à partir du prefix associé à l'iptype parent""" - if self.type.ip_type.prefix_v6: + if self.machine_type.ip_type.prefix_v6: return EUI(self.mac_address).ipv6( - IPNetwork(self.type.ip_type.prefix_v6).network + IPNetwork(self.machine_type.ip_type.prefix_v6).network ) else: return None @@ -1037,7 +1037,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): @cached_property def gen_ipv6_dhcpv6(self): """Cree une ip, à assigner avec dhcpv6 sur une machine""" - prefix_v6 = self.type.ip_type.prefix_v6.encode().decode('utf-8') + prefix_v6 = self.machine_type.ip_type.prefix_v6.encode().decode('utf-8') if not prefix_v6: return None return IPv6Address( @@ -1122,7 +1122,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): def assign_ipv4(self): """ Assigne une ip à l'interface """ - free_ips = self.type.ip_type.free_ip() + free_ips = self.machine_type.ip_type.free_ip() if free_ips: self.ipv4 = free_ips[0] else: @@ -1162,16 +1162,16 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): # instance. # But in our case, it's impossible to create a type value so we raise # the error. - if not hasattr(self, 'type'): + if not hasattr(self, 'machine_type'): raise ValidationError(_("The selected IP type is invalid.")) self.filter_macaddress() - if not self.ipv4 or self.type.ip_type != self.ipv4.ip_type: + if not self.ipv4 or self.machine_type.ip_type != self.ipv4.ip_type: self.assign_ipv4() super(Interface, self).clean(*args, **kwargs) def validate_unique(self, *args, **kwargs): super(Interface, self).validate_unique(*args, **kwargs) - interfaces_similar = Interface.objects.filter(mac_address=self.mac_address, type__ip_type=self.type.ip_type) + interfaces_similar = Interface.objects.filter(mac_address=self.mac_address, machine_type__ip_type=self.machine_type.ip_type) if interfaces_similar and interfaces_similar.first() != self: raise ValidationError(_("Mac address already registered in this Machine Type/Subnet")) @@ -1179,7 +1179,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): self.filter_macaddress() # On verifie la cohérence en forçant l'extension par la méthode if self.ipv4: - if self.type.ip_type != self.ipv4.ip_type: + if self.machine_type.ip_type != self.ipv4.ip_type: raise ValidationError(_("The IPv4 address and the machine type" " don't match.")) self.validate_unique() @@ -1381,7 +1381,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): def check_and_replace_prefix(self, prefix=None): """Si le prefixe v6 est incorrect, on maj l'ipv6""" - prefix_v6 = prefix or self.interface.type.ip_type.prefix_v6.encode().decode('utf-8') + prefix_v6 = prefix or self.interface.machine_type.ip_type.prefix_v6.encode().decode('utf-8') if not prefix_v6: return if (IPv6Address(self.ipv6.encode().decode('utf-8')).exploded[:20] != @@ -1398,7 +1398,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): .exclude(id=self.id)): raise ValidationError(_("A SLAAC IP address is already registered.")) try: - prefix_v6 = self.interface.type.ip_type.prefix_v6.encode().decode('utf-8') + prefix_v6 = self.interface.machine_type.ip_type.prefix_v6.encode().decode('utf-8') except AttributeError: # Prevents from crashing when there is no defined prefix_v6 prefix_v6 = None if prefix_v6: @@ -1453,7 +1453,7 @@ class Domain(RevMixin, AclMixin, models.Model): """ Retourne l'extension de l'interface parente si c'est un A Retourne l'extension propre si c'est un cname, renvoie None sinon""" if self.interface_parent: - return self.interface_parent.type.ip_type.extension + return self.interface_parent.machine_type.ip_type.extension elif hasattr(self, 'extension'): return self.extension else: diff --git a/machines/templates/machines/aff_iptype.html b/machines/templates/machines/aff_iptype.html index c30c0c73..08372a7d 100644 --- a/machines/templates/machines/aff_iptype.html +++ b/machines/templates/machines/aff_iptype.html @@ -45,7 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% for type in iptype_list %} - {{ type.type }} + {{ type.name }} {{ type.extension }} {{ type.need_infra|tick }} {{ type.domaine_ip_start }}-{{ type.domaine_ip_stop }}{% if type.ip_network %} on diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html index 6001f7ce..c444b78b 100644 --- a/machines/templates/machines/aff_machines.html +++ b/machines/templates/machines/aff_machines.html @@ -88,7 +88,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% endif %} - {{ interface.type }} + {{ interface.machine_type }} {{ interface.mac_address }} diff --git a/machines/templates/machines/aff_machinetype.html b/machines/templates/machines/aff_machinetype.html index ebd77b4f..d80044bb 100644 --- a/machines/templates/machines/aff_machinetype.html +++ b/machines/templates/machines/aff_machinetype.html @@ -36,7 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% for type in machinetype_list %} - {{ type.type }} + {{ type.name }} {{ type.ip_type }} {% can_edit type %} diff --git a/machines/views.py b/machines/views.py index 59d4bd5a..bdbb1a83 100644 --- a/machines/views.py +++ b/machines/views.py @@ -144,7 +144,7 @@ def f_type_id(is_type_tt): """ The id that will be used in HTML to store the value of the field type. Depends on the fact that type is generate using typeahead or not """ - return 'id_Interface-type_hidden' if is_type_tt else 'id_Interface-type' + return 'id_Interface-machine_type_hidden' if is_type_tt else 'id_Interface-machine_type' def generate_ipv4_choices(form_obj): @@ -170,7 +170,7 @@ def generate_ipv4_choices(form_obj): v=ip.ipv4 ) - for t in form_obj.fields['type'].queryset.exclude(id__in=used_mtype_id): + for t in form_obj.fields['machine_type'].queryset.exclude(id__in=used_mtype_id): choices += '], "' + str(t.id) + '": [' choices += '{key: "", value: "' + str(f_ipv4.empty_label) + '"},' choices += ']}' @@ -184,11 +184,11 @@ def generate_ipv4_engine(is_type_tt): 'new Bloodhound( {{' 'datumTokenizer: Bloodhound.tokenizers.obj.whitespace( "value" ),' 'queryTokenizer: Bloodhound.tokenizers.whitespace,' - 'local: choices_ipv4[ $( "#{type_id}" ).val() ],' + 'local: choices_ipv4[ $( "#{machine_type_id}" ).val() ],' 'identify: function( obj ) {{ return obj.key; }}' '}} )' ).format( - type_id=f_type_id(is_type_tt) + machine_type_id=f_type_id(is_type_tt) ) @@ -198,7 +198,7 @@ def generate_ipv4_match_func(is_type_tt): return ( 'function(q, sync) {{' 'if (q === "") {{' - 'var first = choices_ipv4[$("#{type_id}").val()].slice(0, 5);' + 'var first = choices_ipv4[$("#{machine_type_id}").val()].slice(0, 5);' 'first = first.map( function (obj) {{ return obj.key; }} );' 'sync(engine_ipv4.get(first));' '}} else {{' @@ -206,7 +206,7 @@ def generate_ipv4_match_func(is_type_tt): '}}' '}}' ).format( - type_id=f_type_id(is_type_tt) + machine_type_id=f_type_id(is_type_tt) ) @@ -1388,7 +1388,7 @@ def index(request): .prefetch_related('interface_set__domain__extension') .prefetch_related('interface_set__ipv4__ip_type') .prefetch_related( - 'interface_set__type__ip_type__extension' + 'interface_set__machine_type__ip_type__extension' ).prefetch_related( 'interface_set__domain__related_domain__extension' ).prefetch_related('interface_set__ipv6list')) @@ -1417,7 +1417,7 @@ def index_iptype(request): iptype_list = (IpType.objects .select_related('extension') .select_related('vlan') - .order_by('type')) + .order_by('name')) return render( request, 'machines/index_iptype.html', @@ -1443,7 +1443,7 @@ def index_machinetype(request): """ View displaying the list of existing types of machines """ machinetype_list = (MachineType.objects .select_related('ip_type') - .order_by('type')) + .order_by('name')) return render( request, 'machines/index_machinetype.html', diff --git a/re2o/utils.py b/re2o/utils.py index 20218a81..ca8bce43 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -126,7 +126,7 @@ def filter_active_interfaces(interface_set): ).filter(active=True) ).select_related('domain') .select_related('machine') - .select_related('type') + .select_related('machine_type') .select_related('ipv4') .select_related('domain__extension') .select_related('ipv4__ip_type') diff --git a/topologie/models.py b/topologie/models.py index 82a9c6a8..61448a79 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -300,7 +300,7 @@ class Switch(AclMixin, Machine): It must the the management interface for that device""" switch_iptype = OptionalTopologie.get_cached_value('switchs_ip_type') if switch_iptype: - return self.interface_set.filter(type__ip_type=switch_iptype).first() + return self.interface_set.filter(machine_type__ip_type=switch_iptype).first() return self.interface_set.first() @cached_property diff --git a/users/views.py b/users/views.py index ea22359a..eac93790 100644 --- a/users/views.py +++ b/users/views.py @@ -965,7 +965,7 @@ def profil(request, users, **_kwargs): machines = Machine.objects.filter(user=users).select_related('user')\ .prefetch_related('interface_set__domain__extension')\ .prefetch_related('interface_set__ipv4__ip_type__extension')\ - .prefetch_related('interface_set__type')\ + .prefetch_related('interface_set__machine_type')\ .prefetch_related('interface_set__domain__related_domain__extension') machines = SortTable.sort( machines, From 706903f8c99769cfff681fd689a663ce683fb4ba Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 17 Mar 2019 03:00:28 +0100 Subject: [PATCH 015/228] Add new full_archive state for user --- logs/views.py | 12 ++++- users/migrations/0081_auto_20190317_0302.py | 20 +++++++++ users/models.py | 49 +++++++++++++++------ users/templates/users/profil.html | 2 + 4 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 users/migrations/0081_auto_20190317_0302.py diff --git a/logs/views.py b/logs/views.py index a54edd56..9d047f07 100644 --- a/logs/views.py +++ b/logs/views.py @@ -104,8 +104,8 @@ from re2o.utils import ( all_adherent, all_active_assigned_interfaces_count, all_active_interfaces_count, -) -from re2o.base import ( +) +from re2o.base import ( re2o_paginator, SortTable ) @@ -257,6 +257,14 @@ def stats_general(request): .count()), Club.objects.filter(state=Club.STATE_ARCHIVE).count() ], + 'full_archive_users': [ + _("Full Archived users"), + User.objects.filter(state=User.STATE_FULL_ARCHIVE).count(), + (Adherent.objects + .filter(state=Adherent.STATE_FULL_ARCHIVE) + .count()), + Club.objects.filter(state=Club.STATE_FULL_ARCHIVE).count() + ], 'not_active_users': [ _("Not yet active users"), User.objects.filter(state=User.STATE_NOT_YET_ACTIVE).count(), diff --git a/users/migrations/0081_auto_20190317_0302.py b/users/migrations/0081_auto_20190317_0302.py new file mode 100644 index 00000000..d17085be --- /dev/null +++ b/users/migrations/0081_auto_20190317_0302.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-03-17 02:02 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0080_auto_20190108_1726'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='state', + field=models.IntegerField(choices=[(0, 'Active'), (1, 'Disabled'), (2, 'Archived'), (3, 'Not yet active'), (4, 'Full Archived')], default=3), + ), + ] diff --git a/users/models.py b/users/models.py index c1d0789a..d8a19da5 100755 --- a/users/models.py +++ b/users/models.py @@ -188,11 +188,13 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, STATE_DISABLED = 1 STATE_ARCHIVE = 2 STATE_NOT_YET_ACTIVE = 3 + STATE_FULL_ARCHIVE = 4 STATES = ( (0, _("Active")), (1, _("Disabled")), (2, _("Archived")), (3, _("Not yet active")), + (4, _("Full Archived")), ) surname = models.CharField(max_length=255) @@ -335,11 +337,17 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, return self.state == self.STATE_ACTIVE or self.state == self.STATE_NOT_YET_ACTIVE def set_active(self): - """Enable this user if he subscribed successfully one time before""" + """Enable this user if he subscribed successfully one time before + Reenable it if it was archived + Do nothing if disabed""" if self.state == self.STATE_NOT_YET_ACTIVE: if self.facture_set.filter(valid=True).filter(Q(vente__type_cotisation='All') | Q(vente__type_cotisation='Adhesion')).exists() or OptionalUser.get_cached_value('all_users_active'): self.state = self.STATE_ACTIVE self.save() + if self.state == self.STATE_ARCHIVE or self.state == self.STATE_FULL_ARCHIVE: + self.state = self.STATE_ACTIVE + self.unarchive() + self.save() @property def is_staff(self): @@ -519,12 +527,17 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, )['total'] or 0 return somme_credit - somme_debit - def user_interfaces(self, active=True): + def user_interfaces(self, active=True, all_interfaces=False): """ Renvoie toutes les interfaces dont les machines appartiennent à self. Par defaut ne prend que les interfaces actives""" - return Interface.objects.filter( - machine__in=Machine.objects.filter(user=self, active=active) - ).select_related('domain__extension') + if all_interfaces: + return Interface.objects.filter( + machine__in=Machine.objects.filter(user=self) + ).select_related('domain__extension') + else: + return Interface.objects.filter( + machine__in=Machine.objects.filter(user=self, active=active) + ).select_related('domain__extension') def assign_ips(self): """ Assign une ipv4 aux machines d'un user """ @@ -547,25 +560,37 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def disable_email(self): """Disable email account and redirection""" - self.email = "" self.local_email_enabled = False self.local_email_redirect = False + def delete_data(self): + """This user will be completely archived, so only keep mandatory data""" + self.disabled_email() + self.user_interfaces(all_interfaces=True).delete() + self.ldap_del() + def archive(self): """ Filling the user; no more active""" self.unassign_ips() - self.disable_email() + + def full_archive(self): + """Full Archive = Archive + Service access complete deletion""" + self.archive() + self.delete_data() def unarchive(self): """Unfilling the user""" self.assign_ips() + self.ldap_sync() def state_sync(self): """Archive, or unarchive, if the user was not active/or archived before""" - if self.__original_state != self.STATE_ACTIVE and self.state == self.STATE_ACTIVE: + if self.__original_state != self.STATE_ACTIVE and self.state == self.STATE_ACTIVE: self.unarchive() elif self.__original_state != self.STATE_ARCHIVE and self.state == self.STATE_ARCHIVE: self.archive() + elif self.__original_state != self.STATE_FULL_ARCHIVE and self.state == self.STATE_FULL_ARCHIVE: + self.full_archive() def ldap_sync(self, base=True, access_refresh=True, mac_refresh=True, group_refresh=False): @@ -578,15 +603,11 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, mac_refresh : synchronise les machines de l'user group_refresh : synchronise les group de l'user Si l'instance n'existe pas, on crée le ldapuser correspondant""" - if sys.version_info[0] >= 3 and self.state != self.STATE_ARCHIVE and\ - self.state != self.STATE_DISABLED: + if sys.version_info[0] >= 3 and (self.state == self.STATE_ACTIVE or self.state == self.STATE_ARCHIVE or self.state == self.STATE_DISABLED): self.refresh_from_db() try: user_ldap = LdapUser.objects.get(uidNumber=self.uid_number) except LdapUser.DoesNotExist: - # Freshly created users are NOT synced in ldap base - if self.state == self.STATE_NOT_YET_ACTIVE: - return user_ldap = LdapUser(uidNumber=self.uid_number) base = True access_refresh = True @@ -1025,7 +1046,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, .filter(local_part=self.pseudo.lower()).exclude(user_id=self.id) ): raise ValidationError(_("This username is already used.")) - if not self.local_email_enabled and not self.email and not (self.state == self.STATE_ARCHIVE): + if not self.local_email_enabled and not self.email and not (self.state == self.STATE_FULL_ARCHIVE): raise ValidationError(_("There is neither a local email address nor an external" " email address for this user.") ) diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index 7361d2b7..52a214a6 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -253,6 +253,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Archived" %}
{% elif users.state == 3 %}
{% trans "Not yet member" %}
+ {% elif users.state == 4 %} +
{% trans "Full Archived" %}
{% endif %}
From e0194ba4e3b46279f5691cf7fed79b72d2556d96 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 17 Mar 2019 04:46:55 +0100 Subject: [PATCH 016/228] Fonctions mass_achivage pour objects multiples --- machines/models.py | 17 +++++++++++ users/forms.py | 5 ++++ users/models.py | 74 ++++++++++++++++++++++++++++++++++------------ users/views.py | 34 +++++++++++---------- 4 files changed, 95 insertions(+), 35 deletions(-) diff --git a/machines/models.py b/machines/models.py index a1ab5b6c..c16e57a6 100644 --- a/machines/models.py +++ b/machines/models.py @@ -41,6 +41,8 @@ from django.db.models.signals import post_save, post_delete from django.dispatch import receiver from django.forms import ValidationError from django.utils import timezone +from django.db import transaction +from reversion import revisions as reversion from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from macaddress.fields import MACAddressField, default_dialect @@ -1134,6 +1136,21 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): """ Sans commentaire, désassigne une ipv4""" self.ipv4 = None + @classmethod + def mass_unassign_ipv4(cls, interface_list): + """Unassign ipv4 to multiple interfaces""" + with transaction.atomic(), reversion.create_revision(): + interface_list.update(ipv4=None) + reversion.set_comment(_("IPv4 unassigning")) + + @classmethod + def mass_assign_ipv4(cls, interface_list): + for interface in interface_list: + with transaction.atomic(), reversion.create_revision(): + interface.assign_ipv4() + interface.save() + reversion.set_comment(_("IPv4 assigning")) + def update_type(self): """ Lorsque le machinetype est changé de type d'ip, on réassigne""" self.clean() diff --git a/users/forms.py b/users/forms.py index 6fcfea81..582b2f97 100644 --- a/users/forms.py +++ b/users/forms.py @@ -297,6 +297,11 @@ class MassArchiveForm(forms.Form): du formulaire la date de depart avant laquelle archiver les users""" date = forms.DateTimeField(help_text='%d/%m/%y') + full_archive = forms.BooleanField( + label=_("Make a full archive operation ? (WARNING : CRITICAL OPERATION IF TRUE)"), + initial=False, + required=False + ) def clean(self): cleaned_data = super(MassArchiveForm, self).clean() diff --git a/users/models.py b/users/models.py index d8a19da5..2bb7decd 100755 --- a/users/models.py +++ b/users/models.py @@ -527,47 +527,78 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, )['total'] or 0 return somme_credit - somme_debit - def user_interfaces(self, active=True, all_interfaces=False): + @classmethod + def users_interfaces(cls, users, active=True, all_interfaces=False): """ Renvoie toutes les interfaces dont les machines appartiennent à self. Par defaut ne prend que les interfaces actives""" if all_interfaces: return Interface.objects.filter( - machine__in=Machine.objects.filter(user=self) + machine__in=Machine.objects.filter(user__in=users) ).select_related('domain__extension') else: return Interface.objects.filter( - machine__in=Machine.objects.filter(user=self, active=active) + machine__in=Machine.objects.filter(user__in=users, active=active) ).select_related('domain__extension') + def user_interfaces(self, active=True, all_interfaces=False): + """ Renvoie toutes les interfaces dont les machines appartiennent à + self. Par defaut ne prend que les interfaces actives""" + return self.users_interfaces([self], active=active, all_interfaces=all_interfaces) + def assign_ips(self): """ Assign une ipv4 aux machines d'un user """ interfaces = self.user_interfaces() - for interface in interfaces: - if not interface.ipv4: - with transaction.atomic(), reversion.create_revision(): - interface.assign_ipv4() - reversion.set_comment(_("IPv4 assigning")) - interface.save() + with transaction.atomic(), reversion.create_revision(): + Interface.mass_assign_ipv4(interfaces) + reversion.set_comment(_("IPv4 assigning")) def unassign_ips(self): """ Désassigne les ipv4 aux machines de l'user""" interfaces = self.user_interfaces() - for interface in interfaces: - with transaction.atomic(), reversion.create_revision(): - interface.unassign_ipv4() - reversion.set_comment(_("IPv4 unassigning")) - interface.save() + with transaction.atomic(), reversion.create_revision(): + Interface.mass_unassign_ipv4(interfaces) + reversion.set_comment(_("IPv4 unassigning")) + + @classmethod + def mass_unassign_ips(cls, users_list): + interfaces = cls.users_interfaces(users_list) + with transaction.atomic(), reversion.create_revision(): + Interface.mass_unassign_ipv4(interfaces) + reversion.set_comment(_("IPv4 assigning")) + + @classmethod + def mass_disable_email(cls, queryset_users): + """Disable email account and redirection""" + queryset_users.update(local_email_enabled=False) + queryset_users.update(local_email_redirect=False) + + @classmethod + def mass_delete_data(cls, queryset_users): + """This users will be completely archived, so only keep mandatory data""" + cls.mass_disable_email(queryset_users) + Machine.objects.filter(user__in=queryset_users).delete() + cls.ldap_delete_users(queryset_users) def disable_email(self): """Disable email account and redirection""" - self.local_email_enabled = False - self.local_email_redirect = False + self.local_email_enabled=False + self.local_email_redirect=False def delete_data(self): """This user will be completely archived, so only keep mandatory data""" - self.disabled_email() - self.user_interfaces(all_interfaces=True).delete() - self.ldap_del() + self.disable_email() + self.machine_set.all().delete() + + @classmethod + def mass_archive(cls, users_list): + cls.mass_unassign_ips(users_list) + users_list.update(state=User.STATE_ARCHIVE) + + @classmethod + def mass_full_archive(cls, users_list): + cls.mass_unassign_ips(users_list) + cls.mass_delete_data(users_list) + users_list.update(state=User.STATE_FULL_ARCHIVE) def archive(self): """ Filling the user; no more active""" @@ -660,6 +691,11 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, except LdapUser.DoesNotExist: pass + @classmethod + def ldap_delete_users(cls, queryset_users): + """Delete multiple users in ldap""" + LdapUser.objects.filter(name__in=list(queryset_users.values_list('pseudo', flat=True))) + def notif_inscription(self): """ Prend en argument un objet user, envoie un mail de bienvenue """ template = loader.get_template('users/email_welcome') diff --git a/users/views.py b/users/views.py index eac93790..7c8149b5 100644 --- a/users/views.py +++ b/users/views.py @@ -776,26 +776,28 @@ def del_listright(request, instances): @can_change(User, 'state') def mass_archive(request): """ Permet l'archivage massif""" - to_archive_date = MassArchiveForm(request.POST or None) + pagination_number = GeneralOption.get_cached_value('pagination_number') + to_archive_form = MassArchiveForm(request.POST or None) to_archive_list = [] - if to_archive_date.is_valid(): - date = to_archive_date.cleaned_data['date'] - to_archive_list = [user for user in - User.objects.exclude(state=User.STATE_ARCHIVE) - if not user.end_access() - or user.end_access() < date] + if to_archive_form.is_valid(): + date = to_archive_form.cleaned_data['date'] + full_archive = to_archive_form.cleaned_data['full_archive'] + to_archive_list = User.objects.exclude(id__in=all_has_access()).exclude(id__in=all_has_access(search_time=date)).exclude(state=User.STATE_NOT_YET_ACTIVE).exclude(state=User.STATE_FULL_ARCHIVE) + if not full_archive: + to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE) + number_to_archive = to_archive_list.count() if "valider" in request.POST: - for user in to_archive_list: - with transaction.atomic(), reversion.create_revision(): - user.archive() - user.save() - reversion.set_comment(_("Archiving")) - messages.success(request, _("%s users were archived.") % len( - to_archive_list - )) + if full_archive: + User.mass_full_archive(to_archive_list) + else: + User.mass_archive(to_archive_list) + messages.success(request, _("%s users were archived.") % + number_to_archive + ) return redirect(reverse('users:index')) + to_archive_list = re2o_paginator(request, to_archive_list, pagination_number) return form( - {'userform': to_archive_date, 'to_archive_list': to_archive_list}, + {'userform': to_archive_form, 'to_archive_list': to_archive_list}, 'users/mass_archive.html', request ) From 0d0d09bc9f8dffde31e67750d78c92fe9559bb89 Mon Sep 17 00:00:00 2001 From: detraz Date: Sun, 17 Mar 2019 14:53:11 +0100 Subject: [PATCH 017/228] Fix type var rename --- preferences/models.py | 10 +++++----- topologie/models.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/preferences/models.py b/preferences/models.py index 445d7139..610f7cdf 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -256,7 +256,7 @@ class OptionalTopologie(AclMixin, PreferencesModel): """Return the ip of the interface that the switch have to contact to get it's config""" if self.switchs_ip_type: from machines.models import Role, Interface - return Interface.objects.filter(machine__interface__in=Role.interface_for_roletype("switch-conf-server")).filter(type__ip_type=self.switchs_ip_type).first() + return Interface.objects.filter(machine__interface__in=Role.interface_for_roletype("switch-conf-server")).filter(machine_type__ip_type=self.switchs_ip_type).first() else: return None @@ -282,11 +282,11 @@ class OptionalTopologie(AclMixin, PreferencesModel): def return_ips_dict(interfaces): return {'ipv4' : [str(interface.ipv4) for interface in interfaces], 'ipv6' : Ipv6List.objects.filter(interface__in=interfaces).values_list('ipv6', flat=True)} - ntp_servers = Role.all_interfaces_for_roletype("ntp-server").filter(type__ip_type=self.switchs_ip_type) - log_servers = Role.all_interfaces_for_roletype("log-server").filter(type__ip_type=self.switchs_ip_type) - radius_servers = Role.all_interfaces_for_roletype("radius-server").filter(type__ip_type=self.switchs_ip_type) + ntp_servers = Role.all_interfaces_for_roletype("ntp-server").filter(machine_type__ip_type=self.switchs_ip_type) + log_servers = Role.all_interfaces_for_roletype("log-server").filter(machine_type__ip_type=self.switchs_ip_type) + radius_servers = Role.all_interfaces_for_roletype("radius-server").filter(machine_type__ip_type=self.switchs_ip_type) dhcp_servers = Role.all_interfaces_for_roletype("dhcp-server") - dns_recursive_servers = Role.all_interfaces_for_roletype("dns-recursive-server").filter(type__ip_type=self.switchs_ip_type) + dns_recursive_servers = Role.all_interfaces_for_roletype("dns-recursive-server").filter(machine_type__ip_type=self.switchs_ip_type) subnet = None subnet6 = None if self.switchs_ip_type: diff --git a/topologie/models.py b/topologie/models.py index 61448a79..dee8abb3 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -361,12 +361,12 @@ class Switch(AclMixin, Machine): @cached_property def interfaces_subnet(self): """Return dict ip:subnet for all ip of the switch""" - return dict((str(interface.ipv4), interface.type.ip_type.ip_set_full_info) for interface in self.interface_set.all()) + return dict((str(interface.ipv4), interface.machine_type.ip_type.ip_set_full_info) for interface in self.interface_set.all()) @cached_property def interfaces6_subnet(self): """Return dict ip6:subnet for all ipv6 of the switch""" - return dict((str(interface.ipv6().first()), interface.type.ip_type.ip6_set_full_info) for interface in self.interface_set.all()) + return dict((str(interface.ipv6().first()), interface.machine_type.ip_type.ip6_set_full_info) for interface in self.interface_set.all()) @cached_property def list_modules(self): From 9053a752b12a89e4f0c60567a0b22e6c0c740bc7 Mon Sep 17 00:00:00 2001 From: detraz Date: Sun, 17 Mar 2019 15:23:51 +0100 Subject: [PATCH 018/228] New argument on all_adh and all_access including asso --- logs/views.py | 4 ++-- re2o/utils.py | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/logs/views.py b/logs/views.py index 9d047f07..28205063 100644 --- a/logs/views.py +++ b/logs/views.py @@ -217,8 +217,8 @@ def stats_general(request): ).count() ip_dict[ip_range] = [ip_range, ip_range.vlan, all_ip.count(), used_ip, active_ip, all_ip.count()-used_ip] - _all_adherent = all_adherent() - _all_has_access = all_has_access() + _all_adherent = all_adherent(including_asso=False) + _all_has_access = all_has_access(including_asso=False) _all_baned = all_baned() _all_whitelisted = all_whitelisted() _all_active_interfaces_count = all_active_interfaces_count() diff --git a/re2o/utils.py b/re2o/utils.py index ca8bce43..2470cf50 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -44,15 +44,15 @@ from machines.models import Interface, Machine from users.models import Adherent, User, Ban, Whitelist from preferences.models import AssoOption -def all_adherent(search_time=None): +def all_adherent(search_time=None, including_asso=True): """ Fonction renvoyant tous les users adherents. Optimisee pour n'est qu'une seule requete sql Inspecte les factures de l'user et ses cotisation, regarde si elles sont posterieur à now (end_time)""" if search_time is None: search_time = timezone.now() - return User.objects.filter( - facture__in=Facture.objects.filter( + filter_user = ( + Q(facture__in=Facture.objects.filter( vente__in=Vente.objects.filter( Q(type_cotisation='All') | Q(type_cotisation='Adhesion'), cotisation__in=Cotisation.objects.filter( @@ -62,7 +62,12 @@ def all_adherent(search_time=None): ).filter(Q(date_start__lt=search_time) & Q(date_end__gt=search_time)) ) ) - ).distinct() + )) + if including_asso: + asso_user = AssoOption.get_cached_value('utilisateur_asso') + if asso_user: + filter_user |= Q(id=asso_user.id) + return User.objects.filter(filter_user).distinct() def all_baned(search_time=None): @@ -87,7 +92,7 @@ def all_whitelisted(search_time=None): ).distinct() -def all_has_access(search_time=None): +def all_has_access(search_time=None, including_asso=True): """ Return all connected users : active users and whitelisted + asso_user defined in AssoOption pannel ---- @@ -111,9 +116,10 @@ def all_has_access(search_time=None): ) ))) ) - asso_user = AssoOption.get_cached_value('utilisateur_asso') - if asso_user: - filter_user |= Q(id=asso_user.id) + if including_asso: + asso_user = AssoOption.get_cached_value('utilisateur_asso') + if asso_user: + filter_user |= Q(id=asso_user.id) return User.objects.filter(filter_user).distinct() From 6e569566edc19c8e3400e2093cc2cd883df79655 Mon Sep 17 00:00:00 2001 From: detraz Date: Sun, 17 Mar 2019 17:20:11 +0100 Subject: [PATCH 019/228] Avoid lazy eval problems with django queryset --- users/models.py | 10 ++++++++++ users/views.py | 3 +-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/users/models.py b/users/models.py index 2bb7decd..bc959a21 100755 --- a/users/models.py +++ b/users/models.py @@ -591,11 +591,21 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, @classmethod def mass_archive(cls, users_list): + """Mass Archive several users, take a queryset + Copy Queryset to avoid eval problem with queryset update""" + #Force eval of queryset + bool(users_list) + users_list = users_list.all() cls.mass_unassign_ips(users_list) users_list.update(state=User.STATE_ARCHIVE) @classmethod def mass_full_archive(cls, users_list): + """Mass Archive several users, take a queryset + Copy Queryset to avoid eval problem with queryset update""" + #Force eval of queryset + bool(users_list) + users_list = users_list.all() cls.mass_unassign_ips(users_list) cls.mass_delete_data(users_list) users_list.update(state=User.STATE_FULL_ARCHIVE) diff --git a/users/views.py b/users/views.py index 7c8149b5..ad8543b5 100644 --- a/users/views.py +++ b/users/views.py @@ -785,14 +785,13 @@ def mass_archive(request): to_archive_list = User.objects.exclude(id__in=all_has_access()).exclude(id__in=all_has_access(search_time=date)).exclude(state=User.STATE_NOT_YET_ACTIVE).exclude(state=User.STATE_FULL_ARCHIVE) if not full_archive: to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE) - number_to_archive = to_archive_list.count() if "valider" in request.POST: if full_archive: User.mass_full_archive(to_archive_list) else: User.mass_archive(to_archive_list) messages.success(request, _("%s users were archived.") % - number_to_archive + to_archive_list.count() ) return redirect(reverse('users:index')) to_archive_list = re2o_paginator(request, to_archive_list, pagination_number) From 986cdcd90a437e76dac35d7570ed98f682ef95da Mon Sep 17 00:00:00 2001 From: detraz Date: Sun, 17 Mar 2019 17:56:46 +0100 Subject: [PATCH 020/228] Mass delete machine intelligent function --- machines/models.py | 10 ++++++++++ users/models.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/machines/models.py b/machines/models.py index c16e57a6..61834149 100644 --- a/machines/models.py +++ b/machines/models.py @@ -224,6 +224,16 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): """Return a name : user provided name or first interface name""" return self.name or self.short_name + @classmethod + def mass_delete(cls, machine_queryset): + """Mass delete for machine queryset""" + Domain.objects.filter(cname__interface_parent__machine__in=machine_queryset)._raw_delete(machine_queryset.db) + Domain.objects.filter(interface_parent__machine__in=machine_queryset)._raw_delete(machine_queryset.db) + Ipv6List.objects.filter(interface__machine__in=machine_queryset)._raw_delete(machine_queryset.db) + Interface.objects.filter(machine__in=machine_queryset).filter(port_lists__isnull=False).delete() + Interface.objects.filter(machine__in=machine_queryset)._raw_delete(machine_queryset.db) + machine_queryset._raw_delete(machine_queryset.db) + @cached_property def all_complete_names(self): """Renvoie tous les tls complets de la machine""" diff --git a/users/models.py b/users/models.py index bc959a21..c553acf4 100755 --- a/users/models.py +++ b/users/models.py @@ -576,7 +576,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def mass_delete_data(cls, queryset_users): """This users will be completely archived, so only keep mandatory data""" cls.mass_disable_email(queryset_users) - Machine.objects.filter(user__in=queryset_users).delete() + Machine.mass_delete(Machine.objects.filter(user__in=queryset_users)) cls.ldap_delete_users(queryset_users) def disable_email(self): From 857c42c89211eadbe3f77f0535127cbe731e1ff3 Mon Sep 17 00:00:00 2001 From: detraz Date: Sun, 17 Mar 2019 18:03:33 +0100 Subject: [PATCH 021/228] Enable search for full archived state --- search/forms.py | 1 + 1 file changed, 1 insertion(+) diff --git a/search/forms.py b/search/forms.py index a32c8abc..073fac02 100644 --- a/search/forms.py +++ b/search/forms.py @@ -34,6 +34,7 @@ CHOICES_USER = ( ('1', _("Disabled")), ('2', _("Archived")), ('3', _("Not yet active")), + ('4', _("Full archived")), ) CHOICES_AFF = ( From 682803cca4adac6831af9f52fae08756d25b2d81 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 17 Mar 2019 18:14:17 +0100 Subject: [PATCH 022/228] Exclude full archive for home creation --- api/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/views.py b/api/views.py index 3108f9f3..d27b585c 100644 --- a/api/views.py +++ b/api/views.py @@ -455,7 +455,7 @@ class UserViewSet(viewsets.ReadOnlyModelViewSet): class HomeCreationViewSet(viewsets.ReadOnlyModelViewSet): """Exposes infos of `users.models.Users` objects to create homes. """ - queryset = users.User.objects.exclude(Q(state=users.User.STATE_DISABLED) | Q(state=users.User.STATE_NOT_YET_ACTIVE)) + queryset = users.User.objects.exclude(Q(state=users.User.STATE_DISABLED) | Q(state=users.User.STATE_NOT_YET_ACTIVE) | Q(state=users.User.STATE_FULL_ARCHIVE)) serializer_class = serializers.BasicUserSerializer From 2e2c72a9c37b58a79d0d2ba375ea8fef1e5ac1df Mon Sep 17 00:00:00 2001 From: klafyvel Date: Sun, 17 Mar 2019 19:30:30 +0100 Subject: [PATCH 023/228] Delete LDAPUser when full archiving a single user. --- users/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/users/models.py b/users/models.py index c553acf4..59beba1d 100755 --- a/users/models.py +++ b/users/models.py @@ -618,6 +618,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, """Full Archive = Archive + Service access complete deletion""" self.archive() self.delete_data() + LdapUser.objects.filter(name__in=self.pseudo) def unarchive(self): """Unfilling the user""" From f69c88d8fe14546f33ceb1e4e2adbea85a0b5de3 Mon Sep 17 00:00:00 2001 From: klafyvel Date: Sun, 17 Mar 2019 19:36:44 +0100 Subject: [PATCH 024/228] Fix LDAP deletion on single user full archiving. --- users/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/models.py b/users/models.py index 59beba1d..823d1f7f 100755 --- a/users/models.py +++ b/users/models.py @@ -618,7 +618,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, """Full Archive = Archive + Service access complete deletion""" self.archive() self.delete_data() - LdapUser.objects.filter(name__in=self.pseudo) + self.ldap_del() def unarchive(self): """Unfilling the user""" From 458fe2f5050d0341613f2f600e5a4eaa2f712da1 Mon Sep 17 00:00:00 2001 From: Maxime Bombar Date: Mon, 15 Apr 2019 10:00:38 +0200 Subject: [PATCH 025/228] Correct http response status code --- re2o/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/re2o/views.py b/re2o/views.py index 0ff2774b..aa85e997 100644 --- a/re2o/views.py +++ b/re2o/views.py @@ -125,10 +125,10 @@ def contact_page(request): def handler500(request): """The handler view for a 500 error""" - return render(request, 'errors/500.html') + return render(request, 'errors/500.html', status=500) def handler404(request): """The handler view for a 404 error""" - return render(request, 'errors/404.html') + return render(request, 'errors/404.html', status=404) From f4c9ac19cfb47a1c5c35af92f0c2de3441f5f591 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Mon, 15 Apr 2019 09:28:19 +0200 Subject: [PATCH 026/228] Override Django Contrib Auth templates This override Django Contrib Auth templates to make them more integrated with the user site. More precisely the breadcrumb now redirects to the index page rather to the Django Contrib Admin index page. *It also fix a security vulnerability in Re2o.* Without this patch users are able to request for a new password AND the existing login name. So just with access to someone mail, it would be possible to hack into his account. And yes, Re2o implements another password system. But this one is not disabled (see by yourself : https://intranet.crans.org/password_reset/). This also is part of the Aube patch-set for Re2o and one of Aube goal is to drop the custom admin password reset system and use the Django Contrib Auth one. --- templates/registration/password_change_done.html | 13 +++++++++++++ templates/registration/password_change_form.html | 13 +++++++++++++ templates/registration/password_reset_complete.html | 13 +++++++++++++ templates/registration/password_reset_confirm.html | 13 +++++++++++++ templates/registration/password_reset_done.html | 13 +++++++++++++ templates/registration/password_reset_email.html | 13 +++++++++++++ templates/registration/password_reset_form.html | 13 +++++++++++++ 7 files changed, 91 insertions(+) create mode 100644 templates/registration/password_change_done.html create mode 100644 templates/registration/password_change_form.html create mode 100644 templates/registration/password_reset_complete.html create mode 100644 templates/registration/password_reset_confirm.html create mode 100644 templates/registration/password_reset_done.html create mode 100644 templates/registration/password_reset_email.html create mode 100644 templates/registration/password_reset_form.html diff --git a/templates/registration/password_change_done.html b/templates/registration/password_change_done.html new file mode 100644 index 00000000..0e514b53 --- /dev/null +++ b/templates/registration/password_change_done.html @@ -0,0 +1,13 @@ +{% extends "registration/password_change_done.html" %} +{% comment %} +SPDX-License-Identifier: GPL-2.0-or-later + +Copyright © 2019 Alexandre Iooss +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/templates/registration/password_change_form.html b/templates/registration/password_change_form.html new file mode 100644 index 00000000..5524bfa0 --- /dev/null +++ b/templates/registration/password_change_form.html @@ -0,0 +1,13 @@ +{% extends "registration/password_change_form.html" %} +{% comment %} +SPDX-License-Identifier: GPL-2.0-or-later + +Copyright © 2019 Alexandre Iooss +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/templates/registration/password_reset_complete.html b/templates/registration/password_reset_complete.html new file mode 100644 index 00000000..506c0981 --- /dev/null +++ b/templates/registration/password_reset_complete.html @@ -0,0 +1,13 @@ +{% extends "registration/password_reset_complete.html" %} +{% comment %} +SPDX-License-Identifier: GPL-2.0-or-later + +Copyright © 2019 Alexandre Iooss +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/templates/registration/password_reset_confirm.html b/templates/registration/password_reset_confirm.html new file mode 100644 index 00000000..de710a83 --- /dev/null +++ b/templates/registration/password_reset_confirm.html @@ -0,0 +1,13 @@ +{% extends "registration/password_reset_confirm.html" %} +{% comment %} +SPDX-License-Identifier: GPL-2.0-or-later + +Copyright © 2019 Alexandre Iooss +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/templates/registration/password_reset_done.html b/templates/registration/password_reset_done.html new file mode 100644 index 00000000..5e008001 --- /dev/null +++ b/templates/registration/password_reset_done.html @@ -0,0 +1,13 @@ +{% extends "registration/password_reset_done.html" %} +{% comment %} +SPDX-License-Identifier: GPL-2.0-or-later + +Copyright © 2019 Alexandre Iooss +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/templates/registration/password_reset_email.html b/templates/registration/password_reset_email.html new file mode 100644 index 00000000..f43d80c3 --- /dev/null +++ b/templates/registration/password_reset_email.html @@ -0,0 +1,13 @@ +{% load i18n %}{% autoescape off %} +{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %} + +{% trans "Please go to the following page and choose a new password:" %} +{% block reset_link %} +{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} +{% endblock %} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} + +{% endautoescape %} diff --git a/templates/registration/password_reset_form.html b/templates/registration/password_reset_form.html new file mode 100644 index 00000000..26c1e282 --- /dev/null +++ b/templates/registration/password_reset_form.html @@ -0,0 +1,13 @@ +{% extends "registration/password_reset_form.html" %} +{% comment %} +SPDX-License-Identifier: GPL-2.0-or-later + +Copyright © 2019 Alexandre Iooss +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} From 58196cadad6ae69aaa01bfeb28d355517c8e8e20 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Mon, 15 Apr 2019 09:37:33 +0200 Subject: [PATCH 027/228] Redirect Django Contrib Admin login page Without this patch, Re2o has two login screen with different features. This patch redirects `/admin/login/` to the login page. This patch is part of the Aube patchset for Re2o. This helps in the goal to unify the login process and drop the custom login page. --- re2o/urls.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/re2o/urls.py b/re2o/urls.py index 39f51ec3..2e18a863 100644 --- a/re2o/urls.py +++ b/re2o/urls.py @@ -47,6 +47,7 @@ from django.conf import settings from django.conf.urls import include, url from django.contrib import admin from django.contrib.auth import views as auth_views +from django.views.generic import RedirectView from .views import index, about_page, contact_page @@ -74,6 +75,9 @@ urlpatterns = [ r'^preferences/', include('preferences.urls', namespace='preferences') ), + + # manage/login/ is redirected to the non-admin login page + url(r'^manage/login/$', RedirectView.as_view(pattern_name='login')), ] # Add debug_toolbar URLs if activated if 'debug_toolbar' in settings.INSTALLED_APPS: From a7d7cbd261718455d713549f59dc866fbf66ad71 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Mon, 15 Apr 2019 09:43:18 +0200 Subject: [PATCH 028/228] Add a logout confirmation This patch remove the custom rule in router responsible to redirect logout to index page and place a template with pre-translated strings. This is part of Aube patchset for Re2o to unify the login procedure with Django Contrib Auth. --- re2o/urls.py | 2 -- templates/registration/logged_out.html | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 templates/registration/logged_out.html diff --git a/re2o/urls.py b/re2o/urls.py index 2e18a863..fb6fcc6a 100644 --- a/re2o/urls.py +++ b/re2o/urls.py @@ -46,7 +46,6 @@ from __future__ import unicode_literals from django.conf import settings from django.conf.urls import include, url from django.contrib import admin -from django.contrib.auth import views as auth_views from django.views.generic import RedirectView from .views import index, about_page, contact_page @@ -58,7 +57,6 @@ urlpatterns = [ url(r'^$', index, name='index'), url(r'^about/$', about_page, name='about'), url(r'^contact/$', contact_page, name='contact'), - url('^logout/', auth_views.logout, {'next_page': '/'}), url('^', include('django.contrib.auth.urls')), url(r'^i18n/', include('django.conf.urls.i18n')), url(r'^admin/', include(admin.site.urls)), diff --git a/templates/registration/logged_out.html b/templates/registration/logged_out.html new file mode 100644 index 00000000..c3feb15d --- /dev/null +++ b/templates/registration/logged_out.html @@ -0,0 +1,18 @@ +{% extends "registration/logged_out.html" %} +{% comment %} +SPDX-License-Identifier: GPL-2.0-or-later + +Copyright © 2019 Alexandre Iooss +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} + +{% block content %} +

{% trans "Thanks for spending some quality time with the Web site today." %}

+

{% trans 'Log in again' %}

+{% endblock %} From 10c6a268d25d9101b9a29448c5279dd6b720bc91 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Mon, 15 Apr 2019 09:45:08 +0200 Subject: [PATCH 029/228] Add customisation to Django Contrib Admin The default theme of Django Contrib Admin is not really great. This theme the Django Admin with Re2o logo and colors. It also comes with a new dynamic-generated menu to navigate in the admin interface. A new index page override the global index of Django Contrib Admin to prepare for new features. This patch is part of the Aube patchset for Re2o, targeting the use of Django Contrib Admin as a manage interface for active members. --- re2o/urls.py | 5 + static/css/admin.css | 158 ++++++++++++++++++++++++++++++ templates/admin/base_site.html | 91 +++++++++++++++++ templates/admin/custom_index.html | 57 +++++++++++ 4 files changed, 311 insertions(+) create mode 100644 static/css/admin.css create mode 100644 templates/admin/base_site.html create mode 100644 templates/admin/custom_index.html diff --git a/re2o/urls.py b/re2o/urls.py index fb6fcc6a..9c13965b 100644 --- a/re2o/urls.py +++ b/re2o/urls.py @@ -46,10 +46,15 @@ from __future__ import unicode_literals from django.conf import settings from django.conf.urls import include, url from django.contrib import admin +from django.utils.translation import gettext_lazy as _ from django.views.generic import RedirectView from .views import index, about_page, contact_page +# Admin site configuration +admin.site.index_title = _('Homepage') +admin.site.index_template = 'admin/custom_index.html' + handler500 = 're2o.views.handler500' handler404 = 're2o.views.handler404' diff --git a/static/css/admin.css b/static/css/admin.css new file mode 100644 index 00000000..b8888ae4 --- /dev/null +++ b/static/css/admin.css @@ -0,0 +1,158 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright © 2019 Alexandre Iooss + * + * This is the custom style for Django Contrib Admin + */ + +/* Colors */ +#header { + background-color: #222; + border-bottom: solid 3px #f9a01b; +} + +.module h2, .module caption, .inline-group h2 { + background: #e6e0d8; + color: #222; +} + +a.section:link, a.section:visited { + color: #222; +} + +#user-tools a { + border-bottom: none; + font-weight: bold; +} + +div.breadcrumbs { + background: #3c3c3c; +} + +.button, input[type=submit], input[type=button], .submit-row input, a.button { + background: #d8a456; +} + +.button:active, input[type=submit]:active, input[type=button]:active, .button:focus, input[type=submit]:focus, +input[type=button]:focus, .button:hover, input[type=submit]:hover, input[type=button]:hover { + background: #b98d4a; +} + +.button.default, input[type=submit].default, .submit-row input.default { + background: #b98d4a; +} + +.button.default:active, input[type=submit].default:active, .button.default:focus, input[type=submit].default:focus, +.button.default:hover, input[type=submit].default:hover { + background: #a7752b; +} + +/* Image in branding */ +img.banding-logo { + margin-top: -3px; + height: 32px; +} + +/* Navbar menu */ +#nav { + padding: 0; + margin: 0 0 0 20px; + font-weight: 300; + font-size: 11px; + letter-spacing: 0.5px; + text-transform: uppercase; + text-align: left; +} + +#nav a { + border-bottom: none; + font-weight: bold; + display: inline-block; +} + +#nav div.dropdown:hover > a, #nav div.dropdown:focus > a { + text-decoration: none; + color: #79aec8; +} + +#nav a.activated { + text-decoration: underline; +} + +#nav div.dropdown { + position: relative; /* needed to position the dropdown content */ + display: inline-block; +} + +#nav div.dropdown-content { + display: none; + position: absolute; + background-color: #444444; + min-width: 220px; + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); + z-index: 100; +} + +#nav div.dropdown-content a { + color: #fff; + padding: 7px 8px; + text-decoration: none; + display: block; + line-height: 16px; +} + +#nav div.dropdown-content a:hover { + background-color: #636363; +} + +#nav div.dropdown:hover .dropdown-content { + display: block; +} + +/* Fix navigation hidden */ +#header { + overflow: visible; +} + +.login #header { + overflow: hidden; +} + +/* Footer */ +#footer { + padding: 20px 40px; + color: #999; +} + +.login #footer { + padding: 10px; +} + +#footer a { + color: #777; +} + +#footer select { + height: 24px; + padding: 0; +} + +/* Pull footer to bottom */ +#content { + min-height: calc(100vh - 310px); +} + +.login #content { + min-height: 0; +} + +/* Recenter login button */ +.login .submit-row { + padding: 1em 0 0 8.5em !important; +} + +/* Dashboard should take all page */ +.dashboard #content { + width: auto; +} diff --git a/templates/admin/base_site.html b/templates/admin/base_site.html new file mode 100644 index 00000000..ebccdad7 --- /dev/null +++ b/templates/admin/base_site.html @@ -0,0 +1,91 @@ +{% extends "admin/base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-2.0-or-later + +Copyright © 2019 Alexandre Iooss +{% endcomment %} + +{% load i18n staticfiles %} + +{% block title %}{{ title }} | {{ name_website }}{% endblock %} + +{% block branding %} +

+ + + + + {{ name_website }} + +

+{% endblock %} + +{% block nav-global %} + +{% endblock %} + +{% block extrahead %} + {# Favicon with iOS, Android, touchbar support #} + + + + + + + +{% endblock %} + +{% block extrastyle %} + +{% endblock %} + +{% block footer %} + +{% endblock %} diff --git a/templates/admin/custom_index.html b/templates/admin/custom_index.html new file mode 100644 index 00000000..df0a330c --- /dev/null +++ b/templates/admin/custom_index.html @@ -0,0 +1,57 @@ +{% extends "admin/index.html" %} +{% comment %} +SPDX-License-Identifier: GPL-2.0-or-later + +Copyright © 2019 Alexandre Iooss +{% endcomment %} + +{% load i18n static %} + +{% block content_title %} +

{% blocktrans %}Welcome to {{ name_website }}{% endblocktrans %}

+{% endblock %} + +{% block content %} +
+

+ {% blocktrans %}You are on the operator interface. Here you will be able to manage the network and users + from the top left menu. You can also go read the developer documentation.{% endblocktrans %} +

+

+ {% blocktrans %}To go back to the main site, click "View site" button in top right menu.{% endblocktrans %} +

+
+{% endblock %} + +{% block sidebar %} + +{% endblock %} From 831e0c0690a4fa99d46fe4261f9f278691fa7c77 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Sat, 20 Apr 2019 19:24:49 +0200 Subject: [PATCH 030/228] Link to login page when logged out --- templates/registration/logged_out.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/registration/logged_out.html b/templates/registration/logged_out.html index c3feb15d..b700f171 100644 --- a/templates/registration/logged_out.html +++ b/templates/registration/logged_out.html @@ -14,5 +14,5 @@ Copyright © 2019 Alexandre Iooss {% block content %}

{% trans "Thanks for spending some quality time with the Web site today." %}

-

{% trans 'Log in again' %}

+

{% trans 'Log in again' %}

{% endblock %} From e900ce0d0d2653bef504812842192f60621722d1 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Sat, 20 Apr 2019 19:25:24 +0200 Subject: [PATCH 031/228] Fix login screen not being redirected --- re2o/urls.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/re2o/urls.py b/re2o/urls.py index 9c13965b..37497572 100644 --- a/re2o/urls.py +++ b/re2o/urls.py @@ -62,9 +62,7 @@ urlpatterns = [ url(r'^$', index, name='index'), url(r'^about/$', about_page, name='about'), url(r'^contact/$', contact_page, name='contact'), - url('^', include('django.contrib.auth.urls')), url(r'^i18n/', include('django.conf.urls.i18n')), - url(r'^admin/', include(admin.site.urls)), url(r'^users/', include('users.urls', namespace='users')), url(r'^search/', include('search.urls', namespace='search')), url( @@ -79,8 +77,11 @@ urlpatterns = [ include('preferences.urls', namespace='preferences') ), + # Include contrib auth and contrib admin # manage/login/ is redirected to the non-admin login page - url(r'^manage/login/$', RedirectView.as_view(pattern_name='login')), + url(r'^', include('django.contrib.auth.urls')), + url(r'^admin/login/$', RedirectView.as_view(pattern_name='login')), + url(r'^admin/', include(admin.site.urls)), ] # Add debug_toolbar URLs if activated if 'debug_toolbar' in settings.INSTALLED_APPS: From 074b944246c147b15a51a0e42c036aba85d7b17b Mon Sep 17 00:00:00 2001 From: Fardale Date: Wed, 24 Apr 2019 23:36:25 +0200 Subject: [PATCH 032/228] fix crypt password verification function --- re2o/login.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/re2o/login.py b/re2o/login.py index 0b552239..d45fed5a 100644 --- a/re2o/login.py +++ b/re2o/login.py @@ -115,7 +115,7 @@ class CryptPasswordHasher(hashers.BasePasswordHasher): """ assert encoded.startswith(self.algorithm) salt = hash_password_salt(encoded) - return constant_time_compare(crypt.crypt(password, salt), + return constant_time_compare(self.algorithm + crypt.crypt(password, salt), encoded) def safe_summary(self, encoded): From 4a14d6480cce1acc9c85e71dd4b194619393846a Mon Sep 17 00:00:00 2001 From: Fardale Date: Fri, 26 Apr 2019 00:37:07 +0200 Subject: [PATCH 033/228] fix md5 password verification function --- re2o/login.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/re2o/login.py b/re2o/login.py index d45fed5a..9e18f17d 100644 --- a/re2o/login.py +++ b/re2o/login.py @@ -157,9 +157,9 @@ class MD5PasswordHasher(hashers.BasePasswordHasher): """ assert encoded.startswith(self.algorithm) salt = hash_password_salt(encoded) - return constant_time_compare( - b64encode(hashlib.md5(password.encode() + salt).digest() + salt), - encoded.encode()) + return constant_time_compare(self.algorithm + "$" + + b64encode(hashlib.md5(password.encode() + salt).digest() + salt).decode(), + encoded) def safe_summary(self, encoded): """ From 94aca35190fe6e97b761b2765bee8050fe29eec1 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Fri, 12 Jul 2019 18:27:12 +0200 Subject: [PATCH 034/228] [Reminder] Broaden with textfield and unlimited message for customized end_membership --- .../migrations/0060_auto_20190712_1821.py | 20 +++++++++++++++++++ preferences/models.py | 3 +-- 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 preferences/migrations/0060_auto_20190712_1821.py diff --git a/preferences/migrations/0060_auto_20190712_1821.py b/preferences/migrations/0060_auto_20190712_1821.py new file mode 100644 index 00000000..e1eb76e8 --- /dev/null +++ b/preferences/migrations/0060_auto_20190712_1821.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-07-12 16:21 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0059_auto_20190120_1739'), + ] + + operations = [ + migrations.AlterField( + model_name='reminder', + name='message', + field=models.TextField(blank=True, default='', help_text='Message displayed specifically for this reminder', null=True), + ), + ] diff --git a/preferences/models.py b/preferences/models.py index 610f7cdf..be8b8ec2 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -380,8 +380,7 @@ class Reminder(AclMixin, models.Model): unique=True, help_text=_("Delay between the email and the membership's end") ) - message = models.CharField( - max_length=255, + message = models.TextField( default="", null=True, blank=True, From e60196db9b83d428e6b8a1825088397ad54d94c1 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 7 Jul 2019 15:17:53 +0200 Subject: [PATCH 035/228] Fix : Evite le plantage si le montant vaut exactement le minimum --- cotisations/forms.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cotisations/forms.py b/cotisations/forms.py index 3f99382b..39c194ec 100644 --- a/cotisations/forms.py +++ b/cotisations/forms.py @@ -284,8 +284,7 @@ class RechargeForm(FormRevMixin, Form): """ value = forms.DecimalField( label=_("Amount"), - min_value=0.01, - validators=[] + decimal_places=2, ) payment = forms.ModelChoiceField( queryset=Paiement.objects.none(), From a51c5f4b57722bc0a1d7567b6e691475d347ad60 Mon Sep 17 00:00:00 2001 From: chirac Date: Sun, 14 Jul 2019 19:55:53 +0200 Subject: [PATCH 036/228] Fix Article (s) --- cotisations/migrations/0026_auto_20171028_0126.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cotisations/migrations/0026_auto_20171028_0126.py b/cotisations/migrations/0026_auto_20171028_0126.py index df44bb89..41395a94 100644 --- a/cotisations/migrations/0026_auto_20171028_0126.py +++ b/cotisations/migrations/0026_auto_20171028_0126.py @@ -29,7 +29,7 @@ def delete_type(apps, schema_editor): Vente = apps.get_model('cotisations', 'Vente') Article = apps.get_model('cotisations', 'Article') db_alias = schema_editor.connection.alias - articles = Articles.objects.using(db_alias).all() + articles = Article.objects.using(db_alias).all() ventes = Vente.objects.using(db_alias).all() for article in articles: if article.type_cotisation: From 3ec4fdd9d9de31dae87e31a8afc84abe972bc882 Mon Sep 17 00:00:00 2001 From: chirac Date: Sun, 21 Jul 2019 01:02:32 +0200 Subject: [PATCH 037/228] Profile default different for dormitories (option) --- .../migrations/0072_auto_20190720_2318.py | 34 +++++++++++++++++++ topologie/models.py | 20 +++++++++-- .../templates/topologie/aff_port_profile.html | 4 +-- 3 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 topologie/migrations/0072_auto_20190720_2318.py diff --git a/topologie/migrations/0072_auto_20190720_2318.py b/topologie/migrations/0072_auto_20190720_2318.py new file mode 100644 index 00000000..3c403bfa --- /dev/null +++ b/topologie/migrations/0072_auto_20190720_2318.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-07-20 21:18 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('topologie', '0071_auto_20190218_1936'), + ] + + operations = [ + migrations.AlterModelOptions( + name='room', + options={'ordering': ['building__name'], 'permissions': (('view_room', 'Can view a room object'),), 'verbose_name': 'room', 'verbose_name_plural': 'rooms'}, + ), + migrations.AddField( + model_name='portprofile', + name='on_dormitory', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='dormitory_ofprofil', to='topologie.Dormitory', verbose_name='Profil on dormitory'), + ), + migrations.AlterField( + model_name='portprofile', + name='profil_default', + field=models.CharField(blank=True, choices=[('room', 'Room'), ('access_point', 'Access point'), ('uplink', 'Uplink'), ('asso_machine', 'Organisation machine'), ('nothing', 'Nothing')], max_length=32, null=True, verbose_name='Default profile'), + ), + migrations.AlterUniqueTogether( + name='portprofile', + unique_together=set([('on_dormitory', 'profil_default')]), + ), + ] diff --git a/topologie/models.py b/topologie/models.py index dee8abb3..a379e005 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -650,7 +650,7 @@ class Port(AclMixin, RevMixin, models.Model): :returns: the profile of self (port)""" def profile_or_nothing(profile): port_profile = PortProfile.objects.filter( - profil_default=profile).first() + profil_default=profile).filter(switch__switchbay__building__dormitory).first() if port_profile: return port_profile else: @@ -791,9 +791,16 @@ class PortProfile(AclMixin, RevMixin, models.Model): choices=PROFIL_DEFAULT, blank=True, null=True, - unique=True, verbose_name=_("Default profile") ) + on_dormitory = models.ForeignKey( + 'topologie.Dormitory', + related_name='dormitory_ofprofil', + on_delete=models.SET_NULL, + blank=True, + null=True, + verbose_name=_("Profil on dormitory") + ) vlan_untagged = models.ForeignKey( 'machines.Vlan', related_name='vlan_untagged', @@ -871,6 +878,7 @@ class PortProfile(AclMixin, RevMixin, models.Model): ) verbose_name = _("port profile") verbose_name_plural = _("port profiles") + unique_together = ['on_dormitory', 'profil_default'] security_parameters_fields = [ 'loop_protect', @@ -893,6 +901,14 @@ class PortProfile(AclMixin, RevMixin, models.Model): def security_parameters_as_str(self): return ','.join(self.security_parameters_enabled) + def clean(self): + """ Check that there is only one generic profil default""" + super(PortProfile, self).clean() + if self.profil_default and not self.on_dormitory and PortProfile.objects.exclude(id=self.id).filter(profil_default=self.profil_default).exclude(on_dormitory__isnull=False).exists(): + raise ValidationError( + {'profil_default': _("A default profile for all dormitory of that type already exists.")} + ) + def __str__(self): return self.name diff --git a/topologie/templates/topologie/aff_port_profile.html b/topologie/templates/topologie/aff_port_profile.html index b335904e..4ed8a7b4 100644 --- a/topologie/templates/topologie/aff_port_profile.html +++ b/topologie/templates/topologie/aff_port_profile.html @@ -35,7 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Name" %} - {% trans "Default for" %} + {% trans "Default for and place" %} {% trans "VLANs" %} {% trans "RADIUS settings" %} {% trans "Speed limit" %} @@ -47,7 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% for port_profile in port_profile_list %} {{ port_profile.name }} - {{ port_profile.profil_default }} + {{ port_profile.profil_default }} {% if port_profile.profil_default%} - {% if port_profile.on_dormitory %} on {{ port_profile.on_dormitory }} {% else %} Everywhere {% endif %}{% endif %} {% if port_profile.vlan_untagged %} {% trans "Untagged: " %}{{ port_profile.vlan_untagged }} From 5b112657c9c87795802a99134e7350fc926ae02f Mon Sep 17 00:00:00 2001 From: chirac Date: Sun, 21 Jul 2019 01:25:04 +0200 Subject: [PATCH 038/228] Returns correct port profile --- topologie/models.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/topologie/models.py b/topologie/models.py index a379e005..c01d5b53 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -379,6 +379,14 @@ class Switch(AclMixin, Machine): modules.append((module_of_self.slot, module_of_self.module.reference)) return modules + @cached_property + def get_dormitory(self): + """Returns the dormitory of that switch""" + if self.switchbay: + return self.switchbay.building.dormitory + else: + return None + def __str__(self): return str(self.get_name) @@ -647,10 +655,18 @@ class Port(AclMixin, RevMixin, models.Model): @cached_property def get_port_profile(self): """Return the config profil for this port - :returns: the profile of self (port)""" + :returns: the profile of self (port) + + If is defined a custom profile, returns it + elIf a default profile is defined for its dormitory, returns it + Else, returns the global default profil + If not exists, create a nothing profile""" def profile_or_nothing(profile): - port_profile = PortProfile.objects.filter( - profil_default=profile).filter(switch__switchbay__building__dormitory).first() + if self.switch.get_dormitory: + port_profile = PortProfile.objects.filter( + profil_default=profile).filter(on_dormitory=self.switch.get_dormitory).first() + if not port_profile: + port_profile = PortProfile.objects.filter(profil_default=profile).first() if port_profile: return port_profile else: From 7cc0fd1e66353e14a4326d72568a1e61c32046e4 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sat, 27 Jul 2019 01:53:06 +0200 Subject: [PATCH 039/228] =?UTF-8?q?Mise=20en=20cache=20et=20gestion=20corr?= =?UTF-8?q?ecte=20des=20profile=20de=20port=20par=20r=C3=A9sidence?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- topologie/models.py | 69 ++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/topologie/models.py b/topologie/models.py index c01d5b53..2eaa3364 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -387,6 +387,50 @@ class Switch(AclMixin, Machine): else: return None + @classmethod + def nothing_profile(cls): + """Return default nothing port profile""" + nothing_profile, _created = PortProfile.objects.get_or_create( + profil_default='nothing', + name='nothing', + radius_type='NO' + ) + return nothing_profile + + def profile_type_or_nothing(self, profile_type): + """Return the profile for a profile_type of this switch + + If exists, returns the defined default profile for a profile type on the dormitory which + the switch belongs + + Otherwise, returns the nothing profile""" + profile_queryset = PortProfile.objects.filter(profil_default=profile_type) + if self.get_dormitory: + port_profile = profile_queryset.filter(on_dormitory=self.get_dormitory).first() or profile_queryset.first() + else: + port_profile = profile_queryset.first() + return port_profile or Switch.nothing_profile + + @cached_property + def default_uplink_profile(self): + """Default uplink profile for that switch -- in cache""" + return self.profile_type_or_nothing('uplink') + + @cached_property + def default_access_point_profile(self): + """Default ap profile for that switch -- in cache""" + return self.profile_type_or_nothing('access_point') + + @cached_property + def default_room_profile(self): + """Default room profile for that switch -- in cache""" + return self.profile_type_or_nothing('room') + + @cached_property + def default_asso_machine_profile(self): + """Default asso machine profile for that switch -- in cache""" + return self.profile_type_or_nothing('asso_machine') + def __str__(self): return str(self.get_name) @@ -661,35 +705,20 @@ class Port(AclMixin, RevMixin, models.Model): elIf a default profile is defined for its dormitory, returns it Else, returns the global default profil If not exists, create a nothing profile""" - def profile_or_nothing(profile): - if self.switch.get_dormitory: - port_profile = PortProfile.objects.filter( - profil_default=profile).filter(on_dormitory=self.switch.get_dormitory).first() - if not port_profile: - port_profile = PortProfile.objects.filter(profil_default=profile).first() - if port_profile: - return port_profile - else: - nothing_profile, _created = PortProfile.objects.get_or_create( - profil_default='nothing', - name='nothing', - radius_type='NO' - ) - return nothing_profile if self.custom_profile: return self.custom_profile elif self.related: - return profile_or_nothing('uplink') + return self.switch.default_uplink_profile elif self.machine_interface: if hasattr(self.machine_interface.machine, 'accesspoint'): - return profile_or_nothing('access_point') + return self.switch.default_access_point_profile else: - return profile_or_nothing('asso_machine') + return self.switch.default_asso_machine_profile elif self.room: - return profile_or_nothing('room') + return self.switch.default_room_profile else: - return profile_or_nothing('nothing') + return Switch.nothing_profile @classmethod def get_instance(cls, portid, *_args, **kwargs): From 9882310d61a0ebdd191feb90b2e10e6463779ea2 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sat, 27 Jul 2019 01:55:26 +0200 Subject: [PATCH 040/228] Affichage correct si port profile custom --- topologie/templates/topologie/aff_port.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topologie/templates/topologie/aff_port.html b/topologie/templates/topologie/aff_port.html index 6a02b484..c789694e 100644 --- a/topologie/templates/topologie/aff_port.html +++ b/topologie/templates/topologie/aff_port.html @@ -88,7 +88,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% endif %} - {% if not port.custom_profil %} + {% if not port.custom_profile %} {% trans "Default: " %} {% endif %} {{ port.get_port_profile }} From d8ad882effcb9fd8264f9f75e330d99c7360e43f Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 6 Aug 2019 04:11:17 +0200 Subject: [PATCH 041/228] =?UTF-8?q?xOptimisation=20des=20requ=C3=A8tes=20S?= =?UTF-8?q?QL=20chargement=20des=20switchs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- topologie/views.py | 59 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/topologie/views.py b/topologie/views.py index 201c8eb4..558666c6 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -129,7 +129,9 @@ def index(request): .select_related('ipv4__ip_type__extension') .select_related('domain__extension')) )) - .select_related('stack')) + .select_related('stack') + .select_related('switchbay__building__dormitory') + .select_related('model__constructor')) switch_list = SortTable.sort( switch_list, request.GET.get('col'), @@ -1265,7 +1267,14 @@ def make_machine_graph(): 'head_server': "#1c3777" } } - missing = list(Switch.objects.all()) + missing = list(Switch.objects.prefetch_related(Prefetch( + 'interface_set', + queryset=( + Interface.objects + .select_related('ipv4__ip_type__extension') + .select_related('domain__extension') + ) + ))) detected = [] for building in Building.objects.all(): # Visit all buildings @@ -1279,9 +1288,16 @@ def make_machine_graph(): } ) # Visit all switchs in this building - for switch in Switch.objects.filter(switchbay__building=building): + for switch in Switch.objects.filter(switchbay__building=building).prefetch_related( + Prefetch( + 'interface_set', + queryset=( + Interface.objects + .select_related('ipv4__ip_type__extension') + .select_related('domain__extension') + ))).select_related('switchbay__building').select_related('switchbay__building__dormitory').select_related('model__constructor'): dico['subs'][-1]['switchs'].append({ - 'name': switch.main_interface().domain.name, + 'name': switch.get_name, 'nombre': switch.number, 'model': switch.model, 'id': switch.id, @@ -1289,27 +1305,42 @@ def make_machine_graph(): 'ports': [] }) # visit all ports of this switch and add the switchs linked to it - for port in switch.ports.filter(related__isnull=False): + for port in switch.ports.filter(related__isnull=False).select_related('related__switch'): dico['subs'][-1]['switchs'][-1]['ports'].append({ 'numero': port.port, - 'related': port.related.switch.main_interface().domain.name + 'related': port.related.switch.get_name, }) - for ap in AccessPoint.all_ap_in(building): + for ap in AccessPoint.all_ap_in(building).prefetch_related(Prefetch( + 'interface_set', + queryset=( + Interface.objects + .select_related('ipv4__ip_type__extension') + .select_related('domain__extension') + )) + ): + switch = ap.switch().first() dico['subs'][-1]['bornes'].append({ 'name': ap.short_name, - 'switch': ap.switch()[0].main_interface().domain.name, - 'port': ap.switch()[0].ports.filter( + 'switch': switch.get_name, + 'port': switch.ports.filter( machine_interface__machine=ap - )[0].port + ).first().port }) - for server in Server.all_server_in(building): + for server in Server.all_server_in(building).prefetch_related(Prefetch( + 'interface_set', + queryset=( + Interface.objects + .select_related('ipv4__ip_type__extension') + .select_related('domain__extension') + )) + ): dico['subs'][-1]['machines'].append({ 'name': server.short_name, - 'switch': server.switch()[0].main_interface().domain.name, + 'switch': server.switch().first().get_name, 'port': Port.objects.filter( machine_interface__machine=server - )[0].port + ).first().port }) # While the list of forgotten ones is not empty @@ -1330,7 +1361,7 @@ def make_machine_graph(): switchbay__isnull=True).exclude(ports__related__isnull=False): dico['alone'].append({ 'id': switch.id, - 'name': switch.main_interface().domain.name + 'name': switch.get_name, }) # generate the dot file From 99fd3031430b378990eb86ffb2af7cbd3f3310b6 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 6 Aug 2019 04:20:53 +0200 Subject: [PATCH 042/228] Optimisation chargement des profils de ports --- topologie/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/topologie/views.py b/topologie/views.py index 558666c6..59532b99 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -165,8 +165,10 @@ def index(request): @can_view_all(PortProfile) def index_port_profile(request): pagination_number = GeneralOption.get_cached_value('pagination_number') - port_profile_list = PortProfile.objects.all().select_related( - 'vlan_untagged') + port_profile_list = PortProfile.objects.all()\ + .select_related('vlan_untagged')\ + .select_related('on_dormitory')\ + .prefetch_related('vlan_tagged') port_profile_list = re2o_paginator( request, port_profile_list, pagination_number) vlan_list = Vlan.objects.all().order_by('vlan_id') From 5034c2656ccf5d808726210c98144b7bb9d05e7f Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 6 Aug 2019 04:30:04 +0200 Subject: [PATCH 043/228] Optimisation chargement des modules switchs --- topologie/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/topologie/views.py b/topologie/views.py index 59532b99..c8be33b7 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -339,7 +339,8 @@ def index_model_switch(request): def index_module(request): """Display all modules of switchs""" module_list = ModuleSwitch.objects.all() - modular_switchs = Switch.objects.filter(model__is_modular=True) + modular_switchs = Switch.objects.filter(model__is_modular=True)\ + .select_related('model').prefetch_related('moduleonswitch_set__module') pagination_number = GeneralOption.get_cached_value('pagination_number') module_list = re2o_paginator(request, module_list, pagination_number) return render( From e17b28cae0369df3304136a86d4feef0434a791a Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 6 Aug 2019 17:46:13 +0200 Subject: [PATCH 044/228] Optimise le chargement des chambres --- topologie/models.py | 13 ++++++++----- topologie/views.py | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/topologie/models.py b/topologie/models.py index 2eaa3364..954fa9c4 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -611,16 +611,19 @@ class Building(AclMixin, RevMixin, models.Model): """Returns all ap of the building""" return AccessPoint.all_ap_in(self) - @cached_property - def cached_name(self): - return self.__str__() - - def __str__(self): + def get_name(self): if Dormitory.objects.count() > 1: return self.dormitory.name + " : " + self.name else: return self.name + @cached_property + def cached_name(self): + return self.get_name() + + def __str__(self): + return self.cached_name + class Port(AclMixin, RevMixin, models.Model): """ Definition d'un port. Relié à un switch(foreign_key), diff --git a/topologie/views.py b/topologie/views.py index c8be33b7..9781a7d2 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -217,7 +217,7 @@ def index_port(request, switch, switchid): @can_view_all(Room) def index_room(request): """ Affichage de l'ensemble des chambres""" - room_list = Room.objects + room_list = Room.objects.select_related('building__dormitory') room_list = SortTable.sort( room_list, request.GET.get('col'), From 84cab79d6f784b69a14b28373bede27f3219f80a Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 6 Aug 2019 17:50:27 +0200 Subject: [PATCH 045/228] Optimisation de l'affichage des switchs --- topologie/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topologie/views.py b/topologie/views.py index 9781a7d2..97b430fc 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -310,7 +310,7 @@ def index_physical_grouping(request): @can_view_all(ModelSwitch, ConstructorSwitch) def index_model_switch(request): """ Affichage de l'ensemble des modèles de switches""" - model_switch_list = ModelSwitch.objects.select_related('constructor') + model_switch_list = ModelSwitch.objects.select_related('constructor').prefetch_related('switch_set__interface_set__domain') constructor_switch_list = ConstructorSwitch.objects model_switch_list = SortTable.sort( model_switch_list, From 0794056d19c1dce8cef79a656b47f50e4b05de8d Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 7 Aug 2019 00:08:19 +0200 Subject: [PATCH 046/228] Optimisation chargement des locaux --- topologie/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/topologie/views.py b/topologie/views.py index 97b430fc..01c21cfb 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -267,9 +267,9 @@ def index_physical_grouping(request): .prefetch_related( 'switch_set__interface_set__domain__extension' )) - building_list = Building.objects.all() - dormitory_list = Dormitory.objects.all() - switch_bay_list = SwitchBay.objects.select_related('building') + building_list = Building.objects.all().select_related('dormitory') + dormitory_list = Dormitory.objects.all().prefetch_related('building_set') + switch_bay_list = SwitchBay.objects.select_related('building__dormitory').prefetch_related('switch_set__interface_set__domain') stack_list = SortTable.sort( stack_list, request.GET.get('col'), From 08d9e04a9e38ff5b4eaa5c3ce0c016abb1264efb Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 7 Aug 2019 00:29:21 +0200 Subject: [PATCH 047/228] =?UTF-8?q?Optimisation=20affichage=20d=C3=A9taill?= =?UTF-8?q?=C3=A9=20d'un=20switch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- topologie/views.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/topologie/views.py b/topologie/views.py index 01c21cfb..d3acdff2 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -186,16 +186,18 @@ def index_port(request, switch, switchid): """ Affichage de l'ensemble des ports reliés à un switch particulier""" port_list = (Port.objects .filter(switch=switch) - .select_related('room') + .select_related('room__building__dormitory') .select_related('machine_interface__domain__extension') .select_related('machine_interface__machine__user') - .select_related('related__switch') + .select_related('machine_interface__machine__accesspoint') + .select_related('related__switch__switchbay__building__dormitory') .prefetch_related(Prefetch( 'related__switch__interface_set', queryset=(Interface.objects .select_related('domain__extension')) )) - .select_related('switch')) + .select_related('switch__switchbay__building__dormitory') + .select_related('switch__model__constructor')) port_list = SortTable.sort( port_list, request.GET.get('col'), From 0770da51d1ba9e1739f00df92544e881838e2041 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 7 Aug 2019 00:43:47 +0200 Subject: [PATCH 048/228] Correction de l'affichage des chambres/locaux --- topologie/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topologie/models.py b/topologie/models.py index 954fa9c4..c4e0591b 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -802,7 +802,7 @@ class Room(AclMixin, RevMixin, models.Model): unique_together = ('name', 'building') def __str__(self): - return self.building.cached_name + self.name + return self.building.cached_name + ' ' + self.name class PortProfile(AclMixin, RevMixin, models.Model): From 105348b73aa79908909f183f08e8e45847a7795b Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 7 Aug 2019 00:44:44 +0200 Subject: [PATCH 049/228] =?UTF-8?q?Prechargement=20des=20donn=C3=A9es=20ba?= =?UTF-8?q?timent/r=C3=A9sidences=20pour=20selection=20des=20chambres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- topologie/forms.py | 1 + 1 file changed, 1 insertion(+) diff --git a/topologie/forms.py b/topologie/forms.py index bdc8ba4e..72b499d4 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -93,6 +93,7 @@ class EditPortForm(FormRevMixin, ModelForm): Interface.objects.all().select_related('domain__extension') ) self.fields['related'].queryset = Port.objects.all().prefetch_related('switch__machine_ptr__interface_set__domain__extension') + self.fields['room'].queryset = Room.objects.all().select_related('building__dormitory') class AddPortForm(FormRevMixin, ModelForm): From 3f82adb720ad91e6caae16b23e54bc4b8e59be49 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Wed, 7 Aug 2019 02:09:57 +0200 Subject: [PATCH 050/228] =?UTF-8?q?Mise=20en=20cache=20affichage=20r=C3=A9?= =?UTF-8?q?sidence?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- topologie/models.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/topologie/models.py b/topologie/models.py index c4e0591b..250e52a9 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -42,6 +42,7 @@ import itertools from django.db import models from django.db.models.signals import post_save, post_delete from django.utils.functional import cached_property +from django.core.cache import cache from django.dispatch import receiver from django.core.exceptions import ValidationError from django.db import IntegrityError @@ -586,6 +587,14 @@ class Dormitory(AclMixin, RevMixin, models.Model): """Returns all ap of the dorms""" return AccessPoint.all_ap_in(self.building_set.all()) + @classmethod + def is_multiple_dorms(cls): + multiple_dorms = cache.get('multiple_dorms') + if multiple_dorms: + return multiple_dorms + else: + return cache.get_or_set('multiple_dorms', cls.objects.count() > 1) + def __str__(self): return self.name @@ -612,7 +621,7 @@ class Building(AclMixin, RevMixin, models.Model): return AccessPoint.all_ap_in(self) def get_name(self): - if Dormitory.objects.count() > 1: + if Dormitory.is_multiple_dorms(): return self.dormitory.name + " : " + self.name else: return self.name From fb437dd09612c6e518b0b23b0f62e54b408a0fc6 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sat, 6 Jul 2019 08:25:24 +0000 Subject: [PATCH 051/228] Commit initial start app tickets --- tickets/__init__.py | 0 tickets/admin.py | 3 +++ tickets/apps.py | 5 +++++ tickets/migrations/__init__.py | 0 tickets/models.py | 3 +++ tickets/tests.py | 3 +++ tickets/views.py | 3 +++ 7 files changed, 17 insertions(+) create mode 100644 tickets/__init__.py create mode 100644 tickets/admin.py create mode 100644 tickets/apps.py create mode 100644 tickets/migrations/__init__.py create mode 100644 tickets/models.py create mode 100644 tickets/tests.py create mode 100644 tickets/views.py diff --git a/tickets/__init__.py b/tickets/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tickets/admin.py b/tickets/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/tickets/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/tickets/apps.py b/tickets/apps.py new file mode 100644 index 00000000..3ea742ac --- /dev/null +++ b/tickets/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class TicketsConfig(AppConfig): + name = 'tickets' diff --git a/tickets/migrations/__init__.py b/tickets/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tickets/models.py b/tickets/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/tickets/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/tickets/tests.py b/tickets/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/tickets/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/tickets/views.py b/tickets/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/tickets/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. From f054c0a2af15d8aed66e5860fbfb1e360c1597ec Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sun, 7 Jul 2019 17:09:56 +0000 Subject: [PATCH 052/228] Premiere vue d'affichage des tickets --- re2o/settings.py | 1 + re2o/urls.py | 1 + tickets/forms.py | 27 ++++++++++ tickets/models.py | 34 ++++++++++++- tickets/templates/tickets/aff_tickets.html | 59 ++++++++++++++++++++++ tickets/urls.py | 10 ++++ tickets/views.py | 25 ++++++++- 7 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 tickets/forms.py create mode 100644 tickets/templates/tickets/aff_tickets.html create mode 100644 tickets/urls.py diff --git a/re2o/settings.py b/re2o/settings.py index f2557b44..ce7d3257 100644 --- a/re2o/settings.py +++ b/re2o/settings.py @@ -77,6 +77,7 @@ LOCAL_APPS = ( 're2o', 'preferences', 'logs', + 'tickets', ) INSTALLED_APPS = ( DJANGO_CONTRIB_APPS + diff --git a/re2o/urls.py b/re2o/urls.py index 37497572..c9e00667 100644 --- a/re2o/urls.py +++ b/re2o/urls.py @@ -70,6 +70,7 @@ urlpatterns = [ include('cotisations.urls', namespace='cotisations') ), url(r'^machines/', include('machines.urls', namespace='machines')), + url(r'^tickets/', include('tickets.urls', namespace='tickets')), url(r'^topologie/', include('topologie.urls', namespace='topologie')), url(r'^logs/', include('logs.urls', namespace='logs')), url( diff --git a/tickets/forms.py b/tickets/forms.py new file mode 100644 index 00000000..d1ebc323 --- /dev/null +++ b/tickets/forms.py @@ -0,0 +1,27 @@ +from django import forms +from django.forms import ModelForm, Form + +from .models import( + Ticket +) + +class EditTicketForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): + """Formulaire d'edition d'un Ticket""" + + class Meta: + model = Ticket + exclude = ['user','assigned_staff','date'] + + def __init__(self,*args, **kwargs): + prefix = kwargs.pop('prefix',self.Meta.model.__name__) + super(EditMachineForm, self).__init__(*args, prefix=prefix, **kwargs) + self.fields['title'].label = _("Titre du ticket") + self.fields['decription'].label = _("Description du ticket") + self.field['solved'].label = _("Problème réglé ?") + + + +class NewTicketForm(EditTicketForm): + """ Creation d'une machine""" + class Meta(EditeTicketForm): + fields = '__all__' diff --git a/tickets/models.py b/tickets/models.py index 71a83623..e1a0f81e 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -1,3 +1,35 @@ from django.db import models +from django.utils.translation import ugettext_lazy as _ -# Create your models here. +import users.models + +class Ticket(models.Model): + """Class définissant un ticket""" + + user = models.ForeignKey( + 'users.User', + on_delete=models.CASCADE, + related_name="tickets") + title = models.CharField( + max_length=255, + help_text=_("Nom du ticket"), + blank=False, + null=False,) + description = models.CharField( + max_length=3000, + help_text=_("Description du ticket"), + blank=False, + null=False) + date = models.DateTimeField(auto_now_add=True) + assigned_staff = models.ForeignKey( + 'users.User', + on_delete=models.PROTECT, + related_name="tickets_assigned", + blank=False, + null=True) + #categories = models.OneToManyFiled('Category') + solved = models.BooleanField(default=False) + + class Meta: + verbose_name = _("Ticket") + verbose_name_plural = _("Tickets") diff --git a/tickets/templates/tickets/aff_tickets.html b/tickets/templates/tickets/aff_tickets.html new file mode 100644 index 00000000..ebd658b1 --- /dev/null +++ b/tickets/templates/tickets/aff_tickets.html @@ -0,0 +1,59 @@ +{% extends 'users/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load i18n %} + +{% block title %}{% trans "Tickets" %}{% endblock %} + +{% block content %} +
+ + + + + + + + + + {% for ticket in tickets_list %} + + + + + + {% if ticket.solved %} + + {% else %} + + {% endif %} + + {% endfor %} + + +
UserTitreDateRésolu
Lien {{ ticket.user }}{{ ticket.title }}{{ ticket.date }}
+
+{% endblock %} diff --git a/tickets/urls.py b/tickets/urls.py new file mode 100644 index 00000000..f7af41ce --- /dev/null +++ b/tickets/urls.py @@ -0,0 +1,10 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [ + url(r'^$', views.aff_tickets, name='index des tickets'), + url(r'^new_ticket/(?P[0-9]+)$', + views.new_ticket, + name='new-ticket'), +] diff --git a/tickets/views.py b/tickets/views.py index 91ea44a2..51c3e104 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -1,3 +1,26 @@ from django.shortcuts import render -# Create your views here. +from .models import( + Ticket +) + +def new_ticket(request,user): + """ Vue de création d'un ticket """ + ticket = NewTicketForm(request.POST or None, user=request.user) + if ticket.is_valid(): + new_ticket_obj = machine.save(commit=False) + nex_ticket_obj.user = user + new_machine_obj.save() + + return form( + { + 'ticketform':ticket, + }, + 'ticket/ticket.html', + request + ) +def aff_tickets(request): + """ Vue d'affichage de tout les tickets """ + tickets = Ticket.objects.all() + return render(request,'tickets/aff_tickets.html', + {'tickets_list':tickets}) From c11cc35ffc59cb06bcd96713ca0bcf420e0d1a38 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Mon, 8 Jul 2019 09:59:35 +0000 Subject: [PATCH 053/228] Just a bit of front --- templates/base.html | 1 + tickets/urls.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/base.html b/templates/base.html index e58950ab..fa3b4706 100644 --- a/templates/base.html +++ b/templates/base.html @@ -100,6 +100,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% can_view_app cotisations %}
  • {% trans "Manage the subscriptions" %}
  • {% acl_end %} +
  • {% trans "Tickets" %}
  • {% acl_end %} diff --git a/tickets/urls.py b/tickets/urls.py index f7af41ce..34913bf6 100644 --- a/tickets/urls.py +++ b/tickets/urls.py @@ -3,7 +3,7 @@ from django.conf.urls import url from . import views urlpatterns = [ - url(r'^$', views.aff_tickets, name='index des tickets'), + url(r'^$', views.aff_tickets, name='aff-tickets'), url(r'^new_ticket/(?P[0-9]+)$', views.new_ticket, name='new-ticket'), From 1381433501830620b5ccf2defe0ab03c3ba177e5 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Mon, 8 Jul 2019 10:21:51 +0000 Subject: [PATCH 054/228] Affichage d'un ticket individuel --- tickets/templates/tickets/aff_ticket.html | 35 ++++++++++++++++++++++ tickets/templates/tickets/aff_tickets.html | 8 +++-- tickets/urls.py | 5 ++-- tickets/views.py | 6 ++++ 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 tickets/templates/tickets/aff_ticket.html diff --git a/tickets/templates/tickets/aff_ticket.html b/tickets/templates/tickets/aff_ticket.html new file mode 100644 index 00000000..4436182a --- /dev/null +++ b/tickets/templates/tickets/aff_ticket.html @@ -0,0 +1,35 @@ +{% extends 'users/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load i18n %} + +{% block title %}{% trans "Tickets" %}{% endblock %} + +{% block content %} + +{{ ticket.title }} + +{% endblock %} diff --git a/tickets/templates/tickets/aff_tickets.html b/tickets/templates/tickets/aff_tickets.html index ebd658b1..04487425 100644 --- a/tickets/templates/tickets/aff_tickets.html +++ b/tickets/templates/tickets/aff_tickets.html @@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc., - + @@ -41,7 +41,11 @@ with this program; if not, write to the Free Software Foundation, Inc., {% for ticket in tickets_list %} - + diff --git a/tickets/urls.py b/tickets/urls.py index 34913bf6..3e1e2c48 100644 --- a/tickets/urls.py +++ b/tickets/urls.py @@ -4,7 +4,6 @@ from . import views urlpatterns = [ url(r'^$', views.aff_tickets, name='aff-tickets'), - url(r'^new_ticket/(?P[0-9]+)$', - views.new_ticket, - name='new-ticket'), + url(r'^ticket/(?P[0-9]+)$', views.aff_ticket, name='aff-ticket'), + url(r'^new_ticket/(?P[0-9]+)$',views.new_ticket,name='new-ticket'), ] diff --git a/tickets/views.py b/tickets/views.py index 51c3e104..70e3857e 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -19,6 +19,12 @@ def new_ticket(request,user): 'ticket/ticket.html', request ) + +def aff_ticket(request,ticketid): + """Vue d'affichage d'un ticket""" + ticket = Ticket.objects.filter(id=ticketid).get() + return render(request,'tickets/aff_ticket.html',{'ticket':ticket}) + def aff_tickets(request): """ Vue d'affichage de tout les tickets """ tickets = Ticket.objects.all() From c4259658eb3c490c55563bd4f73da984dd7bd92b Mon Sep 17 00:00:00 2001 From: Grizzly Date: Wed, 10 Jul 2019 08:28:16 +0000 Subject: [PATCH 055/228] Formulaire de creation de ticket --- tickets/admin.py | 3 +- tickets/forms.py | 31 ++++++++------ tickets/models.py | 4 +- tickets/templates/tickets/form_ticket.html | 48 ++++++++++++++++++++++ tickets/urls.py | 2 +- tickets/views.py | 41 +++++++++++------- users/templates/users/profil.html | 5 +++ 7 files changed, 103 insertions(+), 31 deletions(-) create mode 100644 tickets/templates/tickets/form_ticket.html diff --git a/tickets/admin.py b/tickets/admin.py index 8c38f3f3..76763b9c 100644 --- a/tickets/admin.py +++ b/tickets/admin.py @@ -1,3 +1,4 @@ from django.contrib import admin - +from .models import Ticket +admin.site.register(Ticket) # Register your models here. diff --git a/tickets/forms.py b/tickets/forms.py index d1ebc323..f2a6891f 100644 --- a/tickets/forms.py +++ b/tickets/forms.py @@ -1,27 +1,34 @@ from django import forms from django.forms import ModelForm, Form +from re2o.field_permissions import FieldPermissionFormMixin +from re2o.mixins import FormRevMixin +from django.utils.translation import ugettext_lazy as _ from .models import( Ticket ) -class EditTicketForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): +class EditTicketForm(FormRevMixin, ModelForm): """Formulaire d'edition d'un Ticket""" + + #def __init__(self,*args, **kwargs): + #prefix = kwargs.pop('prefix',self.Meta.model.__name__) + #super(EditTicketForm, self).__init__(*args, prefix=prefix, **kwargs) + #self.fields['title'].label = _("Titre du ticket") + #self.fields['decription'].label = _("Description du ticket") + #self.fields['solved'].label = _("Problème réglé ?") class Meta: model = Ticket exclude = ['user','assigned_staff','date'] - - def __init__(self,*args, **kwargs): - prefix = kwargs.pop('prefix',self.Meta.model.__name__) - super(EditMachineForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['title'].label = _("Titre du ticket") - self.fields['decription'].label = _("Description du ticket") - self.field['solved'].label = _("Problème réglé ?") - -class NewTicketForm(EditTicketForm): +class NewTicketForm(ModelForm): """ Creation d'une machine""" - class Meta(EditeTicketForm): - fields = '__all__' + class Meta: + model = Ticket + fields = ['title', 'description'] + + #def __init(self,*args, **kwargs): + #prefix = kwargs.pop('prefix', self.Meta.model.__name__) + #super(NewTicketForm, self).__init__(*args, prefix=prefix, **kwargs) diff --git a/tickets/models.py b/tickets/models.py index e1a0f81e..abdab335 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -15,7 +15,7 @@ class Ticket(models.Model): help_text=_("Nom du ticket"), blank=False, null=False,) - description = models.CharField( + description = models.TextField( max_length=3000, help_text=_("Description du ticket"), blank=False, @@ -25,7 +25,7 @@ class Ticket(models.Model): 'users.User', on_delete=models.PROTECT, related_name="tickets_assigned", - blank=False, + blank=True, null=True) #categories = models.OneToManyFiled('Category') solved = models.BooleanField(default=False) diff --git a/tickets/templates/tickets/form_ticket.html b/tickets/templates/tickets/form_ticket.html new file mode 100644 index 00000000..79e9c68f --- /dev/null +++ b/tickets/templates/tickets/form_ticket.html @@ -0,0 +1,48 @@ +{% extends 'machines/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle +Copyright © 2017 Maël Kervella + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load massive_bootstrap_form %} +{% load i18n %} + +{% block title %}{% trans "Ticket" %}{% endblock %} + +{% block content %} +

    Ouverture d'un Ticket

    + +{% for message in messages %} +
    + + {{ message | safe }} +
    +{% endfor %} + +
    + {% csrf_token %} + {% bootstrap_form ticketform %} + {% bootstrap_button "Ouvrir le Ticket" button_type="submit" icon='ok' button_class='btn-success' %} + +{% endblock %} diff --git a/tickets/urls.py b/tickets/urls.py index 3e1e2c48..d270aa4c 100644 --- a/tickets/urls.py +++ b/tickets/urls.py @@ -5,5 +5,5 @@ from . import views urlpatterns = [ url(r'^$', views.aff_tickets, name='aff-tickets'), url(r'^ticket/(?P[0-9]+)$', views.aff_ticket, name='aff-ticket'), - url(r'^new_ticket/(?P[0-9]+)$',views.new_ticket,name='new-ticket'), + url(r'^new_ticket/$',views.new_ticket,name='new-ticket'), ] diff --git a/tickets/views.py b/tickets/views.py index 70e3857e..af2ccc83 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -1,24 +1,35 @@ -from django.shortcuts import render +from django.contrib import messages +from django.shortcuts import render, redirect +from django.urls import reverse +from django.forms import modelformset_factory +from re2o.views import form from .models import( Ticket ) -def new_ticket(request,user): - """ Vue de création d'un ticket """ - ticket = NewTicketForm(request.POST or None, user=request.user) - if ticket.is_valid(): - new_ticket_obj = machine.save(commit=False) - nex_ticket_obj.user = user - new_machine_obj.save() +from .forms import ( + NewTicketForm +) - return form( - { - 'ticketform':ticket, - }, - 'ticket/ticket.html', - request - ) +def new_ticket(request): + """ Vue de création d'un ticket """ + ticketform = NewTicketForm(request.POST or None)#, user=request.user) + + if request.method == 'POST': + ticketform = NewTicketForm(request.POST) + + if ticketform.is_valid(): + ticket = ticketform.save(commit=False) + ticket.user = request.user + ticket.save() + messages.success(request,'Votre ticket à été ouvert. Nous vous répondront le plus rapidement possible.') + return redirect(reverse('users:profil',kwargs={'userid':str(request.user.id)})) + else: + messages.error(request, 'Formulaire invalide') + else: + ticketform = NewTicketForm + return form({'ticketform':ticketform,},'tickets/form_ticket.html',request) def aff_ticket(request,ticketid): """Vue d'affichage d'un ticket""" diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index 52a214a6..5b57f6a8 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -119,6 +119,11 @@ with this program; if not, write to the Free Software Foundation, Inc., + + + {% trans " Open a Ticket" %} + +
    Date: Wed, 10 Jul 2019 09:16:37 +0000 Subject: [PATCH 056/228] Affichage des tickets sur le profil --- tickets/templates/tickets/aff_tickets.html | 1 - users/templates/users/profil.html | 25 ++++++++++++++++++---- users/views.py | 8 +++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/tickets/templates/tickets/aff_tickets.html b/tickets/templates/tickets/aff_tickets.html index 04487425..54573ace 100644 --- a/tickets/templates/tickets/aff_tickets.html +++ b/tickets/templates/tickets/aff_tickets.html @@ -1,4 +1,3 @@ -{% extends 'users/sidebar.html' %} {% comment %} Re2o est un logiciel d'administration développé initiallement au rezometz. Il se veut agnostique au réseau considéré, de manière à être installable en diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index 5b57f6a8..dee64ccc 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -120,10 +120,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    - - {% trans " Open a Ticket" %} - -
    +
    +
    +

    + {% trans " Tickets" %} +

    +
    +
    + +
    + {% if tickets_list %} + {% include 'tickets/aff_tickets.html' with tickets_list=tickets_list %} + {% else %} +

    {% trans "No tickets" %}

    + {% endif %} +
    +
    +
    {% endblock %} diff --git a/users/views.py b/users/views.py index ad8543b5..ca95e584 100644 --- a/users/views.py +++ b/users/views.py @@ -53,6 +53,10 @@ from reversion import revisions as reversion from cotisations.models import Facture, Paiement from machines.models import Machine + +# A IMPORTER SOUS CONDITION QUE TICKET SOIT INSTALLED +from tickets.models import Ticket + from preferences.models import OptionalUser, GeneralOption, AssoOption from re2o.views import form from re2o.utils import ( @@ -974,6 +978,8 @@ def profil(request, users, **_kwargs): request.GET.get('order'), SortTable.MACHINES_INDEX ) + tickets = Ticket.objects.filter(user=users).all() + nb_tickets = tickets.count() pagination_large_number = GeneralOption.get_cached_value( 'pagination_large_number' ) @@ -1016,6 +1022,8 @@ def profil(request, users, **_kwargs): 'users': users, 'machines_list': machines, 'nb_machines': nb_machines, + 'tickets_list': tickets, + 'nb_tickets': nb_tickets, 'facture_list': factures, 'ban_list': bans, 'white_list': whitelists, From 790b43ccc36498d360ce60570ed7c3cd066791f6 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Wed, 10 Jul 2019 12:24:06 +0000 Subject: [PATCH 057/228] Affichage propre d'un ticket simple --- re2o/settings.py | 1 + tickets/templates/tickets/aff_ticket.html | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/re2o/settings.py b/re2o/settings.py index ce7d3257..96fa9308 100644 --- a/re2o/settings.py +++ b/re2o/settings.py @@ -62,6 +62,7 @@ DJANGO_CONTRIB_APPS = ( 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django.contrib.humanize', ) EXTERNAL_CONTRIB_APPS = ( 'bootstrap3', diff --git a/tickets/templates/tickets/aff_ticket.html b/tickets/templates/tickets/aff_ticket.html index 4436182a..242aa4f4 100644 --- a/tickets/templates/tickets/aff_ticket.html +++ b/tickets/templates/tickets/aff_ticket.html @@ -25,11 +25,28 @@ with this program; if not, write to the Free Software Foundation, Inc., {% load bootstrap3 %} {% load i18n %} +{% load humanize %} {% block title %}{% trans "Tickets" %}{% endblock %} {% block content %} -{{ ticket.title }} +

    Ticket #{{ticket.id}}

    + +
    +
    + {% trans "Opened by" %} + + {{ ticket.user.get_full_name }} + + {{ ticket.date | naturalday}}. +
    +
    + +

    {% trans "Title:" %} {{ticket.title}}

    +

    {% trans "Description" %} {{ ticket.description }}

    + +
    +
    {% endblock %} From a561f094582a1792391645c99dfac03b4233af58 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Wed, 10 Jul 2019 14:39:55 +0000 Subject: [PATCH 058/228] Meilleur affichage de tout les tickets --- tickets/templates/tickets/aff_tickets.html | 2 +- tickets/templates/tickets/index.html | 34 ++++++++++++++++++++++ tickets/views.py | 2 +- 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tickets/templates/tickets/index.html diff --git a/tickets/templates/tickets/aff_tickets.html b/tickets/templates/tickets/aff_tickets.html index 54573ace..5c10a4a4 100644 --- a/tickets/templates/tickets/aff_tickets.html +++ b/tickets/templates/tickets/aff_tickets.html @@ -32,7 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    id User Titre Date
    Lien + + + + {{ ticket.user }} {{ ticket.title }} {{ ticket.date }}
    - + diff --git a/tickets/templates/tickets/index.html b/tickets/templates/tickets/index.html new file mode 100644 index 00000000..4429c4fd --- /dev/null +++ b/tickets/templates/tickets/index.html @@ -0,0 +1,34 @@ +{% extends 'users/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load i18n %} + +{% block title%}{% trans "Tickets" %}{% endblock %} + +{% block content %} +

    {% trans "Tickets" %}

    + {% include 'tickets/aff_tickets.html' with tickets_list=tickets_list %} +{% endblock %} diff --git a/tickets/views.py b/tickets/views.py index af2ccc83..98a9518d 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -39,5 +39,5 @@ def aff_ticket(request,ticketid): def aff_tickets(request): """ Vue d'affichage de tout les tickets """ tickets = Ticket.objects.all() - return render(request,'tickets/aff_tickets.html', + return render(request,'tickets/index.html', {'tickets_list':tickets}) From 609904c279e9f98cd61d502864697a3657b6d52f Mon Sep 17 00:00:00 2001 From: Grizzly Date: Thu, 11 Jul 2019 08:00:49 +0000 Subject: [PATCH 059/228] Ordonancement des tickets par date --- tickets/views.py | 2 +- users/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tickets/views.py b/tickets/views.py index 98a9518d..c6eccdd7 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -38,6 +38,6 @@ def aff_ticket(request,ticketid): def aff_tickets(request): """ Vue d'affichage de tout les tickets """ - tickets = Ticket.objects.all() + tickets = Ticket.objects.all().order_by('date') return render(request,'tickets/index.html', {'tickets_list':tickets}) diff --git a/users/views.py b/users/views.py index ca95e584..4bed47f4 100644 --- a/users/views.py +++ b/users/views.py @@ -978,7 +978,7 @@ def profil(request, users, **_kwargs): request.GET.get('order'), SortTable.MACHINES_INDEX ) - tickets = Ticket.objects.filter(user=users).all() + tickets = Ticket.objects.filter(user=users).all().order_by('date') nb_tickets = tickets.count() pagination_large_number = GeneralOption.get_cached_value( 'pagination_large_number' From 13afc5aaebf32a5160bf6a9aea21c9b38908de8d Mon Sep 17 00:00:00 2001 From: Grizzly Date: Thu, 11 Jul 2019 08:27:58 +0000 Subject: [PATCH 060/228] Dummy bouton, order des date, et affichage dans l'admin --- tickets/models.py | 3 +++ tickets/templates/tickets/aff_ticket.html | 10 ++++++++++ tickets/views.py | 2 +- users/views.py | 2 +- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tickets/models.py b/tickets/models.py index abdab335..ba0b183e 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -33,3 +33,6 @@ class Ticket(models.Model): class Meta: verbose_name = _("Ticket") verbose_name_plural = _("Tickets") + + def __str__(self): + return "Ticket de {} date: {}".format(self.user.surname,self.date) diff --git a/tickets/templates/tickets/aff_ticket.html b/tickets/templates/tickets/aff_ticket.html index 242aa4f4..42ef897b 100644 --- a/tickets/templates/tickets/aff_ticket.html +++ b/tickets/templates/tickets/aff_ticket.html @@ -46,6 +46,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,

    {% trans "Title:" %} {{ticket.title}}

    {% trans "Description" %} {{ ticket.description }}

    + diff --git a/tickets/views.py b/tickets/views.py index c6eccdd7..270bf0df 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -38,6 +38,6 @@ def aff_ticket(request,ticketid): def aff_tickets(request): """ Vue d'affichage de tout les tickets """ - tickets = Ticket.objects.all().order_by('date') + tickets = Ticket.objects.all().order_by('-date') return render(request,'tickets/index.html', {'tickets_list':tickets}) diff --git a/users/views.py b/users/views.py index 4bed47f4..a039bad6 100644 --- a/users/views.py +++ b/users/views.py @@ -978,7 +978,7 @@ def profil(request, users, **_kwargs): request.GET.get('order'), SortTable.MACHINES_INDEX ) - tickets = Ticket.objects.filter(user=users).all().order_by('date') + tickets = Ticket.objects.filter(user=users).all().order_by('-date') nb_tickets = tickets.count() pagination_large_number = GeneralOption.get_cached_value( 'pagination_large_number' From 2650065787ea4631a3a16c1462e60d1fb2e64ff9 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Fri, 12 Jul 2019 11:41:17 +0000 Subject: [PATCH 061/228] Ouverture de ticket pour les utilisaterus non authentifies --- tickets/forms.py | 5 ++++- tickets/models.py | 8 +++++++- tickets/templates/tickets/form_ticket.html | 21 +++++++++++++++++++-- tickets/views.py | 21 +++++++++++++++------ 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/tickets/forms.py b/tickets/forms.py index f2a6891f..d914d022 100644 --- a/tickets/forms.py +++ b/tickets/forms.py @@ -25,9 +25,12 @@ class EditTicketForm(FormRevMixin, ModelForm): class NewTicketForm(ModelForm): """ Creation d'une machine""" + + email = forms.EmailField(required=False) + class Meta: model = Ticket - fields = ['title', 'description'] + fields = ['title', 'description', 'email'] #def __init(self,*args, **kwargs): #prefix = kwargs.pop('prefix', self.Meta.model.__name__) diff --git a/tickets/models.py b/tickets/models.py index ba0b183e..01a4d77b 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -9,7 +9,9 @@ class Ticket(models.Model): user = models.ForeignKey( 'users.User', on_delete=models.CASCADE, - related_name="tickets") + related_name="tickets", + blank=True, + null=True) title = models.CharField( max_length=255, help_text=_("Nom du ticket"), @@ -21,6 +23,10 @@ class Ticket(models.Model): blank=False, null=False) date = models.DateTimeField(auto_now_add=True) + email = models.EmailField( + help_text = _("Une adresse mail pour vous recontacter"), + max_length=100, + null=True) assigned_staff = models.ForeignKey( 'users.User', on_delete=models.PROTECT, diff --git a/tickets/templates/tickets/form_ticket.html b/tickets/templates/tickets/form_ticket.html index 79e9c68f..d80a993e 100644 --- a/tickets/templates/tickets/form_ticket.html +++ b/tickets/templates/tickets/form_ticket.html @@ -40,9 +40,26 @@ with this program; if not, write to the Free Software Foundation, Inc., {% endfor %} -
    + {% csrf_token %} - {% bootstrap_form ticketform %} + {% if not user.is_authenticated %} +

    {% trans "Vous n'êtes pas authentifié. Veuillez fournir une adresse mail afin que nous puissions vous recontacter." %}

    + {% bootstrap_field ticketform.email %} + {% endif %} + {% bootstrap_field ticketform.title %} +
    +

    {% trans "Description de votre problème. Veuillez fournir le plus d'informations possible afin de faciliter la recherche de solution. Voici quelques informations dont nous pourions avoir besoin:" %}

    +
      +
    • +

      {% trans "Le type de votre problème (adhesion, connexion, paiement ou autre)." %}

      +
    • +
    • +

      {% trans "Les conditions dans lesquelles vous rencontrez le problème (Wifi/filaire, sur tout les apareils ou sur un seul. Est-ce une nouvelle machine ?" %}

      +
    • +
    • +

      {% trans "Les endroits dans lequels le problème survient (chez vous, dans une partie commune, dans un batiment en particulier)." %}

      +
    + {% bootstrap_field ticketform.description %} {% bootstrap_button "Ouvrir le Ticket" button_type="submit" icon='ok' button_class='btn-success' %} {% endblock %} diff --git a/tickets/views.py b/tickets/views.py index 270bf0df..cb138590 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -20,13 +20,22 @@ def new_ticket(request): ticketform = NewTicketForm(request.POST) if ticketform.is_valid(): + email = ticketform.cleaned_data.get('email') ticket = ticketform.save(commit=False) - ticket.user = request.user - ticket.save() - messages.success(request,'Votre ticket à été ouvert. Nous vous répondront le plus rapidement possible.') - return redirect(reverse('users:profil',kwargs={'userid':str(request.user.id)})) - else: - messages.error(request, 'Formulaire invalide') + #raise ValueError("email: {} type: {}".format(email,type(email))) + if request.user.is_authenticated: + ticket.user = request.user + ticket.save() + messages.success(request,'Votre ticket à été ouvert. Nous vous répondront le plus rapidement possible.') + return redirect(reverse('users:profil',kwargs={'userid':str(request.user.id)})) + if not request.user.is_authenticated and email != "": + ticket.save() + messages.success(request,'Votre ticket à été ouvert. Nous vous répondront le plus rapidement possible.') + return redirect(reverse('index')) + else: + messages.error(request,"Vous n'êtes pas authentifié, veuillez vous authentifier ou fournir une adresse mail pour que nous puissions vous recontacter") + return form({'ticketform':ticketform,},'tickets/form_ticket.html',request) + else: ticketform = NewTicketForm return form({'ticketform':ticketform,},'tickets/form_ticket.html',request) From 22c311c1eca17936f92797520e07e40281da9431 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Fri, 12 Jul 2019 12:00:56 +0000 Subject: [PATCH 062/228] affichage des tickets sans user et adresse de reponse --- tickets/templates/tickets/aff_ticket.html | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tickets/templates/tickets/aff_ticket.html b/tickets/templates/tickets/aff_ticket.html index 42ef897b..4683f1fc 100644 --- a/tickets/templates/tickets/aff_ticket.html +++ b/tickets/templates/tickets/aff_ticket.html @@ -35,11 +35,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    - {% trans "Opened by" %} - - {{ ticket.user.get_full_name }} - + {% trans "Opened by" %} + {% if ticket.user %} + + {{ ticket.user.get_full_name }} + + {% else %} + {% trans "Anonymous User" %} + {% endif %} {{ ticket.date | naturalday}}. + {% if not ticket.user %} + {% trans "Response address: " %}{{ticket.email}} + {% endif %}
    From 7099d6d57af4367f81c35187bff2debad9d9b158 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Fri, 12 Jul 2019 13:57:50 +0000 Subject: [PATCH 063/228] Ouverture des tickets disponible sur la page d'accueil --- templates/base.html | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/base.html b/templates/base.html index fa3b4706..10590167 100644 --- a/templates/base.html +++ b/templates/base.html @@ -131,6 +131,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if not request.user.is_authenticated %} From 575e570d16b28806e82d18599280e5565d83cb96 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Thu, 25 Jul 2019 14:44:40 +0000 Subject: [PATCH 064/228] Cannonisation de l'affichage des apps optionnels sur le profil et imports conditionnels dans les urls --- re2o/settings.py | 1 - re2o/urls.py | 7 ++++++- templates/base.html | 5 +++++ tickets/templates/tickets/profil.html | 23 +++++++++++++++++++++++ tickets/views.py | 6 ++++++ users/templates/users/profil.html | 26 +++++--------------------- users/views.py | 15 ++++++++------- 7 files changed, 53 insertions(+), 30 deletions(-) create mode 100644 tickets/templates/tickets/profil.html diff --git a/re2o/settings.py b/re2o/settings.py index 96fa9308..14907570 100644 --- a/re2o/settings.py +++ b/re2o/settings.py @@ -78,7 +78,6 @@ LOCAL_APPS = ( 're2o', 'preferences', 'logs', - 'tickets', ) INSTALLED_APPS = ( DJANGO_CONTRIB_APPS + diff --git a/re2o/urls.py b/re2o/urls.py index c9e00667..5db9abe8 100644 --- a/re2o/urls.py +++ b/re2o/urls.py @@ -49,6 +49,8 @@ from django.contrib import admin from django.utils.translation import gettext_lazy as _ from django.views.generic import RedirectView +from .settings_local import OPTIONNAL_APPS + from .views import index, about_page, contact_page # Admin site configuration @@ -70,7 +72,6 @@ urlpatterns = [ include('cotisations.urls', namespace='cotisations') ), url(r'^machines/', include('machines.urls', namespace='machines')), - url(r'^tickets/', include('tickets.urls', namespace='tickets')), url(r'^topologie/', include('topologie.urls', namespace='topologie')), url(r'^logs/', include('logs.urls', namespace='logs')), url( @@ -84,6 +85,10 @@ urlpatterns = [ url(r'^admin/login/$', RedirectView.as_view(pattern_name='login')), url(r'^admin/', include(admin.site.urls)), ] + + +urlpatterns += [url(r'^{}/'.format(app), include('{}.urls'.format(app), namespace=app)) for app in OPTIONNAL_APPS] + # Add debug_toolbar URLs if activated if 'debug_toolbar' in settings.INSTALLED_APPS: import debug_toolbar diff --git a/templates/base.html b/templates/base.html index 10590167..6d39f8c8 100644 --- a/templates/base.html +++ b/templates/base.html @@ -100,7 +100,10 @@ with this program; if not, write to the Free Software Foundation, Inc., {% can_view_app cotisations %}
  • {% trans "Manage the subscriptions" %}
  • {% acl_end %} + + {% comment %}
  • {% trans "Tickets" %}
  • + {% endcomment %} {% acl_end %} @@ -131,7 +134,9 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if not request.user.is_authenticated %} diff --git a/tickets/templates/tickets/profil.html b/tickets/templates/tickets/profil.html new file mode 100644 index 00000000..06b727a4 --- /dev/null +++ b/tickets/templates/tickets/profil.html @@ -0,0 +1,23 @@ +{% load i18n %} + +
    +
    +

    + {% trans " Tickets" %} +

    +
    +
    + +
    + {% if tickets_list %} + {% include 'tickets/aff_tickets.html' with tickets_list=tickets_list %} + {% else %} +

    {% trans "No tickets" %}

    + {% endif %} +
    +
    +
    diff --git a/tickets/views.py b/tickets/views.py index cb138590..9c6b42e6 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -1,5 +1,6 @@ from django.contrib import messages from django.shortcuts import render, redirect +from django.template.loader import render_to_string from django.urls import reverse from django.forms import modelformset_factory from re2o.views import form @@ -50,3 +51,8 @@ def aff_tickets(request): tickets = Ticket.objects.all().order_by('-date') return render(request,'tickets/index.html', {'tickets_list':tickets}) +def profil(request,user): + """ Vue cannonique d'affichage des tickets dans l'accordeon du profil""" + tickets = Ticket.objects.filter(user=user).all().order_by('-date') + context = {'tickets_list':tickets} + return render_to_string('tickets/profil.html', context=context, request=request, using=None) diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index dee64ccc..a7079232 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -528,27 +528,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    -
    -
    -

    - {% trans " Tickets" %} -

    -
    -
    - -
    - {% if tickets_list %} - {% include 'tickets/aff_tickets.html' with tickets_list=tickets_list %} - {% else %} -

    {% trans "No tickets" %}

    - {% endif %} -
    -
    -
    + + {% for template in optionnal_templates_list %} + {{ template }} + {% endfor %} + {% endblock %} diff --git a/users/views.py b/users/views.py index a039bad6..426645e5 100644 --- a/users/views.py +++ b/users/views.py @@ -47,6 +47,7 @@ from django.http import HttpResponse from django.http import HttpResponseRedirect from django.views.decorators.csrf import csrf_exempt from django.utils.translation import ugettext as _ +from django.template import loader from rest_framework.renderers import JSONRenderer from reversion import revisions as reversion @@ -54,10 +55,9 @@ from reversion import revisions as reversion from cotisations.models import Facture, Paiement from machines.models import Machine -# A IMPORTER SOUS CONDITION QUE TICKET SOIT INSTALLED -from tickets.models import Ticket - from preferences.models import OptionalUser, GeneralOption, AssoOption +from importlib import import_module +from re2o.settings_local import OPTIONNAL_APPS from re2o.views import form from re2o.utils import ( all_has_access, @@ -978,8 +978,10 @@ def profil(request, users, **_kwargs): request.GET.get('order'), SortTable.MACHINES_INDEX ) - tickets = Ticket.objects.filter(user=users).all().order_by('-date') - nb_tickets = tickets.count() + + optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS] + optionnal_templates_list = [app.views.profil(request,users) for app in optionnal_apps] + pagination_large_number = GeneralOption.get_cached_value( 'pagination_large_number' ) @@ -1022,8 +1024,7 @@ def profil(request, users, **_kwargs): 'users': users, 'machines_list': machines, 'nb_machines': nb_machines, - 'tickets_list': tickets, - 'nb_tickets': nb_tickets, + 'optionnal_templates_list': optionnal_templates_list, 'facture_list': factures, 'ban_list': bans, 'white_list': whitelists, From 8e403443b522dbc760de24fd3f1c8ccfffa61528 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Mon, 5 Aug 2019 14:38:53 +0000 Subject: [PATCH 065/228] =?UTF-8?q?Affichage=20des=20pr=C3=A9f=C3=A9rences?= =?UTF-8?q?=20des=20tickets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../preferences/display_preferences.html | 4 ++++ preferences/views.py | 7 ++++++ tickets/models.py | 22 +++++++++++++++++++ tickets/templates/tickets/preferences.html | 12 ++++++++++ tickets/views.py | 13 ++++++++++- 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tickets/templates/tickets/preferences.html diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index a7d15679..3e71c817 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -503,5 +503,9 @@ with this program; if not, write to the Free Software Foundation, Inc., +{% for template in optionnal_templates_list %} + {{ template }} +{% endfor %} + {% endblock %} diff --git a/preferences/views.py b/preferences/views.py index ecb3826e..680fcac0 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -40,6 +40,8 @@ from django.utils.translation import ugettext as _ from reversion import revisions as reversion +from importlib import import_module +from re2o.settings_local import OPTIONNAL_APPS from re2o.views import form from re2o.acl import can_create, can_edit, can_delete_set, can_view_all, can_delete @@ -94,6 +96,10 @@ def display_options(request): radiusoptions, _ = RadiusOption.objects.get_or_create() cotisationsoptions, _created = CotisationsOption.objects.get_or_create() document_template_list = DocumentTemplate.objects.order_by('name') + + optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS] + optionnal_templates_list = [app.views.preferences(request) for app in optionnal_apps] + return form({ 'useroptions': useroptions, 'machineoptions': machineoptions, @@ -109,6 +115,7 @@ def display_options(request): 'switchmanagementcred_list': switchmanagementcred_list, 'radiusoptions' : radiusoptions, 'cotisationsoptions': cotisationsoptions, + 'optionnal_templates_list': optionnal_templates_list, 'document_template_list': document_template_list, }, 'preferences/display_preferences.html', request) diff --git a/tickets/models.py b/tickets/models.py index 01a4d77b..df1cd8ac 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -1,5 +1,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ +from django.core.mail import send_mail +from django.template import Context, loader import users.models @@ -42,3 +44,23 @@ class Ticket(models.Model): def __str__(self): return "Ticket de {} date: {}".format(self.user.surname,self.date) + + def publish_mail(self): + template = loader.get_template('ticket/mail_publish_ticket') + context = Context({'ticket':self}) + send_mail( + 'Nouvelle ouverture de ticket', + '', + 'ticket_app_re2o@crans.org', + '', + html_message=template.render(context)) + +class Preferences(models.Model): + """ Class cannonique définissants les préférences des tickets """ + + publish_address = models.EmailField( + help_text = _("Adresse mail pour annoncer les nouveau tickets (laisser vide pour ne rien annoncer)"), + max_length = 1000, + null = True) + class Meta: + verbose_name = _("Préférences des tickets") diff --git a/tickets/templates/tickets/preferences.html b/tickets/templates/tickets/preferences.html new file mode 100644 index 00000000..c27c0a99 --- /dev/null +++ b/tickets/templates/tickets/preferences.html @@ -0,0 +1,12 @@ +{% load i18n %} + +
    + +
    + preferences des tickets +
    +
    diff --git a/tickets/views.py b/tickets/views.py index 9c6b42e6..ef268f9f 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -6,13 +6,15 @@ from django.forms import modelformset_factory from re2o.views import form from .models import( - Ticket + Ticket, + Preferences, ) from .forms import ( NewTicketForm ) + def new_ticket(request): """ Vue de création d'un ticket """ ticketform = NewTicketForm(request.POST or None)#, user=request.user) @@ -51,8 +53,17 @@ def aff_tickets(request): tickets = Ticket.objects.all().order_by('-date') return render(request,'tickets/index.html', {'tickets_list':tickets}) + + +# views cannoniques des apps optionnels def profil(request,user): """ Vue cannonique d'affichage des tickets dans l'accordeon du profil""" tickets = Ticket.objects.filter(user=user).all().order_by('-date') context = {'tickets_list':tickets} return render_to_string('tickets/profil.html', context=context, request=request, using=None) + +def preferences(request): + """ Vue cannonique d'affichage des tickets dans l'affichage du profil""" + preferences = Preferences.objects.first() + context = {'preferences':preferences} + return render_to_string('tickets/preferences.html', context=context, request=request, using=None) From 1d60f62555d8ac5e27d90844d9cf7adf7b316682 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Tue, 6 Aug 2019 05:10:37 +0000 Subject: [PATCH 066/228] =?UTF-8?q?Edition=20des=20pr=C3=A9f=C3=A9rences?= =?UTF-8?q?=20des=20tickets=20sur=20la=20page=20des=20pr=C3=A9f=C3=A9rence?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tickets/forms.py | 21 +++----- .../templates/tickets/form_preferences.html | 48 +++++++++++++++++++ tickets/templates/tickets/preferences.html | 25 +++++++++- tickets/urls.py | 1 + tickets/views.py | 22 ++++++++- 5 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 tickets/templates/tickets/form_preferences.html diff --git a/tickets/forms.py b/tickets/forms.py index d914d022..1b4fa4ce 100644 --- a/tickets/forms.py +++ b/tickets/forms.py @@ -5,19 +5,12 @@ from re2o.mixins import FormRevMixin from django.utils.translation import ugettext_lazy as _ from .models import( - Ticket + Ticket, + Preferences, ) class EditTicketForm(FormRevMixin, ModelForm): """Formulaire d'edition d'un Ticket""" - - #def __init__(self,*args, **kwargs): - #prefix = kwargs.pop('prefix',self.Meta.model.__name__) - #super(EditTicketForm, self).__init__(*args, prefix=prefix, **kwargs) - #self.fields['title'].label = _("Titre du ticket") - #self.fields['decription'].label = _("Description du ticket") - #self.fields['solved'].label = _("Problème réglé ?") - class Meta: model = Ticket exclude = ['user','assigned_staff','date'] @@ -25,13 +18,13 @@ class EditTicketForm(FormRevMixin, ModelForm): class NewTicketForm(ModelForm): """ Creation d'une machine""" - email = forms.EmailField(required=False) - class Meta: model = Ticket fields = ['title', 'description', 'email'] - #def __init(self,*args, **kwargs): - #prefix = kwargs.pop('prefix', self.Meta.model.__name__) - #super(NewTicketForm, self).__init__(*args, prefix=prefix, **kwargs) +class EditPreferencesForm(ModelForm): + """ Edition des préférences des tickets """ + class Meta: + model = Preferences + fields = '__all__' diff --git a/tickets/templates/tickets/form_preferences.html b/tickets/templates/tickets/form_preferences.html new file mode 100644 index 00000000..83339484 --- /dev/null +++ b/tickets/templates/tickets/form_preferences.html @@ -0,0 +1,48 @@ +{% extends 'machines/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle +Copyright © 2017 Maël Kervella + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load massive_bootstrap_form %} +{% load i18n %} + +{% block title %}{% trans "Ticket" %}{% endblock %} + +{% block content %} +

    Edition des préférences des Tickets

    + +{% for message in messages %} +
    + + {{ message | safe }} +
    +{% endfor %} + +
    + {% csrf_token %} + {% bootstrap_field preferencesform.publish_address %} + {% bootstrap_button "Editer" button_type="submit" icon='ok' button_class='btn-success' %} + +{% endblock %} diff --git a/tickets/templates/tickets/preferences.html b/tickets/templates/tickets/preferences.html index c27c0a99..8f9fe490 100644 --- a/tickets/templates/tickets/preferences.html +++ b/tickets/templates/tickets/preferences.html @@ -6,7 +6,28 @@ {% trans "Tickets" %} -
    - preferences des tickets + +
    id User Titre Date
    + + + + {% if preferences.publish_address %} + + {% else %} + + {% endif %} + +

    Email de publication

    {{ preferences.publish_address }}

    {% trans "Pas d'adresse, les tickets ne sont pas annoncés" %}

    +
    +
    diff --git a/tickets/urls.py b/tickets/urls.py index d270aa4c..98556a7a 100644 --- a/tickets/urls.py +++ b/tickets/urls.py @@ -5,5 +5,6 @@ from . import views urlpatterns = [ url(r'^$', views.aff_tickets, name='aff-tickets'), url(r'^ticket/(?P[0-9]+)$', views.aff_ticket, name='aff-ticket'), + url(r'^ticket/edit-preferences-tickets$', views.edit_preferences, name='edit-preferences-tickets'), url(r'^new_ticket/$',views.new_ticket,name='new-ticket'), ] diff --git a/tickets/views.py b/tickets/views.py index ef268f9f..13b6ad23 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -11,13 +11,14 @@ from .models import( ) from .forms import ( - NewTicketForm + NewTicketForm, + EditPreferencesForm, ) def new_ticket(request): """ Vue de création d'un ticket """ - ticketform = NewTicketForm(request.POST or None)#, user=request.user) + ticketform = NewTicketForm(request.POST or None) if request.method == 'POST': ticketform = NewTicketForm(request.POST) @@ -54,6 +55,23 @@ def aff_tickets(request): return render(request,'tickets/index.html', {'tickets_list':tickets}) +def edit_preferences(request): + """ Vue d'édition des préférences des tickets """ + + preferences_instance, created = Preferences.objects.get_or_create(id=1) + preferencesform = EditPreferencesForm( + request.POST or None, + instance = preferences_instance,) + + if preferencesform.is_valid(): + if preferencesform.changed_data: + preferencesform.save() + messages.success(request,'Préférences des Tickets mises à jour') + return redirect(reverse('preferences:display-options',)) + else: + messages.error(request,'Formulaire Invalide') + return form({'preferencesform':preferencesform,},'tickets/form_preferences.html',request) + return form({'preferencesform':preferencesform,},'tickets/form_preferences.html',request) # views cannoniques des apps optionnels def profil(request,user): From 209f118de2be448b3dbe1e105379f833731df95a Mon Sep 17 00:00:00 2001 From: Grizzly Date: Tue, 6 Aug 2019 07:41:27 +0000 Subject: [PATCH 067/228] =?UTF-8?q?R=C3=A9solution=20et=20r=C3=A9ouverture?= =?UTF-8?q?=20des=20tickets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tickets/forms.py | 7 +++++++ tickets/templates/tickets/aff_ticket.html | 18 ++++++++++-------- tickets/views.py | 7 ++++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/tickets/forms.py b/tickets/forms.py index 1b4fa4ce..4bb59458 100644 --- a/tickets/forms.py +++ b/tickets/forms.py @@ -28,3 +28,10 @@ class EditPreferencesForm(ModelForm): class Meta: model = Preferences fields = '__all__' + +class ChangeStatusTicketForm(ModelForm): + """ Passe un Ticket en résolu """ + class Meta: + model = Ticket + fields = [] + diff --git a/tickets/templates/tickets/aff_ticket.html b/tickets/templates/tickets/aff_ticket.html index 4683f1fc..f56a6b6c 100644 --- a/tickets/templates/tickets/aff_ticket.html +++ b/tickets/templates/tickets/aff_ticket.html @@ -54,14 +54,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,

    {% trans "Description" %} {{ ticket.description }}

    -{% if not ticket.solved %} - - {% trans "Mark as Solved" %} -{% else %} - - {% trans "Mark as Not Solved" %} -{% endif %} - +
    + {% csrf_token %} + {% bootstrap_form changestatusform %} + + {% if not ticket.solved %} + {% bootstrap_button "Résoudre" button_type="submit" button_class='btn-info' %} + {% else %} + {% bootstrap_button "Ouvrir" button_type="submit" button_class='btn-warning' %} + {% endif %} +
    diff --git a/tickets/views.py b/tickets/views.py index 13b6ad23..0e89218d 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -12,6 +12,7 @@ from .models import( from .forms import ( NewTicketForm, + ChangeStatusTicketForm, EditPreferencesForm, ) @@ -47,7 +48,11 @@ def new_ticket(request): def aff_ticket(request,ticketid): """Vue d'affichage d'un ticket""" ticket = Ticket.objects.filter(id=ticketid).get() - return render(request,'tickets/aff_ticket.html',{'ticket':ticket}) + changestatusform = ChangeStatusTicketForm(request.POST) + if request.method == 'POST': + ticket.solved = not ticket.solved + ticket.save() + return render(request,'tickets/aff_ticket.html',{'ticket':ticket,'changestatusform':changestatusform}) def aff_tickets(request): """ Vue d'affichage de tout les tickets """ From 034dec924d73d13dd4e27edbbe0a09c16a1c44c7 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Tue, 6 Aug 2019 16:06:53 +0000 Subject: [PATCH 068/228] frontend kikoo --- tickets/templates/tickets/aff_ticket.html | 17 ++++++++++++++--- tickets/templates/tickets/aff_tickets.html | 20 +++++++++++++++++++- tickets/views.py | 11 +++++++++-- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/tickets/templates/tickets/aff_ticket.html b/tickets/templates/tickets/aff_ticket.html index f56a6b6c..7bf5b04d 100644 --- a/tickets/templates/tickets/aff_ticket.html +++ b/tickets/templates/tickets/aff_ticket.html @@ -31,7 +31,13 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block content %} -

    Ticket #{{ticket.id}}

    +

    Ticket #{{ticket.id}} +{% if ticket.solved %} +{% trans "Solved" %} +{% else %} +{% trans "Not Solved" %} +{% endif %} +

    @@ -59,13 +65,18 @@ with this program; if not, write to the Free Software Foundation, Inc., {% bootstrap_form changestatusform %} {% if not ticket.solved %} - {% bootstrap_button "Résoudre" button_type="submit" button_class='btn-info' %} + {% bootstrap_button "Mark as Solved" button_type="submit" button_class='btn-info' %} {% else %} - {% bootstrap_button "Ouvrir" button_type="submit" button_class='btn-warning' %} + {% bootstrap_button "Mark as not Solved" button_type="submit" button_class='btn-warning' %} {% endif %}
    + + + {% endblock %} diff --git a/tickets/templates/tickets/aff_tickets.html b/tickets/templates/tickets/aff_tickets.html index 5c10a4a4..1d447234 100644 --- a/tickets/templates/tickets/aff_tickets.html +++ b/tickets/templates/tickets/aff_tickets.html @@ -28,8 +28,26 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block title %}{% trans "Tickets" %}{% endblock %} {% block content %} + + +
    +
    +
    +
    + {{ nbr_tickets }} {% trans "Tickets" %} +
    +
    + {{ nbr_tickets_unsolved }}{% trans "Not Solved Tickets" %} +
    +
    + {% trans "Last Ticket:" %} {{ last_ticket_date }} +
    +
    +
    +
    +
    - +
    diff --git a/tickets/views.py b/tickets/views.py index 0e89218d..7a86ecf4 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -57,8 +57,15 @@ def aff_ticket(request,ticketid): def aff_tickets(request): """ Vue d'affichage de tout les tickets """ tickets = Ticket.objects.all().order_by('-date') - return render(request,'tickets/index.html', - {'tickets_list':tickets}) + last_ticket_date = tickets.first().date + nbr_tickets = tickets.count() + nbr_tickets_unsolved = Ticket.objects.filter(solved=False).count() + context = {'tickets_list':tickets, + 'last_ticket_date':last_ticket_date, + 'nbr_tickets':nbr_tickets, + 'nbr_tickets_unsolved':nbr_tickets_unsolved} + + return render(request,'tickets/index.html',context=context) def edit_preferences(request): """ Vue d'édition des préférences des tickets """ From 49184d32d63a59b663233effcf205257fe2ec59d Mon Sep 17 00:00:00 2001 From: Grizzly Date: Tue, 6 Aug 2019 19:27:03 +0000 Subject: [PATCH 069/228] pagination --- tickets/templates/tickets/aff_tickets.html | 11 +++++++++-- tickets/views.py | 23 ++++++++++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/tickets/templates/tickets/aff_tickets.html b/tickets/templates/tickets/aff_tickets.html index 1d447234..401d1c3c 100644 --- a/tickets/templates/tickets/aff_tickets.html +++ b/tickets/templates/tickets/aff_tickets.html @@ -37,7 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ nbr_tickets }} {% trans "Tickets" %}
    - {{ nbr_tickets_unsolved }}{% trans "Not Solved Tickets" %} + {{ nbr_tickets_unsolved }}{% trans "Not Solved Tickets" %}
    {% trans "Last Ticket:" %} {{ last_ticket_date }} @@ -46,8 +46,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    + +
    -
    + +
    @@ -76,5 +79,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    + + {% if tickets_list.paginator %} + {% include 'pagination.html' with list=tickets_list go_to_id="tickets" %} + {% endif %}
    {% endblock %} diff --git a/tickets/views.py b/tickets/views.py index 7a86ecf4..e5dd14a5 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -5,6 +5,11 @@ from django.urls import reverse from django.forms import modelformset_factory from re2o.views import form +from re2o.base import ( + re2o_paginator, +) + +from preferences.models import GeneralOption from .models import( Ticket, Preferences, @@ -56,10 +61,20 @@ def aff_ticket(request,ticketid): def aff_tickets(request): """ Vue d'affichage de tout les tickets """ - tickets = Ticket.objects.all().order_by('-date') - last_ticket_date = tickets.first().date - nbr_tickets = tickets.count() - nbr_tickets_unsolved = Ticket.objects.filter(solved=False).count() + tickets_list = Ticket.objects.all().order_by('-date') + last_ticket_date = tickets_list.first().date + nbr_tickets = tickets_list.count() + nbr_tickets_unsolved = tickets_list.filter(solved=False).count() + + pagination_number = (GeneralOption + .get_cached_value('pagination_number')) + + tickets = re2o_paginator( + request, + tickets_list, + pagination_number, + ) + context = {'tickets_list':tickets, 'last_ticket_date':last_ticket_date, 'nbr_tickets':nbr_tickets, From 02a4305cbd9fa8cee4f97cc3ad2400b9e3e68f7d Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sat, 10 Aug 2019 08:12:49 +0000 Subject: [PATCH 070/228] regle l'affichage sur le profil --- tickets/views.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tickets/views.py b/tickets/views.py index e5dd14a5..b4111204 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -103,8 +103,24 @@ def edit_preferences(request): # views cannoniques des apps optionnels def profil(request,user): """ Vue cannonique d'affichage des tickets dans l'accordeon du profil""" - tickets = Ticket.objects.filter(user=user).all().order_by('-date') - context = {'tickets_list':tickets} + tickets_list = Ticket.objects.filter(user=user).all().order_by('-date') + last_ticket_date = tickets_list.first().date + nbr_tickets = tickets_list.count() + nbr_tickets_unsolved = tickets_list.filter(solved=False).count() + + pagination_number = (GeneralOption + .get_cached_value('pagination_large_number')) + + tickets = re2o_paginator( + request, + tickets_list, + pagination_number, + ) + + context = {'tickets_list':tickets, + 'last_ticket_date':last_ticket_date, + 'nbr_tickets':nbr_tickets, + 'nbr_tickets_unsolved':nbr_tickets_unsolved} return render_to_string('tickets/profil.html', context=context, request=request, using=None) def preferences(request): From 84ab2b0cbdd4d7e7af8a53b9d14abd34ffa63900 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sat, 10 Aug 2019 08:21:24 +0000 Subject: [PATCH 071/228] Titre moche --- tickets/templates/tickets/aff_tickets.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/tickets/templates/tickets/aff_tickets.html b/tickets/templates/tickets/aff_tickets.html index 401d1c3c..56dda782 100644 --- a/tickets/templates/tickets/aff_tickets.html +++ b/tickets/templates/tickets/aff_tickets.html @@ -25,8 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc., {% load bootstrap3 %} {% load i18n %} -{% block title %}{% trans "Tickets" %}{% endblock %} - {% block content %} From f112cf3305b091fe2a30c54ff57838e33cee9b7f Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sat, 10 Aug 2019 08:53:52 +0000 Subject: [PATCH 072/228] liens des profils dans la liste des tickets --- tickets/templates/tickets/aff_tickets.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tickets/templates/tickets/aff_tickets.html b/tickets/templates/tickets/aff_tickets.html index 56dda782..ed9e1f88 100644 --- a/tickets/templates/tickets/aff_tickets.html +++ b/tickets/templates/tickets/aff_tickets.html @@ -64,7 +64,11 @@ with this program; if not, write to the Free Software Foundation, Inc., - {{ ticket.user }} + {% if ticket.user %} + {{ ticket.user.id }} + {% else %} + Anonyme + {% endif %} {{ ticket.title }} {{ ticket.date }} {% if ticket.solved %} From 9fa82776cfd22e3aa6ceba92d1d2fa8f006bf618 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sat, 10 Aug 2019 09:45:13 +0000 Subject: [PATCH 073/228] =?UTF-8?q?Envoit=20de=20mail=20=C3=A0=20l'ouvertu?= =?UTF-8?q?re=20des=20tickets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tickets/models.py | 23 ++++++++++++++++------ tickets/templates/tickets/publication_mail | 12 +++++++++++ tickets/views.py | 4 ++-- 3 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 tickets/templates/tickets/publication_mail diff --git a/tickets/models.py b/tickets/models.py index df1cd8ac..6af24c4c 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -2,6 +2,8 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from django.core.mail import send_mail from django.template import Context, loader +from django.db.models.signals import post_save +from django.dispatch import receiver import users.models @@ -46,21 +48,30 @@ class Ticket(models.Model): return "Ticket de {} date: {}".format(self.user.surname,self.date) def publish_mail(self): - template = loader.get_template('ticket/mail_publish_ticket') + to_addr = Preferences.objects.first().publish_address + template = loader.get_template('tickets/publication_mail') context = Context({'ticket':self}) send_mail( 'Nouvelle ouverture de ticket', - '', - 'ticket_app_re2o@crans.org', - '', - html_message=template.render(context)) + template.render(context), + 'grisel-davy@crans.org', + [to_addr], + fail_silently = False) class Preferences(models.Model): """ Class cannonique définissants les préférences des tickets """ - + publish_address = models.EmailField( help_text = _("Adresse mail pour annoncer les nouveau tickets (laisser vide pour ne rien annoncer)"), max_length = 1000, null = True) class Meta: verbose_name = _("Préférences des tickets") + + +@receiver(post_save, sender=Ticket) +def ticket_post_save(**kwargs): + """Envoit du mail de publication du ticket""" + if Preferences.objects.first().publish_address: + ticket = kwargs['instance'] + ticket.publish_mail() diff --git a/tickets/templates/tickets/publication_mail b/tickets/templates/tickets/publication_mail new file mode 100644 index 00000000..f68c729d --- /dev/null +++ b/tickets/templates/tickets/publication_mail @@ -0,0 +1,12 @@ +{% if ticket.user %} +{{ ticket.user.get_full_name }} à ouvert un ticket. +Répondre à l'adresse: {{ticket.user.get_mail}}. + +{% else %} +Un utilisateur anonyme (non connecté) à ouvert un ticket. +Répondre à l'adresse: {{ticket.email}}. +{% endif %} + +Titre: {{ticket.title}} + +Description: {{ticket.description}} diff --git a/tickets/views.py b/tickets/views.py index b4111204..f75b1766 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -36,11 +36,11 @@ def new_ticket(request): if request.user.is_authenticated: ticket.user = request.user ticket.save() - messages.success(request,'Votre ticket à été ouvert. Nous vous répondront le plus rapidement possible.') + messages.success(request,'Votre ticket a été ouvert. Nous vous répondrons le plus rapidement possible.') return redirect(reverse('users:profil',kwargs={'userid':str(request.user.id)})) if not request.user.is_authenticated and email != "": ticket.save() - messages.success(request,'Votre ticket à été ouvert. Nous vous répondront le plus rapidement possible.') + messages.success(request,'Votre ticket a été ouvert. Nous vous répondront le plus rapidement possible.') return redirect(reverse('index')) else: messages.error(request,"Vous n'êtes pas authentifié, veuillez vous authentifier ou fournir une adresse mail pour que nous puissions vous recontacter") From 6440ac48e86ee8aaf5d74e9cb8cf58b1e047e2d0 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sat, 10 Aug 2019 17:25:21 +0000 Subject: [PATCH 074/228] =?UTF-8?q?Inclusion=20des=20apps=20optionnels=20d?= =?UTF-8?q?ans=20le=20navbar=20(je=20sais=20pas=20trop=20pourquoi=20=C3=A7?= =?UTF-8?q?a=20marche=20=C3=A7a=20risque=20de=20casser)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- re2o/context_processors.py | 10 +++++++++- re2o/settings.py | 1 + templates/base.html | 6 +++--- tickets/views.py | 5 +++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/re2o/context_processors.py b/re2o/context_processors.py index 6beac564..739f4ab8 100644 --- a/re2o/context_processors.py +++ b/re2o/context_processors.py @@ -29,7 +29,8 @@ from django.contrib import messages from django.http import HttpRequest from preferences.models import GeneralOption, OptionalMachine from django.utils.translation import get_language - +from importlib import import_module +from re2o.settings_local import OPTIONNAL_APPS def context_user(request): """Fonction de context lorsqu'un user est logué (ou non), @@ -57,6 +58,13 @@ def context_user(request): 'ipv6_enabled': OptionalMachine.get_cached_value('ipv6'), } +def context_optionnal_apps(request): + """Fonction de context pour générer la navbar en fonction des + apps optionnels""" + optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS] + optionnal_templates_navbar_list = [app.views.navbar(request) for app in optionnal_apps] + return {'optionnal_templates_navbar_list':optionnal_templates_navbar_list} + def date_now(request): """Add the current date in the context for quick informations and diff --git a/re2o/settings.py b/re2o/settings.py index 14907570..ee219cfa 100644 --- a/re2o/settings.py +++ b/re2o/settings.py @@ -132,6 +132,7 @@ TEMPLATES = [ 'django.contrib.messages.context_processors.messages', 'django.template.context_processors.request', 're2o.context_processors.context_user', + 're2o.context_processors.context_optionnal_apps', 're2o.context_processors.date_now', ], }, diff --git a/templates/base.html b/templates/base.html index 6d39f8c8..67799c28 100644 --- a/templates/base.html +++ b/templates/base.html @@ -101,9 +101,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
  • {% trans "Manage the subscriptions" %}
  • {% acl_end %} - {% comment %} -
  • {% trans "Tickets" %}
  • - {% endcomment %} + {% for template in optionnal_templates_navbar_list%} + {{ template }} + {% endfor %} {% acl_end %} diff --git a/tickets/views.py b/tickets/views.py index f75b1766..e4ffda89 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -1,6 +1,7 @@ from django.contrib import messages from django.shortcuts import render, redirect from django.template.loader import render_to_string +from django.views.decorators.cache import cache_page from django.urls import reverse from django.forms import modelformset_factory from re2o.views import form @@ -128,3 +129,7 @@ def preferences(request): preferences = Preferences.objects.first() context = {'preferences':preferences} return render_to_string('tickets/preferences.html', context=context, request=request, using=None) + +def navbar(request): + """Vue cannonique d'affichage des tickets dans la navbar""" + return render_to_string('tickets/navbar.html') From 295f7fa5fa65afb1b9454e0e0d9c83f1b2a98cf5 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sat, 10 Aug 2019 22:41:33 +0000 Subject: [PATCH 075/228] Pas d'envoit de mail pour les updates --- tickets/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tickets/models.py b/tickets/models.py index 6af24c4c..85857a1f 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -72,6 +72,7 @@ class Preferences(models.Model): @receiver(post_save, sender=Ticket) def ticket_post_save(**kwargs): """Envoit du mail de publication du ticket""" - if Preferences.objects.first().publish_address: - ticket = kwargs['instance'] - ticket.publish_mail() + if kwargs['created']: + if Preferences.objects.first().publish_address: + ticket = kwargs['instance'] + ticket.publish_mail() From 81d2bf233abdcbe3c548f5625920801b43b3d195 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sun, 11 Aug 2019 09:03:47 +0000 Subject: [PATCH 076/228] =?UTF-8?q?Envoit=20du=20mail=20avec=20l'adresse?= =?UTF-8?q?=20sp=C3=A9cifi=C3=A9e=20dans=20les=20preferences?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tickets/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tickets/models.py b/tickets/models.py index 85857a1f..ff609437 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -5,6 +5,8 @@ from django.template import Context, loader from django.db.models.signals import post_save from django.dispatch import receiver +from preferences.models import GeneralOption + import users.models class Ticket(models.Model): @@ -54,7 +56,7 @@ class Ticket(models.Model): send_mail( 'Nouvelle ouverture de ticket', template.render(context), - 'grisel-davy@crans.org', + GeneralOption.get_cached_value('email_from'), [to_addr], fail_silently = False) From 18a97caa567debf754112a69646090d15bb80ecb Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sun, 11 Aug 2019 09:50:37 +0000 Subject: [PATCH 077/228] Changement de noms et commit du template --- re2o/context_processors.py | 2 +- tickets/templates/tickets/navbar.html | 2 ++ tickets/views.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 tickets/templates/tickets/navbar.html diff --git a/re2o/context_processors.py b/re2o/context_processors.py index 739f4ab8..ad7194cf 100644 --- a/re2o/context_processors.py +++ b/re2o/context_processors.py @@ -62,7 +62,7 @@ def context_optionnal_apps(request): """Fonction de context pour générer la navbar en fonction des apps optionnels""" optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS] - optionnal_templates_navbar_list = [app.views.navbar(request) for app in optionnal_apps] + optionnal_templates_navbar_list = [app.views.navbar_user(request) for app in optionnal_apps] return {'optionnal_templates_navbar_list':optionnal_templates_navbar_list} diff --git a/tickets/templates/tickets/navbar.html b/tickets/templates/tickets/navbar.html new file mode 100644 index 00000000..3c4318f7 --- /dev/null +++ b/tickets/templates/tickets/navbar.html @@ -0,0 +1,2 @@ +{% load i18n %} +
  • {% trans "Tickets" %}
  • diff --git a/tickets/views.py b/tickets/views.py index e4ffda89..be7cc270 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -130,6 +130,6 @@ def preferences(request): context = {'preferences':preferences} return render_to_string('tickets/preferences.html', context=context, request=request, using=None) -def navbar(request): +def navbar_user(request): """Vue cannonique d'affichage des tickets dans la navbar""" return render_to_string('tickets/navbar.html') From 0596df673f26e460637aa0a986737d6e952453fa Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sun, 11 Aug 2019 13:06:56 +0000 Subject: [PATCH 078/228] Correction d'une erreure si aucun ticket et creation des acls --- tickets/models.py | 24 +++++++++++++++++++++++- tickets/views.py | 26 ++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/tickets/models.py b/tickets/models.py index ff609437..9cdb334b 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -5,11 +5,13 @@ from django.template import Context, loader from django.db.models.signals import post_save from django.dispatch import receiver +from re2o.mixins import AclMixin + from preferences.models import GeneralOption import users.models -class Ticket(models.Model): +class Ticket(AclMixin, models.Model): """Class définissant un ticket""" user = models.ForeignKey( @@ -59,6 +61,26 @@ class Ticket(models.Model): GeneralOption.get_cached_value('email_from'), [to_addr], fail_silently = False) + + def can_view(self, user_request, *_args, **_kwargs): + """Verifie que la personne à le droit pour voir le ticket + ou qu'elle est l'auteur du ticket""" + if (not user_request.has_perm('tickets.view_ticket') and self.user != user_request): + return False, _("You don't have the right to view other Tickets than yours.") + else: + return True, None + + @staticmethod + def can_view_all(user_request, *_args, **_kwargs): + """Vérifie si l'user a acccés à la liste de tous les tickets""" + return( + user_request.has_perm('tickets.view_tickets'), + _("You don't have the right to view the list of tickets.") + ) + + def can_create(user_request,*_args, **_kwargs): + """Autorise tout les utilisateurs à créer des tickets""" + return True,None class Preferences(models.Model): """ Class cannonique définissants les préférences des tickets """ diff --git a/tickets/views.py b/tickets/views.py index be7cc270..a556efe3 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -1,4 +1,5 @@ from django.contrib import messages +from django.contrib.auth.decorators import login_required from django.shortcuts import render, redirect from django.template.loader import render_to_string from django.views.decorators.cache import cache_page @@ -10,6 +11,13 @@ from re2o.base import ( re2o_paginator, ) +from re2o.acl import( + can_view, + can_view_all, + can_edit, + can_create, +) + from preferences.models import GeneralOption from .models import( Ticket, @@ -51,6 +59,8 @@ def new_ticket(request): ticketform = NewTicketForm return form({'ticketform':ticketform,},'tickets/form_ticket.html',request) +@login_required +@can_view(Ticket) def aff_ticket(request,ticketid): """Vue d'affichage d'un ticket""" ticket = Ticket.objects.filter(id=ticketid).get() @@ -59,13 +69,18 @@ def aff_ticket(request,ticketid): ticket.solved = not ticket.solved ticket.save() return render(request,'tickets/aff_ticket.html',{'ticket':ticket,'changestatusform':changestatusform}) - + +@login_required +@can_view_all(Ticket) def aff_tickets(request): """ Vue d'affichage de tout les tickets """ tickets_list = Ticket.objects.all().order_by('-date') - last_ticket_date = tickets_list.first().date nbr_tickets = tickets_list.count() nbr_tickets_unsolved = tickets_list.filter(solved=False).count() + if nbr_tickets: + last_ticket_date = tickets_list.first().date + else: + last_ticket_date = "Jamais" pagination_number = (GeneralOption .get_cached_value('pagination_number')) @@ -105,10 +120,13 @@ def edit_preferences(request): def profil(request,user): """ Vue cannonique d'affichage des tickets dans l'accordeon du profil""" tickets_list = Ticket.objects.filter(user=user).all().order_by('-date') - last_ticket_date = tickets_list.first().date nbr_tickets = tickets_list.count() nbr_tickets_unsolved = tickets_list.filter(solved=False).count() - + if nbr_tickets: + last_ticket_date = tickets_list.first().date + else: + last_ticket_date = "Jamais" + pagination_number = (GeneralOption .get_cached_value('pagination_large_number')) From a42624d0d9db8094add7728fc65053b703f31d0d Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sun, 11 Aug 2019 14:01:44 +0000 Subject: [PATCH 079/228] Acl pour le visualisation des tickets --- tickets/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tickets/views.py b/tickets/views.py index a556efe3..52b4f68f 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -61,9 +61,8 @@ def new_ticket(request): @login_required @can_view(Ticket) -def aff_ticket(request,ticketid): +def aff_ticket(request, ticket, ticketid): """Vue d'affichage d'un ticket""" - ticket = Ticket.objects.filter(id=ticketid).get() changestatusform = ChangeStatusTicketForm(request.POST) if request.method == 'POST': ticket.solved = not ticket.solved @@ -98,6 +97,7 @@ def aff_tickets(request): return render(request,'tickets/index.html',context=context) + def edit_preferences(request): """ Vue d'édition des préférences des tickets """ From a0dcda697542a136358bef52a202f79a7cb3d1b9 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sun, 11 Aug 2019 16:03:45 +0000 Subject: [PATCH 080/228] Vues cannoniques navbar et adresses de contact --- re2o/context_processors.py | 6 ++++-- re2o/templates/re2o/contact.html | 4 ++++ re2o/views.py | 8 +++++++- templates/base.html | 5 ++++- tickets/templates/tickets/contact.html | 13 +++++++++++++ tickets/templates/tickets/navbar_logout.html | 6 ++++++ tickets/views.py | 12 +++++++++++- 7 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 tickets/templates/tickets/contact.html create mode 100644 tickets/templates/tickets/navbar_logout.html diff --git a/re2o/context_processors.py b/re2o/context_processors.py index ad7194cf..860a5a58 100644 --- a/re2o/context_processors.py +++ b/re2o/context_processors.py @@ -62,8 +62,10 @@ def context_optionnal_apps(request): """Fonction de context pour générer la navbar en fonction des apps optionnels""" optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS] - optionnal_templates_navbar_list = [app.views.navbar_user(request) for app in optionnal_apps] - return {'optionnal_templates_navbar_list':optionnal_templates_navbar_list} + optionnal_templates_navbar_user_list = [app.views.navbar_user(request) for app in optionnal_apps] + optionnal_templates_navbar_logout_list = [app.views.navbar_logout(request) for app in optionnal_apps] + return {'optionnal_templates_navbar_user_list':optionnal_templates_navbar_user_list, + 'optionnal_templates_navbar_logout_list':optionnal_templates_navbar_logout_list} def date_now(request): diff --git a/re2o/templates/re2o/contact.html b/re2o/templates/re2o/contact.html index b20fe875..05b34655 100644 --- a/re2o/templates/re2o/contact.html +++ b/re2o/templates/re2o/contact.html @@ -31,6 +31,10 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block content %}

    {% blocktrans %}Contact the organisation {{asso_name}}{% endblocktrans %}


    + +{% for template in optionnal_templates_contact_list %} + {{template}} +{% endfor %} {% for contact in contacts %} diff --git a/re2o/views.py b/re2o/views.py index aa85e997..c4c8b72e 100644 --- a/re2o/views.py +++ b/re2o/views.py @@ -43,6 +43,8 @@ from preferences.models import ( ) from .contributors import CONTRIBUTORS +from importlib import import_module +from re2o.settings_local import OPTIONNAL_APPS def form(ctx, template, request): @@ -113,12 +115,16 @@ def contact_page(request): """ address = MailContact.objects.all() + optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS] + optionnal_templates_contact_list = [app.views.contact(request) for app in optionnal_apps] + return render( request, "re2o/contact.html", { 'contacts': address, - 'asso_name': AssoOption.objects.first().name + 'asso_name': AssoOption.objects.first().name, + 'optionnal_templates_contact_list':optionnal_templates_contact_list, } ) diff --git a/templates/base.html b/templates/base.html index 67799c28..de6f308c 100644 --- a/templates/base.html +++ b/templates/base.html @@ -101,7 +101,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
  • {% trans "Manage the subscriptions" %}
  • {% acl_end %} - {% for template in optionnal_templates_navbar_list%} + {% for template in optionnal_templates_navbar_user_list%} {{ template }} {% endfor %} @@ -140,6 +140,9 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if not request.user.is_authenticated %} + {% for template in optionnal_templates_navbar_logout_list %} + {{ template }} + {% endfor %} {% if var_sa %}
  • diff --git a/tickets/templates/tickets/contact.html b/tickets/templates/tickets/contact.html new file mode 100644 index 00000000..0a348f01 --- /dev/null +++ b/tickets/templates/tickets/contact.html @@ -0,0 +1,13 @@ +{% load i18n %} + + diff --git a/tickets/templates/tickets/navbar_logout.html b/tickets/templates/tickets/navbar_logout.html new file mode 100644 index 00000000..8a7114f3 --- /dev/null +++ b/tickets/templates/tickets/navbar_logout.html @@ -0,0 +1,6 @@ +{% load i18n %} +
  • + + {% trans "Ouvrir un ticket" %} + +
  • diff --git a/tickets/views.py b/tickets/views.py index 52b4f68f..26dce0cd 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -148,6 +148,16 @@ def preferences(request): context = {'preferences':preferences} return render_to_string('tickets/preferences.html', context=context, request=request, using=None) +def contact(request): + """Vue cannonique d'affichage d'une adresse dans la page contact. + Utilisée ici pour proposer l'ouverture d'un ticket""" + return render_to_string('tickets/contact.html') + def navbar_user(request): """Vue cannonique d'affichage des tickets dans la navbar""" - return render_to_string('tickets/navbar.html') + return render_to_string('tickets/navbar.html') + +def navbar_logout(request): + """Vue cannonique d'affichage du lien de creation de ticket + lorsque l'utilisateur est déconnecté dans la navbar""" + return render_to_string('tickets/navbar_logout.html') From 3a5fad0287b5bc605e8984c6c4a7301f3df42c58 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Sun, 11 Aug 2019 19:51:31 +0000 Subject: [PATCH 081/228] =?UTF-8?q?Separation=20des=20lists=20d'apps=20opt?= =?UTF-8?q?ionnelles=20pour=20eviter=20les=20erreurs=20d'import=20d'urls?= =?UTF-8?q?=20non=20pr=C3=A9sents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- preferences/views.py | 4 ++-- re2o/context_processors.py | 4 ++-- re2o/settings_local.example.py | 5 ++++- re2o/urls.py | 4 ++-- re2o/views.py | 4 ++-- users/views.py | 4 ++-- 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/preferences/views.py b/preferences/views.py index 680fcac0..471207e0 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -41,7 +41,7 @@ from django.utils.translation import ugettext as _ from reversion import revisions as reversion from importlib import import_module -from re2o.settings_local import OPTIONNAL_APPS +from re2o.settings_local import OPTIONNAL_APPS_RE2O from re2o.views import form from re2o.acl import can_create, can_edit, can_delete_set, can_view_all, can_delete @@ -97,7 +97,7 @@ def display_options(request): cotisationsoptions, _created = CotisationsOption.objects.get_or_create() document_template_list = DocumentTemplate.objects.order_by('name') - optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS] + optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] optionnal_templates_list = [app.views.preferences(request) for app in optionnal_apps] return form({ diff --git a/re2o/context_processors.py b/re2o/context_processors.py index 860a5a58..67a700be 100644 --- a/re2o/context_processors.py +++ b/re2o/context_processors.py @@ -30,7 +30,7 @@ from django.http import HttpRequest from preferences.models import GeneralOption, OptionalMachine from django.utils.translation import get_language from importlib import import_module -from re2o.settings_local import OPTIONNAL_APPS +from re2o.settings_local import OPTIONNAL_APPS_RE2O def context_user(request): """Fonction de context lorsqu'un user est logué (ou non), @@ -61,7 +61,7 @@ def context_user(request): def context_optionnal_apps(request): """Fonction de context pour générer la navbar en fonction des apps optionnels""" - optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS] + optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] optionnal_templates_navbar_user_list = [app.views.navbar_user(request) for app in optionnal_apps] optionnal_templates_navbar_logout_list = [app.views.navbar_logout(request) for app in optionnal_apps] return {'optionnal_templates_navbar_user_list':optionnal_templates_navbar_user_list, diff --git a/re2o/settings_local.example.py b/re2o/settings_local.example.py index 662c1447..bb0fd21e 100644 --- a/re2o/settings_local.example.py +++ b/re2o/settings_local.example.py @@ -108,5 +108,8 @@ GID_RANGES = { 'posix': [501, 600], } +# Some optionnal Re2o Apps +OPTIONNAL_APPS_RE2O = () + # Some Django apps you want to add in you local project -OPTIONNAL_APPS = () +OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + () diff --git a/re2o/urls.py b/re2o/urls.py index 5db9abe8..8af7335a 100644 --- a/re2o/urls.py +++ b/re2o/urls.py @@ -49,7 +49,7 @@ from django.contrib import admin from django.utils.translation import gettext_lazy as _ from django.views.generic import RedirectView -from .settings_local import OPTIONNAL_APPS +from .settings_local import OPTIONNAL_APPS_RE2O from .views import index, about_page, contact_page @@ -87,7 +87,7 @@ urlpatterns = [ ] -urlpatterns += [url(r'^{}/'.format(app), include('{}.urls'.format(app), namespace=app)) for app in OPTIONNAL_APPS] +urlpatterns += [url(r'^{}/'.format(app), include('{}.urls'.format(app), namespace=app)) for app in OPTIONNAL_APPS_RE2O] # Add debug_toolbar URLs if activated if 'debug_toolbar' in settings.INSTALLED_APPS: diff --git a/re2o/views.py b/re2o/views.py index c4c8b72e..17622fd5 100644 --- a/re2o/views.py +++ b/re2o/views.py @@ -44,7 +44,7 @@ from preferences.models import ( from .contributors import CONTRIBUTORS from importlib import import_module -from re2o.settings_local import OPTIONNAL_APPS +from re2o.settings_local import OPTIONNAL_APPS_RE2O def form(ctx, template, request): @@ -115,7 +115,7 @@ def contact_page(request): """ address = MailContact.objects.all() - optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS] + optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] optionnal_templates_contact_list = [app.views.contact(request) for app in optionnal_apps] return render( diff --git a/users/views.py b/users/views.py index 426645e5..045446b1 100644 --- a/users/views.py +++ b/users/views.py @@ -57,7 +57,7 @@ from machines.models import Machine from preferences.models import OptionalUser, GeneralOption, AssoOption from importlib import import_module -from re2o.settings_local import OPTIONNAL_APPS +from re2o.settings_local import OPTIONNAL_APPS_RE2O from re2o.views import form from re2o.utils import ( all_has_access, @@ -979,7 +979,7 @@ def profil(request, users, **_kwargs): SortTable.MACHINES_INDEX ) - optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS] + optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] optionnal_templates_list = [app.views.profil(request,users) for app in optionnal_apps] pagination_large_number = GeneralOption.get_cached_value( From cb3fdff202f601c26be58637e2bcfcaba0b9e007 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Tue, 13 Aug 2019 13:05:12 +0000 Subject: [PATCH 082/228] =?UTF-8?q?r=C3=A9partition=20des=20preferences=20?= =?UTF-8?q?et=20squash=20des=20migrations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tickets/forms.py | 5 +- ...0008_remove_preferences_publish_tickets.py | 48 +++++++++++++++++++ tickets/models.py | 5 +- tickets/preferences/forms.py | 11 +++++ tickets/preferences/models.py | 12 +++++ tickets/views.py | 8 ++++ 6 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 tickets/migrations/0001_squashed_0008_remove_preferences_publish_tickets.py create mode 100644 tickets/preferences/forms.py create mode 100644 tickets/preferences/models.py diff --git a/tickets/forms.py b/tickets/forms.py index 4bb59458..5e565cc7 100644 --- a/tickets/forms.py +++ b/tickets/forms.py @@ -6,7 +6,6 @@ from django.utils.translation import ugettext_lazy as _ from .models import( Ticket, - Preferences, ) class EditTicketForm(FormRevMixin, ModelForm): @@ -22,12 +21,12 @@ class NewTicketForm(ModelForm): class Meta: model = Ticket fields = ['title', 'description', 'email'] - +""" class EditPreferencesForm(ModelForm): - """ Edition des préférences des tickets """ class Meta: model = Preferences fields = '__all__' +""" class ChangeStatusTicketForm(ModelForm): """ Passe un Ticket en résolu """ diff --git a/tickets/migrations/0001_squashed_0008_remove_preferences_publish_tickets.py b/tickets/migrations/0001_squashed_0008_remove_preferences_publish_tickets.py new file mode 100644 index 00000000..2b42726e --- /dev/null +++ b/tickets/migrations/0001_squashed_0008_remove_preferences_publish_tickets.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-08-13 12:55 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + replaces = [('tickets', '0001_initial'), ('tickets', '0002_auto_20190710_0952'), ('tickets', '0003_ticket_email'), ('tickets', '0004_auto_20190712_1205'), ('tickets', '0005_auto_20190712_1209'), ('tickets', '0006_preferences'), ('tickets', '0007_preferences_publish_tickets'), ('tickets', '0008_remove_preferences_publish_tickets')] + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Ticket', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(help_text='Nom du ticket', max_length=255)), + ('description', models.TextField(help_text='Description du ticket', max_length=3000)), + ('date', models.DateTimeField(auto_now_add=True)), + ('solved', models.BooleanField(default=False)), + ('assigned_staff', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='tickets_assigned', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tickets', to=settings.AUTH_USER_MODEL)), + ('email', models.EmailField(help_text='Une adresse mail pour vous recontacter', max_length=100, null=True)), + ], + options={ + 'verbose_name_plural': 'Tickets', + 'verbose_name': 'Ticket', + }, + ), + migrations.CreateModel( + name='Preferences', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('publish_address', models.EmailField(help_text='Adresse mail pour annoncer les nouveau tickets (laisser vide pour ne rien annoncer)', max_length=1000, null=True)), + ], + options={ + 'verbose_name': 'Préférences des tickets', + }, + ), + ] diff --git a/tickets/models.py b/tickets/models.py index 9cdb334b..ed446064 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -81,9 +81,8 @@ class Ticket(AclMixin, models.Model): def can_create(user_request,*_args, **_kwargs): """Autorise tout les utilisateurs à créer des tickets""" return True,None - +""" class Preferences(models.Model): - """ Class cannonique définissants les préférences des tickets """ publish_address = models.EmailField( help_text = _("Adresse mail pour annoncer les nouveau tickets (laisser vide pour ne rien annoncer)"), @@ -91,7 +90,7 @@ class Preferences(models.Model): null = True) class Meta: verbose_name = _("Préférences des tickets") - +""" @receiver(post_save, sender=Ticket) def ticket_post_save(**kwargs): diff --git a/tickets/preferences/forms.py b/tickets/preferences/forms.py new file mode 100644 index 00000000..9aa7319e --- /dev/null +++ b/tickets/preferences/forms.py @@ -0,0 +1,11 @@ +from django import forms +from django.forms import ModelForm, Form +from django.utils.translation import ugettext_lazy as _ + +from .models import Preferences + +class EditPreferencesForm(ModelForm): + """ Edition des préférences des tickets """ + class Meta: + model = Preferences + fields = '__all__' diff --git a/tickets/preferences/models.py b/tickets/preferences/models.py new file mode 100644 index 00000000..62a98a09 --- /dev/null +++ b/tickets/preferences/models.py @@ -0,0 +1,12 @@ +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +class Preferences(models.Model): + """ Class cannonique définissants les préférences des tickets """ + + publish_address = models.EmailField( + help_text = _("Adresse mail pour annoncer les nouveau tickets (laisser vide pour ne rien annoncer)"), + max_length = 1000, + null = True) + class Meta: + verbose_name = _("Préférences des tickets") diff --git a/tickets/views.py b/tickets/views.py index 26dce0cd..b09ef3e4 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -19,18 +19,26 @@ from re2o.acl import( ) from preferences.models import GeneralOption + from .models import( Ticket, +) + +from .preferences.models import( Preferences, ) from .forms import ( NewTicketForm, ChangeStatusTicketForm, +) + +from .preferences.forms import ( EditPreferencesForm, ) + def new_ticket(request): """ Vue de création d'un ticket """ ticketform = NewTicketForm(request.POST or None) From 19f4fdbf97876e0b2514dc3124dccd33335c2ee8 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Wed, 14 Aug 2019 15:09:46 +0000 Subject: [PATCH 083/228] Ajout d'un lien vers le profil dans le mail --- tickets/models.py | 10 ++++++++-- tickets/templates/tickets/publication_mail | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tickets/models.py b/tickets/models.py index ed446064..5ec2e544 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -11,6 +11,8 @@ from preferences.models import GeneralOption import users.models +from .preferences.models import Preferences + class Ticket(AclMixin, models.Model): """Class définissant un ticket""" @@ -49,12 +51,16 @@ class Ticket(AclMixin, models.Model): verbose_name_plural = _("Tickets") def __str__(self): - return "Ticket de {} date: {}".format(self.user.surname,self.date) + if self.user: + return "Ticket de {}. Date: {}".format(self.user.surname,self.date) + else: + return "Ticket anonyme. Date: {}".format(self.date) def publish_mail(self): + site_url = GeneralOption.objects.first().main_site_url to_addr = Preferences.objects.first().publish_address template = loader.get_template('tickets/publication_mail') - context = Context({'ticket':self}) + context = Context({'ticket':self,'site_url':site_url}) send_mail( 'Nouvelle ouverture de ticket', template.render(context), diff --git a/tickets/templates/tickets/publication_mail b/tickets/templates/tickets/publication_mail index f68c729d..1f3752be 100644 --- a/tickets/templates/tickets/publication_mail +++ b/tickets/templates/tickets/publication_mail @@ -1,5 +1,5 @@ -{% if ticket.user %} -{{ ticket.user.get_full_name }} à ouvert un ticket. +{% if ticket.user %} {{ ticket.user.get_full_name }} à ouvert un ticket. +Profile: {{site_url}}{% url 'users:profil' ticket.user.id%} Répondre à l'adresse: {{ticket.user.get_mail}}. {% else %} From d59783fd6bfd4c2afd07c3411dc7abbea0590629 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Wed, 14 Aug 2019 17:07:31 +0000 Subject: [PATCH 084/228] Affichage du nom et pas de l'id --- tickets/templates/tickets/aff_tickets.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tickets/templates/tickets/aff_tickets.html b/tickets/templates/tickets/aff_tickets.html index ed9e1f88..6bb062fb 100644 --- a/tickets/templates/tickets/aff_tickets.html +++ b/tickets/templates/tickets/aff_tickets.html @@ -65,7 +65,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if ticket.user %} - {{ ticket.user.id }} + {{ ticket.user.get_short_name }} {% else %} Anonyme {% endif %} From 0f203f43e46b5178f15bb4ebeb2df133916e9ae2 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Wed, 14 Aug 2019 17:39:19 +0000 Subject: [PATCH 085/228] La doc en anglais et le commentaires en moins --- tickets/forms.py | 16 ++-------- tickets/models.py | 41 +++++++----------------- tickets/preferences/forms.py | 2 +- tickets/preferences/models.py | 6 ++-- tickets/views.py | 60 +++++++++++++++++++++++++---------- 5 files changed, 61 insertions(+), 64 deletions(-) diff --git a/tickets/forms.py b/tickets/forms.py index 5e565cc7..bbeea0c4 100644 --- a/tickets/forms.py +++ b/tickets/forms.py @@ -8,28 +8,16 @@ from .models import( Ticket, ) -class EditTicketForm(FormRevMixin, ModelForm): - """Formulaire d'edition d'un Ticket""" - class Meta: - model = Ticket - exclude = ['user','assigned_staff','date'] - class NewTicketForm(ModelForm): - """ Creation d'une machine""" + """ Creation of a ticket""" email = forms.EmailField(required=False) class Meta: model = Ticket fields = ['title', 'description', 'email'] -""" -class EditPreferencesForm(ModelForm): - class Meta: - model = Preferences - fields = '__all__' -""" class ChangeStatusTicketForm(ModelForm): - """ Passe un Ticket en résolu """ + """ Change ticket status""" class Meta: model = Ticket fields = [] diff --git a/tickets/models.py b/tickets/models.py index 5ec2e544..9c21fb74 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -14,7 +14,7 @@ import users.models from .preferences.models import Preferences class Ticket(AclMixin, models.Model): - """Class définissant un ticket""" + """Model of a ticket""" user = models.ForeignKey( 'users.User', @@ -24,26 +24,19 @@ class Ticket(AclMixin, models.Model): null=True) title = models.CharField( max_length=255, - help_text=_("Nom du ticket"), + help_text=_("Title of the ticket"), blank=False, null=False,) description = models.TextField( max_length=3000, - help_text=_("Description du ticket"), + help_text=_("Description of the ticket"), blank=False, null=False) date = models.DateTimeField(auto_now_add=True) email = models.EmailField( - help_text = _("Une adresse mail pour vous recontacter"), + help_text = _("An email address to get back to you"), max_length=100, null=True) - assigned_staff = models.ForeignKey( - 'users.User', - on_delete=models.PROTECT, - related_name="tickets_assigned", - blank=True, - null=True) - #categories = models.OneToManyFiled('Category') solved = models.BooleanField(default=False) class Meta: @@ -52,9 +45,9 @@ class Ticket(AclMixin, models.Model): def __str__(self): if self.user: - return "Ticket de {}. Date: {}".format(self.user.surname,self.date) + return "Ticket from {}. Date: {}".format(self.user.surname,self.date) else: - return "Ticket anonyme. Date: {}".format(self.date) + return "Anonymous Ticket. Date: {}".format(self.date) def publish_mail(self): site_url = GeneralOption.objects.first().main_site_url @@ -69,38 +62,28 @@ class Ticket(AclMixin, models.Model): fail_silently = False) def can_view(self, user_request, *_args, **_kwargs): - """Verifie que la personne à le droit pour voir le ticket - ou qu'elle est l'auteur du ticket""" + """ Check that the user has the right to view the ticket + or that it is the author""" if (not user_request.has_perm('tickets.view_ticket') and self.user != user_request): - return False, _("You don't have the right to view other Tickets than yours.") + return False, _("You don't have the right to view other tickets than yours.") else: return True, None @staticmethod def can_view_all(user_request, *_args, **_kwargs): - """Vérifie si l'user a acccés à la liste de tous les tickets""" + """ Check that the user has access to the list of all tickets""" return( user_request.has_perm('tickets.view_tickets'), _("You don't have the right to view the list of tickets.") ) def can_create(user_request,*_args, **_kwargs): - """Autorise tout les utilisateurs à créer des tickets""" + """ Authorise all users to open tickets """ return True,None -""" -class Preferences(models.Model): - - publish_address = models.EmailField( - help_text = _("Adresse mail pour annoncer les nouveau tickets (laisser vide pour ne rien annoncer)"), - max_length = 1000, - null = True) - class Meta: - verbose_name = _("Préférences des tickets") -""" @receiver(post_save, sender=Ticket) def ticket_post_save(**kwargs): - """Envoit du mail de publication du ticket""" + """ Send the mail to publish the new ticket """ if kwargs['created']: if Preferences.objects.first().publish_address: ticket = kwargs['instance'] diff --git a/tickets/preferences/forms.py b/tickets/preferences/forms.py index 9aa7319e..5bdc65d2 100644 --- a/tickets/preferences/forms.py +++ b/tickets/preferences/forms.py @@ -5,7 +5,7 @@ from django.utils.translation import ugettext_lazy as _ from .models import Preferences class EditPreferencesForm(ModelForm): - """ Edition des préférences des tickets """ + """ Edit the ticket's settings""" class Meta: model = Preferences fields = '__all__' diff --git a/tickets/preferences/models.py b/tickets/preferences/models.py index 62a98a09..684c192e 100644 --- a/tickets/preferences/models.py +++ b/tickets/preferences/models.py @@ -2,11 +2,11 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ class Preferences(models.Model): - """ Class cannonique définissants les préférences des tickets """ + """ Definition of the ticket's settings""" publish_address = models.EmailField( - help_text = _("Adresse mail pour annoncer les nouveau tickets (laisser vide pour ne rien annoncer)"), + help_text = _("Email address to publish the new tickets (leave empty for no publications)"), max_length = 1000, null = True) class Meta: - verbose_name = _("Préférences des tickets") + verbose_name = _("Ticket's settings") diff --git a/tickets/views.py b/tickets/views.py index b09ef3e4..26b5cad5 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -1,8 +1,36 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2017 Gabriel Détraz +# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Augustin Lemesle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# App de gestion des users pour re2o +# Goulven Kermarec, Gabriel Détraz, Lemesle Augustin +# Gplv2 + from django.contrib import messages from django.contrib.auth.decorators import login_required from django.shortcuts import render, redirect from django.template.loader import render_to_string from django.views.decorators.cache import cache_page +from django.utils.translation import ugettext as _ from django.urls import reverse from django.forms import modelformset_factory from re2o.views import form @@ -40,7 +68,7 @@ from .preferences.forms import ( def new_ticket(request): - """ Vue de création d'un ticket """ + """ Ticket creation view""" ticketform = NewTicketForm(request.POST or None) if request.method == 'POST': @@ -49,18 +77,17 @@ def new_ticket(request): if ticketform.is_valid(): email = ticketform.cleaned_data.get('email') ticket = ticketform.save(commit=False) - #raise ValueError("email: {} type: {}".format(email,type(email))) if request.user.is_authenticated: ticket.user = request.user ticket.save() - messages.success(request,'Votre ticket a été ouvert. Nous vous répondrons le plus rapidement possible.') + messages.success(request,_('Your ticket has been succesfully open. We will take care of it as soon as possible.')) return redirect(reverse('users:profil',kwargs={'userid':str(request.user.id)})) if not request.user.is_authenticated and email != "": ticket.save() - messages.success(request,'Votre ticket a été ouvert. Nous vous répondront le plus rapidement possible.') + messages.success(request,_('Your ticket has been succesfully open. We will take care of it as soon as possible.')) return redirect(reverse('index')) else: - messages.error(request,"Vous n'êtes pas authentifié, veuillez vous authentifier ou fournir une adresse mail pour que nous puissions vous recontacter") + messages.error(request,_("You are not authenticated. Please login or provide an email address so we can get back to you.")) return form({'ticketform':ticketform,},'tickets/form_ticket.html',request) else: @@ -70,7 +97,7 @@ def new_ticket(request): @login_required @can_view(Ticket) def aff_ticket(request, ticket, ticketid): - """Vue d'affichage d'un ticket""" + """View to display only one ticket""" changestatusform = ChangeStatusTicketForm(request.POST) if request.method == 'POST': ticket.solved = not ticket.solved @@ -80,14 +107,14 @@ def aff_ticket(request, ticket, ticketid): @login_required @can_view_all(Ticket) def aff_tickets(request): - """ Vue d'affichage de tout les tickets """ + """ View to display all the tickets """ tickets_list = Ticket.objects.all().order_by('-date') nbr_tickets = tickets_list.count() nbr_tickets_unsolved = tickets_list.filter(solved=False).count() if nbr_tickets: last_ticket_date = tickets_list.first().date else: - last_ticket_date = "Jamais" + last_ticket_date = _("Never") pagination_number = (GeneralOption .get_cached_value('pagination_number')) @@ -107,7 +134,7 @@ def aff_tickets(request): def edit_preferences(request): - """ Vue d'édition des préférences des tickets """ + """ View to edit the settings of the tickets """ preferences_instance, created = Preferences.objects.get_or_create(id=1) preferencesform = EditPreferencesForm( @@ -126,14 +153,14 @@ def edit_preferences(request): # views cannoniques des apps optionnels def profil(request,user): - """ Vue cannonique d'affichage des tickets dans l'accordeon du profil""" + """ View to display the ticket's module on the profil""" tickets_list = Ticket.objects.filter(user=user).all().order_by('-date') nbr_tickets = tickets_list.count() nbr_tickets_unsolved = tickets_list.filter(solved=False).count() if nbr_tickets: last_ticket_date = tickets_list.first().date else: - last_ticket_date = "Jamais" + last_ticket_date = _("Never") pagination_number = (GeneralOption .get_cached_value('pagination_large_number')) @@ -151,21 +178,20 @@ def profil(request,user): return render_to_string('tickets/profil.html', context=context, request=request, using=None) def preferences(request): - """ Vue cannonique d'affichage des tickets dans l'affichage du profil""" + """ View to display the settings of the tickets in the preferences page""" preferences = Preferences.objects.first() context = {'preferences':preferences} return render_to_string('tickets/preferences.html', context=context, request=request, using=None) def contact(request): - """Vue cannonique d'affichage d'une adresse dans la page contact. - Utilisée ici pour proposer l'ouverture d'un ticket""" + """View to display a contact address on the contact page + used here to display a link to open a ticket""" return render_to_string('tickets/contact.html') def navbar_user(request): - """Vue cannonique d'affichage des tickets dans la navbar""" + """View to display the ticket link in thet user's dropdown in the navbar""" return render_to_string('tickets/navbar.html') def navbar_logout(request): - """Vue cannonique d'affichage du lien de creation de ticket - lorsque l'utilisateur est déconnecté dans la navbar""" + """View to display the ticket link to log out users""" return render_to_string('tickets/navbar_logout.html') From 5e3fb3044196764a5332023b9145a4c172ef1314 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Wed, 14 Aug 2019 17:48:58 +0000 Subject: [PATCH 086/228] traduction --- tickets/templates/tickets/aff_ticket.html | 2 +- tickets/templates/tickets/contact.html | 2 +- tickets/templates/tickets/form_preferences.html | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tickets/templates/tickets/aff_ticket.html b/tickets/templates/tickets/aff_ticket.html index 7bf5b04d..ede878b3 100644 --- a/tickets/templates/tickets/aff_ticket.html +++ b/tickets/templates/tickets/aff_ticket.html @@ -51,7 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% endif %} {{ ticket.date | naturalday}}. {% if not ticket.user %} - {% trans "Response address: " %}{{ticket.email}} + {% trans "Response address: " %}{{ticket.email}} {% endif %}
    diff --git a/tickets/templates/tickets/contact.html b/tickets/templates/tickets/contact.html index 0a348f01..475af26d 100644 --- a/tickets/templates/tickets/contact.html +++ b/tickets/templates/tickets/contact.html @@ -5,7 +5,7 @@
    - {% blocktrans %} Si vous rencontrez des problème concernant les services proposés par l'association {{ asso_name }}, il vous est possible d'ouvir un ticket qui sera traité par les membres actifs de l'association. Si vous souhaitez nous contacter pour une question autres qu'un problème technique, choisissez l'une des adresses mail ci-dessous. {% endblocktrans %} + {% blocktrans %}If you are experiencing issues with the services offered by {{asso_name}}, you can open a ticket that will be taken care of. If you want to contact us on any other topic, please choose one address below.{% endblocktrans %}
    diff --git a/tickets/templates/tickets/form_preferences.html b/tickets/templates/tickets/form_preferences.html index 83339484..03a6a333 100644 --- a/tickets/templates/tickets/form_preferences.html +++ b/tickets/templates/tickets/form_preferences.html @@ -25,13 +25,12 @@ with this program; if not, write to the Free Software Foundation, Inc., {% endcomment %} {% load bootstrap3 %} -{% load massive_bootstrap_form %} {% load i18n %} {% block title %}{% trans "Ticket" %}{% endblock %} {% block content %} -

    Edition des préférences des Tickets

    +

    {% trans "Tickets settings modification" %}

    {% for message in messages %}
    From 8e2e36c882c00e405d334e5e5c619f8ed93c9ad1 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Fri, 16 Aug 2019 13:43:32 +0000 Subject: [PATCH 087/228] =?UTF-8?q?migrations=20compress=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...uashed_0007_preferences_publish_tickets.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 tickets/migrations/0001_squashed_0007_preferences_publish_tickets.py diff --git a/tickets/migrations/0001_squashed_0007_preferences_publish_tickets.py b/tickets/migrations/0001_squashed_0007_preferences_publish_tickets.py new file mode 100644 index 00000000..b2293a4a --- /dev/null +++ b/tickets/migrations/0001_squashed_0007_preferences_publish_tickets.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-08-16 13:41 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + replaces = [('tickets', '0001_initial'), ('tickets', '0002_auto_20190710_0952'), ('tickets', '0003_ticket_email'), ('tickets', '0004_auto_20190712_1205'), ('tickets', '0005_auto_20190712_1209'), ('tickets', '0006_preferences'), ('tickets', '0007_preferences_publish_tickets')] + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Ticket', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(help_text='Nom du ticket', max_length=255)), + ('description', models.TextField(help_text='Description du ticket', max_length=3000)), + ('date', models.DateTimeField(auto_now_add=True)), + ('solved', models.BooleanField(default=False)), + ('assigned_staff', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='tickets_assigned', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tickets', to=settings.AUTH_USER_MODEL)), + ('email', models.EmailField(help_text='Une adresse mail pour vous recontacter', max_length=100, null=True)), + ], + options={ + 'verbose_name': 'Ticket', + 'verbose_name_plural': 'Tickets', + }, + ), + migrations.CreateModel( + name='Preferences', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('publish_address', models.EmailField(help_text='Adresse mail pour annoncer les nouveau tickets (laisser vide pour ne rien annoncer)', max_length=1000, null=True)), + ('publish_tickets', models.BooleanField(default=True, help_text='Publier ou pas les tickets')), + ], + options={ + 'verbose_name': 'Préférences des tickets', + }, + ), + ] From b0fb188e24b7e11bb018b1b8803c6b898c2486e0 Mon Sep 17 00:00:00 2001 From: Grizzly Date: Fri, 16 Aug 2019 14:13:20 +0000 Subject: [PATCH 088/228] =?UTF-8?q?menu=20deroulant=20et=20migrations=20su?= =?UTF-8?q?pprim=C3=A9e=20oubli=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/base.html | 2 +- ...0008_remove_preferences_publish_tickets.py | 48 ------------------- 2 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 tickets/migrations/0001_squashed_0008_remove_preferences_publish_tickets.py diff --git a/templates/base.html b/templates/base.html index de6f308c..7a2074f2 100644 --- a/templates/base.html +++ b/templates/base.html @@ -130,7 +130,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    +
    {% trans "RADIUS policies" %}
    {% trans "Edit" %} {% include 'preferences/aff_radiusoptions.html' %} +
    {% trans "Available RADIUS attributes"%}
    + {% trans " Add an attribute" %} + {% include 'preferences/aff_radiusattributes.html' %}
    diff --git a/preferences/urls.py b/preferences/urls.py index 9bfd67d3..d07aa0be 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -126,5 +126,12 @@ urlpatterns = [ views.del_document_template, name='del-document-template' ), + url(r'^add_radiusattribute/$', views.add_radiusattribute, name='add-radiusattribute'), + url( + r'^edit_radiusattribute/(?P[0-9]+)$', + views.edit_radiusattribute, + name='edit-radiusattribute' + ), + url(r'^del_radiusattribute/(?P[0-9]+)$', views.del_radiusattribute, name='del-radiusattribute'), url(r'^$', views.display_options, name='display-options'), ] diff --git a/preferences/views.py b/preferences/views.py index 90afa2e8..5ccd7cad 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -52,7 +52,9 @@ from .forms import ( RadiusKeyForm, SwitchManagementCredForm, DocumentTemplateForm, - DelDocumentTemplateForm + DelDocumentTemplateForm, + RadiusAttributeForm, + DelRadiusAttributeForm ) from .models import ( Service, @@ -69,7 +71,8 @@ from .models import ( SwitchManagementCred, RadiusOption, CotisationsOption, - DocumentTemplate + DocumentTemplate, + RadiusAttribute ) from . import models from . import forms @@ -94,6 +97,7 @@ def display_options(request): radiuskey_list = RadiusKey.objects.all() switchmanagementcred_list = SwitchManagementCred.objects.all() radiusoptions, _ = RadiusOption.objects.get_or_create() + radius_attributes = RadiusAttribute.objects.all() cotisationsoptions, _created = CotisationsOption.objects.get_or_create() document_template_list = DocumentTemplate.objects.order_by('name') @@ -114,6 +118,7 @@ def display_options(request): 'radiuskey_list' : radiuskey_list, 'switchmanagementcred_list': switchmanagementcred_list, 'radiusoptions' : radiusoptions, + 'radius_attributes' : radius_attributes, 'cotisationsoptions': cotisationsoptions, 'optionnal_templates_list': optionnal_templates_list, 'document_template_list': document_template_list, @@ -502,3 +507,54 @@ def del_document_template(request, instances): 'action_name': _("Delete"), 'title': _("Delete document template") }, 'preferences/preferences.html', request) + + +@login_required +@can_create(RadiusAttribute) +def add_radiusattribute(request): + """Create a RADIUS attribute.""" + attribute = RadiusAttributeForm(request.POST or None) + if attribute.is_valid(): + attribute.save() + messages.success(request, _("The attribute was added.")) + return redirect(reverse('preferences:display-options')) + return form( + {'preferenceform': attribute, 'action_name': _("Add a RADIUS attribute")}, + 'preferences/preferences.html', + request + ) + + +@login_required +@can_edit(RadiusAttribute) +def edit_radiusattribute(request, radiusattribute_instance, **_kwargs): + """Edit a RADIUS attribute.""" + attribute = RadiusAttributeForm( + request.POST or None, + instance=radiusattribute_instance + ) + if attribute.is_valid(): + attribute.save() + messages.success(request, _("The attribute was edited.")) + return redirect(reverse('preferences:display-options')) + return form( + {'preferenceform': attribute, 'action_name': _("Edit")}, + 'preferences/preferences.html', + request + ) + +@login_required +@can_delete(RadiusAttribute) +def del_radiusattribute(request, radiusattribute_instance, **_kwargs): + """Delete a RADIUS attribute.""" + if request.method == "POST": + radiusattribute_instance.delete() + messages.success(request, _("The attribute was deleted.")) + return redirect(reverse('preferences:display-options')) + return form( + {'objet': radiusattribute_instance, 'objet_name': 'attribute'}, + 'preferences/delete.html', + request + ) + + From 0b00b42365b2f9b49c77f50928619e514d4af182 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Mon, 9 Sep 2019 17:59:43 +0200 Subject: [PATCH 127/228] Make use of attributes in auth.py --- freeradius_utils/auth.py | 78 +++++++++++++++++++++++++++------------- preferences/models.py | 10 ++++++ 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index 7245013e..1c74303d 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -225,7 +225,7 @@ def post_auth(data): # La ligne suivante fonctionne pour cisco, HP et Juniper port = port.split(".")[0].split('/')[-1][-2:] out = decide_vlan_switch(nas_machine, nas_type, port, mac) - sw_name, room, reason, vlan_id, decision = out + sw_name, room, reason, vlan_id, decision, attributes = out if decision: log_message = '(fil) %s -> %s [%s%s]' % ( @@ -243,7 +243,7 @@ def post_auth(data): ("Tunnel-Type", "VLAN"), ("Tunnel-Medium-Type", "IEEE-802"), ("Tunnel-Private-Group-Id", '%d' % int(vlan_id)), - ), + ) + attributes, () ) else: @@ -254,7 +254,11 @@ def post_auth(data): ) logger.info(log_message) - return radiusd.RLM_MODULE_REJECT + return ( + radiusd.RLM_MODULE_REJECT, + attributes, + () + ) else: return radiusd.RLM_MODULE_OK @@ -363,12 +367,20 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, - raison de la décision (str) - vlan_id (int) - decision (bool) + - Attributs supplémentaires (attribut:str, operateur:str, valeur:str) """ # Get port from switch and port number extra_log = "" # Si le NAS est inconnu, on place sur le vlan defaut if not nas_machine: - return ('?', u'Chambre inconnue', u'Nas inconnu', RadiusOption.get_cached_value('vlan_decision_ok').vlan_id, True) + return ( + '?', + u'Chambre inconnue', + u'Nas inconnu', + RadiusOption.get_cached_value('vlan_decision_ok').vlan_id, + True, + RadiusOption.get_attributes('ok_attributes') + ) sw_name = str(getattr(nas_machine, 'short_name', str(nas_machine))) @@ -385,10 +397,11 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, if not port: return ( sw_name, - "Chambre inconnue", + "Port inconnu", u'Port inconnu', getattr(RadiusOption.get_cached_value('unknown_port_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('unknown_port')!= RadiusOption.REJECT + RadiusOption.get_cached_value('unknown_port')!= RadiusOption.REJECT, + RadiusOption.get_attributes('unknown_port_attributes') ) # On récupère le profil du port @@ -399,12 +412,14 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, if port_profile.vlan_untagged: DECISION_VLAN = int(port_profile.vlan_untagged.vlan_id) extra_log = u"Force sur vlan " + str(DECISION_VLAN) + attributes = () else: DECISION_VLAN = RadiusOption.get_cached_value('vlan_decision_ok').vlan_id + attributes = RadiusOption.get_attributes('ok_attributes') # Si le port est désactivé, on rejette la connexion if not port.state: - return (sw_name, port.room, u'Port desactive', None, False) + return (sw_name, port.room, u'Port desactive', None, False, ()) # Si radius est désactivé, on laisse passer if port_profile.radius_type == 'NO': @@ -412,7 +427,9 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, "", u"Pas d'authentification sur ce port" + extra_log, DECISION_VLAN, - True) + True, + attributes + ) # Si le 802.1X est activé sur ce port, cela veut dire que la personne a # été accept précédemment @@ -424,7 +441,8 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, room, u'Acceptation authentification 802.1X', DECISION_VLAN, - True + True, + attributes ) # Sinon, cela veut dire qu'on fait de l'auth radius par mac @@ -441,7 +459,8 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, "Inconnue", u'Chambre inconnue', getattr(RadiusOption.get_cached_value('unknown_room_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('unknown_room')!= RadiusOption.REJECT + RadiusOption.get_cached_value('unknown_room')!= RadiusOption.REJECT, + RadiusOption.get_attributes('unknown_room_attributes'), ) room_user = User.objects.filter( @@ -451,18 +470,20 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, return ( sw_name, room, - u'Chambre non cotisante -> Web redirect', - None, - False + u'Chambre non cotisante', + getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), + RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, + RadiusOption.get_attributes('non_member_attributes'), ) for user in room_user: if user.is_ban() or user.state != User.STATE_ACTIVE: return ( sw_name, room, - u'Utilisateur banni ou desactive -> Web redirect', - None, - False + u'Utilisateur banni ou desactive', + getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None), + RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT, + RadiusOption.get_attributes('banned_attributes'), ) elif not (user.is_connected() or user.is_whitelisted()): return ( @@ -470,7 +491,8 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, room, u'Utilisateur non cotisant', getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT + RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, + RadiusOption.get_attributes('non_member_attributes'), ) # else: user OK, on passe à la verif MAC @@ -491,9 +513,10 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, return ( sw_name, room, - u'Machine Inconnue -> Web redirect', - None, - False + u'Machine Inconnue', + getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None), + RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT, + RadiusOption.get_attributes('unknown_machine_attributes'), ) # Sinon on bascule sur la politique définie dans les options # radius. @@ -503,7 +526,8 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, "", u'Machine inconnue', getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT + RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT, + RadiusOption.get_attributes('unknown_machine_attributes'), ) # L'interface a été trouvée, on vérifie qu'elle est active, @@ -518,7 +542,8 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, room, u'Adherent banni', getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT + RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT, + RadiusOption.get_attributes('banned_attributes'), ) if not interface.is_active: return ( @@ -526,7 +551,8 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, room, u'Machine non active / adherent non cotisant', getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT + RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, + RadiusOption.get_attributes('non_member_attributes'), ) # Si on choisi de placer les machines sur le vlan # correspondant à leur type : @@ -539,7 +565,8 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, room, u"Ok, Reassignation de l'ipv4" + extra_log, DECISION_VLAN, - True + True, + attributes ) else: return ( @@ -547,5 +574,6 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, room, u'Machine OK' + extra_log, DECISION_VLAN, - True + True, + attributes ) diff --git a/preferences/models.py b/preferences/models.py index ea7e9dd5..098d9b18 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -637,6 +637,9 @@ class RadiusAttribute(RevMixin, AclMixin, models.Model): def __str__(self): return ' '.join([self.attribute, self.operator, self.value]) + def as_tuple(self): + return (self.attribute, self.operator, self.value) + class RadiusOption(AclMixin, PreferencesModel): class Meta: @@ -786,6 +789,13 @@ class RadiusOption(AclMixin, PreferencesModel): help_text=_("Answer attributes for accepted users."), ) + @classmethod + def get_attributes(cls, name): + return ( + attribute.as_tuple() + for attribute in cls.get_cached_value(name).all() + ) + def default_invoice(): tpl, _ = DocumentTemplate.objects.get_or_create( From 42053ac384c3331638e39666aba98fe8f35b1b23 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sun, 1 Sep 2019 16:04:53 +0200 Subject: [PATCH 128/228] Radius installation. --- apt_requirements_radius.txt | 23 ++ freeradius_utils/freeradius3/clients.conf | 29 ++ install_re2o.sh | 320 ++++++++++++++++++++++ pip_requirements_radius.txt | 3 + re2o/settings_local.example.py | 1 + 5 files changed, 376 insertions(+) create mode 100644 apt_requirements_radius.txt create mode 100644 freeradius_utils/freeradius3/clients.conf create mode 100644 pip_requirements_radius.txt diff --git a/apt_requirements_radius.txt b/apt_requirements_radius.txt new file mode 100644 index 00000000..2d4e9bde --- /dev/null +++ b/apt_requirements_radius.txt @@ -0,0 +1,23 @@ +python-django +python-dateutil +texlive-latex-base +texlive-fonts-recommended +python-djangorestframework +python-django-reversion +python-pip +libsasl2-dev libldap2-dev +libssl-dev +python-crypto +python-git +javascript-common +libjs-jquery +libjs-jquery-ui +libjs-jquery-timepicker +libjs-bootstrap +fonts-font-awesome +graphviz +git +gettext +freeradius-common +freeradius-python2 +python-mysqldb diff --git a/freeradius_utils/freeradius3/clients.conf b/freeradius_utils/freeradius3/clients.conf new file mode 100644 index 00000000..186181d4 --- /dev/null +++ b/freeradius_utils/freeradius3/clients.conf @@ -0,0 +1,29 @@ +# Your client radius configuration below +client radius-filaire { + ipaddr = + netmask = + secret = + require_message_authenticator = no + nastype = other + virtual_server = radius-filaire +} +client radius-wifi { + ipaddr = + netmask = + secret = + require_message_authenticator = no + nastype = other + virtual_server = radius-wifi +} + +# Parangon (federez) +client parangon { + ipaddr = 185.230.78.47 + secret = please_ask_for_a_secret_to_federez_admin +} + +# Dodecagon (federez) +client dodecagon { + ipaddr = 163.172.48.168 + secret = please_ask_for_a_secret_to_federez_admin +} diff --git a/install_re2o.sh b/install_re2o.sh index b8a8c87d..6cc9a2fb 100755 --- a/install_re2o.sh +++ b/install_re2o.sh @@ -4,11 +4,21 @@ SETTINGS_LOCAL_FILE='re2o/settings_local.py' SETTINGS_EXAMPLE_FILE='re2o/settings_local.example.py' APT_REQ_FILE="apt_requirements.txt" +APT_RADIUS_REQ_FILE="apt_requirements_radius.txt" PIP_REQ_FILE="pip_requirements.txt" +PIP_RADIUS_REQ_FILE="pip_requirements_radius.txt" LDIF_DB_FILE="install_utils/db.ldiff" LDIF_SCHEMA_FILE="install_utils/schema.ldiff" +FREERADIUS_CLIENTS="freeradius_utils/freeradius3/clients.conf" +FREERADIUS_AUTH="freeradius_utils/auth.py" +FREERADIUS_RADIUSD="freeradius_utils/freeradius3/radiusd.conf" +FREERADIUS_MOD_PYTHON="freeradius_utils/freeradius3/mods-enabled/python" +FREERADIUS_MOD_EAP="freeradius_utils/freeradius3/mods-enabled/eap" +FREERADIUS_SITE_DEFAULT="freeradius_utils/freeradius3/sites-enabled/default" +FREERADIUS_SITE_INNER_TUNNEL="freeradius_utils/freeradius3/sites-enabled/inner-tunnel" +EDITOR="nano" VALUE= # global value used to return values by some functions @@ -73,6 +83,44 @@ install_requirements() { } +install_radius_requirements() { + ### Usage: install_radius_requirements + # + # This function will install the required packages from APT repository + # and Pypi repository. Those packages are all required for Re2o to work + # properly. + ### + + echo "Setting up the required packages ..." + cat $APT_RADIUS_REQ_FILE | xargs apt-get -y install + python -m pip install -r $PIP_RADIUS_REQ_FILE + echo "Setting up the required packages: Done" +} + + +configure_radius() { + ### Usage: configure_radius + # + # This function configures freeradius. + ### + echo "Configuring Freeradius ..." + + cat $FREERADIUS_CLIENTS >> /etc/freeradius/3.0/clients.conf + ln -fs $(pwd)/$FREERADIUS_AUTH /etc/freeradius/3.0/auth.py + ln -fs $(pwd)/$FREERADIUS_RADIUSD /etc/freeradius/3.0/radiusd.conf + ln -fs $(pwd)/$FREERADIUS_MOD_PYTHON /etc/freeradius/3.0/mods-enabled/python + ln -fs $(pwd)/$FREERADIUS_MOD_EAP /etc/freeradius/3.0/mods-enabled/eap + ln -fs $(pwd)/$FREERADIUS_SITE_DEFAULT /etc/freeradius/3.0/sites-enabled/default + ln -fs $(pwd)/$FREERADIUS_SITE_INNER_TUNNEL /etc/freeradius/3.0/sites-enabled/inner-tunnel + _ask_value "Ready to edit clients.conf ?" "yes" + $EDITOR /etc/freeradius/3.0/clients.conf + + + echo "Configuring Freeradius: Done" + +} + + install_database() { ### Usage: install_database @@ -715,6 +763,265 @@ interactive_guide() { +interactive_radius_guide() { + ### Usage: interactive_radius_guide + # + # This function will guide through the automated setup of radius with + # Re2o by asking the user for some informations and some installation + # choices. It will then proceed to setup and configuration of the + # required tools according to the user choices. + ### + + echo "Re2o setup !" + echo "This tool will help you setup re2o radius. It is highly recommended to use a Debian clean server for this operation." + + echo "Installing basic packages required for this script to work ..." + apt-get -y install sudo dialog + echo "Installing basic packages required for this script to work: Done" + + # Common setup for the dialog prompts + export DEBIAN_FRONTEND=noninteractive + HEIGHT=20 + WIDTH=60 + CHOICE_HEIGHT=4 + + + + ############# + ## Welcome ## + ############# + + BACKTITLE="Re2o setup" + + # Welcome prompt + TITLE="Welcome" + MSGBOX="This tool will help you setup re2o. It is highly recommended to use a Debian clean server for this operation." + init="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --msgbox "$MSGBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + + + + ###################### + ## Database options ## + ###################### + + BACKTITLE="Re2o setup - configuration of the database" + + # Prompt for choosing the database engine + TITLE="Database engine" + MENU="Which engine should be used as the database ?" + OPTIONS=(1 "mysql" + 2 "postgresql") + sql_bdd_type="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --menu "$MENU" \ + $HEIGHT $WIDTH $CHOICE_HEIGHT "${OPTIONS[@]}" 2>&1 >/dev/tty)" + + # Prompt for choosing the database location + TITLE="SQL location" + MENU="Where to install the SQL database ? + * 'Local' will setup everything automatically but is not recommended for production + * 'Remote' will ask you to manually perform some setup commands on the remote server" + OPTIONS=(1 "Local" + 2 "Remote") + sql_is_local="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --menu "$MENU" \ + $HEIGHT $WIDTH $CHOICE_HEIGHT "${OPTIONS[@]}" 2>&1 >/dev/tty)" + + if [ $sql_is_local == 2 ]; then + # Prompt to enter the remote database hostname + TITLE="SQL hostname" + INPUTBOX="The hostname of the remote SQL database" + sql_host="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --inputbox "$INPUTBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + + # Prompt to enter the remote database name + TITLE="SQL database name" + INPUTBOX="The name of the remote SQL database" + sql_name="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --inputbox "$INPUTBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + + # Prompt to enter the remote database username + TITLE="SQL username" + INPUTBOX="The username to access the remote SQL database" + sql_login="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --inputbox "$INPUTBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + clear + else + # Use of default values for local setup + sql_name="re2o" + sql_login="re2o" + sql_host="localhost" + fi + + # Prompt to enter the database password + TITLE="SQL password" + INPUTBOX="The password to access the SQL database" + sql_password="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --inputbox "$INPUTBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + + + + ################## + ## LDAP options ## + ################## + + BACKTITLE="Re2o setup - configuration of the LDAP" + + # Prompt to choose the LDAP location + TITLE="LDAP location" + MENU="Where would you like to install the LDAP ? + * 'Local' will setup everything automatically but is not recommended for production + * 'Remote' will ask you to manually perform some setup commands on the remote server" + OPTIONS=(1 "Local" + 2 "Remote") + ldap_is_local="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --menu "$MENU" \ + $HEIGHT $WIDTH $CHOICE_HEIGHT "${OPTIONS[@]}" 2>&1 >/dev/tty)" + + # Prompt to enter the LDAP domain extension + TITLE="Domain extension" + INPUTBOX="The local domain extension to use (e.g. 'example.net'). This is used in the LDAP configuration." + extension_locale="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --inputbox "$INPUTBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + + # Building the DN of the LDAP from the extension + IFS='.' read -a extension_locale_array <<< $extension_locale + for i in "${extension_locale_array[@]}" + do + ldap_dn+="dc=$i," + done + ldap_dn="${ldap_dn::-1}" + + if [ "$ldap_is_local" == 2 ]; then + # Prompt to enter the remote LDAP hostname + TITLE="LDAP hostname" + INPUTBOX="The hostname of the remote LDAP" + ldap_host="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --inputbox "$INPUTBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + + # Prompt to choose if TLS should be activated or not for the LDAP + TITLE="TLS on LDAP" + MENU="Would you like to activate TLS for communicating with the remote LDAP ?" + OPTIONS=(1 "Yes" + 2 "No") + ldap_tls="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --MENU "$MENU" \ + $HEIGHT $WIDTH $CHOICE_HEIGHT "${OPTIONS[@]}" 2>&1 >/dev/tty)" + + # Prompt to enter the admin's CN of the remote LDAP + TITLE="CN of amdin user" + INPUTBOX="The CN entry for the admin user of the remote LDAP" + ldap_cn="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --inputbox "$INPUTBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + else + ldap_cn="cn=admin," + ldap_cn+="$ldap_dn" + ldap_host="localhost" + ldap_tls=2 + fi + + # Prompt to enter the LDAP password + TITLE="LDAP password" + INPUTBOX="The password to access the LDAP" + ldap_password="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --inputbox "$INPUTBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + + + + ######################### + ## Mail server options ## + ######################### + + BACKTITLE="Re2o setup - configuration of the mail server" + + # Prompt to enter the hostname of the mail server + TITLE="Mail server hostname" + INPUTBOX="The hostname of the mail server to use" + email_host="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --inputbox "$TITLE" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + + # Prompt to choose the port of the mail server + TITLE="Mail server port" + MENU="Which port (thus which protocol) to use to contact the mail server" + OPTIONS=(25 "SMTP" + 465 "SMTPS" + 587 "Submission") + email_port="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --menu "$MENU" \ + $HEIGHT $WIDTH $CHOICE_HEIGHT "${OPTIONS[@]}" 2>&1 >/dev/tty)" + + + + ############################### + ## End of configuration step ## + ############################### + + BACKTITLE="Re2o setup" + + # Prompt to inform the config setup is over + TITLE="End of configuration step" + MSGBOX="The configuration step is now finished. The script will now perform the following actions: + * Install the required packages + * Install and setup the requested database if 'local' has been selected + * Install and setup the ldap if 'local' has been selected + * Write a local version of 'settings_local.py' file with the previously given informations + * Apply the Django migrations for the project + * Install and setup freeradius" + end_config="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --msgbox "$MSGBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" + + clear + + + + ################################ + ## Perform the actual actions ## + ################################ + + install_radius_requirements + + configure_radius + + install_database "$sql_bdd_type" "$sql_is_local" "$sql_name" "$sql_login" "$sql_password" + + install_ldap "$ldap_is_local" "$ldap_password" "$ldap_dn" + + + write_settings_file "$sql_bdd_type" "$sql_host" "$sql_name" "$sql_login" "$sql_password" \ + "$ldap_cn" "$ldap_tls" "$ldap_password" "$ldap_host" "$ldap_dn" \ + "$email_host" "$email_port" "$extension_locale" "$url_server" + + update_django + + + ########################### + ## End of the setup step ## + ########################### + + BACKTITLE="Re2o setup" + + # Prompt to inform the installation process is over + TITLE="End of the setup" + MSGBOX="You can now use your RADIUS server." + end="$(dialog --clear --backtitle "$BACKTITLE" \ + --title "$TITLE" --msgbox "$MSGBOX" \ + $HEIGHT $WIDTH 2>&1 >/dev/tty)" +} + + + + interactive_update_settings() { ### Usage: interactvie_update_settings @@ -763,9 +1070,13 @@ main_function() { echo " * {help} ---------- Display this quick usage documentation" echo " * {setup} --------- Launch the full interactive guide to setup entirely" echo " re2o from scratch" + echo " * {setup-radius} -- Launch the full interactive guide to setup entirely" + echo " re2o radius from scratch" echo " * {update} -------- Collect frontend statics, install the missing APT" echo " and pip packages, copy LaTeX templates files" echo " and apply the migrations to the DB" + echo " * {update-radius} - Update radius apt and pip packages and copy radius" + echo " configuration files to their proper location." echo " * {update-django} - Apply Django migration and collect frontend statics" echo " * {copy-template-files} - Copy LaTeX templates files to media/templates" echo " * {update-packages} Install the missing APT and pip packages" @@ -797,12 +1108,21 @@ main_function() { interactive_guide ;; + setup-radius ) + interactive_radius_guide + ;; + update ) install_requirements copy_templates_files update_django ;; + update-radius ) + install_radius_requirements + configure_radius + ;; + copy-templates-files ) copy_templates_files ;; diff --git a/pip_requirements_radius.txt b/pip_requirements_radius.txt new file mode 100644 index 00000000..c49222aa --- /dev/null +++ b/pip_requirements_radius.txt @@ -0,0 +1,3 @@ +django-bootstrap3 +django-macaddress +django-ldapdb==1.3.0 diff --git a/re2o/settings_local.example.py b/re2o/settings_local.example.py index bb0fd21e..80c109c4 100644 --- a/re2o/settings_local.example.py +++ b/re2o/settings_local.example.py @@ -1,3 +1,4 @@ +# coding: utf-8 # Re2o est un logiciel d'administration développé initiallement au rezometz. Il # se veut agnostique au réseau considéré, de manière à être installable en # quelques clics. From f9b7d70314e10838bedbd201106337f0eb00ccf3 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Tue, 10 Sep 2019 19:11:14 +0200 Subject: [PATCH 129/228] Fix various bugs in auth.py. --- freeradius_utils/auth.py | 39 ++++++++++++------- ...tributes.py => 0062_auto_20190910_1909.py} | 3 +- preferences/models.py | 31 +++------------ topologie/models.py | 12 +++--- 4 files changed, 36 insertions(+), 49 deletions(-) rename preferences/migrations/{0062_radius_attributes.py => 0062_auto_20190910_1909.py} (88%) diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index 1c74303d..c2cb3fed 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -117,8 +117,11 @@ def radius_event(fun): # (str,str) : rlm_python ne digère PAS les unicodes return fun(data) except Exception as err: + exc_type, exc_instance, exc_traceback = sys.exc_info() + formatted_traceback = ''.join(traceback.format_tb( + exc_traceback)) logger.error('Failed %r on data %r' % (err, auth_data)) - logger.debug('Function %r, Traceback: %s' % (fun, repr(traceback.format_stack()))) + logger.error('Function %r, Traceback : %r' % (fun, formatted_traceback)) return radiusd.RLM_MODULE_FAIL return new_f @@ -243,7 +246,7 @@ def post_auth(data): ("Tunnel-Type", "VLAN"), ("Tunnel-Medium-Type", "IEEE-802"), ("Tunnel-Private-Group-Id", '%d' % int(vlan_id)), - ) + attributes, + ) + tuple(attributes), () ) else: @@ -256,7 +259,7 @@ def post_auth(data): return ( radiusd.RLM_MODULE_REJECT, - attributes, + tuple(attributes), () ) @@ -369,6 +372,10 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, - decision (bool) - Attributs supplémentaires (attribut:str, operateur:str, valeur:str) """ + attributes_kwargs = { + 'client_mac' : str(mac_address), + 'switch_port' : str(port_number), + } # Get port from switch and port number extra_log = "" # Si le NAS est inconnu, on place sur le vlan defaut @@ -379,14 +386,16 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Nas inconnu', RadiusOption.get_cached_value('vlan_decision_ok').vlan_id, True, - RadiusOption.get_attributes('ok_attributes') + RadiusOption.get_attributes('ok_attributes', attributes_kwargs) ) sw_name = str(getattr(nas_machine, 'short_name', str(nas_machine))) + switch = Switch.objects.filter(machine_ptr=nas_machine).first() + attributes_kwargs['switch_ip'] = str(switch.ipv4) port = (Port.objects .filter( - switch=Switch.objects.filter(machine_ptr=nas_machine), + switch=switch, port=port_number ) .first()) @@ -401,7 +410,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Port inconnu', getattr(RadiusOption.get_cached_value('unknown_port_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('unknown_port')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_port_attributes') + RadiusOption.get_attributes('unknown_port_attributes', attributes_kwargs) ) # On récupère le profil du port @@ -415,7 +424,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, attributes = () else: DECISION_VLAN = RadiusOption.get_cached_value('vlan_decision_ok').vlan_id - attributes = RadiusOption.get_attributes('ok_attributes') + attributes = RadiusOption.get_attributes('ok_attributes', attributes_kwargs) # Si le port est désactivé, on rejette la connexion if not port.state: @@ -460,7 +469,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Chambre inconnue', getattr(RadiusOption.get_cached_value('unknown_room_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('unknown_room')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_room_attributes'), + RadiusOption.get_attributes('unknown_room_attributes', attributes_kwargs), ) room_user = User.objects.filter( @@ -473,7 +482,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Chambre non cotisante', getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, - RadiusOption.get_attributes('non_member_attributes'), + RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), ) for user in room_user: if user.is_ban() or user.state != User.STATE_ACTIVE: @@ -483,7 +492,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Utilisateur banni ou desactive', getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT, - RadiusOption.get_attributes('banned_attributes'), + RadiusOption.get_attributes('banned_attributes', attributes_kwargs), ) elif not (user.is_connected() or user.is_whitelisted()): return ( @@ -492,7 +501,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Utilisateur non cotisant', getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, - RadiusOption.get_attributes('non_member_attributes'), + RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), ) # else: user OK, on passe à la verif MAC @@ -516,7 +525,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Machine Inconnue', getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_machine_attributes'), + RadiusOption.get_attributes('unknown_machine_attributes', attributes_kwargs), ) # Sinon on bascule sur la politique définie dans les options # radius. @@ -527,7 +536,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Machine inconnue', getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_machine_attributes'), + RadiusOption.get_attributes('unknown_machine_attributes', attributes_kwargs), ) # L'interface a été trouvée, on vérifie qu'elle est active, @@ -543,7 +552,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Adherent banni', getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT, - RadiusOption.get_attributes('banned_attributes'), + RadiusOption.get_attributes('banned_attributes', attributes_kwargs), ) if not interface.is_active: return ( @@ -552,7 +561,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Machine non active / adherent non cotisant', getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, - RadiusOption.get_attributes('non_member_attributes'), + RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), ) # Si on choisi de placer les machines sur le vlan # correspondant à leur type : diff --git a/preferences/migrations/0062_radius_attributes.py b/preferences/migrations/0062_auto_20190910_1909.py similarity index 88% rename from preferences/migrations/0062_radius_attributes.py rename to preferences/migrations/0062_auto_20190910_1909.py index 05a34493..d121ba7c 100644 --- a/preferences/migrations/0062_radius_attributes.py +++ b/preferences/migrations/0062_auto_20190910_1909.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.23 on 2019-09-09 14:13 +# Generated by Django 1.11.23 on 2019-09-10 17:09 from __future__ import unicode_literals from django.db import migrations, models @@ -18,7 +18,6 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('attribute', models.CharField(help_text='See http://freeradius.org/rfc/attributes.html', max_length=255, verbose_name='Attribute')), - ('operator', models.CharField(choices=[('=', '='), (':=', ':='), ('==', '=='), ('+=', '+='), ('!=', '!='), ('>', '>'), ('>=', '>='), ('<', '<'), ('<=', '<='), ('=~', '=~'), ('!~', '!~'), ('=*', '=*'), ('!*', '!*')], default=':=', help_text='See https://wiki.freeradius.org/config/Operators', max_length=2, verbose_name='Operator')), ('value', models.CharField(max_length=255, verbose_name='Value')), ('comment', models.TextField(blank=True, default='', help_text='Use this field to document this attribute.', verbose_name='Comment')), ], diff --git a/preferences/models.py b/preferences/models.py index 098d9b18..f5309b01 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -596,33 +596,11 @@ class RadiusAttribute(RevMixin, AclMixin, models.Model): verbose_name = _("RADIUS attribute") verbose_name_plural = _("RADIUS attributes") - CHOICE_OPERATOR = ( - ('=' , '=' ), - (':=', ':='), - ('==', '=='), - ('+=', '+='), - ('!=', '!='), - ('>' , '>' ), - ('>=', '>='), - ('<' , '<' ), - ('<=', '<='), - ('=~', '=~'), - ('!~', '!~'), - ('=*', '=*'), - ('!*', '!*') - ) attribute = models.CharField( max_length=255, verbose_name=_("Attribute"), help_text=_("See http://freeradius.org/rfc/attributes.html"), ) - operator = models.CharField( - max_length=2, - verbose_name=_("Operator"), - help_text=_("See https://wiki.freeradius.org/config/Operators"), - choices=CHOICE_OPERATOR, - default=':=' - ) value = models.CharField( max_length=255, verbose_name=_("Value") @@ -637,8 +615,6 @@ class RadiusAttribute(RevMixin, AclMixin, models.Model): def __str__(self): return ' '.join([self.attribute, self.operator, self.value]) - def as_tuple(self): - return (self.attribute, self.operator, self.value) class RadiusOption(AclMixin, PreferencesModel): @@ -790,9 +766,12 @@ class RadiusOption(AclMixin, PreferencesModel): ) @classmethod - def get_attributes(cls, name): + def get_attributes(cls, name, attribute_kwargs={}): return ( - attribute.as_tuple() + ( + str(attribute.attribute), + str(attribute.value % attribute_kwargs) + ) for attribute in cls.get_cached_value(name).all() ) diff --git a/topologie/models.py b/topologie/models.py index 250e52a9..235b3885 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -400,17 +400,17 @@ class Switch(AclMixin, Machine): def profile_type_or_nothing(self, profile_type): """Return the profile for a profile_type of this switch - + If exists, returns the defined default profile for a profile type on the dormitory which the switch belongs - + Otherwise, returns the nothing profile""" profile_queryset = PortProfile.objects.filter(profil_default=profile_type) if self.get_dormitory: port_profile = profile_queryset.filter(on_dormitory=self.get_dormitory).first() or profile_queryset.first() else: port_profile = profile_queryset.first() - return port_profile or Switch.nothing_profile + return port_profile or Switch.nothing_profile() @cached_property def default_uplink_profile(self): @@ -628,7 +628,7 @@ class Building(AclMixin, RevMixin, models.Model): @cached_property def cached_name(self): - return self.get_name() + return self.get_name() def __str__(self): return self.cached_name @@ -712,7 +712,7 @@ class Port(AclMixin, RevMixin, models.Model): def get_port_profile(self): """Return the config profil for this port :returns: the profile of self (port) - + If is defined a custom profile, returns it elIf a default profile is defined for its dormitory, returns it Else, returns the global default profil @@ -730,7 +730,7 @@ class Port(AclMixin, RevMixin, models.Model): elif self.room: return self.switch.default_room_profile else: - return Switch.nothing_profile + return Switch.nothing_profile() @classmethod def get_instance(cls, portid, *_args, **kwargs): From 7fb5f786fdffca076cdf3c178516520713df337d Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 17 Sep 2019 18:41:41 +0200 Subject: [PATCH 130/228] Fix list usable machine by rights --- machines/forms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/machines/forms.py b/machines/forms.py index af05a48e..c89334dd 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -104,7 +104,7 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): self.fields['ipv4'].queryset = IpList.objects.filter( interface__isnull=True ) - can_use_all_iptype, _reason = IpType.can_use_all(user) + can_use_all_iptype, _reason, _message = IpType.can_use_all(user) if not can_use_all_iptype: self.fields['ipv4'].queryset = IpList.objects.filter( interface__isnull=True @@ -120,7 +120,7 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): if "machine" in self.fields: self.fields['machine'].queryset = Machine.objects.all() \ .select_related('user') - can_use_all_machinetype, _reason = MachineType.can_use_all(user) + can_use_all_machinetype, _reason, _message = MachineType.can_use_all(user) if not can_use_all_machinetype: self.fields['machine_type'].queryset = MachineType.objects.filter( ip_type__in=IpType.objects.filter(need_infra=False) @@ -146,7 +146,7 @@ class AliasForm(FormRevMixin, ModelForm): prefix = kwargs.pop('prefix', self.Meta.model.__name__) user = kwargs.pop('user') super(AliasForm, self).__init__(*args, prefix=prefix, **kwargs) - can_use_all, _reason = Extension.can_use_all(user) + can_use_all, _reason, _message = Extension.can_use_all(user) if not can_use_all: self.fields['extension'].queryset = Extension.objects.filter( need_infra=False From d3310866cdd651f13c87f539abcb1936aad0ae1b Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 17 Sep 2019 02:51:00 +0200 Subject: [PATCH 131/228] Rend l'API fonctionnelle sous buster --- api/routers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/routers.py b/api/routers.py index 7c9e4a0f..bb2411f5 100644 --- a/api/routers.py +++ b/api/routers.py @@ -76,7 +76,7 @@ class AllViewsRouter(DefaultRouter): """ return pattern.split('/')[-1] - def get_api_root_view(self, schema_urls=None): + def get_api_root_view(self, schema_urls=None, api_urls=None): """Create a class-based view to use as the API root. Highly inspired by the base class. See details on the implementation From 17704fce9cca8d1867d8c01eaa0d173a80bd02a1 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 17 Sep 2019 19:09:31 +0200 Subject: [PATCH 132/228] Fix can_view extra arg for logs --- logs/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/views.py b/logs/views.py index 28205063..5d8cf1a9 100644 --- a/logs/views.py +++ b/logs/views.py @@ -521,7 +521,7 @@ def history(request, application, object_name, object_id): 'users:profil', kwargs={'userid': str(request.user.id)} )) - can, msg = instance.can_view(request.user) + can, msg, _extra_msg = instance.can_view(request.user) if not can: messages.error(request, msg or _("You don't have the right to access this menu.")) return redirect(reverse( From 6c476f080e69f2507b0593750f25ff25d403bdf4 Mon Sep 17 00:00:00 2001 From: klafyvel Date: Thu, 19 Sep 2019 23:14:33 +0200 Subject: [PATCH 133/228] Better naming --- logs/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/views.py b/logs/views.py index 5d8cf1a9..47ceab06 100644 --- a/logs/views.py +++ b/logs/views.py @@ -521,7 +521,7 @@ def history(request, application, object_name, object_id): 'users:profil', kwargs={'userid': str(request.user.id)} )) - can, msg, _extra_msg = instance.can_view(request.user) + can, msg, _permissions = instance.can_view(request.user) if not can: messages.error(request, msg or _("You don't have the right to access this menu.")) return redirect(reverse( From 1c2ce26060dbcf6d66250cd3388e03719cf086e3 Mon Sep 17 00:00:00 2001 From: klafyvel Date: Thu, 19 Sep 2019 23:15:11 +0200 Subject: [PATCH 134/228] Better naming --- machines/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machines/forms.py b/machines/forms.py index c89334dd..a56ecbf3 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -104,7 +104,7 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): self.fields['ipv4'].queryset = IpList.objects.filter( interface__isnull=True ) - can_use_all_iptype, _reason, _message = IpType.can_use_all(user) + can_use_all_iptype, _reason, _permissions = IpType.can_use_all(user) if not can_use_all_iptype: self.fields['ipv4'].queryset = IpList.objects.filter( interface__isnull=True From 4f1102c0c5502461f5d97f6071281f056b4f844a Mon Sep 17 00:00:00 2001 From: klafyvel Date: Thu, 19 Sep 2019 23:16:02 +0200 Subject: [PATCH 135/228] Better naming --- machines/forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machines/forms.py b/machines/forms.py index a56ecbf3..4ea2323b 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -120,7 +120,7 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): if "machine" in self.fields: self.fields['machine'].queryset = Machine.objects.all() \ .select_related('user') - can_use_all_machinetype, _reason, _message = MachineType.can_use_all(user) + can_use_all_machinetype, _reason, _permissions = MachineType.can_use_all(user) if not can_use_all_machinetype: self.fields['machine_type'].queryset = MachineType.objects.filter( ip_type__in=IpType.objects.filter(need_infra=False) @@ -146,7 +146,7 @@ class AliasForm(FormRevMixin, ModelForm): prefix = kwargs.pop('prefix', self.Meta.model.__name__) user = kwargs.pop('user') super(AliasForm, self).__init__(*args, prefix=prefix, **kwargs) - can_use_all, _reason, _message = Extension.can_use_all(user) + can_use_all, _reason, _permissions = Extension.can_use_all(user) if not can_use_all: self.fields['extension'].queryset = Extension.objects.filter( need_infra=False From 86e5c8d322552d7d9a11c250566168f618e9fc9f Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Fri, 20 Sep 2019 11:04:02 +0200 Subject: [PATCH 136/228] Fix radius attributes __str__ --- preferences/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/preferences/models.py b/preferences/models.py index f5309b01..af85847b 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -613,7 +613,7 @@ class RadiusAttribute(RevMixin, AclMixin, models.Model): ) def __str__(self): - return ' '.join([self.attribute, self.operator, self.value]) + return ' '.join([self.attribute, '=', self.value]) From b6740252596e971a89507f1a8742a223325c561f Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Fri, 20 Sep 2019 11:57:57 +0200 Subject: [PATCH 137/228] Fix #220 --- users/forms.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/users/forms.py b/users/forms.py index 747b4aff..d29d0bdd 100644 --- a/users/forms.py +++ b/users/forms.py @@ -409,10 +409,11 @@ class AdherentCreationForm(AdherentForm): def __init__(self, *args, **kwargs): super(AdherentCreationForm, self).__init__(*args, **kwargs) + gtu_file = GeneralOption.get_cached_value('GTU') self.fields['gtu_check'].label = mark_safe( - "%s %s." % ( + "%s %s." % ( _("I commit to accept the"), - GeneralOption.get_cached_value('GTU').url, + gtu_file.url if gtu_file else "https://en.wikipedia.org/wiki/Llama", _("General Terms of Use") ) ) From aee410508d75f1c17052279cd374be0a482cc39d Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Fri, 20 Sep 2019 11:57:57 +0200 Subject: [PATCH 138/228] Fix #220 --- users/forms.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/users/forms.py b/users/forms.py index 747b4aff..d29d0bdd 100644 --- a/users/forms.py +++ b/users/forms.py @@ -409,10 +409,11 @@ class AdherentCreationForm(AdherentForm): def __init__(self, *args, **kwargs): super(AdherentCreationForm, self).__init__(*args, **kwargs) + gtu_file = GeneralOption.get_cached_value('GTU') self.fields['gtu_check'].label = mark_safe( - "%s %s." % ( + "%s %s." % ( _("I commit to accept the"), - GeneralOption.get_cached_value('GTU').url, + gtu_file.url if gtu_file else "https://en.wikipedia.org/wiki/Llama", _("General Terms of Use") ) ) From d9f5514b585a1de9e152f0974378319fb49a8029 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Fri, 20 Sep 2019 14:20:42 +0200 Subject: [PATCH 139/228] Llamas are being oppressed. --- users/forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/users/forms.py b/users/forms.py index d29d0bdd..33100c9d 100644 --- a/users/forms.py +++ b/users/forms.py @@ -411,9 +411,9 @@ class AdherentCreationForm(AdherentForm): super(AdherentCreationForm, self).__init__(*args, **kwargs) gtu_file = GeneralOption.get_cached_value('GTU') self.fields['gtu_check'].label = mark_safe( - "%s %s." % ( + "%s %s." % ( _("I commit to accept the"), - gtu_file.url if gtu_file else "https://en.wikipedia.org/wiki/Llama", + gtu_file.url if gtu_file else "#", _("General Terms of Use") ) ) From b8d8c11cb040091333aa7b1ed03d51c36dc7bc73 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Fri, 20 Sep 2019 14:48:37 +0200 Subject: [PATCH 140/228] Fix #151 --- templates/base.html | 7 ++++--- users/forms.py | 3 ++- .../migrations/0083_user_shortcuts_enabled.py | 20 +++++++++++++++++++ users/models.py | 4 ++++ users/templates/users/profil.html | 4 ++++ 5 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 users/migrations/0083_user_shortcuts_enabled.py diff --git a/templates/base.html b/templates/base.html index 7a2074f2..891e243f 100644 --- a/templates/base.html +++ b/templates/base.html @@ -93,14 +93,14 @@ with this program; if not, write to the Free Software Foundation, Inc., {% can_view_app users %}
  • {% trans "Manage the users" %}
  • {% trans "Manage the clubs" %}
  • - {% acl_end %} + {% acl_end %} {% can_view_app machines %}
  • {% trans "Manage the machines" %}
  • {% acl_end %} {% can_view_app cotisations %}
  • {% trans "Manage the subscriptions" %}
  • {% acl_end %} - + {% for template in optionnal_templates_navbar_user_list%} {{ template }} {% endfor %} @@ -301,8 +301,9 @@ with this program; if not, write to the Free Software Foundation, Inc., let s = Sapphire(); Konami(s.activate); + {% if request.user.shortcuts_enabled %} - + {% endif %} {# Read the documentation for more information #} diff --git a/users/forms.py b/users/forms.py index 33100c9d..75d73de1 100644 --- a/users/forms.py +++ b/users/forms.py @@ -441,7 +441,8 @@ class AdherentEditForm(AdherentForm): 'telephone', 'room', 'shell', - 'gpg_fingerprint' + 'gpg_fingerprint', + 'shortcuts_enabled', ] class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): diff --git a/users/migrations/0083_user_shortcuts_enabled.py b/users/migrations/0083_user_shortcuts_enabled.py new file mode 100644 index 00000000..8ba2252d --- /dev/null +++ b/users/migrations/0083_user_shortcuts_enabled.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-09-20 12:38 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0082_auto_20190908_1338'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='shortcuts_enabled', + field=models.BooleanField(default=True, verbose_name='Enable shortcuts on Re2o website'), + ), + ] diff --git a/users/models.py b/users/models.py index 66d53a96..0438ae83 100755 --- a/users/models.py +++ b/users/models.py @@ -247,6 +247,10 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, blank=True, null=True ) + shortcuts_enabled = models.BooleanField( + verbose_name=_("Enable shortcuts on Re2o website"), + default=True + ) USERNAME_FIELD = 'pseudo' REQUIRED_FIELDS = ['surname', 'email'] diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index a7079232..29c55f32 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -305,6 +305,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    {{ users.shell }}
    {% endif %} +
    +
    {% trans "Shortcuts enabled" %}
    +
    {{ users.shortcuts_enabled | tick }}
    +
    From e404fa36ec7fc8566ca17b2d0e83d4c0d9910e89 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Fri, 20 Sep 2019 15:09:57 +0200 Subject: [PATCH 141/228] Fix typo in User.can_view_all --- users/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/models.py b/users/models.py index 0438ae83..bbb4146d 100755 --- a/users/models.py +++ b/users/models.py @@ -1109,7 +1109,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, :return: True if the user can view the list and an explanation message. """ - can = user_request.has_perm('use.view_user') + can = user_request.has_perm('users.view_user') return ( can, _("You don't have the right to view the list of users.") if not can else None, From b648078b4e98f16a98968ec72f6cb91c3f2fe0b2 Mon Sep 17 00:00:00 2001 From: Maxime Bombar Date: Sun, 22 Sep 2019 00:34:10 +0200 Subject: [PATCH 142/228] [machines/views] Domain MUST be saved to get the right extension --- machines/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/machines/views.py b/machines/views.py index bdbb1a83..a07d7e75 100644 --- a/machines/views.py +++ b/machines/views.py @@ -304,8 +304,7 @@ def edit_interface(request, interface_instance, **_kwargs): new_machine_obj.save() if interface_form.changed_data: new_interface_obj.save() - if domain_form.changed_data: - new_domain_obj.save() + new_domain_obj.save() messages.success(request, _("The machine was edited.")) return redirect(reverse( 'users:profil', From 657ef77bfe2e7959439c41a4b400b78cc54e2571 Mon Sep 17 00:00:00 2001 From: klafyvel Date: Tue, 24 Sep 2019 00:44:16 +0200 Subject: [PATCH 143/228] Remove contributor levy arcas --- cotisations/models.py | 3 ++- cotisations/templates/cotisations/email_subscription_accepted | 4 ++-- cotisations/utils.py | 3 ++- re2o/contributors.py | 1 - 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cotisations/models.py b/cotisations/models.py index 006e8d69..8174e0bb 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -297,7 +297,8 @@ class Facture(BaseInvoice): if self.is_subscription() \ and not self.__original_control \ and self.control \ - and CotisationsOption.get_cached_value('send_voucher_mail'): + and CotisationsOption.get_cached_value('send_voucher_mail') \ + and self.user.is_adherent(): send_mail_voucher(self) def __str__(self): diff --git a/cotisations/templates/cotisations/email_subscription_accepted b/cotisations/templates/cotisations/email_subscription_accepted index 58027cec..bd1c7628 100644 --- a/cotisations/templates/cotisations/email_subscription_accepted +++ b/cotisations/templates/cotisations/email_subscription_accepted @@ -1,6 +1,6 @@ Bonjour {{name}} ! -Nous vous informons que votre cotisation auprès de {{asso_name}} a été acceptée. Vous voilà donc membre de l'association. +Nous vous informons que votre cotisation auprès de {{asso_name}} a été acceptée. Vous voilà donc membre de l'association jusqu'au {{ date_end|date:"d/m/Y" }}. Vous trouverez en pièce jointe un reçu. @@ -11,7 +11,7 @@ L'équipe de {{asso_name}}. --- -Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}}. +Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}} until {{ date_end|date:"d/m/Y" }}. You will find with this email a subscription voucher. diff --git a/cotisations/utils.py b/cotisations/utils.py index 4715338b..8b7ee2b0 100644 --- a/cotisations/utils.py +++ b/cotisations/utils.py @@ -117,7 +117,8 @@ def send_mail_voucher(invoice): invoice.user.surname ), 'asso_email': AssoOption.get_cached_value('contact'), - 'asso_name': AssoOption.get_cached_value('name') + 'asso_name': AssoOption.get_cached_value('name'), + 'date_end': invoice.get_subscription().latest('date_end').date_end, } mail = EmailMessage( diff --git a/re2o/contributors.py b/re2o/contributors.py index ac663d9c..e9f201c3 100644 --- a/re2o/contributors.py +++ b/re2o/contributors.py @@ -14,7 +14,6 @@ CONTRIBUTORS = [ 'Matthieu "Lebanni" Michelet', 'Arthur "Grizzly" Grisel-Davy', 'Simon "Rezatoune" Brélivet', - 'Sellem Lev-Arcady', 'David "5-1" Sinquin', 'Pierre "Redstorm" Cadart', 'Éloi "Goslig" Alain', From eae1d9385dc6fd511d7f3ab251d4e0e7cf025d6b Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Tue, 24 Sep 2019 00:18:14 +0200 Subject: [PATCH 144/228] Remove preferences menu related to radius in topologie options, as it is no longer used. --- .../preferences/display_preferences.html | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index 99ee9be3..2c5dec2b 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -196,30 +196,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    - - - {% trans "Edit" %} - -

    - - - - - - - - - - - - - - - - - -
    {% trans "General policy for VLAN setting" %}{{ topologieoptions.radius_general_policy }}{% trans "This setting defines the VLAN policy after acceptance by RADIUS: either on the IP range's VLAN of the machine, or a VLAN preset in 'VLAN for machines accepted by RADIUS'" %}
    {% trans "VLAN for machines accepted by RADIUS" %}{{ topologieoptions.vlan_decision_ok }}{% trans "VLAN for machines rejected by RADIUS" %}{{ topologieoptions.vlan_decision_nok }}
    {% trans "VLAN for non members machines" %}{{ topologieoptions.vlan_non_member }}
    -

    {% trans "RADIUS keys" %}

    {% can_create RadiusKey%} {% trans " Add a RADIUS key" %} From 0cb9388cde5791726e989aa17b4a1d6980010fa1 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Mon, 30 Sep 2019 11:33:01 +0200 Subject: [PATCH 145/228] Fix #191 --- cotisations/migrations/0039_freepayment.py | 28 +++++++++ cotisations/payment_methods/__init__.py | 5 +- cotisations/payment_methods/free/__init__.py | 27 ++++++++ cotisations/payment_methods/free/models.py | 61 +++++++++++++++++++ .../templates/cotisations/facture.html | 3 - cotisations/views.py | 2 +- 6 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 cotisations/migrations/0039_freepayment.py create mode 100644 cotisations/payment_methods/free/__init__.py create mode 100644 cotisations/payment_methods/free/models.py diff --git a/cotisations/migrations/0039_freepayment.py b/cotisations/migrations/0039_freepayment.py new file mode 100644 index 00000000..127f80e1 --- /dev/null +++ b/cotisations/migrations/0039_freepayment.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-09-30 09:19 +from __future__ import unicode_literals + +import cotisations.payment_methods.mixins +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('cotisations', '0038_auto_20181231_1657'), + ] + + operations = [ + migrations.CreateModel( + name='FreePayment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), + ], + options={ + 'verbose_name': 'Free payment', + }, + bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), + ), + ] diff --git a/cotisations/payment_methods/__init__.py b/cotisations/payment_methods/__init__.py index 1efde30b..3071b9c0 100644 --- a/cotisations/payment_methods/__init__.py +++ b/cotisations/payment_methods/__init__.py @@ -127,11 +127,12 @@ method to your model, where `form` is an instance of """ -from . import comnpay, cheque, balance, note_kfet, urls +from . import comnpay, cheque, balance, note_kfet, free, urls PAYMENT_METHODS = [ comnpay, cheque, balance, - note_kfet + note_kfet, + free ] diff --git a/cotisations/payment_methods/free/__init__.py b/cotisations/payment_methods/free/__init__.py new file mode 100644 index 00000000..1a7168a9 --- /dev/null +++ b/cotisations/payment_methods/free/__init__.py @@ -0,0 +1,27 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2019 Hugo Levy-Falk +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +This module contains a method to pay online using user balance. +""" +from . import models +NAME = "FREE" + +PaymentMethod = models.FreePayment diff --git a/cotisations/payment_methods/free/models.py b/cotisations/payment_methods/free/models.py new file mode 100644 index 00000000..46ecca87 --- /dev/null +++ b/cotisations/payment_methods/free/models.py @@ -0,0 +1,61 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2018 Hugo Levy-Falk +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from django.contrib import messages + + +from cotisations.models import Paiement +from cotisations.payment_methods.mixins import PaymentMethodMixin + + +class FreePayment(PaymentMethodMixin, models.Model): + """ + The model allowing you to bypass payment if the invoice is free. + """ + + class Meta: + verbose_name = _("Free payment") + + payment = models.OneToOneField( + Paiement, + on_delete=models.CASCADE, + related_name='payment_method', + editable=False + ) + + def end_payment(self, invoice, request): + """Ends the payment normally. + """ + return invoice.paiement.end_payment( + invoice, + request, + use_payment_method=False + ) + + def check_price(self, price, user, *args, **kwargs): + """Checks that the price meets the requirement to be paid with user + balance. + """ + return ( + price == 0, + _("You cannot validate this invoice for free.") + ) diff --git a/cotisations/templates/cotisations/facture.html b/cotisations/templates/cotisations/facture.html index 65b05199..4f42f8e8 100644 --- a/cotisations/templates/cotisations/facture.html +++ b/cotisations/templates/cotisations/facture.html @@ -44,9 +44,6 @@ with this program; if not, write to the Free Software Foundation, Inc., {% blocktrans %}Current balance: {{ balance }} €{% endblocktrans %}

    {% endif %} -{% if factureform %} -{% bootstrap_form_errors factureform %} -{% endif %} {% if discount_form %} {% bootstrap_form_errors discount_form %} {% endif %} diff --git a/cotisations/views.py b/cotisations/views.py index b6d5a8a6..0e7212fa 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -123,7 +123,7 @@ def new_facture(request, user, userid): if invoice_form.is_valid() and article_formset.is_valid(): new_invoice_instance = invoice_form.save(commit=False) articles = article_formset - # Check if at leat one article has been selected + # Check if at least one article has been selected if any(art.cleaned_data for art in articles): # Building a purchase for each article sold purchases = [] From 3be0b48c1b6bd984c9c9055f204f7d482ea6099c Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sun, 29 Sep 2019 18:27:35 +0200 Subject: [PATCH 146/228] Fix #223 --- users/views.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/users/views.py b/users/views.py index 045446b1..c948698f 100644 --- a/users/views.py +++ b/users/views.py @@ -919,18 +919,15 @@ def index_listright(request): .order_by('name') .prefetch_related('permissions') .prefetch_related('user_set') - .prefetch_related('user_set__facture_set__vente_set__cotisation') ): rights[right] = (right.user_set .annotate(action_number=Count('revision'), - last_seen=Max('revision__date_created'), - end_adhesion=Max('facture__vente__cotisation__date_end')) + last_seen=Max('revision__date_created')) ) superusers = (User.objects .filter(is_superuser=True) .annotate(action_number=Count('revision'), - last_seen=Max('revision__date_created'), - end_adhesion=Max('facture__vente__cotisation__date_end')) + last_seen=Max('revision__date_created')) ) return render( request, @@ -978,7 +975,7 @@ def profil(request, users, **_kwargs): request.GET.get('order'), SortTable.MACHINES_INDEX ) - + optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] optionnal_templates_list = [app.views.profil(request,users) for app in optionnal_apps] From e1575c09d47db0b5b2b26f28cd6df82530519e98 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sun, 29 Sep 2019 17:57:10 +0200 Subject: [PATCH 147/228] Fix mass_delete of machine so that AccessPoint deletion is possible. --- machines/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/machines/models.py b/machines/models.py index 68c7c58b..fdc7821e 100644 --- a/machines/models.py +++ b/machines/models.py @@ -258,11 +258,13 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): @classmethod def mass_delete(cls, machine_queryset): """Mass delete for machine queryset""" + from topologie.models import AccessPoint Domain.objects.filter(cname__interface_parent__machine__in=machine_queryset)._raw_delete(machine_queryset.db) Domain.objects.filter(interface_parent__machine__in=machine_queryset)._raw_delete(machine_queryset.db) Ipv6List.objects.filter(interface__machine__in=machine_queryset)._raw_delete(machine_queryset.db) Interface.objects.filter(machine__in=machine_queryset).filter(port_lists__isnull=False).delete() Interface.objects.filter(machine__in=machine_queryset)._raw_delete(machine_queryset.db) + AccessPoint.objects.filter(machine_ptr__in=machine_queryset)._raw_delete(machine_queryset.db) machine_queryset._raw_delete(machine_queryset.db) @cached_property From 693c2b567606b41f7b0f496367f5e21ef8fa70e8 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sun, 29 Sep 2019 17:57:31 +0200 Subject: [PATCH 148/228] Fix #218 --- users/management/commands/archive.py | 99 ++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 users/management/commands/archive.py diff --git a/users/management/commands/archive.py b/users/management/commands/archive.py new file mode 100644 index 00000000..c2ff7801 --- /dev/null +++ b/users/management/commands/archive.py @@ -0,0 +1,99 @@ +# ⁻*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2019 Hugo Levy--Falk +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import argparse +import datetime + +from django.core.management.base import BaseCommand, CommandError +from django.utils.timezone import make_aware + +from re2o.utils import all_has_access +from users.models import User + +def valid_date(s): + try: + return make_aware(datetime.datetime.strptime(s, "%d/%m/%Y")) + except ValueError: + msg = "Not a valid date: '{0}'.".format(s) + raise argparse.ArgumentTypeError(msg) + +class Command(BaseCommand): + help = "Allow unactive users archiving by unassigning their IP addresses." + + def add_arguments(self, parser): + parser.add_argument( + '--full', + '-f', + action='store_true', + help="Full archive users, i.e. delete their email address, machines and remove them from the LDAP." + ) + parser.add_argument( + '--date', + '-d', + default=datetime.date.today().strftime('%d/%m/%Y'), + type=valid_date, + help="Users which membership ends sooner than this date will be archived.", + ) + parser.add_argument( + '--show', + '-s', + action='store_true', + help="Only show a list of users, without doing anything." + ) + parser.add_argument( + '-y', + action='store_true', + help='Do not ask for confirmation befor full archiving.' + ) + + def handle(self, *args, **kwargs): + full_archive = kwargs["full"] + date = kwargs["date"] + force = kwargs["y"] + show = kwargs["show"] + + to_archive_list = User.objects.exclude(id__in=all_has_access()).exclude(id__in=all_has_access(search_time=date)).exclude(state=User.STATE_NOT_YET_ACTIVE).exclude(state=User.STATE_FULL_ARCHIVE) + + if show: + self.stdout.write( + "%s users found : " % to_archive_list.count() + ) + self.stdout.write('\n'.join(map(str, to_archive_list.all()))) + return + + if full_archive and not force: + self.stdout.write( + self.style.WARNING( + "Please confirm full archiving (it is a critical operation !) [Y/n]" + ) + ) + if input() != 'Y': + self.stdout.write("Leaving without archiving.") + return + if full_archive: + self.stdout.write("Full archiving users with a membership ending prior to %s" % date.strftime("%d/%m/%Y")) + User.mass_full_archive(to_archive_list) + else: + self.stdout.write("Archiving users with a membership ending prior to %s" % date.strftime("%d/%m/%Y")) + to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE) + User.mass_archive(to_archive_list) + self.stdout.write(self.style.SUCCESS("%s users were archived." % to_archive_list.count())) + From a9194b405a8bd7fc8f0646504377b6afd16575ba Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sun, 29 Sep 2019 16:02:28 +0200 Subject: [PATCH 149/228] Hello Lara :D Just ran `find /var/www/re2o \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/Goulven/Lara/g'`. --- cotisations/__init__.py | 2 +- cotisations/acl.py | 2 +- cotisations/admin.py | 2 +- cotisations/forms.py | 2 +- cotisations/migrations/0001_initial.py | 2 +- cotisations/migrations/0002_remove_facture_article.py | 2 +- cotisations/migrations/0003_auto_20160702_1448.py | 2 +- cotisations/migrations/0004_auto_20160702_1528.py | 2 +- cotisations/migrations/0005_auto_20160702_1532.py | 2 +- cotisations/migrations/0006_auto_20160702_1534.py | 2 +- cotisations/migrations/0007_auto_20160702_1543.py | 2 +- cotisations/migrations/0008_auto_20160702_1614.py | 2 +- cotisations/migrations/0009_remove_cotisation_user.py | 2 +- cotisations/migrations/0010_auto_20160702_1840.py | 2 +- cotisations/migrations/0011_auto_20160702_1911.py | 2 +- cotisations/migrations/0012_auto_20160704_0118.py | 2 +- cotisations/migrations/0013_auto_20160711_2240.py | 2 +- cotisations/migrations/0014_auto_20160712_0245.py | 2 +- cotisations/migrations/0015_auto_20160714_2142.py | 2 +- cotisations/migrations/0016_auto_20160715_0110.py | 2 +- cotisations/migrations/__init__.py | 2 +- cotisations/models.py | 2 +- cotisations/templates/cotisations/aff_article.html | 2 +- cotisations/templates/cotisations/aff_banque.html | 2 +- cotisations/templates/cotisations/aff_cotisations.html | 2 +- cotisations/templates/cotisations/aff_paiement.html | 2 +- cotisations/templates/cotisations/control.html | 2 +- cotisations/templates/cotisations/delete.html | 2 +- cotisations/templates/cotisations/edit_facture.html | 2 +- cotisations/templates/cotisations/facture.html | 2 +- cotisations/templates/cotisations/index.html | 2 +- cotisations/templates/cotisations/index_article.html | 2 +- cotisations/templates/cotisations/index_banque.html | 2 +- cotisations/templates/cotisations/index_cost_estimate.html | 2 +- cotisations/templates/cotisations/index_custom_invoice.html | 2 +- cotisations/templates/cotisations/index_paiement.html | 2 +- cotisations/templates/cotisations/payment.html | 2 +- cotisations/templates/cotisations/sidebar.html | 2 +- cotisations/tests.py | 2 +- cotisations/tex.py | 2 +- cotisations/urls.py | 2 +- cotisations/views.py | 4 ++-- freeradius_utils/auth.py | 2 +- logs/__init__.py | 2 +- logs/acl.py | 2 +- logs/templates/logs/aff_stats_general.html | 2 +- logs/templates/logs/aff_stats_logs.html | 2 +- logs/templates/logs/aff_stats_models.html | 2 +- logs/templates/logs/aff_stats_users.html | 2 +- logs/templates/logs/aff_summary.html | 2 +- logs/templates/logs/delete.html | 2 +- logs/templates/logs/index.html | 2 +- logs/templates/logs/sidebar.html | 2 +- logs/templates/logs/stats_general.html | 2 +- logs/templates/logs/stats_logs.html | 2 +- logs/templates/logs/stats_models.html | 2 +- logs/templates/logs/stats_users.html | 2 +- logs/templatetags/__init__.py | 2 +- logs/templatetags/logs_extra.py | 2 +- logs/tests.py | 2 +- logs/urls.py | 2 +- logs/views.py | 2 +- machines/__init__.py | 2 +- machines/acl.py | 2 +- machines/admin.py | 2 +- machines/forms.py | 2 +- machines/migrations/0001_initial.py | 2 +- machines/migrations/0002_auto_20160703_1444.py | 2 +- machines/migrations/0003_auto_20160703_1450.py | 2 +- machines/migrations/0004_auto_20160703_1451.py | 2 +- machines/migrations/0005_auto_20160703_1523.py | 2 +- machines/migrations/0006_auto_20160703_1813.py | 2 +- machines/migrations/0007_auto_20160703_1816.py | 2 +- machines/migrations/0008_remove_interface_ipv6.py | 2 +- machines/migrations/0009_auto_20160703_2358.py | 2 +- machines/migrations/0010_auto_20160704_0104.py | 2 +- machines/migrations/0011_auto_20160704_0105.py | 2 +- machines/migrations/0012_auto_20160704_0118.py | 2 +- machines/migrations/0013_auto_20160705_1014.py | 2 +- machines/migrations/0014_auto_20160706_1220.py | 2 +- machines/migrations/0015_auto_20160707_0105.py | 2 +- machines/migrations/0016_auto_20160708_1633.py | 2 +- machines/migrations/0017_auto_20160708_1645.py | 2 +- machines/migrations/0018_auto_20160708_1813.py | 2 +- machines/migrations/0019_auto_20160718_1141.py | 2 +- machines/migrations/0020_auto_20160718_1849.py | 2 +- machines/migrations/0021_auto_20161006_1943.py | 2 +- machines/migrations/0022_auto_20161011_1829.py | 2 +- machines/migrations/0023_iplist_ip_type.py | 2 +- machines/migrations/0024_machinetype_need_infra.py | 2 +- machines/migrations/0025_auto_20161023_0038.py | 2 +- machines/migrations/0026_auto_20161026_1348.py | 2 +- machines/migrations/0027_alias.py | 2 +- machines/migrations/0028_iptype_domaine_ip.py | 2 +- machines/migrations/0029_iptype_domaine_range.py | 2 +- machines/migrations/0030_auto_20161118_1730.py | 2 +- machines/migrations/0031_auto_20161119_1709.py | 2 +- machines/migrations/0032_auto_20161119_1850.py | 2 +- machines/migrations/0033_extension_need_infra.py | 2 +- machines/migrations/0034_iplist_need_infra.py | 2 +- machines/migrations/0035_auto_20161224_1201.py | 2 +- machines/migrations/0036_auto_20161224_1204.py | 2 +- machines/migrations/0037_domain_cname.py | 2 +- machines/migrations/0038_auto_20161224_1721.py | 2 +- machines/migrations/0039_auto_20161224_1732.py | 2 +- machines/migrations/0040_remove_interface_dns.py | 2 +- machines/migrations/0041_remove_ns_interface.py | 2 +- machines/migrations/0042_ns_ns.py | 2 +- machines/migrations/__init__.py | 2 +- machines/models.py | 2 +- machines/serializers.py | 2 +- machines/templates/machines/aff_alias.html | 2 +- machines/templates/machines/aff_extension.html | 2 +- machines/templates/machines/aff_iptype.html | 2 +- machines/templates/machines/aff_ipv6.html | 2 +- machines/templates/machines/aff_machines.html | 2 +- machines/templates/machines/aff_machinetype.html | 2 +- machines/templates/machines/aff_mx.html | 2 +- machines/templates/machines/aff_nas.html | 2 +- machines/templates/machines/aff_ns.html | 2 +- machines/templates/machines/aff_role.html | 2 +- machines/templates/machines/aff_servers.html | 2 +- machines/templates/machines/aff_service.html | 2 +- machines/templates/machines/aff_soa.html | 2 +- machines/templates/machines/aff_srv.html | 2 +- machines/templates/machines/aff_txt.html | 2 +- machines/templates/machines/aff_vlan.html | 2 +- machines/templates/machines/delete.html | 2 +- machines/templates/machines/edit_portlist.html | 2 +- machines/templates/machines/index.html | 2 +- machines/templates/machines/index_alias.html | 2 +- machines/templates/machines/index_extension.html | 2 +- machines/templates/machines/index_iptype.html | 2 +- machines/templates/machines/index_ipv6.html | 2 +- machines/templates/machines/index_machinetype.html | 2 +- machines/templates/machines/index_nas.html | 2 +- machines/templates/machines/index_role.html | 2 +- machines/templates/machines/index_service.html | 2 +- machines/templates/machines/index_vlan.html | 2 +- machines/templates/machines/machine.html | 2 +- machines/templates/machines/sidebar.html | 2 +- machines/tests.py | 2 +- machines/urls.py | 2 +- machines/views.py | 2 +- preferences/__init__.py | 2 +- preferences/acl.py | 2 +- preferences/admin.py | 2 +- preferences/forms.py | 2 +- preferences/models.py | 2 +- preferences/templates/preferences/aff_document_template.html | 2 +- preferences/templates/preferences/aff_mailcontact.html | 2 +- preferences/templates/preferences/aff_radiuskey.html | 2 +- preferences/templates/preferences/aff_reminder.html | 2 +- preferences/templates/preferences/aff_service.html | 2 +- .../templates/preferences/aff_switchmanagementcred.html | 2 +- preferences/templates/preferences/delete.html | 2 +- preferences/templates/preferences/display_preferences.html | 2 +- preferences/templates/preferences/edit_preferences.html | 2 +- preferences/templates/preferences/preferences.html | 2 +- preferences/templates/preferences/sidebar.html | 2 +- preferences/tests.py | 2 +- preferences/urls.py | 2 +- preferences/views.py | 2 +- re2o/__init__.py | 2 +- re2o/acl.py | 2 +- re2o/aes_field.py | 2 +- re2o/context_processors.py | 2 +- re2o/contributors.py | 2 +- re2o/field_permissions.py | 2 +- re2o/login.py | 4 ++-- re2o/settings.py | 2 +- re2o/settings_local.example.py | 2 +- re2o/templates/re2o/about.html | 2 +- re2o/templates/re2o/aff_history.html | 2 +- re2o/templates/re2o/contact.html | 2 +- re2o/templates/re2o/history.html | 2 +- re2o/templates/re2o/index.html | 2 +- re2o/templates/re2o/sidebar.html | 2 +- re2o/templatetags/self_adhesion.py | 2 +- re2o/urls.py | 2 +- re2o/utils.py | 4 ++-- re2o/views.py | 2 +- re2o/wsgi.py | 2 +- search/__init__.py | 2 +- search/acl.py | 2 +- search/admin.py | 2 +- search/forms.py | 2 +- search/templates/search/index.html | 2 +- search/templates/search/search.html | 2 +- search/templates/search/sidebar.html | 2 +- search/tests.py | 2 +- search/urls.py | 2 +- search/views.py | 4 ++-- templates/base.html | 2 +- templates/buttons/add.html | 2 +- templates/buttons/edit.html | 2 +- templates/buttons/history.html | 2 +- templates/buttons/multiple_checkbox_alt.html | 2 +- templates/buttons/sort.html | 2 +- templates/buttons/suppr.html | 2 +- templates/pagination.html | 2 +- templates/registration/login.html | 2 +- test_utils/runner.py | 2 +- tickets/templates/tickets/aff_ticket.html | 2 +- tickets/templates/tickets/aff_tickets.html | 2 +- tickets/templates/tickets/form_preferences.html | 2 +- tickets/templates/tickets/form_ticket.html | 2 +- tickets/templates/tickets/index.html | 2 +- tickets/views.py | 4 ++-- topologie/__init__.py | 2 +- topologie/acl.py | 2 +- topologie/admin.py | 2 +- topologie/forms.py | 2 +- topologie/migrations/0001_initial.py | 2 +- topologie/migrations/0002_auto_20160703_1118.py | 2 +- topologie/migrations/0003_room.py | 2 +- topologie/migrations/0004_auto_20160703_1122.py | 2 +- topologie/migrations/0005_auto_20160703_1123.py | 2 +- topologie/migrations/0006_auto_20160703_1129.py | 2 +- topologie/migrations/0007_auto_20160703_1148.py | 2 +- topologie/migrations/0008_port_room.py | 2 +- topologie/migrations/0009_auto_20160703_1200.py | 2 +- topologie/migrations/0010_auto_20160704_2148.py | 2 +- topologie/migrations/0011_auto_20160704_2153.py | 2 +- topologie/migrations/0012_port_machine_interface.py | 2 +- topologie/migrations/0013_port_related.py | 2 +- topologie/migrations/0014_auto_20160706_1238.py | 2 +- topologie/migrations/0015_auto_20160706_1452.py | 2 +- topologie/migrations/0016_auto_20160706_1531.py | 2 +- topologie/migrations/0017_auto_20160718_1141.py | 2 +- topologie/migrations/0018_room_details.py | 2 +- topologie/migrations/0019_auto_20161026_1348.py | 2 +- topologie/migrations/0020_auto_20161119_0033.py | 2 +- topologie/migrations/0021_port_radius.py | 2 +- topologie/migrations/0022_auto_20161211_1622.py | 2 +- topologie/migrations/__init__.py | 2 +- topologie/models.py | 2 +- topologie/templates/topologie/aff_ap.html | 2 +- topologie/templates/topologie/aff_building.html | 2 +- topologie/templates/topologie/aff_chambres.html | 2 +- topologie/templates/topologie/aff_constructor_switch.html | 2 +- topologie/templates/topologie/aff_dormitory.html | 2 +- topologie/templates/topologie/aff_model_switch.html | 2 +- topologie/templates/topologie/aff_modules.html | 2 +- topologie/templates/topologie/aff_port.html | 2 +- topologie/templates/topologie/aff_repr_switch.html | 2 +- topologie/templates/topologie/aff_stacks.html | 2 +- topologie/templates/topologie/aff_switch.html | 2 +- topologie/templates/topologie/aff_switch_bay.html | 2 +- topologie/templates/topologie/aff_vlanoptions.html | 2 +- topologie/templates/topologie/delete.html | 2 +- topologie/templates/topologie/edit_stack_sw.html | 2 +- topologie/templates/topologie/index.html | 2 +- topologie/templates/topologie/index_ap.html | 2 +- topologie/templates/topologie/index_model_switch.html | 2 +- topologie/templates/topologie/index_module.html | 2 +- topologie/templates/topologie/index_p.html | 2 +- topologie/templates/topologie/index_physical_grouping.html | 2 +- topologie/templates/topologie/index_room.html | 2 +- topologie/templates/topologie/sidebar.html | 2 +- topologie/templates/topologie/switch.html | 2 +- topologie/templates/topologie/topo.html | 2 +- topologie/templates/topologie/topo_more.html | 2 +- topologie/tests.py | 2 +- topologie/urls.py | 2 +- topologie/views.py | 2 +- users/__init__.py | 2 +- users/acl.py | 2 +- users/admin.py | 2 +- users/forms.py | 2 +- users/management/commands/clean_notyetactive.py | 2 +- users/management/commands/ldap_sync.py | 2 +- users/migrations/0001_initial.py | 2 +- users/migrations/0002_auto_20160630_2301.py | 2 +- users/migrations/0003_listrights_rights.py | 2 +- users/migrations/0004_auto_20160701_2312.py | 2 +- users/migrations/0005_auto_20160702_0006.py | 2 +- users/migrations/0006_ban.py | 2 +- users/migrations/0007_auto_20160702_2322.py | 2 +- users/migrations/0008_user_registered.py | 2 +- users/migrations/0009_user_room.py | 2 +- users/migrations/0010_auto_20160703_1226.py | 2 +- users/migrations/0011_auto_20160703_1227.py | 2 +- users/migrations/0012_auto_20160703_1230.py | 2 +- users/migrations/0013_auto_20160704_1547.py | 2 +- users/migrations/0014_auto_20160704_1548.py | 2 +- users/migrations/0015_whitelist.py | 2 +- users/migrations/0016_auto_20160706_1220.py | 2 +- users/migrations/0017_auto_20160707_0105.py | 2 +- users/migrations/0018_auto_20160707_0115.py | 2 +- users/migrations/0019_auto_20160708_1633.py | 2 +- users/migrations/0020_request.py | 2 +- users/migrations/0021_ldapuser.py | 2 +- users/migrations/0022_ldapuser_sambasid.py | 2 +- users/migrations/0023_auto_20160724_1908.py | 2 +- users/migrations/0024_remove_ldapuser_mac_list.py | 2 +- users/migrations/0025_listshell.py | 2 +- users/migrations/0026_user_shell.py | 2 +- users/migrations/0027_auto_20160726_0216.py | 2 +- users/migrations/0028_auto_20160726_0227.py | 2 +- users/migrations/0029_auto_20160726_0229.py | 2 +- users/migrations/0030_auto_20160726_0357.py | 2 +- users/migrations/0031_auto_20160726_0359.py | 2 +- users/migrations/0032_auto_20160727_2122.py | 2 +- users/migrations/0033_remove_ldapuser_loginshell.py | 2 +- users/migrations/0034_auto_20161018_0037.py | 2 +- users/migrations/0035_auto_20161018_0046.py | 2 +- users/migrations/0036_auto_20161022_2146.py | 2 +- users/migrations/0037_auto_20161028_1906.py | 2 +- users/migrations/0038_auto_20161031_0258.py | 2 +- users/migrations/0039_auto_20161119_0033.py | 2 +- users/migrations/0040_auto_20161119_1709.py | 2 +- users/migrations/0041_listright_details.py | 2 +- users/migrations/0042_auto_20161126_2028.py | 2 +- users/migrations/__init__.py | 2 +- users/models.py | 2 +- users/serializers.py | 2 +- users/templates/users/aff_bans.html | 2 +- users/templates/users/aff_clubs.html | 2 +- users/templates/users/aff_emailaddress.html | 2 +- users/templates/users/aff_listright.html | 2 +- users/templates/users/aff_rights.html | 2 +- users/templates/users/aff_schools.html | 2 +- users/templates/users/aff_serviceusers.html | 2 +- users/templates/users/aff_shell.html | 2 +- users/templates/users/aff_users.html | 2 +- users/templates/users/aff_whitelists.html | 2 +- users/templates/users/delete.html | 2 +- users/templates/users/index.html | 2 +- users/templates/users/index_ban.html | 2 +- users/templates/users/index_clubs.html | 2 +- users/templates/users/index_emailaddress.html | 2 +- users/templates/users/index_listright.html | 2 +- users/templates/users/index_rights.html | 2 +- users/templates/users/index_schools.html | 2 +- users/templates/users/index_serviceusers.html | 2 +- users/templates/users/index_shell.html | 2 +- users/templates/users/index_whitelist.html | 2 +- users/templates/users/mass_archive.html | 2 +- users/templates/users/plugin_out.html | 2 +- users/templates/users/profil.html | 2 +- users/templates/users/sidebar.html | 2 +- users/templates/users/user.html | 2 +- users/templates/users/user_autocapture.html | 2 +- users/tests.py | 2 +- users/urls.py | 2 +- users/views.py | 4 ++-- 347 files changed, 353 insertions(+), 353 deletions(-) diff --git a/cotisations/__init__.py b/cotisations/__init__.py index ee5a305d..be5cb5d2 100644 --- a/cotisations/__init__.py +++ b/cotisations/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/acl.py b/cotisations/acl.py index 1b1611ab..ce0b1eff 100644 --- a/cotisations/acl.py +++ b/cotisations/acl.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/admin.py b/cotisations/admin.py index 4b47ccc8..44af149d 100644 --- a/cotisations/admin.py +++ b/cotisations/admin.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/forms.py b/cotisations/forms.py index 39c194ec..8ae4ae29 100644 --- a/cotisations/forms.py +++ b/cotisations/forms.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2018 Hugo Levy-Falk # diff --git a/cotisations/migrations/0001_initial.py b/cotisations/migrations/0001_initial.py index 63df0077..b235f605 100644 --- a/cotisations/migrations/0001_initial.py +++ b/cotisations/migrations/0001_initial.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0002_remove_facture_article.py b/cotisations/migrations/0002_remove_facture_article.py index 1122ac5f..b8617be4 100644 --- a/cotisations/migrations/0002_remove_facture_article.py +++ b/cotisations/migrations/0002_remove_facture_article.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0003_auto_20160702_1448.py b/cotisations/migrations/0003_auto_20160702_1448.py index dd611edc..f8c2681f 100644 --- a/cotisations/migrations/0003_auto_20160702_1448.py +++ b/cotisations/migrations/0003_auto_20160702_1448.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0004_auto_20160702_1528.py b/cotisations/migrations/0004_auto_20160702_1528.py index 4489008c..8a92b54a 100644 --- a/cotisations/migrations/0004_auto_20160702_1528.py +++ b/cotisations/migrations/0004_auto_20160702_1528.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0005_auto_20160702_1532.py b/cotisations/migrations/0005_auto_20160702_1532.py index 4042fe9c..8e29e93d 100644 --- a/cotisations/migrations/0005_auto_20160702_1532.py +++ b/cotisations/migrations/0005_auto_20160702_1532.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0006_auto_20160702_1534.py b/cotisations/migrations/0006_auto_20160702_1534.py index b55edebd..affe71f7 100644 --- a/cotisations/migrations/0006_auto_20160702_1534.py +++ b/cotisations/migrations/0006_auto_20160702_1534.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0007_auto_20160702_1543.py b/cotisations/migrations/0007_auto_20160702_1543.py index ca0507ec..58b9200b 100644 --- a/cotisations/migrations/0007_auto_20160702_1543.py +++ b/cotisations/migrations/0007_auto_20160702_1543.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0008_auto_20160702_1614.py b/cotisations/migrations/0008_auto_20160702_1614.py index 63ae27e9..c94db952 100644 --- a/cotisations/migrations/0008_auto_20160702_1614.py +++ b/cotisations/migrations/0008_auto_20160702_1614.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0009_remove_cotisation_user.py b/cotisations/migrations/0009_remove_cotisation_user.py index b93f9f70..0347ca95 100644 --- a/cotisations/migrations/0009_remove_cotisation_user.py +++ b/cotisations/migrations/0009_remove_cotisation_user.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0010_auto_20160702_1840.py b/cotisations/migrations/0010_auto_20160702_1840.py index 76780e28..c57d013b 100644 --- a/cotisations/migrations/0010_auto_20160702_1840.py +++ b/cotisations/migrations/0010_auto_20160702_1840.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0011_auto_20160702_1911.py b/cotisations/migrations/0011_auto_20160702_1911.py index 250ef78c..3bb82f45 100644 --- a/cotisations/migrations/0011_auto_20160702_1911.py +++ b/cotisations/migrations/0011_auto_20160702_1911.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0012_auto_20160704_0118.py b/cotisations/migrations/0012_auto_20160704_0118.py index 056f21fd..64fab6da 100644 --- a/cotisations/migrations/0012_auto_20160704_0118.py +++ b/cotisations/migrations/0012_auto_20160704_0118.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0013_auto_20160711_2240.py b/cotisations/migrations/0013_auto_20160711_2240.py index c4a636c4..69e437b8 100644 --- a/cotisations/migrations/0013_auto_20160711_2240.py +++ b/cotisations/migrations/0013_auto_20160711_2240.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0014_auto_20160712_0245.py b/cotisations/migrations/0014_auto_20160712_0245.py index fa4c3af7..530ba427 100644 --- a/cotisations/migrations/0014_auto_20160712_0245.py +++ b/cotisations/migrations/0014_auto_20160712_0245.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0015_auto_20160714_2142.py b/cotisations/migrations/0015_auto_20160714_2142.py index 7e666e4d..203d2702 100644 --- a/cotisations/migrations/0015_auto_20160714_2142.py +++ b/cotisations/migrations/0015_auto_20160714_2142.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/0016_auto_20160715_0110.py b/cotisations/migrations/0016_auto_20160715_0110.py index 205cdb3d..79c7ba56 100644 --- a/cotisations/migrations/0016_auto_20160715_0110.py +++ b/cotisations/migrations/0016_auto_20160715_0110.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/migrations/__init__.py b/cotisations/migrations/__init__.py index 20abb0d2..b2b50566 100644 --- a/cotisations/migrations/__init__.py +++ b/cotisations/migrations/__init__.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/models.py b/cotisations/models.py index 8174e0bb..3cb64ec3 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2018 Hugo Levy-Falk # diff --git a/cotisations/templates/cotisations/aff_article.html b/cotisations/templates/cotisations/aff_article.html index 682d6a05..df187abb 100644 --- a/cotisations/templates/cotisations/aff_article.html +++ b/cotisations/templates/cotisations/aff_article.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/aff_banque.html b/cotisations/templates/cotisations/aff_banque.html index 057c6995..1bf1fcd2 100644 --- a/cotisations/templates/cotisations/aff_banque.html +++ b/cotisations/templates/cotisations/aff_banque.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/aff_cotisations.html b/cotisations/templates/cotisations/aff_cotisations.html index e27ae8c7..b9a1a810 100644 --- a/cotisations/templates/cotisations/aff_cotisations.html +++ b/cotisations/templates/cotisations/aff_cotisations.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/aff_paiement.html b/cotisations/templates/cotisations/aff_paiement.html index afb78b48..edd485f1 100644 --- a/cotisations/templates/cotisations/aff_paiement.html +++ b/cotisations/templates/cotisations/aff_paiement.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/control.html b/cotisations/templates/cotisations/control.html index 5a18bd01..b199ba2d 100644 --- a/cotisations/templates/cotisations/control.html +++ b/cotisations/templates/cotisations/control.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/delete.html b/cotisations/templates/cotisations/delete.html index e6060d09..483dd218 100644 --- a/cotisations/templates/cotisations/delete.html +++ b/cotisations/templates/cotisations/delete.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/edit_facture.html b/cotisations/templates/cotisations/edit_facture.html index 891f7476..99dd2cd8 100644 --- a/cotisations/templates/cotisations/edit_facture.html +++ b/cotisations/templates/cotisations/edit_facture.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/facture.html b/cotisations/templates/cotisations/facture.html index 4f42f8e8..df29a2cb 100644 --- a/cotisations/templates/cotisations/facture.html +++ b/cotisations/templates/cotisations/facture.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/index.html b/cotisations/templates/cotisations/index.html index 42b8a3bf..ba3a3ea4 100644 --- a/cotisations/templates/cotisations/index.html +++ b/cotisations/templates/cotisations/index.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/index_article.html b/cotisations/templates/cotisations/index_article.html index 5f93b5ce..8adc7639 100644 --- a/cotisations/templates/cotisations/index_article.html +++ b/cotisations/templates/cotisations/index_article.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/index_banque.html b/cotisations/templates/cotisations/index_banque.html index 87067222..a497198f 100644 --- a/cotisations/templates/cotisations/index_banque.html +++ b/cotisations/templates/cotisations/index_banque.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/index_cost_estimate.html b/cotisations/templates/cotisations/index_cost_estimate.html index c3d57197..0d2fad01 100644 --- a/cotisations/templates/cotisations/index_cost_estimate.html +++ b/cotisations/templates/cotisations/index_cost_estimate.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/index_custom_invoice.html b/cotisations/templates/cotisations/index_custom_invoice.html index 9b539614..cbc502d2 100644 --- a/cotisations/templates/cotisations/index_custom_invoice.html +++ b/cotisations/templates/cotisations/index_custom_invoice.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/index_paiement.html b/cotisations/templates/cotisations/index_paiement.html index 09b7e033..b76dec65 100644 --- a/cotisations/templates/cotisations/index_paiement.html +++ b/cotisations/templates/cotisations/index_paiement.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/payment.html b/cotisations/templates/cotisations/payment.html index ceb8db6f..39dbb195 100644 --- a/cotisations/templates/cotisations/payment.html +++ b/cotisations/templates/cotisations/payment.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/templates/cotisations/sidebar.html b/cotisations/templates/cotisations/sidebar.html index 608f95c2..96a674f9 100644 --- a/cotisations/templates/cotisations/sidebar.html +++ b/cotisations/templates/cotisations/sidebar.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/cotisations/tests.py b/cotisations/tests.py index 46b9d708..b2ecee78 100644 --- a/cotisations/tests.py +++ b/cotisations/tests.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/tex.py b/cotisations/tex.py index d843049b..dd519122 100644 --- a/cotisations/tex.py +++ b/cotisations/tex.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/urls.py b/cotisations/urls.py index 0c7256f7..9cc6e62c 100644 --- a/cotisations/urls.py +++ b/cotisations/urls.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/cotisations/views.py b/cotisations/views.py index 0e7212fa..e53b8553 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2018 Hugo Levy-Falk # @@ -22,7 +22,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # App de gestion des users pour re2o -# Goulven Kermarec, Gabriel Détraz +# Lara Kermarec, Gabriel Détraz # Gplv2 """cotisations.views The different views used in the Cotisations module diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index c2cb3fed..212ada1e 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -5,7 +5,7 @@ # # Copyirght © 2017 Daniel Stan # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/logs/__init__.py b/logs/__init__.py index 20338670..32f6fa7d 100644 --- a/logs/__init__.py +++ b/logs/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/logs/acl.py b/logs/acl.py index b4df34af..7c68add1 100644 --- a/logs/acl.py +++ b/logs/acl.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/aff_stats_general.html b/logs/templates/logs/aff_stats_general.html index 662efa54..48d79b92 100644 --- a/logs/templates/logs/aff_stats_general.html +++ b/logs/templates/logs/aff_stats_general.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/aff_stats_logs.html b/logs/templates/logs/aff_stats_logs.html index 44a937f9..adccc95f 100644 --- a/logs/templates/logs/aff_stats_logs.html +++ b/logs/templates/logs/aff_stats_logs.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/aff_stats_models.html b/logs/templates/logs/aff_stats_models.html index 7809dfdf..93e14109 100644 --- a/logs/templates/logs/aff_stats_models.html +++ b/logs/templates/logs/aff_stats_models.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/aff_stats_users.html b/logs/templates/logs/aff_stats_users.html index 0ea6a426..4978b2ad 100644 --- a/logs/templates/logs/aff_stats_users.html +++ b/logs/templates/logs/aff_stats_users.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/aff_summary.html b/logs/templates/logs/aff_summary.html index 3c43e2ac..cf1725b0 100644 --- a/logs/templates/logs/aff_summary.html +++ b/logs/templates/logs/aff_summary.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/delete.html b/logs/templates/logs/delete.html index a8f6b52f..3bd0d638 100644 --- a/logs/templates/logs/delete.html +++ b/logs/templates/logs/delete.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/index.html b/logs/templates/logs/index.html index 3bd61b40..cc446f5b 100644 --- a/logs/templates/logs/index.html +++ b/logs/templates/logs/index.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/sidebar.html b/logs/templates/logs/sidebar.html index e997abd5..7f7d6cbf 100644 --- a/logs/templates/logs/sidebar.html +++ b/logs/templates/logs/sidebar.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/stats_general.html b/logs/templates/logs/stats_general.html index 96d5612c..e7021716 100644 --- a/logs/templates/logs/stats_general.html +++ b/logs/templates/logs/stats_general.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/stats_logs.html b/logs/templates/logs/stats_logs.html index df9708b1..e3314cb2 100644 --- a/logs/templates/logs/stats_logs.html +++ b/logs/templates/logs/stats_logs.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/stats_models.html b/logs/templates/logs/stats_models.html index ddc66c15..03b82b37 100644 --- a/logs/templates/logs/stats_models.html +++ b/logs/templates/logs/stats_models.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templates/logs/stats_users.html b/logs/templates/logs/stats_users.html index d55d1e52..de706833 100644 --- a/logs/templates/logs/stats_users.html +++ b/logs/templates/logs/stats_users.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/logs/templatetags/__init__.py b/logs/templatetags/__init__.py index cd256e09..b8b9a128 100644 --- a/logs/templatetags/__init__.py +++ b/logs/templatetags/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/logs/templatetags/logs_extra.py b/logs/templatetags/logs_extra.py index 813a577f..8aba7563 100644 --- a/logs/templatetags/logs_extra.py +++ b/logs/templatetags/logs_extra.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/logs/tests.py b/logs/tests.py index 65679fa3..51ef33ae 100644 --- a/logs/tests.py +++ b/logs/tests.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/logs/urls.py b/logs/urls.py index 9398cfe4..7496b50a 100644 --- a/logs/urls.py +++ b/logs/urls.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/logs/views.py b/logs/views.py index 47ceab06..a3c8fe47 100644 --- a/logs/views.py +++ b/logs/views.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2018 Gabriel Détraz -# Copyright © 2018 Goulven Kermarec +# Copyright © 2018 Lara Kermarec # Copyright © 2018 Augustin Lemesle # Copyright © 2018 Hugo Levy-Falk # diff --git a/machines/__init__.py b/machines/__init__.py index f874399a..4f7225d5 100644 --- a/machines/__init__.py +++ b/machines/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/acl.py b/machines/acl.py index 477df6f9..b61ac5ae 100644 --- a/machines/acl.py +++ b/machines/acl.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/admin.py b/machines/admin.py index 099fa1ba..2d763cb4 100644 --- a/machines/admin.py +++ b/machines/admin.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/forms.py b/machines/forms.py index 4ea2323b..6a9f287d 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2017 Maël Kervella # diff --git a/machines/migrations/0001_initial.py b/machines/migrations/0001_initial.py index b9f1bb9f..64eb9d3b 100644 --- a/machines/migrations/0001_initial.py +++ b/machines/migrations/0001_initial.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0002_auto_20160703_1444.py b/machines/migrations/0002_auto_20160703_1444.py index e8203b19..6b3d8588 100644 --- a/machines/migrations/0002_auto_20160703_1444.py +++ b/machines/migrations/0002_auto_20160703_1444.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0003_auto_20160703_1450.py b/machines/migrations/0003_auto_20160703_1450.py index 89a1862f..89b22311 100644 --- a/machines/migrations/0003_auto_20160703_1450.py +++ b/machines/migrations/0003_auto_20160703_1450.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0004_auto_20160703_1451.py b/machines/migrations/0004_auto_20160703_1451.py index 7e8c344e..29061e15 100644 --- a/machines/migrations/0004_auto_20160703_1451.py +++ b/machines/migrations/0004_auto_20160703_1451.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0005_auto_20160703_1523.py b/machines/migrations/0005_auto_20160703_1523.py index 10ca1acb..0666147a 100644 --- a/machines/migrations/0005_auto_20160703_1523.py +++ b/machines/migrations/0005_auto_20160703_1523.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0006_auto_20160703_1813.py b/machines/migrations/0006_auto_20160703_1813.py index fb4b2adf..ae408269 100644 --- a/machines/migrations/0006_auto_20160703_1813.py +++ b/machines/migrations/0006_auto_20160703_1813.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0007_auto_20160703_1816.py b/machines/migrations/0007_auto_20160703_1816.py index a1cff4cd..0f3cd574 100644 --- a/machines/migrations/0007_auto_20160703_1816.py +++ b/machines/migrations/0007_auto_20160703_1816.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0008_remove_interface_ipv6.py b/machines/migrations/0008_remove_interface_ipv6.py index c96f7188..1e569c25 100644 --- a/machines/migrations/0008_remove_interface_ipv6.py +++ b/machines/migrations/0008_remove_interface_ipv6.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0009_auto_20160703_2358.py b/machines/migrations/0009_auto_20160703_2358.py index 454cfb91..eef5659e 100644 --- a/machines/migrations/0009_auto_20160703_2358.py +++ b/machines/migrations/0009_auto_20160703_2358.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0010_auto_20160704_0104.py b/machines/migrations/0010_auto_20160704_0104.py index 87ff48d2..de60578d 100644 --- a/machines/migrations/0010_auto_20160704_0104.py +++ b/machines/migrations/0010_auto_20160704_0104.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0011_auto_20160704_0105.py b/machines/migrations/0011_auto_20160704_0105.py index a595ee49..c2bd2158 100644 --- a/machines/migrations/0011_auto_20160704_0105.py +++ b/machines/migrations/0011_auto_20160704_0105.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0012_auto_20160704_0118.py b/machines/migrations/0012_auto_20160704_0118.py index 7a22e166..6d924e01 100644 --- a/machines/migrations/0012_auto_20160704_0118.py +++ b/machines/migrations/0012_auto_20160704_0118.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0013_auto_20160705_1014.py b/machines/migrations/0013_auto_20160705_1014.py index edd636b7..ed497ac2 100644 --- a/machines/migrations/0013_auto_20160705_1014.py +++ b/machines/migrations/0013_auto_20160705_1014.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0014_auto_20160706_1220.py b/machines/migrations/0014_auto_20160706_1220.py index dbfe0edb..8f5d63da 100644 --- a/machines/migrations/0014_auto_20160706_1220.py +++ b/machines/migrations/0014_auto_20160706_1220.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0015_auto_20160707_0105.py b/machines/migrations/0015_auto_20160707_0105.py index e12409f6..7e670949 100644 --- a/machines/migrations/0015_auto_20160707_0105.py +++ b/machines/migrations/0015_auto_20160707_0105.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0016_auto_20160708_1633.py b/machines/migrations/0016_auto_20160708_1633.py index 6269e717..ab3f3c19 100644 --- a/machines/migrations/0016_auto_20160708_1633.py +++ b/machines/migrations/0016_auto_20160708_1633.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0017_auto_20160708_1645.py b/machines/migrations/0017_auto_20160708_1645.py index 2dbe8daa..da8253a1 100644 --- a/machines/migrations/0017_auto_20160708_1645.py +++ b/machines/migrations/0017_auto_20160708_1645.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0018_auto_20160708_1813.py b/machines/migrations/0018_auto_20160708_1813.py index 40ad7af3..164e986f 100644 --- a/machines/migrations/0018_auto_20160708_1813.py +++ b/machines/migrations/0018_auto_20160708_1813.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0019_auto_20160718_1141.py b/machines/migrations/0019_auto_20160718_1141.py index 1c7189c4..ba34c076 100644 --- a/machines/migrations/0019_auto_20160718_1141.py +++ b/machines/migrations/0019_auto_20160718_1141.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0020_auto_20160718_1849.py b/machines/migrations/0020_auto_20160718_1849.py index 669eb7f0..83cd66ae 100644 --- a/machines/migrations/0020_auto_20160718_1849.py +++ b/machines/migrations/0020_auto_20160718_1849.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0021_auto_20161006_1943.py b/machines/migrations/0021_auto_20161006_1943.py index b69efbf0..e0a90ed9 100644 --- a/machines/migrations/0021_auto_20161006_1943.py +++ b/machines/migrations/0021_auto_20161006_1943.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0022_auto_20161011_1829.py b/machines/migrations/0022_auto_20161011_1829.py index 5d513091..3d88148a 100644 --- a/machines/migrations/0022_auto_20161011_1829.py +++ b/machines/migrations/0022_auto_20161011_1829.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0023_iplist_ip_type.py b/machines/migrations/0023_iplist_ip_type.py index d15294b8..a1412b4f 100644 --- a/machines/migrations/0023_iplist_ip_type.py +++ b/machines/migrations/0023_iplist_ip_type.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0024_machinetype_need_infra.py b/machines/migrations/0024_machinetype_need_infra.py index 529e8ddc..019ae2b0 100644 --- a/machines/migrations/0024_machinetype_need_infra.py +++ b/machines/migrations/0024_machinetype_need_infra.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0025_auto_20161023_0038.py b/machines/migrations/0025_auto_20161023_0038.py index d37dcf8d..6c20d4bf 100644 --- a/machines/migrations/0025_auto_20161023_0038.py +++ b/machines/migrations/0025_auto_20161023_0038.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0026_auto_20161026_1348.py b/machines/migrations/0026_auto_20161026_1348.py index 69dd1b67..60cf9635 100644 --- a/machines/migrations/0026_auto_20161026_1348.py +++ b/machines/migrations/0026_auto_20161026_1348.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0027_alias.py b/machines/migrations/0027_alias.py index 99b18752..e5182352 100644 --- a/machines/migrations/0027_alias.py +++ b/machines/migrations/0027_alias.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0028_iptype_domaine_ip.py b/machines/migrations/0028_iptype_domaine_ip.py index d524514f..6cd5e4bc 100644 --- a/machines/migrations/0028_iptype_domaine_ip.py +++ b/machines/migrations/0028_iptype_domaine_ip.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0029_iptype_domaine_range.py b/machines/migrations/0029_iptype_domaine_range.py index bdd823d4..80b9fdee 100644 --- a/machines/migrations/0029_iptype_domaine_range.py +++ b/machines/migrations/0029_iptype_domaine_range.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0030_auto_20161118_1730.py b/machines/migrations/0030_auto_20161118_1730.py index 6f21e8a7..f6c67314 100644 --- a/machines/migrations/0030_auto_20161118_1730.py +++ b/machines/migrations/0030_auto_20161118_1730.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0031_auto_20161119_1709.py b/machines/migrations/0031_auto_20161119_1709.py index de995806..87814fcc 100644 --- a/machines/migrations/0031_auto_20161119_1709.py +++ b/machines/migrations/0031_auto_20161119_1709.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0032_auto_20161119_1850.py b/machines/migrations/0032_auto_20161119_1850.py index 0d2f30f8..15daff9a 100644 --- a/machines/migrations/0032_auto_20161119_1850.py +++ b/machines/migrations/0032_auto_20161119_1850.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0033_extension_need_infra.py b/machines/migrations/0033_extension_need_infra.py index d88f4d18..9a68f1de 100644 --- a/machines/migrations/0033_extension_need_infra.py +++ b/machines/migrations/0033_extension_need_infra.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0034_iplist_need_infra.py b/machines/migrations/0034_iplist_need_infra.py index 297e4279..2eae9caa 100644 --- a/machines/migrations/0034_iplist_need_infra.py +++ b/machines/migrations/0034_iplist_need_infra.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0035_auto_20161224_1201.py b/machines/migrations/0035_auto_20161224_1201.py index 81564fe9..742568eb 100644 --- a/machines/migrations/0035_auto_20161224_1201.py +++ b/machines/migrations/0035_auto_20161224_1201.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0036_auto_20161224_1204.py b/machines/migrations/0036_auto_20161224_1204.py index 3b585b36..58de1c85 100644 --- a/machines/migrations/0036_auto_20161224_1204.py +++ b/machines/migrations/0036_auto_20161224_1204.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0037_domain_cname.py b/machines/migrations/0037_domain_cname.py index b7dd198e..9e33c5d9 100644 --- a/machines/migrations/0037_domain_cname.py +++ b/machines/migrations/0037_domain_cname.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0038_auto_20161224_1721.py b/machines/migrations/0038_auto_20161224_1721.py index 574b8e58..5e481e42 100644 --- a/machines/migrations/0038_auto_20161224_1721.py +++ b/machines/migrations/0038_auto_20161224_1721.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0039_auto_20161224_1732.py b/machines/migrations/0039_auto_20161224_1732.py index 836571b2..e7bcc6f2 100644 --- a/machines/migrations/0039_auto_20161224_1732.py +++ b/machines/migrations/0039_auto_20161224_1732.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0040_remove_interface_dns.py b/machines/migrations/0040_remove_interface_dns.py index 2171f6b2..38c2a107 100644 --- a/machines/migrations/0040_remove_interface_dns.py +++ b/machines/migrations/0040_remove_interface_dns.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0041_remove_ns_interface.py b/machines/migrations/0041_remove_ns_interface.py index 15a2c87e..a4808c67 100644 --- a/machines/migrations/0041_remove_ns_interface.py +++ b/machines/migrations/0041_remove_ns_interface.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/0042_ns_ns.py b/machines/migrations/0042_ns_ns.py index 00212836..009715aa 100644 --- a/machines/migrations/0042_ns_ns.py +++ b/machines/migrations/0042_ns_ns.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/migrations/__init__.py b/machines/migrations/__init__.py index 20abb0d2..b2b50566 100644 --- a/machines/migrations/__init__.py +++ b/machines/migrations/__init__.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/models.py b/machines/models.py index fdc7821e..c2012568 100644 --- a/machines/models.py +++ b/machines/models.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2016-2018 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2018 Charlie Jacomme # diff --git a/machines/serializers.py b/machines/serializers.py index 3f5fb966..8e716e9f 100644 --- a/machines/serializers.py +++ b/machines/serializers.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_alias.html b/machines/templates/machines/aff_alias.html index ee8580b0..15b765c9 100644 --- a/machines/templates/machines/aff_alias.html +++ b/machines/templates/machines/aff_alias.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_extension.html b/machines/templates/machines/aff_extension.html index 1083b1b1..809ef4ba 100644 --- a/machines/templates/machines/aff_extension.html +++ b/machines/templates/machines/aff_extension.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_iptype.html b/machines/templates/machines/aff_iptype.html index 08372a7d..2675b87a 100644 --- a/machines/templates/machines/aff_iptype.html +++ b/machines/templates/machines/aff_iptype.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_ipv6.html b/machines/templates/machines/aff_ipv6.html index f67bf4c3..e27ba3b8 100644 --- a/machines/templates/machines/aff_ipv6.html +++ b/machines/templates/machines/aff_ipv6.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html index c444b78b..e59cfde6 100644 --- a/machines/templates/machines/aff_machines.html +++ b/machines/templates/machines/aff_machines.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_machinetype.html b/machines/templates/machines/aff_machinetype.html index d80044bb..087b27d2 100644 --- a/machines/templates/machines/aff_machinetype.html +++ b/machines/templates/machines/aff_machinetype.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_mx.html b/machines/templates/machines/aff_mx.html index b10d4eff..1393423d 100644 --- a/machines/templates/machines/aff_mx.html +++ b/machines/templates/machines/aff_mx.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_nas.html b/machines/templates/machines/aff_nas.html index 7a98a7f4..339ff608 100644 --- a/machines/templates/machines/aff_nas.html +++ b/machines/templates/machines/aff_nas.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_ns.html b/machines/templates/machines/aff_ns.html index dda578f3..97859cfd 100644 --- a/machines/templates/machines/aff_ns.html +++ b/machines/templates/machines/aff_ns.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_role.html b/machines/templates/machines/aff_role.html index 6f285c89..11b923d6 100644 --- a/machines/templates/machines/aff_role.html +++ b/machines/templates/machines/aff_role.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_servers.html b/machines/templates/machines/aff_servers.html index 4134c269..36c4bca0 100644 --- a/machines/templates/machines/aff_servers.html +++ b/machines/templates/machines/aff_servers.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_service.html b/machines/templates/machines/aff_service.html index d3eb16ba..535ddf63 100644 --- a/machines/templates/machines/aff_service.html +++ b/machines/templates/machines/aff_service.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_soa.html b/machines/templates/machines/aff_soa.html index 50a4a5c3..31905b31 100644 --- a/machines/templates/machines/aff_soa.html +++ b/machines/templates/machines/aff_soa.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_srv.html b/machines/templates/machines/aff_srv.html index 1a699b49..42f66fe5 100644 --- a/machines/templates/machines/aff_srv.html +++ b/machines/templates/machines/aff_srv.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_txt.html b/machines/templates/machines/aff_txt.html index 3da268ca..ca0988d0 100644 --- a/machines/templates/machines/aff_txt.html +++ b/machines/templates/machines/aff_txt.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/aff_vlan.html b/machines/templates/machines/aff_vlan.html index 0b10262b..f60424a2 100644 --- a/machines/templates/machines/aff_vlan.html +++ b/machines/templates/machines/aff_vlan.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/delete.html b/machines/templates/machines/delete.html index 59ba2102..3c890c67 100644 --- a/machines/templates/machines/delete.html +++ b/machines/templates/machines/delete.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/edit_portlist.html b/machines/templates/machines/edit_portlist.html index fa9f771a..387723bb 100644 --- a/machines/templates/machines/edit_portlist.html +++ b/machines/templates/machines/edit_portlist.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/index.html b/machines/templates/machines/index.html index 3aad6d06..d83d99b4 100644 --- a/machines/templates/machines/index.html +++ b/machines/templates/machines/index.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/index_alias.html b/machines/templates/machines/index_alias.html index 7f392667..a887e74b 100644 --- a/machines/templates/machines/index_alias.html +++ b/machines/templates/machines/index_alias.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/index_extension.html b/machines/templates/machines/index_extension.html index 636b314e..ad6cb4e5 100644 --- a/machines/templates/machines/index_extension.html +++ b/machines/templates/machines/index_extension.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/index_iptype.html b/machines/templates/machines/index_iptype.html index 7ffa8cf3..08f88d82 100644 --- a/machines/templates/machines/index_iptype.html +++ b/machines/templates/machines/index_iptype.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/index_ipv6.html b/machines/templates/machines/index_ipv6.html index 98ea697a..df3472dc 100644 --- a/machines/templates/machines/index_ipv6.html +++ b/machines/templates/machines/index_ipv6.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/index_machinetype.html b/machines/templates/machines/index_machinetype.html index 407aef5b..4f029791 100644 --- a/machines/templates/machines/index_machinetype.html +++ b/machines/templates/machines/index_machinetype.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/index_nas.html b/machines/templates/machines/index_nas.html index bb17395a..d9c1f39e 100644 --- a/machines/templates/machines/index_nas.html +++ b/machines/templates/machines/index_nas.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/index_role.html b/machines/templates/machines/index_role.html index 38799aa5..ab859c2e 100644 --- a/machines/templates/machines/index_role.html +++ b/machines/templates/machines/index_role.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/index_service.html b/machines/templates/machines/index_service.html index 19244e71..56886638 100644 --- a/machines/templates/machines/index_service.html +++ b/machines/templates/machines/index_service.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/index_vlan.html b/machines/templates/machines/index_vlan.html index 830cde65..dbeb4dcd 100644 --- a/machines/templates/machines/index_vlan.html +++ b/machines/templates/machines/index_vlan.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/templates/machines/machine.html b/machines/templates/machines/machine.html index 27c7ea27..0021caa2 100644 --- a/machines/templates/machines/machine.html +++ b/machines/templates/machines/machine.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle Copyright © 2017 Maël Kervella diff --git a/machines/templates/machines/sidebar.html b/machines/templates/machines/sidebar.html index f7c63f6f..c5519c8d 100644 --- a/machines/templates/machines/sidebar.html +++ b/machines/templates/machines/sidebar.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/machines/tests.py b/machines/tests.py index 2074f683..8dc56f18 100644 --- a/machines/tests.py +++ b/machines/tests.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/urls.py b/machines/urls.py index 77fb5e2e..f8518460 100644 --- a/machines/urls.py +++ b/machines/urls.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/machines/views.py b/machines/views.py index a07d7e75..a9bbd215 100644 --- a/machines/views.py +++ b/machines/views.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2016-2018 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2017-2018 Maël Kervella # Copyright © 2018 Charlie Jacomme diff --git a/preferences/__init__.py b/preferences/__init__.py index c287fce8..74c32297 100644 --- a/preferences/__init__.py +++ b/preferences/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2018 Maël Kervella # diff --git a/preferences/acl.py b/preferences/acl.py index 08bfd8e7..bfa83dec 100644 --- a/preferences/acl.py +++ b/preferences/acl.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/preferences/admin.py b/preferences/admin.py index efeefc87..ed42ee4e 100644 --- a/preferences/admin.py +++ b/preferences/admin.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/preferences/forms.py b/preferences/forms.py index e216ea1f..c3d6376f 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/preferences/models.py b/preferences/models.py index af85847b..39eb814e 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/aff_document_template.html b/preferences/templates/preferences/aff_document_template.html index 8d2184b4..d2f5e577 100644 --- a/preferences/templates/preferences/aff_document_template.html +++ b/preferences/templates/preferences/aff_document_template.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/aff_mailcontact.html b/preferences/templates/preferences/aff_mailcontact.html index 98ee8cdc..2d80e0b1 100644 --- a/preferences/templates/preferences/aff_mailcontact.html +++ b/preferences/templates/preferences/aff_mailcontact.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/aff_radiuskey.html b/preferences/templates/preferences/aff_radiuskey.html index 7c972abe..b12288fb 100644 --- a/preferences/templates/preferences/aff_radiuskey.html +++ b/preferences/templates/preferences/aff_radiuskey.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/aff_reminder.html b/preferences/templates/preferences/aff_reminder.html index c0586b31..134b45d5 100644 --- a/preferences/templates/preferences/aff_reminder.html +++ b/preferences/templates/preferences/aff_reminder.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/aff_service.html b/preferences/templates/preferences/aff_service.html index dce81768..ff2d80af 100644 --- a/preferences/templates/preferences/aff_service.html +++ b/preferences/templates/preferences/aff_service.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/aff_switchmanagementcred.html b/preferences/templates/preferences/aff_switchmanagementcred.html index b45dd356..8f2f7ff6 100644 --- a/preferences/templates/preferences/aff_switchmanagementcred.html +++ b/preferences/templates/preferences/aff_switchmanagementcred.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/delete.html b/preferences/templates/preferences/delete.html index 7897e286..227eaf31 100644 --- a/preferences/templates/preferences/delete.html +++ b/preferences/templates/preferences/delete.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index 2c5dec2b..0d2b3a6e 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/edit_preferences.html b/preferences/templates/preferences/edit_preferences.html index b5f8c506..b0f70bad 100644 --- a/preferences/templates/preferences/edit_preferences.html +++ b/preferences/templates/preferences/edit_preferences.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/preferences.html b/preferences/templates/preferences/preferences.html index 308d121e..a2759781 100644 --- a/preferences/templates/preferences/preferences.html +++ b/preferences/templates/preferences/preferences.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/templates/preferences/sidebar.html b/preferences/templates/preferences/sidebar.html index 2dccf639..7fb0d086 100644 --- a/preferences/templates/preferences/sidebar.html +++ b/preferences/templates/preferences/sidebar.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/preferences/tests.py b/preferences/tests.py index 8b980c73..68ad1667 100644 --- a/preferences/tests.py +++ b/preferences/tests.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2018 Maël Kervella # diff --git a/preferences/urls.py b/preferences/urls.py index d07aa0be..656689ba 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/preferences/views.py b/preferences/views.py index 5ccd7cad..065ea6cf 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/re2o/__init__.py b/re2o/__init__.py index eda09716..aeb27316 100644 --- a/re2o/__init__.py +++ b/re2o/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/re2o/acl.py b/re2o/acl.py index 75857dbf..cf831a37 100644 --- a/re2o/acl.py +++ b/re2o/acl.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/re2o/aes_field.py b/re2o/aes_field.py index eeab5e12..edabfc40 100644 --- a/re2o/aes_field.py +++ b/re2o/aes_field.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2018 Maël Kervella # Copyright © 2018 Hugo Levy-Falk diff --git a/re2o/context_processors.py b/re2o/context_processors.py index 67a700be..3ee39073 100644 --- a/re2o/context_processors.py +++ b/re2o/context_processors.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/re2o/contributors.py b/re2o/contributors.py index e9f201c3..e9851eb0 100644 --- a/re2o/contributors.py +++ b/re2o/contributors.py @@ -8,7 +8,7 @@ CONTRIBUTORS = [ 'Maël "MoaMoaK" Kervella', 'Hugo "Klafyvel" Levy--Falk', 'Augustin "Dahlaro" Lemesle', - 'Goulven "Lhark" Kermarec', + 'Lara "Lhark" Kermarec', 'Guillaume "Guimoz" Goessel', 'Yoann "Nanoy" Pietri', 'Matthieu "Lebanni" Michelet', diff --git a/re2o/field_permissions.py b/re2o/field_permissions.py index 4e3be7f3..b56711bd 100644 --- a/re2o/field_permissions.py +++ b/re2o/field_permissions.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # Copyright © 2018 Maël Kervella # diff --git a/re2o/login.py b/re2o/login.py index 378f7ea1..559636ce 100644 --- a/re2o/login.py +++ b/re2o/login.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify @@ -23,7 +23,7 @@ # -*- coding: utf-8 -*- # Module d'authentification -# David Sinquin, Gabriel Détraz, Goulven Kermarec +# David Sinquin, Gabriel Détraz, Lara Kermarec """re2o.login Module in charge of handling the login process and verifications """ diff --git a/re2o/settings.py b/re2o/settings.py index ee219cfa..34ad0981 100644 --- a/re2o/settings.py +++ b/re2o/settings.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/re2o/settings_local.example.py b/re2o/settings_local.example.py index 80c109c4..bb4efa45 100644 --- a/re2o/settings_local.example.py +++ b/re2o/settings_local.example.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/re2o/templates/re2o/about.html b/re2o/templates/re2o/about.html index aab3b620..2503246a 100644 --- a/re2o/templates/re2o/about.html +++ b/re2o/templates/re2o/about.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/re2o/templates/re2o/aff_history.html b/re2o/templates/re2o/aff_history.html index 7079d7de..6256ff23 100644 --- a/re2o/templates/re2o/aff_history.html +++ b/re2o/templates/re2o/aff_history.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/re2o/templates/re2o/contact.html b/re2o/templates/re2o/contact.html index 05b34655..f508932e 100644 --- a/re2o/templates/re2o/contact.html +++ b/re2o/templates/re2o/contact.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/re2o/templates/re2o/history.html b/re2o/templates/re2o/history.html index d991b033..285fd62f 100644 --- a/re2o/templates/re2o/history.html +++ b/re2o/templates/re2o/history.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/re2o/templates/re2o/index.html b/re2o/templates/re2o/index.html index a6b1a8c5..89a50489 100644 --- a/re2o/templates/re2o/index.html +++ b/re2o/templates/re2o/index.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/re2o/templates/re2o/sidebar.html b/re2o/templates/re2o/sidebar.html index e7e58599..75f23c03 100644 --- a/re2o/templates/re2o/sidebar.html +++ b/re2o/templates/re2o/sidebar.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/re2o/templatetags/self_adhesion.py b/re2o/templatetags/self_adhesion.py index 09fe5ede..315e4728 100644 --- a/re2o/templatetags/self_adhesion.py +++ b/re2o/templatetags/self_adhesion.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/re2o/urls.py b/re2o/urls.py index 8af7335a..d661012c 100644 --- a/re2o/urls.py +++ b/re2o/urls.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/re2o/utils.py b/re2o/utils.py index a5cb2238..ebcddbc3 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify @@ -22,7 +22,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -*- coding: utf-8 -*- -# David Sinquin, Gabriel Détraz, Goulven Kermarec +# David Sinquin, Gabriel Détraz, Lara Kermarec """ Regroupe les fonctions transversales utiles diff --git a/re2o/views.py b/re2o/views.py index 17622fd5..414416a7 100644 --- a/re2o/views.py +++ b/re2o/views.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/re2o/wsgi.py b/re2o/wsgi.py index 2a60249b..968298ed 100644 --- a/re2o/wsgi.py +++ b/re2o/wsgi.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/search/__init__.py b/search/__init__.py index 5460ff54..93f634cc 100644 --- a/search/__init__.py +++ b/search/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/search/acl.py b/search/acl.py index 7ae541f8..3eee656a 100644 --- a/search/acl.py +++ b/search/acl.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/search/admin.py b/search/admin.py index decd096a..b4cf317a 100644 --- a/search/admin.py +++ b/search/admin.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/search/forms.py b/search/forms.py index 073fac02..aa5d4aab 100644 --- a/search/forms.py +++ b/search/forms.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/search/templates/search/index.html b/search/templates/search/index.html index 4d3e2942..8f1174fb 100644 --- a/search/templates/search/index.html +++ b/search/templates/search/index.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/search/templates/search/search.html b/search/templates/search/search.html index d957a4cf..5f54da97 100644 --- a/search/templates/search/search.html +++ b/search/templates/search/search.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/search/templates/search/sidebar.html b/search/templates/search/sidebar.html index 28d7a115..717a46b1 100644 --- a/search/templates/search/sidebar.html +++ b/search/templates/search/sidebar.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/search/tests.py b/search/tests.py index d15f1f07..3f0410dd 100644 --- a/search/tests.py +++ b/search/tests.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/search/urls.py b/search/urls.py index dc1490e5..dd22193b 100644 --- a/search/urls.py +++ b/search/urls.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/search/views.py b/search/views.py index eb0027ec..a6f7de4c 100644 --- a/search/views.py +++ b/search/views.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify @@ -21,7 +21,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """The views for the search app, responsible for finding the matches -Augustin lemesle, Gabriel Détraz, Goulven Kermarec, Maël Kervella +Augustin lemesle, Gabriel Détraz, Lara Kermarec, Maël Kervella Gplv2""" diff --git a/templates/base.html b/templates/base.html index 891e243f..f116c2be 100644 --- a/templates/base.html +++ b/templates/base.html @@ -3,7 +3,7 @@ Re2o est un logiciel d'administration développé initiallement au rezometz. Il se veut agnostique au réseau considéré, de manière à être installable en quelques clics. -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/templates/buttons/add.html b/templates/buttons/add.html index efbbe142..b04381ca 100644 --- a/templates/buttons/add.html +++ b/templates/buttons/add.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/templates/buttons/edit.html b/templates/buttons/edit.html index a169b6c6..c7bbaac4 100644 --- a/templates/buttons/edit.html +++ b/templates/buttons/edit.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/templates/buttons/history.html b/templates/buttons/history.html index cabcd6b2..c4bee631 100644 --- a/templates/buttons/history.html +++ b/templates/buttons/history.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/templates/buttons/multiple_checkbox_alt.html b/templates/buttons/multiple_checkbox_alt.html index 2809d3a2..2e59845f 100644 --- a/templates/buttons/multiple_checkbox_alt.html +++ b/templates/buttons/multiple_checkbox_alt.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/templates/buttons/sort.html b/templates/buttons/sort.html index 3de5b6cd..2f34a2c6 100644 --- a/templates/buttons/sort.html +++ b/templates/buttons/sort.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/templates/buttons/suppr.html b/templates/buttons/suppr.html index 4910db03..1cb6cbe4 100644 --- a/templates/buttons/suppr.html +++ b/templates/buttons/suppr.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/templates/pagination.html b/templates/pagination.html index 5ecced6d..a0cc905a 100644 --- a/templates/pagination.html +++ b/templates/pagination.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/templates/registration/login.html b/templates/registration/login.html index f4226d7d..47e8b25f 100644 --- a/templates/registration/login.html +++ b/templates/registration/login.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/test_utils/runner.py b/test_utils/runner.py index 54ddd82f..77885dcf 100644 --- a/test_utils/runner.py +++ b/test_utils/runner.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/tickets/templates/tickets/aff_ticket.html b/tickets/templates/tickets/aff_ticket.html index ede878b3..c5605863 100644 --- a/tickets/templates/tickets/aff_ticket.html +++ b/tickets/templates/tickets/aff_ticket.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/tickets/templates/tickets/aff_tickets.html b/tickets/templates/tickets/aff_tickets.html index 6bb062fb..1f0c963e 100644 --- a/tickets/templates/tickets/aff_tickets.html +++ b/tickets/templates/tickets/aff_tickets.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/tickets/templates/tickets/form_preferences.html b/tickets/templates/tickets/form_preferences.html index 5c7e5d5e..d6521a8b 100644 --- a/tickets/templates/tickets/form_preferences.html +++ b/tickets/templates/tickets/form_preferences.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle Copyright © 2017 Maël Kervella diff --git a/tickets/templates/tickets/form_ticket.html b/tickets/templates/tickets/form_ticket.html index d35e9f5d..f4c90147 100644 --- a/tickets/templates/tickets/form_ticket.html +++ b/tickets/templates/tickets/form_ticket.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle Copyright © 2017 Maël Kervella diff --git a/tickets/templates/tickets/index.html b/tickets/templates/tickets/index.html index 4429c4fd..ba5730e6 100644 --- a/tickets/templates/tickets/index.html +++ b/tickets/templates/tickets/index.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/tickets/views.py b/tickets/views.py index 5da692d0..7fb96511 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify @@ -22,7 +22,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # App de gestion des users pour re2o -# Goulven Kermarec, Gabriel Détraz, Lemesle Augustin +# Lara Kermarec, Gabriel Détraz, Lemesle Augustin # Gplv2 from django.contrib import messages diff --git a/topologie/__init__.py b/topologie/__init__.py index 9e8202ea..2f5cebcd 100644 --- a/topologie/__init__.py +++ b/topologie/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/acl.py b/topologie/acl.py index 2a7227fd..6f8f79d4 100644 --- a/topologie/acl.py +++ b/topologie/acl.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/admin.py b/topologie/admin.py index d6fa318e..d1e28945 100644 --- a/topologie/admin.py +++ b/topologie/admin.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/forms.py b/topologie/forms.py index 72b499d4..2f4ac411 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0001_initial.py b/topologie/migrations/0001_initial.py index 78cd6524..02fd7076 100644 --- a/topologie/migrations/0001_initial.py +++ b/topologie/migrations/0001_initial.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0002_auto_20160703_1118.py b/topologie/migrations/0002_auto_20160703_1118.py index 3440a1c7..86736cd9 100644 --- a/topologie/migrations/0002_auto_20160703_1118.py +++ b/topologie/migrations/0002_auto_20160703_1118.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0003_room.py b/topologie/migrations/0003_room.py index 89112861..7a867be2 100644 --- a/topologie/migrations/0003_room.py +++ b/topologie/migrations/0003_room.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0004_auto_20160703_1122.py b/topologie/migrations/0004_auto_20160703_1122.py index b5b9d14a..01e75354 100644 --- a/topologie/migrations/0004_auto_20160703_1122.py +++ b/topologie/migrations/0004_auto_20160703_1122.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0005_auto_20160703_1123.py b/topologie/migrations/0005_auto_20160703_1123.py index 0ceb531a..fb3a6c1d 100644 --- a/topologie/migrations/0005_auto_20160703_1123.py +++ b/topologie/migrations/0005_auto_20160703_1123.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0006_auto_20160703_1129.py b/topologie/migrations/0006_auto_20160703_1129.py index c4f8ebba..bfb49574 100644 --- a/topologie/migrations/0006_auto_20160703_1129.py +++ b/topologie/migrations/0006_auto_20160703_1129.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0007_auto_20160703_1148.py b/topologie/migrations/0007_auto_20160703_1148.py index 28ab8699..b2c30c21 100644 --- a/topologie/migrations/0007_auto_20160703_1148.py +++ b/topologie/migrations/0007_auto_20160703_1148.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0008_port_room.py b/topologie/migrations/0008_port_room.py index 9ffb3bef..53a124b6 100644 --- a/topologie/migrations/0008_port_room.py +++ b/topologie/migrations/0008_port_room.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0009_auto_20160703_1200.py b/topologie/migrations/0009_auto_20160703_1200.py index 4d17d332..08cf6498 100644 --- a/topologie/migrations/0009_auto_20160703_1200.py +++ b/topologie/migrations/0009_auto_20160703_1200.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0010_auto_20160704_2148.py b/topologie/migrations/0010_auto_20160704_2148.py index a38e92e6..9e408a5f 100644 --- a/topologie/migrations/0010_auto_20160704_2148.py +++ b/topologie/migrations/0010_auto_20160704_2148.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0011_auto_20160704_2153.py b/topologie/migrations/0011_auto_20160704_2153.py index 0ffc658f..5b678799 100644 --- a/topologie/migrations/0011_auto_20160704_2153.py +++ b/topologie/migrations/0011_auto_20160704_2153.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0012_port_machine_interface.py b/topologie/migrations/0012_port_machine_interface.py index a248242b..9c0bb3bb 100644 --- a/topologie/migrations/0012_port_machine_interface.py +++ b/topologie/migrations/0012_port_machine_interface.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0013_port_related.py b/topologie/migrations/0013_port_related.py index 405fa211..ef7fb986 100644 --- a/topologie/migrations/0013_port_related.py +++ b/topologie/migrations/0013_port_related.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0014_auto_20160706_1238.py b/topologie/migrations/0014_auto_20160706_1238.py index aee43d73..17971b79 100644 --- a/topologie/migrations/0014_auto_20160706_1238.py +++ b/topologie/migrations/0014_auto_20160706_1238.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0015_auto_20160706_1452.py b/topologie/migrations/0015_auto_20160706_1452.py index 849a3dfe..d9a49edb 100644 --- a/topologie/migrations/0015_auto_20160706_1452.py +++ b/topologie/migrations/0015_auto_20160706_1452.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0016_auto_20160706_1531.py b/topologie/migrations/0016_auto_20160706_1531.py index 3187b0ad..a25df3dc 100644 --- a/topologie/migrations/0016_auto_20160706_1531.py +++ b/topologie/migrations/0016_auto_20160706_1531.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0017_auto_20160718_1141.py b/topologie/migrations/0017_auto_20160718_1141.py index 178b9acd..226a84c3 100644 --- a/topologie/migrations/0017_auto_20160718_1141.py +++ b/topologie/migrations/0017_auto_20160718_1141.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0018_room_details.py b/topologie/migrations/0018_room_details.py index 84bb19a6..ed0dd057 100644 --- a/topologie/migrations/0018_room_details.py +++ b/topologie/migrations/0018_room_details.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0019_auto_20161026_1348.py b/topologie/migrations/0019_auto_20161026_1348.py index 84562039..2790b7de 100644 --- a/topologie/migrations/0019_auto_20161026_1348.py +++ b/topologie/migrations/0019_auto_20161026_1348.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0020_auto_20161119_0033.py b/topologie/migrations/0020_auto_20161119_0033.py index 6bb23fc9..efb6e739 100644 --- a/topologie/migrations/0020_auto_20161119_0033.py +++ b/topologie/migrations/0020_auto_20161119_0033.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0021_port_radius.py b/topologie/migrations/0021_port_radius.py index 9f49bacd..91571157 100644 --- a/topologie/migrations/0021_port_radius.py +++ b/topologie/migrations/0021_port_radius.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/0022_auto_20161211_1622.py b/topologie/migrations/0022_auto_20161211_1622.py index 92413125..b1133466 100644 --- a/topologie/migrations/0022_auto_20161211_1622.py +++ b/topologie/migrations/0022_auto_20161211_1622.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/migrations/__init__.py b/topologie/migrations/__init__.py index 20abb0d2..b2b50566 100644 --- a/topologie/migrations/__init__.py +++ b/topologie/migrations/__init__.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/models.py b/topologie/models.py index 235b3885..c942c93b 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_ap.html b/topologie/templates/topologie/aff_ap.html index 1acd54bb..afbf00ca 100644 --- a/topologie/templates/topologie/aff_ap.html +++ b/topologie/templates/topologie/aff_ap.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_building.html b/topologie/templates/topologie/aff_building.html index 5775bb28..cf288b53 100644 --- a/topologie/templates/topologie/aff_building.html +++ b/topologie/templates/topologie/aff_building.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_chambres.html b/topologie/templates/topologie/aff_chambres.html index 4a79efbd..d03f7b19 100644 --- a/topologie/templates/topologie/aff_chambres.html +++ b/topologie/templates/topologie/aff_chambres.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_constructor_switch.html b/topologie/templates/topologie/aff_constructor_switch.html index eceeb682..9e4dcb42 100644 --- a/topologie/templates/topologie/aff_constructor_switch.html +++ b/topologie/templates/topologie/aff_constructor_switch.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_dormitory.html b/topologie/templates/topologie/aff_dormitory.html index 758e5e2c..cd5a0fbb 100644 --- a/topologie/templates/topologie/aff_dormitory.html +++ b/topologie/templates/topologie/aff_dormitory.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_model_switch.html b/topologie/templates/topologie/aff_model_switch.html index 426b308a..24a759e1 100644 --- a/topologie/templates/topologie/aff_model_switch.html +++ b/topologie/templates/topologie/aff_model_switch.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_modules.html b/topologie/templates/topologie/aff_modules.html index 021457f2..ac09ec13 100644 --- a/topologie/templates/topologie/aff_modules.html +++ b/topologie/templates/topologie/aff_modules.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_port.html b/topologie/templates/topologie/aff_port.html index c789694e..91742147 100644 --- a/topologie/templates/topologie/aff_port.html +++ b/topologie/templates/topologie/aff_port.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_repr_switch.html b/topologie/templates/topologie/aff_repr_switch.html index c482da7a..f0924124 100644 --- a/topologie/templates/topologie/aff_repr_switch.html +++ b/topologie/templates/topologie/aff_repr_switch.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_stacks.html b/topologie/templates/topologie/aff_stacks.html index c1032ee6..1ca259eb 100644 --- a/topologie/templates/topologie/aff_stacks.html +++ b/topologie/templates/topologie/aff_stacks.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_switch.html b/topologie/templates/topologie/aff_switch.html index 93c05530..58871d19 100644 --- a/topologie/templates/topologie/aff_switch.html +++ b/topologie/templates/topologie/aff_switch.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_switch_bay.html b/topologie/templates/topologie/aff_switch_bay.html index 0aa81449..9335f0a8 100644 --- a/topologie/templates/topologie/aff_switch_bay.html +++ b/topologie/templates/topologie/aff_switch_bay.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/aff_vlanoptions.html b/topologie/templates/topologie/aff_vlanoptions.html index 9b2dc913..65c80e34 100644 --- a/topologie/templates/topologie/aff_vlanoptions.html +++ b/topologie/templates/topologie/aff_vlanoptions.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/delete.html b/topologie/templates/topologie/delete.html index 24e6edad..e5dea3c4 100644 --- a/topologie/templates/topologie/delete.html +++ b/topologie/templates/topologie/delete.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/edit_stack_sw.html b/topologie/templates/topologie/edit_stack_sw.html index bf094f07..6e1cf848 100644 --- a/topologie/templates/topologie/edit_stack_sw.html +++ b/topologie/templates/topologie/edit_stack_sw.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/index.html b/topologie/templates/topologie/index.html index be3667ca..1d0c8722 100644 --- a/topologie/templates/topologie/index.html +++ b/topologie/templates/topologie/index.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/index_ap.html b/topologie/templates/topologie/index_ap.html index 5fbd3d94..570d22ab 100644 --- a/topologie/templates/topologie/index_ap.html +++ b/topologie/templates/topologie/index_ap.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/index_model_switch.html b/topologie/templates/topologie/index_model_switch.html index e7ad725f..2612c29c 100644 --- a/topologie/templates/topologie/index_model_switch.html +++ b/topologie/templates/topologie/index_model_switch.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/index_module.html b/topologie/templates/topologie/index_module.html index a7fee190..f7432bf1 100644 --- a/topologie/templates/topologie/index_module.html +++ b/topologie/templates/topologie/index_module.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/index_p.html b/topologie/templates/topologie/index_p.html index 04a516ec..8d215ebd 100644 --- a/topologie/templates/topologie/index_p.html +++ b/topologie/templates/topologie/index_p.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/index_physical_grouping.html b/topologie/templates/topologie/index_physical_grouping.html index 7b081439..9e4c32a8 100644 --- a/topologie/templates/topologie/index_physical_grouping.html +++ b/topologie/templates/topologie/index_physical_grouping.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/index_room.html b/topologie/templates/topologie/index_room.html index 248ce05d..c383a226 100644 --- a/topologie/templates/topologie/index_room.html +++ b/topologie/templates/topologie/index_room.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/sidebar.html b/topologie/templates/topologie/sidebar.html index 249c4308..f90e5d55 100644 --- a/topologie/templates/topologie/sidebar.html +++ b/topologie/templates/topologie/sidebar.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/switch.html b/topologie/templates/topologie/switch.html index 5bb738f6..5c39e322 100644 --- a/topologie/templates/topologie/switch.html +++ b/topologie/templates/topologie/switch.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/topo.html b/topologie/templates/topologie/topo.html index 2f6449e5..7dad1138 100644 --- a/topologie/templates/topologie/topo.html +++ b/topologie/templates/topologie/topo.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/templates/topologie/topo_more.html b/topologie/templates/topologie/topo_more.html index 89f6404d..1c9e26a1 100644 --- a/topologie/templates/topologie/topo_more.html +++ b/topologie/templates/topologie/topo_more.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/topologie/tests.py b/topologie/tests.py index dfe72a14..42d5ddfd 100644 --- a/topologie/tests.py +++ b/topologie/tests.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/urls.py b/topologie/urls.py index 76cf089c..ee26cb2e 100644 --- a/topologie/urls.py +++ b/topologie/urls.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/topologie/views.py b/topologie/views.py index d3acdff2..47621c04 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/__init__.py b/users/__init__.py index b661a850..b75d67cb 100644 --- a/users/__init__.py +++ b/users/__init__.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/acl.py b/users/acl.py index 33ad864e..81d52026 100644 --- a/users/acl.py +++ b/users/acl.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/admin.py b/users/admin.py index e7dd3240..f2fdc0c5 100644 --- a/users/admin.py +++ b/users/admin.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/forms.py b/users/forms.py index 75d73de1..66ab7e74 100644 --- a/users/forms.py +++ b/users/forms.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/management/commands/clean_notyetactive.py b/users/management/commands/clean_notyetactive.py index 44c5b24e..247fc668 100644 --- a/users/management/commands/clean_notyetactive.py +++ b/users/management/commands/clean_notyetactive.py @@ -1,5 +1,5 @@ # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/management/commands/ldap_sync.py b/users/management/commands/ldap_sync.py index 9301c788..d6ac8469 100644 --- a/users/management/commands/ldap_sync.py +++ b/users/management/commands/ldap_sync.py @@ -1,5 +1,5 @@ # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py index f718e4f0..8fd3d2ff 100644 --- a/users/migrations/0001_initial.py +++ b/users/migrations/0001_initial.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0002_auto_20160630_2301.py b/users/migrations/0002_auto_20160630_2301.py index b45d09e3..a5964850 100644 --- a/users/migrations/0002_auto_20160630_2301.py +++ b/users/migrations/0002_auto_20160630_2301.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0003_listrights_rights.py b/users/migrations/0003_listrights_rights.py index a16345f7..cc74369f 100644 --- a/users/migrations/0003_listrights_rights.py +++ b/users/migrations/0003_listrights_rights.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0004_auto_20160701_2312.py b/users/migrations/0004_auto_20160701_2312.py index e0fb528e..c9739719 100644 --- a/users/migrations/0004_auto_20160701_2312.py +++ b/users/migrations/0004_auto_20160701_2312.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0005_auto_20160702_0006.py b/users/migrations/0005_auto_20160702_0006.py index 45d011c3..8962cf41 100644 --- a/users/migrations/0005_auto_20160702_0006.py +++ b/users/migrations/0005_auto_20160702_0006.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0006_ban.py b/users/migrations/0006_ban.py index 9ff71e57..69e04e5a 100644 --- a/users/migrations/0006_ban.py +++ b/users/migrations/0006_ban.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0007_auto_20160702_2322.py b/users/migrations/0007_auto_20160702_2322.py index 4e6e75b1..ab288eca 100644 --- a/users/migrations/0007_auto_20160702_2322.py +++ b/users/migrations/0007_auto_20160702_2322.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0008_user_registered.py b/users/migrations/0008_user_registered.py index 1c262423..ab992540 100644 --- a/users/migrations/0008_user_registered.py +++ b/users/migrations/0008_user_registered.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0009_user_room.py b/users/migrations/0009_user_room.py index df5bcfbb..ac3e6094 100644 --- a/users/migrations/0009_user_room.py +++ b/users/migrations/0009_user_room.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0010_auto_20160703_1226.py b/users/migrations/0010_auto_20160703_1226.py index 47f89c6d..db5b8758 100644 --- a/users/migrations/0010_auto_20160703_1226.py +++ b/users/migrations/0010_auto_20160703_1226.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0011_auto_20160703_1227.py b/users/migrations/0011_auto_20160703_1227.py index a6c86731..d9f2e120 100644 --- a/users/migrations/0011_auto_20160703_1227.py +++ b/users/migrations/0011_auto_20160703_1227.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0012_auto_20160703_1230.py b/users/migrations/0012_auto_20160703_1230.py index 4cb69574..8e82895e 100644 --- a/users/migrations/0012_auto_20160703_1230.py +++ b/users/migrations/0012_auto_20160703_1230.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0013_auto_20160704_1547.py b/users/migrations/0013_auto_20160704_1547.py index 11b146d3..b765cb09 100644 --- a/users/migrations/0013_auto_20160704_1547.py +++ b/users/migrations/0013_auto_20160704_1547.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0014_auto_20160704_1548.py b/users/migrations/0014_auto_20160704_1548.py index ccdc9c35..a825a9b2 100644 --- a/users/migrations/0014_auto_20160704_1548.py +++ b/users/migrations/0014_auto_20160704_1548.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0015_whitelist.py b/users/migrations/0015_whitelist.py index bb356041..6762ab21 100644 --- a/users/migrations/0015_whitelist.py +++ b/users/migrations/0015_whitelist.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0016_auto_20160706_1220.py b/users/migrations/0016_auto_20160706_1220.py index 0a6e969a..d9e7092c 100644 --- a/users/migrations/0016_auto_20160706_1220.py +++ b/users/migrations/0016_auto_20160706_1220.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0017_auto_20160707_0105.py b/users/migrations/0017_auto_20160707_0105.py index c0459213..45fa4826 100644 --- a/users/migrations/0017_auto_20160707_0105.py +++ b/users/migrations/0017_auto_20160707_0105.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0018_auto_20160707_0115.py b/users/migrations/0018_auto_20160707_0115.py index dc97f9d4..4bccb938 100644 --- a/users/migrations/0018_auto_20160707_0115.py +++ b/users/migrations/0018_auto_20160707_0115.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0019_auto_20160708_1633.py b/users/migrations/0019_auto_20160708_1633.py index 13a72514..980bf112 100644 --- a/users/migrations/0019_auto_20160708_1633.py +++ b/users/migrations/0019_auto_20160708_1633.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0020_request.py b/users/migrations/0020_request.py index 8fa7a498..379f5f3c 100644 --- a/users/migrations/0020_request.py +++ b/users/migrations/0020_request.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0021_ldapuser.py b/users/migrations/0021_ldapuser.py index e2ee9844..712842cd 100644 --- a/users/migrations/0021_ldapuser.py +++ b/users/migrations/0021_ldapuser.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0022_ldapuser_sambasid.py b/users/migrations/0022_ldapuser_sambasid.py index 9f9d6521..61e9c935 100644 --- a/users/migrations/0022_ldapuser_sambasid.py +++ b/users/migrations/0022_ldapuser_sambasid.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0023_auto_20160724_1908.py b/users/migrations/0023_auto_20160724_1908.py index 14e9fee7..9bced0fc 100644 --- a/users/migrations/0023_auto_20160724_1908.py +++ b/users/migrations/0023_auto_20160724_1908.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0024_remove_ldapuser_mac_list.py b/users/migrations/0024_remove_ldapuser_mac_list.py index c0a218f6..d4e4e458 100644 --- a/users/migrations/0024_remove_ldapuser_mac_list.py +++ b/users/migrations/0024_remove_ldapuser_mac_list.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0025_listshell.py b/users/migrations/0025_listshell.py index f96bc335..8f63776d 100644 --- a/users/migrations/0025_listshell.py +++ b/users/migrations/0025_listshell.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0026_user_shell.py b/users/migrations/0026_user_shell.py index f506ae78..081d9498 100644 --- a/users/migrations/0026_user_shell.py +++ b/users/migrations/0026_user_shell.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0027_auto_20160726_0216.py b/users/migrations/0027_auto_20160726_0216.py index 03309afe..9324c815 100644 --- a/users/migrations/0027_auto_20160726_0216.py +++ b/users/migrations/0027_auto_20160726_0216.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0028_auto_20160726_0227.py b/users/migrations/0028_auto_20160726_0227.py index 9593434d..c541bc14 100644 --- a/users/migrations/0028_auto_20160726_0227.py +++ b/users/migrations/0028_auto_20160726_0227.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0029_auto_20160726_0229.py b/users/migrations/0029_auto_20160726_0229.py index 62f765f9..6b5d16d9 100644 --- a/users/migrations/0029_auto_20160726_0229.py +++ b/users/migrations/0029_auto_20160726_0229.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0030_auto_20160726_0357.py b/users/migrations/0030_auto_20160726_0357.py index 753f1ad7..a4c3d727 100644 --- a/users/migrations/0030_auto_20160726_0357.py +++ b/users/migrations/0030_auto_20160726_0357.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0031_auto_20160726_0359.py b/users/migrations/0031_auto_20160726_0359.py index 7df9b3a0..7f327e79 100644 --- a/users/migrations/0031_auto_20160726_0359.py +++ b/users/migrations/0031_auto_20160726_0359.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0032_auto_20160727_2122.py b/users/migrations/0032_auto_20160727_2122.py index cdafbd57..b583b5db 100644 --- a/users/migrations/0032_auto_20160727_2122.py +++ b/users/migrations/0032_auto_20160727_2122.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0033_remove_ldapuser_loginshell.py b/users/migrations/0033_remove_ldapuser_loginshell.py index 4d73f138..e8a4c616 100644 --- a/users/migrations/0033_remove_ldapuser_loginshell.py +++ b/users/migrations/0033_remove_ldapuser_loginshell.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0034_auto_20161018_0037.py b/users/migrations/0034_auto_20161018_0037.py index e26e2373..911357a2 100644 --- a/users/migrations/0034_auto_20161018_0037.py +++ b/users/migrations/0034_auto_20161018_0037.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0035_auto_20161018_0046.py b/users/migrations/0035_auto_20161018_0046.py index aea0d13d..f026737b 100644 --- a/users/migrations/0035_auto_20161018_0046.py +++ b/users/migrations/0035_auto_20161018_0046.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0036_auto_20161022_2146.py b/users/migrations/0036_auto_20161022_2146.py index 16016a27..3619cc31 100644 --- a/users/migrations/0036_auto_20161022_2146.py +++ b/users/migrations/0036_auto_20161022_2146.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0037_auto_20161028_1906.py b/users/migrations/0037_auto_20161028_1906.py index 4022ba9f..ee4d5d5f 100644 --- a/users/migrations/0037_auto_20161028_1906.py +++ b/users/migrations/0037_auto_20161028_1906.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0038_auto_20161031_0258.py b/users/migrations/0038_auto_20161031_0258.py index bc10db42..342d302b 100644 --- a/users/migrations/0038_auto_20161031_0258.py +++ b/users/migrations/0038_auto_20161031_0258.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0039_auto_20161119_0033.py b/users/migrations/0039_auto_20161119_0033.py index f4028b1f..a5118b89 100644 --- a/users/migrations/0039_auto_20161119_0033.py +++ b/users/migrations/0039_auto_20161119_0033.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0040_auto_20161119_1709.py b/users/migrations/0040_auto_20161119_1709.py index cd917def..bc2c3de2 100644 --- a/users/migrations/0040_auto_20161119_1709.py +++ b/users/migrations/0040_auto_20161119_1709.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0041_listright_details.py b/users/migrations/0041_listright_details.py index 324856b3..1e44fe2b 100644 --- a/users/migrations/0041_listright_details.py +++ b/users/migrations/0041_listright_details.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/0042_auto_20161126_2028.py b/users/migrations/0042_auto_20161126_2028.py index ca732521..04a301c7 100644 --- a/users/migrations/0042_auto_20161126_2028.py +++ b/users/migrations/0042_auto_20161126_2028.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py index 20abb0d2..b2b50566 100644 --- a/users/migrations/__init__.py +++ b/users/migrations/__init__.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/models.py b/users/models.py index bbb4146d..69348c17 100755 --- a/users/models.py +++ b/users/models.py @@ -4,7 +4,7 @@ # en quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/serializers.py b/users/serializers.py index be925881..893b6c3a 100644 --- a/users/serializers.py +++ b/users/serializers.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/aff_bans.html b/users/templates/users/aff_bans.html index 30256747..f4f973f7 100644 --- a/users/templates/users/aff_bans.html +++ b/users/templates/users/aff_bans.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/aff_clubs.html b/users/templates/users/aff_clubs.html index 080dc031..e4ea9857 100644 --- a/users/templates/users/aff_clubs.html +++ b/users/templates/users/aff_clubs.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/aff_emailaddress.html b/users/templates/users/aff_emailaddress.html index f5d5dd1d..9bd3c8d0 100644 --- a/users/templates/users/aff_emailaddress.html +++ b/users/templates/users/aff_emailaddress.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/aff_listright.html b/users/templates/users/aff_listright.html index 8a069529..2a829e7e 100644 --- a/users/templates/users/aff_listright.html +++ b/users/templates/users/aff_listright.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/aff_rights.html b/users/templates/users/aff_rights.html index 710c1f14..bb3bdec9 100644 --- a/users/templates/users/aff_rights.html +++ b/users/templates/users/aff_rights.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/aff_schools.html b/users/templates/users/aff_schools.html index 9ec3b443..586c657c 100644 --- a/users/templates/users/aff_schools.html +++ b/users/templates/users/aff_schools.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/aff_serviceusers.html b/users/templates/users/aff_serviceusers.html index b5e0ae62..6d0c7dc8 100644 --- a/users/templates/users/aff_serviceusers.html +++ b/users/templates/users/aff_serviceusers.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/aff_shell.html b/users/templates/users/aff_shell.html index b422ab52..e95d79f0 100644 --- a/users/templates/users/aff_shell.html +++ b/users/templates/users/aff_shell.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/aff_users.html b/users/templates/users/aff_users.html index fe6e431a..8365e259 100644 --- a/users/templates/users/aff_users.html +++ b/users/templates/users/aff_users.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/aff_whitelists.html b/users/templates/users/aff_whitelists.html index ea2d1d4f..e93f3ecf 100644 --- a/users/templates/users/aff_whitelists.html +++ b/users/templates/users/aff_whitelists.html @@ -4,7 +4,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/delete.html b/users/templates/users/delete.html index 9490c0c4..3e923617 100644 --- a/users/templates/users/delete.html +++ b/users/templates/users/delete.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/index.html b/users/templates/users/index.html index 4691114f..048ed9ee 100644 --- a/users/templates/users/index.html +++ b/users/templates/users/index.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/index_ban.html b/users/templates/users/index_ban.html index 1efa669f..07ad100f 100644 --- a/users/templates/users/index_ban.html +++ b/users/templates/users/index_ban.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/index_clubs.html b/users/templates/users/index_clubs.html index 88a9b4fa..73493a19 100644 --- a/users/templates/users/index_clubs.html +++ b/users/templates/users/index_clubs.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/index_emailaddress.html b/users/templates/users/index_emailaddress.html index 2b170f8c..e337d2ba 100644 --- a/users/templates/users/index_emailaddress.html +++ b/users/templates/users/index_emailaddress.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/index_listright.html b/users/templates/users/index_listright.html index 35738413..cb5b86d6 100644 --- a/users/templates/users/index_listright.html +++ b/users/templates/users/index_listright.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/index_rights.html b/users/templates/users/index_rights.html index a0fa5bc0..d89c454c 100644 --- a/users/templates/users/index_rights.html +++ b/users/templates/users/index_rights.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/index_schools.html b/users/templates/users/index_schools.html index e27f63a9..4d86ce67 100644 --- a/users/templates/users/index_schools.html +++ b/users/templates/users/index_schools.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/index_serviceusers.html b/users/templates/users/index_serviceusers.html index 90aa8a63..c7684488 100644 --- a/users/templates/users/index_serviceusers.html +++ b/users/templates/users/index_serviceusers.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/index_shell.html b/users/templates/users/index_shell.html index 9d75fdd8..d476f9d2 100644 --- a/users/templates/users/index_shell.html +++ b/users/templates/users/index_shell.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/index_whitelist.html b/users/templates/users/index_whitelist.html index 67164ffc..544e7db8 100644 --- a/users/templates/users/index_whitelist.html +++ b/users/templates/users/index_whitelist.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/mass_archive.html b/users/templates/users/mass_archive.html index 54281945..c3f67a34 100644 --- a/users/templates/users/mass_archive.html +++ b/users/templates/users/mass_archive.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/plugin_out.html b/users/templates/users/plugin_out.html index a6261250..23e696fe 100644 --- a/users/templates/users/plugin_out.html +++ b/users/templates/users/plugin_out.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index 29c55f32..00489017 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/sidebar.html b/users/templates/users/sidebar.html index 7a7daae3..d2ee77ff 100644 --- a/users/templates/users/sidebar.html +++ b/users/templates/users/sidebar.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/user.html b/users/templates/users/user.html index d7d4a0f0..86841c8f 100644 --- a/users/templates/users/user.html +++ b/users/templates/users/user.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/templates/users/user_autocapture.html b/users/templates/users/user_autocapture.html index 7ba0a6c3..79a4b3c2 100644 --- a/users/templates/users/user_autocapture.html +++ b/users/templates/users/user_autocapture.html @@ -5,7 +5,7 @@ se veut agnostique au réseau considéré, de manière à être installable en quelques clics. Copyright © 2017 Gabriel Détraz -Copyright © 2017 Goulven Kermarec +Copyright © 2017 Lara Kermarec Copyright © 2017 Augustin Lemesle This program is free software; you can redistribute it and/or modify diff --git a/users/tests.py b/users/tests.py index 6b2bfb41..2706c5af 100644 --- a/users/tests.py +++ b/users/tests.py @@ -3,7 +3,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/urls.py b/users/urls.py index 1e6ffa8c..b31f374b 100644 --- a/users/urls.py +++ b/users/urls.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify diff --git a/users/views.py b/users/views.py index c948698f..37c0ec88 100644 --- a/users/views.py +++ b/users/views.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Lara Kermarec # Copyright © 2017 Augustin Lemesle # # This program is free software; you can redistribute it and/or modify @@ -22,7 +22,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # App de gestion des users pour re2o -# Goulven Kermarec, Gabriel Détraz, Lemesle Augustin +# Lara Kermarec, Gabriel Détraz, Lemesle Augustin # Gplv2 """ Module des views. From 75bb3658ac2a24e4644b5af005893ccbae9501c2 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sat, 21 Sep 2019 23:10:28 +0200 Subject: [PATCH 150/228] Add Mandate model --- preferences/forms.py | 14 ++++- preferences/migrations/0063_mandate.py | 54 +++++++++++++++++ preferences/models.py | 35 +++++++++++ .../templates/preferences/aff_mandate.html | 52 ++++++++++++++++ .../preferences/display_preferences.html | 7 +++ preferences/urls.py | 15 +++++ preferences/views.py | 59 ++++++++++++++++++- 7 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 preferences/migrations/0063_mandate.py create mode 100644 preferences/templates/preferences/aff_mandate.html diff --git a/preferences/forms.py b/preferences/forms.py index c3d6376f..981bf5e2 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -45,7 +45,8 @@ from .models import ( RadiusOption, CotisationsOption, DocumentTemplate, - RadiusAttribute + RadiusAttribute, + Mandate ) from topologie.models import Switch @@ -261,6 +262,17 @@ class EditCotisationsOptionForm(ModelForm): fields = '__all__' +class MandateForm(ModelForm): + """Edit Mandates""" + class Meta: + model = Mandate + fields = '__all__' + + def __init__(self, *args, **kwargs): + prefix = kwargs.pop('prefix', self.Meta.model.__name__) + super(MandateForm, self).__init__(*args, prefix=prefix, **kwargs) + + class ServiceForm(ModelForm): """Edition, ajout de services sur la page d'accueil""" class Meta: diff --git a/preferences/migrations/0063_mandate.py b/preferences/migrations/0063_mandate.py new file mode 100644 index 00000000..f28acee4 --- /dev/null +++ b/preferences/migrations/0063_mandate.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-09-21 18:23 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +from django.utils import timezone +import re2o.mixins + + +def create_current_mandate(apps, schema_editor): + AssoOption = apps.get_model('preferences', 'AssoOption') + Mandate = apps.get_model('preferences', 'Mandate') + Adherent = apps.get_model('users', 'Adherent') + pres_name = AssoOption.objects.get_or_create()[0].pres_name + l = pres_name.split(' ') + try: + name, surname = l[0], l[1] + president = Adherent.objects.get(name__icontains=name, surname__icontains=surname) + Mandate.objects.create( + president=president, + start_date=timezone.now(), + ) + except Exception as e: + print("Warning : I was unable to find an adherent corresponding to %s. You might want to edit your preferences afterward." % pres_name) + + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('preferences', '0062_auto_20190910_1909'), + ] + + operations = [ + migrations.CreateModel( + name='Mandate', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start_date', models.DateTimeField(verbose_name='start date')), + ('end_date', models.DateTimeField(blank=True, null=True, verbose_name='end date')), + ('president', models.ForeignKey(blank=True, help_text='Displayed on subscription vouchers', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='President of the association')), + ], + options={ + 'verbose_name': 'Mandate', + 'verbose_name_plural': 'Mandates', + 'permissions': (('view_mandate', 'Can view a mandate'),), + }, + bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), + ), + migrations.RunPython(create_current_mandate), + ] diff --git a/preferences/models.py b/preferences/models.py index 39eb814e..90655d48 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -501,6 +501,41 @@ class MailContact(AclMixin, models.Model): def __str__(self): return(self.address) +class Mandate(RevMixin, AclMixin, models.Model): + class Meta: + verbose_name = _("Mandate") + verbose_name_plural = _("Mandates") + permissions = ( + ("view_mandate", _("Can view a mandate")), + ) + + president = models.ForeignKey( + 'users.User', + on_delete=models.SET_NULL, + null=True, + blank=True, + verbose_name=_("President of the association"), + help_text=_("Displayed on subscription vouchers") + ) + start_date = models.DateTimeField( + verbose_name=_("start date") + ) + end_date = models.DateTimeField( + verbose_name=_("end date"), + blank=True, + null=True + ) + + @classmethod + def get_mandate(cls, date=timezone.now): + if callable(date): + date = date() + return cls.objects.get( + start_date__gte=date, end_date__lte=date + ) + + def is_over(self): + return self.end_date is None class AssoOption(AclMixin, PreferencesModel): """Options générales de l'asso : siret, addresse, nom, etc""" diff --git a/preferences/templates/preferences/aff_mandate.html b/preferences/templates/preferences/aff_mandate.html new file mode 100644 index 00000000..38017985 --- /dev/null +++ b/preferences/templates/preferences/aff_mandate.html @@ -0,0 +1,52 @@ +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2018 Hugo Levy-Falk + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} +{% load i18n %} +{% load acl %} +{% load logs_extra %} + + + + + + + + + + + {% for mandate in mandate_list %} + + + + + + + {% endfor %} +
    {% trans "Start date" %}{% trans "End date" %}{% trans "President" %}
    {{mandate.start_date|date:"d/m/Y"}}{% if mandate.end_date %}{{mandate.end_date|date:"d/m/Y"}}{% else %}{% trans "In progress." %}{% endif %}{{mandate.president.name}} {{mandate.president.surname}} + {% can_edit mandate%} + {% include 'buttons/edit.html' with href='preferences:edit-mandate' id=mandate.id %} + {% acl_end %} + {% can_delete mandate %} + {% include 'buttons/suppr.html' with href='preferences:del-mandate' id=mandate.id %} + {% acl_end %} + {% history_button mandate %} +
    + diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index 0d2b3a6e..a94c2c11 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -330,6 +330,13 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ assooptions.pres_name }} +
    {% trans "Mandates" %}
    + {% can_create Mandate %} + + {% trans "Add a mandate" %} + + {% acl_end %} + {% include 'preferences/aff_mandate.html' with mandate_list=mandate_list %}
    diff --git a/preferences/urls.py b/preferences/urls.py index 656689ba..a03d7412 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -126,6 +126,21 @@ urlpatterns = [ views.del_document_template, name='del-document-template' ), + url( + r'^add_mandate/$', + views.add_mandate, + name='add-mandate' + ), + url( + r'^edit_mandate/(?P[0-9]+)$', + views.edit_mandate, + name='edit-mandate' + ), + url( + r'^del_mandate/(?P[0-9]+)$', + views.del_mandate, + name='del-mandate' + ), url(r'^add_radiusattribute/$', views.add_radiusattribute, name='add-radiusattribute'), url( r'^edit_radiusattribute/(?P[0-9]+)$', diff --git a/preferences/views.py b/preferences/views.py index 065ea6cf..9a5da84d 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -54,7 +54,8 @@ from .forms import ( DocumentTemplateForm, DelDocumentTemplateForm, RadiusAttributeForm, - DelRadiusAttributeForm + DelRadiusAttributeForm, + MandateForm ) from .models import ( Service, @@ -72,7 +73,8 @@ from .models import ( RadiusOption, CotisationsOption, DocumentTemplate, - RadiusAttribute + RadiusAttribute, + Mandate ) from . import models from . import forms @@ -89,6 +91,7 @@ def display_options(request): topologieoptions, _created = OptionalTopologie.objects.get_or_create() generaloptions, _created = GeneralOption.objects.get_or_create() assooptions, _created = AssoOption.objects.get_or_create() + mandate_list = Mandate.objects.order_by('start_date') homeoptions, _created = HomeOption.objects.get_or_create() mailmessageoptions, _created = MailMessageOption.objects.get_or_create() service_list = Service.objects.all() @@ -110,6 +113,7 @@ def display_options(request): 'topologieoptions': topologieoptions, 'generaloptions': generaloptions, 'assooptions': assooptions, + 'mandate_list': mandate_list, 'homeoptions': homeoptions, 'mailmessageoptions': mailmessageoptions, 'service_list': service_list, @@ -558,3 +562,54 @@ def del_radiusattribute(request, radiusattribute_instance, **_kwargs): ) +@login_required +@can_create(Mandate) +def add_mandate(request): + """Create a mandate.""" + mandate = MandateForm(request.POST or None) + if mandate.is_valid(): + mandate.save() + messages.success(request, _("The mandate was added.")) + return redirect(reverse('preferences:display-options')) + return form( + {'preferenceform': mandate, 'action_name': _("Add a mandate")}, + 'preferences/preferences.html', + request + ) + + +@login_required +@can_edit(Mandate) +def edit_mandate(request, mandate_instance, **_kwargs): + """Edit a mandate.""" + mandate = MandateForm( + request.POST or None, + instance=mandate_instance + ) + if mandate.is_valid(): + mandate.save() + messages.success(request, _("The mandate was edited.")) + return redirect(reverse('preferences:display-options')) + return form( + {'preferenceform': mandate, 'action_name': _("Edit")}, + 'preferences/preferences.html', + request + ) + +@login_required +@can_delete(Mandate) +def del_mandate(request, mandate_instance, **_kwargs): + """Delete a mandate.""" + if request.method == "POST": + mandate_instance.delete() + messages.success(request, _("The mandate was deleted.")) + return redirect(reverse('preferences:display-options')) + return form( + {'objet': mandate_instance, 'objet_name': 'attribute'}, + 'preferences/delete.html', + request + ) + + + + From 6dd4e776c1b7e5bd5a4f7caec051d06976d391fc Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Mon, 23 Sep 2019 22:49:59 +0200 Subject: [PATCH 151/228] Make use of mandates everywhere. --- cotisations/utils.py | 7 +++++-- cotisations/views.py | 5 +++-- preferences/migrations/0063_mandate.py | 5 +++++ preferences/models.py | 20 +++++++++++++++++--- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/cotisations/utils.py b/cotisations/utils.py index 8b7ee2b0..b1e5f613 100644 --- a/cotisations/utils.py +++ b/cotisations/utils.py @@ -25,7 +25,9 @@ from django.template.loader import get_template from django.core.mail import EmailMessage from .tex import create_pdf -from preferences.models import AssoOption, GeneralOption, CotisationsOption +from preferences.models import ( + AssoOption, GeneralOption, CotisationsOption, Mandate +) from re2o.settings import LOGO_PATH from re2o import settings @@ -97,9 +99,10 @@ def send_mail_invoice(invoice): def send_mail_voucher(invoice): """Creates a voucher from an invoice and sends it by email to the client""" + president = Mandate.get_mandate().president ctx = { 'asso_name': AssoOption.get_cached_value('name'), - 'pres_name': AssoOption.get_cached_value('pres_name'), + 'pres_name': ' '.join([president.name, president.surname]), 'firstname': invoice.user.name, 'lastname': invoice.user.surname, 'email': invoice.user.email, diff --git a/cotisations/views.py b/cotisations/views.py index e53b8553..a32c320f 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -60,7 +60,7 @@ from re2o.acl import ( can_delete_set, can_change, ) -from preferences.models import AssoOption, GeneralOption +from preferences.models import AssoOption, GeneralOption, Mandate from .models import ( Facture, Article, @@ -1068,9 +1068,10 @@ def voucher_pdf(request, invoice, **_kwargs): _("Could not find a voucher for that invoice.") ) return redirect(reverse('cotisations:index')) + president = Mandate.get_mandate().president return render_voucher(request, { 'asso_name': AssoOption.get_cached_value('name'), - 'pres_name': AssoOption.get_cached_value('pres_name'), + 'pres_name': ' '.join([president.name, president.surname]), 'firstname': invoice.user.name, 'lastname': invoice.user.surname, 'email': invoice.user.email, diff --git a/preferences/migrations/0063_mandate.py b/preferences/migrations/0063_mandate.py index f28acee4..7f5dcf8b 100644 --- a/preferences/migrations/0063_mandate.py +++ b/preferences/migrations/0063_mandate.py @@ -51,4 +51,9 @@ class Migration(migrations.Migration): bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), ), migrations.RunPython(create_current_mandate), + migrations.AlterField( + model_name='cotisationsoption', + name='send_voucher_mail', + field=models.BooleanField(default=False, help_text='Be carefull, if no mandate is defined on the preferences page, errors will be triggered when generating vouchers.', verbose_name='Send voucher by email when the invoice is controlled.'), + ), ] diff --git a/preferences/models.py b/preferences/models.py index 90655d48..eb904148 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -528,11 +528,24 @@ class Mandate(RevMixin, AclMixin, models.Model): @classmethod def get_mandate(cls, date=timezone.now): + """"Find the mandate taking place at the given date. If none is found + look for the nearest in the future. If none is found (again), look + for the nearest in the past.""" if callable(date): date = date() - return cls.objects.get( - start_date__gte=date, end_date__lte=date - ) + try: + return cls.objects.get( + start_date__gte=date, end_date__lte=date + ) + except cls.DoesNotExist: + try: + return cls.objects.filter(start_date__gte=date).earliest('start_date') + except cls.DoesNotExist: + try: + return cls.objects.filter(start_date__lte=date).latest('start_date') + except cls.DoesNotExist: + raise cls.DoesNotExist("No mandate have been created. Please go to the preferences page to create one.") + def is_over(self): return self.end_date is None @@ -847,6 +860,7 @@ class CotisationsOption(AclMixin, PreferencesModel): ) send_voucher_mail = models.BooleanField( verbose_name=_("Send voucher by email when the invoice is controlled."), + help_text=_("Be carefull, if no mandate is defined on the preferences page, errors will be triggered when generating vouchers."), default=False, ) From 621cdc96599f59c89d3b9bfcda83b3ee76b1f03d Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Mon, 23 Sep 2019 23:39:54 +0200 Subject: [PATCH 152/228] Try to make mandate edition fool-proof --- preferences/forms.py | 55 +++++++++++++++++++ .../templates/preferences/preferences.html | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/preferences/forms.py b/preferences/forms.py index 981bf5e2..f860640b 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -26,6 +26,7 @@ Formulaire d'edition des réglages : user, machine, topologie, asso... from __future__ import unicode_literals from django.forms import ModelForm, Form +from django.db.models import Q from django import forms from django.utils.translation import ugettext_lazy as _ from re2o.mixins import FormRevMixin @@ -272,6 +273,60 @@ class MandateForm(ModelForm): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(MandateForm, self).__init__(*args, prefix=prefix, **kwargs) + def clean_start_date(self): + date = self.cleaned_data.get('start_date') + existing_mandates = Mandate.objects.filter( + start_date__gte=date, end_date__lt=date + ) + if existing_mandates: + raise forms.ValidationError( + _("There is already a mandate taking place at the specified start date.") + ) + return date + + def clean_end_date(self): + date = self.cleaned_data.get('end_date') + if date is None: + return None + existing_mandates = Mandate.objects.filter( + start_date__gte=date, end_date__lt=date + ) + if existing_mandates: + raise forms.ValidationError( + _("There is already a mandate taking place at the specified end date.") + ) + return date + + def clean(self): + cleaned_data = super(MandateForm, self).clean() + start_date, end_date = cleaned_data['start_date'], cleaned_data['end_date'] + included_mandates = Mandate.objects.filter( + Q(start_date__gte=start_date, start_date__lt=end_date) + | Q(end_date__gt=start_date, end_date__lte=end_date) + ) + if included_mandates: + raise forms.ValidationError( + _("The specified dates overlap with an existing mandate."), + code='invalid' + ) + return cleaned_data + + def save(self, commit=True): + """Warning, side effect : if a mandate with a null end_date + exists, its end_date will be set to instance.start_date, no matter the + value of commit.""" + instance = super(MandateForm, self).save(commit=False) + if instance.end_date is None: + try: + previous_mandate = Mandate.objects.get(end_date__isnull=True) + previous_mandate.end_date = instance.start_date + previous_mandate.save() + except Mandate.DoesNotExist: + pass + if commit: + instance.save() + return instance + class ServiceForm(ModelForm): """Edition, ajout de services sur la page d'accueil""" diff --git a/preferences/templates/preferences/preferences.html b/preferences/templates/preferences/preferences.html index a2759781..5c76de61 100644 --- a/preferences/templates/preferences/preferences.html +++ b/preferences/templates/preferences/preferences.html @@ -38,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% csrf_token %} {% if preferenceform %} - {% massive_bootstrap_form preferenceform 'members' %} + {% massive_bootstrap_form preferenceform 'members,president' %} {% endif %} {% bootstrap_button action_name button_type="submit" icon='ok' button_class='btn-success' %} From 7db8872bc8a196a3d8c2194cc3e6d69fba993260 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Tue, 24 Sep 2019 00:04:00 +0200 Subject: [PATCH 153/228] Delete CotisationsOption.pres_name and better migration. --- preferences/migrations/0063_mandate.py | 13 +++++++++++-- preferences/models.py | 6 ------ .../templates/preferences/display_preferences.html | 4 ---- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/preferences/migrations/0063_mandate.py b/preferences/migrations/0063_mandate.py index 7f5dcf8b..16e52b29 100644 --- a/preferences/migrations/0063_mandate.py +++ b/preferences/migrations/0063_mandate.py @@ -13,7 +13,8 @@ def create_current_mandate(apps, schema_editor): AssoOption = apps.get_model('preferences', 'AssoOption') Mandate = apps.get_model('preferences', 'Mandate') Adherent = apps.get_model('users', 'Adherent') - pres_name = AssoOption.objects.get_or_create()[0].pres_name + assooption = AssoOption.objects.get_or_create()[0] + pres_name = assooption.pres_name l = pres_name.split(' ') try: name, surname = l[0], l[1] @@ -23,7 +24,11 @@ def create_current_mandate(apps, schema_editor): start_date=timezone.now(), ) except Exception as e: - print("Warning : I was unable to find an adherent corresponding to %s. You might want to edit your preferences afterward." % pres_name) + print("Warning : I was unable to find an adherent corresponding to %s. You might want to edit your preferences afterward. I will disable the sending of vouchers by email." % pres_name) + CotisationsOption = apps.get_model('preferences', 'CotisationsOption') + cotisoption = CotisationsOption.objects.get_or_create()[0] + cotisoption.send_voucher_mail = False + cotisoption.save() @@ -56,4 +61,8 @@ class Migration(migrations.Migration): name='send_voucher_mail', field=models.BooleanField(default=False, help_text='Be carefull, if no mandate is defined on the preferences page, errors will be triggered when generating vouchers.', verbose_name='Send voucher by email when the invoice is controlled.'), ), + migrations.RemoveField( + model_name='assooption', + name='pres_name', + ), ] diff --git a/preferences/models.py b/preferences/models.py index eb904148..0473ef9d 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -573,12 +573,6 @@ class AssoOption(AclMixin, PreferencesModel): null=True, blank=True, ) - pres_name = models.CharField( - max_length=255, - default="", - verbose_name=_("President of the association"), - help_text=_("Displayed on subscription vouchers") - ) class Meta: permissions = ( diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index a94c2c11..ff186f11 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -325,10 +325,6 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Description of the organisation" %} {{ assooptions.description|safe }} - - {% trans "President of the association"%} - {{ assooptions.pres_name }} -
    {% trans "Mandates" %}
    {% can_create Mandate %} From 21f95fbc9d555e7d7e3d9236c589a3b7debdabcf Mon Sep 17 00:00:00 2001 From: chirac Date: Tue, 24 Sep 2019 00:40:22 +0200 Subject: [PATCH 154/228] Simplify models.py --- preferences/models.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/preferences/models.py b/preferences/models.py index 0473ef9d..ab2aa29c 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -528,27 +528,21 @@ class Mandate(RevMixin, AclMixin, models.Model): @classmethod def get_mandate(cls, date=timezone.now): - """"Find the mandate taking place at the given date. If none is found - look for the nearest in the future. If none is found (again), look - for the nearest in the past.""" + """"Find the mandate taking place at the given date.""" if callable(date): date = date() - try: - return cls.objects.get( - start_date__gte=date, end_date__lte=date - ) - except cls.DoesNotExist: - try: - return cls.objects.filter(start_date__gte=date).earliest('start_date') - except cls.DoesNotExist: - try: - return cls.objects.filter(start_date__lte=date).latest('start_date') - except cls.DoesNotExist: - raise cls.DoesNotExist("No mandate have been created. Please go to the preferences page to create one.") + mandate = cls.objects.filter(start_date__lte=date).order_by('-start_date').first() + if not mandate: + raise cls.DoesNotExist("No mandate have been created. Please go to the preferences page to create one.") + return mandate def is_over(self): return self.end_date is None + + def __str__(self): + return str(self.president) + ' ' + str(self.start_date.year) + class AssoOption(AclMixin, PreferencesModel): """Options générales de l'asso : siret, addresse, nom, etc""" From b38521db690b3278f52f6de96fafc443fc046b45 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 24 Sep 2019 01:04:38 +0200 Subject: [PATCH 155/228] For my klafy : return best mandate possible --- preferences/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/preferences/models.py b/preferences/models.py index ab2aa29c..f09e63a7 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -531,7 +531,7 @@ class Mandate(RevMixin, AclMixin, models.Model): """"Find the mandate taking place at the given date.""" if callable(date): date = date() - mandate = cls.objects.filter(start_date__lte=date).order_by('-start_date').first() + mandate = cls.objects.exclude(end_date__lte=date).order_by('start_date').first() or cls.objects.order_by('start_date').last() if not mandate: raise cls.DoesNotExist("No mandate have been created. Please go to the preferences page to create one.") return mandate From 5c0a4ce748661fafce648a8176346ca4e2128eb3 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sat, 28 Sep 2019 12:38:57 +0200 Subject: [PATCH 156/228] Fix form validation --- preferences/forms.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/preferences/forms.py b/preferences/forms.py index f860640b..312d0b2b 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -300,15 +300,16 @@ class MandateForm(ModelForm): def clean(self): cleaned_data = super(MandateForm, self).clean() start_date, end_date = cleaned_data['start_date'], cleaned_data['end_date'] - included_mandates = Mandate.objects.filter( - Q(start_date__gte=start_date, start_date__lt=end_date) - | Q(end_date__gt=start_date, end_date__lte=end_date) - ) - if included_mandates: - raise forms.ValidationError( - _("The specified dates overlap with an existing mandate."), - code='invalid' + if end_date: + included_mandates = Mandate.objects.filter( + Q(start_date__gte=start_date, start_date__lt=end_date) + | Q(end_date__gt=start_date, end_date__lte=end_date) ) + if included_mandates: + raise forms.ValidationError( + _("The specified dates overlap with an existing mandate."), + code='invalid' + ) return cleaned_data def save(self, commit=True): From 6171f42b6602b5e0a250cda2eaae7bd06e383e84 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sat, 28 Sep 2019 13:01:22 +0200 Subject: [PATCH 157/228] Get the right mandate when creating voucher. --- cotisations/utils.py | 2 +- cotisations/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cotisations/utils.py b/cotisations/utils.py index b1e5f613..6746a1da 100644 --- a/cotisations/utils.py +++ b/cotisations/utils.py @@ -99,7 +99,7 @@ def send_mail_invoice(invoice): def send_mail_voucher(invoice): """Creates a voucher from an invoice and sends it by email to the client""" - president = Mandate.get_mandate().president + president = Mandate.get_mandate(invoice.date).president ctx = { 'asso_name': AssoOption.get_cached_value('name'), 'pres_name': ' '.join([president.name, president.surname]), diff --git a/cotisations/views.py b/cotisations/views.py index a32c320f..437d5df1 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -1068,7 +1068,7 @@ def voucher_pdf(request, invoice, **_kwargs): _("Could not find a voucher for that invoice.") ) return redirect(reverse('cotisations:index')) - president = Mandate.get_mandate().president + president = Mandate.get_mandate(invoice.date).president return render_voucher(request, { 'asso_name': AssoOption.get_cached_value('name'), 'pres_name': ' '.join([president.name, president.surname]), From e7679193b266803eeb6241f8496c71dc19921740 Mon Sep 17 00:00:00 2001 From: jr-garnier Date: Tue, 1 Oct 2019 21:59:38 +0200 Subject: [PATCH 158/228] Bootstrap accordion ios --- static/css/base.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/static/css/base.css b/static/css/base.css index a13c596f..c1b8bcbc 100644 --- a/static/css/base.css +++ b/static/css/base.css @@ -143,3 +143,8 @@ dl.profile-info > div { padding: 8px; border-top: 1px solid #ddd; } + +/* Make bootstrap accordions clickable on iOS */ +[data-toggle~="collapse"] { + cursor: pointer; +} From 051ec84f6ea0096c6bdd1f18d33e4f0cc4e04e1b Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Fri, 20 Sep 2019 00:09:49 +0200 Subject: [PATCH 159/228] Multi_opp app optional start --- multi_op/__init__.py | 0 multi_op/apps.py | 33 ++++ multi_op/forms.py | 54 ++++++ multi_op/preferences/forms.py | 39 ++++ multi_op/preferences/models.py | 40 ++++ .../templates/multi_op/aff_room_state.html | 69 +++++++ .../templates/multi_op/form_preferences.html | 48 +++++ multi_op/templates/multi_op/form_ticket.html | 58 ++++++ multi_op/templates/multi_op/index.html | 34 ++++ .../templates/multi_op/index_room_state.html | 53 ++++++ multi_op/templates/multi_op/navbar.html | 2 + .../templates/multi_op/navbar_logout.html | 6 + multi_op/templates/multi_op/preferences.html | 36 ++++ multi_op/templates/multi_op/sidebar.html | 43 +++++ multi_op/tests.py | 3 + multi_op/urls.py | 38 ++++ multi_op/views.py | 179 ++++++++++++++++++ users/views.py | 2 +- 18 files changed, 736 insertions(+), 1 deletion(-) create mode 100644 multi_op/__init__.py create mode 100644 multi_op/apps.py create mode 100644 multi_op/forms.py create mode 100644 multi_op/preferences/forms.py create mode 100644 multi_op/preferences/models.py create mode 100644 multi_op/templates/multi_op/aff_room_state.html create mode 100644 multi_op/templates/multi_op/form_preferences.html create mode 100644 multi_op/templates/multi_op/form_ticket.html create mode 100644 multi_op/templates/multi_op/index.html create mode 100644 multi_op/templates/multi_op/index_room_state.html create mode 100644 multi_op/templates/multi_op/navbar.html create mode 100644 multi_op/templates/multi_op/navbar_logout.html create mode 100644 multi_op/templates/multi_op/preferences.html create mode 100644 multi_op/templates/multi_op/sidebar.html create mode 100644 multi_op/tests.py create mode 100644 multi_op/urls.py create mode 100644 multi_op/views.py diff --git a/multi_op/__init__.py b/multi_op/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/multi_op/apps.py b/multi_op/apps.py new file mode 100644 index 00000000..ae633793 --- /dev/null +++ b/multi_op/apps.py @@ -0,0 +1,33 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2019 Gabriel Détraz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +The database models for the 'apps' app of re2o. + +For further details on each of those models, see the documentation details for +each. +""" + + +from django.apps import AppConfig + + +class MultiOpConfig(AppConfig): + name = 'multi_op' diff --git a/multi_op/forms.py b/multi_op/forms.py new file mode 100644 index 00000000..bedebb0a --- /dev/null +++ b/multi_op/forms.py @@ -0,0 +1,54 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2017 Gabriel Détraz +# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Augustin Lemesle +# Copyright © 2017 Maël Kervella +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +Select a dorm +""" + + +from django import forms +from django.forms import ModelForm, Form +from re2o.field_permissions import FieldPermissionFormMixin +from re2o.mixins import FormRevMixin +from django.utils.translation import ugettext_lazy as _ + +from topologie.models import( + Dormitory, +) + + +class DormitoryForm(FormRevMixin, Form): + """Select a dorm""" + dormitory = forms.ModelMultipleChoiceField( + queryset=Dormitory.objects.all(), + label=_("Dormitory"), + widget=forms.CheckboxSelectMultiple, + required=False + ) + + def __init__(self, *args, **kwargs): + super(DormitoryForm, self).__init__(*args, **kwargs) + + + + diff --git a/multi_op/preferences/forms.py b/multi_op/preferences/forms.py new file mode 100644 index 00000000..d5e6ce80 --- /dev/null +++ b/multi_op/preferences/forms.py @@ -0,0 +1,39 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2019 Gabriel Détraz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +The database models for the 'preference' app of re2o. + +For further details on each of those models, see the documentation details for +each. +""" + + +from django import forms +from django.forms import ModelForm, Form +from django.utils.translation import ugettext_lazy as _ + +from .models import Preferences + +class EditPreferencesForm(ModelForm): + """ Edit the ticket's settings""" + class Meta: + model = Preferences + fields = '__all__' diff --git a/multi_op/preferences/models.py b/multi_op/preferences/models.py new file mode 100644 index 00000000..89e82fb2 --- /dev/null +++ b/multi_op/preferences/models.py @@ -0,0 +1,40 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2019 Gabriel Détraz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +Fichier définissant les administration des models de preference +""" + + +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +class Preferences(models.Model): + """ Definition of the app settings""" + + enabled_dorm = models.ManyToManyField( + 'topologie.Dormitory', + related_name='vlan_tagged', + blank=True, + verbose_name=_("Enabled dorm") + ) + + class Meta: + verbose_name = _("Dormitory of connection settings") diff --git a/multi_op/templates/multi_op/aff_room_state.html b/multi_op/templates/multi_op/aff_room_state.html new file mode 100644 index 00000000..57205953 --- /dev/null +++ b/multi_op/templates/multi_op/aff_room_state.html @@ -0,0 +1,69 @@ +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load acl %} +{% load logs_extra %} +{% load i18n %} + +{% if room_list.paginator %} + {% include 'pagination.html' with list=room_list %} +{% endif %} + + + + + {% trans "Room" as tr_room %} + {% trans "Building" as tr_building %} + + + + + + + + + + {% for room in room_list %} + + + + + + + + + + {% endfor %} +
    {% include 'buttons/sort.html' with prefix='building' col='name' text=tr_building %}{% include 'buttons/sort.html' with prefix='room' col='name' text=tr_room %}{% trans "Connnected on" %}{% trans "User" %}{% trans "Details" %}{% trans "End of subscription on" %}{% trans "Internet access" %}
    {{ room.building }}{{ room.name }}{% if room.port_set.all %}AURORE{% else %}{% trans "Other operator" %}{% endif %}{% if room.adherent %}{{ room.adherent }}{% else %} {% trans "Aucun" %}{% endif %}{{ room.details }}{% if room.user.is_adherent %}{{ room.user.end_adhesion }}{% else %}{% trans "Not a member" %}{% endif %} + {% if room.user.has_access == True %} + {% trans "Active" %} + {% else %} + {% trans "Disabled" %} + {% endif %} +
    + +{% if room_list.paginator %} + {% include 'pagination.html' with list=room_list %} +{% endif %} + diff --git a/multi_op/templates/multi_op/form_preferences.html b/multi_op/templates/multi_op/form_preferences.html new file mode 100644 index 00000000..5c7e5d5e --- /dev/null +++ b/multi_op/templates/multi_op/form_preferences.html @@ -0,0 +1,48 @@ +{% extends 'machines/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle +Copyright © 2017 Maël Kervella + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load i18n %} + +{% block title %}{% trans "Ticket" %}{% endblock %} + +{% block content %} +

    {% trans "Tickets settings modification" %}

    + +{% for message in messages %} +
    + + {{ message | safe }} +
    +{% endfor %} + +
    + {% csrf_token %} + {% bootstrap_field preferencesform.publish_address %} + {% bootstrap_field preferencesform.mail_language %} + {% bootstrap_button "Editer" button_type="submit" icon='ok' button_class='btn-success' %} +
    +{% endblock %} diff --git a/multi_op/templates/multi_op/form_ticket.html b/multi_op/templates/multi_op/form_ticket.html new file mode 100644 index 00000000..d35e9f5d --- /dev/null +++ b/multi_op/templates/multi_op/form_ticket.html @@ -0,0 +1,58 @@ +{% extends 'machines/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle +Copyright © 2017 Maël Kervella + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load massive_bootstrap_form %} +{% load i18n %} + +{% block title %}{% trans "Ticket" %}{% endblock %} + +{% block content %} +

    Ouverture d'un Ticket

    + +
    + {% csrf_token %} + {% if not user.is_authenticated %} +

    {% trans "Vous n'êtes pas authentifié. Veuillez fournir une adresse mail afin que nous puissions vous recontacter." %}

    + {% bootstrap_field ticketform.email %} + {% endif %} + {% bootstrap_field ticketform.title %} +
    +

    {% trans "Description de votre problème. Veuillez fournir le plus d'informations possible afin de faciliter la recherche de solution. Voici quelques informations dont nous pourions avoir besoin:" %}

    +
      +
    • +

      {% trans "Le type de votre problème (adhesion, connexion, paiement ou autre)." %}

      +
    • +
    • +

      {% trans "Les conditions dans lesquelles vous rencontrez le problème (Wifi/filaire, sur tout les apareils ou sur un seul. Est-ce une nouvelle machine ?" %}

      +
    • +
    • +

      {% trans "Les endroits dans lequels le problème survient (chez vous, dans une partie commune, dans un batiment en particulier)." %}

      +
    + {% bootstrap_field ticketform.description %} + {% bootstrap_button "Ouvrir le Ticket" button_type="submit" icon='ok' button_class='btn-success' %} +
    +{% endblock %} diff --git a/multi_op/templates/multi_op/index.html b/multi_op/templates/multi_op/index.html new file mode 100644 index 00000000..4429c4fd --- /dev/null +++ b/multi_op/templates/multi_op/index.html @@ -0,0 +1,34 @@ +{% extends 'users/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load i18n %} + +{% block title%}{% trans "Tickets" %}{% endblock %} + +{% block content %} +

    {% trans "Tickets" %}

    + {% include 'tickets/aff_tickets.html' with tickets_list=tickets_list %} +{% endblock %} diff --git a/multi_op/templates/multi_op/index_room_state.html b/multi_op/templates/multi_op/index_room_state.html new file mode 100644 index 00000000..50881a19 --- /dev/null +++ b/multi_op/templates/multi_op/index_room_state.html @@ -0,0 +1,53 @@ +{% extends 'multi_op/sidebar.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load bootstrap3 %} +{% load acl %} +{% load i18n %} + +{% block title %}{% trans "Multi Operators" %}{% endblock %} + +{% block content %} + +{% if dormitory_form %} +{% bootstrap_form_errors dormitory_form %} +{% endif %} + +

    {% trans "Rooms connections" %}

    + +{% if dormitory_form %} +
    + {% csrf_token %} + {% bootstrap_form dormitory_form %} + {% bootstrap_button "Select Dormitory" icon='ok' button_class='btn-success' %} +
    +{% endif %} + +{% include 'multi_op/aff_room_state.html' with room_list=room_list %} +
    +
    +
    +{% endblock %} + diff --git a/multi_op/templates/multi_op/navbar.html b/multi_op/templates/multi_op/navbar.html new file mode 100644 index 00000000..d5b6cb51 --- /dev/null +++ b/multi_op/templates/multi_op/navbar.html @@ -0,0 +1,2 @@ +{% load i18n %} +
  • {% trans "Tickets" %}
  • diff --git a/multi_op/templates/multi_op/navbar_logout.html b/multi_op/templates/multi_op/navbar_logout.html new file mode 100644 index 00000000..8a7114f3 --- /dev/null +++ b/multi_op/templates/multi_op/navbar_logout.html @@ -0,0 +1,6 @@ +{% load i18n %} +
  • + + {% trans "Ouvrir un ticket" %} + +
  • diff --git a/multi_op/templates/multi_op/preferences.html b/multi_op/templates/multi_op/preferences.html new file mode 100644 index 00000000..60cbfac6 --- /dev/null +++ b/multi_op/templates/multi_op/preferences.html @@ -0,0 +1,36 @@ +{% load i18n %} + +
    + + +
    + + + + {% trans "Edit" %} + +

    + +
    + + + + {% if preferences.publish_address %} + + {% else %} + + {% endif %} + + + + +

    {% trans "Publication email address"%}

    {{ preferences.publish_address }}

    {% trans "Pas d'adresse, les tickets ne sont pas annoncés" %}

    {% trans "Email language" %}

    {{ language }}

    +
    +
    +
    +
    +
    diff --git a/multi_op/templates/multi_op/sidebar.html b/multi_op/templates/multi_op/sidebar.html new file mode 100644 index 00000000..0433fc61 --- /dev/null +++ b/multi_op/templates/multi_op/sidebar.html @@ -0,0 +1,43 @@ +{% extends 'base.html' %} +{% comment %} +Re2o est un logiciel d'administration développé initiallement au rezometz. Il +se veut agnostique au réseau considéré, de manière à être installable en +quelques clics. + +Copyright © 2017 Gabriel Détraz +Copyright © 2017 Goulven Kermarec +Copyright © 2017 Augustin Lemesle + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +{% endcomment %} + +{% load i18n %} + +{% block sidebar %} + + + {% trans "Rooms connection state" %} + + + + {% trans "Sockets to connect" %} + + + + {% trans "Sockets to disconnect" %} + + +{% endblock %} + diff --git a/multi_op/tests.py b/multi_op/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/multi_op/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/multi_op/urls.py b/multi_op/urls.py new file mode 100644 index 00000000..0dbb0ca8 --- /dev/null +++ b/multi_op/urls.py @@ -0,0 +1,38 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2019 Gabriel Détraz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" +The database models for the 'urls' app of re2o. + +For further details on each of those models, see the documentation details for +each. +""" + +from django.conf.urls import url + +from . import views + +urlpatterns = [ + url(r'^$', views.aff_state_global, name='aff-state-global'), + url(r'^(?P[0-9]+)$', views.aff_state_dormitory, name='aff-state-dormitory'), + url(r'^pending-connection$', views.aff_pending_connection, name='aff-pending-connection'), + url(r'^pending-disconnection$', views.aff_pending_disconnection, name='aff-pending-disconnection'), + # url(r'^multi_op/edit-preferences-multiop$', views.edit_preferences, name='edit-preferences-multiop'), +] diff --git a/multi_op/views.py b/multi_op/views.py new file mode 100644 index 00000000..41c7e40d --- /dev/null +++ b/multi_op/views.py @@ -0,0 +1,179 @@ +# -*- mode: python; coding: utf-8 -*- +# Re2o est un logiciel d'administration développé initiallement au rezometz. Il +# se veut agnostique au réseau considéré, de manière à être installable en +# quelques clics. +# +# Copyright © 2017 Gabriel Détraz +# Copyright © 2017 Goulven Kermarec +# Copyright © 2017 Augustin Lemesle +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# App de gestion des users pour re2o +# Goulven Kermarec, Gabriel Détraz, Lemesle Augustin +# Gplv2 + +from django.contrib import messages +from django.contrib.auth.decorators import login_required +from django.shortcuts import render, redirect +from django.template.loader import render_to_string +from django.views.decorators.cache import cache_page +from django.utils.translation import ugettext as _ +from django.urls import reverse +from django.forms import modelformset_factory +from django.db.models import Q +from re2o.views import form +from re2o.utils import all_has_access, all_adherent + +from re2o.base import ( + re2o_paginator, + SortTable, +) + +from re2o.acl import( + can_view, + can_view_all, + can_edit, + can_create, +) + +from preferences.models import GeneralOption + +from .forms import DormitoryForm + +from .preferences.models import( + Preferences, +) + +from topologie.models import Room, Dormitory + +from .preferences.forms import ( + EditPreferencesForm, +) + + +def display_rooms_connection(request, dormitory=None): + """View to display global state of connection state""" + room_list = Room.objects.select_related('building__dormitory').order_by('building_dormitory', 'port') + if dormitory: + room_list = room_list.filter(building__dormitory=dormitory) + room_list = SortTable.sort( + room_list, + request.GET.get('col'), + request.GET.get('order'), + SortTable.TOPOLOGIE_INDEX_ROOM + ) + pagination_number = GeneralOption.get_cached_value('pagination_number') + room_list = re2o_paginator(request, room_list, pagination_number) + return render( + request, + 'multi_op/index_room_state.html', + {'room_list': room_list} + ) + + +@login_required +@can_view_all(Room) +def aff_state_global(request): + return display_rooms_connection(request) + + +@login_required +@can_view(Dormitory) +def aff_state_dormitory(request, dormitory, dormitoryid): + return display_rooms_connection(dormitory=dormitory) + + +@login_required +@can_view_all(Room) +def aff_pending_connection(request): + """Aff pending Rooms to connect on our network""" + room_list = Room.objects.select_related('building__dormitory').filter(port__isnull=True).filter(adherent__in=all_has_access()).order_by('building_dormitory', 'port') + dormitory_form = DormitoryForm(request.POST or None) + if dormitory_form.is_valid(): + room_list = room_list.filter(building__dormitory__in=dormitory_form.cleaned_data['dormitory']) + room_list = SortTable.sort( + room_list, + request.GET.get('col'), + request.GET.get('order'), + SortTable.TOPOLOGIE_INDEX_ROOM + ) + pagination_number = GeneralOption.get_cached_value('pagination_number') + room_list = re2o_paginator(request, room_list, pagination_number) + return render( + request, + 'multi_op/index_room_state.html', + {'room_list': room_list, 'dormitory_form': dormitory_form} + ) + + +@login_required +@can_view_all(Room) +def aff_pending_disconnection(request): + """Aff pending Rooms to disconnect from our network""" + room_list = Room.objects.select_related('building__dormitory').filter(port__isnull=False).exclude(Q(adherent__in=all_has_access()) | Q(adherent__in=all_adherent())).order_by('building_dormitory', 'port') + dormitory_form = DormitoryForm(request.POST or None) + if dormitory_form.is_valid(): + room_list = room_list.filter(building__dormitory__in=dormitory_form.cleaned_data['dormitory']) + room_list = SortTable.sort( + room_list, + request.GET.get('col'), + request.GET.get('order'), + SortTable.TOPOLOGIE_INDEX_ROOM + ) + pagination_number = GeneralOption.get_cached_value('pagination_number') + room_list = re2o_paginator(request, room_list, pagination_number) + return render( + request, + 'multi_op/index_room_state.html', + {'room_list': room_list, 'dormitory_form': dormitory_form} + ) + + +def edit_preferences(request): + """ View to edit the settings of the tickets """ + + preferences_instance, created = Preferences.objects.get_or_create(id=1) + preferencesform = EditPreferencesForm( + request.POST or None, + instance = preferences_instance,) + + if preferencesform.is_valid(): + if preferencesform.changed_data: + preferencesform.save() + messages.success(request,'Preferences updated') + return redirect(reverse('preferences:display-options',)) + else: + messages.error(request,'Formulaire Invalide') + return form({'preferencesform':preferencesform,},'multi_op/form_preferences.html',request) + return form({'preferencesform':preferencesform,},'multi_op/form_preferences.html',request) + + +def navbar_user(request): + """View to display the app in user's dropdown in the navbar""" + return render_to_string('multi_op/navbar.html') + +def navbar_logout(request): + """View to display the app in user's dropdown in the navbar""" + return None + + +def preferences(request): + """ View to display the settings of the tickets in the preferences page""" + pref, created = Preferences.objects.get_or_create(id=1) + context = {'preferences':pref,'language':str(pref.LANGUES[pref.mail_language][1])} + return render_to_string('tickets/preferences.html', context=context, request=request, using=None) + + diff --git a/users/views.py b/users/views.py index 37c0ec88..9764fbe0 100644 --- a/users/views.py +++ b/users/views.py @@ -977,7 +977,7 @@ def profil(request, users, **_kwargs): ) optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] - optionnal_templates_list = [app.views.profil(request,users) for app in optionnal_apps] + optionnal_templates_list = [app.views.profil(request,users) for app in optionnal_apps if hasattr(app.views, 'profil')] pagination_large_number = GeneralOption.get_cached_value( 'pagination_large_number' From 8a41a1af60e35bf9c9c534fc66bb6785b75f8c0d Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Fri, 20 Sep 2019 00:37:59 +0200 Subject: [PATCH 160/228] Fix bug affichage --- multi_op/templates/multi_op/aff_room_state.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/multi_op/templates/multi_op/aff_room_state.html b/multi_op/templates/multi_op/aff_room_state.html index 57205953..de25171b 100644 --- a/multi_op/templates/multi_op/aff_room_state.html +++ b/multi_op/templates/multi_op/aff_room_state.html @@ -51,9 +51,9 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if room.port_set.all %}AURORE{% else %}{% trans "Other operator" %}{% endif %} {% if room.adherent %}{{ room.adherent }}{% else %} {% trans "Aucun" %}{% endif %} {{ room.details }} - {% if room.user.is_adherent %}{{ room.user.end_adhesion }}{% else %}{% trans "Not a member" %}{% endif %} + {% if room.adherent.is_adherent %}{{ room.adherent.end_adhesion }}{% else %}{% trans "Not a member" %}{% endif %} - {% if room.user.has_access == True %} + {% if room.adherent.has_access == True %} {% trans "Active" %} {% else %} {% trans "Disabled" %} From 6d76d0a5f7a8f8ab47fb0dc4f85c17c1720646d6 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Fri, 20 Sep 2019 13:56:26 +0200 Subject: [PATCH 161/228] Contact view on optional app... is optionnal --- re2o/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/re2o/views.py b/re2o/views.py index 414416a7..d443a84c 100644 --- a/re2o/views.py +++ b/re2o/views.py @@ -116,7 +116,7 @@ def contact_page(request): address = MailContact.objects.all() optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] - optionnal_templates_contact_list = [app.views.contact(request) for app in optionnal_apps] + optionnal_templates_contact_list = [app.views.contact(request) for app in optionnal_apps if hasattr(app.views, 'contact')] return render( request, From 6617d6a000c3d3713d50a53bfcbb031bbfd0a8cb Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Fri, 20 Sep 2019 19:56:19 +0200 Subject: [PATCH 162/228] =?UTF-8?q?Fix=20affichage=20dans=20le=20dropdown?= =?UTF-8?q?=20adapt=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- multi_op/templates/multi_op/navbar.html | 2 +- multi_op/views.py | 8 ++------ re2o/context_processors.py | 4 ++-- templates/base.html | 13 ++++++++++--- tickets/templates/tickets/navbar.html | 2 +- tickets/views.py | 8 ++++---- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/multi_op/templates/multi_op/navbar.html b/multi_op/templates/multi_op/navbar.html index d5b6cb51..c5e84c43 100644 --- a/multi_op/templates/multi_op/navbar.html +++ b/multi_op/templates/multi_op/navbar.html @@ -1,2 +1,2 @@ {% load i18n %} -
  • {% trans "Tickets" %}
  • +
  • {% trans "Multi Operators" %}
  • diff --git a/multi_op/views.py b/multi_op/views.py index 41c7e40d..75811a0d 100644 --- a/multi_op/views.py +++ b/multi_op/views.py @@ -161,13 +161,9 @@ def edit_preferences(request): return form({'preferencesform':preferencesform,},'multi_op/form_preferences.html',request) -def navbar_user(request): +def navbar_user(): """View to display the app in user's dropdown in the navbar""" - return render_to_string('multi_op/navbar.html') - -def navbar_logout(request): - """View to display the app in user's dropdown in the navbar""" - return None + return ('topologie', render_to_string('multi_op/navbar.html')) def preferences(request): diff --git a/re2o/context_processors.py b/re2o/context_processors.py index 3ee39073..97f2d4f8 100644 --- a/re2o/context_processors.py +++ b/re2o/context_processors.py @@ -62,8 +62,8 @@ def context_optionnal_apps(request): """Fonction de context pour générer la navbar en fonction des apps optionnels""" optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] - optionnal_templates_navbar_user_list = [app.views.navbar_user(request) for app in optionnal_apps] - optionnal_templates_navbar_logout_list = [app.views.navbar_logout(request) for app in optionnal_apps] + optionnal_templates_navbar_user_list = [app.views.navbar_user() for app in optionnal_apps if hasattr(app.views, 'navbar_user')] + optionnal_templates_navbar_logout_list = [app.views.navbar_logout() for app in optionnal_apps if hasattr(app.views, 'navbar_logout')] return {'optionnal_templates_navbar_user_list':optionnal_templates_navbar_user_list, 'optionnal_templates_navbar_logout_list':optionnal_templates_navbar_logout_list} diff --git a/templates/base.html b/templates/base.html index f116c2be..122c7c3a 100644 --- a/templates/base.html +++ b/templates/base.html @@ -101,9 +101,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
  • {% trans "Manage the subscriptions" %}
  • {% acl_end %} - {% for template in optionnal_templates_navbar_user_list%} - {{ template }} - {% endfor %} + {% for app, template in optionnal_templates_navbar_user_list %} + {% if app != 'topologie' %} + {{ template }} + {% endif %} + {% endfor %} {% acl_end %} @@ -114,6 +116,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
  • {% trans "Switches" %}
  • {% trans "Access points" %}
  • {% trans "Rooms" %}
  • + {% for app, template in optionnal_templates_navbar_user_list %} + {% if app == 'topologie' %} + {{ template }} + {% endif %} + {% endfor %} {% acl_end %} diff --git a/tickets/templates/tickets/navbar.html b/tickets/templates/tickets/navbar.html index 3c4318f7..11473229 100644 --- a/tickets/templates/tickets/navbar.html +++ b/tickets/templates/tickets/navbar.html @@ -1,2 +1,2 @@ {% load i18n %} -
  • {% trans "Tickets" %}
  • +
  • {% trans "Tickets" %}
  • diff --git a/tickets/views.py b/tickets/views.py index 7fb96511..b16e4eea 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -186,12 +186,12 @@ def preferences(request): def contact(request): """View to display a contact address on the contact page used here to display a link to open a ticket""" - return render_to_string('tickets/contact.html') + return ('users', render_to_string('tickets/contact.html')) -def navbar_user(request): +def navbar_user(): """View to display the ticket link in thet user's dropdown in the navbar""" - return render_to_string('tickets/navbar.html') + return ('users', render_to_string('tickets/navbar.html')) -def navbar_logout(request): +def navbar_logout(): """View to display the ticket link to log out users""" return render_to_string('tickets/navbar_logout.html') From 745a30280c21307c96b17d8d805e1edddac75699 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Fri, 20 Sep 2019 21:45:48 +0200 Subject: [PATCH 163/228] Display connection state for luser --- users/templates/users/profil.html | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/users/templates/users/profil.html b/users/templates/users/profil.html index 00489017..bf3fd9e5 100644 --- a/users/templates/users/profil.html +++ b/users/templates/users/profil.html @@ -187,9 +187,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    {% trans "Room" %}
    - {{ users.room }} {% can_view_all Port %}{% if users.room.port_set.all %} / - {{ users.room.port_set.all|join:", " }} {% endif %}{% acl_end %} -
    + {{ users.room }} {% if users.room.port_set.all %}{% can_view_all Port %}/ + {{ users.room.port_set.all|join:", " }} {% acl_else %} + {% trans "Connected" %}{% acl_end %} + {% else %}{% if users.room %}{% trans "Pending connection..." %}{% endif %} + {% endif %} +
    @@ -222,7 +225,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if users.end_adhesion != None %}
    {{ users.end_adhesion }}
    {% else %} -
    {% trans "Not a member" %}
    +
    {% trans "not a member" %}
    {% endif %}
    From 2df79830b64285e15ce31eef17353748ac36c4bc Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Fri, 20 Sep 2019 23:03:44 +0200 Subject: [PATCH 164/228] An optional app can possibly not have a pannel pref --- preferences/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/preferences/views.py b/preferences/views.py index 9a5da84d..d27cdb4f 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -105,7 +105,7 @@ def display_options(request): document_template_list = DocumentTemplate.objects.order_by('name') optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] - optionnal_templates_list = [app.views.preferences(request) for app in optionnal_apps] + optionnal_templates_list = [app.views.preferences(request) for app in optionnal_apps if hasattr(app.views, 'preferences')] return form({ 'useroptions': useroptions, From dfe15ec23d3028870e6f2665795ec20f17b9c6f7 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sat, 21 Sep 2019 16:25:05 +0200 Subject: [PATCH 165/228] Button to remove port of a room --- multi_op/templates/multi_op/aff_room_state.html | 8 +++++++- multi_op/urls.py | 2 +- multi_op/views.py | 12 ++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/multi_op/templates/multi_op/aff_room_state.html b/multi_op/templates/multi_op/aff_room_state.html index de25171b..75ca027c 100644 --- a/multi_op/templates/multi_op/aff_room_state.html +++ b/multi_op/templates/multi_op/aff_room_state.html @@ -42,6 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Details" %} {% trans "End of subscription on" %} {% trans "Internet access" %} + {% trans "Action" %} {% for room in room_list %} @@ -51,7 +52,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if room.port_set.all %}AURORE{% else %}{% trans "Other operator" %}{% endif %} {% if room.adherent %}{{ room.adherent }}{% else %} {% trans "Aucun" %}{% endif %} {{ room.details }} - {% if room.adherent.is_adherent %}{{ room.adherent.end_adhesion }}{% else %}{% trans "Not a member" %}{% endif %} + {% if room.adherent.is_adherent %}{% else %}{% endif %}{% if room.adherent.end_adhesion %}{{ room.adherent.end_adhesion}}{% else %}{% trans "No member" %}{% endif %} {% if room.adherent.has_access == True %} {% trans "Active" %} @@ -59,6 +60,11 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Disabled" %} {% endif %} + + {% if room.port_set.all %} + + {% endif %} + {% endfor %} diff --git a/multi_op/urls.py b/multi_op/urls.py index 0dbb0ca8..866de712 100644 --- a/multi_op/urls.py +++ b/multi_op/urls.py @@ -34,5 +34,5 @@ urlpatterns = [ url(r'^(?P[0-9]+)$', views.aff_state_dormitory, name='aff-state-dormitory'), url(r'^pending-connection$', views.aff_pending_connection, name='aff-pending-connection'), url(r'^pending-disconnection$', views.aff_pending_disconnection, name='aff-pending-disconnection'), - # url(r'^multi_op/edit-preferences-multiop$', views.edit_preferences, name='edit-preferences-multiop'), + url(r'^disconnect-room/(?P[0-9]+)$', views.disconnect_room, name='disconnect-room'), ] diff --git a/multi_op/views.py b/multi_op/views.py index 75811a0d..7b94a158 100644 --- a/multi_op/views.py +++ b/multi_op/views.py @@ -142,6 +142,18 @@ def aff_pending_disconnection(request): ) +@login_required +@can_edit(Room) +def disconnect_room(request, room, roomid): + """Action of disconnecting a room""" + room.port_set.clear() + room.save() + messages.success(request,'Room %s disconnected' % room) + return redirect(reverse( + 'multi_op:aff-pending-disconnection' + )) + + def edit_preferences(request): """ View to edit the settings of the tickets """ From bed24b5c1c955d3d918ba682389870535f59a088 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sat, 21 Sep 2019 16:26:55 +0200 Subject: [PATCH 166/228] Unusefull stuff --- multi_op/views.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/multi_op/views.py b/multi_op/views.py index 7b94a158..7debd02e 100644 --- a/multi_op/views.py +++ b/multi_op/views.py @@ -154,34 +154,10 @@ def disconnect_room(request, room, roomid): )) -def edit_preferences(request): - """ View to edit the settings of the tickets """ - - preferences_instance, created = Preferences.objects.get_or_create(id=1) - preferencesform = EditPreferencesForm( - request.POST or None, - instance = preferences_instance,) - - if preferencesform.is_valid(): - if preferencesform.changed_data: - preferencesform.save() - messages.success(request,'Preferences updated') - return redirect(reverse('preferences:display-options',)) - else: - messages.error(request,'Formulaire Invalide') - return form({'preferencesform':preferencesform,},'multi_op/form_preferences.html',request) - return form({'preferencesform':preferencesform,},'multi_op/form_preferences.html',request) - - def navbar_user(): """View to display the app in user's dropdown in the navbar""" return ('topologie', render_to_string('multi_op/navbar.html')) -def preferences(request): - """ View to display the settings of the tickets in the preferences page""" - pref, created = Preferences.objects.get_or_create(id=1) - context = {'preferences':pref,'language':str(pref.LANGUES[pref.mail_language][1])} - return render_to_string('tickets/preferences.html', context=context, request=request, using=None) From c5f96fee62061cde6008351fb9c20ef02df92821 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 8 Oct 2019 18:27:09 +0200 Subject: [PATCH 167/228] =?UTF-8?q?Fix=20:=20autorise=20blank=20pour=20mes?= =?UTF-8?q?sage=20mail=20adh=C3=A9sion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0064_auto_20191008_1335.py | 25 +++++++++++++++++++ preferences/models.py | 12 +++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 preferences/migrations/0064_auto_20191008_1335.py diff --git a/preferences/migrations/0064_auto_20191008_1335.py b/preferences/migrations/0064_auto_20191008_1335.py new file mode 100644 index 00000000..a1bdb9fc --- /dev/null +++ b/preferences/migrations/0064_auto_20191008_1335.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-10-08 11:35 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0063_mandate'), + ] + + operations = [ + migrations.AlterField( + model_name='mailmessageoption', + name='welcome_mail_en', + field=models.TextField(blank=True, default='', help_text='Welcome email in English'), + ), + migrations.AlterField( + model_name='mailmessageoption', + name='welcome_mail_fr', + field=models.TextField(blank=True, default='', help_text='Welcome email in French'), + ), + ] diff --git a/preferences/models.py b/preferences/models.py index f09e63a7..c0bd1f89 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -616,8 +616,16 @@ def homeoption_post_save(**kwargs): class MailMessageOption(AclMixin, models.Model): """Reglages, mail de bienvenue et autre""" - welcome_mail_fr = models.TextField(default="", help_text=_("Welcome email in French")) - welcome_mail_en = models.TextField(default="", help_text=_("Welcome email in English")) + welcome_mail_fr = models.TextField( + default="", + blank=True, + help_text=_("Welcome email in French") + ) + welcome_mail_en = models.TextField( + default="", + blank=True, + help_text=_("Welcome email in English") + ) class Meta: permissions = ( From 144119c26adbdcbcd9d03db59bd6ddfa2113bfc7 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Thu, 10 Oct 2019 15:43:01 +0200 Subject: [PATCH 168/228] =?UTF-8?q?Fix=20:=20possibilit=C3=A9=20de=20mettr?= =?UTF-8?q?e=20plusieurs=20clefs=20radius=20sans=20crash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0065_auto_20191010_1227.py | 20 +++++++++++++++++++ preferences/models.py | 10 ++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 preferences/migrations/0065_auto_20191010_1227.py diff --git a/preferences/migrations/0065_auto_20191010_1227.py b/preferences/migrations/0065_auto_20191010_1227.py new file mode 100644 index 00000000..175dfd5b --- /dev/null +++ b/preferences/migrations/0065_auto_20191010_1227.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-10-10 10:27 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0064_auto_20191008_1335'), + ] + + operations = [ + migrations.AlterField( + model_name='radiuskey', + name='default_switch', + field=models.BooleanField(default=False, help_text='Default key for switches'), + ), + ] diff --git a/preferences/models.py b/preferences/models.py index c0bd1f89..f3c8fd7b 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -330,8 +330,7 @@ class RadiusKey(AclMixin, models.Model): help_text=_("Comment for this key") ) default_switch = models.BooleanField( - default=True, - unique=True, + default=False, help_text=_("Default key for switches") ) @@ -342,6 +341,13 @@ class RadiusKey(AclMixin, models.Model): verbose_name = _("RADIUS key") verbose_name_plural = _("RADIUS keys") + def clean(self): + """Clean model: + Check default switch is unique + """ + if RadiusKey.objects.filter(default_switch=True).count() > 1: + raise ValidationError(_("Default radiuskey for switchs already exist")) + def __str__(self): return _("RADIUS key ") + str(self.id) + " " + str(self.comment) From 58c120410a5f0c89f57d9c4c9455fa49a3d85834 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Thu, 10 Oct 2019 15:43:52 +0200 Subject: [PATCH 169/228] =?UTF-8?q?Fix=20:=20affichage=20des=20tickets,=20?= =?UTF-8?q?=C3=A9vite=20un=20crash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tickets/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tickets/views.py b/tickets/views.py index b16e4eea..e59c69a0 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -186,7 +186,7 @@ def preferences(request): def contact(request): """View to display a contact address on the contact page used here to display a link to open a ticket""" - return ('users', render_to_string('tickets/contact.html')) + return render_to_string('tickets/contact.html') def navbar_user(): """View to display the ticket link in thet user's dropdown in the navbar""" From 0b8cdb8e07a1a028056ae5db1af422ce8000904c Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Thu, 10 Oct 2019 17:55:59 +0200 Subject: [PATCH 170/228] =?UTF-8?q?Fix=20:=20Permet=20d'avoir=20plusieurs?= =?UTF-8?q?=20blocs=20de=20switchs=20ordonn=C3=A9s=20sur=20le=20m=C3=AAme?= =?UTF-8?q?=20sous-r=C3=A9seau=20(ex=20/24=20dans=20/16)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/serializers.py | 2 +- machines/models.py | 17 +++++++++++------ preferences/models.py | 2 +- topologie/models.py | 20 ++++++++++++++++++-- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/api/serializers.py b/api/serializers.py index eabcc73a..f925d2bd 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -824,7 +824,7 @@ class SwitchPortSerializer(serializers.ModelSerializer): fields = ('short_name', 'model', 'switchbay', 'ports', 'ipv4', 'ipv6', 'interfaces_subnet', 'interfaces6_subnet', 'automatic_provision', 'rest_enabled', 'web_management_enabled', 'get_radius_key_value', 'get_management_cred_value', - 'list_modules') + 'get_radius_servers', 'list_modules') # LOCAL EMAILS diff --git a/machines/models.py b/machines/models.py index c2012568..97881438 100644 --- a/machines/models.py +++ b/machines/models.py @@ -448,12 +448,17 @@ class IpType(RevMixin, AclMixin, models.Model): @cached_property def ip_net_full_info(self): """Renvoie les infos du network contenant du range""" - return { - 'network': str(self.ip_network.network), - 'netmask': str(self.ip_network.netmask), - 'broadcast': str(self.ip_network.broadcast), - 'netmask_cidr': str(self.ip_network.prefixlen), - } + if self.ip_network: + return { + 'network': str(self.ip_network.network), + 'netmask': str(self.ip_network.netmask), + 'broadcast': str(self.ip_network.broadcast), + 'netmask_cidr': str(self.ip_network.prefixlen), + 'vlan': str(self.vlan), + 'vlan_id': self.vlan.vlan_id + } + else: + return None @cached_property def complete_prefixv6(self): diff --git a/preferences/models.py b/preferences/models.py index f3c8fd7b..e52998cd 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -294,7 +294,7 @@ class OptionalTopologie(AclMixin, PreferencesModel): subnet = None subnet6 = None if self.switchs_ip_type: - subnet = self.switchs_ip_type.ip_set_full_info + subnet = self.switchs_ip_type.ip_net_full_info or self.switchs_ip_type.ip_set_full_info[0] subnet6 = self.switchs_ip_type.ip6_set_full_info return {'ntp_servers': return_ips_dict(ntp_servers), 'log_servers': return_ips_dict(log_servers), 'radius_servers': return_ips_dict(radius_servers), 'dhcp_servers': return_ips_dict(dhcp_servers), 'dns_recursive_servers': return_ips_dict(dns_recursive_servers), 'subnet': subnet, 'subnet6': subnet6} diff --git a/topologie/models.py b/topologie/models.py index c942c93b..0ed4b9dd 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -55,7 +55,13 @@ from preferences.models import ( RadiusKey, SwitchManagementCred ) -from machines.models import Machine, regen +from machines.models import ( + Machine, + regen, + Role, + MachineType, + Ipv6List +) from re2o.mixins import AclMixin, RevMixin @@ -321,6 +327,16 @@ class Switch(AclMixin, Machine): else: return None + @cached_property + def get_radius_servers_objects(self): + return Role.all_interfaces_for_roletype("radius-server").filter(machine_type__in=MachineType.objects.filter(interface__in=self.interface_set.all())) + + @cached_property + def get_radius_servers(self): + def return_ips_dict(interfaces): + return {'ipv4' : [str(interface.ipv4) for interface in interfaces], 'ipv6' : Ipv6List.objects.filter(interface__in=interfaces).values_list('ipv6', flat=True)} + return return_ips_dict(self.get_radius_servers_objects) + @cached_property def get_management_cred(self): """Retourne l'objet des creds de managament de ce switch""" @@ -362,7 +378,7 @@ class Switch(AclMixin, Machine): @cached_property def interfaces_subnet(self): """Return dict ip:subnet for all ip of the switch""" - return dict((str(interface.ipv4), interface.machine_type.ip_type.ip_set_full_info) for interface in self.interface_set.all()) + return dict((str(interface.ipv4), interface.machine_type.ip_type.ip_net_full_info or interface.machine_type.ip_type.ip_set_full_info[0]) for interface in self.interface_set.all()) @cached_property def interfaces6_subnet(self): From e38e30408784c6e92f226f2fe94a6195645d40c0 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Thu, 10 Oct 2019 18:06:38 +0200 Subject: [PATCH 171/228] Display legal notice --- re2o/templates/re2o/about.html | 23 +++++++++++++++++++++-- re2o/views.py | 10 +++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/re2o/templates/re2o/about.html b/re2o/templates/re2o/about.html index 2503246a..514fd4d3 100644 --- a/re2o/templates/re2o/about.html +++ b/re2o/templates/re2o/about.html @@ -29,8 +29,27 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block title %}{% trans "About Re2o" %}{% endblock %} {% block content %} -

    {% blocktrans %}About {{AssoName}}{% endblocktrans %}

    - {{ description | safe }} +

    {% trans "Legal notes" %}

    + +

    {% trans "Legal entity" %}

    +

    {{ option.name }}

    + +

    {% trans "Registered office" %}

    +

    {{ option.adresse1 }}

    +

    {{ option.adresse2 }}

    + +

    SIRET : {{ option.siret }}

    + +

    {% trans "Publication manager" %}

    +

    {{ president }} - {% trans "President of " %} {{ option.pseudo }}

    + +

    {% trans "General conditions of use" %}

    +

    {{ gtu }}

    + + {% if option.description %} +

    Extra informations

    +

    {{ option.description }}

    + {% endif %}

    {% trans "About Re2o" %}

    {% blocktrans trimmed %} diff --git a/re2o/views.py b/re2o/views.py index d443a84c..05aa5798 100644 --- a/re2o/views.py +++ b/re2o/views.py @@ -39,7 +39,9 @@ from preferences.models import ( Service, MailContact, AssoOption, - HomeOption + HomeOption, + GeneralOption, + Mandate ) from .contributors import CONTRIBUTORS @@ -77,6 +79,7 @@ def about_page(request): Fetch some info about the configuration of the project. If it can't get the info from the Git repository, fallback to default string """ option = AssoOption.objects.get() + general = GeneralOption.objects.get() git_info_contributors = CONTRIBUTORS try: git_repo = git.Repo(settings.BASE_DIR) @@ -98,8 +101,9 @@ def about_page(request): request, "re2o/about.html", { - 'description': option.description, - 'AssoName': option.name, + 'option': option, + 'gtu': general.GTU, + 'president': Mandate.get_mandate().president.get_full_name(), 'git_info_contributors': git_info_contributors, 'git_info_remote': git_info_remote, 'git_info_branch': git_info_branch, From aabacec83a518701b02fe3173f3464f65cb8ba00 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Thu, 10 Oct 2019 21:57:06 +0200 Subject: [PATCH 172/228] Filter safe for info asso --- re2o/templates/re2o/about.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/re2o/templates/re2o/about.html b/re2o/templates/re2o/about.html index 514fd4d3..c2a226e1 100644 --- a/re2o/templates/re2o/about.html +++ b/re2o/templates/re2o/about.html @@ -32,13 +32,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,

    {% trans "Legal notes" %}

    {% trans "Legal entity" %}

    -

    {{ option.name }}

    +

    {{ option.name | safe}}

    {% trans "Registered office" %}

    -

    {{ option.adresse1 }}

    -

    {{ option.adresse2 }}

    +

    {{ option.adresse1 | safe }}

    +

    {{ option.adresse2 | safe }}

    -

    SIRET : {{ option.siret }}

    +

    SIRET : {{ option.siret | safe }}

    {% trans "Publication manager" %}

    {{ president }} - {% trans "President of " %} {{ option.pseudo }}

    @@ -48,7 +48,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if option.description %}

    Extra informations

    -

    {{ option.description }}

    +

    {{ option.description | safe }}

    {% endif %}

    {% trans "About Re2o" %}

    From d51f1e126d5799dff6ec7cf0d65bdaa629824555 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Mon, 14 Oct 2019 23:43:36 +0200 Subject: [PATCH 173/228] =?UTF-8?q?Fix=20r=C3=A9ponses=20multiples,=20ne?= =?UTF-8?q?=20crash=20pas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- users/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/models.py b/users/models.py index 69348c17..a168eb51 100755 --- a/users/models.py +++ b/users/models.py @@ -768,7 +768,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def autoregister_machine(self, mac_address, nas_type): """ Fonction appellée par freeradius. Enregistre la mac pour une machine inconnue sur le compte de l'user""" - allowed, _message = Machine.can_create(self, self.id) + allowed, _message, _rights = Machine.can_create(self, self.id) if not allowed: return False, _("Maximum number of registered machines reached.") if not nas_type: From 47e67c3a40143b298f3747caef8f27f60df4a2fc Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Mon, 14 Oct 2019 23:47:34 +0200 Subject: [PATCH 174/228] Retourne au moins l'interface principale du switch --- topologie/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topologie/models.py b/topologie/models.py index 0ed4b9dd..093907df 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -307,7 +307,7 @@ class Switch(AclMixin, Machine): It must the the management interface for that device""" switch_iptype = OptionalTopologie.get_cached_value('switchs_ip_type') if switch_iptype: - return self.interface_set.filter(machine_type__ip_type=switch_iptype).first() + return self.interface_set.filter(machine_type__ip_type=switch_iptype).first() or self.interface_set.first() return self.interface_set.first() @cached_property From aab6fa2ba06fbdda3f8703bffb370c0001fc3d3b Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Wed, 2 Oct 2019 22:48:33 +0200 Subject: [PATCH 175/228] Fix #212 --- machines/forms.py | 16 ++++---- .../migrations/0103_auto_20191002_2222.py | 37 +++++++++++++++++++ .../migrations/0104_auto_20191002_2231.py | 19 ++++++++++ machines/models.py | 32 +++++++++++++++- machines/templates/machines/aff_alias.html | 2 + machines/templates/machines/aff_mx.html | 2 + machines/templates/machines/aff_ns.html | 2 + machines/templates/machines/aff_txt.html | 2 + .../0064_optionalmachine_default_dns_ttl.py | 20 ++++++++++ preferences/models.py | 6 ++- .../preferences/display_preferences.html | 6 ++- 11 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 machines/migrations/0103_auto_20191002_2222.py create mode 100644 machines/migrations/0104_auto_20191002_2231.py create mode 100644 preferences/migrations/0064_optionalmachine_default_dns_ttl.py diff --git a/machines/forms.py b/machines/forms.py index 6a9f287d..b85fd967 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -135,16 +135,16 @@ class AddInterfaceForm(EditInterfaceForm): fields = ['machine_type', 'ipv4', 'mac_address', 'details'] -class AliasForm(FormRevMixin, ModelForm): +class AliasForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Ajout d'un alias (et edition), CNAME, contenant nom et extension""" class Meta: model = Domain - fields = ['name', 'extension'] + fields = ['name', 'extension', 'ttl'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) - user = kwargs.pop('user') + user = kwargs['user'] super(AliasForm, self).__init__(*args, prefix=prefix, **kwargs) can_use_all, _reason, _permissions = Extension.can_use_all(user) if not can_use_all: @@ -153,16 +153,16 @@ class AliasForm(FormRevMixin, ModelForm): ) -class DomainForm(FormRevMixin, ModelForm): +class DomainForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Ajout et edition d'un enregistrement de nom, relié à interface""" class Meta: model = Domain - fields = ['name'] + fields = ['name', 'ttl'] def __init__(self, *args, **kwargs): if 'user' in kwargs: - user = kwargs.pop('user') + user = kwargs['user'] initial = kwargs.get('initial', {}) initial['name'] = user.get_next_domain_name() kwargs['initial'] = initial @@ -339,7 +339,7 @@ class MxForm(FormRevMixin, ModelForm): class Meta: model = Mx - fields = ['zone', 'priority', 'name'] + fields = ['zone', 'priority', 'name', 'ttl'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) @@ -373,7 +373,7 @@ class NsForm(FormRevMixin, ModelForm): class Meta: model = Ns - fields = ['zone', 'ns'] + fields = ['zone', 'ns', 'ttl'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) diff --git a/machines/migrations/0103_auto_20191002_2222.py b/machines/migrations/0103_auto_20191002_2222.py new file mode 100644 index 00000000..ef0bc830 --- /dev/null +++ b/machines/migrations/0103_auto_20191002_2222.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-10-02 20:22 +from __future__ import unicode_literals + +from django.db import migrations, models +import machines.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0102_auto_20190303_1611'), + ('preferences', '0064_optionalmachine_default_dns_ttl'), + ] + + operations = [ + migrations.AddField( + model_name='domain', + name='ttl', + field=models.PositiveIntegerField(default=machines.models.get_default_ttl, verbose_name='Time To Live (TTL)'), + ), + migrations.AddField( + model_name='mx', + name='ttl', + field=models.PositiveIntegerField(default=172800, verbose_name='Time To Live (TTL)'), + ), + migrations.AddField( + model_name='ns', + name='ttl', + field=models.PositiveIntegerField(default=172800, verbose_name='Time To Live (TTL)'), + ), + migrations.AddField( + model_name='txt', + name='ttl', + field=models.PositiveIntegerField(default=172800, verbose_name='Time To Live (TTL)'), + ), + ] diff --git a/machines/migrations/0104_auto_20191002_2231.py b/machines/migrations/0104_auto_20191002_2231.py new file mode 100644 index 00000000..344bddb7 --- /dev/null +++ b/machines/migrations/0104_auto_20191002_2231.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-10-02 20:31 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0103_auto_20191002_2222'), + ] + + operations = [ + migrations.AlterModelOptions( + name='domain', + options={'permissions': (('view_domain', 'Can view a domain object'), ('change_ttl', 'Can change TTL of a domain object')), 'verbose_name': 'domain', 'verbose_name_plural': 'domains'}, + ), + ] diff --git a/machines/models.py b/machines/models.py index 97881438..7b3c0dab 100644 --- a/machines/models.py +++ b/machines/models.py @@ -834,6 +834,10 @@ class Mx(RevMixin, AclMixin, models.Model): zone = models.ForeignKey('Extension', on_delete=models.PROTECT) priority = models.PositiveIntegerField() name = models.ForeignKey('Domain', on_delete=models.PROTECT) + ttl = models.PositiveIntegerField( + verbose_name=_("Time To Live (TTL)"), + default=172800, # 2 days + ) class Meta: permissions = ( @@ -859,6 +863,10 @@ class Ns(RevMixin, AclMixin, models.Model): """Liste des enregistrements name servers par zone considéérée""" zone = models.ForeignKey('Extension', on_delete=models.PROTECT) ns = models.ForeignKey('Domain', on_delete=models.PROTECT) + ttl = models.PositiveIntegerField( + verbose_name=_("Time To Live (TTL)"), + default=172800, # 2 days + ) class Meta: permissions = ( @@ -881,6 +889,10 @@ class Txt(RevMixin, AclMixin, models.Model): zone = models.ForeignKey('Extension', on_delete=models.PROTECT) field1 = models.CharField(max_length=255) field2 = models.TextField(max_length=2047) + ttl = models.PositiveIntegerField( + verbose_name=_("Time To Live (TTL)"), + default=172800, # 2 days + ) class Meta: permissions = ( @@ -1544,7 +1556,11 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): return str(self.ipv6) -class Domain(RevMixin, AclMixin, models.Model): +def get_default_ttl(): + return preferences.models.OptionalMachine.get_cached_value('default_dns_ttl') + + +class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, 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""" @@ -1566,11 +1582,16 @@ class Domain(RevMixin, AclMixin, models.Model): blank=True, related_name='related_domain' ) + ttl = models.PositiveIntegerField( + verbose_name=_("Time To Live (TTL)"), + default=get_default_ttl + ) class Meta: unique_together = (("name", "extension"),) permissions = ( ("view_domain", _("Can view a domain object")), + ("change_ttl", _("Can change TTL of a domain object")), ) verbose_name = _("domain") verbose_name_plural = _("domains") @@ -1728,6 +1749,15 @@ class Domain(RevMixin, AclMixin, models.Model): ) return True, None, None + @staticmethod + def can_change_ttl(user_request, *_args, **_kwargs): + can = user_request.has_perm('machines.change_ttl') + return ( + can, + _("You don't have the right to change the domain's TTL.") if not can else None, + ('machines.change_ttl',) + ) + def __str__(self): return str(self.name) + str(self.extension) diff --git a/machines/templates/machines/aff_alias.html b/machines/templates/machines/aff_alias.html index 15b765c9..8fe7260c 100644 --- a/machines/templates/machines/aff_alias.html +++ b/machines/templates/machines/aff_alias.html @@ -30,12 +30,14 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Aliases" %} + {% trans "TTL" %} {% for alias in alias_list %} {{ alias }} + {{ alias.ttl }} {% can_edit alias %} {% include 'buttons/edit.html' with href='machines:edit-alias' id=alias.id %} diff --git a/machines/templates/machines/aff_mx.html b/machines/templates/machines/aff_mx.html index 1393423d..f6fe5fd8 100644 --- a/machines/templates/machines/aff_mx.html +++ b/machines/templates/machines/aff_mx.html @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Concerned zone" %} {% trans "Priority" %} {% trans "Record" %} + {% trans "TTL" %} @@ -40,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ mx.zone }} {{ mx.priority }} {{ mx.name }} + {{ mx.ttl }} {% can_edit mx %} {% include 'buttons/edit.html' with href='machines:edit-mx' id=mx.id %} diff --git a/machines/templates/machines/aff_ns.html b/machines/templates/machines/aff_ns.html index 97859cfd..96534f8a 100644 --- a/machines/templates/machines/aff_ns.html +++ b/machines/templates/machines/aff_ns.html @@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Concerned zone" %} {% trans "Authoritarian interface for the concerned zone" %} + {% trans "TTL" %} @@ -38,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ ns.zone }} {{ ns.ns }} + {{ ns.ttl }} {% can_edit ns %} {% include 'buttons/edit.html' with href='machines:edit-ns' id=ns.id %} diff --git a/machines/templates/machines/aff_txt.html b/machines/templates/machines/aff_txt.html index ca0988d0..bb140ce8 100644 --- a/machines/templates/machines/aff_txt.html +++ b/machines/templates/machines/aff_txt.html @@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Concerned zone" %} {% trans "Record" %} + {% trans "TTL" %} @@ -38,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ txt.zone }} {{ txt.dns_entry }} + {{ txt.ttl }} {% can_edit txt %} {% include 'buttons/edit.html' with href='machines:edit-txt' id=txt.id %} diff --git a/preferences/migrations/0064_optionalmachine_default_dns_ttl.py b/preferences/migrations/0064_optionalmachine_default_dns_ttl.py new file mode 100644 index 00000000..f87cafca --- /dev/null +++ b/preferences/migrations/0064_optionalmachine_default_dns_ttl.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-10-02 20:22 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0063_mandate'), + ] + + operations = [ + migrations.AddField( + model_name='optionalmachine', + name='default_dns_ttl', + field=models.PositiveIntegerField(default=172800, verbose_name='Default Time To Live (TTL) for CNAME, A and AAA records.'), + ), + ] diff --git a/preferences/models.py b/preferences/models.py index e52998cd..b7153e72 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -173,6 +173,10 @@ class OptionalMachine(AclMixin, PreferencesModel): create_machine = models.BooleanField( default=True ) + default_dns_ttl = models.PositiveIntegerField( + verbose_name=_("Default Time To Live (TTL) for CNAME, A and AAA records."), + default=172800, # 2 days + ) @cached_property def ipv6(self): @@ -545,7 +549,7 @@ class Mandate(RevMixin, AclMixin, models.Model): def is_over(self): return self.end_date is None - + def __str__(self): return str(self.president) + ' ' + str(self.start_date.year) diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index ff186f11..fcc9064f 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -177,10 +177,12 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Maximum number of DNS aliases allowed for a standard user" %} {{ machineoptions.max_lambdauser_aliases }} - {% trans "IPv6 support" %} - {{ machineoptions.ipv6_mode }} + {% trans "Default Time To Live (TTL) for CNAME, A and AAA records." %} + {{ machineoptions.default_dns_ttl }} + {% trans "IPv6 support" %} + {{ machineoptions.ipv6_mode }} {% trans "Creation of machines" %} {{ machineoptions.create_machine|tick }} From 13a06c1a67ec659995a05d0af9f8ff5f89f733e1 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Wed, 2 Oct 2019 23:53:27 +0200 Subject: [PATCH 176/228] TTL for DNAMEs --- machines/migrations/0105_dname_ttl.py | 20 ++++++++++++++++++++ machines/models.py | 4 ++++ machines/templates/machines/aff_dname.html | 2 ++ 3 files changed, 26 insertions(+) create mode 100644 machines/migrations/0105_dname_ttl.py diff --git a/machines/migrations/0105_dname_ttl.py b/machines/migrations/0105_dname_ttl.py new file mode 100644 index 00000000..d3c38073 --- /dev/null +++ b/machines/migrations/0105_dname_ttl.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-10-02 21:47 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0104_auto_20191002_2231'), + ] + + operations = [ + migrations.AddField( + model_name='dname', + name='ttl', + field=models.PositiveIntegerField(default=172800, verbose_name='Time To Live (TTL)'), + ), + ] diff --git a/machines/models.py b/machines/models.py index 7b3c0dab..708dd8c9 100644 --- a/machines/models.py +++ b/machines/models.py @@ -915,6 +915,10 @@ class DName(RevMixin, AclMixin, models.Model): """A DNAME entry for the DNS.""" zone = models.ForeignKey('Extension', on_delete=models.PROTECT) alias = models.CharField(max_length=255) + ttl = models.PositiveIntegerField( + verbose_name=_("Time To Live (TTL)"), + default=172800, # 2 days + ) class Meta: permissions = ( diff --git a/machines/templates/machines/aff_dname.html b/machines/templates/machines/aff_dname.html index 6d07a7bc..4073a388 100644 --- a/machines/templates/machines/aff_dname.html +++ b/machines/templates/machines/aff_dname.html @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Target zone" %} {% trans "Record" %} + {% trans "TTL" %} @@ -36,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ dname.zone }} {{ dname.dns_entry }} + {{ dname.ttl }} {% can_edit dname %} {% include 'buttons/edit.html' with href='machines:edit-dname' id=dname.id %} From 48ec3d353efd719e1343f1bf88e07b60a0d73e85 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sat, 12 Oct 2019 17:22:51 +0200 Subject: [PATCH 177/228] default ttl to 0 --- machines/migrations/0103_auto_20191002_2222.py | 4 ++-- machines/models.py | 7 ++----- ..._dns_ttl.py => 0066_optionalmachine_default_dns_ttl.py} | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) rename preferences/migrations/{0064_optionalmachine_default_dns_ttl.py => 0066_optionalmachine_default_dns_ttl.py} (90%) diff --git a/machines/migrations/0103_auto_20191002_2222.py b/machines/migrations/0103_auto_20191002_2222.py index ef0bc830..43adac74 100644 --- a/machines/migrations/0103_auto_20191002_2222.py +++ b/machines/migrations/0103_auto_20191002_2222.py @@ -10,14 +10,14 @@ class Migration(migrations.Migration): dependencies = [ ('machines', '0102_auto_20190303_1611'), - ('preferences', '0064_optionalmachine_default_dns_ttl'), + ('preferences', '0066_optionalmachine_default_dns_ttl'), ] operations = [ migrations.AddField( model_name='domain', name='ttl', - field=models.PositiveIntegerField(default=machines.models.get_default_ttl, verbose_name='Time To Live (TTL)'), + field=models.PositiveIntegerField(default=0, verbose_name='Time To Live (TTL)'), ), migrations.AddField( model_name='mx', diff --git a/machines/models.py b/machines/models.py index 708dd8c9..ca881033 100644 --- a/machines/models.py +++ b/machines/models.py @@ -1560,10 +1560,6 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): return str(self.ipv6) -def get_default_ttl(): - return preferences.models.OptionalMachine.get_cached_value('default_dns_ttl') - - class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, 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 @@ -1588,7 +1584,8 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ) ttl = models.PositiveIntegerField( verbose_name=_("Time To Live (TTL)"), - default=get_default_ttl + default=0 # 0 means that the re2o-service for DNS should retrieve the + # default TTL ) class Meta: diff --git a/preferences/migrations/0064_optionalmachine_default_dns_ttl.py b/preferences/migrations/0066_optionalmachine_default_dns_ttl.py similarity index 90% rename from preferences/migrations/0064_optionalmachine_default_dns_ttl.py rename to preferences/migrations/0066_optionalmachine_default_dns_ttl.py index f87cafca..47e3519e 100644 --- a/preferences/migrations/0064_optionalmachine_default_dns_ttl.py +++ b/preferences/migrations/0066_optionalmachine_default_dns_ttl.py @@ -8,7 +8,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('preferences', '0063_mandate'), + ('preferences', '0065_auto_20191010_1227'), ] operations = [ From 6a590570c55c03b488d1439bc3f732f1831a2587 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 15 Oct 2019 00:17:38 +0200 Subject: [PATCH 178/228] Fix delete_set form --- re2o/acl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/re2o/acl.py b/re2o/acl.py index cf831a37..b36fd48c 100644 --- a/re2o/acl.py +++ b/re2o/acl.py @@ -255,7 +255,7 @@ def can_delete_set(model): all_objects = model.objects.all() instances_id = [] for instance in all_objects: - can, _msg = instance.can_delete(request.user) + can, _msg, _reason = instance.can_delete(request.user) if can: instances_id.append(instance.id) instances = model.objects.filter(id__in=instances_id) From 42f65bea6a0d7953ed38af2d6a6a12d37bbd5b35 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Thu, 17 Oct 2019 20:20:19 +0200 Subject: [PATCH 179/228] Fix DomainForm usage. --- machines/views.py | 5 +++-- topologie/views.py | 14 +++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/machines/views.py b/machines/views.py index a9bbd215..34f63a59 100644 --- a/machines/views.py +++ b/machines/views.py @@ -292,7 +292,8 @@ def edit_interface(request, interface_instance, **_kwargs): ) domain_form = DomainForm( request.POST or None, - instance=interface_instance.domain + instance=interface_instance.domain, + user=request.user ) if (machine_form.is_valid() and interface_form.is_valid() and @@ -349,7 +350,7 @@ def new_interface(request, machine, **_kwargs): """ Ajoute une interface et son domain associé à une machine existante""" interface_form = AddInterfaceForm(request.POST or None, user=request.user) - domain_form = DomainForm(request.POST or None) + domain_form = DomainForm(request.POST or None, user=request.user) if interface_form.is_valid(): new_interface_obj = interface_form.save(commit=False) domain_form.instance.interface_parent = new_interface_obj diff --git a/topologie/views.py b/topologie/views.py index 47621c04..e900387f 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -69,7 +69,7 @@ from machines.forms import ( from machines.views import generate_ipv4_mbf_param from machines.models import ( Interface, - Service_link, + Service_link, Vlan ) from preferences.models import AssoOption, GeneralOption @@ -524,6 +524,7 @@ def new_switch(request): ) domain = DomainForm( request.POST or None, + user=request.user ) if switch.is_valid() and interface.is_valid(): user = AssoOption.get_cached_value('utilisateur_asso') @@ -570,7 +571,7 @@ def create_ports(request, switchid): except Switch.DoesNotExist: messages.error(request, _("Nonexistent switch.")) return redirect(reverse('topologie:index')) - + first_port = getattr(switch.ports.order_by('port').first(), 'port', 1) last_port = switch.number + first_port - 1 port_form = CreatePortsForm( @@ -614,7 +615,8 @@ def edit_switch(request, switch, switchid): ) domain_form = DomainForm( request.POST or None, - instance=switch.interface_set.first().domain + instance=switch.interface_set.first().domain, + domain=request.user ) if switch_form.is_valid() and interface_form.is_valid(): new_switch_obj = switch_form.save(commit=False) @@ -659,6 +661,7 @@ def new_ap(request): ) domain = DomainForm( request.POST or None, + user=request.user ) if ap.is_valid() and interface.is_valid(): user = AssoOption.get_cached_value('utilisateur_asso') @@ -713,7 +716,8 @@ def edit_ap(request, ap, **_kwargs): ) domain_form = DomainForm( request.POST or None, - instance=ap.interface_set.first().domain + instance=ap.interface_set.first().domain, + user=request.user ) if ap_form.is_valid() and interface_form.is_valid(): user = AssoOption.get_cached_value('utilisateur_asso') @@ -1279,7 +1283,7 @@ def make_machine_graph(): .select_related('ipv4__ip_type__extension') .select_related('domain__extension') ) - ))) + ))) detected = [] for building in Building.objects.all(): # Visit all buildings From 1385e8f4580fbc351551dea174fdf531e8bcefab Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Mon, 21 Oct 2019 16:33:50 +0200 Subject: [PATCH 180/228] Prevent crash with tls 1.3 and ubuntu (see https://github.com/FreeRADIUS/freeradius-server/issues/2385 ) --- freeradius_utils/freeradius3/mods-enabled/eap | 109 +++++++++++++----- 1 file changed, 81 insertions(+), 28 deletions(-) diff --git a/freeradius_utils/freeradius3/mods-enabled/eap b/freeradius_utils/freeradius3/mods-enabled/eap index 72f72955..8213bdae 100644 --- a/freeradius_utils/freeradius3/mods-enabled/eap +++ b/freeradius_utils/freeradius3/mods-enabled/eap @@ -2,7 +2,7 @@ ## ## eap.conf -- Configuration for EAP types (PEAP, TTLS, etc.) ## -## $Id: 0e8d5caef5ad09dfa6acb14c5d475bae55cf4b27 $ +## $Id: f67cbdbff9b6560cec9f68da1adb82b59723d2ef $ ####################################################################### # @@ -285,6 +285,10 @@ eap { ca_path = ${cadir} + # Accept an expired Certificate Revocation List + # +# allow_expired_crl = no + # # If check_cert_issuer is set, the value will # be checked against the DN of the issuer in @@ -292,10 +296,10 @@ eap { # match, the certificate verification will fail, # rejecting the user. # - # In 2.1.10 and later, this check can be done - # more generally by checking the value of the - # TLS-Client-Cert-Issuer attribute. This check - # can be done via any mechanism you choose. + # This check can be done more generally by checking + # the value of the TLS-Client-Cert-Issuer attribute. + # This check can be done via any mechanism you + # choose. # # check_cert_issuer = "/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd" @@ -325,16 +329,42 @@ eap { # cipher_list = "DEFAULT" - # Work-arounds for OpenSSL nonsense - # OpenSSL 1.0.1f and 1.0.1g do not calculate - # the EAP keys correctly. The fix is to upgrade - # OpenSSL, or disable TLS 1.2 here. - # - # For EAP-FAST, this MUST be set to "yes". - # -# disable_tlsv1_2 = no + # If enabled, OpenSSL will use server cipher list + # (possibly defined by cipher_list option above) + # for choosing right cipher suite rather than + # using client-specified list which is OpenSSl default + # behavior. Having it set to yes is a current best practice + # for TLS + cipher_server_preference = no # + # You can selectively disable TLS versions for + # compatability with old client devices. + # + # If your system has OpenSSL 1.1.0 or greater, do NOT + # use these. Instead, set tls_min_version and + # tls_max_version. + # +# disable_tlsv1_2 = no +# disable_tlsv1_1 = no +# disable_tlsv1 = no + + # + # Set min / max TLS version. Mainly for Debian + # "trusty", which disables older versions of TLS, and + # requires the application to manually enable them. + # + # If you are running Debian trusty, you should set + # these options, otherwise older clients will not be + # able to connect. + # + # Allowed values are "1.0", "1.1", and "1.2". + # + # The values must be in quotes. + # + tls_min_version = "1.0" + tls_max_version = "1.2" + # # Elliptical cryptography configuration @@ -374,6 +404,12 @@ eap { # Enable it. The default is "no". Deleting the entire "cache" # subsection also disables caching. # + # As of version 3.0.14, the session cache requires the use + # of the "name" and "persist_dir" configuration items, below. + # + # The internal OpenSSL session cache has been permanently + # disabled. + # # You can disallow resumption for a particular user by adding the # following attribute to the control item list: # @@ -388,16 +424,7 @@ eap { # Lifetime of the cached entries, in hours. The sessions will be # deleted/invalidated after this time. # - lifetime = 24 # hours - - # - # The maximum number of entries in the - # cache. Set to "0" for "infinite". - # - # This could be set to the number of users - # who are logged in... which can be a LOT. - # - max_entries = 255 + lifetime = 1 # hours # # Internal "name" of the session cache. Used to @@ -416,6 +443,11 @@ eap { # state and the cached VPs. This will persist session # across server restarts. # + # The default directory is ${logdir}, for historical + # reasons. You should ${db_dir} instead. And check + # the value of db_dir in the main radiusd.conf file. + # It should not point to ${raddb} + # # The server will need write perms, and the directory # should be secured from anyone else. You might want # a script to remove old files from here periodically: @@ -663,6 +695,10 @@ eap { # # in the control items for a request. # + # Note that the majority of supplicants do not support using a + # client certificate with EAP-TTLS, so this option is unlikely + # to be usable for most people. + # # require_client_cert = yes } @@ -789,6 +825,10 @@ eap { # # in the control items for a request. # + # Note that the majority of supplicants do not support using a + # client certificate with PEAP, so this option is unlikely to + # be usable for most people. + # # require_client_cert = yes } @@ -839,13 +879,26 @@ eap { # fast { # Point to the common TLS configuration # - # cipher_list though must include "ADH" for anonymous provisioning. - # This is not as straight forward as appending "ADH" alongside - # "DEFAULT" as "DEFAULT" contains "!aNULL" so instead it is - # recommended "ALL:!EXPORT:!eNULL:!SSLv2" is used - # # tls = tls-common + # + # If 'cipher_list' is set here, it will over-ride the + # 'cipher_list' configuration from the 'tls-common' + # configuration. The EAP-FAST module has it's own + # over-ride for 'cipher_list' because the + # specifications mandata a different set of ciphers + # than are used by the other EAP methods. + # + # cipher_list though must include "ADH" for anonymous provisioning. + # This is not as straight forward as appending "ADH" alongside + # "DEFAULT" as "DEFAULT" contains "!aNULL" so instead it is + # recommended "ALL:!EXPORT:!eNULL:!SSLv2" is used + # + # Note - for OpenSSL 1.1.0 and above you may need + # to add ":@SECLEVEL=0" + # +# cipher_list = "ALL:!EXPORT:!eNULL:!SSLv2" + # PAC lifetime in seconds (default: seven days) # # pac_lifetime = 604800 From 9c28662058d3ad82c525d3cf07b44b76694f6e43 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Tue, 29 Oct 2019 17:49:23 +0100 Subject: [PATCH 181/228] Fix display affichage date summary --- logs/templates/logs/aff_summary.html | 10 +++++----- logs/views.py | 4 +--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/logs/templates/logs/aff_summary.html b/logs/templates/logs/aff_summary.html index cf1725b0..7205bc6a 100644 --- a/logs/templates/logs/aff_summary.html +++ b/logs/templates/logs/aff_summary.html @@ -43,7 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% for v in versions_list %} {% if v.version.content_type.model == 'ban' %} - {{ v.datetime }} + {{ v.datetime|date:"j/m/y H:i:s" }} {% blocktrans with username=v.username %}{{ username }} has banned{% endblocktrans %} {{ v.version.object.user.get_username }} @@ -66,7 +66,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% elif v.version.content_type.model == 'whitelist' %} - {{ v.datetime }} + {{ v.datetime|date:"j/m/y H:i:s" }} {% blocktrans with username=v.username %}{{ username }} has graciously authorised{% endblocktrans %} {{ v.version.object.user.get_username }} @@ -89,7 +89,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% elif v.version.content_type.model == 'user' %} - {{ v.datetime }} + {{ v.datetime|date:"j/m/y H:i:s" }} {% blocktrans with username=v.username %}{{ username }} has updated{% endblocktrans %} {{ v.version.object.get_username }} @@ -108,7 +108,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% elif v.version.content_type.model == 'vente' %} - {{ v.datetime }} + {{ v.datetime|date:"j/m/y H:i:s" }} {% blocktrans with username=v.username number=v.version.object.number name=v.version.object.name %}{{ username }} has sold {{ number }}x {{ name }}{% endblocktrans %} {% with invoice=v.version.object.facture %} @@ -132,7 +132,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% elif v.version.content_type.model == 'interface' %} - {{ v.datetime }} + {{ v.datetime|date:"j/m/y H:i:s" }} {% blocktrans with username=v.username %}{{ username }} has edited an interface of{% endblocktrans %} {{ v.version.object.machine.user.get_username }} diff --git a/logs/views.py b/logs/views.py index a3c8fe47..9e4629a4 100644 --- a/logs/views.py +++ b/logs/views.py @@ -148,9 +148,7 @@ def index(request): versions.object_list[i] = { 'rev_id': version.revision.id, 'comment': version.revision.comment, - 'datetime': version.revision.date_created.strftime( - '%d/%m/%y %H:%M:%S' - ), + 'datetime': version.revision.date_created, 'username': version.revision.user.get_username() if version.revision.user else '?', From 804d5a711bffce9b08ccbf4036ac8f157c07f7c9 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Thu, 31 Oct 2019 21:54:25 +0100 Subject: [PATCH 182/228] Fix typo in view edit_switch --- topologie/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topologie/views.py b/topologie/views.py index e900387f..60ebc272 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -616,7 +616,7 @@ def edit_switch(request, switch, switchid): domain_form = DomainForm( request.POST or None, instance=switch.interface_set.first().domain, - domain=request.user + user=request.user ) if switch_form.is_valid() and interface_form.is_valid(): new_switch_obj = switch_form.save(commit=False) From c76f32cf260cd6fd379d24c3aa3e5163c9c9204c Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Wed, 2 Oct 2019 23:42:54 +0200 Subject: [PATCH 183/228] Fix #222 --- .../migrations/0040_auto_20191002_2335.py | 26 +++++++++++++++++++ cotisations/models.py | 23 +++++++++++++--- .../templates/cotisations/aff_article.html | 2 ++ cotisations/views.py | 1 + 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 cotisations/migrations/0040_auto_20191002_2335.py diff --git a/cotisations/migrations/0040_auto_20191002_2335.py b/cotisations/migrations/0040_auto_20191002_2335.py new file mode 100644 index 00000000..56c99f69 --- /dev/null +++ b/cotisations/migrations/0040_auto_20191002_2335.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-10-02 21:35 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cotisations', '0039_freepayment'), + ] + + operations = [ + migrations.AddField( + model_name='article', + name='duration_days', + field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='duration (in days, will be added to duration in months)'), + ), + migrations.AddField( + model_name='vente', + name='duration_days', + field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='duration (in days, will be added to duration in months)'), + ), + ] diff --git a/cotisations/models.py b/cotisations/models.py index 3cb64ec3..b9d01b8d 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -460,6 +460,12 @@ class Vente(RevMixin, AclMixin, models.Model): null=True, verbose_name=_("duration (in months)") ) + duration_days = models.PositiveIntegerField( + blank=True, + null=True, + validators=[MinValueValidator(0)], + verbose_name=_("duration (in days, will be added to duration in months)") + ) # TODO : this field is not needed if you use Article ForeignKey type_cotisation = models.CharField( choices=COTISATION_TYPE, @@ -492,7 +498,9 @@ class Vente(RevMixin, AclMixin, models.Model): if hasattr(self, 'cotisation'): cotisation = self.cotisation cotisation.date_end = cotisation.date_start + relativedelta( - months=self.duration*self.number) + months=(self.duration or 0)*self.number, + days=(self.duration_days or 0)*self.number, + ) return def create_cotis(self, date_start=False): @@ -529,7 +537,8 @@ class Vente(RevMixin, AclMixin, models.Model): date_max = max(end_cotisation, date_start) cotisation.date_start = date_max cotisation.date_end = cotisation.date_start + relativedelta( - months=self.duration*self.number + months=(self.duration or 0)*self.number, + days=(self.duration_days or 0)*self.number, ) return @@ -540,7 +549,7 @@ class Vente(RevMixin, AclMixin, models.Model): effect on the user's cotisation """ # Checking that if a cotisation is specified, there is also a duration - if self.type_cotisation and not self.duration: + if self.type_cotisation and not (self.duration or self.duration_days): raise ValidationError( _("Duration must be specified for a subscription.") ) @@ -695,6 +704,12 @@ class Article(RevMixin, AclMixin, models.Model): validators=[MinValueValidator(0)], verbose_name=_("duration (in months)") ) + duration_days = models.PositiveIntegerField( + blank=True, + null=True, + validators=[MinValueValidator(0)], + verbose_name=_("duration (in days, will be added to duration in months)") + ) type_user = models.CharField( choices=USER_TYPES, default='All', @@ -729,7 +744,7 @@ class Article(RevMixin, AclMixin, models.Model): raise ValidationError( _("Balance is a reserved article name.") ) - if self.type_cotisation and not self.duration: + if self.type_cotisation and not (self.duration or self.duration_days): raise ValidationError( _("Duration must be specified for a subscription.") ) diff --git a/cotisations/templates/cotisations/aff_article.html b/cotisations/templates/cotisations/aff_article.html index df187abb..7ead24dc 100644 --- a/cotisations/templates/cotisations/aff_article.html +++ b/cotisations/templates/cotisations/aff_article.html @@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Price" %} {% trans "Subscription type" %} {% trans "Duration (in months)" %} + {% trans "Duration (in days)" %} {% trans "Concerned users" %} {% trans "Available for everyone" %} @@ -45,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ article.prix }} {{ article.type_cotisation }} {{ article.duration }} + {{ article.duration_days }} {{ article.type_user }} {{ article.available_for_everyone | tick }} diff --git a/cotisations/views.py b/cotisations/views.py index 437d5df1..2a262704 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -139,6 +139,7 @@ def new_facture(request, user, userid): prix=article.prix, type_cotisation=article.type_cotisation, duration=article.duration, + duration_days=article.duration_days, number=quantity ) purchases.append(new_purchase) From e0a65e4d044199d414ae2606813fe08fedf4420a Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sun, 3 Nov 2019 21:46:18 +0100 Subject: [PATCH 184/228] Setup tests for Vente model. --- .../migrations/0041_auto_20191103_2131.py | 41 ++++++++++++++++ cotisations/payment_methods/balance/models.py | 2 +- cotisations/payment_methods/cheque/models.py | 2 +- cotisations/payment_methods/comnpay/models.py | 2 +- cotisations/payment_methods/free/models.py | 2 +- .../payment_methods/note_kfet/models.py | 2 +- cotisations/test_models.py | 49 +++++++++++++++++++ cotisations/tests.py | 28 ----------- 8 files changed, 95 insertions(+), 33 deletions(-) create mode 100644 cotisations/migrations/0041_auto_20191103_2131.py create mode 100644 cotisations/test_models.py delete mode 100644 cotisations/tests.py diff --git a/cotisations/migrations/0041_auto_20191103_2131.py b/cotisations/migrations/0041_auto_20191103_2131.py new file mode 100644 index 00000000..09f763ed --- /dev/null +++ b/cotisations/migrations/0041_auto_20191103_2131.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-11-03 20:31 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('cotisations', '0040_auto_20191002_2335'), + ] + + operations = [ + migrations.AlterField( + model_name='balancepayment', + name='payment', + field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_balance', to='cotisations.Paiement'), + ), + migrations.AlterField( + model_name='chequepayment', + name='payment', + field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_cheque', to='cotisations.Paiement'), + ), + migrations.AlterField( + model_name='comnpaypayment', + name='payment', + field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_comnpay', to='cotisations.Paiement'), + ), + migrations.AlterField( + model_name='freepayment', + name='payment', + field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_free', to='cotisations.Paiement'), + ), + migrations.AlterField( + model_name='notepayment', + name='payment', + field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_note', to='cotisations.Paiement'), + ), + ] diff --git a/cotisations/payment_methods/balance/models.py b/cotisations/payment_methods/balance/models.py index 221cca3e..e3e05ea4 100644 --- a/cotisations/payment_methods/balance/models.py +++ b/cotisations/payment_methods/balance/models.py @@ -40,7 +40,7 @@ class BalancePayment(PaymentMethodMixin, models.Model): payment = models.OneToOneField( Paiement, on_delete=models.CASCADE, - related_name='payment_method', + related_name='payment_method_balance', editable=False ) minimum_balance = models.DecimalField( diff --git a/cotisations/payment_methods/cheque/models.py b/cotisations/payment_methods/cheque/models.py index 8f00ff46..a834bb93 100644 --- a/cotisations/payment_methods/cheque/models.py +++ b/cotisations/payment_methods/cheque/models.py @@ -38,7 +38,7 @@ class ChequePayment(PaymentMethodMixin, models.Model): payment = models.OneToOneField( Paiement, on_delete=models.CASCADE, - related_name='payment_method', + related_name='payment_method_cheque', editable=False ) diff --git a/cotisations/payment_methods/comnpay/models.py b/cotisations/payment_methods/comnpay/models.py index 7fac089a..a5568f22 100644 --- a/cotisations/payment_methods/comnpay/models.py +++ b/cotisations/payment_methods/comnpay/models.py @@ -41,7 +41,7 @@ class ComnpayPayment(PaymentMethodMixin, models.Model): payment = models.OneToOneField( Paiement, on_delete=models.CASCADE, - related_name='payment_method', + related_name='payment_method_comnpay', editable=False ) payment_credential = models.CharField( diff --git a/cotisations/payment_methods/free/models.py b/cotisations/payment_methods/free/models.py index 46ecca87..2931faad 100644 --- a/cotisations/payment_methods/free/models.py +++ b/cotisations/payment_methods/free/models.py @@ -38,7 +38,7 @@ class FreePayment(PaymentMethodMixin, models.Model): payment = models.OneToOneField( Paiement, on_delete=models.CASCADE, - related_name='payment_method', + related_name='payment_method_free', editable=False ) diff --git a/cotisations/payment_methods/note_kfet/models.py b/cotisations/payment_methods/note_kfet/models.py index be54bd54..0e2ebea1 100644 --- a/cotisations/payment_methods/note_kfet/models.py +++ b/cotisations/payment_methods/note_kfet/models.py @@ -42,7 +42,7 @@ class NotePayment(PaymentMethodMixin, models.Model): payment = models.OneToOneField( Paiement, on_delete = models.CASCADE, - related_name = 'payment_method', + related_name = 'payment_method_note', editable = False ) server = models.CharField( diff --git a/cotisations/test_models.py b/cotisations/test_models.py new file mode 100644 index 00000000..33f32a18 --- /dev/null +++ b/cotisations/test_models.py @@ -0,0 +1,49 @@ +from django.test import TestCase + +import datetime +from django.utils import timezone + +from users.models import User +from .models import Vente, Facture, Cotisation, Paiement + +class VenteModelTests(TestCase): + def setUp(self): + self.user = User.objects.create( + pseudo="testUser", + email="test@example.org" + ) + self.paiement = Paiement.objects.create( + moyen="test payment" + ) + self.f = Facture.objects.create( + user=self.user, + paiement=self.paiement, + valid=True + ) + + def test_one_day_cotisation(self): + """ + It should be possible to have one day membership. + """ + date = timezone.now() + purchase = Vente.objects.create( + facture=self.f, + number=1, + name="Test purchase", + duration=0, + duration_days=1, + type_cotisation="All", + prix=0, + ) + self.assertAlmostEqual( + self.user.end_connexion() - date, + datetime.timedelta(days=1), + delta=datetime.timedelta(seconds=1) + ) + + def tearDown(self): + self.f.delete() + self.user.delete() + self.paiement.delete() + + diff --git a/cotisations/tests.py b/cotisations/tests.py deleted file mode 100644 index b2ecee78..00000000 --- a/cotisations/tests.py +++ /dev/null @@ -1,28 +0,0 @@ -# Re2o est un logiciel d'administration développé initiallement au rezometz. Il -# se veut agnostique au réseau considéré, de manière à être installable en -# quelques clics. -# -# Copyright © 2017 Gabriel Détraz -# Copyright © 2017 Lara Kermarec -# Copyright © 2017 Augustin Lemesle -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -"""cotisations.tests -The tests for the Cotisations module. -""" - -# from django.test import TestCase - -# Create your tests here. From 034b50bc58632abba6f1375e06ae394d4870f813 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Mon, 4 Nov 2019 00:25:29 +0100 Subject: [PATCH 185/228] Fix #189 --- cotisations/models.py | 16 +++- cotisations/test_models.py | 43 ++++++++++ cotisations/test_views.py | 166 +++++++++++++++++++++++++++++++++++++ users/test_models.py | 51 ++++++++++++ 4 files changed, 274 insertions(+), 2 deletions(-) create mode 100644 cotisations/test_views.py create mode 100644 users/test_models.py diff --git a/cotisations/models.py b/cotisations/models.py index b9d01b8d..77337a84 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -290,9 +290,22 @@ class Facture(BaseInvoice): """Returns True if this invoice contains at least one subscribtion.""" return bool(self.get_subscription()) + def reorder_purchases(self): + date = self.date + for purchase in self.vente_set.all(): + if hasattr(purchase, 'cotisation'): + cotisation = purchase.cotisation + cotisation.date_start = date + date += relativedelta( + months=(purchase.duration or 0)*purchase.number, + days=(purchase.duration_days or 0)*purchase.number, + ) + purchase.save() + def save(self, *args, **kwargs): super(Facture, self).save(*args, **kwargs) if not self.__original_valid and self.valid: + self.reorder_purchases() send_mail_invoice(self) if self.is_subscription() \ and not self.__original_control \ @@ -540,7 +553,6 @@ class Vente(RevMixin, AclMixin, models.Model): months=(self.duration or 0)*self.number, days=(self.duration_days or 0)*self.number, ) - return def save(self, *args, **kwargs): """ @@ -1042,7 +1054,7 @@ class Cotisation(RevMixin, AclMixin, models.Model): return True, None, None def __str__(self): - return str(self.vente) + return str(self.vente) + "from " + str(self.date_start) + " to " + str(self.date_end) @receiver(post_save, sender=Cotisation) diff --git a/cotisations/test_models.py b/cotisations/test_models.py index 33f32a18..ed53c0a1 100644 --- a/cotisations/test_models.py +++ b/cotisations/test_models.py @@ -2,6 +2,7 @@ from django.test import TestCase import datetime from django.utils import timezone +from dateutil.relativedelta import relativedelta from users.models import User from .models import Vente, Facture, Cotisation, Paiement @@ -41,6 +42,48 @@ class VenteModelTests(TestCase): delta=datetime.timedelta(seconds=1) ) + def test_one_month_cotisation(self): + """ + It should be possible to have one day membership. + """ + date = timezone.now() + purchase = Vente.objects.create( + facture=self.f, + number=1, + name="Test purchase", + duration=1, + duration_days=0, + type_cotisation="All", + prix=0, + ) + delta = relativedelta(self.user.end_connexion(), date) + delta.microseconds=0 + self.assertEqual( + delta, + relativedelta(months=1), + ) + + def test_one_month_and_one_week_cotisation(self): + """ + It should be possible to have one day membership. + """ + date = timezone.now() + purchase = Vente.objects.create( + facture=self.f, + number=1, + name="Test purchase", + duration=1, + duration_days=7, + type_cotisation="All", + prix=0, + ) + delta = relativedelta(self.user.end_connexion(), date) + delta.microseconds=0 + self.assertEqual( + delta, + relativedelta(months=1, days=7), + ) + def tearDown(self): self.f.delete() self.user.delete() diff --git a/cotisations/test_views.py b/cotisations/test_views.py new file mode 100644 index 00000000..ba24c4d6 --- /dev/null +++ b/cotisations/test_views.py @@ -0,0 +1,166 @@ +from django.test import TestCase +from django.urls import reverse +from django.contrib.auth.models import Permission + +import datetime +from dateutil.relativedelta import relativedelta +from django.utils import timezone + +from users.models import Adherent +from .models import Vente, Facture, Cotisation, Paiement, Article + +class NewFactureTests(TestCase): + def tearDown(self): + self.user.facture_set.all().delete() + self.user.delete() + self.paiement.delete() + self.article_one_day.delete() + self.article_one_month.delete() + self.article_one_month_and_one_week.delete() + + def setUp(self): + self.user = Adherent.objects.create( + pseudo="testUser", + email="test@example.org", + ) + self.user.set_password('plopiplop') + self.user.user_permissions.set( + [ + Permission.objects.get_by_natural_key("add_facture", "cotisations", "Facture"), + Permission.objects.get_by_natural_key("use_every_payment", "cotisations", "Paiement"), + ] + ) + self.user.save() + + self.paiement = Paiement.objects.create( + moyen="test payment", + + ) + self.article_one_day = Article.objects.create( + name="One day", + prix=0, + duration=0, + duration_days=1, + type_cotisation='All', + available_for_everyone=True + ) + self.article_one_month = Article.objects.create( + name="One day", + prix=0, + duration=1, + duration_days=0, + type_cotisation='All', + available_for_everyone=True + ) + self.article_one_month_and_one_week = Article.objects.create( + name="One day", + prix=0, + duration=1, + duration_days=7, + type_cotisation='All', + available_for_everyone=True + ) + self.client.login( + username="testUser", + password="plopiplop" + ) + + def test_invoice_with_one_day(self): + data = { + "Facture-paiement": self.paiement.pk, + "form-TOTAL_FORMS": 1, + "form-INITIAL_FORMS": 0, + "form-MIN_NUM_FORMS": 0, + "form-MAX_NUM_FORMS": 1000, + "form-0-article": 1, + "form-0-quantity": 1, + } + date = timezone.now() + response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) + self.assertEqual( + response.status_code, + 302 + ) + self.assertEqual( + response.url, + "/users/profil/%d"%self.user.pk + ) + self.assertAlmostEqual( + self.user.end_connexion() - date, + datetime.timedelta(days=1), + delta=datetime.timedelta(seconds=1) + ) + + def test_invoice_with_one_month(self): + data = { + "Facture-paiement": self.paiement.pk, + "form-TOTAL_FORMS": 1, + "form-INITIAL_FORMS": 0, + "form-MIN_NUM_FORMS": 0, + "form-MAX_NUM_FORMS": 1000, + "form-0-article": 2, + "form-0-quantity": 1, + } + date = timezone.now() + response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) + self.assertEqual( + response.status_code, + 302 + ) + self.assertEqual( + response.url, + "/users/profil/%d"%self.user.pk + ) + delta = relativedelta(self.user.end_connexion(), date) + delta.microseconds=0 + self.assertEqual( + delta, + relativedelta(months=1), + ) + + def test_invoice_with_one_month_and_one_week(self): + data = { + "Facture-paiement": self.paiement.pk, + "form-TOTAL_FORMS": 2, + "form-INITIAL_FORMS": 0, + "form-MIN_NUM_FORMS": 0, + "form-MAX_NUM_FORMS": 1000, + "form-0-article": 1, + "form-0-quantity": 7, + "form-1-article": 2, + "form-1-quantity": 1, + } + date = timezone.now() + response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) + self.assertEqual( + response.status_code, + 302 + ) + self.assertEqual( + response.url, + "/users/profil/%d"%self.user.pk + ) + invoice = self.user.facture_set.first() + delta = relativedelta(self.user.end_connexion(), date) + delta.microseconds=0 + self.assertEqual( + delta, + relativedelta(months=1, days=7), + ) + + + def test_several_articles_creates_several_purchases(self): + data = { + "Facture-paiement": self.paiement.pk, + "form-TOTAL_FORMS": 2, + "form-INITIAL_FORMS": 0, + "form-MIN_NUM_FORMS": 0, + "form-MAX_NUM_FORMS": 1000, + "form-0-article": 2, + "form-0-quantity": 1, + "form-1-article": 2, + "form-1-quantity": 1, + } + response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) + f = self.user.facture_set.first() + self.assertEqual(f.vente_set.count(), 2) diff --git a/users/test_models.py b/users/test_models.py new file mode 100644 index 00000000..e9cb7d7b --- /dev/null +++ b/users/test_models.py @@ -0,0 +1,51 @@ +from django.test import TestCase + +import datetime +from django.utils import timezone + +from users.models import User +from cotisations.models import Vente, Facture, Paiement + +class UserModelTests(TestCase): + def setUp(self): + self.user = User.objects.create( + pseudo="testUser" + ) + + def tearDown(self): + self.user.facture_set.all().delete() + self.user.delete() + + def test_multiple_cotisations_are_taken_into_account(self): + paiement = Paiement.objects.create( + moyen="test payment" + ) + invoice = Facture.objects.create( + user=self.user, + paiement=paiement, + valid=True + ) + date = timezone.now() + purchase1 = Vente.objects.create( + facture=invoice, + number=1, + name="Test purchase", + duration=0, + duration_days=1, + type_cotisation="All", + prix=0, + ) + purchase2 = Vente.objects.create( + facture=invoice, + number=1, + name="Test purchase", + duration=0, + duration_days=1, + type_cotisation="All", + prix=0, + ) + self.assertAlmostEqual( + self.user.end_connexion() - date, + datetime.timedelta(days=2), + delta=datetime.timedelta(seconds=1) + ) From ce862a3bde60f7a1437e8b0d33e7dfd95e9d4b3f Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Mon, 4 Nov 2019 17:49:17 +0100 Subject: [PATCH 186/228] =?UTF-8?q?What=20Is=20Dead=20May=20Never=20Die=20?= =?UTF-8?q?=F0=9F=A7=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- users/management/commands/email.py | 35 ------------------------------ 1 file changed, 35 deletions(-) delete mode 100644 users/management/commands/email.py diff --git a/users/management/commands/email.py b/users/management/commands/email.py deleted file mode 100644 index 5e1d02c4..00000000 --- a/users/management/commands/email.py +++ /dev/null @@ -1,35 +0,0 @@ -from django.core.management.base import BaseCommand, CommandError - -from datetime import datetime, timedelta -from pytz - -from users.models import User - -UTC = pytz.timezone('UTC') - - -# TODO : remove of finsihed this because currently it should -# be failing! Who commited that ?! -class Command(BaseCommand): - commands = ['email_remainder'] - args = '[command]' - help = 'Send email remainders' - - def handle(self, *args, **options): - ''' - Sends an email before the end of a user's subscription - ''' - users = User.objects.filter(state="STATE_ACTIVE") - - for user in users: - remaining = user.end_adhesion() - datetime.today(tz=UTC) - if (timedelta(weeks=4) - remaining).days == 1: - 4_weeks_reminder() - elif (timedelta(weeks=1) - remaining).days == 1: - week_reminder() - elif remaining.days == 1: - last_day_reminder() - - -def month_reminder(): - pass From c4a104b3b6a4c760c780f6f409e6b6f64786336b Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Mon, 4 Nov 2019 17:55:03 +0100 Subject: [PATCH 187/228] =?UTF-8?q?I=20like=20my=20=E2=98=95=20black.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just ran black on the whoe repository. Fix #210. --- api/acl.py | 17 +- api/authentication.py | 4 +- api/pagination.py | 5 +- api/permissions.py | 62 +- api/routers.py | 12 +- api/serializers.py | 828 +++++++---- api/settings.py | 28 +- api/tests.py | 525 ++++--- api/urls.py | 170 +-- api/views.py | 179 ++- cotisations/acl.py | 7 +- cotisations/admin.py | 8 + cotisations/forms.py | 158 +-- cotisations/migrations/0001_initial.py | 102 +- .../migrations/0002_remove_facture_article.py | 11 +- .../migrations/0003_auto_20160702_1448.py | 17 +- .../migrations/0004_auto_20160702_1528.py | 12 +- .../migrations/0005_auto_20160702_1532.py | 10 +- .../migrations/0006_auto_20160702_1534.py | 18 +- .../migrations/0007_auto_20160702_1543.py | 14 +- .../migrations/0008_auto_20160702_1614.py | 48 +- .../migrations/0009_remove_cotisation_user.py | 11 +- .../migrations/0010_auto_20160702_1840.py | 17 +- .../migrations/0011_auto_20160702_1911.py | 10 +- .../migrations/0012_auto_20160704_0118.py | 14 +- .../migrations/0013_auto_20160711_2240.py | 49 +- .../migrations/0014_auto_20160712_0245.py | 13 +- .../migrations/0015_auto_20160714_2142.py | 28 +- .../migrations/0016_auto_20160715_0110.py | 23 +- .../migrations/0017_auto_20170718_2329.py | 19 +- .../migrations/0018_paiement_type_paiement.py | 16 +- .../migrations/0019_auto_20170819_0055.py | 14 +- .../migrations/0020_auto_20170819_0057.py | 14 +- .../migrations/0021_auto_20170819_0104.py | 12 +- .../migrations/0022_auto_20170824_0128.py | 14 +- .../migrations/0023_auto_20170902_1303.py | 12 +- .../migrations/0024_auto_20171015_2033.py | 23 +- .../migrations/0025_article_type_user.py | 16 +- .../migrations/0026_auto_20171028_0126.py | 85 +- .../migrations/0027_auto_20171029_1156.py | 10 +- .../migrations/0028_auto_20171231_0007.py | 53 +- .../migrations/0029_auto_20180414_2056.py | 261 ++-- cotisations/migrations/0030_custom_payment.py | 214 ++- .../0031_comnpaypayment_production.py | 15 +- cotisations/migrations/0032_custom_invoice.py | 134 +- .../migrations/0033_auto_20180818_1319.py | 317 +++-- .../migrations/0034_auto_20180831_1532.py | 12 +- cotisations/migrations/0035_notepayment.py | 38 +- .../migrations/0036_custominvoice_remark.py | 12 +- cotisations/migrations/0037_costestimate.py | 39 +- .../migrations/0038_auto_20181231_1657.py | 30 +- cotisations/migrations/0039_freepayment.py | 32 +- .../migrations/0040_auto_20191002_2335.py | 26 +- .../migrations/0041_auto_20191103_2131.py | 59 +- cotisations/migrations/__init__.py | 1 - cotisations/models.py | 604 ++++---- cotisations/payment_methods/__init__.py | 8 +- .../payment_methods/balance/__init__.py | 1 + cotisations/payment_methods/balance/models.py | 43 +- .../payment_methods/cheque/__init__.py | 1 + cotisations/payment_methods/cheque/forms.py | 3 +- cotisations/payment_methods/cheque/models.py | 12 +- cotisations/payment_methods/cheque/urls.py | 8 +- cotisations/payment_methods/cheque/views.py | 22 +- .../payment_methods/comnpay/__init__.py | 1 + .../payment_methods/comnpay/comnpay.py | 46 +- cotisations/payment_methods/comnpay/models.py | 65 +- cotisations/payment_methods/comnpay/urls.py | 18 +- cotisations/payment_methods/comnpay/views.py | 48 +- cotisations/payment_methods/forms.py | 50 +- cotisations/payment_methods/free/__init__.py | 1 + cotisations/payment_methods/free/models.py | 15 +- cotisations/payment_methods/mixins.py | 3 +- .../payment_methods/note_kfet/__init__.py | 1 + .../payment_methods/note_kfet/forms.py | 12 +- .../payment_methods/note_kfet/models.py | 30 +- cotisations/payment_methods/note_kfet/note.py | 35 +- cotisations/payment_methods/note_kfet/urls.py | 6 +- .../payment_methods/note_kfet/views.py | 46 +- cotisations/payment_methods/urls.py | 6 +- cotisations/test_models.py | 32 +- cotisations/test_views.py | 95 +- cotisations/tex.py | 73 +- cotisations/urls.py | 162 +-- cotisations/utils.py | 108 +- cotisations/validators.py | 6 +- cotisations/views.py | 859 ++++++------ freeradius_utils/auth.py | 335 ++--- logs/acl.py | 8 +- logs/templatetags/logs_extra.py | 16 +- logs/urls.py | 24 +- logs/views.py | 453 +++--- machines/acl.py | 8 +- machines/admin.py | 27 +- machines/forms.py | 333 ++--- machines/migrations/0001_initial.py | 46 +- .../migrations/0002_auto_20160703_1444.py | 57 +- .../migrations/0003_auto_20160703_1450.py | 10 +- .../migrations/0004_auto_20160703_1451.py | 12 +- .../migrations/0005_auto_20160703_1523.py | 18 +- .../migrations/0006_auto_20160703_1813.py | 12 +- .../migrations/0007_auto_20160703_1816.py | 12 +- .../migrations/0008_remove_interface_ipv6.py | 11 +- .../migrations/0009_auto_20160703_2358.py | 14 +- .../migrations/0010_auto_20160704_0104.py | 18 +- .../migrations/0011_auto_20160704_0105.py | 14 +- .../migrations/0012_auto_20160704_0118.py | 14 +- .../migrations/0013_auto_20160705_1014.py | 18 +- .../migrations/0014_auto_20160706_1220.py | 16 +- .../migrations/0015_auto_20160707_0105.py | 16 +- .../migrations/0016_auto_20160708_1633.py | 39 +- .../migrations/0017_auto_20160708_1645.py | 16 +- .../migrations/0018_auto_20160708_1813.py | 16 +- .../migrations/0019_auto_20160718_1141.py | 12 +- .../migrations/0020_auto_20160718_1849.py | 19 +- .../migrations/0021_auto_20161006_1943.py | 10 +- .../migrations/0022_auto_20161011_1829.py | 16 +- machines/migrations/0023_iplist_ip_type.py | 16 +- .../migrations/0024_machinetype_need_infra.py | 10 +- .../migrations/0025_auto_20161023_0038.py | 57 +- .../migrations/0026_auto_20161026_1348.py | 16 +- machines/migrations/0027_alias.py | 29 +- machines/migrations/0028_iptype_domaine_ip.py | 14 +- .../migrations/0029_iptype_domaine_range.py | 19 +- .../migrations/0030_auto_20161118_1730.py | 26 +- .../migrations/0031_auto_20161119_1709.py | 78 +- .../migrations/0032_auto_20161119_1850.py | 19 +- .../migrations/0033_extension_need_infra.py | 10 +- machines/migrations/0034_iplist_need_infra.py | 10 +- .../migrations/0035_auto_20161224_1201.py | 8 +- .../migrations/0036_auto_20161224_1204.py | 19 +- machines/migrations/0037_domain_cname.py | 17 +- .../migrations/0038_auto_20161224_1721.py | 17 +- .../migrations/0039_auto_20161224_1732.py | 12 +- .../migrations/0040_remove_interface_dns.py | 11 +- .../migrations/0041_remove_ns_interface.py | 11 +- machines/migrations/0042_ns_ns.py | 16 +- .../migrations/0043_auto_20170721_0350.py | 17 +- .../migrations/0044_auto_20170808_0233.py | 63 +- .../migrations/0045_auto_20170808_0348.py | 12 +- .../migrations/0046_auto_20170808_1423.py | 10 +- .../migrations/0047_auto_20170809_0606.py | 29 +- .../migrations/0048_auto_20170823_2315.py | 17 +- machines/migrations/0049_vlan.py | 24 +- .../migrations/0050_auto_20170826_0022.py | 10 +- machines/migrations/0051_iptype_vlan.py | 17 +- .../migrations/0052_auto_20170828_2322.py | 21 +- machines/migrations/0053_text.py | 22 +- machines/migrations/0054_text_zone.py | 14 +- machines/migrations/0055_nas.py | 38 +- .../migrations/0056_nas_port_access_mode.py | 16 +- .../migrations/0057_nas_autocapture_mac.py | 10 +- .../migrations/0058_auto_20171002_0350.py | 68 +- machines/migrations/0059_iptype_prefix_v6.py | 12 +- .../migrations/0060_iptype_ouverture_ports.py | 17 +- .../migrations/0061_auto_20171015_2033.py | 32 +- .../migrations/0062_extension_origin_v6.py | 12 +- .../migrations/0063_auto_20171020_0040.py | 66 +- .../migrations/0064_auto_20171115_0253.py | 10 +- .../migrations/0065_auto_20171115_1514.py | 11 +- machines/migrations/0066_srv.py | 73 +- .../migrations/0067_auto_20171116_0152.py | 41 +- .../migrations/0068_auto_20171116_0252.py | 57 +- .../migrations/0069_auto_20171116_0822.py | 17 +- .../migrations/0070_auto_20171231_1947.py | 98 +- .../migrations/0071_auto_20171231_2100.py | 9 +- .../migrations/0072_auto_20180108_1822.py | 18 +- .../migrations/0073_auto_20180128_2203.py | 31 +- .../migrations/0074_auto_20180129_0352.py | 18 +- .../migrations/0075_auto_20180130_0052.py | 9 +- .../migrations/0076_auto_20180130_1623.py | 16 +- .../migrations/0077_auto_20180409_2243.py | 18 +- .../migrations/0078_auto_20180415_1252.py | 16 +- .../migrations/0079_auto_20180416_0107.py | 18 +- .../migrations/0080_auto_20180502_2334.py | 14 +- .../migrations/0081_auto_20180521_1413.py | 14 +- .../migrations/0082_auto_20180525_2209.py | 14 +- .../0083_remove_duplicate_rights.py | 19 +- machines/migrations/0084_dname.py | 34 +- machines/migrations/0085_sshfingerprint.py | 58 +- machines/migrations/0086_role.py | 51 +- machines/migrations/0087_dnssec.py | 20 +- .../0088_iptype_prefix_v6_length.py | 18 +- .../migrations/0089_auto_20180805_1148.py | 10 +- .../migrations/0090_auto_20180805_1459.py | 12 +- .../migrations/0091_auto_20180806_2310.py | 28 +- .../migrations/0092_auto_20180807_0926.py | 12 +- .../migrations/0093_auto_20180807_1115.py | 16 +- .../migrations/0094_auto_20180815_1918.py | 431 ++++-- .../migrations/0095_auto_20180919_2225.py | 28 +- .../migrations/0096_auto_20181013_1417.py | 14 +- machines/migrations/0097_extension_dnssec.py | 14 +- .../migrations/0098_auto_20190102_1745.py | 32 +- .../migrations/0099_role_recursive_dns.py | 16 +- .../migrations/0100_auto_20190102_1753.py | 31 +- .../migrations/0101_auto_20190108_1623.py | 37 +- .../migrations/0102_auto_20190303_1611.py | 18 +- .../migrations/0103_auto_20191002_2222.py | 36 +- .../migrations/0104_auto_20191002_2231.py | 17 +- machines/migrations/0105_dname_ttl.py | 14 +- machines/migrations/__init__.py | 1 - machines/models.py | 1228 ++++++++--------- machines/serializers.py | 147 +- machines/urls.py | 252 ++-- machines/views.py | 1159 +++++++--------- multi_op/apps.py | 2 +- multi_op/forms.py | 11 +- multi_op/preferences/forms.py | 4 +- multi_op/preferences/models.py | 7 +- multi_op/urls.py | 26 +- multi_op/views.py | 96 +- preferences/acl.py | 8 +- preferences/admin.py | 17 +- preferences/forms.py | 340 +++-- preferences/migrations/0001_initial.py | 51 +- .../migrations/0002_auto_20170625_1923.py | 24 +- .../0003_optionaluser_solde_negatif.py | 10 +- .../migrations/0004_assooption_services.py | 61 +- .../migrations/0005_auto_20170824_0139.py | 11 +- .../migrations/0006_auto_20170824_0143.py | 12 +- .../migrations/0007_auto_20170824_2056.py | 14 +- .../migrations/0008_auto_20170824_2122.py | 31 +- .../0009_assooption_utilisateur_asso.py | 15 +- .../migrations/0010_auto_20170825_0459.py | 56 +- .../migrations/0011_auto_20170825_2307.py | 32 +- .../0012_generaloption_req_expire_hrs.py | 10 +- .../0013_generaloption_site_name.py | 12 +- .../0014_generaloption_email_from.py | 12 +- ...optionaltopologie_radius_general_policy.py | 19 +- .../migrations/0016_auto_20170902_1520.py | 22 +- .../migrations/0017_mailmessageoption.py | 22 +- .../0018_optionaltopologie_mac_autocapture.py | 10 +- ...emove_optionaltopologie_mac_autocapture.py | 9 +- .../migrations/0020_optionalmachine_ipv6.py | 10 +- .../migrations/0021_auto_20171015_1741.py | 22 +- .../migrations/0022_auto_20171015_1758.py | 22 +- .../migrations/0023_auto_20171015_2033.py | 22 +- .../0024_optionaluser_all_can_create.py | 14 +- .../migrations/0025_auto_20171231_2142.py | 56 +- .../0025_generaloption_general_message.py | 15 +- .../migrations/0026_auto_20171216_0401.py | 16 +- .../migrations/0027_merge_20180106_2019.py | 7 +- .../migrations/0028_assooption_description.py | 12 +- .../migrations/0028_auto_20180111_1129.py | 10 +- .../migrations/0028_auto_20180128_2203.py | 23 +- .../migrations/0029_auto_20180111_1134.py | 16 +- .../migrations/0029_auto_20180318_0213.py | 10 +- .../migrations/0029_auto_20180318_1005.py | 12 +- .../migrations/0030_auto_20180111_2346.py | 13 +- .../migrations/0030_merge_20180320_1419.py | 7 +- .../migrations/0031_auto_20180323_0218.py | 12 +- .../0031_optionaluser_self_adhesion.py | 15 +- .../0032_optionaluser_min_online_payment.py | 10 +- .../0032_optionaluser_shell_default.py | 17 +- preferences/migrations/0033_accueiloption.py | 46 +- .../0033_generaloption_gtu_sum_up.py | 12 +- .../migrations/0034_auto_20180114_2025.py | 16 +- .../migrations/0034_auto_20180416_1120.py | 17 +- .../migrations/0035_auto_20180114_2132.py | 12 +- ...35_optionaluser_allow_self_subscription.py | 15 +- .../migrations/0036_auto_20180114_2141.py | 12 +- .../migrations/0037_auto_20180114_2156.py | 12 +- .../migrations/0038_auto_20180114_2209.py | 12 +- .../migrations/0039_auto_20180115_0003.py | 10 +- .../migrations/0040_auto_20180129_1745.py | 15 +- .../migrations/0041_merge_20180130_0052.py | 7 +- .../migrations/0042_auto_20180222_1743.py | 27 +- .../0043_optionalmachine_create_machine.py | 14 +- .../migrations/0044_remove_payment_pass.py | 12 +- .../0045_remove_unused_payment_fields.py | 37 +- .../0046_optionaluser_mail_extension.py | 31 +- preferences/migrations/0047_mailcontact.py | 41 +- .../migrations/0048_auto_20180811_1515.py | 30 +- .../0049_optionaluser_self_change_shell.py | 14 +- .../migrations/0050_auto_20180818_1329.py | 232 +++- .../migrations/0051_auto_20180919_2225.py | 199 ++- .../0052_optionaluser_delete_notyetactive.py | 15 +- .../0053_optionaluser_self_change_room.py | 14 +- .../0055_generaloption_main_site_url.py | 12 +- preferences/migrations/0056_1_radiusoption.py | 187 ++- preferences/migrations/0056_2_radiusoption.py | 17 +- preferences/migrations/0056_3_radiusoption.py | 17 +- preferences/migrations/0056_4_radiusoption.py | 20 +- .../0057_optionaluser_all_users_active.py | 15 +- .../migrations/0058_auto_20190108_1650.py | 387 ++++-- .../migrations/0059_auto_20190120_1739.py | 92 +- .../migrations/0060_auto_20190712_1821.py | 17 +- ...1_optionaluser_allow_archived_connexion.py | 15 +- .../migrations/0062_auto_20190910_1909.py | 113 +- preferences/migrations/0063_mandate.py | 79 +- .../migrations/0064_auto_20191008_1335.py | 20 +- .../migrations/0065_auto_20191010_1227.py | 14 +- .../0066_optionalmachine_default_dns_ttl.py | 15 +- preferences/models.py | 487 +++---- preferences/templatetags/__init__.py | 2 +- preferences/urls.py | 170 +-- preferences/views.py | 464 ++++--- re2o/acl.py | 84 +- re2o/aes_field.py | 24 +- re2o/base.py | 230 ++- re2o/context_processors.py | 38 +- re2o/contributors.py | 2 +- re2o/field_permissions.py | 16 +- re2o/login.py | 79 +- re2o/management/commands/gen_contrib.py | 11 +- re2o/middleware.py | 7 +- re2o/mixins.py | 58 +- re2o/script_utils.py | 18 +- re2o/settings.py | 158 +-- re2o/settings_local.example.py | 72 +- re2o/templatetags/acl.py | 177 ++- re2o/templatetags/design.py | 6 +- re2o/templatetags/massive_bootstrap_form.py | 493 +++---- re2o/templatetags/url_insert_param.py | 12 +- re2o/urls.py | 61 +- re2o/utils.py | 98 +- re2o/views.py | 68 +- search/forms.py | 69 +- search/urls.py | 4 +- search/views.py | 341 ++--- test_utils/runner.py | 234 ++-- tickets/admin.py | 1 + tickets/apps.py | 2 +- tickets/forms.py | 11 +- tickets/migrations/0001_initial.py | 92 +- tickets/models.py | 67 +- tickets/preferences/forms.py | 4 +- tickets/preferences/models.py | 18 +- tickets/urls.py | 12 +- tickets/views.py | 180 +-- topologie/acl.py | 8 +- topologie/admin.py | 12 + topologie/forms.py | 176 +-- topologie/migrations/0001_initial.py | 23 +- .../migrations/0002_auto_20160703_1118.py | 37 +- topologie/migrations/0003_room.py | 24 +- .../migrations/0004_auto_20160703_1122.py | 9 +- .../migrations/0005_auto_20160703_1123.py | 9 +- .../migrations/0006_auto_20160703_1129.py | 19 +- .../migrations/0007_auto_20160703_1148.py | 10 +- topologie/migrations/0008_port_room.py | 17 +- .../migrations/0009_auto_20160703_1200.py | 17 +- .../migrations/0010_auto_20160704_2148.py | 30 +- .../migrations/0011_auto_20160704_2153.py | 10 +- .../migrations/0012_port_machine_interface.py | 17 +- topologie/migrations/0013_port_related.py | 14 +- .../migrations/0014_auto_20160706_1238.py | 17 +- .../migrations/0015_auto_20160706_1452.py | 17 +- .../migrations/0016_auto_20160706_1531.py | 17 +- .../migrations/0017_auto_20160718_1141.py | 17 +- topologie/migrations/0018_room_details.py | 10 +- .../migrations/0019_auto_20161026_1348.py | 26 +- .../migrations/0020_auto_20161119_0033.py | 17 +- topologie/migrations/0021_port_radius.py | 25 +- .../migrations/0022_auto_20161211_1622.py | 25 +- .../migrations/0023_auto_20170817_1654.py | 44 +- .../migrations/0023_auto_20170826_1530.py | 28 +- .../migrations/0024_auto_20170818_1021.py | 17 +- .../migrations/0024_auto_20170826_1800.py | 21 +- .../migrations/0025_merge_20170902_1242.py | 7 +- .../migrations/0026_auto_20170902_1245.py | 28 +- .../migrations/0027_auto_20170905_1442.py | 24 +- .../migrations/0028_auto_20170913_1503.py | 27 +- .../migrations/0029_auto_20171002_0334.py | 28 +- .../migrations/0030_auto_20171004_0235.py | 31 +- .../migrations/0031_auto_20171015_2033.py | 28 +- .../migrations/0032_auto_20171026_0338.py | 51 +- .../migrations/0033_auto_20171231_1743.py | 37 +- topologie/migrations/0034_borne.py | 33 +- .../migrations/0035_auto_20180324_0023.py | 17 +- topologie/migrations/0036_transferborne.py | 18 +- .../migrations/0037_auto_20180325_0127.py | 49 +- topologie/migrations/0038_transfersw.py | 12 +- topologie/migrations/0039_port_new_switch.py | 18 +- topologie/migrations/0040_transferports.py | 12 +- topologie/migrations/0041_transferportsw.py | 16 +- topologie/migrations/0042_transferswitch.py | 10 +- topologie/migrations/0043_renamenewswitch.py | 8 +- .../migrations/0044_auto_20180326_0002.py | 19 +- .../migrations/0045_auto_20180326_0123.py | 16 +- .../migrations/0046_auto_20180326_0129.py | 9 +- topologie/migrations/0047_ap_machine.py | 34 +- topologie/migrations/0048_ap_machine.py | 13 +- topologie/migrations/0049_switchs_machine.py | 50 +- topologie/migrations/0050_port_new_switch.py | 18 +- topologie/migrations/0051_switchs_machine.py | 13 +- topologie/migrations/0052_transferports.py | 18 +- topologie/migrations/0053_finalsw.py | 15 +- .../migrations/0054_auto_20180326_1742.py | 28 +- .../migrations/0055_auto_20180329_0431.py | 10 +- .../migrations/0056_building_switchbay.py | 63 +- .../migrations/0057_auto_20180408_0316.py | 20 +- .../migrations/0058_remove_switch_location.py | 11 +- .../migrations/0059_auto_20180415_2249.py | 42 +- topologie/migrations/0060_server.py | 17 +- topologie/migrations/0061_portprofile.py | 330 ++++- .../migrations/0062_auto_20180815_1918.py | 284 +++- .../migrations/0063_auto_20180919_2225.py | 32 +- .../0064_switch_automatic_provision.py | 14 +- .../migrations/0065_auto_20180927_1836.py | 25 +- .../0066_modelswitch_commercial_name.py | 10 +- .../migrations/0067_auto_20181230_1819.py | 101 +- .../migrations/0068_auto_20190102_1758.py | 14 +- .../migrations/0069_auto_20190108_1439.py | 109 +- .../migrations/0070_auto_20190218_1743.py | 37 +- .../migrations/0071_auto_20190218_1936.py | 44 +- .../migrations/0072_auto_20190720_2318.py | 48 +- topologie/migrations/__init__.py | 1 - topologie/models.py | 523 ++++--- topologie/urls.py | 200 +-- topologie/views.py | 1057 +++++++------- users/acl.py | 9 +- users/admin.py | 112 +- users/forms.py | 492 ++++--- users/management/commands/anonymize.py | 107 +- users/management/commands/archive.py | 62 +- users/management/commands/chgpass.py | 11 +- users/management/commands/chsh.py | 22 +- .../management/commands/clean_notyetactive.py | 10 +- .../management/commands/derniere_connexion.py | 31 +- users/management/commands/ldap_rebuild.py | 58 +- users/management/commands/ldap_sync.py | 12 +- users/migrations/0001_initial.py | 63 +- users/migrations/0002_auto_20160630_2301.py | 21 +- users/migrations/0003_listrights_rights.py | 45 +- users/migrations/0004_auto_20160701_2312.py | 14 +- users/migrations/0005_auto_20160702_0006.py | 9 +- users/migrations/0006_ban.py | 31 +- users/migrations/0007_auto_20160702_2322.py | 10 +- users/migrations/0008_user_registered.py | 15 +- users/migrations/0009_user_room.py | 16 +- users/migrations/0010_auto_20160703_1226.py | 17 +- users/migrations/0011_auto_20160703_1227.py | 18 +- users/migrations/0012_auto_20160703_1230.py | 17 +- users/migrations/0013_auto_20160704_1547.py | 18 +- users/migrations/0014_auto_20160704_1548.py | 17 +- users/migrations/0015_whitelist.py | 31 +- users/migrations/0016_auto_20160706_1220.py | 27 +- users/migrations/0017_auto_20160707_0105.py | 26 +- users/migrations/0018_auto_20160707_0115.py | 11 +- users/migrations/0019_auto_20160708_1633.py | 10 +- users/migrations/0020_request.py | 39 +- users/migrations/0021_ldapuser.py | 80 +- users/migrations/0022_ldapuser_sambasid.py | 18 +- users/migrations/0023_auto_20160724_1908.py | 12 +- .../0024_remove_ldapuser_mac_list.py | 11 +- users/migrations/0025_listshell.py | 20 +- users/migrations/0026_user_shell.py | 16 +- users/migrations/0027_auto_20160726_0216.py | 31 +- users/migrations/0028_auto_20160726_0227.py | 70 +- users/migrations/0029_auto_20160726_0229.py | 14 +- users/migrations/0030_auto_20160726_0357.py | 14 +- users/migrations/0031_auto_20160726_0359.py | 17 +- users/migrations/0032_auto_20160727_2122.py | 64 +- .../0033_remove_ldapuser_loginshell.py | 11 +- users/migrations/0034_auto_20161018_0037.py | 37 +- users/migrations/0035_auto_20161018_0046.py | 14 +- users/migrations/0036_auto_20161022_2146.py | 19 +- users/migrations/0037_auto_20161028_1906.py | 16 +- users/migrations/0038_auto_20161031_0258.py | 16 +- users/migrations/0039_auto_20161119_0033.py | 16 +- users/migrations/0040_auto_20161119_1709.py | 16 +- users/migrations/0041_listright_details.py | 12 +- users/migrations/0042_auto_20161126_2028.py | 16 +- users/migrations/0043_auto_20161224_1156.py | 16 +- users/migrations/0043_ban_state.py | 15 +- users/migrations/0044_user_ssh_public_key.py | 10 +- users/migrations/0045_merge.py | 8 +- users/migrations/0046_auto_20170617_1433.py | 36 +- users/migrations/0047_auto_20170618_0156.py | 35 +- users/migrations/0048_auto_20170618_0210.py | 14 +- users/migrations/0049_auto_20170618_1424.py | 20 +- users/migrations/0050_serviceuser_comment.py | 12 +- users/migrations/0051_user_telephone.py | 10 +- .../migrations/0052_ldapuser_shadowexpire.py | 22 +- users/migrations/0053_auto_20170626_2105.py | 14 +- users/migrations/0054_auto_20170626_2219.py | 14 +- users/migrations/0055_auto_20171003_0556.py | 21 +- users/migrations/0056_auto_20171015_2033.py | 35 +- users/migrations/0057_auto_20171023_0301.py | 60 +- users/migrations/0058_auto_20171025_0154.py | 44 +- users/migrations/0059_auto_20171025_1854.py | 12 +- users/migrations/0060_auto_20171120_0317.py | 20 +- users/migrations/0061_auto_20171230_2033.py | 40 +- users/migrations/0062_auto_20171231_0056.py | 27 +- users/migrations/0063_auto_20171231_0140.py | 10 +- users/migrations/0064_auto_20171231_0150.py | 42 +- users/migrations/0065_auto_20171231_2053.py | 50 +- users/migrations/0066_grouppermissions.py | 680 ++++----- users/migrations/0067_serveurpermission.py | 30 +- users/migrations/0068_auto_20180107_2245.py | 40 +- users/migrations/0069_club_mailing.py | 10 +- users/migrations/0070_auto_20180324_1906.py | 14 +- users/migrations/0071_auto_20180415_1252.py | 21 +- users/migrations/0072_auto_20180426_2021.py | 12 +- users/migrations/0073_auto_20180629_1614.py | 68 +- users/migrations/0074_auto_20180810_2104.py | 22 +- users/migrations/0074_auto_20180814_1059.py | 32 +- users/migrations/0075_merge_20180815_2202.py | 7 +- users/migrations/0076_auto_20180818_1321.py | 203 ++- users/migrations/0077_auto_20180824_1750.py | 20 +- users/migrations/0078_auto_20181011_1405.py | 14 +- users/migrations/0079_auto_20181228_2039.py | 10 +- users/migrations/0080_auto_20190108_1726.py | 20 +- users/migrations/0081_auto_20190317_0302.py | 21 +- users/migrations/0082_auto_20190908_1338.py | 36 +- .../migrations/0083_user_shortcuts_enabled.py | 14 +- users/migrations/__init__.py | 1 - users/models.py | 1098 ++++++++------- users/serializers.py | 6 +- users/test_models.py | 17 +- users/tests.py | 15 +- users/urls.py | 176 +-- users/views.py | 780 +++++------ users/widgets.py | 86 +- 515 files changed, 16814 insertions(+), 13681 deletions(-) diff --git a/api/acl.py b/api/acl.py index ec46ee0c..c2db9862 100644 --- a/api/acl.py +++ b/api/acl.py @@ -40,14 +40,14 @@ def _create_api_permission(): """ api_content_type, created = ContentType.objects.get_or_create( app_label=settings.API_CONTENT_TYPE_APP_LABEL, - model=settings.API_CONTENT_TYPE_MODEL + model=settings.API_CONTENT_TYPE_MODEL, ) if created: api_content_type.save() api_permission, created = Permission.objects.get_or_create( name=settings.API_PERMISSION_NAME, content_type=api_content_type, - codename=settings.API_PERMISSION_CODENAME + codename=settings.API_PERMISSION_CODENAME, ) if created: api_permission.save() @@ -67,10 +67,13 @@ def can_view(user): viewing is granted and msg is a message (can be None). """ kwargs = { - 'app_label': settings.API_CONTENT_TYPE_APP_LABEL, - 'codename': settings.API_PERMISSION_CODENAME + "app_label": settings.API_CONTENT_TYPE_APP_LABEL, + "codename": settings.API_PERMISSION_CODENAME, } - permission = '%(app_label)s.%(codename)s' % kwargs + permission = "%(app_label)s.%(codename)s" % kwargs can = user.has_perm(permission) - return can, None if can else _("You don't have the right to see this" - " application."), (permission,) + return ( + can, + None if can else _("You don't have the right to see this" " application."), + (permission,), + ) diff --git a/api/authentication.py b/api/authentication.py index d426db24..88922987 100644 --- a/api/authentication.py +++ b/api/authentication.py @@ -41,9 +41,7 @@ class ExpiringTokenAuthentication(TokenAuthentication): user, token = base.authenticate_credentials(key) # Check that the genration time of the token is not too old - token_duration = datetime.timedelta( - seconds=settings.API_TOKEN_DURATION - ) + token_duration = datetime.timedelta(seconds=settings.API_TOKEN_DURATION) utc_now = datetime.datetime.now(datetime.timezone.utc) if token.created < utc_now - token_duration: raise exceptions.AuthenticationFailed(_("The token has expired.")) diff --git a/api/pagination.py b/api/pagination.py index d34c17ab..79da050e 100644 --- a/api/pagination.py +++ b/api/pagination.py @@ -38,8 +38,9 @@ class PageSizedPagination(pagination.PageNumberPagination): max_page_size: The maximum number of results a page can output no matter what is requested. """ - page_size_query_param = 'page_size' - all_pages_strings = ('all',) + + page_size_query_param = "page_size" + all_pages_strings = ("all",) max_page_size = 10000 def get_page_size(self, request): diff --git a/api/permissions.py b/api/permissions.py index 7d778c69..a8c70f67 100644 --- a/api/permissions.py +++ b/api/permissions.py @@ -55,17 +55,21 @@ def _get_param_in_view(view, param_name): AssertionError: None of the getter function or the attribute are defined in the view. """ - assert hasattr(view, 'get_' + param_name) \ - or getattr(view, param_name, None) is not None, ( - 'cannot apply {} on a view that does not set ' - '`.{}` or have a `.get_{}()` method.' - ).format(self.__class__.__name__, param_name, param_name) + assert ( + hasattr(view, "get_" + param_name) + or getattr(view, param_name, None) is not None + ), ( + "cannot apply {} on a view that does not set " + "`.{}` or have a `.get_{}()` method." + ).format( + self.__class__.__name__, param_name, param_name + ) - if hasattr(view, 'get_' + param_name): - param = getattr(view, 'get_' + param_name)() - assert param is not None, ( - '{}.get_{}() returned None' - ).format(view.__class__.__name__, param_name) + if hasattr(view, "get_" + param_name): + param = getattr(view, "get_" + param_name)() + assert param is not None, ("{}.get_{}() returned None").format( + view.__class__.__name__, param_name + ) return param return getattr(view, param_name) @@ -97,7 +101,7 @@ class ACLPermission(permissions.BasePermission): rest_framework.exception.MethodNotAllowed: The requested method is not allowed for this view. """ - perms_map = _get_param_in_view(view, 'perms_map') + perms_map = _get_param_in_view(view, "perms_map") if method not in perms_map: raise exceptions.MethodNotAllowed(method) @@ -123,7 +127,7 @@ class ACLPermission(permissions.BasePermission): """ # Workaround to ensure ACLPermissions are not applied # to the root view when using DefaultRouter. - if getattr(view, '_ignore_model_permissions', False): + if getattr(view, "_ignore_model_permissions", False): return True if not request.user or not request.user.is_authenticated: @@ -148,22 +152,22 @@ class AutodetectACLPermission(permissions.BasePermission): """ perms_map = { - 'GET': [can_see_api, lambda model: model.can_view_all], - 'OPTIONS': [can_see_api, lambda model: model.can_view_all], - 'HEAD': [can_see_api, lambda model: model.can_view_all], - 'POST': [can_see_api, lambda model: model.can_create], - 'PUT': [], # No restrictions, apply to objects - 'PATCH': [], # No restrictions, apply to objects - 'DELETE': [], # No restrictions, apply to objects + "GET": [can_see_api, lambda model: model.can_view_all], + "OPTIONS": [can_see_api, lambda model: model.can_view_all], + "HEAD": [can_see_api, lambda model: model.can_view_all], + "POST": [can_see_api, lambda model: model.can_create], + "PUT": [], # No restrictions, apply to objects + "PATCH": [], # No restrictions, apply to objects + "DELETE": [], # No restrictions, apply to objects } perms_obj_map = { - 'GET': [can_see_api, lambda obj: obj.can_view], - 'OPTIONS': [can_see_api, lambda obj: obj.can_view], - 'HEAD': [can_see_api, lambda obj: obj.can_view], - 'POST': [], # No restrictions, apply to models - 'PUT': [can_see_api, lambda obj: obj.can_edit], - 'PATCH': [can_see_api, lambda obj: obj.can_edit], - 'DELETE': [can_see_api, lambda obj: obj.can_delete], + "GET": [can_see_api, lambda obj: obj.can_view], + "OPTIONS": [can_see_api, lambda obj: obj.can_view], + "HEAD": [can_see_api, lambda obj: obj.can_view], + "POST": [], # No restrictions, apply to models + "PUT": [can_see_api, lambda obj: obj.can_edit], + "PATCH": [can_see_api, lambda obj: obj.can_edit], + "DELETE": [can_see_api, lambda obj: obj.can_delete], } def get_required_permissions(self, method, model): @@ -210,7 +214,7 @@ class AutodetectACLPermission(permissions.BasePermission): @staticmethod def _queryset(view): - return _get_param_in_view(view, 'queryset') + return _get_param_in_view(view, "queryset") def has_permission(self, request, view): """Check that the user has the model-based permissions to perform @@ -232,7 +236,7 @@ class AutodetectACLPermission(permissions.BasePermission): """ # Workaround to ensure ACLPermissions are not applied # to the root view when using DefaultRouter. - if getattr(view, '_ignore_model_permissions', False): + if getattr(view, "_ignore_model_permissions", False): return True if not request.user or not request.user.is_authenticated: @@ -274,7 +278,7 @@ class AutodetectACLPermission(permissions.BasePermission): # to make another lookup. raise Http404 - read_perms = self.get_required_object_permissions('GET', obj) + read_perms = self.get_required_object_permissions("GET", obj) if not read_perms(request.user)[0]: raise Http404 diff --git a/api/routers.py b/api/routers.py index bb2411f5..5841d09c 100644 --- a/api/routers.py +++ b/api/routers.py @@ -74,7 +74,7 @@ class AllViewsRouter(DefaultRouter): Returns: The name to use for this route. """ - return pattern.split('/')[-1] + return pattern.split("/")[-1] def get_api_root_view(self, schema_urls=None, api_urls=None): """Create a class-based view to use as the API root. @@ -102,12 +102,10 @@ class AllViewsRouter(DefaultRouter): if schema_urls and self.schema_title: view_renderers += list(self.schema_renderers) schema_generator = SchemaGenerator( - title=self.schema_title, - patterns=schema_urls + title=self.schema_title, patterns=schema_urls ) schema_media_types = [ - renderer.media_type - for renderer in self.schema_renderers + renderer.media_type for renderer in self.schema_renderers ] class APIRoot(views.APIView): @@ -128,14 +126,14 @@ class AllViewsRouter(DefaultRouter): namespace = request.resolver_match.namespace for key, url_name in api_root_dict.items(): if namespace: - url_name = namespace + ':' + url_name + url_name = namespace + ":" + url_name try: ret[key] = reverse( url_name, args=args, kwargs=kwargs, request=request, - format=kwargs.get('format', None) + format=kwargs.get("format", None), ) except NoReverseMatch: # Don't bail out if eg. no list routes exist, only detail routes. diff --git a/api/serializers.py b/api/serializers.py index f925d2bd..3e111920 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -32,7 +32,7 @@ import users.models as users # The namespace used for the API. It must match the namespace used in the # urlpatterns to include the API URLs. -API_NAMESPACE = 'api' +API_NAMESPACE = "api" class NamespacedHRField(serializers.HyperlinkedRelatedField): @@ -42,7 +42,7 @@ class NamespacedHRField(serializers.HyperlinkedRelatedField): def __init__(self, view_name=None, **kwargs): if view_name is not None: - view_name = '%s:%s' % (API_NAMESPACE, view_name) + view_name = "%s:%s" % (API_NAMESPACE, view_name) super(NamespacedHRField, self).__init__(view_name=view_name, **kwargs) @@ -53,7 +53,7 @@ class NamespacedHIField(serializers.HyperlinkedIdentityField): def __init__(self, view_name=None, **kwargs): if view_name is not None: - view_name = '%s:%s' % (API_NAMESPACE, view_name) + view_name = "%s:%s" % (API_NAMESPACE, view_name) super(NamespacedHIField, self).__init__(view_name=view_name, **kwargs) @@ -61,6 +61,7 @@ class NamespacedHMSerializer(serializers.HyperlinkedModelSerializer): """A `rest_framework.serializers.HyperlinkedModelSerializer` subclass to automatically prefix view names with the API namespace. """ + serializer_related_field = NamespacedHRField serializer_url_field = NamespacedHIField @@ -74,14 +75,25 @@ class FactureSerializer(NamespacedHMSerializer): class Meta: model = cotisations.Facture - fields = ('user', 'paiement', 'banque', 'cheque', 'date', 'valid', - 'control', 'prix_total', 'name', 'api_url') + fields = ( + "user", + "paiement", + "banque", + "cheque", + "date", + "valid", + "control", + "prix_total", + "name", + "api_url", + ) class BaseInvoiceSerializer(NamespacedHMSerializer): class Meta: model = cotisations.BaseInvoice - fields = ('__all__') + fields = "__all__" + class VenteSerializer(NamespacedHMSerializer): """Serialize `cotisations.models.Vente` objects. @@ -89,9 +101,16 @@ class VenteSerializer(NamespacedHMSerializer): class Meta: model = cotisations.Vente - fields = ('facture', - 'number', 'name', 'prix', 'duration', - 'type_cotisation', 'prix_total', 'api_url') + fields = ( + "facture", + "number", + "name", + "prix", + "duration", + "type_cotisation", + "prix_total", + "api_url", + ) class ArticleSerializer(NamespacedHMSerializer): @@ -100,8 +119,7 @@ class ArticleSerializer(NamespacedHMSerializer): class Meta: model = cotisations.Article - fields = ('name', 'prix', 'duration', 'type_user', - 'type_cotisation', 'api_url') + fields = ("name", "prix", "duration", "type_user", "type_cotisation", "api_url") class BanqueSerializer(NamespacedHMSerializer): @@ -110,7 +128,7 @@ class BanqueSerializer(NamespacedHMSerializer): class Meta: model = cotisations.Banque - fields = ('name', 'api_url') + fields = ("name", "api_url") class PaiementSerializer(NamespacedHMSerializer): @@ -119,7 +137,7 @@ class PaiementSerializer(NamespacedHMSerializer): class Meta: model = cotisations.Paiement - fields = ('moyen', 'api_url') + fields = ("moyen", "api_url") class CotisationSerializer(NamespacedHMSerializer): @@ -128,8 +146,7 @@ class CotisationSerializer(NamespacedHMSerializer): class Meta: model = cotisations.Cotisation - fields = ('vente', 'type_cotisation', 'date_start', 'date_end', - 'api_url') + fields = ("vente", "type_cotisation", "date_start", "date_end", "api_url") # MACHINES @@ -141,7 +158,7 @@ class MachineSerializer(NamespacedHMSerializer): class Meta: model = machines.Machine - fields = ('user', 'name', 'active', 'api_url') + fields = ("user", "name", "active", "api_url") class MachineTypeSerializer(NamespacedHMSerializer): @@ -150,7 +167,7 @@ class MachineTypeSerializer(NamespacedHMSerializer): class Meta: model = machines.MachineType - fields = ('name', 'ip_type', 'api_url') + fields = ("name", "ip_type", "api_url") class IpTypeSerializer(NamespacedHMSerializer): @@ -159,9 +176,17 @@ class IpTypeSerializer(NamespacedHMSerializer): class Meta: model = machines.IpType - fields = ('name', 'extension', 'need_infra', 'domaine_ip_start', - 'domaine_ip_stop', 'prefix_v6', 'vlan', 'ouverture_ports', - 'api_url') + fields = ( + "name", + "extension", + "need_infra", + "domaine_ip_start", + "domaine_ip_stop", + "prefix_v6", + "vlan", + "ouverture_ports", + "api_url", + ) class VlanSerializer(NamespacedHMSerializer): @@ -170,8 +195,17 @@ class VlanSerializer(NamespacedHMSerializer): class Meta: model = machines.Vlan - fields = ('vlan_id', 'name', 'comment', 'arp_protect', 'dhcp_snooping', - 'dhcpv6_snooping', 'igmp', 'mld', 'api_url') + fields = ( + "vlan_id", + "name", + "comment", + "arp_protect", + "dhcp_snooping", + "dhcpv6_snooping", + "igmp", + "mld", + "api_url", + ) class NasSerializer(NamespacedHMSerializer): @@ -180,8 +214,14 @@ class NasSerializer(NamespacedHMSerializer): class Meta: model = machines.Nas - fields = ('name', 'nas_type', 'machine_type', 'port_access_mode', - 'autocapture_mac', 'api_url') + fields = ( + "name", + "nas_type", + "machine_type", + "port_access_mode", + "autocapture_mac", + "api_url", + ) class SOASerializer(NamespacedHMSerializer): @@ -190,8 +230,7 @@ class SOASerializer(NamespacedHMSerializer): class Meta: model = machines.SOA - fields = ('name', 'mail', 'refresh', 'retry', 'expire', 'ttl', - 'api_url') + fields = ("name", "mail", "refresh", "retry", "expire", "ttl", "api_url") class ExtensionSerializer(NamespacedHMSerializer): @@ -200,8 +239,7 @@ class ExtensionSerializer(NamespacedHMSerializer): class Meta: model = machines.Extension - fields = ('name', 'need_infra', 'origin', 'origin_v6', 'soa', - 'api_url') + fields = ("name", "need_infra", "origin", "origin_v6", "soa", "api_url") class MxSerializer(NamespacedHMSerializer): @@ -210,7 +248,7 @@ class MxSerializer(NamespacedHMSerializer): class Meta: model = machines.Mx - fields = ('zone', 'priority', 'name', 'api_url') + fields = ("zone", "priority", "name", "api_url") class DNameSerializer(NamespacedHMSerializer): @@ -219,7 +257,7 @@ class DNameSerializer(NamespacedHMSerializer): class Meta: model = machines.DName - fields = ('zone', 'alias', 'api_url') + fields = ("zone", "alias", "api_url") class NsSerializer(NamespacedHMSerializer): @@ -228,7 +266,7 @@ class NsSerializer(NamespacedHMSerializer): class Meta: model = machines.Ns - fields = ('zone', 'ns', 'api_url') + fields = ("zone", "ns", "api_url") class TxtSerializer(NamespacedHMSerializer): @@ -237,7 +275,7 @@ class TxtSerializer(NamespacedHMSerializer): class Meta: model = machines.Txt - fields = ('zone', 'field1', 'field2', 'api_url') + fields = ("zone", "field1", "field2", "api_url") class SrvSerializer(NamespacedHMSerializer): @@ -246,8 +284,17 @@ class SrvSerializer(NamespacedHMSerializer): class Meta: model = machines.Srv - fields = ('service', 'protocole', 'extension', 'ttl', 'priority', - 'weight', 'port', 'target', 'api_url') + fields = ( + "service", + "protocole", + "extension", + "ttl", + "priority", + "weight", + "port", + "target", + "api_url", + ) class SshFpSerializer(NamespacedHMSerializer): @@ -256,19 +303,28 @@ class SshFpSerializer(NamespacedHMSerializer): class Meta: model = machines.SshFp - field = ('machine', 'pub_key_entry', 'algo', 'comment', 'api_url') + field = ("machine", "pub_key_entry", "algo", "comment", "api_url") class InterfaceSerializer(NamespacedHMSerializer): """Serialize `machines.models.Interface` objects. """ + mac_address = serializers.CharField() - active = serializers.BooleanField(source='is_active') + active = serializers.BooleanField(source="is_active") class Meta: model = machines.Interface - fields = ('ipv4', 'mac_address', 'machine', 'machine_type', 'details', - 'port_lists', 'active', 'api_url') + fields = ( + "ipv4", + "mac_address", + "machine", + "machine_type", + "details", + "port_lists", + "active", + "api_url", + ) class Ipv6ListSerializer(NamespacedHMSerializer): @@ -277,7 +333,7 @@ class Ipv6ListSerializer(NamespacedHMSerializer): class Meta: model = machines.Ipv6List - fields = ('ipv6', 'interface', 'slaac_ip', 'api_url') + fields = ("ipv6", "interface", "slaac_ip", "api_url") class DomainSerializer(NamespacedHMSerializer): @@ -286,8 +342,7 @@ class DomainSerializer(NamespacedHMSerializer): class Meta: model = machines.Domain - fields = ('interface_parent', 'name', 'extension', 'cname', - 'api_url') + fields = ("interface_parent", "name", "extension", "cname", "api_url") class IpListSerializer(NamespacedHMSerializer): @@ -296,7 +351,7 @@ class IpListSerializer(NamespacedHMSerializer): class Meta: model = machines.IpList - fields = ('ipv4', 'ip_type', 'need_infra', 'api_url') + fields = ("ipv4", "ip_type", "need_infra", "api_url") class ServiceSerializer(NamespacedHMSerializer): @@ -305,8 +360,13 @@ class ServiceSerializer(NamespacedHMSerializer): class Meta: model = machines.Service - fields = ('service_type', 'min_time_regen', 'regular_time_regen', - 'servers', 'api_url') + fields = ( + "service_type", + "min_time_regen", + "regular_time_regen", + "servers", + "api_url", + ) class ServiceLinkSerializer(NamespacedHMSerializer): @@ -315,25 +375,44 @@ class ServiceLinkSerializer(NamespacedHMSerializer): class Meta: model = machines.Service_link - fields = ('service', 'server', 'last_regen', 'asked_regen', - 'need_regen', 'api_url') - extra_kwargs = { - 'api_url': {'view_name': 'servicelink-detail'} - } + fields = ( + "service", + "server", + "last_regen", + "asked_regen", + "need_regen", + "api_url", + ) + extra_kwargs = {"api_url": {"view_name": "servicelink-detail"}} class OuverturePortListSerializer(NamespacedHMSerializer): """Serialize `machines.models.OuverturePortList` objects. """ - tcp_ports_in = NamespacedHRField(view_name='ouvertureport-detail', many=True, read_only=True) - udp_ports_in = NamespacedHRField(view_name='ouvertureport-detail', many=True, read_only=True) - tcp_ports_out = NamespacedHRField(view_name='ouvertureport-detail', many=True, read_only=True) - udp_ports_out = NamespacedHRField(view_name='ouvertureport-detail', many=True, read_only=True) + + tcp_ports_in = NamespacedHRField( + view_name="ouvertureport-detail", many=True, read_only=True + ) + udp_ports_in = NamespacedHRField( + view_name="ouvertureport-detail", many=True, read_only=True + ) + tcp_ports_out = NamespacedHRField( + view_name="ouvertureport-detail", many=True, read_only=True + ) + udp_ports_out = NamespacedHRField( + view_name="ouvertureport-detail", many=True, read_only=True + ) class Meta: model = machines.OuverturePortList - fields = ('name', 'tcp_ports_in', 'udp_ports_in', 'tcp_ports_out', - 'udp_ports_out', 'api_url') + fields = ( + "name", + "tcp_ports_in", + "udp_ports_in", + "tcp_ports_out", + "udp_ports_out", + "api_url", + ) class OuverturePortSerializer(NamespacedHMSerializer): @@ -342,17 +421,18 @@ class OuverturePortSerializer(NamespacedHMSerializer): class Meta: model = machines.OuverturePort - fields = ('begin', 'end', 'port_list', 'protocole', 'io', 'api_url') + fields = ("begin", "end", "port_list", "protocole", "io", "api_url") class RoleSerializer(NamespacedHMSerializer): """Serialize `machines.models.OuverturePort` objects. """ + servers = InterfaceSerializer(read_only=True, many=True) class Meta: model = machines.Role - fields = ('role_type', 'servers', 'api_url') + fields = ("role_type", "servers", "api_url") # PREFERENCES @@ -361,15 +441,22 @@ class RoleSerializer(NamespacedHMSerializer): class OptionalUserSerializer(NamespacedHMSerializer): """Serialize `preferences.models.OptionalUser` objects. """ - tel_mandatory = serializers.BooleanField(source='is_tel_mandatory') + + tel_mandatory = serializers.BooleanField(source="is_tel_mandatory") shell_default = serializers.StringRelatedField() class Meta: model = preferences.OptionalUser - fields = ('tel_mandatory', 'gpg_fingerprint', - 'all_can_create_club', 'self_adhesion', 'shell_default', - 'self_change_shell', 'local_email_accounts_enabled', 'local_email_domain', - 'max_email_address', + fields = ( + "tel_mandatory", + "gpg_fingerprint", + "all_can_create_club", + "self_adhesion", + "shell_default", + "self_change_shell", + "local_email_accounts_enabled", + "local_email_domain", + "max_email_address", ) @@ -379,22 +466,35 @@ class OptionalMachineSerializer(NamespacedHMSerializer): class Meta: model = preferences.OptionalMachine - fields = ('password_machine', 'max_lambdauser_interfaces', - 'max_lambdauser_aliases', 'ipv6_mode', 'create_machine', - 'ipv6') + fields = ( + "password_machine", + "max_lambdauser_interfaces", + "max_lambdauser_aliases", + "ipv6_mode", + "create_machine", + "ipv6", + ) class OptionalTopologieSerializer(NamespacedHMSerializer): """Serialize `preferences.models.OptionalTopologie` objects. """ + switchs_management_interface_ip = serializers.CharField() class Meta: model = preferences.OptionalTopologie - fields = ('switchs_ip_type', 'switchs_web_management', - 'switchs_web_management_ssl', 'switchs_rest_management', - 'switchs_management_utils', 'switchs_management_interface_ip', - 'provision_switchs_enabled', 'switchs_provision', 'switchs_management_sftp_creds') + fields = ( + "switchs_ip_type", + "switchs_web_management", + "switchs_web_management_ssl", + "switchs_rest_management", + "switchs_management_utils", + "switchs_management_interface_ip", + "provision_switchs_enabled", + "switchs_provision", + "switchs_management_sftp_creds", + ) class RadiusOptionSerializer(NamespacedHMSerializer): @@ -403,11 +503,20 @@ class RadiusOptionSerializer(NamespacedHMSerializer): class Meta: model = preferences.RadiusOption - fields = ('radius_general_policy', 'unknown_machine', - 'unknown_machine_vlan', 'unknown_port', - 'unknown_port_vlan', 'unknown_room', 'unknown_room_vlan', - 'non_member', 'non_member_vlan', 'banned', 'banned_vlan', - 'vlan_decision_ok') + fields = ( + "radius_general_policy", + "unknown_machine", + "unknown_machine_vlan", + "unknown_port", + "unknown_port_vlan", + "unknown_room", + "unknown_room_vlan", + "non_member", + "non_member_vlan", + "banned", + "banned_vlan", + "vlan_decision_ok", + ) class GeneralOptionSerializer(NamespacedHMSerializer): @@ -416,11 +525,20 @@ class GeneralOptionSerializer(NamespacedHMSerializer): class Meta: model = preferences.GeneralOption - fields = ('general_message_fr', 'general_message_en', - 'search_display_page', 'pagination_number', - 'pagination_large_number', 'req_expire_hrs', - 'site_name', 'main_site_url', 'email_from', - 'GTU_sum_up', 'GTU') + fields = ( + "general_message_fr", + "general_message_en", + "search_display_page", + "pagination_number", + "pagination_large_number", + "req_expire_hrs", + "site_name", + "main_site_url", + "email_from", + "GTU_sum_up", + "GTU", + ) + class HomeServiceSerializer(NamespacedHMSerializer): """Serialize `preferences.models.Service` objects. @@ -428,10 +546,8 @@ class HomeServiceSerializer(NamespacedHMSerializer): class Meta: model = preferences.Service - fields = ('name', 'url', 'description', 'image', 'api_url') - extra_kwargs = { - 'api_url': {'view_name': 'homeservice-detail'} - } + fields = ("name", "url", "description", "image", "api_url") + extra_kwargs = {"api_url": {"view_name": "homeservice-detail"}} class AssoOptionSerializer(NamespacedHMSerializer): @@ -440,8 +556,17 @@ class AssoOptionSerializer(NamespacedHMSerializer): class Meta: model = preferences.AssoOption - fields = ('name', 'siret', 'adresse1', 'adresse2', 'contact', - 'telephone', 'pseudo', 'utilisateur_asso', 'description') + fields = ( + "name", + "siret", + "adresse1", + "adresse2", + "contact", + "telephone", + "pseudo", + "utilisateur_asso", + "description", + ) class HomeOptionSerializer(NamespacedHMSerializer): @@ -450,7 +575,7 @@ class HomeOptionSerializer(NamespacedHMSerializer): class Meta: model = preferences.HomeOption - fields = ('facebook_url', 'twitter_url', 'twitter_account_name') + fields = ("facebook_url", "twitter_url", "twitter_account_name") class MailMessageOptionSerializer(NamespacedHMSerializer): @@ -459,7 +584,7 @@ class MailMessageOptionSerializer(NamespacedHMSerializer): class Meta: model = preferences.MailMessageOption - fields = ('welcome_mail_fr', 'welcome_mail_en') + fields = ("welcome_mail_fr", "welcome_mail_en") # TOPOLOGIE @@ -471,8 +596,14 @@ class StackSerializer(NamespacedHMSerializer): class Meta: model = topologie.Stack - fields = ('name', 'stack_id', 'details', 'member_id_min', - 'member_id_max', 'api_url') + fields = ( + "name", + "stack_id", + "details", + "member_id_min", + "member_id_max", + "api_url", + ) class AccessPointSerializer(NamespacedHMSerializer): @@ -481,18 +612,28 @@ class AccessPointSerializer(NamespacedHMSerializer): class Meta: model = topologie.AccessPoint - fields = ('user', 'name', 'active', 'location', 'api_url') + fields = ("user", "name", "active", "location", "api_url") class SwitchSerializer(NamespacedHMSerializer): """Serialize `topologie.models.Switch` objects """ - port_amount = serializers.IntegerField(source='number') + + port_amount = serializers.IntegerField(source="number") class Meta: model = topologie.Switch - fields = ('user', 'name', 'active', 'port_amount', 'stack', - 'stack_member_id', 'model', 'switchbay', 'api_url') + fields = ( + "user", + "name", + "active", + "port_amount", + "stack", + "stack_member_id", + "model", + "switchbay", + "api_url", + ) class ServerSerializer(NamespacedHMSerializer): @@ -501,7 +642,7 @@ class ServerSerializer(NamespacedHMSerializer): class Meta: model = topologie.Server - fields = ('user', 'name', 'active', 'api_url') + fields = ("user", "name", "active", "api_url") class ModelSwitchSerializer(NamespacedHMSerializer): @@ -510,7 +651,7 @@ class ModelSwitchSerializer(NamespacedHMSerializer): class Meta: model = topologie.ModelSwitch - fields = ('reference', 'constructor', 'api_url') + fields = ("reference", "constructor", "api_url") class ConstructorSwitchSerializer(NamespacedHMSerializer): @@ -519,7 +660,7 @@ class ConstructorSwitchSerializer(NamespacedHMSerializer): class Meta: model = topologie.ConstructorSwitch - fields = ('name', 'api_url') + fields = ("name", "api_url") class SwitchBaySerializer(NamespacedHMSerializer): @@ -528,7 +669,7 @@ class SwitchBaySerializer(NamespacedHMSerializer): class Meta: model = topologie.SwitchBay - fields = ('name', 'building', 'info', 'api_url') + fields = ("name", "building", "info", "api_url") class BuildingSerializer(NamespacedHMSerializer): @@ -537,34 +678,59 @@ class BuildingSerializer(NamespacedHMSerializer): class Meta: model = topologie.Building - fields = ('name', 'api_url') + fields = ("name", "api_url") class SwitchPortSerializer(NamespacedHMSerializer): """Serialize `topologie.models.Port` objects """ - get_port_profile = NamespacedHIField(view_name='portprofile-detail', read_only=True) + get_port_profile = NamespacedHIField(view_name="portprofile-detail", read_only=True) class Meta: model = topologie.Port - fields = ('switch', 'port', 'room', 'machine_interface', 'related', - 'custom_profile', 'state', 'get_port_profile', 'details', 'api_url') + fields = ( + "switch", + "port", + "room", + "machine_interface", + "related", + "custom_profile", + "state", + "get_port_profile", + "details", + "api_url", + ) extra_kwargs = { - 'related': {'view_name': 'switchport-detail'}, - 'api_url': {'view_name': 'switchport-detail'}, + "related": {"view_name": "switchport-detail"}, + "api_url": {"view_name": "switchport-detail"}, } class PortProfileSerializer(NamespacedHMSerializer): """Serialize `topologie.models.Room` objects """ + class Meta: model = topologie.PortProfile - fields = ('name', 'profil_default', 'vlan_untagged', 'vlan_tagged', - 'radius_type', 'radius_mode', 'speed', 'mac_limit', 'flow_control', - 'dhcp_snooping', 'dhcpv6_snooping', 'dhcpv6_snooping', 'arp_protect', - 'ra_guard', 'loop_protect', 'api_url') + fields = ( + "name", + "profil_default", + "vlan_untagged", + "vlan_tagged", + "radius_type", + "radius_mode", + "speed", + "mac_limit", + "flow_control", + "dhcp_snooping", + "dhcpv6_snooping", + "dhcpv6_snooping", + "arp_protect", + "ra_guard", + "loop_protect", + "api_url", + ) class RoomSerializer(NamespacedHMSerializer): @@ -573,7 +739,7 @@ class RoomSerializer(NamespacedHMSerializer): class Meta: model = topologie.Room - fields = ('name', 'details', 'api_url') + fields = ("name", "details", "api_url") class PortProfileSerializer(NamespacedHMSerializer): @@ -581,11 +747,24 @@ class PortProfileSerializer(NamespacedHMSerializer): class Meta: model = topologie.PortProfile - fields = ('name', 'profil_default', 'vlan_untagged', 'vlan_tagged', - 'radius_type', 'radius_mode', 'speed', 'mac_limit', - 'flow_control', 'dhcp_snooping', 'dhcpv6_snooping', - 'arp_protect', 'ra_guard', 'loop_protect', 'vlan_untagged', - 'vlan_tagged') + fields = ( + "name", + "profil_default", + "vlan_untagged", + "vlan_tagged", + "radius_type", + "radius_mode", + "speed", + "mac_limit", + "flow_control", + "dhcp_snooping", + "dhcpv6_snooping", + "arp_protect", + "ra_guard", + "loop_protect", + "vlan_untagged", + "vlan_tagged", + ) # USERS @@ -594,64 +773,111 @@ class PortProfileSerializer(NamespacedHMSerializer): class UserSerializer(NamespacedHMSerializer): """Serialize `users.models.User` objects. """ - access = serializers.BooleanField(source='has_access') - uid = serializers.IntegerField(source='uid_number') + + access = serializers.BooleanField(source="has_access") + uid = serializers.IntegerField(source="uid_number") class Meta: model = users.User - fields = ('surname', 'pseudo', 'email', 'local_email_redirect', - 'local_email_enabled', 'school', 'shell', 'comment', - 'state', 'registered', 'telephone', 'solde', 'access', - 'end_access', 'uid', 'class_name', 'api_url') - extra_kwargs = { - 'shell': {'view_name': 'shell-detail'} - } + fields = ( + "surname", + "pseudo", + "email", + "local_email_redirect", + "local_email_enabled", + "school", + "shell", + "comment", + "state", + "registered", + "telephone", + "solde", + "access", + "end_access", + "uid", + "class_name", + "api_url", + ) + extra_kwargs = {"shell": {"view_name": "shell-detail"}} class ClubSerializer(NamespacedHMSerializer): """Serialize `users.models.Club` objects. """ - name = serializers.CharField(source='surname') - access = serializers.BooleanField(source='has_access') - uid = serializers.IntegerField(source='uid_number') + + name = serializers.CharField(source="surname") + access = serializers.BooleanField(source="has_access") + uid = serializers.IntegerField(source="uid_number") class Meta: model = users.Club - fields = ('name', 'pseudo', 'email', 'local_email_redirect', - 'local_email_enabled', 'school', 'shell', 'comment', - 'state', 'registered', 'telephone', 'solde', 'room', - 'access', 'end_access', 'administrators', 'members', - 'mailing', 'uid', 'api_url') - extra_kwargs = { - 'shell': {'view_name': 'shell-detail'} - } + fields = ( + "name", + "pseudo", + "email", + "local_email_redirect", + "local_email_enabled", + "school", + "shell", + "comment", + "state", + "registered", + "telephone", + "solde", + "room", + "access", + "end_access", + "administrators", + "members", + "mailing", + "uid", + "api_url", + ) + extra_kwargs = {"shell": {"view_name": "shell-detail"}} class AdherentSerializer(NamespacedHMSerializer): """Serialize `users.models.Adherent` objects. """ - access = serializers.BooleanField(source='has_access') - uid = serializers.IntegerField(source='uid_number') + + access = serializers.BooleanField(source="has_access") + uid = serializers.IntegerField(source="uid_number") class Meta: model = users.Adherent - fields = ('name', 'surname', 'pseudo', 'email', 'local_email_redirect', - 'local_email_enabled', 'school', 'shell', 'comment', - 'state', 'registered', 'telephone', 'room', 'solde', - 'access', 'end_access', 'uid', 'api_url', 'gid') - extra_kwargs = { - 'shell': {'view_name': 'shell-detail'} - } + fields = ( + "name", + "surname", + "pseudo", + "email", + "local_email_redirect", + "local_email_enabled", + "school", + "shell", + "comment", + "state", + "registered", + "telephone", + "room", + "solde", + "access", + "end_access", + "uid", + "api_url", + "gid", + ) + extra_kwargs = {"shell": {"view_name": "shell-detail"}} class BasicUserSerializer(NamespacedHMSerializer): """Serialize 'users.models.User' minimal infos""" - uid = serializers.IntegerField(source='uid_number') - gid = serializers.IntegerField(source='gid_number') + + uid = serializers.IntegerField(source="uid_number") + gid = serializers.IntegerField(source="gid_number") class Meta: model = users.User - fields = ('pseudo', 'uid', 'gid') + fields = ("pseudo", "uid", "gid") class ServiceUserSerializer(NamespacedHMSerializer): @@ -660,7 +886,7 @@ class ServiceUserSerializer(NamespacedHMSerializer): class Meta: model = users.ServiceUser - fields = ('pseudo', 'access_group', 'comment', 'api_url') + fields = ("pseudo", "access_group", "comment", "api_url") class SchoolSerializer(NamespacedHMSerializer): @@ -669,7 +895,7 @@ class SchoolSerializer(NamespacedHMSerializer): class Meta: model = users.School - fields = ('name', 'api_url') + fields = ("name", "api_url") class ListRightSerializer(NamespacedHMSerializer): @@ -678,7 +904,7 @@ class ListRightSerializer(NamespacedHMSerializer): class Meta: model = users.ListRight - fields = ('unix_name', 'gid', 'critical', 'details', 'api_url') + fields = ("unix_name", "gid", "critical", "details", "api_url") class ShellSerializer(NamespacedHMSerializer): @@ -687,41 +913,49 @@ class ShellSerializer(NamespacedHMSerializer): class Meta: model = users.ListShell - fields = ('shell', 'api_url') - extra_kwargs = { - 'api_url': {'view_name': 'shell-detail'} - } + fields = ("shell", "api_url") + extra_kwargs = {"api_url": {"view_name": "shell-detail"}} class BanSerializer(NamespacedHMSerializer): """Serialize `users.models.Ban` objects. """ - active = serializers.BooleanField(source='is_active') + + active = serializers.BooleanField(source="is_active") class Meta: model = users.Ban - fields = ('user', 'raison', 'date_start', 'date_end', 'state', - 'active', 'api_url') + fields = ( + "user", + "raison", + "date_start", + "date_end", + "state", + "active", + "api_url", + ) class WhitelistSerializer(NamespacedHMSerializer): """Serialize `users.models.Whitelist` objects. """ - active = serializers.BooleanField(source='is_active') + + active = serializers.BooleanField(source="is_active") class Meta: model = users.Whitelist - fields = ('user', 'raison', 'date_start', 'date_end', 'active', 'api_url') + fields = ("user", "raison", "date_start", "date_end", "active", "api_url") class EMailAddressSerializer(NamespacedHMSerializer): """Serialize `users.models.EMailAddress` objects. """ - user = serializers.CharField(source='user.pseudo', read_only=True) + + user = serializers.CharField(source="user.pseudo", read_only=True) class Meta: model = users.EMailAddress - fields = ('user', 'local_part', 'complete_email_address', 'api_url') + fields = ("user", "local_part", "complete_email_address", "api_url") # SERVICE REGEN @@ -730,51 +964,58 @@ class EMailAddressSerializer(NamespacedHMSerializer): class ServiceRegenSerializer(NamespacedHMSerializer): """Serialize the data about the services to regen. """ - hostname = serializers.CharField(source='server.domain.name', read_only=True) - service_name = serializers.CharField(source='service.service_type', read_only=True) + + hostname = serializers.CharField(source="server.domain.name", read_only=True) + service_name = serializers.CharField(source="service.service_type", read_only=True) need_regen = serializers.BooleanField() class Meta: model = machines.Service_link - fields = ('hostname', 'service_name', 'need_regen', 'api_url') - extra_kwargs = { - 'api_url': {'view_name': 'serviceregen-detail'} - } + fields = ("hostname", "service_name", "need_regen", "api_url") + extra_kwargs = {"api_url": {"view_name": "serviceregen-detail"}} + # Switches et ports + class InterfaceVlanSerializer(NamespacedHMSerializer): domain = serializers.CharField(read_only=True) ipv4 = serializers.CharField(read_only=True) ipv6 = Ipv6ListSerializer(read_only=True, many=True) - vlan_id = serializers.IntegerField(source='machine_type.ip_type.vlan.vlan_id', read_only=True) + vlan_id = serializers.IntegerField( + source="machine_type.ip_type.vlan.vlan_id", read_only=True + ) class Meta: model = machines.Interface - fields = ('ipv4', 'ipv6', 'domain', 'vlan_id') + fields = ("ipv4", "ipv6", "domain", "vlan_id") + class InterfaceRoleSerializer(NamespacedHMSerializer): - interface = InterfaceVlanSerializer(source='machine.interface_set', read_only=True, many=True) + interface = InterfaceVlanSerializer( + source="machine.interface_set", read_only=True, many=True + ) class Meta: model = machines.Interface - fields = ('interface',) + fields = ("interface",) class RoleSerializer(NamespacedHMSerializer): """Serialize `machines.models.OuverturePort` objects. """ + servers = InterfaceRoleSerializer(read_only=True, many=True) class Meta: model = machines.Role - fields = ('role_type', 'servers', 'specific_role') + fields = ("role_type", "servers", "specific_role") class VlanPortSerializer(NamespacedHMSerializer): class Meta: model = machines.Vlan - fields = ('vlan_id', 'name') + fields = ("vlan_id", "name") class ProfilSerializer(NamespacedHMSerializer): @@ -783,7 +1024,24 @@ class ProfilSerializer(NamespacedHMSerializer): class Meta: model = topologie.PortProfile - fields = ('name', 'profil_default', 'vlan_untagged', 'vlan_tagged', 'radius_type', 'radius_mode', 'speed', 'mac_limit', 'flow_control', 'dhcp_snooping', 'dhcpv6_snooping', 'arp_protect', 'ra_guard', 'loop_protect', 'vlan_untagged', 'vlan_tagged') + fields = ( + "name", + "profil_default", + "vlan_untagged", + "vlan_tagged", + "radius_type", + "radius_mode", + "speed", + "mac_limit", + "flow_control", + "dhcp_snooping", + "dhcpv6_snooping", + "arp_protect", + "ra_guard", + "loop_protect", + "vlan_untagged", + "vlan_tagged", + ) class ModelSwitchSerializer(NamespacedHMSerializer): @@ -791,62 +1049,77 @@ class ModelSwitchSerializer(NamespacedHMSerializer): class Meta: model = topologie.ModelSwitch - fields = ('reference', 'firmware', 'constructor') + fields = ("reference", "firmware", "constructor") class SwitchBaySerializer(NamespacedHMSerializer): class Meta: model = topologie.SwitchBay - fields = ('name',) + fields = ("name",) class PortsSerializer(NamespacedHMSerializer): """Serialize `machines.models.Ipv6List` objects. """ - get_port_profile = ProfilSerializer(read_only=True) + get_port_profile = ProfilSerializer(read_only=True) class Meta: model = topologie.Port - fields = ('state', 'port', 'pretty_name', 'get_port_profile') - + fields = ("state", "port", "pretty_name", "get_port_profile") class SwitchPortSerializer(serializers.ModelSerializer): """Serialize the data about the switches""" + ports = PortsSerializer(many=True, read_only=True) model = ModelSwitchSerializer(read_only=True) switchbay = SwitchBaySerializer(read_only=True) - class Meta: model = topologie.Switch - fields = ('short_name', 'model', 'switchbay', 'ports', 'ipv4', 'ipv6', - 'interfaces_subnet', 'interfaces6_subnet', 'automatic_provision', 'rest_enabled', - 'web_management_enabled', 'get_radius_key_value', 'get_management_cred_value', - 'get_radius_servers', 'list_modules') + fields = ( + "short_name", + "model", + "switchbay", + "ports", + "ipv4", + "ipv6", + "interfaces_subnet", + "interfaces6_subnet", + "automatic_provision", + "rest_enabled", + "web_management_enabled", + "get_radius_key_value", + "get_management_cred_value", + "get_radius_servers", + "list_modules", + ) + # LOCAL EMAILS class LocalEmailUsersSerializer(NamespacedHMSerializer): - email_address = EMailAddressSerializer( - read_only=True, - many=True - ) + email_address = EMailAddressSerializer(read_only=True, many=True) class Meta: model = users.User - fields = ('local_email_enabled', 'local_email_redirect', - 'email_address', 'email') + fields = ( + "local_email_enabled", + "local_email_redirect", + "email_address", + "email", + ) # Firewall + class FirewallPortListSerializer(serializers.ModelSerializer): class Meta: model = machines.OuverturePort - fields = ('begin', 'end', 'protocole', 'io', 'show_port') + fields = ("begin", "end", "protocole", "io", "show_port") class FirewallOuverturePortListSerializer(serializers.ModelSerializer): @@ -857,7 +1130,7 @@ class FirewallOuverturePortListSerializer(serializers.ModelSerializer): class Meta: model = machines.OuverturePortList - fields = ('tcp_ports_in', 'udp_ports_in', 'tcp_ports_out', 'udp_ports_out') + fields = ("tcp_ports_in", "udp_ports_in", "tcp_ports_out", "udp_ports_out") class SubnetPortsOpenSerializer(serializers.ModelSerializer): @@ -865,17 +1138,23 @@ class SubnetPortsOpenSerializer(serializers.ModelSerializer): class Meta: model = machines.IpType - fields = ('name', 'domaine_ip_start', 'domaine_ip_stop', 'complete_prefixv6', 'ouverture_ports') + fields = ( + "name", + "domaine_ip_start", + "domaine_ip_stop", + "complete_prefixv6", + "ouverture_ports", + ) class InterfacePortsOpenSerializer(serializers.ModelSerializer): port_lists = FirewallOuverturePortListSerializer(read_only=True, many=True) - ipv4 = serializers.CharField(source='ipv4.ipv4', read_only=True) + ipv4 = serializers.CharField(source="ipv4.ipv4", read_only=True) ipv6 = Ipv6ListSerializer(many=True, read_only=True) class Meta: model = machines.Interface - fields = ('port_lists', 'ipv4', 'ipv6') + fields = ("port_lists", "ipv4", "ipv6") # DHCP @@ -885,14 +1164,15 @@ class HostMacIpSerializer(serializers.ModelSerializer): """Serialize the data about the hostname-ipv4-mac address association to build the DHCP lease files. """ - hostname = serializers.CharField(source='domain.name', read_only=True) - extension = serializers.CharField(source='domain.extension.name', read_only=True) + + hostname = serializers.CharField(source="domain.name", read_only=True) + extension = serializers.CharField(source="domain.extension.name", read_only=True) mac_address = serializers.CharField(read_only=True) - ipv4 = serializers.CharField(source='ipv4.ipv4', read_only=True) + ipv4 = serializers.CharField(source="ipv4.ipv4", read_only=True) class Meta: model = machines.Interface - fields = ('hostname', 'extension', 'mac_address', 'ipv4') + fields = ("hostname", "extension", "mac_address", "ipv4") # DNS @@ -905,7 +1185,7 @@ class SOARecordSerializer(SOASerializer): class Meta: model = machines.SOA - fields = ('name', 'mail', 'refresh', 'retry', 'expire', 'ttl') + fields = ("name", "mail", "refresh", "retry", "expire", "ttl") class OriginV4RecordSerializer(IpListSerializer): @@ -914,27 +1194,29 @@ class OriginV4RecordSerializer(IpListSerializer): """ class Meta(IpListSerializer.Meta): - fields = ('ipv4',) + fields = ("ipv4",) class NSRecordSerializer(NsSerializer): """Serialize `machines.models.Ns` objects with the data needed to generate a NS DNS record. """ - target = serializers.CharField(source='ns', read_only=True) + + target = serializers.CharField(source="ns", read_only=True) class Meta(NsSerializer.Meta): - fields = ('target',) + fields = ("target",) class MXRecordSerializer(MxSerializer): """Serialize `machines.models.Mx` objects with the data needed to generate a MX DNS record. """ - target = serializers.CharField(source='name', read_only=True) + + target = serializers.CharField(source="name", read_only=True) class Meta(MxSerializer.Meta): - fields = ('target', 'priority') + fields = ("target", "priority") class TXTRecordSerializer(TxtSerializer): @@ -943,17 +1225,18 @@ class TXTRecordSerializer(TxtSerializer): """ class Meta(TxtSerializer.Meta): - fields = ('field1', 'field2') + fields = ("field1", "field2") class SRVRecordSerializer(SrvSerializer): """Serialize `machines.models.Srv` objects with the data needed to generate a SRV DNS record. """ - target = serializers.CharField(source='target.name', read_only=True) + + target = serializers.CharField(source="target.name", read_only=True) class Meta(SrvSerializer.Meta): - fields = ('service', 'protocole', 'ttl', 'priority', 'weight', 'port', 'target') + fields = ("service", "protocole", "ttl", "priority", "weight", "port", "target") class SSHFPRecordSerializer(SshFpSerializer): @@ -962,127 +1245,171 @@ class SSHFPRecordSerializer(SshFpSerializer): """ class Meta(SshFpSerializer.Meta): - fields = ('algo_id', 'hash') + fields = ("algo_id", "hash") class SSHFPInterfaceSerializer(serializers.ModelSerializer): """Serialize `machines.models.Domain` objects with the data needed to generate a CNAME DNS record. """ - hostname = serializers.CharField(source='domain.name', read_only=True) - sshfp = SSHFPRecordSerializer(source='machine.sshfp_set', many=True, read_only=True) + + hostname = serializers.CharField(source="domain.name", read_only=True) + sshfp = SSHFPRecordSerializer(source="machine.sshfp_set", many=True, read_only=True) class Meta: model = machines.Interface - fields = ('hostname', 'sshfp') + fields = ("hostname", "sshfp") class ARecordSerializer(serializers.ModelSerializer): """Serialize `machines.models.Interface` objects with the data needed to generate a A DNS record. """ - hostname = serializers.CharField(source='domain.name', read_only=True) - ipv4 = serializers.CharField(source='ipv4.ipv4', read_only=True) + + hostname = serializers.CharField(source="domain.name", read_only=True) + ipv4 = serializers.CharField(source="ipv4.ipv4", read_only=True) class Meta: model = machines.Interface - fields = ('hostname', 'ipv4') + fields = ("hostname", "ipv4") class AAAARecordSerializer(serializers.ModelSerializer): """Serialize `machines.models.Interface` objects with the data needed to generate a AAAA DNS record. """ - hostname = serializers.CharField(source='domain.name', read_only=True) + + hostname = serializers.CharField(source="domain.name", read_only=True) ipv6 = Ipv6ListSerializer(many=True, read_only=True) class Meta: model = machines.Interface - fields = ('hostname', 'ipv6') + fields = ("hostname", "ipv6") class CNAMERecordSerializer(serializers.ModelSerializer): """Serialize `machines.models.Domain` objects with the data needed to generate a CNAME DNS record. """ - alias = serializers.CharField(source='cname', read_only=True) - hostname = serializers.CharField(source='name', read_only=True) + + alias = serializers.CharField(source="cname", read_only=True) + hostname = serializers.CharField(source="name", read_only=True) class Meta: model = machines.Domain - fields = ('alias', 'hostname') + fields = ("alias", "hostname") + class DNAMERecordSerializer(serializers.ModelSerializer): """Serialize `machines.models.Domain` objects with the data needed to generate a DNAME DNS record. """ + alias = serializers.CharField(read_only=True) zone = serializers.CharField(read_only=True) class Meta: model = machines.DName - fields = ('alias', 'zone') + fields = ("alias", "zone") class DNSZonesSerializer(serializers.ModelSerializer): """Serialize the data about DNS Zones. """ + soa = SOARecordSerializer() - ns_records = NSRecordSerializer(many=True, source='ns_set') - originv4 = OriginV4RecordSerializer(source='origin') - originv6 = serializers.CharField(source='origin_v6') - mx_records = MXRecordSerializer(many=True, source='mx_set') - txt_records = TXTRecordSerializer(many=True, source='txt_set') - srv_records = SRVRecordSerializer(many=True, source='srv_set') - a_records = ARecordSerializer(many=True, source='get_associated_a_records') - aaaa_records = AAAARecordSerializer(many=True, source='get_associated_aaaa_records') - cname_records = CNAMERecordSerializer(many=True, source='get_associated_cname_records') - dname_records = DNAMERecordSerializer(many=True, source='get_associated_dname_records') - sshfp_records = SSHFPInterfaceSerializer(many=True, source='get_associated_sshfp_records') + ns_records = NSRecordSerializer(many=True, source="ns_set") + originv4 = OriginV4RecordSerializer(source="origin") + originv6 = serializers.CharField(source="origin_v6") + mx_records = MXRecordSerializer(many=True, source="mx_set") + txt_records = TXTRecordSerializer(many=True, source="txt_set") + srv_records = SRVRecordSerializer(many=True, source="srv_set") + a_records = ARecordSerializer(many=True, source="get_associated_a_records") + aaaa_records = AAAARecordSerializer(many=True, source="get_associated_aaaa_records") + cname_records = CNAMERecordSerializer( + many=True, source="get_associated_cname_records" + ) + dname_records = DNAMERecordSerializer( + many=True, source="get_associated_dname_records" + ) + sshfp_records = SSHFPInterfaceSerializer( + many=True, source="get_associated_sshfp_records" + ) class Meta: model = machines.Extension - fields = ('name', 'soa', 'ns_records', 'originv4', 'originv6', - 'mx_records', 'txt_records', 'srv_records', 'a_records', - 'aaaa_records', 'cname_records', 'dname_records', 'sshfp_records') -#REMINDER + fields = ( + "name", + "soa", + "ns_records", + "originv4", + "originv6", + "mx_records", + "txt_records", + "srv_records", + "a_records", + "aaaa_records", + "cname_records", + "dname_records", + "sshfp_records", + ) + + +# REMINDER class ReminderUsersSerializer(UserSerializer): """Serialize the data about a mailing member. """ + class Meta(UserSerializer.Meta): - fields = ('get_full_name', 'get_mail') + fields = ("get_full_name", "get_mail") class ReminderSerializer(serializers.ModelSerializer): """ Serialize the data about a reminder """ + users_to_remind = ReminderUsersSerializer(many=True) class Meta: model = preferences.Reminder - fields = ('days','message','users_to_remind') + fields = ("days", "message", "users_to_remind") class DNSReverseZonesSerializer(serializers.ModelSerializer): """Serialize the data about DNS Zones. """ - soa = SOARecordSerializer(source='extension.soa') - extension = serializers.CharField(source='extension.name', read_only=True) - cidrs = serializers.ListField(child=serializers.CharField(), source='ip_set_cidrs_as_str', read_only=True) - ns_records = NSRecordSerializer(many=True, source='extension.ns_set') - mx_records = MXRecordSerializer(many=True, source='extension.mx_set') - txt_records = TXTRecordSerializer(many=True, source='extension.txt_set') - ptr_records = ARecordSerializer(many=True, source='get_associated_ptr_records') - ptr_v6_records = AAAARecordSerializer(many=True, source='get_associated_ptr_v6_records') + + soa = SOARecordSerializer(source="extension.soa") + extension = serializers.CharField(source="extension.name", read_only=True) + cidrs = serializers.ListField( + child=serializers.CharField(), source="ip_set_cidrs_as_str", read_only=True + ) + ns_records = NSRecordSerializer(many=True, source="extension.ns_set") + mx_records = MXRecordSerializer(many=True, source="extension.mx_set") + txt_records = TXTRecordSerializer(many=True, source="extension.txt_set") + ptr_records = ARecordSerializer(many=True, source="get_associated_ptr_records") + ptr_v6_records = AAAARecordSerializer( + many=True, source="get_associated_ptr_v6_records" + ) class Meta: model = machines.IpType - fields = ('name', 'extension', 'soa', 'ns_records', 'mx_records', - 'txt_records', 'ptr_records', 'ptr_v6_records', 'cidrs', - 'prefix_v6', 'prefix_v6_length') + fields = ( + "name", + "extension", + "soa", + "ns_records", + "mx_records", + "txt_records", + "ptr_records", + "ptr_v6_records", + "cidrs", + "prefix_v6", + "prefix_v6_length", + ) # MAILING @@ -1093,14 +1420,15 @@ class MailingMemberSerializer(UserSerializer): """ class Meta(UserSerializer.Meta): - fields = ('name', 'pseudo', 'get_mail') + fields = ("name", "pseudo", "get_mail") class MailingSerializer(ClubSerializer): """Serialize the data about a mailing. """ + members = MailingMemberSerializer(many=True) - admins = MailingMemberSerializer(source='administrators', many=True) + admins = MailingMemberSerializer(source="administrators", many=True) class Meta(ClubSerializer.Meta): - fields = ('name', 'members', 'admins') + fields = ("name", "members", "admins") diff --git a/api/settings.py b/api/settings.py index 0ddf5d69..1435aee6 100644 --- a/api/settings.py +++ b/api/settings.py @@ -24,28 +24,24 @@ # RestFramework config for API REST_FRAMEWORK = { - 'URL_FIELD_NAME': 'api_url', - 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'api.authentication.ExpiringTokenAuthentication', - 'rest_framework.authentication.SessionAuthentication', + "URL_FIELD_NAME": "api_url", + "DEFAULT_AUTHENTICATION_CLASSES": ( + "api.authentication.ExpiringTokenAuthentication", + "rest_framework.authentication.SessionAuthentication", ), - 'DEFAULT_PERMISSION_CLASSES': ( - 'api.permissions.AutodetectACLPermission', - ), - 'DEFAULT_PAGINATION_CLASS': 'api.pagination.PageSizedPagination', - 'PAGE_SIZE': 100 + "DEFAULT_PERMISSION_CLASSES": ("api.permissions.AutodetectACLPermission",), + "DEFAULT_PAGINATION_CLASS": "api.pagination.PageSizedPagination", + "PAGE_SIZE": 100, } # API permission settings -API_CONTENT_TYPE_APP_LABEL = 'api' -API_CONTENT_TYPE_MODEL = 'api' -API_PERMISSION_NAME = 'Can use the API' -API_PERMISSION_CODENAME = 'use_api' +API_CONTENT_TYPE_APP_LABEL = "api" +API_CONTENT_TYPE_MODEL = "api" +API_PERMISSION_NAME = "Can use the API" +API_PERMISSION_CODENAME = "use_api" # Activate token authentication -API_APPS = ( - 'rest_framework.authtoken', -) +API_APPS = ("rest_framework.authtoken",) # The expiration time for an authentication token API_TOKEN_DURATION = 86400 # 24 hours diff --git a/api/tests.py b/api/tests.py index 5c244152..df0b7a7d 100644 --- a/api/tests.py +++ b/api/tests.py @@ -50,171 +50,170 @@ class APIEndpointsTestCase(APITestCase): superuser: A superuser (with all permissions) used for the tests and initialized at the beggining of this test case. """ - no_auth_endpoints = [ - '/api/' - ] + + no_auth_endpoints = ["/api/"] auth_no_perm_endpoints = [] auth_perm_endpoints = [ - '/api/cotisations/article/', - '/api/cotisations/article/1/', - '/api/cotisations/banque/', - '/api/cotisations/banque/1/', - '/api/cotisations/cotisation/', - '/api/cotisations/cotisation/1/', - '/api/cotisations/facture/', - '/api/cotisations/facture/1/', - '/api/cotisations/paiement/', - '/api/cotisations/paiement/1/', - '/api/cotisations/vente/', - '/api/cotisations/vente/1/', - '/api/machines/domain/', - '/api/machines/domain/1/', - '/api/machines/extension/', - '/api/machines/extension/1/', - '/api/machines/interface/', - '/api/machines/interface/1/', - '/api/machines/iplist/', - '/api/machines/iplist/1/', - '/api/machines/iptype/', - '/api/machines/iptype/1/', - '/api/machines/ipv6list/', - '/api/machines/ipv6list/1/', - '/api/machines/machine/', - '/api/machines/machine/1/', - '/api/machines/machinetype/', - '/api/machines/machinetype/1/', - '/api/machines/mx/', - '/api/machines/mx/1/', - '/api/machines/nas/', - '/api/machines/nas/1/', - '/api/machines/ns/', - '/api/machines/ns/1/', - '/api/machines/ouvertureportlist/', - '/api/machines/ouvertureportlist/1/', - '/api/machines/ouvertureport/', - '/api/machines/ouvertureport/1/', - '/api/machines/servicelink/', - '/api/machines/servicelink/1/', - '/api/machines/service/', - '/api/machines/service/1/', - '/api/machines/soa/', - '/api/machines/soa/1/', - '/api/machines/srv/', - '/api/machines/srv/1/', - '/api/machines/txt/', - '/api/machines/txt/1/', - '/api/machines/vlan/', - '/api/machines/vlan/1/', - '/api/preferences/optionaluser/', - '/api/preferences/optionalmachine/', - '/api/preferences/optionaltopologie/', - '/api/preferences/generaloption/', - '/api/preferences/service/', - '/api/preferences/service/1/', - '/api/preferences/assooption/', - '/api/preferences/homeoption/', - '/api/preferences/mailmessageoption/', - '/api/topologie/acesspoint/', + "/api/cotisations/article/", + "/api/cotisations/article/1/", + "/api/cotisations/banque/", + "/api/cotisations/banque/1/", + "/api/cotisations/cotisation/", + "/api/cotisations/cotisation/1/", + "/api/cotisations/facture/", + "/api/cotisations/facture/1/", + "/api/cotisations/paiement/", + "/api/cotisations/paiement/1/", + "/api/cotisations/vente/", + "/api/cotisations/vente/1/", + "/api/machines/domain/", + "/api/machines/domain/1/", + "/api/machines/extension/", + "/api/machines/extension/1/", + "/api/machines/interface/", + "/api/machines/interface/1/", + "/api/machines/iplist/", + "/api/machines/iplist/1/", + "/api/machines/iptype/", + "/api/machines/iptype/1/", + "/api/machines/ipv6list/", + "/api/machines/ipv6list/1/", + "/api/machines/machine/", + "/api/machines/machine/1/", + "/api/machines/machinetype/", + "/api/machines/machinetype/1/", + "/api/machines/mx/", + "/api/machines/mx/1/", + "/api/machines/nas/", + "/api/machines/nas/1/", + "/api/machines/ns/", + "/api/machines/ns/1/", + "/api/machines/ouvertureportlist/", + "/api/machines/ouvertureportlist/1/", + "/api/machines/ouvertureport/", + "/api/machines/ouvertureport/1/", + "/api/machines/servicelink/", + "/api/machines/servicelink/1/", + "/api/machines/service/", + "/api/machines/service/1/", + "/api/machines/soa/", + "/api/machines/soa/1/", + "/api/machines/srv/", + "/api/machines/srv/1/", + "/api/machines/txt/", + "/api/machines/txt/1/", + "/api/machines/vlan/", + "/api/machines/vlan/1/", + "/api/preferences/optionaluser/", + "/api/preferences/optionalmachine/", + "/api/preferences/optionaltopologie/", + "/api/preferences/generaloption/", + "/api/preferences/service/", + "/api/preferences/service/1/", + "/api/preferences/assooption/", + "/api/preferences/homeoption/", + "/api/preferences/mailmessageoption/", + "/api/topologie/acesspoint/", # 2nd machine to be create (machines_machine_1, topologie_accesspoint_1) - '/api/topologie/acesspoint/2/', - '/api/topologie/building/', - '/api/topologie/building/1/', - '/api/topologie/constructorswitch/', - '/api/topologie/constructorswitch/1/', - '/api/topologie/modelswitch/', - '/api/topologie/modelswitch/1/', - '/api/topologie/room/', - '/api/topologie/room/1/', - '/api/topologie/server/', + "/api/topologie/acesspoint/2/", + "/api/topologie/building/", + "/api/topologie/building/1/", + "/api/topologie/constructorswitch/", + "/api/topologie/constructorswitch/1/", + "/api/topologie/modelswitch/", + "/api/topologie/modelswitch/1/", + "/api/topologie/room/", + "/api/topologie/room/1/", + "/api/topologie/server/", # 3rd machine to be create (machines_machine_1, topologie_accesspoint_1, # topologie_server_1) - '/api/topologie/server/3/', - '/api/topologie/stack/', - '/api/topologie/stack/1/', - '/api/topologie/switch/', + "/api/topologie/server/3/", + "/api/topologie/stack/", + "/api/topologie/stack/1/", + "/api/topologie/switch/", # 4th machine to be create (machines_machine_1, topologie_accesspoint_1, # topologie_server_1, topologie_switch_1) - '/api/topologie/switch/4/', - '/api/topologie/switchbay/', - '/api/topologie/switchbay/1/', - '/api/topologie/switchport/', - '/api/topologie/switchport/1/', - '/api/topologie/switchport/2/', - '/api/topologie/switchport/3/', - '/api/users/adherent/', + "/api/topologie/switch/4/", + "/api/topologie/switchbay/", + "/api/topologie/switchbay/1/", + "/api/topologie/switchport/", + "/api/topologie/switchport/1/", + "/api/topologie/switchport/2/", + "/api/topologie/switchport/3/", + "/api/users/adherent/", # 3rd user to be create (stduser, superuser, users_adherent_1) - '/api/users/adherent/3/', - '/api/users/ban/', - '/api/users/ban/1/', - '/api/users/club/', + "/api/users/adherent/3/", + "/api/users/ban/", + "/api/users/ban/1/", + "/api/users/club/", # 4th user to be create (stduser, superuser, users_adherent_1, # users_club_1) - '/api/users/club/4/', - '/api/users/listright/', + "/api/users/club/4/", + "/api/users/listright/", # TODO: Merge !145 # '/api/users/listright/1/', - '/api/users/school/', - '/api/users/school/1/', - '/api/users/serviceuser/', - '/api/users/serviceuser/1/', - '/api/users/shell/', - '/api/users/shell/1/', - '/api/users/user/', - '/api/users/user/1/', - '/api/users/whitelist/', - '/api/users/whitelist/1/', - '/api/dns/zones/', - '/api/dhcp/hostmacip/', - '/api/mailing/standard', - '/api/mailing/club', - '/api/services/regen/', + "/api/users/school/", + "/api/users/school/1/", + "/api/users/serviceuser/", + "/api/users/serviceuser/1/", + "/api/users/shell/", + "/api/users/shell/1/", + "/api/users/user/", + "/api/users/user/1/", + "/api/users/whitelist/", + "/api/users/whitelist/1/", + "/api/dns/zones/", + "/api/dhcp/hostmacip/", + "/api/mailing/standard", + "/api/mailing/club", + "/api/services/regen/", ] not_found_endpoints = [ - '/api/cotisations/article/4242/', - '/api/cotisations/banque/4242/', - '/api/cotisations/cotisation/4242/', - '/api/cotisations/facture/4242/', - '/api/cotisations/paiement/4242/', - '/api/cotisations/vente/4242/', - '/api/machines/domain/4242/', - '/api/machines/extension/4242/', - '/api/machines/interface/4242/', - '/api/machines/iplist/4242/', - '/api/machines/iptype/4242/', - '/api/machines/ipv6list/4242/', - '/api/machines/machine/4242/', - '/api/machines/machinetype/4242/', - '/api/machines/mx/4242/', - '/api/machines/nas/4242/', - '/api/machines/ns/4242/', - '/api/machines/ouvertureportlist/4242/', - '/api/machines/ouvertureport/4242/', - '/api/machines/servicelink/4242/', - '/api/machines/service/4242/', - '/api/machines/soa/4242/', - '/api/machines/srv/4242/', - '/api/machines/txt/4242/', - '/api/machines/vlan/4242/', - '/api/preferences/service/4242/', - '/api/topologie/acesspoint/4242/', - '/api/topologie/building/4242/', - '/api/topologie/constructorswitch/4242/', - '/api/topologie/modelswitch/4242/', - '/api/topologie/room/4242/', - '/api/topologie/server/4242/', - '/api/topologie/stack/4242/', - '/api/topologie/switch/4242/', - '/api/topologie/switchbay/4242/', - '/api/topologie/switchport/4242/', - '/api/users/adherent/4242/', - '/api/users/ban/4242/', - '/api/users/club/4242/', - '/api/users/listright/4242/', - '/api/users/school/4242/', - '/api/users/serviceuser/4242/', - '/api/users/shell/4242/', - '/api/users/user/4242/', - '/api/users/whitelist/4242/', + "/api/cotisations/article/4242/", + "/api/cotisations/banque/4242/", + "/api/cotisations/cotisation/4242/", + "/api/cotisations/facture/4242/", + "/api/cotisations/paiement/4242/", + "/api/cotisations/vente/4242/", + "/api/machines/domain/4242/", + "/api/machines/extension/4242/", + "/api/machines/interface/4242/", + "/api/machines/iplist/4242/", + "/api/machines/iptype/4242/", + "/api/machines/ipv6list/4242/", + "/api/machines/machine/4242/", + "/api/machines/machinetype/4242/", + "/api/machines/mx/4242/", + "/api/machines/nas/4242/", + "/api/machines/ns/4242/", + "/api/machines/ouvertureportlist/4242/", + "/api/machines/ouvertureport/4242/", + "/api/machines/servicelink/4242/", + "/api/machines/service/4242/", + "/api/machines/soa/4242/", + "/api/machines/srv/4242/", + "/api/machines/txt/4242/", + "/api/machines/vlan/4242/", + "/api/preferences/service/4242/", + "/api/topologie/acesspoint/4242/", + "/api/topologie/building/4242/", + "/api/topologie/constructorswitch/4242/", + "/api/topologie/modelswitch/4242/", + "/api/topologie/room/4242/", + "/api/topologie/server/4242/", + "/api/topologie/stack/4242/", + "/api/topologie/switch/4242/", + "/api/topologie/switchbay/4242/", + "/api/topologie/switchport/4242/", + "/api/users/adherent/4242/", + "/api/users/ban/4242/", + "/api/users/club/4242/", + "/api/users/listright/4242/", + "/api/users/school/4242/", + "/api/users/serviceuser/4242/", + "/api/users/shell/4242/", + "/api/users/user/4242/", + "/api/users/whitelist/4242/", ] stduser = None @@ -232,26 +231,18 @@ class APIEndpointsTestCase(APITestCase): # A user with no rights cls.stduser = users.User.objects.create_user( - "apistduser", - "apistduser", - "apistduser@example.net", - "apistduser" + "apistduser", "apistduser", "apistduser@example.net", "apistduser" ) # A user with all the rights cls.superuser = users.User.objects.create_superuser( - "apisuperuser", - "apisuperuser", - "apisuperuser@example.net", - "apisuperuser" + "apisuperuser", "apisuperuser", "apisuperuser@example.net", "apisuperuser" ) # Creates 1 instance for each object so the "details" endpoints # can be tested too. Objects need to be created in the right order. # Dependencies (relatedFields, ...) are highlighted by a comment at # the end of the concerned line (# Dep ). - cls.users_school_1 = users.School.objects.create( - name="users_school_1" - ) + cls.users_school_1 = users.School.objects.create(name="users_school_1") cls.users_school_1.save() cls.users_listshell_1 = users.ListShell.objects.create( shell="users_listshell_1" @@ -270,7 +261,7 @@ class APIEndpointsTestCase(APITestCase): registered=datetime.datetime.now(datetime.timezone.utc), telephone="0123456789", uid_number=21102, - rezo_rez_uid=21102 + rezo_rez_uid=21102, ) cls.users_user_1 = cls.users_adherent_1 cls.cotisations_article_1 = cotisations.Article.objects.create( @@ -278,14 +269,14 @@ class APIEndpointsTestCase(APITestCase): prix=10, duration=1, type_user=cotisations.Article.USER_TYPES[0][0], - type_cotisation=cotisations.Article.COTISATION_TYPE[0][0] + type_cotisation=cotisations.Article.COTISATION_TYPE[0][0], ) cls.cotisations_banque_1 = cotisations.Banque.objects.create( name="cotisations_banque_1" ) cls.cotisations_paiement_1 = cotisations.Paiement.objects.create( moyen="cotisations_paiement_1", - type_paiement=cotisations.Paiement.PAYMENT_TYPES[0][0] + type_paiement=cotisations.Paiement.PAYMENT_TYPES[0][0], ) cls.cotisations_facture_1 = cotisations.Facture.objects.create( user=cls.users_user_1, # Dep users.User @@ -294,7 +285,7 @@ class APIEndpointsTestCase(APITestCase): cheque="1234567890", date=datetime.datetime.now(datetime.timezone.utc), valid=True, - control=False + control=False, ) cls.cotisations_vente_1 = cotisations.Vente.objects.create( facture=cls.cotisations_facture_1, # Dep cotisations.Facture @@ -302,18 +293,18 @@ class APIEndpointsTestCase(APITestCase): name="cotisations_vente_1", prix=10, duration=1, - type_cotisation=cotisations.Vente.COTISATION_TYPE[0][0] + type_cotisation=cotisations.Vente.COTISATION_TYPE[0][0], ) # A cotisation is automatically created by the Vente object and # trying to create another cotisation associated with this vente # will fail so we simply retrieve it so it can be used in the tests cls.cotisations_cotisation_1 = cotisations.Cotisation.objects.get( - vente=cls.cotisations_vente_1, # Dep cotisations.Vente + vente=cls.cotisations_vente_1 # Dep cotisations.Vente ) cls.machines_machine_1 = machines.Machine.objects.create( user=cls.users_user_1, # Dep users.User name="machines_machine_1", - active=True + active=True, ) cls.machines_ouvertureportlist_1 = machines.OuverturePortList.objects.create( name="machines_ouvertureportlist_1" @@ -324,19 +315,17 @@ class APIEndpointsTestCase(APITestCase): refresh=86400, retry=7200, expire=3600000, - ttl=172800 + ttl=172800, ) cls.machines_extension_1 = machines.Extension.objects.create( name="machines_extension_1", need_infra=False, # Do not set origin because of circular dependency origin_v6="2001:db8:1234::", - soa=cls.machines_soa_1 # Dep machines.SOA + soa=cls.machines_soa_1, # Dep machines.SOA ) cls.machines_vlan_1 = machines.Vlan.objects.create( - vlan_id=0, - name="machines_vlan_1", - comment="machines Vlan 1" + vlan_id=0, name="machines_vlan_1", comment="machines Vlan 1" ) cls.machines_iptype_1 = machines.IpType.objects.create( type="machines_iptype_1", @@ -346,13 +335,12 @@ class APIEndpointsTestCase(APITestCase): domaine_ip_stop="10.0.0.255", prefix_v6="2001:db8:1234::", vlan=cls.machines_vlan_1, # Dep machines.Vlan - ouverture_ports=cls.machines_ouvertureportlist_1 # Dep machines.OuverturePortList + ouverture_ports=cls.machines_ouvertureportlist_1, # Dep machines.OuverturePortList ) # All IPs in the IpType range are autocreated so we can't create # new ones and thus we only retrieve it if needed in the tests cls.machines_iplist_1 = machines.IpList.objects.get( - ipv4="10.0.0.1", - ip_type=cls.machines_iptype_1, # Dep machines.IpType + ipv4="10.0.0.1", ip_type=cls.machines_iptype_1 # Dep machines.IpType ) cls.machines_machinetype_1 = machines.MachineType.objects.create( type="machines_machinetype_1", @@ -375,16 +363,16 @@ class APIEndpointsTestCase(APITestCase): cls.machines_mx_1 = machines.Mx.objects.create( zone=cls.machines_extension_1, # Dep machines.Extension priority=10, - name=cls.machines_domain_1 # Dep machines.Domain + name=cls.machines_domain_1, # Dep machines.Domain ) cls.machines_ns_1 = machines.Ns.objects.create( zone=cls.machines_extension_1, # Dep machines.Extension - ns=cls.machines_domain_1 # Dep machines.Domain + ns=cls.machines_domain_1, # Dep machines.Domain ) cls.machines_txt_1 = machines.Txt.objects.create( zone=cls.machines_extension_1, # Dep machines.Extension field1="machines_txt_1", - field2="machies Txt 1" + field2="machies Txt 1", ) cls.machines_srv_1 = machines.Srv.objects.create( service="machines_srv_1", @@ -398,7 +386,7 @@ class APIEndpointsTestCase(APITestCase): cls.machines_ipv6list_1 = machines.Ipv6List.objects.create( ipv6="2001:db8:1234::", interface=cls.machines_interface_1, # Dep machines.Interface - slaac_ip=False + slaac_ip=False, ) cls.machines_service_1 = machines.Service.objects.create( service_type="machines_service_1", @@ -410,45 +398,45 @@ class APIEndpointsTestCase(APITestCase): service=cls.machines_service_1, # Dep machines.Service server=cls.machines_interface_1, # Dep machines.Interface last_regen=datetime.datetime.now(datetime.timezone.utc), - asked_regen=False + asked_regen=False, ) cls.machines_ouvertureport_1 = machines.OuverturePort.objects.create( begin=1, end=2, port_list=cls.machines_ouvertureportlist_1, # Dep machines.OuverturePortList protocole=machines.OuverturePort.TCP, - io=machines.OuverturePort.OUT + io=machines.OuverturePort.OUT, ) cls.machines_nas_1 = machines.Nas.objects.create( name="machines_nas_1", nas_type=cls.machines_machinetype_1, # Dep machines.MachineType machine_type=cls.machines_machinetype_1, # Dep machines.MachineType port_access_mode=machines.Nas.AUTH[0][0], - autocapture_mac=False + autocapture_mac=False, ) cls.preferences_service_1 = preferences.Service.objects.create( name="preferences_service_1", url="https://example.net", description="preferences Service 1", - image="/media/logo/none.png" + image="/media/logo/none.png", ) cls.topologie_stack_1 = topologie.Stack.objects.create( name="topologie_stack_1", stack_id="1", details="topologie Stack 1", member_id_min=1, - member_id_max=10 + member_id_max=10, ) cls.topologie_accespoint_1 = topologie.AccessPoint.objects.create( user=cls.users_user_1, # Dep users.User name="machines_machine_1", active=True, - location="topologie AccessPoint 1" + location="topologie AccessPoint 1", ) cls.topologie_server_1 = topologie.Server.objects.create( user=cls.users_user_1, # Dep users.User name="machines_machine_1", - active=True + active=True, ) cls.topologie_building_1 = topologie.Building.objects.create( name="topologie_building_1" @@ -456,14 +444,14 @@ class APIEndpointsTestCase(APITestCase): cls.topologie_switchbay_1 = topologie.SwitchBay.objects.create( name="topologie_switchbay_1", building=cls.topologie_building_1, # Dep topologie.Building - info="topologie SwitchBay 1" + info="topologie SwitchBay 1", ) cls.topologie_constructorswitch_1 = topologie.ConstructorSwitch.objects.create( name="topologie_constructorswitch_1" ) cls.topologie_modelswitch_1 = topologie.ModelSwitch.objects.create( reference="topologie_modelswitch_1", - constructor=cls.topologie_constructorswitch_1 # Dep topologie.ConstructorSwitch + constructor=cls.topologie_constructorswitch_1, # Dep topologie.ConstructorSwitch ) cls.topologie_switch_1 = topologie.Switch.objects.create( user=cls.users_user_1, # Dep users.User @@ -473,11 +461,10 @@ class APIEndpointsTestCase(APITestCase): stack=cls.topologie_stack_1, # Dep topologie.Stack stack_member_id=1, model=cls.topologie_modelswitch_1, # Dep topologie.ModelSwitch - switchbay=cls.topologie_switchbay_1 # Dep topologie.SwitchBay + switchbay=cls.topologie_switchbay_1, # Dep topologie.SwitchBay ) cls.topologie_room_1 = topologie.Room.objects.create( - name="topologie_romm_1", - details="topologie Room 1" + name="topologie_romm_1", details="topologie Room 1" ) cls.topologie_port_1 = topologie.Port.objects.create( switch=cls.topologie_switch_1, # Dep topologie.Switch @@ -485,7 +472,7 @@ class APIEndpointsTestCase(APITestCase): room=cls.topologie_room_1, # Dep topologie.Room radius=topologie.Port.STATES[0][0], vlan_force=cls.machines_vlan_1, # Dep machines.Vlan - details="topologie_switch_1" + details="topologie_switch_1", ) cls.topologie_port_2 = topologie.Port.objects.create( switch=cls.topologie_switch_1, # Dep topologie.Switch @@ -493,7 +480,7 @@ class APIEndpointsTestCase(APITestCase): machine_interface=cls.machines_interface_1, # Dep machines.Interface radius=topologie.Port.STATES[0][0], vlan_force=cls.machines_vlan_1, # Dep machines.Vlan - details="topologie_switch_1" + details="topologie_switch_1", ) cls.topologie_port_3 = topologie.Port.objects.create( switch=cls.topologie_switch_1, # Dep topologie.Switch @@ -501,14 +488,15 @@ class APIEndpointsTestCase(APITestCase): room=cls.topologie_room_1, # Dep topologie.Room radius=topologie.Port.STATES[0][0], # Do not defines related because circular dependency # Dep machines.Vlan - details="topologie_switch_1" + details="topologie_switch_1", ) cls.users_ban_1 = users.Ban.objects.create( user=cls.users_user_1, # Dep users.User raison="users Ban 1", date_start=datetime.datetime.now(datetime.timezone.utc), - date_end=datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1), - state=users.Ban.STATES[0][0] + date_end=datetime.datetime.now(datetime.timezone.utc) + + datetime.timedelta(days=1), + state=users.Ban.STATES[0][0], ) cls.users_club_1 = users.Club.objects.create( password="password", @@ -524,7 +512,7 @@ class APIEndpointsTestCase(APITestCase): registered=datetime.datetime.now(datetime.timezone.utc), telephone="0123456789", uid_number=21103, - rezo_rez_uid=21103 + rezo_rez_uid=21103, ) # Need merge of MR145 to work # TODO: Merge !145 @@ -539,17 +527,17 @@ class APIEndpointsTestCase(APITestCase): last_login=datetime.datetime.now(datetime.timezone.utc), pseudo="usersserviceuser1", access_group=users.ServiceUser.ACCESS[0][0], - comment="users ServiceUser 1" + comment="users ServiceUser 1", ) cls.users_whitelist_1 = users.Whitelist.objects.create( user=cls.users_user_1, raison="users Whitelist 1", date_start=datetime.datetime.now(datetime.timezone.utc), - date_end=datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1) + date_end=datetime.datetime.now(datetime.timezone.utc) + + datetime.timedelta(days=1), ) - def check_responses_code(self, urls, expected_code, formats=None, - assert_more=None): + def check_responses_code(self, urls, expected_code, formats=None, assert_more=None): """Utility function to test if a list of urls answer an expected code. Args: @@ -665,17 +653,20 @@ class APIEndpointsTestCase(APITestCase): """ self.client.force_authenticate(user=self.superuser) - urls = self.no_auth_endpoints + self.auth_no_perm_endpoints + \ - self.auth_perm_endpoints + urls = ( + self.no_auth_endpoints + + self.auth_no_perm_endpoints + + self.auth_perm_endpoints + ) def assert_more(response, url, format): """Assert the response is valid json when format is json""" - if format is 'json': + if format is "json": json.loads(response.content.decode()) - self.check_responses_code(urls, codes.ok, - formats=[None, 'json', 'api'], - assert_more=assert_more) + self.check_responses_code( + urls, codes.ok, formats=[None, "json", "api"], assert_more=assert_more + ) class APIPaginationTestCase(APITestCase): @@ -688,56 +679,56 @@ class APIPaginationTestCase(APITestCase): """ endpoints = [ - '/api/cotisations/article/', - '/api/cotisations/banque/', - '/api/cotisations/cotisation/', - '/api/cotisations/facture/', - '/api/cotisations/paiement/', - '/api/cotisations/vente/', - '/api/machines/domain/', - '/api/machines/extension/', - '/api/machines/interface/', - '/api/machines/iplist/', - '/api/machines/iptype/', - '/api/machines/ipv6list/', - '/api/machines/machine/', - '/api/machines/machinetype/', - '/api/machines/mx/', - '/api/machines/nas/', - '/api/machines/ns/', - '/api/machines/ouvertureportlist/', - '/api/machines/ouvertureport/', - '/api/machines/servicelink/', - '/api/machines/service/', - '/api/machines/soa/', - '/api/machines/srv/', - '/api/machines/txt/', - '/api/machines/vlan/', - '/api/preferences/service/', - '/api/topologie/acesspoint/', - '/api/topologie/building/', - '/api/topologie/constructorswitch/', - '/api/topologie/modelswitch/', - '/api/topologie/room/', - '/api/topologie/server/', - '/api/topologie/stack/', - '/api/topologie/switch/', - '/api/topologie/switchbay/', - '/api/topologie/switchport/', - '/api/users/adherent/', - '/api/users/ban/', - '/api/users/club/', - '/api/users/listright/', - '/api/users/school/', - '/api/users/serviceuser/', - '/api/users/shell/', - '/api/users/user/', - '/api/users/whitelist/', - '/api/dns/zones/', - '/api/dhcp/hostmacip/', - '/api/mailing/standard', - '/api/mailing/club', - '/api/services/regen/', + "/api/cotisations/article/", + "/api/cotisations/banque/", + "/api/cotisations/cotisation/", + "/api/cotisations/facture/", + "/api/cotisations/paiement/", + "/api/cotisations/vente/", + "/api/machines/domain/", + "/api/machines/extension/", + "/api/machines/interface/", + "/api/machines/iplist/", + "/api/machines/iptype/", + "/api/machines/ipv6list/", + "/api/machines/machine/", + "/api/machines/machinetype/", + "/api/machines/mx/", + "/api/machines/nas/", + "/api/machines/ns/", + "/api/machines/ouvertureportlist/", + "/api/machines/ouvertureport/", + "/api/machines/servicelink/", + "/api/machines/service/", + "/api/machines/soa/", + "/api/machines/srv/", + "/api/machines/txt/", + "/api/machines/vlan/", + "/api/preferences/service/", + "/api/topologie/acesspoint/", + "/api/topologie/building/", + "/api/topologie/constructorswitch/", + "/api/topologie/modelswitch/", + "/api/topologie/room/", + "/api/topologie/server/", + "/api/topologie/stack/", + "/api/topologie/switch/", + "/api/topologie/switchbay/", + "/api/topologie/switchport/", + "/api/users/adherent/", + "/api/users/ban/", + "/api/users/club/", + "/api/users/listright/", + "/api/users/school/", + "/api/users/serviceuser/", + "/api/users/shell/", + "/api/users/user/", + "/api/users/whitelist/", + "/api/dns/zones/", + "/api/dhcp/hostmacip/", + "/api/mailing/standard", + "/api/mailing/club", + "/api/services/regen/", ] superuser = None @@ -745,14 +736,14 @@ class APIPaginationTestCase(APITestCase): def setUpTestData(cls): # A user with all the rights # We need to use a different username than for the first - # test case because TestCase is using rollbacks which don't + # test case because TestCase is using rollbacks which don't # trigger the ldap_sync() thus the LDAP still have data about # the old users. cls.superuser = users.User.objects.create_superuser( "apisuperuser2", "apisuperuser2", "apisuperuser2@example.net", - "apisuperuser2" + "apisuperuser2", ) @classmethod @@ -771,10 +762,10 @@ class APIPaginationTestCase(APITestCase): self.client.force_authenticate(self.superuser) for url in self.endpoints: with self.subTest(url=url): - response = self.client.get(url, format='json') + response = self.client.get(url, format="json") res_json = json.loads(response.content.decode()) - assert 'count' in res_json.keys() - assert 'next' in res_json.keys() - assert 'previous' in res_json.keys() - assert 'results' in res_json.keys() - assert not len('results') > 100 + assert "count" in res_json.keys() + assert "next" in res_json.keys() + assert "previous" in res_json.keys() + assert "results" in res_json.keys() + assert not len("results") > 100 diff --git a/api/urls.py b/api/urls.py index 4a34c1de..6c2bd4c2 100644 --- a/api/urls.py +++ b/api/urls.py @@ -34,95 +34,109 @@ from .routers import AllViewsRouter router = AllViewsRouter() # COTISATIONS -router.register_viewset(r'cotisations/facture', views.FactureViewSet) -router.register_viewset(r'cotisations/vente', views.VenteViewSet) -router.register_viewset(r'cotisations/article', views.ArticleViewSet) -router.register_viewset(r'cotisations/banque', views.BanqueViewSet) -router.register_viewset(r'cotisations/paiement', views.PaiementViewSet) -router.register_viewset(r'cotisations/cotisation', views.CotisationViewSet) +router.register_viewset(r"cotisations/facture", views.FactureViewSet) +router.register_viewset(r"cotisations/vente", views.VenteViewSet) +router.register_viewset(r"cotisations/article", views.ArticleViewSet) +router.register_viewset(r"cotisations/banque", views.BanqueViewSet) +router.register_viewset(r"cotisations/paiement", views.PaiementViewSet) +router.register_viewset(r"cotisations/cotisation", views.CotisationViewSet) # MACHINES -router.register_viewset(r'machines/machine', views.MachineViewSet) -router.register_viewset(r'machines/machinetype', views.MachineTypeViewSet) -router.register_viewset(r'machines/iptype', views.IpTypeViewSet) -router.register_viewset(r'machines/vlan', views.VlanViewSet) -router.register_viewset(r'machines/nas', views.NasViewSet) -router.register_viewset(r'machines/soa', views.SOAViewSet) -router.register_viewset(r'machines/extension', views.ExtensionViewSet) -router.register_viewset(r'machines/mx', views.MxViewSet) -router.register_viewset(r'machines/ns', views.NsViewSet) -router.register_viewset(r'machines/txt', views.TxtViewSet) -router.register_viewset(r'machines/dname', views.DNameViewSet) -router.register_viewset(r'machines/srv', views.SrvViewSet) -router.register_viewset(r'machines/sshfp', views.SshFpViewSet) -router.register_viewset(r'machines/interface', views.InterfaceViewSet) -router.register_viewset(r'machines/ipv6list', views.Ipv6ListViewSet) -router.register_viewset(r'machines/domain', views.DomainViewSet) -router.register_viewset(r'machines/iplist', views.IpListViewSet) -router.register_viewset(r'machines/service', views.ServiceViewSet) -router.register_viewset(r'machines/servicelink', views.ServiceLinkViewSet, base_name='servicelink') -router.register_viewset(r'machines/ouvertureportlist', views.OuverturePortListViewSet) -router.register_viewset(r'machines/ouvertureport', views.OuverturePortViewSet) -router.register_viewset(r'machines/role', views.RoleViewSet) +router.register_viewset(r"machines/machine", views.MachineViewSet) +router.register_viewset(r"machines/machinetype", views.MachineTypeViewSet) +router.register_viewset(r"machines/iptype", views.IpTypeViewSet) +router.register_viewset(r"machines/vlan", views.VlanViewSet) +router.register_viewset(r"machines/nas", views.NasViewSet) +router.register_viewset(r"machines/soa", views.SOAViewSet) +router.register_viewset(r"machines/extension", views.ExtensionViewSet) +router.register_viewset(r"machines/mx", views.MxViewSet) +router.register_viewset(r"machines/ns", views.NsViewSet) +router.register_viewset(r"machines/txt", views.TxtViewSet) +router.register_viewset(r"machines/dname", views.DNameViewSet) +router.register_viewset(r"machines/srv", views.SrvViewSet) +router.register_viewset(r"machines/sshfp", views.SshFpViewSet) +router.register_viewset(r"machines/interface", views.InterfaceViewSet) +router.register_viewset(r"machines/ipv6list", views.Ipv6ListViewSet) +router.register_viewset(r"machines/domain", views.DomainViewSet) +router.register_viewset(r"machines/iplist", views.IpListViewSet) +router.register_viewset(r"machines/service", views.ServiceViewSet) +router.register_viewset( + r"machines/servicelink", views.ServiceLinkViewSet, base_name="servicelink" +) +router.register_viewset(r"machines/ouvertureportlist", views.OuverturePortListViewSet) +router.register_viewset(r"machines/ouvertureport", views.OuverturePortViewSet) +router.register_viewset(r"machines/role", views.RoleViewSet) # PREFERENCES -router.register_view(r'preferences/optionaluser', views.OptionalUserView), -router.register_view(r'preferences/optionalmachine', views.OptionalMachineView), -router.register_view(r'preferences/optionaltopologie', views.OptionalTopologieView), -router.register_view(r'preferences/radiusoption', views.RadiusOptionView), -router.register_view(r'preferences/generaloption', views.GeneralOptionView), -router.register_viewset(r'preferences/service', views.HomeServiceViewSet, base_name='homeservice'), -router.register_view(r'preferences/assooption', views.AssoOptionView), -router.register_view(r'preferences/homeoption', views.HomeOptionView), -router.register_view(r'preferences/mailmessageoption', views.MailMessageOptionView), +router.register_view(r"preferences/optionaluser", views.OptionalUserView), +router.register_view(r"preferences/optionalmachine", views.OptionalMachineView), +router.register_view(r"preferences/optionaltopologie", views.OptionalTopologieView), +router.register_view(r"preferences/radiusoption", views.RadiusOptionView), +router.register_view(r"preferences/generaloption", views.GeneralOptionView), +router.register_viewset( + r"preferences/service", views.HomeServiceViewSet, base_name="homeservice" +), +router.register_view(r"preferences/assooption", views.AssoOptionView), +router.register_view(r"preferences/homeoption", views.HomeOptionView), +router.register_view(r"preferences/mailmessageoption", views.MailMessageOptionView), # TOPOLOGIE -router.register_viewset(r'topologie/stack', views.StackViewSet) -router.register_viewset(r'topologie/acesspoint', views.AccessPointViewSet) -router.register_viewset(r'topologie/switch', views.SwitchViewSet) -router.register_viewset(r'topologie/server', views.ServerViewSet) -router.register_viewset(r'topologie/modelswitch', views.ModelSwitchViewSet) -router.register_viewset(r'topologie/constructorswitch', views.ConstructorSwitchViewSet) -router.register_viewset(r'topologie/switchbay', views.SwitchBayViewSet) -router.register_viewset(r'topologie/building', views.BuildingViewSet) -router.register_viewset(r'topologie/switchport', views.SwitchPortViewSet, base_name='switchport') -router.register_viewset(r'topologie/portprofile', views.PortProfileViewSet, base_name='portprofile') -router.register_viewset(r'topologie/room', views.RoomViewSet) -router.register(r'topologie/portprofile', views.PortProfileViewSet) +router.register_viewset(r"topologie/stack", views.StackViewSet) +router.register_viewset(r"topologie/acesspoint", views.AccessPointViewSet) +router.register_viewset(r"topologie/switch", views.SwitchViewSet) +router.register_viewset(r"topologie/server", views.ServerViewSet) +router.register_viewset(r"topologie/modelswitch", views.ModelSwitchViewSet) +router.register_viewset(r"topologie/constructorswitch", views.ConstructorSwitchViewSet) +router.register_viewset(r"topologie/switchbay", views.SwitchBayViewSet) +router.register_viewset(r"topologie/building", views.BuildingViewSet) +router.register_viewset( + r"topologie/switchport", views.SwitchPortViewSet, base_name="switchport" +) +router.register_viewset( + r"topologie/portprofile", views.PortProfileViewSet, base_name="portprofile" +) +router.register_viewset(r"topologie/room", views.RoomViewSet) +router.register(r"topologie/portprofile", views.PortProfileViewSet) # USERS -router.register_viewset(r'users/user', views.UserViewSet, base_name='user') -router.register_viewset(r'users/homecreation', views.HomeCreationViewSet, base_name='homecreation') -router.register_viewset(r'users/normaluser', views.NormalUserViewSet, base_name='normaluser') -router.register_viewset(r'users/criticaluser', views.CriticalUserViewSet, base_name='criticaluser') -router.register_viewset(r'users/club', views.ClubViewSet) -router.register_viewset(r'users/adherent', views.AdherentViewSet) -router.register_viewset(r'users/serviceuser', views.ServiceUserViewSet) -router.register_viewset(r'users/school', views.SchoolViewSet) -router.register_viewset(r'users/listright', views.ListRightViewSet) -router.register_viewset(r'users/shell', views.ShellViewSet, base_name='shell') -router.register_viewset(r'users/ban', views.BanViewSet) -router.register_viewset(r'users/whitelist', views.WhitelistViewSet) -router.register_viewset(r'users/emailaddress', views.EMailAddressViewSet) +router.register_viewset(r"users/user", views.UserViewSet, base_name="user") +router.register_viewset( + r"users/homecreation", views.HomeCreationViewSet, base_name="homecreation" +) +router.register_viewset( + r"users/normaluser", views.NormalUserViewSet, base_name="normaluser" +) +router.register_viewset( + r"users/criticaluser", views.CriticalUserViewSet, base_name="criticaluser" +) +router.register_viewset(r"users/club", views.ClubViewSet) +router.register_viewset(r"users/adherent", views.AdherentViewSet) +router.register_viewset(r"users/serviceuser", views.ServiceUserViewSet) +router.register_viewset(r"users/school", views.SchoolViewSet) +router.register_viewset(r"users/listright", views.ListRightViewSet) +router.register_viewset(r"users/shell", views.ShellViewSet, base_name="shell") +router.register_viewset(r"users/ban", views.BanViewSet) +router.register_viewset(r"users/whitelist", views.WhitelistViewSet) +router.register_viewset(r"users/emailaddress", views.EMailAddressViewSet) # SERVICE REGEN -router.register_viewset(r'services/regen', views.ServiceRegenViewSet, base_name='serviceregen') +router.register_viewset( + r"services/regen", views.ServiceRegenViewSet, base_name="serviceregen" +) # DHCP -router.register_view(r'dhcp/hostmacip', views.HostMacIpView), +router.register_view(r"dhcp/hostmacip", views.HostMacIpView), # LOCAL EMAILS -router.register_view(r'localemail/users', views.LocalEmailUsersView), +router.register_view(r"localemail/users", views.LocalEmailUsersView), # Firewall -router.register_view(r'firewall/subnet-ports', views.SubnetPortsOpenView), -router.register_view(r'firewall/interface-ports', views.InterfacePortsOpenView), +router.register_view(r"firewall/subnet-ports", views.SubnetPortsOpenView), +router.register_view(r"firewall/interface-ports", views.InterfacePortsOpenView), # Switches config -router.register_view(r'switchs/ports-config', views.SwitchPortView), -router.register_view(r'switchs/role', views.RoleView), +router.register_view(r"switchs/ports-config", views.SwitchPortView), +router.register_view(r"switchs/role", views.RoleView), # Reminder -router.register_view(r'reminder/get-users', views.ReminderView), +router.register_view(r"reminder/get-users", views.ReminderView), # DNS -router.register_view(r'dns/zones', views.DNSZonesView), -router.register_view(r'dns/reverse-zones', views.DNSReverseZonesView), +router.register_view(r"dns/zones", views.DNSZonesView), +router.register_view(r"dns/reverse-zones", views.DNSReverseZonesView), # MAILING -router.register_view(r'mailing/standard', views.StandardMailingView), -router.register_view(r'mailing/club', views.ClubMailingView), +router.register_view(r"mailing/standard", views.StandardMailingView), +router.register_view(r"mailing/club", views.ClubMailingView), # TOKEN AUTHENTICATION -router.register_view(r'token-auth', views.ObtainExpiringAuthToken) +router.register_view(r"token-auth", views.ObtainExpiringAuthToken) -urlpatterns = [ - url(r'^', include(router.urls)), -] +urlpatterns = [url(r"^", include(router.urls))] diff --git a/api/views.py b/api/views.py index d27b585c..b53ee974 100644 --- a/api/views.py +++ b/api/views.py @@ -52,12 +52,15 @@ from .permissions import ACLPermission class FactureViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `cotisations.models.Facture` objects. """ + queryset = cotisations.Facture.objects.all() serializer_class = serializers.FactureSerializer + class FactureViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `cotisations.models.Facture` objects. """ + queryset = cotisations.BaseInvoice.objects.all() serializer_class = serializers.BaseInvoiceSerializer @@ -65,6 +68,7 @@ class FactureViewSet(viewsets.ReadOnlyModelViewSet): class VenteViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `cotisations.models.Vente` objects. """ + queryset = cotisations.Vente.objects.all() serializer_class = serializers.VenteSerializer @@ -72,6 +76,7 @@ class VenteViewSet(viewsets.ReadOnlyModelViewSet): class ArticleViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `cotisations.models.Article` objects. """ + queryset = cotisations.Article.objects.all() serializer_class = serializers.ArticleSerializer @@ -79,6 +84,7 @@ class ArticleViewSet(viewsets.ReadOnlyModelViewSet): class BanqueViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `cotisations.models.Banque` objects. """ + queryset = cotisations.Banque.objects.all() serializer_class = serializers.BanqueSerializer @@ -86,6 +92,7 @@ class BanqueViewSet(viewsets.ReadOnlyModelViewSet): class PaiementViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `cotisations.models.Paiement` objects. """ + queryset = cotisations.Paiement.objects.all() serializer_class = serializers.PaiementSerializer @@ -93,6 +100,7 @@ class PaiementViewSet(viewsets.ReadOnlyModelViewSet): class CotisationViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `cotisations.models.Cotisation` objects. """ + queryset = cotisations.Cotisation.objects.all() serializer_class = serializers.CotisationSerializer @@ -103,6 +111,7 @@ class CotisationViewSet(viewsets.ReadOnlyModelViewSet): class MachineViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Machine` objects. """ + queryset = machines.Machine.objects.all() serializer_class = serializers.MachineSerializer @@ -110,6 +119,7 @@ class MachineViewSet(viewsets.ReadOnlyModelViewSet): class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.MachineType` objects. """ + queryset = machines.MachineType.objects.all() serializer_class = serializers.MachineTypeSerializer @@ -117,6 +127,7 @@ class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet): class IpTypeViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.IpType` objects. """ + queryset = machines.IpType.objects.all() serializer_class = serializers.IpTypeSerializer @@ -124,6 +135,7 @@ class IpTypeViewSet(viewsets.ReadOnlyModelViewSet): class VlanViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Vlan` objects. """ + queryset = machines.Vlan.objects.all() serializer_class = serializers.VlanSerializer @@ -131,6 +143,7 @@ class VlanViewSet(viewsets.ReadOnlyModelViewSet): class NasViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Nas` objects. """ + queryset = machines.Nas.objects.all() serializer_class = serializers.NasSerializer @@ -138,6 +151,7 @@ class NasViewSet(viewsets.ReadOnlyModelViewSet): class SOAViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.SOA` objects. """ + queryset = machines.SOA.objects.all() serializer_class = serializers.SOASerializer @@ -145,6 +159,7 @@ class SOAViewSet(viewsets.ReadOnlyModelViewSet): class ExtensionViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Extension` objects. """ + queryset = machines.Extension.objects.all() serializer_class = serializers.ExtensionSerializer @@ -152,6 +167,7 @@ class ExtensionViewSet(viewsets.ReadOnlyModelViewSet): class MxViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Mx` objects. """ + queryset = machines.Mx.objects.all() serializer_class = serializers.MxSerializer @@ -159,6 +175,7 @@ class MxViewSet(viewsets.ReadOnlyModelViewSet): class NsViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Ns` objects. """ + queryset = machines.Ns.objects.all() serializer_class = serializers.NsSerializer @@ -166,6 +183,7 @@ class NsViewSet(viewsets.ReadOnlyModelViewSet): class TxtViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Txt` objects. """ + queryset = machines.Txt.objects.all() serializer_class = serializers.TxtSerializer @@ -173,6 +191,7 @@ class TxtViewSet(viewsets.ReadOnlyModelViewSet): class DNameViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.DName` objects. """ + queryset = machines.DName.objects.all() serializer_class = serializers.DNameSerializer @@ -180,6 +199,7 @@ class DNameViewSet(viewsets.ReadOnlyModelViewSet): class SrvViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Srv` objects. """ + queryset = machines.Srv.objects.all() serializer_class = serializers.SrvSerializer @@ -187,6 +207,7 @@ class SrvViewSet(viewsets.ReadOnlyModelViewSet): class SshFpViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.SshFp` objects. """ + queryset = machines.SshFp.objects.all() serializer_class = serializers.SshFpSerializer @@ -194,6 +215,7 @@ class SshFpViewSet(viewsets.ReadOnlyModelViewSet): class InterfaceViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Interface` objects. """ + queryset = machines.Interface.objects.all() serializer_class = serializers.InterfaceSerializer @@ -201,6 +223,7 @@ class InterfaceViewSet(viewsets.ReadOnlyModelViewSet): class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Ipv6List` objects. """ + queryset = machines.Ipv6List.objects.all() serializer_class = serializers.Ipv6ListSerializer @@ -208,6 +231,7 @@ class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet): class DomainViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Domain` objects. """ + queryset = machines.Domain.objects.all() serializer_class = serializers.DomainSerializer @@ -215,6 +239,7 @@ class DomainViewSet(viewsets.ReadOnlyModelViewSet): class IpListViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.IpList` objects. """ + queryset = machines.IpList.objects.all() serializer_class = serializers.IpListSerializer @@ -222,6 +247,7 @@ class IpListViewSet(viewsets.ReadOnlyModelViewSet): class ServiceViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Service` objects. """ + queryset = machines.Service.objects.all() serializer_class = serializers.ServiceSerializer @@ -229,6 +255,7 @@ class ServiceViewSet(viewsets.ReadOnlyModelViewSet): class ServiceLinkViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Service_link` objects. """ + queryset = machines.Service_link.objects.all() serializer_class = serializers.ServiceLinkSerializer @@ -237,6 +264,7 @@ class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.OuverturePortList` objects. """ + queryset = machines.OuverturePortList.objects.all() serializer_class = serializers.OuverturePortListSerializer @@ -244,6 +272,7 @@ class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet): class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.OuverturePort` objects. """ + queryset = machines.OuverturePort.objects.all() serializer_class = serializers.OuverturePortSerializer @@ -251,6 +280,7 @@ class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet): class RoleViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `machines.models.Machine` objects. """ + queryset = machines.Role.objects.all() serializer_class = serializers.RoleSerializer @@ -259,11 +289,13 @@ class RoleViewSet(viewsets.ReadOnlyModelViewSet): # Those views differ a bit because there is only one object # to display, so we don't bother with the listing part + class OptionalUserView(generics.RetrieveAPIView): """Exposes details of `preferences.models.` settings. """ + permission_classes = (ACLPermission,) - perms_map = {'GET': [preferences.OptionalUser.can_view_all]} + perms_map = {"GET": [preferences.OptionalUser.can_view_all]} serializer_class = serializers.OptionalUserSerializer def get_object(self): @@ -273,8 +305,9 @@ class OptionalUserView(generics.RetrieveAPIView): class OptionalMachineView(generics.RetrieveAPIView): """Exposes details of `preferences.models.OptionalMachine` settings. """ + permission_classes = (ACLPermission,) - perms_map = {'GET': [preferences.OptionalMachine.can_view_all]} + perms_map = {"GET": [preferences.OptionalMachine.can_view_all]} serializer_class = serializers.OptionalMachineSerializer def get_object(self): @@ -284,8 +317,9 @@ class OptionalMachineView(generics.RetrieveAPIView): class OptionalTopologieView(generics.RetrieveAPIView): """Exposes details of `preferences.models.OptionalTopologie` settings. """ + permission_classes = (ACLPermission,) - perms_map = {'GET': [preferences.OptionalTopologie.can_view_all]} + perms_map = {"GET": [preferences.OptionalTopologie.can_view_all]} serializer_class = serializers.OptionalTopologieSerializer def get_object(self): @@ -295,8 +329,9 @@ class OptionalTopologieView(generics.RetrieveAPIView): class RadiusOptionView(generics.RetrieveAPIView): """Exposes details of `preferences.models.OptionalTopologie` settings. """ + permission_classes = (ACLPermission,) - perms_map = {'GET': [preferences.RadiusOption.can_view_all]} + perms_map = {"GET": [preferences.RadiusOption.can_view_all]} serializer_class = serializers.RadiusOptionSerializer def get_object(self): @@ -306,8 +341,9 @@ class RadiusOptionView(generics.RetrieveAPIView): class GeneralOptionView(generics.RetrieveAPIView): """Exposes details of `preferences.models.GeneralOption` settings. """ + permission_classes = (ACLPermission,) - perms_map = {'GET': [preferences.GeneralOption.can_view_all]} + perms_map = {"GET": [preferences.GeneralOption.can_view_all]} serializer_class = serializers.GeneralOptionSerializer def get_object(self): @@ -317,6 +353,7 @@ class GeneralOptionView(generics.RetrieveAPIView): class HomeServiceViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `preferences.models.Service` objects. """ + queryset = preferences.Service.objects.all() serializer_class = serializers.HomeServiceSerializer @@ -324,8 +361,9 @@ class HomeServiceViewSet(viewsets.ReadOnlyModelViewSet): class AssoOptionView(generics.RetrieveAPIView): """Exposes details of `preferences.models.AssoOption` settings. """ + permission_classes = (ACLPermission,) - perms_map = {'GET': [preferences.AssoOption.can_view_all]} + perms_map = {"GET": [preferences.AssoOption.can_view_all]} serializer_class = serializers.AssoOptionSerializer def get_object(self): @@ -335,8 +373,9 @@ class AssoOptionView(generics.RetrieveAPIView): class HomeOptionView(generics.RetrieveAPIView): """Exposes details of `preferences.models.HomeOption` settings. """ + permission_classes = (ACLPermission,) - perms_map = {'GET': [preferences.HomeOption.can_view_all]} + perms_map = {"GET": [preferences.HomeOption.can_view_all]} serializer_class = serializers.HomeOptionSerializer def get_object(self): @@ -346,8 +385,9 @@ class HomeOptionView(generics.RetrieveAPIView): class MailMessageOptionView(generics.RetrieveAPIView): """Exposes details of `preferences.models.MailMessageOption` settings. """ + permission_classes = (ACLPermission,) - perms_map = {'GET': [preferences.MailMessageOption.can_view_all]} + perms_map = {"GET": [preferences.MailMessageOption.can_view_all]} serializer_class = serializers.MailMessageOptionSerializer def get_object(self): @@ -360,6 +400,7 @@ class MailMessageOptionView(generics.RetrieveAPIView): class StackViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.Stack` objects. """ + queryset = topologie.Stack.objects.all() serializer_class = serializers.StackSerializer @@ -367,6 +408,7 @@ class StackViewSet(viewsets.ReadOnlyModelViewSet): class AccessPointViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.AccessPoint` objects. """ + queryset = topologie.AccessPoint.objects.all() serializer_class = serializers.AccessPointSerializer @@ -374,6 +416,7 @@ class AccessPointViewSet(viewsets.ReadOnlyModelViewSet): class SwitchViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.Switch` objects. """ + queryset = topologie.Switch.objects.all() serializer_class = serializers.SwitchSerializer @@ -381,6 +424,7 @@ class SwitchViewSet(viewsets.ReadOnlyModelViewSet): class ServerViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.Server` objects. """ + queryset = topologie.Server.objects.all() serializer_class = serializers.ServerSerializer @@ -388,6 +432,7 @@ class ServerViewSet(viewsets.ReadOnlyModelViewSet): class ModelSwitchViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.ModelSwitch` objects. """ + queryset = topologie.ModelSwitch.objects.all() serializer_class = serializers.ModelSwitchSerializer @@ -396,6 +441,7 @@ class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.ConstructorSwitch` objects. """ + queryset = topologie.ConstructorSwitch.objects.all() serializer_class = serializers.ConstructorSwitchSerializer @@ -403,6 +449,7 @@ class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet): class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.SwitchBay` objects. """ + queryset = topologie.SwitchBay.objects.all() serializer_class = serializers.SwitchBaySerializer @@ -410,6 +457,7 @@ class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet): class BuildingViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.Building` objects. """ + queryset = topologie.Building.objects.all() serializer_class = serializers.BuildingSerializer @@ -417,6 +465,7 @@ class BuildingViewSet(viewsets.ReadOnlyModelViewSet): class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.Port` objects. """ + queryset = topologie.Port.objects.all() serializer_class = serializers.SwitchPortSerializer @@ -424,6 +473,7 @@ class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet): class PortProfileViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.PortProfile` objects. """ + queryset = topologie.PortProfile.objects.all() serializer_class = serializers.PortProfileSerializer @@ -431,6 +481,7 @@ class PortProfileViewSet(viewsets.ReadOnlyModelViewSet): class RoomViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.Room` objects. """ + queryset = topologie.Room.objects.all() serializer_class = serializers.RoomSerializer @@ -438,6 +489,7 @@ class RoomViewSet(viewsets.ReadOnlyModelViewSet): class PortProfileViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `topologie.models.PortProfile` objects. """ + queryset = topologie.PortProfile.objects.all() serializer_class = serializers.PortProfileSerializer @@ -448,6 +500,7 @@ class PortProfileViewSet(viewsets.ReadOnlyModelViewSet): class UserViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `users.models.Users` objects. """ + queryset = users.User.objects.all() serializer_class = serializers.UserSerializer @@ -455,18 +508,25 @@ class UserViewSet(viewsets.ReadOnlyModelViewSet): class HomeCreationViewSet(viewsets.ReadOnlyModelViewSet): """Exposes infos of `users.models.Users` objects to create homes. """ - queryset = users.User.objects.exclude(Q(state=users.User.STATE_DISABLED) | Q(state=users.User.STATE_NOT_YET_ACTIVE) | Q(state=users.User.STATE_FULL_ARCHIVE)) + + queryset = users.User.objects.exclude( + Q(state=users.User.STATE_DISABLED) + | Q(state=users.User.STATE_NOT_YET_ACTIVE) + | Q(state=users.User.STATE_FULL_ARCHIVE) + ) serializer_class = serializers.BasicUserSerializer class NormalUserViewSet(viewsets.ReadOnlyModelViewSet): """Exposes infos of `users.models.Users`without specific rights objects.""" + queryset = users.User.objects.exclude(groups__listright__critical=True).distinct() serializer_class = serializers.BasicUserSerializer class CriticalUserViewSet(viewsets.ReadOnlyModelViewSet): """Exposes infos of `users.models.Users`without specific rights objects.""" + queryset = users.User.objects.filter(groups__listright__critical=True).distinct() serializer_class = serializers.BasicUserSerializer @@ -474,6 +534,7 @@ class CriticalUserViewSet(viewsets.ReadOnlyModelViewSet): class ClubViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `users.models.Club` objects. """ + queryset = users.Club.objects.all() serializer_class = serializers.ClubSerializer @@ -481,6 +542,7 @@ class ClubViewSet(viewsets.ReadOnlyModelViewSet): class AdherentViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `users.models.Adherent` objects. """ + queryset = users.Adherent.objects.all() serializer_class = serializers.AdherentSerializer @@ -488,6 +550,7 @@ class AdherentViewSet(viewsets.ReadOnlyModelViewSet): class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `users.models.ServiceUser` objects. """ + queryset = users.ServiceUser.objects.all() serializer_class = serializers.ServiceUserSerializer @@ -495,6 +558,7 @@ class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet): class SchoolViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `users.models.School` objects. """ + queryset = users.School.objects.all() serializer_class = serializers.SchoolSerializer @@ -502,6 +566,7 @@ class SchoolViewSet(viewsets.ReadOnlyModelViewSet): class ListRightViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `users.models.ListRight` objects. """ + queryset = users.ListRight.objects.all() serializer_class = serializers.ListRightSerializer @@ -509,6 +574,7 @@ class ListRightViewSet(viewsets.ReadOnlyModelViewSet): class ShellViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `users.models.ListShell` objects. """ + queryset = users.ListShell.objects.all() serializer_class = serializers.ShellSerializer @@ -516,6 +582,7 @@ class ShellViewSet(viewsets.ReadOnlyModelViewSet): class BanViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `users.models.Ban` objects. """ + queryset = users.Ban.objects.all() serializer_class = serializers.BanSerializer @@ -523,6 +590,7 @@ class BanViewSet(viewsets.ReadOnlyModelViewSet): class WhitelistViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `users.models.Whitelist` objects. """ + queryset = users.Whitelist.objects.all() serializer_class = serializers.WhitelistSerializer @@ -530,14 +598,13 @@ class WhitelistViewSet(viewsets.ReadOnlyModelViewSet): class EMailAddressViewSet(viewsets.ReadOnlyModelViewSet): """Exposes list and details of `users.models.EMailAddress` objects. """ + serializer_class = serializers.EMailAddressSerializer queryset = users.EMailAddress.objects.none() def get_queryset(self): - if preferences.OptionalUser.get_cached_value( - 'local_email_accounts_enabled'): - return (users.EMailAddress.objects - .filter(user__local_email_enabled=True)) + if preferences.OptionalUser.get_cached_value("local_email_accounts_enabled"): + return users.EMailAddress.objects.filter(user__local_email_enabled=True) else: return users.EMailAddress.objects.none() @@ -548,34 +615,47 @@ class EMailAddressViewSet(viewsets.ReadOnlyModelViewSet): class ServiceRegenViewSet(viewsets.ModelViewSet): """Exposes list and details of the services to regen """ + serializer_class = serializers.ServiceRegenSerializer def get_queryset(self): queryset = machines.Service_link.objects.select_related( - 'server__domain' - ).select_related( - 'service' - ) - if 'hostname' in self.request.GET: - hostname = self.request.GET['hostname'] + "server__domain" + ).select_related("service") + if "hostname" in self.request.GET: + hostname = self.request.GET["hostname"] queryset = queryset.filter(server__domain__name__iexact=hostname) return queryset + # Config des switches + class SwitchPortView(generics.ListAPIView): """Output each port of a switch, to be serialized with additionnal informations (profiles etc) """ - queryset = topologie.Switch.objects.all().select_related("switchbay").select_related("model__constructor").prefetch_related("ports__custom_profile__vlan_tagged").prefetch_related("ports__custom_profile__vlan_untagged").prefetch_related("ports__machine_interface__domain__extension").prefetch_related("ports__room") + + queryset = ( + topologie.Switch.objects.all() + .select_related("switchbay") + .select_related("model__constructor") + .prefetch_related("ports__custom_profile__vlan_tagged") + .prefetch_related("ports__custom_profile__vlan_untagged") + .prefetch_related("ports__machine_interface__domain__extension") + .prefetch_related("ports__room") + ) serializer_class = serializers.SwitchPortSerializer + # Rappel fin adhésion + class ReminderView(generics.ListAPIView): """Output for users to remind an end of their subscription. """ + queryset = preferences.Reminder.objects.all() serializer_class = serializers.ReminderSerializer @@ -583,7 +663,8 @@ class ReminderView(generics.ListAPIView): class RoleView(generics.ListAPIView): """Output of roles for each server """ - queryset = machines.Role.objects.all().prefetch_related('servers') + + queryset = machines.Role.objects.all().prefetch_related("servers") serializer_class = serializers.RoleSerializer @@ -593,13 +674,12 @@ class RoleView(generics.ListAPIView): class LocalEmailUsersView(generics.ListAPIView): """Exposes all the aliases of the users that activated the internal address """ + serializer_class = serializers.LocalEmailUsersSerializer def get_queryset(self): - if preferences.OptionalUser.get_cached_value( - 'local_email_accounts_enabled'): - return (users.User.objects - .filter(local_email_enabled=True)) + if preferences.OptionalUser.get_cached_value("local_email_accounts_enabled"): + return users.User.objects.filter(local_email_enabled=True) else: return users.User.objects.none() @@ -611,6 +691,7 @@ class HostMacIpView(generics.ListAPIView): """Exposes the associations between hostname, mac address and IPv4 in order to build the DHCP lease files. """ + serializer_class = serializers.HostMacIpSerializer def get_queryset(self): @@ -619,6 +700,7 @@ class HostMacIpView(generics.ListAPIView): # Firewall + class SubnetPortsOpenView(generics.ListAPIView): queryset = machines.IpType.objects.all() serializer_class = serializers.SubnetPortsOpenSerializer @@ -636,14 +718,19 @@ class DNSZonesView(generics.ListAPIView): """Exposes the detailed information about each extension (hostnames, IPs, DNS records, etc.) in order to build the DNS zone files. """ - queryset = (machines.Extension.objects - .prefetch_related('soa') - .prefetch_related('ns_set').prefetch_related('ns_set__ns') - .prefetch_related('origin') - .prefetch_related('mx_set').prefetch_related('mx_set__name') - .prefetch_related('txt_set') - .prefetch_related('srv_set').prefetch_related('srv_set__target') - .all()) + + queryset = ( + machines.Extension.objects.prefetch_related("soa") + .prefetch_related("ns_set") + .prefetch_related("ns_set__ns") + .prefetch_related("origin") + .prefetch_related("mx_set") + .prefetch_related("mx_set__name") + .prefetch_related("txt_set") + .prefetch_related("srv_set") + .prefetch_related("srv_set__target") + .all() + ) serializer_class = serializers.DNSZonesSerializer @@ -651,7 +738,8 @@ class DNSReverseZonesView(generics.ListAPIView): """Exposes the detailed information about each extension (hostnames, IPs, DNS records, etc.) in order to build the DNS zone files. """ - queryset = (machines.IpType.objects.all()) + + queryset = machines.IpType.objects.all() serializer_class = serializers.DNSReverseZonesSerializer @@ -662,13 +750,16 @@ class StandardMailingView(views.APIView): """Exposes list and details of standard mailings (name and members) in order to building the corresponding mailing lists. """ + pagination_class = PageSizedPagination permission_classes = (ACLPermission,) - perms_map = {'GET': [users.User.can_view_all]} + perms_map = {"GET": [users.User.can_view_all]} def get(self, request, format=None): - adherents_data = serializers.MailingMemberSerializer(all_has_access(), many=True).data - data = [{'name': 'adherents', 'members': adherents_data}] + adherents_data = serializers.MailingMemberSerializer( + all_has_access(), many=True + ).data + data = [{"name": "adherents", "members": adherents_data}] paginator = self.pagination_class() paginator.paginate_queryset(data, request) return paginator.get_paginated_response(data) @@ -678,6 +769,7 @@ class ClubMailingView(generics.ListAPIView): """Exposes list and details of club mailings (name, members and admins) in order to build the corresponding mailing lists. """ + queryset = users.Club.objects.all() serializer_class = serializers.MailingSerializer @@ -696,12 +788,10 @@ class ObtainExpiringAuthToken(ObtainAuthToken): def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) - user = serializer.validated_data['user'] + user = serializer.validated_data["user"] token, created = Token.objects.get_or_create(user=user) - token_duration = datetime.timedelta( - seconds=settings.API_TOKEN_DURATION - ) + token_duration = datetime.timedelta(seconds=settings.API_TOKEN_DURATION) utc_now = datetime.datetime.now(datetime.timezone.utc) if not created and token.created < utc_now - token_duration: token.delete() @@ -709,7 +799,6 @@ class ObtainExpiringAuthToken(ObtainAuthToken): token.created = datetime.datetime.utcnow() token.save() - return Response({ - 'token': token.key, - 'expiration': token.created + token_duration - }) + return Response( + {"token": token.key, "expiration": token.created + token_duration} + ) diff --git a/cotisations/acl.py b/cotisations/acl.py index ce0b1eff..07db6929 100644 --- a/cotisations/acl.py +++ b/cotisations/acl.py @@ -38,13 +38,12 @@ def can_view(user): A couple (allowed, msg) where allowed is a boolean which is True if viewing is granted and msg is a message (can be None). """ - can = user.has_module_perms('cotisations') + can = user.has_module_perms("cotisations") if can: - return can, None, ('cotisations',) + return can, None, ("cotisations",) else: return ( can, _("You don't have the right to view this application."), - ('cotisations',) + ("cotisations",), ) - diff --git a/cotisations/admin.py b/cotisations/admin.py index 44af149d..ebe7d683 100644 --- a/cotisations/admin.py +++ b/cotisations/admin.py @@ -35,42 +35,50 @@ from .models import CustomInvoice, CostEstimate class FactureAdmin(VersionAdmin): """Class admin d'une facture, tous les champs""" + pass class CostEstimateAdmin(VersionAdmin): """Admin class for cost estimates.""" + pass class CustomInvoiceAdmin(VersionAdmin): """Admin class for custom invoices.""" + pass class VenteAdmin(VersionAdmin): """Class admin d'une vente, tous les champs (facture related)""" + pass class ArticleAdmin(VersionAdmin): """Class admin d'un article en vente""" + pass class BanqueAdmin(VersionAdmin): """Class admin de la liste des banques (facture related)""" + pass class PaiementAdmin(VersionAdmin): """Class admin d'un moyen de paiement (facture related""" + pass class CotisationAdmin(VersionAdmin): """Class admin d'une cotisation (date de debut et de fin), Vente related""" + pass diff --git a/cotisations/forms.py b/cotisations/forms.py index 8ae4ae29..6f4a9a45 100644 --- a/cotisations/forms.py +++ b/cotisations/forms.py @@ -47,8 +47,13 @@ from django.shortcuts import get_object_or_404 from re2o.field_permissions import FieldPermissionFormMixin from re2o.mixins import FormRevMixin from .models import ( - Article, Paiement, Facture, Banque, - CustomInvoice, Vente, CostEstimate, + Article, + Paiement, + Facture, + Banque, + CustomInvoice, + Vente, + CostEstimate, ) from .payment_methods import balance @@ -59,31 +64,27 @@ class FactureForm(FieldPermissionFormMixin, FormRevMixin, ModelForm): """ def __init__(self, *args, creation=False, **kwargs): - user = kwargs['user'] - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + user = kwargs["user"] + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(FactureForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['paiement'].empty_label = \ - _("Select a payment method") - self.fields['paiement'].queryset = Paiement.find_allowed_payments(user) + self.fields["paiement"].empty_label = _("Select a payment method") + self.fields["paiement"].queryset = Paiement.find_allowed_payments(user) if not creation: - self.fields['user'].label = _("Member") - self.fields['user'].empty_label = \ - _("Select the proprietary member") - self.fields['valid'].label = _("Validated invoice") + self.fields["user"].label = _("Member") + self.fields["user"].empty_label = _("Select the proprietary member") + self.fields["valid"].label = _("Validated invoice") else: - self.fields = {'paiement': self.fields['paiement']} + self.fields = {"paiement": self.fields["paiement"]} class Meta: model = Facture - fields = '__all__' + fields = "__all__" def clean(self): cleaned_data = super(FactureForm, self).clean() - paiement = cleaned_data.get('paiement') + paiement = cleaned_data.get("paiement") if not paiement: - raise forms.ValidationError( - _("A payment method must be specified.") - ) + raise forms.ValidationError(_("A payment method must be specified.")) return cleaned_data @@ -92,32 +93,30 @@ class SelectArticleForm(FormRevMixin, Form): Form used to select an article during the creation of an invoice for a member. """ + article = forms.ModelChoiceField( - queryset=Article.objects.none(), - label=_("Article"), - required=True + queryset=Article.objects.none(), label=_("Article"), required=True ) quantity = forms.IntegerField( - label=_("Quantity"), - validators=[MinValueValidator(1)], - required=True + label=_("Quantity"), validators=[MinValueValidator(1)], required=True ) def __init__(self, *args, **kwargs): - user = kwargs.pop('user') - target_user = kwargs.pop('target_user', None) + user = kwargs.pop("user") + target_user = kwargs.pop("target_user", None) super(SelectArticleForm, self).__init__(*args, **kwargs) - self.fields['article'].queryset = Article.find_allowed_articles( - user, target_user) + self.fields["article"].queryset = Article.find_allowed_articles( + user, target_user + ) class DiscountForm(Form): """ Form used in oder to create a discount on an invoice. """ + is_relative = forms.BooleanField( - label=_("Discount is on percentage."), - required=False, + label=_("Discount is on percentage."), required=False ) discount = forms.DecimalField( label=_("Discount"), @@ -130,53 +129,51 @@ class DiscountForm(Form): def apply_to_invoice(self, invoice): invoice_price = invoice.prix_total() - discount = self.cleaned_data['discount'] - is_relative = self.cleaned_data['is_relative'] + discount = self.cleaned_data["discount"] + is_relative = self.cleaned_data["is_relative"] if is_relative: - amount = discount/100 * invoice_price + amount = discount / 100 * invoice_price else: amount = discount if amount: name = _("{}% discount") if is_relative else _("{}€ discount") name = name.format(discount) - Vente.objects.create( - facture=invoice, - name=name, - prix=-amount, - number=1 - ) + Vente.objects.create(facture=invoice, name=name, prix=-amount, number=1) class CustomInvoiceForm(FormRevMixin, ModelForm): """ Form used to create a custom invoice. """ + class Meta: model = CustomInvoice - fields = '__all__' + fields = "__all__" class CostEstimateForm(FormRevMixin, ModelForm): """ Form used to create a cost estimate. """ + class Meta: model = CostEstimate - exclude = ['paid', 'final_invoice'] + exclude = ["paid", "final_invoice"] class ArticleForm(FormRevMixin, ModelForm): """ Form used to create an article. """ + class Meta: model = Article - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(ArticleForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['name'].label = _("Article name") + self.fields["name"].label = _("Article name") class DelArticleForm(FormRevMixin, Form): @@ -184,19 +181,20 @@ class DelArticleForm(FormRevMixin, Form): Form used to delete one or more of the currently available articles. The user must choose the one to delete by checking the boxes. """ + articles = forms.ModelMultipleChoiceField( queryset=Article.objects.none(), label=_("Available articles"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelArticleForm, self).__init__(*args, **kwargs) if instances: - self.fields['articles'].queryset = instances + self.fields["articles"].queryset = instances else: - self.fields['articles'].queryset = Article.objects.all() + self.fields["articles"].queryset = Article.objects.all() # TODO : change Paiement to Payment @@ -206,15 +204,16 @@ class PaiementForm(FormRevMixin, ModelForm): The 'cheque' type is used to associate a specific behaviour requiring a cheque number and a bank. """ + class Meta: model = Paiement # TODO : change moyen to method and type_paiement to payment_type - fields = ['moyen', 'available_for_everyone'] + fields = ["moyen", "available_for_everyone"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(PaiementForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['moyen'].label = _("Payment method name") + self.fields["moyen"].label = _("Payment method name") # TODO : change paiement to payment @@ -223,20 +222,21 @@ class DelPaiementForm(FormRevMixin, Form): Form used to delete one or more payment methods. The user must choose the one to delete by checking the boxes. """ + # TODO : change paiement to payment paiements = forms.ModelMultipleChoiceField( queryset=Paiement.objects.none(), label=_("Available payment methods"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelPaiementForm, self).__init__(*args, **kwargs) if instances: - self.fields['paiements'].queryset = instances + self.fields["paiements"].queryset = instances else: - self.fields['paiements'].queryset = Paiement.objects.all() + self.fields["paiements"].queryset = Paiement.objects.all() # TODO : change banque to bank @@ -244,15 +244,16 @@ class BanqueForm(FormRevMixin, ModelForm): """ Form used to create a bank. """ + class Meta: # TODO : change banque to bank model = Banque - fields = ['name'] + fields = ["name"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(BanqueForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['name'].label = _("Bank name") + self.fields["name"].label = _("Bank name") # TODO : change banque to bank @@ -261,20 +262,21 @@ class DelBanqueForm(FormRevMixin, Form): Form used to delete one or more banks. The use must choose the one to delete by checking the boxes. """ + # TODO : change banque to bank banques = forms.ModelMultipleChoiceField( queryset=Banque.objects.none(), label=_("Available banks"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelBanqueForm, self).__init__(*args, **kwargs) if instances: - self.fields['banques'].queryset = instances + self.fields["banques"].queryset = instances else: - self.fields['banques'].queryset = Banque.objects.all() + self.fields["banques"].queryset = Banque.objects.all() # TODO : Better name and docstring @@ -282,36 +284,36 @@ class RechargeForm(FormRevMixin, Form): """ Form used to refill a user's balance """ - value = forms.DecimalField( - label=_("Amount"), - decimal_places=2, - ) + + value = forms.DecimalField(label=_("Amount"), decimal_places=2) payment = forms.ModelChoiceField( - queryset=Paiement.objects.none(), - label=_("Payment method") + queryset=Paiement.objects.none(), label=_("Payment method") ) def __init__(self, *args, user=None, user_source=None, **kwargs): self.user = user super(RechargeForm, self).__init__(*args, **kwargs) - self.fields['payment'].empty_label = \ - _("Select a payment method") - self.fields['payment'].queryset = Paiement.find_allowed_payments( - user_source).exclude(is_balance=True) + self.fields["payment"].empty_label = _("Select a payment method") + self.fields["payment"].queryset = Paiement.find_allowed_payments( + user_source + ).exclude(is_balance=True) def clean(self): """ Returns a cleaned value from the received form by validating the value is well inside the possible limits """ - value = self.cleaned_data['value'] + value = self.cleaned_data["value"] balance_method = get_object_or_404(balance.PaymentMethod) - if balance_method.maximum_balance is not None and \ - value + self.user.solde > balance_method.maximum_balance: + if ( + balance_method.maximum_balance is not None + and value + self.user.solde > balance_method.maximum_balance + ): raise forms.ValidationError( - _("Requested amount is too high. Your balance can't exceed" - " %(max_online_balance)s €.") % { - 'max_online_balance': balance_method.maximum_balance - } + _( + "Requested amount is too high. Your balance can't exceed" + " %(max_online_balance)s €." + ) + % {"max_online_balance": balance_method.maximum_balance} ) return self.cleaned_data diff --git a/cotisations/migrations/0001_initial.py b/cotisations/migrations/0001_initial.py index b235f605..0ffe83c9 100644 --- a/cotisations/migrations/0001_initial.py +++ b/cotisations/migrations/0001_initial.py @@ -29,54 +29,100 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0005_auto_20160702_0006'), - ] + dependencies = [("users", "0005_auto_20160702_0006")] operations = [ migrations.CreateModel( - name='Article', + name="Article", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), - ('name', models.CharField(max_length=255)), - ('prix', models.DecimalField(decimal_places=2, max_digits=5)), + ( + "id", + models.AutoField( + verbose_name="ID", + auto_created=True, + primary_key=True, + serialize=False, + ), + ), + ("name", models.CharField(max_length=255)), + ("prix", models.DecimalField(decimal_places=2, max_digits=5)), ], ), migrations.CreateModel( - name='Banque', + name="Banque", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), - ('name', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + auto_created=True, + primary_key=True, + serialize=False, + ), + ), + ("name", models.CharField(max_length=255)), ], ), migrations.CreateModel( - name='Facture', + name="Facture", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), - ('cheque', models.CharField(max_length=255)), - ('number', models.IntegerField()), - ('date', models.DateTimeField(auto_now_add=True)), - ('name', models.CharField(max_length=255)), - ('prix', models.DecimalField(decimal_places=2, max_digits=5)), - ('article', models.ForeignKey(to='cotisations.Article', on_delete=django.db.models.deletion.PROTECT)), - ('banque', models.ForeignKey(to='cotisations.Banque', on_delete=django.db.models.deletion.PROTECT)), + ( + "id", + models.AutoField( + verbose_name="ID", + auto_created=True, + primary_key=True, + serialize=False, + ), + ), + ("cheque", models.CharField(max_length=255)), + ("number", models.IntegerField()), + ("date", models.DateTimeField(auto_now_add=True)), + ("name", models.CharField(max_length=255)), + ("prix", models.DecimalField(decimal_places=2, max_digits=5)), + ( + "article", + models.ForeignKey( + to="cotisations.Article", + on_delete=django.db.models.deletion.PROTECT, + ), + ), + ( + "banque", + models.ForeignKey( + to="cotisations.Banque", + on_delete=django.db.models.deletion.PROTECT, + ), + ), ], ), migrations.CreateModel( - name='Paiement', + name="Paiement", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), - ('moyen', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + auto_created=True, + primary_key=True, + serialize=False, + ), + ), + ("moyen", models.CharField(max_length=255)), ], ), migrations.AddField( - model_name='facture', - name='paiement', - field=models.ForeignKey(to='cotisations.Paiement', on_delete=django.db.models.deletion.PROTECT), + model_name="facture", + name="paiement", + field=models.ForeignKey( + to="cotisations.Paiement", on_delete=django.db.models.deletion.PROTECT + ), ), migrations.AddField( - model_name='facture', - name='user', - field=models.ForeignKey(to='users.User', on_delete=django.db.models.deletion.PROTECT), + model_name="facture", + name="user", + field=models.ForeignKey( + to="users.User", on_delete=django.db.models.deletion.PROTECT + ), ), ] diff --git a/cotisations/migrations/0002_remove_facture_article.py b/cotisations/migrations/0002_remove_facture_article.py index b8617be4..5a4e68f1 100644 --- a/cotisations/migrations/0002_remove_facture_article.py +++ b/cotisations/migrations/0002_remove_facture_article.py @@ -28,13 +28,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0001_initial'), - ] + dependencies = [("cotisations", "0001_initial")] - operations = [ - migrations.RemoveField( - model_name='facture', - name='article', - ), - ] + operations = [migrations.RemoveField(model_name="facture", name="article")] diff --git a/cotisations/migrations/0003_auto_20160702_1448.py b/cotisations/migrations/0003_auto_20160702_1448.py index f8c2681f..29c4f180 100644 --- a/cotisations/migrations/0003_auto_20160702_1448.py +++ b/cotisations/migrations/0003_auto_20160702_1448.py @@ -29,14 +29,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0002_remove_facture_article'), - ] + dependencies = [("cotisations", "0002_remove_facture_article")] operations = [ migrations.AlterField( - model_name='facture', - name='banque', - field=models.ForeignKey(blank=True, to='cotisations.Banque', on_delete=django.db.models.deletion.PROTECT, null=True), - ), + model_name="facture", + name="banque", + field=models.ForeignKey( + blank=True, + to="cotisations.Banque", + on_delete=django.db.models.deletion.PROTECT, + null=True, + ), + ) ] diff --git a/cotisations/migrations/0004_auto_20160702_1528.py b/cotisations/migrations/0004_auto_20160702_1528.py index 8a92b54a..d0181a64 100644 --- a/cotisations/migrations/0004_auto_20160702_1528.py +++ b/cotisations/migrations/0004_auto_20160702_1528.py @@ -28,19 +28,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0003_auto_20160702_1448'), - ] + dependencies = [("cotisations", "0003_auto_20160702_1448")] operations = [ migrations.AlterField( - model_name='facture', - name='name', + model_name="facture", + name="name", field=models.CharField(null=True, max_length=255), ), migrations.AlterField( - model_name='facture', - name='prix', + model_name="facture", + name="prix", field=models.DecimalField(max_digits=5, null=True, decimal_places=2), ), ] diff --git a/cotisations/migrations/0005_auto_20160702_1532.py b/cotisations/migrations/0005_auto_20160702_1532.py index 8e29e93d..6017ec59 100644 --- a/cotisations/migrations/0005_auto_20160702_1532.py +++ b/cotisations/migrations/0005_auto_20160702_1532.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0004_auto_20160702_1528'), - ] + dependencies = [("cotisations", "0004_auto_20160702_1528")] operations = [ migrations.AlterField( - model_name='facture', - name='cheque', + model_name="facture", + name="cheque", field=models.CharField(max_length=255, blank=True), - ), + ) ] diff --git a/cotisations/migrations/0006_auto_20160702_1534.py b/cotisations/migrations/0006_auto_20160702_1534.py index affe71f7..750fd5b2 100644 --- a/cotisations/migrations/0006_auto_20160702_1534.py +++ b/cotisations/migrations/0006_auto_20160702_1534.py @@ -28,19 +28,19 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0005_auto_20160702_1532'), - ] + dependencies = [("cotisations", "0005_auto_20160702_1532")] operations = [ migrations.AlterField( - model_name='facture', - name='name', - field=models.CharField(null=True, default='plop', max_length=255), + model_name="facture", + name="name", + field=models.CharField(null=True, default="plop", max_length=255), ), migrations.AlterField( - model_name='facture', - name='prix', - field=models.DecimalField(null=True, decimal_places=2, default=1, max_digits=5), + model_name="facture", + name="prix", + field=models.DecimalField( + null=True, decimal_places=2, default=1, max_digits=5 + ), ), ] diff --git a/cotisations/migrations/0007_auto_20160702_1543.py b/cotisations/migrations/0007_auto_20160702_1543.py index 58b9200b..0755befb 100644 --- a/cotisations/migrations/0007_auto_20160702_1543.py +++ b/cotisations/migrations/0007_auto_20160702_1543.py @@ -28,20 +28,18 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0006_auto_20160702_1534'), - ] + dependencies = [("cotisations", "0006_auto_20160702_1534")] operations = [ migrations.AlterField( - model_name='facture', - name='name', - field=models.CharField(default='plop', max_length=255), + model_name="facture", + name="name", + field=models.CharField(default="plop", max_length=255), preserve_default=False, ), migrations.AlterField( - model_name='facture', - name='prix', + model_name="facture", + name="prix", field=models.DecimalField(default=1, max_digits=5, decimal_places=2), preserve_default=False, ), diff --git a/cotisations/migrations/0008_auto_20160702_1614.py b/cotisations/migrations/0008_auto_20160702_1614.py index c94db952..c3490ceb 100644 --- a/cotisations/migrations/0008_auto_20160702_1614.py +++ b/cotisations/migrations/0008_auto_20160702_1614.py @@ -30,43 +30,53 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('users', '0005_auto_20160702_0006'), - ('cotisations', '0007_auto_20160702_1543'), + ("users", "0005_auto_20160702_0006"), + ("cotisations", "0007_auto_20160702_1543"), ] operations = [ migrations.CreateModel( - name='Cotisation', + name="Cotisation", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('date_start', models.DateTimeField(auto_now_add=True)), - ('date_end', models.DateTimeField()), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ("date_start", models.DateTimeField(auto_now_add=True)), + ("date_end", models.DateTimeField()), ], ), migrations.AddField( - model_name='article', - name='cotisation', + model_name="article", + name="cotisation", field=models.BooleanField(default=True), preserve_default=False, ), migrations.AddField( - model_name='article', - name='duration', + model_name="article", + name="duration", field=models.DurationField(blank=True, null=True), ), migrations.AddField( - model_name='facture', - name='valid', - field=models.BooleanField(default=True), + model_name="facture", name="valid", field=models.BooleanField(default=True) ), migrations.AddField( - model_name='cotisation', - name='facture', - field=models.ForeignKey(to='cotisations.Facture', on_delete=django.db.models.deletion.PROTECT), + model_name="cotisation", + name="facture", + field=models.ForeignKey( + to="cotisations.Facture", on_delete=django.db.models.deletion.PROTECT + ), ), migrations.AddField( - model_name='cotisation', - name='user', - field=models.ForeignKey(to='users.User', on_delete=django.db.models.deletion.PROTECT), + model_name="cotisation", + name="user", + field=models.ForeignKey( + to="users.User", on_delete=django.db.models.deletion.PROTECT + ), ), ] diff --git a/cotisations/migrations/0009_remove_cotisation_user.py b/cotisations/migrations/0009_remove_cotisation_user.py index 0347ca95..784e6205 100644 --- a/cotisations/migrations/0009_remove_cotisation_user.py +++ b/cotisations/migrations/0009_remove_cotisation_user.py @@ -28,13 +28,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0008_auto_20160702_1614'), - ] + dependencies = [("cotisations", "0008_auto_20160702_1614")] - operations = [ - migrations.RemoveField( - model_name='cotisation', - name='user', - ), - ] + operations = [migrations.RemoveField(model_name="cotisation", name="user")] diff --git a/cotisations/migrations/0010_auto_20160702_1840.py b/cotisations/migrations/0010_auto_20160702_1840.py index c57d013b..cdae642e 100644 --- a/cotisations/migrations/0010_auto_20160702_1840.py +++ b/cotisations/migrations/0010_auto_20160702_1840.py @@ -28,18 +28,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0009_remove_cotisation_user'), - ] + dependencies = [("cotisations", "0009_remove_cotisation_user")] operations = [ - migrations.RemoveField( - model_name='article', - name='duration', - ), + migrations.RemoveField(model_name="article", name="duration"), migrations.AddField( - model_name='article', - name='duration', - field=models.IntegerField(null=True, help_text='Durée exprimée en mois entiers', blank=True), + model_name="article", + name="duration", + field=models.IntegerField( + null=True, help_text="Durée exprimée en mois entiers", blank=True + ), ), ] diff --git a/cotisations/migrations/0011_auto_20160702_1911.py b/cotisations/migrations/0011_auto_20160702_1911.py index 3bb82f45..fec46c36 100644 --- a/cotisations/migrations/0011_auto_20160702_1911.py +++ b/cotisations/migrations/0011_auto_20160702_1911.py @@ -28,14 +28,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0010_auto_20160702_1840'), - ] + dependencies = [("cotisations", "0010_auto_20160702_1840")] operations = [ migrations.AlterField( - model_name='cotisation', - name='date_start', - field=models.DateTimeField(), - ), + model_name="cotisation", name="date_start", field=models.DateTimeField() + ) ] diff --git a/cotisations/migrations/0012_auto_20160704_0118.py b/cotisations/migrations/0012_auto_20160704_0118.py index 64fab6da..0e2ac7ae 100644 --- a/cotisations/migrations/0012_auto_20160704_0118.py +++ b/cotisations/migrations/0012_auto_20160704_0118.py @@ -29,14 +29,14 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0011_auto_20160702_1911'), - ] + dependencies = [("cotisations", "0011_auto_20160702_1911")] operations = [ migrations.AlterField( - model_name='cotisation', - name='facture', - field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='cotisations.Facture'), - ), + model_name="cotisation", + name="facture", + field=models.OneToOneField( + on_delete=django.db.models.deletion.PROTECT, to="cotisations.Facture" + ), + ) ] diff --git a/cotisations/migrations/0013_auto_20160711_2240.py b/cotisations/migrations/0013_auto_20160711_2240.py index 69e437b8..cfff6a7a 100644 --- a/cotisations/migrations/0013_auto_20160711_2240.py +++ b/cotisations/migrations/0013_auto_20160711_2240.py @@ -29,32 +29,41 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0012_auto_20160704_0118'), - ] + dependencies = [("cotisations", "0012_auto_20160704_0118")] operations = [ migrations.CreateModel( - name='Vente', + name="Vente", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), - ('prix', models.DecimalField(decimal_places=2, max_digits=5)), - ('cotisation', models.BooleanField()), - ('duration', models.IntegerField(null=True, blank=True, help_text='Durée exprimée en mois entiers')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), + ("prix", models.DecimalField(decimal_places=2, max_digits=5)), + ("cotisation", models.BooleanField()), + ( + "duration", + models.IntegerField( + null=True, + blank=True, + help_text="Durée exprimée en mois entiers", + ), + ), ], ), - migrations.RemoveField( - model_name='facture', - name='name', - ), - migrations.RemoveField( - model_name='facture', - name='prix', - ), + migrations.RemoveField(model_name="facture", name="name"), + migrations.RemoveField(model_name="facture", name="prix"), migrations.AddField( - model_name='vente', - name='facture', - field=models.ForeignKey(to='cotisations.Facture', on_delete=django.db.models.deletion.PROTECT), + model_name="vente", + name="facture", + field=models.ForeignKey( + to="cotisations.Facture", on_delete=django.db.models.deletion.PROTECT + ), ), ] diff --git a/cotisations/migrations/0014_auto_20160712_0245.py b/cotisations/migrations/0014_auto_20160712_0245.py index 530ba427..1a7bd48a 100644 --- a/cotisations/migrations/0014_auto_20160712_0245.py +++ b/cotisations/migrations/0014_auto_20160712_0245.py @@ -28,18 +28,13 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0013_auto_20160711_2240'), - ] + dependencies = [("cotisations", "0013_auto_20160711_2240")] operations = [ - migrations.RemoveField( - model_name='facture', - name='number', - ), + migrations.RemoveField(model_name="facture", name="number"), migrations.AddField( - model_name='vente', - name='number', + model_name="vente", + name="number", field=models.IntegerField(default=1), preserve_default=False, ), diff --git a/cotisations/migrations/0015_auto_20160714_2142.py b/cotisations/migrations/0015_auto_20160714_2142.py index 203d2702..636f138f 100644 --- a/cotisations/migrations/0015_auto_20160714_2142.py +++ b/cotisations/migrations/0015_auto_20160714_2142.py @@ -29,29 +29,29 @@ import django.core.validators class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0014_auto_20160712_0245'), - ] + dependencies = [("cotisations", "0014_auto_20160712_0245")] operations = [ migrations.AddField( - model_name='facture', - name='control', + model_name="facture", + name="control", field=models.BooleanField(default=False), ), migrations.AlterField( - model_name='cotisation', - name='facture', - field=models.OneToOneField(to='cotisations.Facture'), + model_name="cotisation", + name="facture", + field=models.OneToOneField(to="cotisations.Facture"), ), migrations.AlterField( - model_name='vente', - name='facture', - field=models.ForeignKey(to='cotisations.Facture'), + model_name="vente", + name="facture", + field=models.ForeignKey(to="cotisations.Facture"), ), migrations.AlterField( - model_name='vente', - name='number', - field=models.IntegerField(validators=[django.core.validators.MinValueValidator(1)]), + model_name="vente", + name="number", + field=models.IntegerField( + validators=[django.core.validators.MinValueValidator(1)] + ), ), ] diff --git a/cotisations/migrations/0016_auto_20160715_0110.py b/cotisations/migrations/0016_auto_20160715_0110.py index 79c7ba56..f7e00396 100644 --- a/cotisations/migrations/0016_auto_20160715_0110.py +++ b/cotisations/migrations/0016_auto_20160715_0110.py @@ -28,29 +28,20 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0015_auto_20160714_2142'), - ] + dependencies = [("cotisations", "0015_auto_20160714_2142")] operations = [ migrations.RenameField( - model_name='article', - old_name='cotisation', - new_name='iscotisation', + model_name="article", old_name="cotisation", new_name="iscotisation" ), migrations.RenameField( - model_name='vente', - old_name='cotisation', - new_name='iscotisation', - ), - migrations.RemoveField( - model_name='cotisation', - name='facture', + model_name="vente", old_name="cotisation", new_name="iscotisation" ), + migrations.RemoveField(model_name="cotisation", name="facture"), migrations.AddField( - model_name='cotisation', - name='vente', - field=models.OneToOneField(to='cotisations.Vente', null=True), + model_name="cotisation", + name="vente", + field=models.OneToOneField(to="cotisations.Vente", null=True), preserve_default=False, ), ] diff --git a/cotisations/migrations/0017_auto_20170718_2329.py b/cotisations/migrations/0017_auto_20170718_2329.py index 4980bb1e..585a3ea0 100644 --- a/cotisations/migrations/0017_auto_20170718_2329.py +++ b/cotisations/migrations/0017_auto_20170718_2329.py @@ -8,19 +8,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0016_auto_20160715_0110'), - ] + dependencies = [("cotisations", "0016_auto_20160715_0110")] operations = [ migrations.AlterField( - model_name='article', - name='duration', - field=models.IntegerField(blank=True, help_text='Durée exprimée en mois entiers', null=True, validators=[django.core.validators.MinValueValidator(0)]), + model_name="article", + name="duration", + field=models.IntegerField( + blank=True, + help_text="Durée exprimée en mois entiers", + null=True, + validators=[django.core.validators.MinValueValidator(0)], + ), ), migrations.AlterField( - model_name='article', - name='name', + model_name="article", + name="name", field=models.CharField(max_length=255, unique=True), ), ] diff --git a/cotisations/migrations/0018_paiement_type_paiement.py b/cotisations/migrations/0018_paiement_type_paiement.py index 488fcf47..8f23742f 100644 --- a/cotisations/migrations/0018_paiement_type_paiement.py +++ b/cotisations/migrations/0018_paiement_type_paiement.py @@ -7,15 +7,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0017_auto_20170718_2329'), - ] + dependencies = [("cotisations", "0017_auto_20170718_2329")] operations = [ migrations.AddField( - model_name='paiement', - name='type_paiement', - field=models.CharField(choices=[('check', 'Chèque'), (None, 'Autre')], default=None, max_length=255), + model_name="paiement", + name="type_paiement", + field=models.CharField( + choices=[("check", "Chèque"), (None, "Autre")], + default=None, + max_length=255, + ), preserve_default=False, - ), + ) ] diff --git a/cotisations/migrations/0019_auto_20170819_0055.py b/cotisations/migrations/0019_auto_20170819_0055.py index e4794a01..66a35e3a 100644 --- a/cotisations/migrations/0019_auto_20170819_0055.py +++ b/cotisations/migrations/0019_auto_20170819_0055.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0018_paiement_type_paiement'), - ] + dependencies = [("cotisations", "0018_paiement_type_paiement")] operations = [ migrations.AlterField( - model_name='paiement', - name='type_paiement', - field=models.CharField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255), - ), + model_name="paiement", + name="type_paiement", + field=models.CharField( + choices=[(0, "Autre"), (1, "Chèque")], default=0, max_length=255 + ), + ) ] diff --git a/cotisations/migrations/0020_auto_20170819_0057.py b/cotisations/migrations/0020_auto_20170819_0057.py index c0a319e8..9e52adaf 100644 --- a/cotisations/migrations/0020_auto_20170819_0057.py +++ b/cotisations/migrations/0020_auto_20170819_0057.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0019_auto_20170819_0055'), - ] + dependencies = [("cotisations", "0019_auto_20170819_0055")] operations = [ migrations.AlterField( - model_name='paiement', - name='type_paiement', - field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255), - ), + model_name="paiement", + name="type_paiement", + field=models.IntegerField( + choices=[(0, "Autre"), (1, "Chèque")], default=0, max_length=255 + ), + ) ] diff --git a/cotisations/migrations/0021_auto_20170819_0104.py b/cotisations/migrations/0021_auto_20170819_0104.py index 1f165a44..f6b95642 100644 --- a/cotisations/migrations/0021_auto_20170819_0104.py +++ b/cotisations/migrations/0021_auto_20170819_0104.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0020_auto_20170819_0057'), - ] + dependencies = [("cotisations", "0020_auto_20170819_0057")] operations = [ migrations.AlterField( - model_name='paiement', - name='type_paiement', - field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0), - ), + model_name="paiement", + name="type_paiement", + field=models.IntegerField(choices=[(0, "Autre"), (1, "Chèque")], default=0), + ) ] diff --git a/cotisations/migrations/0022_auto_20170824_0128.py b/cotisations/migrations/0022_auto_20170824_0128.py index bd605aee..be932b14 100644 --- a/cotisations/migrations/0022_auto_20170824_0128.py +++ b/cotisations/migrations/0022_auto_20170824_0128.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0021_auto_20170819_0104'), - ] + dependencies = [("cotisations", "0021_auto_20170819_0104")] operations = [ migrations.AlterField( - model_name='paiement', - name='type_paiement', - field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255), - ), + model_name="paiement", + name="type_paiement", + field=models.IntegerField( + choices=[(0, "Autre"), (1, "Chèque")], default=0, max_length=255 + ), + ) ] diff --git a/cotisations/migrations/0023_auto_20170902_1303.py b/cotisations/migrations/0023_auto_20170902_1303.py index 04453c18..f9a60526 100644 --- a/cotisations/migrations/0023_auto_20170902_1303.py +++ b/cotisations/migrations/0023_auto_20170902_1303.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0022_auto_20170824_0128'), - ] + dependencies = [("cotisations", "0022_auto_20170824_0128")] operations = [ migrations.AlterField( - model_name='paiement', - name='type_paiement', - field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0), - ), + model_name="paiement", + name="type_paiement", + field=models.IntegerField(choices=[(0, "Autre"), (1, "Chèque")], default=0), + ) ] diff --git a/cotisations/migrations/0024_auto_20171015_2033.py b/cotisations/migrations/0024_auto_20171015_2033.py index b52dad62..c9900946 100644 --- a/cotisations/migrations/0024_auto_20171015_2033.py +++ b/cotisations/migrations/0024_auto_20171015_2033.py @@ -8,19 +8,24 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0023_auto_20170902_1303'), - ] + 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)]), + 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), + 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/migrations/0025_article_type_user.py b/cotisations/migrations/0025_article_type_user.py index 5ad329fa..86e5567b 100644 --- a/cotisations/migrations/0025_article_type_user.py +++ b/cotisations/migrations/0025_article_type_user.py @@ -7,14 +7,16 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0024_auto_20171015_2033'), - ] + dependencies = [("cotisations", "0024_auto_20171015_2033")] operations = [ migrations.AddField( - model_name='article', - name='type_user', - field=models.CharField(choices=[('Adherent', 'Adherent'), ('Club', 'Club'), ('All', 'All')], default='All', max_length=255), - ), + model_name="article", + name="type_user", + field=models.CharField( + choices=[("Adherent", "Adherent"), ("Club", "Club"), ("All", "All")], + default="All", + max_length=255, + ), + ) ] diff --git a/cotisations/migrations/0026_auto_20171028_0126.py b/cotisations/migrations/0026_auto_20171028_0126.py index 41395a94..d9a2e8db 100644 --- a/cotisations/migrations/0026_auto_20171028_0126.py +++ b/cotisations/migrations/0026_auto_20171028_0126.py @@ -6,73 +6,94 @@ from django.db import migrations, models def create_type(apps, schema_editor): - Cotisation = apps.get_model('cotisations', 'Cotisation') - Vente = apps.get_model('cotisations', 'Vente') - Article = apps.get_model('cotisations', 'Article') + Cotisation = apps.get_model("cotisations", "Cotisation") + Vente = apps.get_model("cotisations", "Vente") + Article = apps.get_model("cotisations", "Article") db_alias = schema_editor.connection.alias articles = Article.objects.using(db_alias).all() ventes = Vente.objects.using(db_alias).all() cotisations = Cotisation.objects.using(db_alias).all() for article in articles: if article.iscotisation: - article.type_cotisation='All' + article.type_cotisation = "All" article.save(using=db_alias) for vente in ventes: if vente.iscotisation: - vente.type_cotisation='All' + vente.type_cotisation = "All" vente.save(using=db_alias) for cotisation in cotisations: - cotisation.type_cotisation='All' + cotisation.type_cotisation = "All" cotisation.save(using=db_alias) + def delete_type(apps, schema_editor): - Vente = apps.get_model('cotisations', 'Vente') - Article = apps.get_model('cotisations', 'Article') + Vente = apps.get_model("cotisations", "Vente") + Article = apps.get_model("cotisations", "Article") db_alias = schema_editor.connection.alias articles = Article.objects.using(db_alias).all() ventes = Vente.objects.using(db_alias).all() for article in articles: if article.type_cotisation: - article.iscotisation=True + article.iscotisation = True else: - article.iscotisation=False + article.iscotisation = False article.save(using=db_alias) for vente in ventes: if vente.iscotisation: - vente.iscotisation=True + vente.iscotisation = True else: - vente.iscotisation=False + vente.iscotisation = False vente.save(using=db_alias) + class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0025_article_type_user'), - ] + dependencies = [("cotisations", "0025_article_type_user")] operations = [ migrations.AddField( - model_name='article', - name='type_cotisation', - field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], default=None, max_length=255, null=True), + model_name="article", + name="type_cotisation", + field=models.CharField( + blank=True, + choices=[ + ("Connexion", "Connexion"), + ("Adhesion", "Adhesion"), + ("All", "All"), + ], + default=None, + max_length=255, + null=True, + ), ), migrations.AddField( - model_name='cotisation', - name='type_cotisation', - field=models.CharField(choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], max_length=255, default='All'), + model_name="cotisation", + name="type_cotisation", + field=models.CharField( + choices=[ + ("Connexion", "Connexion"), + ("Adhesion", "Adhesion"), + ("All", "All"), + ], + max_length=255, + default="All", + ), ), migrations.AddField( - model_name='vente', - name='type_cotisation', - field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], max_length=255, null=True), + model_name="vente", + name="type_cotisation", + field=models.CharField( + blank=True, + choices=[ + ("Connexion", "Connexion"), + ("Adhesion", "Adhesion"), + ("All", "All"), + ], + max_length=255, + null=True, + ), ), migrations.RunPython(create_type, delete_type), - migrations.RemoveField( - model_name='article', - name='iscotisation', - ), - migrations.RemoveField( - model_name='vente', - name='iscotisation', - ), + migrations.RemoveField(model_name="article", name="iscotisation"), + migrations.RemoveField(model_name="vente", name="iscotisation"), ] diff --git a/cotisations/migrations/0027_auto_20171029_1156.py b/cotisations/migrations/0027_auto_20171029_1156.py index 8a9a4f0c..fa66698b 100644 --- a/cotisations/migrations/0027_auto_20171029_1156.py +++ b/cotisations/migrations/0027_auto_20171029_1156.py @@ -7,14 +7,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0026_auto_20171028_0126'), - ] + dependencies = [("cotisations", "0026_auto_20171028_0126")] operations = [ migrations.AlterField( - model_name='article', - name='name', - field=models.CharField(max_length=255), - ), + model_name="article", name="name", field=models.CharField(max_length=255) + ) ] diff --git a/cotisations/migrations/0028_auto_20171231_0007.py b/cotisations/migrations/0028_auto_20171231_0007.py index 0d492489..b968072d 100644 --- a/cotisations/migrations/0028_auto_20171231_0007.py +++ b/cotisations/migrations/0028_auto_20171231_0007.py @@ -7,33 +7,56 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0027_auto_20171029_1156'), - ] + dependencies = [("cotisations", "0027_auto_20171029_1156")] operations = [ migrations.AlterModelOptions( - name='article', - options={'permissions': (('view_article', 'Peut voir un objet article'),)}, + name="article", + options={"permissions": (("view_article", "Peut voir un objet article"),)}, ), migrations.AlterModelOptions( - name='banque', - options={'permissions': (('view_banque', 'Peut voir un objet banque'),)}, + name="banque", + options={"permissions": (("view_banque", "Peut voir un objet banque"),)}, ), migrations.AlterModelOptions( - name='cotisation', - options={'permissions': (('view_cotisation', 'Peut voir un objet cotisation'), ('change_all_cotisation', 'Superdroit, peut modifier toutes les cotisations'))}, + name="cotisation", + options={ + "permissions": ( + ("view_cotisation", "Peut voir un objet cotisation"), + ( + "change_all_cotisation", + "Superdroit, peut modifier toutes les cotisations", + ), + ) + }, ), migrations.AlterModelOptions( - name='facture', - options={'permissions': (('change_facture_control', "Peut changer l'etat de controle"), ('change_facture_pdf', 'Peut éditer une facture pdf'), ('view_facture', 'Peut voir un objet facture'), ('change_all_facture', 'Superdroit, peut modifier toutes les factures'))}, + name="facture", + options={ + "permissions": ( + ("change_facture_control", "Peut changer l'etat de controle"), + ("change_facture_pdf", "Peut éditer une facture pdf"), + ("view_facture", "Peut voir un objet facture"), + ( + "change_all_facture", + "Superdroit, peut modifier toutes les factures", + ), + ) + }, ), migrations.AlterModelOptions( - name='paiement', - options={'permissions': (('view_paiement', 'Peut voir un objet paiement'),)}, + name="paiement", + options={ + "permissions": (("view_paiement", "Peut voir un objet paiement"),) + }, ), migrations.AlterModelOptions( - name='vente', - options={'permissions': (('view_vente', 'Peut voir un objet vente'), ('change_all_vente', 'Superdroit, peut modifier toutes les ventes'))}, + name="vente", + options={ + "permissions": ( + ("view_vente", "Peut voir un objet vente"), + ("change_all_vente", "Superdroit, peut modifier toutes les ventes"), + ) + }, ), ] diff --git a/cotisations/migrations/0029_auto_20180414_2056.py b/cotisations/migrations/0029_auto_20180414_2056.py index f0cb63fd..cd13ecad 100644 --- a/cotisations/migrations/0029_auto_20180414_2056.py +++ b/cotisations/migrations/0029_auto_20180414_2056.py @@ -9,143 +9,242 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0028_auto_20171231_0007'), - ] + dependencies = [("cotisations", "0028_auto_20171231_0007")] operations = [ migrations.AlterModelOptions( - name='article', - options={'permissions': (('view_article', "Can see an article's details"),), 'verbose_name': 'Article', 'verbose_name_plural': 'Articles'}, + name="article", + options={ + "permissions": (("view_article", "Can see an article's details"),), + "verbose_name": "Article", + "verbose_name_plural": "Articles", + }, ), migrations.AlterModelOptions( - name='banque', - options={'permissions': (('view_banque', "Can see a bank's details"),), 'verbose_name': 'Bank', 'verbose_name_plural': 'Banks'}, + name="banque", + options={ + "permissions": (("view_banque", "Can see a bank's details"),), + "verbose_name": "Bank", + "verbose_name_plural": "Banks", + }, ), migrations.AlterModelOptions( - name='cotisation', - options={'permissions': (('view_cotisation', "Can see a cotisation's details"), ('change_all_cotisation', 'Can edit the previous cotisations'))}, + name="cotisation", + options={ + "permissions": ( + ("view_cotisation", "Can see a cotisation's details"), + ("change_all_cotisation", "Can edit the previous cotisations"), + ) + }, ), migrations.AlterModelOptions( - name='facture', - options={'permissions': (('change_facture_control', 'Can change the "controlled" state'), ('change_facture_pdf', 'Can create a custom PDF invoice'), ('view_facture', "Can see an invoice's details"), ('change_all_facture', 'Can edit all the previous invoices')), 'verbose_name': 'Invoice', 'verbose_name_plural': 'Invoices'}, + name="facture", + options={ + "permissions": ( + ("change_facture_control", 'Can change the "controlled" state'), + ("change_facture_pdf", "Can create a custom PDF invoice"), + ("view_facture", "Can see an invoice's details"), + ("change_all_facture", "Can edit all the previous invoices"), + ), + "verbose_name": "Invoice", + "verbose_name_plural": "Invoices", + }, ), migrations.AlterModelOptions( - name='paiement', - options={'permissions': (('view_paiement', "Can see a payement's details"),), 'verbose_name': 'Payment method', 'verbose_name_plural': 'Payment methods'}, + name="paiement", + options={ + "permissions": (("view_paiement", "Can see a payement's details"),), + "verbose_name": "Payment method", + "verbose_name_plural": "Payment methods", + }, ), migrations.AlterModelOptions( - name='vente', - options={'permissions': (('view_vente', "Can see a purchase's details"), ('change_all_vente', 'Can edit all the previous purchases')), 'verbose_name': 'Purchase', 'verbose_name_plural': 'Purchases'}, + name="vente", + options={ + "permissions": ( + ("view_vente", "Can see a purchase's details"), + ("change_all_vente", "Can edit all the previous purchases"), + ), + "verbose_name": "Purchase", + "verbose_name_plural": "Purchases", + }, ), migrations.AlterField( - model_name='article', - name='duration', - field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Duration (in whole month)'), + model_name="article", + name="duration", + field=models.PositiveIntegerField( + blank=True, + null=True, + validators=[django.core.validators.MinValueValidator(0)], + verbose_name="Duration (in whole month)", + ), ), migrations.AlterField( - model_name='article', - name='name', - field=models.CharField(max_length=255, verbose_name='Designation'), + model_name="article", + name="name", + field=models.CharField(max_length=255, verbose_name="Designation"), ), migrations.AlterField( - model_name='article', - name='prix', - field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='Unitary price'), + model_name="article", + name="prix", + field=models.DecimalField( + decimal_places=2, max_digits=5, verbose_name="Unitary price" + ), ), migrations.AlterField( - model_name='article', - name='type_cotisation', - field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default=None, max_length=255, null=True, verbose_name='Type of cotisation'), + model_name="article", + name="type_cotisation", + field=models.CharField( + blank=True, + choices=[ + ("Connexion", "Connexion"), + ("Adhesion", "Membership"), + ("All", "Both of them"), + ], + default=None, + max_length=255, + null=True, + verbose_name="Type of cotisation", + ), ), migrations.AlterField( - model_name='article', - name='type_user', - field=models.CharField(choices=[('Adherent', 'Member'), ('Club', 'Club'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='Type of users concerned'), + model_name="article", + name="type_user", + field=models.CharField( + choices=[ + ("Adherent", "Member"), + ("Club", "Club"), + ("All", "Both of them"), + ], + default="All", + max_length=255, + verbose_name="Type of users concerned", + ), ), migrations.AlterField( - model_name='banque', - name='name', - field=models.CharField(max_length=255, verbose_name='Name'), + model_name="banque", + name="name", + field=models.CharField(max_length=255, verbose_name="Name"), ), migrations.AlterField( - model_name='cotisation', - name='date_end', - field=models.DateTimeField(verbose_name='Ending date'), + model_name="cotisation", + name="date_end", + field=models.DateTimeField(verbose_name="Ending date"), ), migrations.AlterField( - model_name='cotisation', - name='date_start', - field=models.DateTimeField(verbose_name='Starting date'), + model_name="cotisation", + name="date_start", + field=models.DateTimeField(verbose_name="Starting date"), ), migrations.AlterField( - model_name='cotisation', - name='type_cotisation', - field=models.CharField(choices=[('Connexion', 'Connexion'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='Type of cotisation'), + model_name="cotisation", + name="type_cotisation", + field=models.CharField( + choices=[ + ("Connexion", "Connexion"), + ("Adhesion", "Membership"), + ("All", "Both of them"), + ], + default="All", + max_length=255, + verbose_name="Type of cotisation", + ), ), migrations.AlterField( - model_name='cotisation', - name='vente', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='cotisations.Vente', verbose_name='Purchase'), + model_name="cotisation", + name="vente", + field=models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="cotisations.Vente", + verbose_name="Purchase", + ), ), migrations.AlterField( - model_name='facture', - name='cheque', - field=models.CharField(blank=True, max_length=255, verbose_name='Cheque number'), + model_name="facture", + name="cheque", + field=models.CharField( + blank=True, max_length=255, verbose_name="Cheque number" + ), ), migrations.AlterField( - model_name='facture', - name='control', - field=models.BooleanField(default=False, verbose_name='Controlled'), + model_name="facture", + name="control", + field=models.BooleanField(default=False, verbose_name="Controlled"), ), migrations.AlterField( - model_name='facture', - name='date', - field=models.DateTimeField(auto_now_add=True, verbose_name='Date'), + model_name="facture", + name="date", + field=models.DateTimeField(auto_now_add=True, verbose_name="Date"), ), migrations.AlterField( - model_name='facture', - name='valid', - field=models.BooleanField(default=True, verbose_name='Validated'), + model_name="facture", + name="valid", + field=models.BooleanField(default=True, verbose_name="Validated"), ), migrations.AlterField( - model_name='paiement', - name='moyen', - field=models.CharField(max_length=255, verbose_name='Method'), + model_name="paiement", + name="moyen", + field=models.CharField(max_length=255, verbose_name="Method"), ), migrations.AlterField( - model_name='paiement', - name='type_paiement', - field=models.IntegerField(choices=[(0, 'Standard'), (1, 'Cheque')], default=0, verbose_name='Payment type'), + model_name="paiement", + name="type_paiement", + field=models.IntegerField( + choices=[(0, "Standard"), (1, "Cheque")], + default=0, + verbose_name="Payment type", + ), ), migrations.AlterField( - model_name='vente', - name='duration', - field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Duration (in whole month)'), + model_name="vente", + name="duration", + field=models.PositiveIntegerField( + blank=True, null=True, verbose_name="Duration (in whole month)" + ), ), migrations.AlterField( - model_name='vente', - name='facture', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cotisations.Facture', verbose_name='Invoice'), + model_name="vente", + name="facture", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="cotisations.Facture", + verbose_name="Invoice", + ), ), migrations.AlterField( - model_name='vente', - name='name', - field=models.CharField(max_length=255, verbose_name='Article'), + model_name="vente", + name="name", + field=models.CharField(max_length=255, verbose_name="Article"), ), migrations.AlterField( - model_name='vente', - name='number', - field=models.IntegerField(validators=[django.core.validators.MinValueValidator(1)], verbose_name='Amount'), + model_name="vente", + name="number", + field=models.IntegerField( + validators=[django.core.validators.MinValueValidator(1)], + verbose_name="Amount", + ), ), migrations.AlterField( - model_name='vente', - name='prix', - field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='Price'), + model_name="vente", + name="prix", + field=models.DecimalField( + decimal_places=2, max_digits=5, verbose_name="Price" + ), ), migrations.AlterField( - model_name='vente', - name='type_cotisation', - field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Membership'), ('All', 'Both of them')], max_length=255, null=True, verbose_name='Type of cotisation'), + model_name="vente", + name="type_cotisation", + field=models.CharField( + blank=True, + choices=[ + ("Connexion", "Connexion"), + ("Adhesion", "Membership"), + ("All", "Both of them"), + ], + max_length=255, + null=True, + verbose_name="Type of cotisation", + ), ), ] diff --git a/cotisations/migrations/0030_custom_payment.py b/cotisations/migrations/0030_custom_payment.py index ec6f08d1..5a528434 100644 --- a/cotisations/migrations/0030_custom_payment.py +++ b/cotisations/migrations/0030_custom_payment.py @@ -9,8 +9,8 @@ import django.db.models.deletion def add_cheque(apps, schema_editor): - ChequePayment = apps.get_model('cotisations', 'ChequePayment') - Payment = apps.get_model('cotisations', 'Paiement') + ChequePayment = apps.get_model("cotisations", "ChequePayment") + Payment = apps.get_model("cotisations", "Paiement") for p in Payment.objects.filter(type_paiement=1): cheque = ChequePayment() cheque.payment = p @@ -18,14 +18,12 @@ def add_cheque(apps, schema_editor): def add_comnpay(apps, schema_editor): - ComnpayPayment = apps.get_model('cotisations', 'ComnpayPayment') - Payment = apps.get_model('cotisations', 'Paiement') - AssoOption = apps.get_model('preferences', 'AssoOption') + ComnpayPayment = apps.get_model("cotisations", "ComnpayPayment") + Payment = apps.get_model("cotisations", "Paiement") + AssoOption = apps.get_model("preferences", "AssoOption") options, _created = AssoOption.objects.get_or_create() try: - payment = Payment.objects.get( - moyen='Rechargement en ligne' - ) + payment = Payment.objects.get(moyen="Rechargement en ligne") except Payment.DoesNotExist: return comnpay = ComnpayPayment() @@ -38,11 +36,11 @@ def add_comnpay(apps, schema_editor): def add_solde(apps, schema_editor): - OptionalUser = apps.get_model('preferences', 'OptionalUser') + OptionalUser = apps.get_model("preferences", "OptionalUser") options, _created = OptionalUser.objects.get_or_create() - Payment = apps.get_model('cotisations', 'Paiement') - BalancePayment = apps.get_model('cotisations', 'BalancePayment') + Payment = apps.get_model("cotisations", "Paiement") + BalancePayment = apps.get_model("cotisations", "BalancePayment") try: solde = Payment.objects.get(moyen="solde") @@ -60,73 +58,191 @@ def add_solde(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('preferences', '0044_remove_payment_pass'), - ('cotisations', '0029_auto_20180414_2056'), + ("preferences", "0044_remove_payment_pass"), + ("cotisations", "0029_auto_20180414_2056"), ] operations = [ migrations.AlterModelOptions( - name='paiement', - options={'permissions': (('view_paiement', "Can see a payement's details"), ('use_every_payment', 'Can use every payement')), 'verbose_name': 'Payment method', 'verbose_name_plural': 'Payment methods'}, + name="paiement", + options={ + "permissions": ( + ("view_paiement", "Can see a payement's details"), + ("use_every_payment", "Can use every payement"), + ), + "verbose_name": "Payment method", + "verbose_name_plural": "Payment methods", + }, ), migrations.AlterModelOptions( - name='article', - options={'permissions': (('view_article', "Can see an article's details"), ('buy_every_article', 'Can buy every_article')), 'verbose_name': 'Article', 'verbose_name_plural': 'Articles'}, + name="article", + options={ + "permissions": ( + ("view_article", "Can see an article's details"), + ("buy_every_article", "Can buy every_article"), + ), + "verbose_name": "Article", + "verbose_name_plural": "Articles", + }, ), migrations.AddField( - model_name='paiement', - name='available_for_everyone', - field=models.BooleanField(default=False, verbose_name='Is available for every user'), + model_name="paiement", + name="available_for_everyone", + field=models.BooleanField( + default=False, verbose_name="Is available for every user" + ), ), migrations.AddField( - model_name='paiement', - name='is_balance', - field=models.BooleanField(default=False, editable=False, help_text='There should be only one balance payment method.', verbose_name='Is user balance', validators=[cotisations.models.check_no_balance]), + model_name="paiement", + name="is_balance", + field=models.BooleanField( + default=False, + editable=False, + help_text="There should be only one balance payment method.", + verbose_name="Is user balance", + validators=[cotisations.models.check_no_balance], + ), ), migrations.AddField( - model_name='article', - name='available_for_everyone', - field=models.BooleanField(default=False, verbose_name='Is available for every user'), + model_name="article", + name="available_for_everyone", + field=models.BooleanField( + default=False, verbose_name="Is available for every user" + ), ), migrations.CreateModel( - name='ChequePayment', + name="ChequePayment", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "payment", + models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="payment_method", + to="cotisations.Paiement", + ), + ), ], bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), - options={'verbose_name': 'Cheque'}, + options={"verbose_name": "Cheque"}, ), migrations.CreateModel( - name='ComnpayPayment', + name="ComnpayPayment", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('payment_credential', models.CharField(blank=True, default='', max_length=255, verbose_name='ComNpay VAD Number')), - ('payment_pass', re2o.aes_field.AESEncryptedField(blank=True, max_length=255, null=True, verbose_name='ComNpay Secret Key')), - ('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), - ('minimum_payment', models.DecimalField(decimal_places=2, default=1, help_text='The minimal amount of money you have to use when paying with ComNpay', max_digits=5, verbose_name='Minimum payment')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "payment_credential", + models.CharField( + blank=True, + default="", + max_length=255, + verbose_name="ComNpay VAD Number", + ), + ), + ( + "payment_pass", + re2o.aes_field.AESEncryptedField( + blank=True, + max_length=255, + null=True, + verbose_name="ComNpay Secret Key", + ), + ), + ( + "payment", + models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="payment_method", + to="cotisations.Paiement", + ), + ), + ( + "minimum_payment", + models.DecimalField( + decimal_places=2, + default=1, + help_text="The minimal amount of money you have to use when paying with ComNpay", + max_digits=5, + verbose_name="Minimum payment", + ), + ), ], bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), - options={'verbose_name': 'ComNpay'}, + options={"verbose_name": "ComNpay"}, ), migrations.CreateModel( - name='BalancePayment', + name="BalancePayment", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('minimum_balance', models.DecimalField(decimal_places=2, default=0, help_text='The minimal amount of money allowed for the balance at the end of a payment. You can specify negative amount.', max_digits=5, verbose_name='Minimum balance')), - ('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), - ('maximum_balance', models.DecimalField(decimal_places=2, default=50, help_text='The maximal amount of money allowed for the balance.', max_digits=5, verbose_name='Maximum balance', null=True, blank=True)), - ('credit_balance_allowed', models.BooleanField(default=False, verbose_name='Allow user to credit their balance')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "minimum_balance", + models.DecimalField( + decimal_places=2, + default=0, + help_text="The minimal amount of money allowed for the balance at the end of a payment. You can specify negative amount.", + max_digits=5, + verbose_name="Minimum balance", + ), + ), + ( + "payment", + models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="payment_method", + to="cotisations.Paiement", + ), + ), + ( + "maximum_balance", + models.DecimalField( + decimal_places=2, + default=50, + help_text="The maximal amount of money allowed for the balance.", + max_digits=5, + verbose_name="Maximum balance", + null=True, + blank=True, + ), + ), + ( + "credit_balance_allowed", + models.BooleanField( + default=False, verbose_name="Allow user to credit their balance" + ), + ), ], bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), - options={'verbose_name': 'User Balance'}, + options={"verbose_name": "User Balance"}, ), migrations.RunPython(add_comnpay), migrations.RunPython(add_cheque), migrations.RunPython(add_solde), - migrations.RemoveField( - model_name='paiement', - name='type_paiement', - ), - + migrations.RemoveField(model_name="paiement", name="type_paiement"), ] diff --git a/cotisations/migrations/0031_comnpaypayment_production.py b/cotisations/migrations/0031_comnpaypayment_production.py index 25ec7fb8..3f0f48ce 100644 --- a/cotisations/migrations/0031_comnpaypayment_production.py +++ b/cotisations/migrations/0031_comnpaypayment_production.py @@ -7,14 +7,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0030_custom_payment'), - ] + dependencies = [("cotisations", "0030_custom_payment")] operations = [ migrations.AddField( - model_name='comnpaypayment', - name='production', - field=models.BooleanField(default=True, verbose_name='Production mode enabled (production url, instead of homologation)'), - ), + model_name="comnpaypayment", + name="production", + field=models.BooleanField( + default=True, + verbose_name="Production mode enabled (production url, instead of homologation)", + ), + ) ] diff --git a/cotisations/migrations/0032_custom_invoice.py b/cotisations/migrations/0032_custom_invoice.py index 39c23e8b..38b28d23 100644 --- a/cotisations/migrations/0032_custom_invoice.py +++ b/cotisations/migrations/0032_custom_invoice.py @@ -10,8 +10,8 @@ import re2o.mixins def reattribute_ids(apps, schema_editor): - Facture = apps.get_model('cotisations', 'Facture') - BaseInvoice = apps.get_model('cotisations', 'BaseInvoice') + Facture = apps.get_model("cotisations", "Facture") + BaseInvoice = apps.get_model("cotisations", "BaseInvoice") for f in Facture.objects.all(): base = BaseInvoice.objects.create(id=f.pk) @@ -22,21 +22,23 @@ def reattribute_ids(apps, schema_editor): def update_rights(apps, schema_editor): - Permission = apps.get_model('auth', 'Permission') + Permission = apps.get_model("auth", "Permission") # creates needed permissions - app = apps.get_app_config('cotisations') + app = apps.get_app_config("cotisations") app.models_module = True create_permissions(app) app.models_module = False ContentType = apps.get_model("contenttypes", "ContentType") content_type = ContentType.objects.get_for_model(Permission) - former, created = Permission.objects.get_or_create(codename='change_facture_pdf', content_type=content_type) - new_1 = Permission.objects.get(codename='add_custominvoice') - new_2 = Permission.objects.get(codename='change_custominvoice') - new_3 = Permission.objects.get(codename='view_custominvoice') - new_4 = Permission.objects.get(codename='delete_custominvoice') + former, created = Permission.objects.get_or_create( + codename="change_facture_pdf", content_type=content_type + ) + new_1 = Permission.objects.get(codename="add_custominvoice") + new_2 = Permission.objects.get(codename="change_custominvoice") + new_3 = Permission.objects.get(codename="view_custominvoice") + new_4 = Permission.objects.get(codename="delete_custominvoice") for group in former.group_set.all(): group.permissions.remove(former) group.permissions.add(new_1) @@ -48,59 +50,105 @@ def update_rights(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0031_comnpaypayment_production'), - ] + dependencies = [("cotisations", "0031_comnpaypayment_production")] operations = [ migrations.CreateModel( - name='BaseInvoice', + name="BaseInvoice", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('date', models.DateTimeField(auto_now_add=True, verbose_name='Date')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("date", models.DateTimeField(auto_now_add=True, verbose_name="Date")), ], - bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, re2o.field_permissions.FieldPermissionModelMixin, models.Model), + bases=( + re2o.mixins.RevMixin, + re2o.mixins.AclMixin, + re2o.field_permissions.FieldPermissionModelMixin, + models.Model, + ), ), migrations.CreateModel( - name='CustomInvoice', + name="CustomInvoice", fields=[ - ('baseinvoice_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.BaseInvoice')), - ('recipient', models.CharField(max_length=255, verbose_name='Recipient')), - ('payment', models.CharField(max_length=255, verbose_name='Payment type')), - ('address', models.CharField(max_length=255, verbose_name='Address')), - ('paid', models.BooleanField(verbose_name='Paid')), + ( + "baseinvoice_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="cotisations.BaseInvoice", + ), + ), + ( + "recipient", + models.CharField(max_length=255, verbose_name="Recipient"), + ), + ( + "payment", + models.CharField(max_length=255, verbose_name="Payment type"), + ), + ("address", models.CharField(max_length=255, verbose_name="Address")), + ("paid", models.BooleanField(verbose_name="Paid")), ], - bases=('cotisations.baseinvoice',), - options={'permissions': (('view_custominvoice', 'Can view a custom invoice'),)}, + bases=("cotisations.baseinvoice",), + options={ + "permissions": (("view_custominvoice", "Can view a custom invoice"),) + }, ), migrations.AddField( - model_name='facture', - name='baseinvoice_ptr', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='cotisations.BaseInvoice', null=True), + model_name="facture", + name="baseinvoice_ptr", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="cotisations.BaseInvoice", + null=True, + ), preserve_default=False, ), migrations.RunPython(reattribute_ids), migrations.AlterField( - model_name='vente', - name='facture', - field=models.ForeignKey(on_delete=models.CASCADE, verbose_name='Invoice', to='cotisations.BaseInvoice') - ), - migrations.RemoveField( - model_name='facture', - name='id', - ), - migrations.RemoveField( - model_name='facture', - name='date', + model_name="vente", + name="facture", + field=models.ForeignKey( + on_delete=models.CASCADE, + verbose_name="Invoice", + to="cotisations.BaseInvoice", + ), ), + migrations.RemoveField(model_name="facture", name="id"), + migrations.RemoveField(model_name="facture", name="date"), migrations.AlterField( - model_name='facture', - name='baseinvoice_ptr', - field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.BaseInvoice'), + model_name="facture", + name="baseinvoice_ptr", + field=models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="cotisations.BaseInvoice", + ), ), migrations.RunPython(update_rights), migrations.AlterModelOptions( - name='facture', - options={'permissions': (('change_facture_control', 'Can change the "controlled" state'), ('view_facture', "Can see an invoice's details"), ('change_all_facture', 'Can edit all the previous invoices')), 'verbose_name': 'Invoice', 'verbose_name_plural': 'Invoices'}, + name="facture", + options={ + "permissions": ( + ("change_facture_control", 'Can change the "controlled" state'), + ("view_facture", "Can see an invoice's details"), + ("change_all_facture", "Can edit all the previous invoices"), + ), + "verbose_name": "Invoice", + "verbose_name_plural": "Invoices", + }, ), ] diff --git a/cotisations/migrations/0033_auto_20180818_1319.py b/cotisations/migrations/0033_auto_20180818_1319.py index 2e61fbb6..edf8a77f 100644 --- a/cotisations/migrations/0033_auto_20180818_1319.py +++ b/cotisations/migrations/0033_auto_20180818_1319.py @@ -11,171 +11,294 @@ import re2o.aes_field class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0032_custom_invoice'), - ] + dependencies = [("cotisations", "0032_custom_invoice")] operations = [ migrations.AlterModelOptions( - name='article', - options={'permissions': (('view_article', 'Can view an article object'), ('buy_every_article', 'Can buy every article')), 'verbose_name': 'article', 'verbose_name_plural': 'articles'}, + name="article", + options={ + "permissions": ( + ("view_article", "Can view an article object"), + ("buy_every_article", "Can buy every article"), + ), + "verbose_name": "article", + "verbose_name_plural": "articles", + }, ), migrations.AlterModelOptions( - name='balancepayment', - options={'verbose_name': 'user balance'}, + name="balancepayment", options={"verbose_name": "user balance"} ), migrations.AlterModelOptions( - name='banque', - options={'permissions': (('view_banque', 'Can view a bank object'),), 'verbose_name': 'bank', 'verbose_name_plural': 'banks'}, + name="banque", + options={ + "permissions": (("view_banque", "Can view a bank object"),), + "verbose_name": "bank", + "verbose_name_plural": "banks", + }, ), migrations.AlterModelOptions( - name='cotisation', - options={'permissions': (('view_cotisation', 'Can view a subscription object'), ('change_all_cotisation', 'Can edit the previous subscriptions')), 'verbose_name': 'subscription', 'verbose_name_plural': 'subscriptions'}, + name="cotisation", + options={ + "permissions": ( + ("view_cotisation", "Can view a subscription object"), + ("change_all_cotisation", "Can edit the previous subscriptions"), + ), + "verbose_name": "subscription", + "verbose_name_plural": "subscriptions", + }, ), migrations.AlterModelOptions( - name='custominvoice', - options={'permissions': (('view_custominvoice', 'Can view a custom invoice object'),)}, + name="custominvoice", + options={ + "permissions": ( + ("view_custominvoice", "Can view a custom invoice object"), + ) + }, ), migrations.AlterModelOptions( - name='facture', - options={'permissions': (('change_facture_control', 'Can edit the "controlled" state'), ('view_facture', 'Can view an invoice object'), ('change_all_facture', 'Can edit all the previous invoices')), 'verbose_name': 'invoice', 'verbose_name_plural': 'invoices'}, + name="facture", + options={ + "permissions": ( + ("change_facture_control", 'Can edit the "controlled" state'), + ("view_facture", "Can view an invoice object"), + ("change_all_facture", "Can edit all the previous invoices"), + ), + "verbose_name": "invoice", + "verbose_name_plural": "invoices", + }, ), migrations.AlterModelOptions( - name='paiement', - options={'permissions': (('view_paiement', 'Can view a payment method object'), ('use_every_payment', 'Can use every payment method')), 'verbose_name': 'payment method', 'verbose_name_plural': 'payment methods'}, + name="paiement", + options={ + "permissions": ( + ("view_paiement", "Can view a payment method object"), + ("use_every_payment", "Can use every payment method"), + ), + "verbose_name": "payment method", + "verbose_name_plural": "payment methods", + }, ), migrations.AlterModelOptions( - name='vente', - options={'permissions': (('view_vente', 'Can view a purchase object'), ('change_all_vente', 'Can edit all the previous purchases')), 'verbose_name': 'purchase', 'verbose_name_plural': 'purchases'}, + name="vente", + options={ + "permissions": ( + ("view_vente", "Can view a purchase object"), + ("change_all_vente", "Can edit all the previous purchases"), + ), + "verbose_name": "purchase", + "verbose_name_plural": "purchases", + }, ), migrations.AlterField( - model_name='article', - name='available_for_everyone', - field=models.BooleanField(default=False, verbose_name='is available for every user'), + model_name="article", + name="available_for_everyone", + field=models.BooleanField( + default=False, verbose_name="is available for every user" + ), ), migrations.AlterField( - model_name='article', - name='duration', - field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='duration (in months)'), + model_name="article", + name="duration", + field=models.PositiveIntegerField( + blank=True, + null=True, + validators=[django.core.validators.MinValueValidator(0)], + verbose_name="duration (in months)", + ), ), migrations.AlterField( - model_name='article', - name='name', - field=models.CharField(max_length=255, verbose_name='designation'), + model_name="article", + name="name", + field=models.CharField(max_length=255, verbose_name="designation"), ), migrations.AlterField( - model_name='article', - name='prix', - field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='unit price'), + model_name="article", + name="prix", + field=models.DecimalField( + decimal_places=2, max_digits=5, verbose_name="unit price" + ), ), migrations.AlterField( - model_name='article', - name='type_cotisation', - field=models.CharField(blank=True, choices=[('Connexion', 'Connection'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default=None, max_length=255, null=True, verbose_name='subscription type'), + model_name="article", + name="type_cotisation", + field=models.CharField( + blank=True, + choices=[ + ("Connexion", "Connection"), + ("Adhesion", "Membership"), + ("All", "Both of them"), + ], + default=None, + max_length=255, + null=True, + verbose_name="subscription type", + ), ), migrations.AlterField( - model_name='article', - name='type_user', - field=models.CharField(choices=[('Adherent', 'Member'), ('Club', 'Club'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='type of users concerned'), + model_name="article", + name="type_user", + field=models.CharField( + choices=[ + ("Adherent", "Member"), + ("Club", "Club"), + ("All", "Both of them"), + ], + default="All", + max_length=255, + verbose_name="type of users concerned", + ), ), migrations.AlterField( - model_name='banque', - name='name', - field=models.CharField(max_length=255), + model_name="banque", name="name", field=models.CharField(max_length=255) ), migrations.AlterField( - model_name='comnpaypayment', - name='payment_credential', - field=models.CharField(blank=True, default='', max_length=255, verbose_name='ComNpay VAT Number'), + model_name="comnpaypayment", + name="payment_credential", + field=models.CharField( + blank=True, + default="", + max_length=255, + verbose_name="ComNpay VAT Number", + ), ), migrations.AlterField( - model_name='comnpaypayment', - name='payment_pass', - field=re2o.aes_field.AESEncryptedField(blank=True, max_length=255, null=True, verbose_name='ComNpay secret key'), + model_name="comnpaypayment", + name="payment_pass", + field=re2o.aes_field.AESEncryptedField( + blank=True, max_length=255, null=True, verbose_name="ComNpay secret key" + ), ), migrations.AlterField( - model_name='comnpaypayment', - name='production', - field=models.BooleanField(default=True, verbose_name='Production mode enabled (production URL, instead of homologation)'), + model_name="comnpaypayment", + name="production", + field=models.BooleanField( + default=True, + verbose_name="Production mode enabled (production URL, instead of homologation)", + ), ), migrations.AlterField( - model_name='cotisation', - name='date_end', - field=models.DateTimeField(verbose_name='end date'), + model_name="cotisation", + name="date_end", + field=models.DateTimeField(verbose_name="end date"), ), migrations.AlterField( - model_name='cotisation', - name='date_start', - field=models.DateTimeField(verbose_name='start date'), + model_name="cotisation", + name="date_start", + field=models.DateTimeField(verbose_name="start date"), ), migrations.AlterField( - model_name='cotisation', - name='type_cotisation', - field=models.CharField(choices=[('Connexion', 'Connection'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='subscription type'), + model_name="cotisation", + name="type_cotisation", + field=models.CharField( + choices=[ + ("Connexion", "Connection"), + ("Adhesion", "Membership"), + ("All", "Both of them"), + ], + default="All", + max_length=255, + verbose_name="subscription type", + ), ), migrations.AlterField( - model_name='cotisation', - name='vente', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='cotisations.Vente', verbose_name='purchase'), + model_name="cotisation", + name="vente", + field=models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="cotisations.Vente", + verbose_name="purchase", + ), ), migrations.AlterField( - model_name='facture', - name='cheque', - field=models.CharField(blank=True, max_length=255, verbose_name='cheque number'), + model_name="facture", + name="cheque", + field=models.CharField( + blank=True, max_length=255, verbose_name="cheque number" + ), ), migrations.AlterField( - model_name='facture', - name='control', - field=models.BooleanField(default=False, verbose_name='controlled'), + model_name="facture", + name="control", + field=models.BooleanField(default=False, verbose_name="controlled"), ), migrations.AlterField( - model_name='facture', - name='valid', - field=models.BooleanField(default=True, verbose_name='validated'), + model_name="facture", + name="valid", + field=models.BooleanField(default=True, verbose_name="validated"), ), migrations.AlterField( - model_name='paiement', - name='available_for_everyone', - field=models.BooleanField(default=False, verbose_name='is available for every user'), + model_name="paiement", + name="available_for_everyone", + field=models.BooleanField( + default=False, verbose_name="is available for every user" + ), ), migrations.AlterField( - model_name='paiement', - name='is_balance', - field=models.BooleanField(default=False, editable=False, help_text='There should be only one balance payment method.', validators=[cotisations.validators.check_no_balance], verbose_name='is user balance'), + model_name="paiement", + name="is_balance", + field=models.BooleanField( + default=False, + editable=False, + help_text="There should be only one balance payment method.", + validators=[cotisations.validators.check_no_balance], + verbose_name="is user balance", + ), ), migrations.AlterField( - model_name='paiement', - name='moyen', - field=models.CharField(max_length=255, verbose_name='method'), + model_name="paiement", + name="moyen", + field=models.CharField(max_length=255, verbose_name="method"), ), migrations.AlterField( - model_name='vente', - name='duration', - field=models.PositiveIntegerField(blank=True, null=True, verbose_name='duration (in months)'), + model_name="vente", + name="duration", + field=models.PositiveIntegerField( + blank=True, null=True, verbose_name="duration (in months)" + ), ), migrations.AlterField( - model_name='vente', - name='facture', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cotisations.BaseInvoice', verbose_name='invoice'), + model_name="vente", + name="facture", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="cotisations.BaseInvoice", + verbose_name="invoice", + ), ), migrations.AlterField( - model_name='vente', - name='name', - field=models.CharField(max_length=255, verbose_name='article'), + model_name="vente", + name="name", + field=models.CharField(max_length=255, verbose_name="article"), ), migrations.AlterField( - model_name='vente', - name='number', - field=models.IntegerField(validators=[django.core.validators.MinValueValidator(1)], verbose_name='amount'), + model_name="vente", + name="number", + field=models.IntegerField( + validators=[django.core.validators.MinValueValidator(1)], + verbose_name="amount", + ), ), migrations.AlterField( - model_name='vente', - name='prix', - field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='price'), + model_name="vente", + name="prix", + field=models.DecimalField( + decimal_places=2, max_digits=5, verbose_name="price" + ), ), migrations.AlterField( - model_name='vente', - name='type_cotisation', - field=models.CharField(blank=True, choices=[('Connexion', 'Connection'), ('Adhesion', 'Membership'), ('All', 'Both of them')], max_length=255, null=True, verbose_name='subscription type'), + model_name="vente", + name="type_cotisation", + field=models.CharField( + blank=True, + choices=[ + ("Connexion", "Connection"), + ("Adhesion", "Membership"), + ("All", "Both of them"), + ], + max_length=255, + null=True, + verbose_name="subscription type", + ), ), ] diff --git a/cotisations/migrations/0034_auto_20180831_1532.py b/cotisations/migrations/0034_auto_20180831_1532.py index ea698374..aca2a3b6 100644 --- a/cotisations/migrations/0034_auto_20180831_1532.py +++ b/cotisations/migrations/0034_auto_20180831_1532.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0033_auto_20180818_1319'), - ] + dependencies = [("cotisations", "0033_auto_20180818_1319")] operations = [ migrations.AlterField( - model_name='facture', - name='valid', - field=models.BooleanField(default=False, verbose_name='validated'), - ), + model_name="facture", + name="valid", + field=models.BooleanField(default=False, verbose_name="validated"), + ) ] diff --git a/cotisations/migrations/0035_notepayment.py b/cotisations/migrations/0035_notepayment.py index 1d8bcd48..5de8c93a 100644 --- a/cotisations/migrations/0035_notepayment.py +++ b/cotisations/migrations/0035_notepayment.py @@ -9,23 +9,35 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0034_auto_20180831_1532'), - ] + dependencies = [("cotisations", "0034_auto_20180831_1532")] operations = [ migrations.CreateModel( - name='NotePayment', + name="NotePayment", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('server', models.CharField(max_length=255, verbose_name='server')), - ('port', models.PositiveIntegerField(blank=True, null=True)), - ('id_note', models.PositiveIntegerField(blank=True, null=True)), - ('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("server", models.CharField(max_length=255, verbose_name="server")), + ("port", models.PositiveIntegerField(blank=True, null=True)), + ("id_note", models.PositiveIntegerField(blank=True, null=True)), + ( + "payment", + models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="payment_method", + to="cotisations.Paiement", + ), + ), ], - options={ - 'verbose_name': 'NoteKfet', - }, + options={"verbose_name": "NoteKfet"}, bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), - ), + ) ] diff --git a/cotisations/migrations/0036_custominvoice_remark.py b/cotisations/migrations/0036_custominvoice_remark.py index 7719b31d..90b40308 100644 --- a/cotisations/migrations/0036_custominvoice_remark.py +++ b/cotisations/migrations/0036_custominvoice_remark.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0035_notepayment'), - ] + dependencies = [("cotisations", "0035_notepayment")] operations = [ migrations.AddField( - model_name='custominvoice', - name='remark', - field=models.TextField(blank=True, null=True, verbose_name='Remark'), - ), + model_name="custominvoice", + name="remark", + field=models.TextField(blank=True, null=True, verbose_name="Remark"), + ) ] diff --git a/cotisations/migrations/0037_costestimate.py b/cotisations/migrations/0037_costestimate.py index 3d97f3f3..4cf72564 100644 --- a/cotisations/migrations/0037_costestimate.py +++ b/cotisations/migrations/0037_costestimate.py @@ -8,21 +8,40 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0036_custominvoice_remark'), - ] + dependencies = [("cotisations", "0036_custominvoice_remark")] operations = [ migrations.CreateModel( - name='CostEstimate', + name="CostEstimate", fields=[ - ('custominvoice_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.CustomInvoice')), - ('validity', models.DurationField(verbose_name='Period of validity')), - ('final_invoice', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='origin_cost_estimate', to='cotisations.CustomInvoice')), + ( + "custominvoice_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="cotisations.CustomInvoice", + ), + ), + ("validity", models.DurationField(verbose_name="Period of validity")), + ( + "final_invoice", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="origin_cost_estimate", + to="cotisations.CustomInvoice", + ), + ), ], options={ - 'permissions': (('view_costestimate', 'Can view a cost estimate object'),), + "permissions": ( + ("view_costestimate", "Can view a cost estimate object"), + ) }, - bases=('cotisations.custominvoice',), - ), + bases=("cotisations.custominvoice",), + ) ] diff --git a/cotisations/migrations/0038_auto_20181231_1657.py b/cotisations/migrations/0038_auto_20181231_1657.py index a9415bf0..9d6c67cd 100644 --- a/cotisations/migrations/0038_auto_20181231_1657.py +++ b/cotisations/migrations/0038_auto_20181231_1657.py @@ -8,24 +8,30 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0037_costestimate'), - ] + dependencies = [("cotisations", "0037_costestimate")] operations = [ migrations.AlterField( - model_name='costestimate', - name='final_invoice', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='origin_cost_estimate', to='cotisations.CustomInvoice'), + model_name="costestimate", + name="final_invoice", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="origin_cost_estimate", + to="cotisations.CustomInvoice", + ), ), migrations.AlterField( - model_name='costestimate', - name='validity', - field=models.DurationField(help_text='DD HH:MM:SS', verbose_name='Period of validity'), + model_name="costestimate", + name="validity", + field=models.DurationField( + help_text="DD HH:MM:SS", verbose_name="Period of validity" + ), ), migrations.AlterField( - model_name='custominvoice', - name='paid', - field=models.BooleanField(default=False, verbose_name='Paid'), + model_name="custominvoice", + name="paid", + field=models.BooleanField(default=False, verbose_name="Paid"), ), ] diff --git a/cotisations/migrations/0039_freepayment.py b/cotisations/migrations/0039_freepayment.py index 127f80e1..9dc0a66f 100644 --- a/cotisations/migrations/0039_freepayment.py +++ b/cotisations/migrations/0039_freepayment.py @@ -9,20 +9,32 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0038_auto_20181231_1657'), - ] + dependencies = [("cotisations", "0038_auto_20181231_1657")] operations = [ migrations.CreateModel( - name='FreePayment', + name="FreePayment", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "payment", + models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="payment_method", + to="cotisations.Paiement", + ), + ), ], - options={ - 'verbose_name': 'Free payment', - }, + options={"verbose_name": "Free payment"}, bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model), - ), + ) ] diff --git a/cotisations/migrations/0040_auto_20191002_2335.py b/cotisations/migrations/0040_auto_20191002_2335.py index 56c99f69..78e5ef2c 100644 --- a/cotisations/migrations/0040_auto_20191002_2335.py +++ b/cotisations/migrations/0040_auto_20191002_2335.py @@ -8,19 +8,27 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0039_freepayment'), - ] + dependencies = [("cotisations", "0039_freepayment")] operations = [ migrations.AddField( - model_name='article', - name='duration_days', - field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='duration (in days, will be added to duration in months)'), + model_name="article", + name="duration_days", + field=models.PositiveIntegerField( + blank=True, + null=True, + validators=[django.core.validators.MinValueValidator(0)], + verbose_name="duration (in days, will be added to duration in months)", + ), ), migrations.AddField( - model_name='vente', - name='duration_days', - field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='duration (in days, will be added to duration in months)'), + model_name="vente", + name="duration_days", + field=models.PositiveIntegerField( + blank=True, + null=True, + validators=[django.core.validators.MinValueValidator(0)], + verbose_name="duration (in days, will be added to duration in months)", + ), ), ] diff --git a/cotisations/migrations/0041_auto_20191103_2131.py b/cotisations/migrations/0041_auto_20191103_2131.py index 09f763ed..5ce1e767 100644 --- a/cotisations/migrations/0041_auto_20191103_2131.py +++ b/cotisations/migrations/0041_auto_20191103_2131.py @@ -8,34 +8,57 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('cotisations', '0040_auto_20191002_2335'), - ] + dependencies = [("cotisations", "0040_auto_20191002_2335")] operations = [ migrations.AlterField( - model_name='balancepayment', - name='payment', - field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_balance', to='cotisations.Paiement'), + model_name="balancepayment", + name="payment", + field=models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="payment_method_balance", + to="cotisations.Paiement", + ), ), migrations.AlterField( - model_name='chequepayment', - name='payment', - field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_cheque', to='cotisations.Paiement'), + model_name="chequepayment", + name="payment", + field=models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="payment_method_cheque", + to="cotisations.Paiement", + ), ), migrations.AlterField( - model_name='comnpaypayment', - name='payment', - field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_comnpay', to='cotisations.Paiement'), + model_name="comnpaypayment", + name="payment", + field=models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="payment_method_comnpay", + to="cotisations.Paiement", + ), ), migrations.AlterField( - model_name='freepayment', - name='payment', - field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_free', to='cotisations.Paiement'), + model_name="freepayment", + name="payment", + field=models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="payment_method_free", + to="cotisations.Paiement", + ), ), migrations.AlterField( - model_name='notepayment', - name='payment', - field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method_note', to='cotisations.Paiement'), + model_name="notepayment", + name="payment", + field=models.OneToOneField( + editable=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="payment_method_note", + to="cotisations.Paiement", + ), ), ] diff --git a/cotisations/migrations/__init__.py b/cotisations/migrations/__init__.py index b2b50566..b409e525 100644 --- a/cotisations/migrations/__init__.py +++ b/cotisations/migrations/__init__.py @@ -19,4 +19,3 @@ # 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. - diff --git a/cotisations/models.py b/cotisations/models.py index 77337a84..5cab9212 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -51,17 +51,12 @@ from machines.models import regen from re2o.field_permissions import FieldPermissionModelMixin from re2o.mixins import AclMixin, RevMixin -from cotisations.utils import ( - find_payment_method, send_mail_invoice, send_mail_voucher -) +from cotisations.utils import find_payment_method, send_mail_invoice, send_mail_voucher from cotisations.validators import check_no_balance class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): - date = models.DateTimeField( - auto_now_add=True, - verbose_name=_("Date") - ) + date = models.DateTimeField(auto_now_add=True, verbose_name=_("Date")) # TODO : change prix to price def prix(self): @@ -69,9 +64,9 @@ class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): Returns: the raw price without the quantities. Deprecated, use :total_price instead. """ - price = Vente.objects.filter( - facture=self - ).aggregate(models.Sum('prix'))['prix__sum'] + price = Vente.objects.filter(facture=self).aggregate(models.Sum("prix"))[ + "prix__sum" + ] return price # TODO : change prix to price @@ -81,23 +76,24 @@ class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): and take the quantities into account. """ # TODO : change Vente to somethingelse - return Vente.objects.filter( - facture=self - ).aggregate( - total=models.Sum( - models.F('prix')*models.F('number'), - output_field=models.DecimalField() - ) - )['total'] or 0 + return ( + Vente.objects.filter(facture=self).aggregate( + total=models.Sum( + models.F("prix") * models.F("number"), + output_field=models.DecimalField(), + ) + )["total"] + or 0 + ) def name(self): """ Returns : a string with the name of all the articles in the invoice. Used for reprensenting the invoice with a string. """ - name = ' - '.join(Vente.objects.filter( - facture=self - ).values_list('name', flat=True)) + name = " - ".join( + Vente.objects.filter(facture=self).values_list("name", flat=True) + ) return name @@ -122,43 +118,29 @@ class Facture(BaseInvoice): necessary in case of non-payment. """ - user = models.ForeignKey('users.User', on_delete=models.PROTECT) + user = models.ForeignKey("users.User", on_delete=models.PROTECT) # TODO : change paiement to payment - paiement = models.ForeignKey('Paiement', on_delete=models.PROTECT) + paiement = models.ForeignKey("Paiement", on_delete=models.PROTECT) # TODO : change banque to bank banque = models.ForeignKey( - 'Banque', - on_delete=models.PROTECT, - blank=True, - null=True + "Banque", on_delete=models.PROTECT, blank=True, null=True ) # TODO : maybe change to cheque nummber because not evident cheque = models.CharField( - max_length=255, - blank=True, - verbose_name=_("cheque number") + max_length=255, blank=True, verbose_name=_("cheque number") ) # TODO : change name to validity for clarity - valid = models.BooleanField( - default=False, - verbose_name=_("validated") - ) + valid = models.BooleanField(default=False, verbose_name=_("validated")) # TODO : changed name to controlled for clarity - control = models.BooleanField( - default=False, - verbose_name=_("controlled") - ) + control = models.BooleanField(default=False, verbose_name=_("controlled")) class Meta: abstract = False permissions = ( # TODO : change facture to invoice - ('change_facture_control', - _("Can edit the \"controlled\" state")), - ('view_facture', - _("Can view an invoice object")), - ('change_all_facture', - _("Can edit all the previous invoices")), + ("change_facture_control", _('Can edit the "controlled" state')), + ("view_facture", _("Can view an invoice object")), + ("change_all_facture", _("Can edit all the previous invoices")), ) verbose_name = _("invoice") verbose_name_plural = _("invoices") @@ -170,72 +152,84 @@ class Facture(BaseInvoice): def can_edit(self, user_request, *args, **kwargs): user_can, _message, permissions = self.user.can_edit( - user_request, *args, **kwargs) - if not user_request.has_perm('cotisations.change_facture'): + user_request, *args, **kwargs + ) + if not user_request.has_perm("cotisations.change_facture"): return ( False, _("You don't have the right to edit an invoice."), - ('cotisations.change_facture',) + ("cotisations.change_facture",), ) - elif not user_request.has_perm('cotisations.change_all_facture') and \ - not user_can: + elif ( + not user_request.has_perm("cotisations.change_all_facture") and not user_can + ): return ( False, _("You don't have the right to edit this user's invoices."), - ('cotisations.change_all_facture',) + permissions + ("cotisations.change_all_facture",) + permissions, ) - elif not user_request.has_perm('cotisations.change_all_facture') and \ - (self.control or not self.valid): + elif not user_request.has_perm("cotisations.change_all_facture") and ( + self.control or not self.valid + ): return ( False, - _("You don't have the right to edit an invoice " - "already controlled or invalidated."), - ('cotisations.change_all_facture',) + _( + "You don't have the right to edit an invoice " + "already controlled or invalidated." + ), + ("cotisations.change_all_facture",), ) else: return True, None, None def can_delete(self, user_request, *args, **kwargs): user_can, _message, permissions = self.user.can_edit( - user_request, *args, **kwargs) - if not user_request.has_perm('cotisations.delete_facture'): + user_request, *args, **kwargs + ) + if not user_request.has_perm("cotisations.delete_facture"): return ( False, _("You don't have the right to delete an invoice."), - ('cotisations.delete_facture',) + ("cotisations.delete_facture",), ) - elif not user_request.has_perm('cotisations.change_all_facture') and \ - not user_can: + elif ( + not user_request.has_perm("cotisations.change_all_facture") and not user_can + ): return ( False, _("You don't have the right to delete this user's invoices."), - ('cotisations.change_all_facture',) + permissions + ("cotisations.change_all_facture",) + permissions, ) - elif not user_request.has_perm('cotisations.change_all_facture') and \ - (self.control or not self.valid): + elif not user_request.has_perm("cotisations.change_all_facture") and ( + self.control or not self.valid + ): return ( False, - _("You don't have the right to delete an invoice " - "already controlled or invalidated."), - ('cotisations.change_all_facture',) + _( + "You don't have the right to delete an invoice " + "already controlled or invalidated." + ), + ("cotisations.change_all_facture",), ) else: return True, None, None def can_view(self, user_request, *_args, **_kwargs): - if not user_request.has_perm('cotisations.view_facture'): + if not user_request.has_perm("cotisations.view_facture"): if self.user != user_request: return ( False, - _("You don't have the right to view someone else's " - "invoices history."), - ('cotisations.view_facture',) + _( + "You don't have the right to view someone else's " + "invoices history." + ), + ("cotisations.view_facture",), ) elif not self.valid: return ( False, _("The invoice has been invalidated."), - ('cotisations.view_facture',) + ("cotisations.view_facture",), ) else: return True, None, None @@ -246,11 +240,13 @@ class Facture(BaseInvoice): def can_change_control(user_request, *_args, **_kwargs): """ Returns True if the user can change the 'controlled' status of this invoice """ - can = user_request.has_perm('cotisations.change_facture_control') + can = user_request.has_perm("cotisations.change_facture_control") return ( can, - _("You don't have the right to edit the \"controlled\" state.") if not can else None, - ('cotisations.change_facture_control',) + _('You don\'t have the right to edit the "controlled" state.') + if not can + else None, + ("cotisations.change_facture_control",), ) @staticmethod @@ -261,19 +257,25 @@ class Facture(BaseInvoice): :return: a message and a boolean which is True if the user can create an invoice or if the `options.allow_self_subscription` is set. """ - if user_request.has_perm('cotisations.add_facture'): + if user_request.has_perm("cotisations.add_facture"): return True, None, None if len(Paiement.find_allowed_payments(user_request)) <= 0: - return False, _("There are no payment method which you can use."), ('cotisations.add_facture',) + return ( + False, + _("There are no payment method which you can use."), + ("cotisations.add_facture",), + ) if len(Article.find_allowed_articles(user_request, user_request)) <= 0: - return False, _("There are no article that you can buy."), ('cotisations.add_facture',) + return ( + False, + _("There are no article that you can buy."), + ("cotisations.add_facture",), + ) return True, None, None def __init__(self, *args, **kwargs): super(Facture, self).__init__(*args, **kwargs) - self.field_permissions = { - 'control': self.can_change_control, - } + self.field_permissions = {"control": self.can_change_control} self.__original_valid = self.valid self.__original_control = self.control @@ -281,8 +283,7 @@ class Facture(BaseInvoice): """Returns every subscription associated with this invoice.""" return Cotisation.objects.filter( vente__in=self.vente_set.filter( - Q(type_cotisation='All') | - Q(type_cotisation='Adhesion') + Q(type_cotisation="All") | Q(type_cotisation="Adhesion") ) ) @@ -293,12 +294,12 @@ class Facture(BaseInvoice): def reorder_purchases(self): date = self.date for purchase in self.vente_set.all(): - if hasattr(purchase, 'cotisation'): + if hasattr(purchase, "cotisation"): cotisation = purchase.cotisation cotisation.date_start = date date += relativedelta( - months=(purchase.duration or 0)*purchase.number, - days=(purchase.duration_days or 0)*purchase.number, + months=(purchase.duration or 0) * purchase.number, + days=(purchase.duration_days or 0) * purchase.number, ) purchase.save() @@ -307,15 +308,17 @@ class Facture(BaseInvoice): if not self.__original_valid and self.valid: self.reorder_purchases() send_mail_invoice(self) - if self.is_subscription() \ - and not self.__original_control \ - and self.control \ - and CotisationsOption.get_cached_value('send_voucher_mail') \ - and self.user.is_adherent(): + if ( + self.is_subscription() + and not self.__original_control + and self.control + and CotisationsOption.get_cached_value("send_voucher_mail") + and self.user.is_adherent() + ): send_mail_voucher(self) def __str__(self): - return str(self.user) + ' ' + str(self.date) + return str(self.user) + " " + str(self.date) @receiver(post_save, sender=Facture) @@ -323,7 +326,7 @@ def facture_post_save(**kwargs): """ Synchronise the LDAP user after an invoice has been saved. """ - facture = kwargs['instance'] + facture = kwargs["instance"] if facture.valid: user = facture.user user.set_active() @@ -335,46 +338,27 @@ def facture_post_delete(**kwargs): """ Synchronise the LDAP user after an invoice has been deleted. """ - user = kwargs['instance'].user + user = kwargs["instance"].user user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) class CustomInvoice(BaseInvoice): class Meta: - permissions = ( - ('view_custominvoice', _("Can view a custom invoice object")), - ) - recipient = models.CharField( - max_length=255, - verbose_name=_("Recipient") - ) - payment = models.CharField( - max_length=255, - verbose_name=_("Payment type") - ) - address = models.CharField( - max_length=255, - verbose_name=_("Address") - ) - paid = models.BooleanField( - verbose_name=_("Paid"), - default=False - ) - remark = models.TextField( - verbose_name=_("Remark"), - blank=True, - null=True - ) + permissions = (("view_custominvoice", _("Can view a custom invoice object")),) + + recipient = models.CharField(max_length=255, verbose_name=_("Recipient")) + payment = models.CharField(max_length=255, verbose_name=_("Payment type")) + address = models.CharField(max_length=255, verbose_name=_("Address")) + paid = models.BooleanField(verbose_name=_("Paid"), default=False) + remark = models.TextField(verbose_name=_("Remark"), blank=True, null=True) class CostEstimate(CustomInvoice): class Meta: - permissions = ( - ('view_costestimate', _("Can view a cost estimate object")), - ) + permissions = (("view_costestimate", _("Can view a cost estimate object")),) + validity = models.DurationField( - verbose_name=_("Period of validity"), - help_text="DD HH:MM:SS" + verbose_name=_("Period of validity"), help_text="DD HH:MM:SS" ) final_invoice = models.ForeignKey( CustomInvoice, @@ -382,7 +366,7 @@ class CostEstimate(CustomInvoice): null=True, blank=True, related_name="origin_cost_estimate", - primary_key=False + primary_key=False, ) def create_invoice(self): @@ -401,25 +385,22 @@ class CostEstimate(CustomInvoice): self.save() for sale in self.vente_set.all(): Vente.objects.create( - facture=invoice, - name=sale.name, - prix=sale.prix, - number=sale.number, + facture=invoice, name=sale.name, prix=sale.prix, number=sale.number ) return invoice def can_delete(self, user_request, *args, **kwargs): - if not user_request.has_perm('cotisations.delete_costestimate'): + if not user_request.has_perm("cotisations.delete_costestimate"): return ( False, _("You don't have the right to delete a cost estimate."), - ('cotisations.delete_costestimate',) + ("cotisations.delete_costestimate",), ) if self.final_invoice is not None: return ( False, _("The cost estimate has an invoice and can't be deleted."), - None + None, ) return True, None, None @@ -440,44 +421,33 @@ class Vente(RevMixin, AclMixin, models.Model): # TODO : change this to English COTISATION_TYPE = ( - ('Connexion', _("Connection")), - ('Adhesion', _("Membership")), - ('All', _("Both of them")), + ("Connexion", _("Connection")), + ("Adhesion", _("Membership")), + ("All", _("Both of them")), ) # TODO : change facture to invoice facture = models.ForeignKey( - 'BaseInvoice', - on_delete=models.CASCADE, - verbose_name=_("invoice") + "BaseInvoice", on_delete=models.CASCADE, verbose_name=_("invoice") ) # TODO : change number to amount for clarity number = models.IntegerField( - validators=[MinValueValidator(1)], - verbose_name=_("amount") + validators=[MinValueValidator(1)], verbose_name=_("amount") ) # TODO : change this field for a ForeinKey to Article - name = models.CharField( - max_length=255, - verbose_name=_("article") - ) + name = models.CharField(max_length=255, verbose_name=_("article")) # TODO : change prix to price # TODO : this field is not needed if you use Article ForeignKey - prix = models.DecimalField( - max_digits=5, - decimal_places=2, - verbose_name=_("price")) + prix = models.DecimalField(max_digits=5, decimal_places=2, verbose_name=_("price")) # TODO : this field is not needed if you use Article ForeignKey duration = models.PositiveIntegerField( - blank=True, - null=True, - verbose_name=_("duration (in months)") + blank=True, null=True, verbose_name=_("duration (in months)") ) duration_days = models.PositiveIntegerField( blank=True, null=True, validators=[MinValueValidator(0)], - verbose_name=_("duration (in days, will be added to duration in months)") + verbose_name=_("duration (in days, will be added to duration in months)"), ) # TODO : this field is not needed if you use Article ForeignKey type_cotisation = models.CharField( @@ -485,13 +455,13 @@ class Vente(RevMixin, AclMixin, models.Model): blank=True, null=True, max_length=255, - verbose_name=_("subscription type") + verbose_name=_("subscription type"), ) class Meta: permissions = ( - ('view_vente', _("Can view a purchase object")), - ('change_all_vente', _("Can edit all the previous purchases")), + ("view_vente", _("Can view a purchase object")), + ("change_all_vente", _("Can edit all the previous purchases")), ) verbose_name = _("purchase") verbose_name_plural = _("purchases") @@ -501,18 +471,18 @@ class Vente(RevMixin, AclMixin, models.Model): """ Returns: the total of price for this amount of items. """ - return self.prix*self.number + return self.prix * self.number def update_cotisation(self): """ Update the related object 'cotisation' if there is one. Based on the duration of the purchase. """ - if hasattr(self, 'cotisation'): + if hasattr(self, "cotisation"): cotisation = self.cotisation cotisation.date_end = cotisation.date_start + relativedelta( - months=(self.duration or 0)*self.number, - days=(self.duration_days or 0)*self.number, + months=(self.duration or 0) * self.number, + days=(self.duration_days or 0) * self.number, ) return @@ -526,21 +496,25 @@ class Vente(RevMixin, AclMixin, models.Model): invoice = self.facture.facture except Facture.DoesNotExist: return - if not hasattr(self, 'cotisation') and self.type_cotisation: + if not hasattr(self, "cotisation") and self.type_cotisation: cotisation = Cotisation(vente=self) cotisation.type_cotisation = self.type_cotisation if date_start: - end_cotisation = Cotisation.objects.filter( - vente__in=Vente.objects.filter( - facture__in=Facture.objects.filter( - user=invoice.user - ).exclude(valid=False)) - ).filter( - Q(type_cotisation='All') | - Q(type_cotisation=self.type_cotisation) - ).filter( - date_start__lt=date_start - ).aggregate(Max('date_end'))['date_end__max'] + end_cotisation = ( + Cotisation.objects.filter( + vente__in=Vente.objects.filter( + facture__in=Facture.objects.filter( + user=invoice.user + ).exclude(valid=False) + ) + ) + .filter( + Q(type_cotisation="All") + | Q(type_cotisation=self.type_cotisation) + ) + .filter(date_start__lt=date_start) + .aggregate(Max("date_end"))["date_end__max"] + ) elif self.type_cotisation == "Adhesion": end_cotisation = invoice.user.end_adhesion() else: @@ -550,8 +524,8 @@ class Vente(RevMixin, AclMixin, models.Model): date_max = max(end_cotisation, date_start) cotisation.date_start = date_max cotisation.date_end = cotisation.date_start + relativedelta( - months=(self.duration or 0)*self.number, - days=(self.duration_days or 0)*self.number, + months=(self.duration or 0) * self.number, + days=(self.duration_days or 0) * self.number, ) def save(self, *args, **kwargs): @@ -562,9 +536,7 @@ class Vente(RevMixin, AclMixin, models.Model): """ # Checking that if a cotisation is specified, there is also a duration if self.type_cotisation and not (self.duration or self.duration_days): - raise ValidationError( - _("Duration must be specified for a subscription.") - ) + raise ValidationError(_("Duration must be specified for a subscription.")) self.update_cotisation() super(Vente, self).save(*args, **kwargs) @@ -572,66 +544,78 @@ class Vente(RevMixin, AclMixin, models.Model): user_can, _message, permissions = self.facture.user.can_edit( user_request, *args, **kwargs ) - if not user_request.has_perm('cotisations.change_vente'): + if not user_request.has_perm("cotisations.change_vente"): return ( False, _("You don't have the right to edit the purchases."), - ('cotisations.change_vente',) + ("cotisations.change_vente",), ) - elif not ( - user_request.has_perm('cotisations.change_all_facture') or - user_can): + elif not (user_request.has_perm("cotisations.change_all_facture") or user_can): return ( False, _("You don't have the right to edit this user's purchases."), - ('cotisations.change_all_facture',) + permissions + ("cotisations.change_all_facture",) + permissions, ) - elif (not user_request.has_perm('cotisations.change_all_vente') and - (self.facture.control or not self.facture.valid)): + elif not user_request.has_perm("cotisations.change_all_vente") and ( + self.facture.control or not self.facture.valid + ): return ( False, - _("You don't have the right to edit a purchase " - "already controlled or invalidated."), - ('cotisations.change_all_vente',) + _( + "You don't have the right to edit a purchase " + "already controlled or invalidated." + ), + ("cotisations.change_all_vente",), ) else: return True, None, None def can_delete(self, user_request, *args, **kwargs): user_can, _message, permissions = self.facture.user.can_edit( - user_request, *args, **kwargs) - if not user_request.has_perm('cotisations.delete_vente'): + user_request, *args, **kwargs + ) + if not user_request.has_perm("cotisations.delete_vente"): return ( False, _("You don't have the right to delete a purchase."), - ('cotisations.delete_vente',) + ("cotisations.delete_vente",), ) if not user_can: return ( False, _("You don't have the right to delete this user's purchases."), - permissions + permissions, ) if self.facture.control or not self.facture.valid: - return False, _("You don't have the right to delete a purchase " - "already controlled or invalidated."), None + return ( + False, + _( + "You don't have the right to delete a purchase " + "already controlled or invalidated." + ), + None, + ) else: return True, None, None def can_view(self, user_request, *_args, **_kwargs): - if (not user_request.has_perm('cotisations.view_vente') and - self.facture.user != user_request): + if ( + not user_request.has_perm("cotisations.view_vente") + and self.facture.user != user_request + ): return ( False, - _("You don't have the right to view someone " - "else's purchase history."), - ('cotisations.view_vente',) + _( + "You don't have the right to view someone " + "else's purchase history." + ), + ("cotisations.view_vente",), ) else: return True, None, None def __str__(self): - return str(self.name) + ' ' + str(self.facture) + return str(self.name) + " " + str(self.facture) # TODO : change vente to purchase @@ -641,12 +625,12 @@ def vente_post_save(**kwargs): Creates a 'cotisation' related object if needed and synchronise the LDAP user when a purchase has been saved. """ - purchase = kwargs['instance'] + purchase = kwargs["instance"] try: purchase.facture.facture except Facture.DoesNotExist: return - if hasattr(purchase, 'cotisation'): + if hasattr(purchase, "cotisation"): purchase.cotisation.vente = purchase purchase.cotisation.save() if purchase.type_cotisation: @@ -663,7 +647,7 @@ def vente_post_delete(**kwargs): """ Synchronise the LDAP user after a purchase has been deleted. """ - purchase = kwargs['instance'] + purchase = kwargs["instance"] try: invoice = purchase.facture.facture except Facture.DoesNotExist: @@ -689,44 +673,39 @@ class Article(RevMixin, AclMixin, models.Model): # TODO : Either use TYPE or TYPES in both choices but not both USER_TYPES = ( - ('Adherent', _("Member")), - ('Club', _("Club")), - ('All', _("Both of them")), + ("Adherent", _("Member")), + ("Club", _("Club")), + ("All", _("Both of them")), ) COTISATION_TYPE = ( - ('Connexion', _("Connection")), - ('Adhesion', _("Membership")), - ('All', _("Both of them")), + ("Connexion", _("Connection")), + ("Adhesion", _("Membership")), + ("All", _("Both of them")), ) - name = models.CharField( - max_length=255, - verbose_name=_("designation") - ) + name = models.CharField(max_length=255, verbose_name=_("designation")) # TODO : change prix to price prix = models.DecimalField( - max_digits=5, - decimal_places=2, - verbose_name=_("unit price") + max_digits=5, decimal_places=2, verbose_name=_("unit price") ) duration = models.PositiveIntegerField( blank=True, null=True, validators=[MinValueValidator(0)], - verbose_name=_("duration (in months)") + verbose_name=_("duration (in months)"), ) duration_days = models.PositiveIntegerField( blank=True, null=True, validators=[MinValueValidator(0)], - verbose_name=_("duration (in days, will be added to duration in months)") + verbose_name=_("duration (in days, will be added to duration in months)"), ) type_user = models.CharField( choices=USER_TYPES, - default='All', + default="All", max_length=255, - verbose_name=_("type of users concerned") + verbose_name=_("type of users concerned"), ) type_cotisation = models.CharField( choices=COTISATION_TYPE, @@ -734,32 +713,27 @@ class Article(RevMixin, AclMixin, models.Model): blank=True, null=True, max_length=255, - verbose_name=_("subscription type") + verbose_name=_("subscription type"), ) available_for_everyone = models.BooleanField( - default=False, - verbose_name=_("is available for every user") + default=False, verbose_name=_("is available for every user") ) - unique_together = ('name', 'type_user') + unique_together = ("name", "type_user") class Meta: permissions = ( - ('view_article', _("Can view an article object")), - ('buy_every_article', _("Can buy every article")) + ("view_article", _("Can view an article object")), + ("buy_every_article", _("Can buy every article")), ) verbose_name = "article" verbose_name_plural = "articles" def clean(self): - if self.name.lower() == 'solde': - raise ValidationError( - _("Balance is a reserved article name.") - ) + if self.name.lower() == "solde": + raise ValidationError(_("Balance is a reserved article name.")) if self.type_cotisation and not (self.duration or self.duration_days): - raise ValidationError( - _("Duration must be specified for a subscription.") - ) + raise ValidationError(_("Duration must be specified for a subscription.")) def __str__(self): return self.name @@ -775,13 +749,15 @@ class Article(RevMixin, AclMixin, models.Model): A boolean stating if usage is granted and an explanation message if the boolean is `False`. """ - can = self.available_for_everyone \ - or user.has_perm('cotisations.buy_every_article') \ - or user.has_perm('cotisations.add_facture') + can = ( + self.available_for_everyone + or user.has_perm("cotisations.buy_every_article") + or user.has_perm("cotisations.add_facture") + ) return ( can, _("You can't buy this article.") if not can else None, - ('cotisations.buy_every_article', 'cotisations.add_facture') + ("cotisations.buy_every_article", "cotisations.add_facture"), ) @classmethod @@ -793,20 +769,18 @@ class Article(RevMixin, AclMixin, models.Model): target_user: The user to sell articles """ if target_user is None: - objects_pool = cls.objects.filter(Q(type_user='All')) + objects_pool = cls.objects.filter(Q(type_user="All")) elif target_user.is_class_club: - objects_pool = cls.objects.filter( - Q(type_user='All') | Q(type_user='Club') - ) + objects_pool = cls.objects.filter(Q(type_user="All") | Q(type_user="Club")) else: objects_pool = cls.objects.filter( - Q(type_user='All') | Q(type_user='Adherent') + Q(type_user="All") | Q(type_user="Adherent") ) if target_user is not None and not target_user.is_adherent(): objects_pool = objects_pool.filter( - Q(type_cotisation='All') | Q(type_cotisation='Adhesion') + Q(type_cotisation="All") | Q(type_cotisation="Adhesion") ) - if user.has_perm('cotisations.buy_every_article'): + if user.has_perm("cotisations.buy_every_article"): return objects_pool return objects_pool.filter(available_for_everyone=True) @@ -820,14 +794,10 @@ class Banque(RevMixin, AclMixin, models.Model): it's easier to use simple object for the banks. """ - name = models.CharField( - max_length=255, - ) + name = models.CharField(max_length=255) class Meta: - permissions = ( - ('view_banque', _("Can view a bank object")), - ) + permissions = (("view_banque", _("Can view a bank object")),) verbose_name = _("bank") verbose_name_plural = _("banks") @@ -845,26 +815,22 @@ class Paiement(RevMixin, AclMixin, models.Model): """ # TODO : change moyen to method - moyen = models.CharField( - max_length=255, - verbose_name=_("method") - ) + moyen = models.CharField(max_length=255, verbose_name=_("method")) available_for_everyone = models.BooleanField( - default=False, - verbose_name=_("is available for every user") + default=False, verbose_name=_("is available for every user") ) is_balance = models.BooleanField( default=False, editable=False, verbose_name=_("is user balance"), help_text=_("There should be only one balance payment method."), - validators=[check_no_balance] + validators=[check_no_balance], ) class Meta: permissions = ( - ('view_paiement', _("Can view a payment method object")), - ('use_every_payment', _("Can use every payment method")), + ("view_paiement", _("Can view a payment method object")), + ("use_every_payment", _("Can use every payment method")), ) verbose_name = _("payment method") verbose_name_plural = _("payment methods") @@ -905,22 +871,19 @@ class Paiement(RevMixin, AclMixin, models.Model): if any(sell.type_cotisation for sell in invoice.vente_set.all()): messages.success( request, - _("The subscription of %(member_name)s was extended to" - " %(end_date)s.") % { - 'member_name': invoice.user.pseudo, - 'end_date': invoice.user.end_adhesion() - } + _( + "The subscription of %(member_name)s was extended to" + " %(end_date)s." + ) + % { + "member_name": invoice.user.pseudo, + "end_date": invoice.user.end_adhesion(), + }, ) # Else, only tell the invoice was created else: - messages.success( - request, - _("The invoice was created.") - ) - return redirect(reverse( - 'users:profil', - kwargs={'userid': invoice.user.pk} - )) + messages.success(request, _("The invoice was created.")) + return redirect(reverse("users:profil", kwargs={"userid": invoice.user.pk})) def can_use_payment(self, user, *_args, **_kwargs): """Check if a user can use this payment. @@ -932,13 +895,15 @@ class Paiement(RevMixin, AclMixin, models.Model): A boolean stating if usage is granted and an explanation message if the boolean is `False`. """ - can = self.available_for_everyone \ - or user.has_perm('cotisations.use_every_payment') \ - or user.has_perm('cotisations.add_facture') + can = ( + self.available_for_everyone + or user.has_perm("cotisations.use_every_payment") + or user.has_perm("cotisations.add_facture") + ) return ( can, _("You can't use this payment method.") if not can else None, - ('cotisations.use_every_payment', 'cotisations.add_facture') + ("cotisations.use_every_payment", "cotisations.add_facture"), ) @classmethod @@ -948,7 +913,7 @@ class Paiement(RevMixin, AclMixin, models.Model): Args: user: The user requesting payment methods. """ - if user.has_perm('cotisations.use_every_payment'): + if user.has_perm("cotisations.use_every_payment"): return cls.objects.all() return cls.objects.filter(available_for_everyone=True) @@ -972,89 +937,96 @@ class Cotisation(RevMixin, AclMixin, models.Model): """ COTISATION_TYPE = ( - ('Connexion', _("Connection")), - ('Adhesion', _("Membership")), - ('All', _("Both of them")), + ("Connexion", _("Connection")), + ("Adhesion", _("Membership")), + ("All", _("Both of them")), ) # TODO : change vente to purchase vente = models.OneToOneField( - 'Vente', - on_delete=models.CASCADE, - null=True, - verbose_name=_("purchase") + "Vente", on_delete=models.CASCADE, null=True, verbose_name=_("purchase") ) type_cotisation = models.CharField( choices=COTISATION_TYPE, max_length=255, - default='All', - verbose_name=_("subscription type") - ) - date_start = models.DateTimeField( - verbose_name=_("start date") - ) - date_end = models.DateTimeField( - verbose_name=_("end date") + default="All", + verbose_name=_("subscription type"), ) + date_start = models.DateTimeField(verbose_name=_("start date")) + date_end = models.DateTimeField(verbose_name=_("end date")) class Meta: permissions = ( - ('view_cotisation', _("Can view a subscription object")), - ('change_all_cotisation', _("Can edit the previous subscriptions")), + ("view_cotisation", _("Can view a subscription object")), + ("change_all_cotisation", _("Can edit the previous subscriptions")), ) verbose_name = _("subscription") verbose_name_plural = _("subscriptions") def can_edit(self, user_request, *_args, **_kwargs): - if not user_request.has_perm('cotisations.change_cotisation'): + if not user_request.has_perm("cotisations.change_cotisation"): return ( False, _("You don't have the right to edit a subscription."), - ('cotisations.change_cotisation',) + ("cotisations.change_cotisation",), ) - elif not user_request.has_perm('cotisations.change_all_cotisation') \ - and (self.vente.facture.control or - not self.vente.facture.valid): + elif not user_request.has_perm("cotisations.change_all_cotisation") and ( + self.vente.facture.control or not self.vente.facture.valid + ): return ( False, - _("You don't have the right to edit a subscription " - "already controlled or invalidated."), - ('cotisations.change_all_cotisation',) + _( + "You don't have the right to edit a subscription " + "already controlled or invalidated." + ), + ("cotisations.change_all_cotisation",), ) else: return True, None, None def can_delete(self, user_request, *_args, **_kwargs): - if not user_request.has_perm('cotisations.delete_cotisation'): + if not user_request.has_perm("cotisations.delete_cotisation"): return ( False, _("You don't have the right to delete a subscription."), - ('cotisations.delete_cotisation',) + ("cotisations.delete_cotisation",), ) if self.vente.facture.control or not self.vente.facture.valid: return ( False, - _("You don't have the right to delete a subscription " - "already controlled or invalidated."), - None + _( + "You don't have the right to delete a subscription " + "already controlled or invalidated." + ), + None, ) else: return True, None, None def can_view(self, user_request, *_args, **_kwargs): - if not user_request.has_perm('cotisations.view_cotisation') and\ - self.vente.facture.user != user_request: + if ( + not user_request.has_perm("cotisations.view_cotisation") + and self.vente.facture.user != user_request + ): return ( False, - _("You don't have the right to view someone else's " - "subscription history."), - ('cotisations.view_cotisation',) + _( + "You don't have the right to view someone else's " + "subscription history." + ), + ("cotisations.view_cotisation",), ) else: return True, None, None def __str__(self): - return str(self.vente) + "from " + str(self.date_start) + " to " + str(self.date_end) + return ( + str(self.vente) + + "from " + + str(self.date_start) + + " to " + + str(self.date_end) + ) @receiver(post_save, sender=Cotisation) @@ -1063,10 +1035,10 @@ def cotisation_post_save(**_kwargs): Mark some services as needing a regeneration after the edition of a cotisation. Indeed the membership status may have changed. """ - regen('dns') - regen('dhcp') - regen('mac_ip_list') - regen('mailing') + regen("dns") + regen("dhcp") + regen("mac_ip_list") + regen("mailing") @receiver(post_delete, sender=Cotisation) @@ -1075,5 +1047,5 @@ def cotisation_post_delete(**_kwargs): Mark some services as needing a regeneration after the deletion of a cotisation. Indeed the membership status may have changed. """ - regen('mac_ip_list') - regen('mailing') + regen("mac_ip_list") + regen("mailing") diff --git a/cotisations/payment_methods/__init__.py b/cotisations/payment_methods/__init__.py index 3071b9c0..cbb9c4a6 100644 --- a/cotisations/payment_methods/__init__.py +++ b/cotisations/payment_methods/__init__.py @@ -129,10 +129,4 @@ method to your model, where `form` is an instance of from . import comnpay, cheque, balance, note_kfet, free, urls -PAYMENT_METHODS = [ - comnpay, - cheque, - balance, - note_kfet, - free -] +PAYMENT_METHODS = [comnpay, cheque, balance, note_kfet, free] diff --git a/cotisations/payment_methods/balance/__init__.py b/cotisations/payment_methods/balance/__init__.py index cacd73f7..ebfaaddd 100644 --- a/cotisations/payment_methods/balance/__init__.py +++ b/cotisations/payment_methods/balance/__init__.py @@ -22,6 +22,7 @@ This module contains a method to pay online using user balance. """ from . import models + NAME = "BALANCE" PaymentMethod = models.BalancePayment diff --git a/cotisations/payment_methods/balance/models.py b/cotisations/payment_methods/balance/models.py index e3e05ea4..a252affb 100644 --- a/cotisations/payment_methods/balance/models.py +++ b/cotisations/payment_methods/balance/models.py @@ -40,15 +40,16 @@ class BalancePayment(PaymentMethodMixin, models.Model): payment = models.OneToOneField( Paiement, on_delete=models.CASCADE, - related_name='payment_method_balance', - editable=False + related_name="payment_method_balance", + editable=False, ) minimum_balance = models.DecimalField( verbose_name=_("Minimum balance"), - help_text=_("The minimal amount of money allowed for the balance" - " at the end of a payment. You can specify negative " - "amount." - ), + help_text=_( + "The minimal amount of money allowed for the balance" + " at the end of a payment. You can specify negative " + "amount." + ), max_digits=5, decimal_places=2, default=0, @@ -63,8 +64,7 @@ class BalancePayment(PaymentMethodMixin, models.Model): null=True, ) credit_balance_allowed = models.BooleanField( - verbose_name=_("Allow user to credit their balance"), - default=False, + verbose_name=_("Allow user to credit their balance"), default=False ) def end_payment(self, invoice, request): @@ -74,27 +74,17 @@ class BalancePayment(PaymentMethodMixin, models.Model): user = invoice.user total_price = invoice.prix_total() if user.solde - total_price < self.minimum_balance: - messages.error( - request, - _("Your balance is too low for this operation.") - ) - return redirect(reverse( - 'users:profil', - kwargs={'userid': user.id} - )) - return invoice.paiement.end_payment( - invoice, - request, - use_payment_method=False - ) + messages.error(request, _("Your balance is too low for this operation.")) + return redirect(reverse("users:profil", kwargs={"userid": user.id})) + return invoice.paiement.end_payment(invoice, request, use_payment_method=False) def valid_form(self, form): """Checks that there is not already a balance payment method.""" p = Paiement.objects.filter(is_balance=True) if len(p) > 0: form.add_error( - 'payment_method', - _("There is already a payment method for user balance.") + "payment_method", + _("There is already a payment method for user balance."), ) def alter_payment(self, payment): @@ -107,12 +97,11 @@ class BalancePayment(PaymentMethodMixin, models.Model): """ return ( user.solde - price >= self.minimum_balance, - _("Your balance is too low for this operation.") + _("Your balance is too low for this operation."), ) def can_credit_balance(self, user_request): return ( - len(Paiement.find_allowed_payments(user_request) - .exclude(is_balance=True)) > 0 + len(Paiement.find_allowed_payments(user_request).exclude(is_balance=True)) + > 0 ) and self.credit_balance_allowed - diff --git a/cotisations/payment_methods/cheque/__init__.py b/cotisations/payment_methods/cheque/__init__.py index 9eb17b09..27e985e5 100644 --- a/cotisations/payment_methods/cheque/__init__.py +++ b/cotisations/payment_methods/cheque/__init__.py @@ -22,6 +22,7 @@ This module contains a method to pay online using cheque. """ from . import models, urls, views + NAME = "CHEQUE" PaymentMethod = models.ChequePayment diff --git a/cotisations/payment_methods/cheque/forms.py b/cotisations/payment_methods/cheque/forms.py index 37942687..370a701d 100644 --- a/cotisations/payment_methods/cheque/forms.py +++ b/cotisations/payment_methods/cheque/forms.py @@ -26,6 +26,7 @@ from cotisations.models import Facture as Invoice class InvoiceForm(FormRevMixin, forms.ModelForm): """A simple form to get the bank a the cheque number.""" + class Meta: model = Invoice - fields = ['banque', 'cheque'] + fields = ["banque", "cheque"] diff --git a/cotisations/payment_methods/cheque/models.py b/cotisations/payment_methods/cheque/models.py index a834bb93..53acef6a 100644 --- a/cotisations/payment_methods/cheque/models.py +++ b/cotisations/payment_methods/cheque/models.py @@ -38,16 +38,14 @@ class ChequePayment(PaymentMethodMixin, models.Model): payment = models.OneToOneField( Paiement, on_delete=models.CASCADE, - related_name='payment_method_cheque', - editable=False + related_name="payment_method_cheque", + editable=False, ) def end_payment(self, invoice, request): """Invalidates the invoice then redirect the user towards a view asking for informations to add to the invoice before validating it. """ - return redirect(reverse( - 'cotisations:cheque:validate', - kwargs={'invoice_pk': invoice.pk} - )) - + return redirect( + reverse("cotisations:cheque:validate", kwargs={"invoice_pk": invoice.pk}) + ) diff --git a/cotisations/payment_methods/cheque/urls.py b/cotisations/payment_methods/cheque/urls.py index 54fe6a50..a29e1b8c 100644 --- a/cotisations/payment_methods/cheque/urls.py +++ b/cotisations/payment_methods/cheque/urls.py @@ -21,10 +21,4 @@ from django.conf.urls import url from . import views -urlpatterns = [ - url( - r'^validate/(?P[0-9]+)$', - views.cheque, - name='validate' - ) -] +urlpatterns = [url(r"^validate/(?P[0-9]+)$", views.cheque, name="validate")] diff --git a/cotisations/payment_methods/cheque/views.py b/cotisations/payment_methods/cheque/views.py index 3cce3e5c..a22e9c09 100644 --- a/cotisations/payment_methods/cheque/views.py +++ b/cotisations/payment_methods/cheque/views.py @@ -42,29 +42,17 @@ def cheque(request, invoice_pk): invoice = get_object_or_404(Invoice, pk=invoice_pk) payment_method = find_payment_method(invoice.paiement) if invoice.valid or not isinstance(payment_method, ChequePayment): - messages.error( - request, - _("You can't pay this invoice with a cheque.") - ) - return redirect(reverse( - 'users:profil', - kwargs={'userid': request.user.pk} - )) + messages.error(request, _("You can't pay this invoice with a cheque.")) + return redirect(reverse("users:profil", kwargs={"userid": request.user.pk})) form = InvoiceForm(request.POST or None, instance=invoice) if form.is_valid(): form.instance.valid = True form.save() return form.instance.paiement.end_payment( - form.instance, - request, - use_payment_method=False + form.instance, request, use_payment_method=False ) return render( request, - 'cotisations/payment.html', - { - 'form': form, - 'amount': invoice.prix_total() - } + "cotisations/payment.html", + {"form": form, "amount": invoice.prix_total()}, ) - diff --git a/cotisations/payment_methods/comnpay/__init__.py b/cotisations/payment_methods/comnpay/__init__.py index 7c80311d..0cfcfab5 100644 --- a/cotisations/payment_methods/comnpay/__init__.py +++ b/cotisations/payment_methods/comnpay/__init__.py @@ -22,5 +22,6 @@ This module contains a method to pay online using comnpay. """ from . import models, urls, views + NAME = "COMNPAY" PaymentMethod = models.ComnpayPayment diff --git a/cotisations/payment_methods/comnpay/comnpay.py b/cotisations/payment_methods/comnpay/comnpay.py index 272ab928..b03239a4 100644 --- a/cotisations/payment_methods/comnpay/comnpay.py +++ b/cotisations/payment_methods/comnpay/comnpay.py @@ -10,13 +10,21 @@ import hashlib from collections import OrderedDict -class Transaction(): +class Transaction: """ The class representing a transaction with all the functions used during the negociation """ - def __init__(self, vad_number="", secret_key="", urlRetourOK="", - urlRetourNOK="", urlIPN="", source="", typeTr="D"): + def __init__( + self, + vad_number="", + secret_key="", + urlRetourOK="", + urlRetourNOK="", + urlIPN="", + source="", + typeTr="D", + ): self.vad_number = vad_number self.secret_key = secret_key self.urlRetourOK = urlRetourOK @@ -26,8 +34,7 @@ class Transaction(): self.typeTr = typeTr self.idTransaction = "" - def buildSecretHTML(self, produit="Produit", montant="0.00", - idTransaction=""): + def buildSecretHTML(self, produit="Produit", montant="0.00", idTransaction=""): """ Build an HTML hidden form with the different parameters for the transaction """ @@ -43,30 +50,26 @@ class Transaction(): idTPE=self.vad_number, idTransaction=self.idTransaction, devise="EUR", - lang='fr', + lang="fr", nom_produit=produit, source=self.source, urlRetourOK=self.urlRetourOK, urlRetourNOK=self.urlRetourNOK, - typeTr=str(self.typeTr) + typeTr=str(self.typeTr), ) if self.urlIPN != "": - array_tpe['urlIPN'] = self.urlIPN + array_tpe["urlIPN"] = self.urlIPN - array_tpe['key'] = self.secret_key - strWithKey = base64.b64encode(bytes( - '|'.join(array_tpe.values()), - 'utf-8' - )) + array_tpe["key"] = self.secret_key + strWithKey = base64.b64encode(bytes("|".join(array_tpe.values()), "utf-8")) del array_tpe["key"] - array_tpe['sec'] = hashlib.sha512(strWithKey).hexdigest() + array_tpe["sec"] = hashlib.sha512(strWithKey).hexdigest() ret = "" for key in array_tpe: ret += ''.format( - k=key, - v=array_tpe[key] + k=key, v=array_tpe[key] ) return ret @@ -75,12 +78,13 @@ class Transaction(): def validSec(values, secret_key): """ Check if the secret value is correct """ if "sec" in values: - sec = values['sec'] + sec = values["sec"] del values["sec"] - strWithKey = hashlib.sha512(base64.b64encode(bytes( - '|'.join(values.values()) + "|" + secret_key, - 'utf-8' - ))).hexdigest() + strWithKey = hashlib.sha512( + base64.b64encode( + bytes("|".join(values.values()) + "|" + secret_key, "utf-8") + ) + ).hexdigest() return strWithKey.upper() == sec.upper() else: return False diff --git a/cotisations/payment_methods/comnpay/models.py b/cotisations/payment_methods/comnpay/models.py index a5568f22..ff35650c 100644 --- a/cotisations/payment_methods/comnpay/models.py +++ b/cotisations/payment_methods/comnpay/models.py @@ -41,39 +41,36 @@ class ComnpayPayment(PaymentMethodMixin, models.Model): payment = models.OneToOneField( Paiement, on_delete=models.CASCADE, - related_name='payment_method_comnpay', - editable=False + related_name="payment_method_comnpay", + editable=False, ) payment_credential = models.CharField( - max_length=255, - default='', - blank=True, - verbose_name=_("ComNpay VAT Number"), + max_length=255, default="", blank=True, verbose_name=_("ComNpay VAT Number") ) payment_pass = AESEncryptedField( - max_length=255, - null=True, - blank=True, - verbose_name=_("ComNpay secret key"), + max_length=255, null=True, blank=True, verbose_name=_("ComNpay secret key") ) minimum_payment = models.DecimalField( verbose_name=_("Minimum payment"), - help_text=_("The minimal amount of money you have to use when paying" - " with ComNpay"), + help_text=_( + "The minimal amount of money you have to use when paying" " with ComNpay" + ), max_digits=5, decimal_places=2, default=1, ) production = models.BooleanField( default=True, - verbose_name=_("Production mode enabled (production URL, instead of homologation)"), + verbose_name=_( + "Production mode enabled (production URL, instead of homologation)" + ), ) def return_url_comnpay(self): if self.production: - return 'https://secure.comnpay.com' + return "https://secure.comnpay.com" else: - return 'https://secure.homologation.comnpay.com' + return "https://secure.homologation.comnpay.com" def end_payment(self, invoice, request): """ @@ -85,32 +82,36 @@ class ComnpayPayment(PaymentMethodMixin, models.Model): p = Transaction( str(self.payment_credential), str(self.payment_pass), - 'https://' + host + reverse( - 'cotisations:comnpay:accept_payment', - kwargs={'factureid': invoice.id} + "https://" + + host + + reverse( + "cotisations:comnpay:accept_payment", kwargs={"factureid": invoice.id} ), - 'https://' + host + reverse('cotisations:comnpay:refuse_payment'), - 'https://' + host + reverse('cotisations:comnpay:ipn'), + "https://" + host + reverse("cotisations:comnpay:refuse_payment"), + "https://" + host + reverse("cotisations:comnpay:ipn"), "", - "D" + "D", ) r = { - 'action': self.return_url_comnpay(), - 'method': 'POST', - 'content': p.buildSecretHTML( - _("Pay invoice number ")+str(invoice.id), + "action": self.return_url_comnpay(), + "method": "POST", + "content": p.buildSecretHTML( + _("Pay invoice number ") + str(invoice.id), invoice.prix_total(), - idTransaction=str(invoice.id) + idTransaction=str(invoice.id), ), - 'amount': invoice.prix_total(), + "amount": invoice.prix_total(), } - return render(request, 'cotisations/payment.html', r) + return render(request, "cotisations/payment.html", r) def check_price(self, price, *args, **kwargs): """Checks that the price meets the requirement to be paid with ComNpay. """ - return ((price >= self.minimum_payment), - _("In order to pay your invoice with ComNpay, the price must" - " be greater than {} €.").format(self.minimum_payment)) - + return ( + (price >= self.minimum_payment), + _( + "In order to pay your invoice with ComNpay, the price must" + " be greater than {} €." + ).format(self.minimum_payment), + ) diff --git a/cotisations/payment_methods/comnpay/urls.py b/cotisations/payment_methods/comnpay/urls.py index 241d53dd..69bb3b38 100644 --- a/cotisations/payment_methods/comnpay/urls.py +++ b/cotisations/payment_methods/comnpay/urls.py @@ -22,19 +22,7 @@ from django.conf.urls import url from . import views urlpatterns = [ - url( - r'^accept/(?P[0-9]+)$', - views.accept_payment, - name='accept_payment' - ), - url( - r'^refuse/$', - views.refuse_payment, - name='refuse_payment' - ), - url( - r'^ipn/$', - views.ipn, - name='ipn' - ), + url(r"^accept/(?P[0-9]+)$", views.accept_payment, name="accept_payment"), + url(r"^refuse/$", views.refuse_payment, name="refuse_payment"), + url(r"^ipn/$", views.ipn, name="ipn"), ] diff --git a/cotisations/payment_methods/comnpay/views.py b/cotisations/payment_methods/comnpay/views.py index 12a5747b..5bfa2a82 100644 --- a/cotisations/payment_methods/comnpay/views.py +++ b/cotisations/payment_methods/comnpay/views.py @@ -50,26 +50,24 @@ def accept_payment(request, factureid): if invoice.valid: messages.success( request, - _("The payment of %(amount)s € was accepted.") % { - 'amount': invoice.prix_total() - } + _("The payment of %(amount)s € was accepted.") + % {"amount": invoice.prix_total()}, ) # In case a cotisation was bought, inform the user, the # cotisation time has been extended too - if any(purchase.type_cotisation - for purchase in invoice.vente_set.all()): + if any(purchase.type_cotisation for purchase in invoice.vente_set.all()): messages.success( request, - _("The subscription of %(member_name)s was extended to" - " %(end_date)s.") % { - 'member_name': invoice.user.pseudo, - 'end_date': invoice.user.end_adhesion() - } + _( + "The subscription of %(member_name)s was extended to" + " %(end_date)s." + ) + % { + "member_name": invoice.user.pseudo, + "end_date": invoice.user.end_adhesion(), + }, ) - return redirect(reverse( - 'users:profil', - kwargs={'userid': invoice.user.id} - )) + return redirect(reverse("users:profil", kwargs={"userid": invoice.user.id})) @csrf_exempt @@ -79,14 +77,8 @@ def refuse_payment(request): The view where the user is redirected when a comnpay payment has been refused. """ - messages.error( - request, - _("The payment was refused.") - ) - return redirect(reverse( - 'users:profil', - kwargs={'userid': request.user.id} - )) + messages.error(request, _("The payment was refused.")) + return redirect(reverse("users:profil", kwargs={"userid": request.user.id})) @csrf_exempt @@ -97,27 +89,26 @@ def ipn(request): Comnpay with 400 response if not or with a 200 response if yes. """ p = Transaction() - order = ('idTpe', 'idTransaction', 'montant', 'result', 'sec', ) + order = ("idTpe", "idTransaction", "montant", "result", "sec") try: data = OrderedDict([(f, request.POST[f]) for f in order]) except MultiValueDictKeyError: return HttpResponseBadRequest("HTTP/1.1 400 Bad Request") - idTransaction = request.POST['idTransaction'] + idTransaction = request.POST["idTransaction"] try: factureid = int(idTransaction) except ValueError: return HttpResponseBadRequest("HTTP/1.1 400 Bad Request") facture = get_object_or_404(Facture, id=factureid) - payment_method = get_object_or_404( - ComnpayPayment, payment=facture.paiement) + payment_method = get_object_or_404(ComnpayPayment, payment=facture.paiement) if not p.validSec(data, payment_method.payment_pass): return HttpResponseBadRequest("HTTP/1.1 400 Bad Request") - result = True if (request.POST['result'] == 'OK') else False - idTpe = request.POST['idTpe'] + result = True if (request.POST["result"] == "OK") else False + idTpe = request.POST["idTpe"] # Checking that the payment is actually for us. if not idTpe == payment_method.payment_credential: @@ -136,4 +127,3 @@ def ipn(request): # Everything worked we send a reponse to Comnpay indicating that # it's ok for them to proceed return HttpResponse("HTTP/1.0 200 OK") - diff --git a/cotisations/payment_methods/forms.py b/cotisations/payment_methods/forms.py index daa65118..fdcd50b8 100644 --- a/cotisations/payment_methods/forms.py +++ b/cotisations/payment_methods/forms.py @@ -24,6 +24,7 @@ from django.utils.translation import ugettext_lazy as _ from . import PAYMENT_METHODS from cotisations.utils import find_payment_method + def payment_method_factory(payment, *args, creation=True, **kwargs): """This function finds the right payment method form for a given payment. @@ -40,12 +41,10 @@ def payment_method_factory(payment, *args, creation=True, **kwargs): Returns: A form or None """ - payment_method = kwargs.pop('instance', find_payment_method(payment)) + payment_method = kwargs.pop("instance", find_payment_method(payment)) if payment_method is not None: - return forms.modelform_factory(type(payment_method), fields='__all__')( - *args, - instance=payment_method, - **kwargs + return forms.modelform_factory(type(payment_method), fields="__all__")( + *args, instance=payment_method, **kwargs ) elif creation: return PaymentMethodForm(*args, **kwargs) @@ -58,23 +57,24 @@ class PaymentMethodForm(forms.Form): payment_method = forms.ChoiceField( label=_("Special payment method"), - help_text=_("Warning: you will not be able to change the payment " - "method later. But you will be allowed to edit the other " - "options." + help_text=_( + "Warning: you will not be able to change the payment " + "method later. But you will be allowed to edit the other " + "options." ), - required=False + required=False, ) def __init__(self, *args, **kwargs): super(PaymentMethodForm, self).__init__(*args, **kwargs) - prefix = kwargs.get('prefix', None) - self.fields['payment_method'].choices = [(i,p.NAME) for (i,p) in enumerate(PAYMENT_METHODS)] - self.fields['payment_method'].choices.insert(0, ('', _('no'))) - self.fields['payment_method'].widget.attrs = { - 'id': 'paymentMethodSelect' - } + prefix = kwargs.get("prefix", None) + self.fields["payment_method"].choices = [ + (i, p.NAME) for (i, p) in enumerate(PAYMENT_METHODS) + ] + self.fields["payment_method"].choices.insert(0, ("", _("no"))) + self.fields["payment_method"].widget.attrs = {"id": "paymentMethodSelect"} self.templates = [ - forms.modelform_factory(p.PaymentMethod, fields='__all__')(prefix=prefix) + forms.modelform_factory(p.PaymentMethod, fields="__all__")(prefix=prefix) for p in PAYMENT_METHODS ] @@ -84,29 +84,29 @@ class PaymentMethodForm(forms.Form): found. Tries to call `payment_method.valid_form` if it exists. """ super(PaymentMethodForm, self).clean() - choice = self.cleaned_data['payment_method'] - if choice=='': + choice = self.cleaned_data["payment_method"] + if choice == "": return choice = int(choice) model = PAYMENT_METHODS[choice].PaymentMethod - form = forms.modelform_factory(model, fields='__all__')(self.data, prefix=self.prefix) + form = forms.modelform_factory(model, fields="__all__")( + self.data, prefix=self.prefix + ) self.payment_method = form.save(commit=False) - if hasattr(self.payment_method, 'valid_form'): + if hasattr(self.payment_method, "valid_form"): self.payment_method.valid_form(self) return self.cleaned_data - - def save(self, payment, *args, **kwargs): """Saves the payment method. Tries to call `payment_method.alter_payment` if it exists. """ - commit = kwargs.pop('commit', True) - if not hasattr(self, 'payment_method'): + commit = kwargs.pop("commit", True) + if not hasattr(self, "payment_method"): return None self.payment_method.payment = payment - if hasattr(self.payment_method, 'alter_payment'): + if hasattr(self.payment_method, "alter_payment"): self.payment_method.alter_payment(payment) if commit: payment.save() diff --git a/cotisations/payment_methods/free/__init__.py b/cotisations/payment_methods/free/__init__.py index 1a7168a9..27041f2e 100644 --- a/cotisations/payment_methods/free/__init__.py +++ b/cotisations/payment_methods/free/__init__.py @@ -22,6 +22,7 @@ This module contains a method to pay online using user balance. """ from . import models + NAME = "FREE" PaymentMethod = models.FreePayment diff --git a/cotisations/payment_methods/free/models.py b/cotisations/payment_methods/free/models.py index 2931faad..b64744fe 100644 --- a/cotisations/payment_methods/free/models.py +++ b/cotisations/payment_methods/free/models.py @@ -38,24 +38,17 @@ class FreePayment(PaymentMethodMixin, models.Model): payment = models.OneToOneField( Paiement, on_delete=models.CASCADE, - related_name='payment_method_free', - editable=False + related_name="payment_method_free", + editable=False, ) def end_payment(self, invoice, request): """Ends the payment normally. """ - return invoice.paiement.end_payment( - invoice, - request, - use_payment_method=False - ) + return invoice.paiement.end_payment(invoice, request, use_payment_method=False) def check_price(self, price, user, *args, **kwargs): """Checks that the price meets the requirement to be paid with user balance. """ - return ( - price == 0, - _("You cannot validate this invoice for free.") - ) + return (price == 0, _("You cannot validate this invoice for free.")) diff --git a/cotisations/payment_methods/mixins.py b/cotisations/payment_methods/mixins.py index 12503e05..1e808f09 100644 --- a/cotisations/payment_methods/mixins.py +++ b/cotisations/payment_methods/mixins.py @@ -29,5 +29,4 @@ class PaymentMethodMixin: Must return a HttpResponse-like object. """ - return self.payment.end_payment( - invoice, request, use_payment_method=False) + return self.payment.end_payment(invoice, request, use_payment_method=False) diff --git a/cotisations/payment_methods/note_kfet/__init__.py b/cotisations/payment_methods/note_kfet/__init__.py index 1f133d11..99949bbc 100644 --- a/cotisations/payment_methods/note_kfet/__init__.py +++ b/cotisations/payment_methods/note_kfet/__init__.py @@ -22,5 +22,6 @@ This module contains a method to pay online using comnpay. """ from . import models, urls + NAME = "NOTE" PaymentMethod = models.NotePayment diff --git a/cotisations/payment_methods/note_kfet/forms.py b/cotisations/payment_methods/note_kfet/forms.py index e52c275c..098315b7 100644 --- a/cotisations/payment_methods/note_kfet/forms.py +++ b/cotisations/payment_methods/note_kfet/forms.py @@ -24,15 +24,11 @@ from django.utils.translation import ugettext_lazy as _ from cotisations.utils import find_payment_method + class NoteCredentialForm(forms.Form): """A special form to get credential to connect to a NoteKfet2015 server throught his API object. """ - login = forms.CharField( - label=_("pseudo note") - ) - password = forms.CharField( - label=_("Password"), - widget=forms.PasswordInput - ) - + + login = forms.CharField(label=_("pseudo note")) + password = forms.CharField(label=_("Password"), widget=forms.PasswordInput) diff --git a/cotisations/payment_methods/note_kfet/models.py b/cotisations/payment_methods/note_kfet/models.py index 0e2ebea1..e83cfb36 100644 --- a/cotisations/payment_methods/note_kfet/models.py +++ b/cotisations/payment_methods/note_kfet/models.py @@ -41,25 +41,17 @@ class NotePayment(PaymentMethodMixin, models.Model): payment = models.OneToOneField( Paiement, - on_delete = models.CASCADE, - related_name = 'payment_method_note', - editable = False - ) - server = models.CharField( - max_length=255, - verbose_name=_("server") - ) - port = models.PositiveIntegerField( - blank = True, - null = True - ) - id_note = models.PositiveIntegerField( - blank = True, - null = True + on_delete=models.CASCADE, + related_name="payment_method_note", + editable=False, ) + server = models.CharField(max_length=255, verbose_name=_("server")) + port = models.PositiveIntegerField(blank=True, null=True) + id_note = models.PositiveIntegerField(blank=True, null=True) def end_payment(self, invoice, request): - return redirect(reverse( - 'cotisations:note_kfet:note_payment', - kwargs={'factureid': invoice.id} - )) + return redirect( + reverse( + "cotisations:note_kfet:note_payment", kwargs={"factureid": invoice.id} + ) + ) diff --git a/cotisations/payment_methods/note_kfet/note.py b/cotisations/payment_methods/note_kfet/note.py index 8b7614b0..40811913 100755 --- a/cotisations/payment_methods/note_kfet/note.py +++ b/cotisations/payment_methods/note_kfet/note.py @@ -12,13 +12,14 @@ import traceback def get_response(socket): - length_str = b'' + length_str = b"" char = socket.recv(1) - while char != b'\n': + while char != b"\n": length_str += char char = socket.recv(1) total = int(length_str) - return json.loads(socket.recv(total).decode('utf-8')) + return json.loads(socket.recv(total).decode("utf-8")) + def connect(server, port): sock = socket.socket() @@ -35,7 +36,8 @@ def connect(server, port): return (False, sock, "Serveur indisponible") return (True, sock, "") -def login(server, port, username, password, masque = [[], [], True]): + +def login(server, port, username, password, masque=[[], [], True]): result, sock, err = connect(server, port) if not result: return (False, None, err) @@ -43,7 +45,7 @@ def login(server, port, username, password, masque = [[], [], True]): commande = ["login", [username, password, "bdd", masque]] sock.send(json.dumps(commande).encode("utf-8")) response = get_response(sock) - retcode = response['retcode'] + retcode = response["retcode"] if retcode == 0: return (True, sock, "") elif retcode == 5: @@ -60,11 +62,28 @@ def don(sock, montant, id_note, facture): Faire faire un don à l'id_note """ try: - sock.send(json.dumps(["dons", [[id_note], round(montant*100), "Facture : id=%s, designation=%s" % (facture.id, facture.name())]]).encode("utf-8")) + sock.send( + json.dumps( + [ + "dons", + [ + [id_note], + round(montant * 100), + "Facture : id=%s, designation=%s" + % (facture.id, facture.name()), + ], + ] + ).encode("utf-8") + ) response = get_response(sock) - retcode = response['retcode'] + retcode = response["retcode"] transaction_retcode = response["msg"][0][0] - if 0 < retcode < 100 or 200 <= retcode or 0 < transaction_retcode < 100 or 200 <= transaction_retcode: + if ( + 0 < retcode < 100 + or 200 <= retcode + or 0 < transaction_retcode < 100 + or 200 <= transaction_retcode + ): return (False, "Transaction échouée. (Solde trop négatif ?)") elif retcode == 0: return (True, "") diff --git a/cotisations/payment_methods/note_kfet/urls.py b/cotisations/payment_methods/note_kfet/urls.py index 7b939136..89bb3eb9 100644 --- a/cotisations/payment_methods/note_kfet/urls.py +++ b/cotisations/payment_methods/note_kfet/urls.py @@ -23,8 +23,6 @@ from . import views urlpatterns = [ url( - r'^note_payment/(?P[0-9]+)$', - views.note_payment, - name='note_payment' - ), + r"^note_payment/(?P[0-9]+)$", views.note_payment, name="note_payment" + ) ] diff --git a/cotisations/payment_methods/note_kfet/views.py b/cotisations/payment_methods/note_kfet/views.py index cfdda9b0..4069a8f5 100644 --- a/cotisations/payment_methods/note_kfet/views.py +++ b/cotisations/payment_methods/note_kfet/views.py @@ -4,7 +4,7 @@ # quelques clics. # # Copyright © 2018 Gabriel Detraz -# Copyright © 2018 Pierre-Antoine Comby +# Copyright © 2018 Pierre-Antoine Comby # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -39,13 +39,11 @@ from cotisations.models import Facture from cotisations.utils import find_payment_method from .models import NotePayment from re2o.views import form -from re2o.acl import ( - can_create, - can_edit -) +from re2o.acl import can_create, can_edit from .note import login, don from .forms import NoteCredentialForm + @login_required @can_edit(Facture) def note_payment(request, facture, factureid): @@ -58,40 +56,38 @@ def note_payment(request, facture, factureid): payment_method = find_payment_method(facture.paiement) if not payment_method or not isinstance(payment_method, NotePayment): messages.error(request, _("Unknown error.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': user.id} - )) + return redirect(reverse("users:profil", kwargs={"userid": user.id})) noteform = NoteCredentialForm(request.POST or None) if noteform.is_valid(): - pseudo = noteform.cleaned_data['login'] - password = noteform.cleaned_data['password'] - result, sock, err = login(payment_method.server, payment_method.port, pseudo, password) + pseudo = noteform.cleaned_data["login"] + password = noteform.cleaned_data["password"] + result, sock, err = login( + payment_method.server, payment_method.port, pseudo, password + ) if not result: messages.error(request, err) return form( - {'form': noteform, 'amount': facture.prix_total()}, + {"form": noteform, "amount": facture.prix_total()}, "cotisations/payment.html", - request + request, ) else: - result, err = don(sock, facture.prix_total(), payment_method.id_note, facture) + result, err = don( + sock, facture.prix_total(), payment_method.id_note, facture + ) if not result: messages.error(request, err) return form( - {'form': noteform, 'amount': facture.prix_total()}, + {"form": noteform, "amount": facture.prix_total()}, "cotisations/payment.html", - request + request, ) facture.valid = True facture.save() messages.success(request, _("The payment with note was done.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': user.id} - )) + return redirect(reverse("users:profil", kwargs={"userid": user.id})) return form( - {'form': noteform, 'amount': facture.prix_total()}, - "cotisations/payment.html", - request - ) + {"form": noteform, "amount": facture.prix_total()}, + "cotisations/payment.html", + request, + ) diff --git a/cotisations/payment_methods/urls.py b/cotisations/payment_methods/urls.py index f6bb31dd..adb606bc 100644 --- a/cotisations/payment_methods/urls.py +++ b/cotisations/payment_methods/urls.py @@ -22,7 +22,7 @@ from django.conf.urls import include, url from . import comnpay, cheque, note_kfet urlpatterns = [ - url(r'^comnpay/', include(comnpay.urls, namespace='comnpay')), - url(r'^cheque/', include(cheque.urls, namespace='cheque')), - url(r'^note_kfet/', include(note_kfet.urls, namespace='note_kfet')), + url(r"^comnpay/", include(comnpay.urls, namespace="comnpay")), + url(r"^cheque/", include(cheque.urls, namespace="cheque")), + url(r"^note_kfet/", include(note_kfet.urls, namespace="note_kfet")), ] diff --git a/cotisations/test_models.py b/cotisations/test_models.py index ed53c0a1..f162ddf1 100644 --- a/cotisations/test_models.py +++ b/cotisations/test_models.py @@ -7,19 +7,13 @@ from dateutil.relativedelta import relativedelta from users.models import User from .models import Vente, Facture, Cotisation, Paiement + class VenteModelTests(TestCase): def setUp(self): - self.user = User.objects.create( - pseudo="testUser", - email="test@example.org" - ) - self.paiement = Paiement.objects.create( - moyen="test payment" - ) + self.user = User.objects.create(pseudo="testUser", email="test@example.org") + self.paiement = Paiement.objects.create(moyen="test payment") self.f = Facture.objects.create( - user=self.user, - paiement=self.paiement, - valid=True + user=self.user, paiement=self.paiement, valid=True ) def test_one_day_cotisation(self): @@ -39,7 +33,7 @@ class VenteModelTests(TestCase): self.assertAlmostEqual( self.user.end_connexion() - date, datetime.timedelta(days=1), - delta=datetime.timedelta(seconds=1) + delta=datetime.timedelta(seconds=1), ) def test_one_month_cotisation(self): @@ -57,11 +51,8 @@ class VenteModelTests(TestCase): prix=0, ) delta = relativedelta(self.user.end_connexion(), date) - delta.microseconds=0 - self.assertEqual( - delta, - relativedelta(months=1), - ) + delta.microseconds = 0 + self.assertEqual(delta, relativedelta(months=1)) def test_one_month_and_one_week_cotisation(self): """ @@ -78,15 +69,10 @@ class VenteModelTests(TestCase): prix=0, ) delta = relativedelta(self.user.end_connexion(), date) - delta.microseconds=0 - self.assertEqual( - delta, - relativedelta(months=1, days=7), - ) + delta.microseconds = 0 + self.assertEqual(delta, relativedelta(months=1, days=7)) def tearDown(self): self.f.delete() self.user.delete() self.paiement.delete() - - diff --git a/cotisations/test_views.py b/cotisations/test_views.py index ba24c4d6..f0c739b0 100644 --- a/cotisations/test_views.py +++ b/cotisations/test_views.py @@ -9,6 +9,7 @@ from django.utils import timezone from users.models import Adherent from .models import Vente, Facture, Cotisation, Paiement, Article + class NewFactureTests(TestCase): def tearDown(self): self.user.facture_set.all().delete() @@ -19,51 +20,46 @@ class NewFactureTests(TestCase): self.article_one_month_and_one_week.delete() def setUp(self): - self.user = Adherent.objects.create( - pseudo="testUser", - email="test@example.org", - ) - self.user.set_password('plopiplop') + self.user = Adherent.objects.create(pseudo="testUser", email="test@example.org") + self.user.set_password("plopiplop") self.user.user_permissions.set( [ - Permission.objects.get_by_natural_key("add_facture", "cotisations", "Facture"), - Permission.objects.get_by_natural_key("use_every_payment", "cotisations", "Paiement"), + Permission.objects.get_by_natural_key( + "add_facture", "cotisations", "Facture" + ), + Permission.objects.get_by_natural_key( + "use_every_payment", "cotisations", "Paiement" + ), ] ) self.user.save() - self.paiement = Paiement.objects.create( - moyen="test payment", - - ) + self.paiement = Paiement.objects.create(moyen="test payment") self.article_one_day = Article.objects.create( name="One day", prix=0, duration=0, duration_days=1, - type_cotisation='All', - available_for_everyone=True + type_cotisation="All", + available_for_everyone=True, ) self.article_one_month = Article.objects.create( name="One day", prix=0, duration=1, duration_days=0, - type_cotisation='All', - available_for_everyone=True + type_cotisation="All", + available_for_everyone=True, ) self.article_one_month_and_one_week = Article.objects.create( name="One day", prix=0, duration=1, duration_days=7, - type_cotisation='All', - available_for_everyone=True - ) - self.client.login( - username="testUser", - password="plopiplop" + type_cotisation="All", + available_for_everyone=True, ) + self.client.login(username="testUser", password="plopiplop") def test_invoice_with_one_day(self): data = { @@ -76,19 +72,15 @@ class NewFactureTests(TestCase): "form-0-quantity": 1, } date = timezone.now() - response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) - self.assertEqual( - response.status_code, - 302 - ) - self.assertEqual( - response.url, - "/users/profil/%d"%self.user.pk + response = self.client.post( + reverse("cotisations:new-facture", kwargs={"userid": self.user.pk}), data ) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, "/users/profil/%d" % self.user.pk) self.assertAlmostEqual( self.user.end_connexion() - date, datetime.timedelta(days=1), - delta=datetime.timedelta(seconds=1) + delta=datetime.timedelta(seconds=1), ) def test_invoice_with_one_month(self): @@ -102,21 +94,14 @@ class NewFactureTests(TestCase): "form-0-quantity": 1, } date = timezone.now() - response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) - self.assertEqual( - response.status_code, - 302 - ) - self.assertEqual( - response.url, - "/users/profil/%d"%self.user.pk + response = self.client.post( + reverse("cotisations:new-facture", kwargs={"userid": self.user.pk}), data ) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, "/users/profil/%d" % self.user.pk) delta = relativedelta(self.user.end_connexion(), date) - delta.microseconds=0 - self.assertEqual( - delta, - relativedelta(months=1), - ) + delta.microseconds = 0 + self.assertEqual(delta, relativedelta(months=1)) def test_invoice_with_one_month_and_one_week(self): data = { @@ -131,23 +116,15 @@ class NewFactureTests(TestCase): "form-1-quantity": 1, } date = timezone.now() - response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) - self.assertEqual( - response.status_code, - 302 - ) - self.assertEqual( - response.url, - "/users/profil/%d"%self.user.pk + response = self.client.post( + reverse("cotisations:new-facture", kwargs={"userid": self.user.pk}), data ) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, "/users/profil/%d" % self.user.pk) invoice = self.user.facture_set.first() delta = relativedelta(self.user.end_connexion(), date) - delta.microseconds=0 - self.assertEqual( - delta, - relativedelta(months=1, days=7), - ) - + delta.microseconds = 0 + self.assertEqual(delta, relativedelta(months=1, days=7)) def test_several_articles_creates_several_purchases(self): data = { @@ -161,6 +138,8 @@ class NewFactureTests(TestCase): "form-1-article": 2, "form-1-quantity": 1, } - response = self.client.post(reverse('cotisations:new-facture', kwargs={'userid':self.user.pk}), data) + response = self.client.post( + reverse("cotisations:new-facture", kwargs={"userid": self.user.pk}), data + ) f = self.user.facture_set.first() self.assertEqual(f.vente_set.count(), 2) diff --git a/cotisations/tex.py b/cotisations/tex.py index dd519122..45ded1aa 100644 --- a/cotisations/tex.py +++ b/cotisations/tex.py @@ -42,9 +42,9 @@ from re2o.mixins import AclMixin, RevMixin from preferences.models import CotisationsOption -TEMP_PREFIX = getattr(settings, 'TEX_TEMP_PREFIX', 'render_tex-') -CACHE_PREFIX = getattr(settings, 'TEX_CACHE_PREFIX', 'render-tex') -CACHE_TIMEOUT = getattr(settings, 'TEX_CACHE_TIMEOUT', 86400) # 1 day +TEMP_PREFIX = getattr(settings, "TEX_TEMP_PREFIX", "render_tex-") +CACHE_PREFIX = getattr(settings, "TEX_CACHE_PREFIX", "render-tex") +CACHE_TIMEOUT = getattr(settings, "TEX_CACHE_TIMEOUT", 86400) # 1 day def render_invoice(_request, ctx={}): @@ -53,20 +53,20 @@ def render_invoice(_request, ctx={}): date, the user, the articles, the prices, ... """ options, _ = CotisationsOption.objects.get_or_create() - is_estimate = ctx.get('is_estimate', False) - filename = '_'.join([ - 'cost_estimate' if is_estimate else 'invoice', - slugify(ctx.get('asso_name', "")), - slugify(ctx.get('recipient_name', "")), - str(ctx.get('DATE', datetime.now()).year), - str(ctx.get('DATE', datetime.now()).month), - str(ctx.get('DATE', datetime.now()).day), - ]) - templatename = options.invoice_template.template.name.split('/')[-1] - r = render_tex(_request, templatename, ctx) - r['Content-Disposition'] = 'attachment; filename="{name}.pdf"'.format( - name=filename + is_estimate = ctx.get("is_estimate", False) + filename = "_".join( + [ + "cost_estimate" if is_estimate else "invoice", + slugify(ctx.get("asso_name", "")), + slugify(ctx.get("recipient_name", "")), + str(ctx.get("DATE", datetime.now()).year), + str(ctx.get("DATE", datetime.now()).month), + str(ctx.get("DATE", datetime.now()).day), + ] ) + templatename = options.invoice_template.template.name.split("/")[-1] + r = render_tex(_request, templatename, ctx) + r["Content-Disposition"] = 'attachment; filename="{name}.pdf"'.format(name=filename) return r @@ -75,20 +75,20 @@ def render_voucher(_request, ctx={}): Render a subscribtion voucher. """ options, _ = CotisationsOption.objects.get_or_create() - filename = '_'.join([ - 'voucher', - slugify(ctx.get('asso_name', "")), - slugify(ctx.get('firstname', "")), - slugify(ctx.get('lastname', "")), - str(ctx.get('date_begin', datetime.now()).year), - str(ctx.get('date_begin', datetime.now()).month), - str(ctx.get('date_begin', datetime.now()).day), - ]) - templatename = options.voucher_template.template.name.split('/')[-1] - r = render_tex(_request, templatename, ctx) - r['Content-Disposition'] = 'attachment; filename="{name}.pdf"'.format( - name=filename + filename = "_".join( + [ + "voucher", + slugify(ctx.get("asso_name", "")), + slugify(ctx.get("firstname", "")), + slugify(ctx.get("lastname", "")), + str(ctx.get("date_begin", datetime.now()).year), + str(ctx.get("date_begin", datetime.now()).month), + str(ctx.get("date_begin", datetime.now()).day), + ] ) + templatename = options.voucher_template.template.name.split("/")[-1] + r = render_tex(_request, templatename, ctx) + r["Content-Disposition"] = 'attachment; filename="{name}.pdf"'.format(name=filename) return r @@ -106,18 +106,18 @@ def create_pdf(template, ctx={}): """ context = ctx template = get_template(template) - rendered_tpl = template.render(context).encode('utf-8') + rendered_tpl = template.render(context).encode("utf-8") with tempfile.TemporaryDirectory() as tempdir: for _ in range(2): with open("/var/www/re2o/out.log", "w") as f: process = Popen( - ['pdflatex', '-output-directory', tempdir], + ["pdflatex", "-output-directory", tempdir], stdin=PIPE, - stdout=f,#PIPE, + stdout=f, # PIPE, ) process.communicate(rendered_tpl) - with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f: + with open(os.path.join(tempdir, "texput.pdf"), "rb") as f: pdf = f.read() return pdf @@ -127,10 +127,7 @@ def escape_chars(string): """Escape the '%' and the '€' signs to avoid messing with LaTeX""" if not isinstance(string, str): return string - mapping = ( - ('€', r'\euro'), - ('%', r'\%'), - ) + mapping = (("€", r"\euro"), ("%", r"\%")) r = str(string) for k, v in mapping: r = r.replace(k, v) @@ -152,6 +149,6 @@ def render_tex(_request, template, ctx={}): An HttpResponse with type `application/pdf` containing the PDF file. """ pdf = create_pdf(template, ctx) - r = HttpResponse(content_type='application/pdf') + r = HttpResponse(content_type="application/pdf") r.write(pdf) return r diff --git a/cotisations/urls.py b/cotisations/urls.py index 9cc6e62c..e0a3aa16 100644 --- a/cotisations/urls.py +++ b/cotisations/urls.py @@ -31,155 +31,77 @@ from . import views from . import payment_methods urlpatterns = [ + url(r"^new_facture/(?P[0-9]+)$", views.new_facture, name="new-facture"), url( - r'^new_facture/(?P[0-9]+)$', - views.new_facture, - name='new-facture' + r"^edit_facture/(?P[0-9]+)$", views.edit_facture, name="edit-facture" + ), + url(r"^del_facture/(?P[0-9]+)$", views.del_facture, name="del-facture"), + url(r"^facture_pdf/(?P[0-9]+)$", views.facture_pdf, name="facture-pdf"), + url(r"^voucher_pdf/(?P[0-9]+)$", views.voucher_pdf, name="voucher-pdf"), + url(r"^new_cost_estimate/$", views.new_cost_estimate, name="new-cost-estimate"), + url( + r"^index_cost_estimate/$", views.index_cost_estimate, name="index-cost-estimate" ), url( - r'^edit_facture/(?P[0-9]+)$', - views.edit_facture, - name='edit-facture' - ), - url( - r'^del_facture/(?P[0-9]+)$', - views.del_facture, - name='del-facture' - ), - url( - r'^facture_pdf/(?P[0-9]+)$', - views.facture_pdf, - name='facture-pdf' - ), - url( - r'^voucher_pdf/(?P[0-9]+)$', - views.voucher_pdf, - name='voucher-pdf' - ), - url( - r'^new_cost_estimate/$', - views.new_cost_estimate, - name='new-cost-estimate' - ), - url( - r'^index_cost_estimate/$', - views.index_cost_estimate, - name='index-cost-estimate' - ), - url( - r'^cost_estimate_pdf/(?P[0-9]+)$', + r"^cost_estimate_pdf/(?P[0-9]+)$", views.cost_estimate_pdf, - name='cost-estimate-pdf', + name="cost-estimate-pdf", ), url( - r'^index_custom_invoice/$', + r"^index_custom_invoice/$", views.index_custom_invoice, - name='index-custom-invoice' + name="index-custom-invoice", ), url( - r'^edit_cost_estimate/(?P[0-9]+)$', + r"^edit_cost_estimate/(?P[0-9]+)$", views.edit_cost_estimate, - name='edit-cost-estimate' + name="edit-cost-estimate", ), url( - r'^cost_estimate_to_invoice/(?P[0-9]+)$', + r"^cost_estimate_to_invoice/(?P[0-9]+)$", views.cost_estimate_to_invoice, - name='cost-estimate-to-invoice' + name="cost-estimate-to-invoice", ), url( - r'^del_cost_estimate/(?P[0-9]+)$', + r"^del_cost_estimate/(?P[0-9]+)$", views.del_cost_estimate, - name='del-cost-estimate' + name="del-cost-estimate", ), + url(r"^new_custom_invoice/$", views.new_custom_invoice, name="new-custom-invoice"), url( - r'^new_custom_invoice/$', - views.new_custom_invoice, - name='new-custom-invoice' - ), - url( - r'^edit_custom_invoice/(?P[0-9]+)$', + r"^edit_custom_invoice/(?P[0-9]+)$", views.edit_custom_invoice, - name='edit-custom-invoice' + name="edit-custom-invoice", ), url( - r'^custom_invoice_pdf/(?P[0-9]+)$', + r"^custom_invoice_pdf/(?P[0-9]+)$", views.custom_invoice_pdf, - name='custom-invoice-pdf', + name="custom-invoice-pdf", ), url( - r'^del_custom_invoice/(?P[0-9]+)$', + r"^del_custom_invoice/(?P[0-9]+)$", views.del_custom_invoice, - name='del-custom-invoice' + name="del-custom-invoice", ), + url(r"^credit_solde/(?P[0-9]+)$", views.credit_solde, name="credit-solde"), + url(r"^add_article/$", views.add_article, name="add-article"), url( - r'^credit_solde/(?P[0-9]+)$', - views.credit_solde, - name='credit-solde' + r"^edit_article/(?P[0-9]+)$", views.edit_article, name="edit-article" ), + url(r"^del_article/$", views.del_article, name="del-article"), + url(r"^add_paiement/$", views.add_paiement, name="add-paiement"), url( - r'^add_article/$', - views.add_article, - name='add-article' - ), - url( - r'^edit_article/(?P[0-9]+)$', - views.edit_article, - name='edit-article' - ), - url( - r'^del_article/$', - views.del_article, - name='del-article' - ), - url( - r'^add_paiement/$', - views.add_paiement, - name='add-paiement' - ), - url( - r'^edit_paiement/(?P[0-9]+)$', + r"^edit_paiement/(?P[0-9]+)$", views.edit_paiement, - name='edit-paiement' + name="edit-paiement", ), - url( - r'^del_paiement/$', - views.del_paiement, - name='del-paiement' - ), - url( - r'^add_banque/$', - views.add_banque, - name='add-banque' - ), - url( - r'^edit_banque/(?P[0-9]+)$', - views.edit_banque, - name='edit-banque' - ), - url( - r'^del_banque/$', - views.del_banque, - name='del-banque' - ), - url( - r'^index_article/$', - views.index_article, - name='index-article' - ), - url( - r'^index_banque/$', - views.index_banque, - name='index-banque' - ), - url( - r'^index_paiement/$', - views.index_paiement, - name='index-paiement' - ), - url( - r'^control/$', - views.control, - name='control' - ), - url(r'^$', views.index, name='index'), + url(r"^del_paiement/$", views.del_paiement, name="del-paiement"), + url(r"^add_banque/$", views.add_banque, name="add-banque"), + url(r"^edit_banque/(?P[0-9]+)$", views.edit_banque, name="edit-banque"), + url(r"^del_banque/$", views.del_banque, name="del-banque"), + url(r"^index_article/$", views.index_article, name="index-article"), + url(r"^index_banque/$", views.index_banque, name="index-banque"), + url(r"^index_paiement/$", views.index_paiement, name="index-paiement"), + url(r"^control/$", views.control, name="control"), + url(r"^$", views.index, name="index"), ] + payment_methods.urls.urlpatterns diff --git a/cotisations/utils.py b/cotisations/utils.py index 6746a1da..facc1197 100644 --- a/cotisations/utils.py +++ b/cotisations/utils.py @@ -25,9 +25,7 @@ from django.template.loader import get_template from django.core.mail import EmailMessage from .tex import create_pdf -from preferences.models import ( - AssoOption, GeneralOption, CotisationsOption, Mandate -) +from preferences.models import AssoOption, GeneralOption, CotisationsOption, Mandate from re2o.settings import LOGO_PATH from re2o import settings @@ -35,6 +33,7 @@ from re2o import settings def find_payment_method(payment): """Finds the payment method associated to the payment if it exists.""" from cotisations.payment_methods import PAYMENT_METHODS + for method in PAYMENT_METHODS: try: o = method.PaymentMethod.objects.get(payment=payment) @@ -48,51 +47,47 @@ def send_mail_invoice(invoice): """Creates the pdf of the invoice and sends it by email to the client""" purchases_info = [] for purchase in invoice.vente_set.all(): - purchases_info.append({ - 'name': purchase.name, - 'price': purchase.prix, - 'quantity': purchase.number, - 'total_price': purchase.prix_total - }) + purchases_info.append( + { + "name": purchase.name, + "price": purchase.prix, + "quantity": purchase.number, + "total_price": purchase.prix_total, + } + ) ctx = { - 'paid': True, - 'fid': invoice.id, - 'DATE': invoice.date, - 'recipient_name': "{} {}".format( - invoice.user.name, - invoice.user.surname - ), - 'address': invoice.user.room, - 'article': purchases_info, - 'total': invoice.prix_total(), - 'asso_name': AssoOption.get_cached_value('name'), - 'line1': AssoOption.get_cached_value('adresse1'), - 'line2': AssoOption.get_cached_value('adresse2'), - 'siret': AssoOption.get_cached_value('siret'), - 'email': AssoOption.get_cached_value('contact'), - 'phone': AssoOption.get_cached_value('telephone'), - 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH) + "paid": True, + "fid": invoice.id, + "DATE": invoice.date, + "recipient_name": "{} {}".format(invoice.user.name, invoice.user.surname), + "address": invoice.user.room, + "article": purchases_info, + "total": invoice.prix_total(), + "asso_name": AssoOption.get_cached_value("name"), + "line1": AssoOption.get_cached_value("adresse1"), + "line2": AssoOption.get_cached_value("adresse2"), + "siret": AssoOption.get_cached_value("siret"), + "email": AssoOption.get_cached_value("contact"), + "phone": AssoOption.get_cached_value("telephone"), + "tpl_path": os.path.join(settings.BASE_DIR, LOGO_PATH), } - pdf = create_pdf('cotisations/factures.tex', ctx) - template = get_template('cotisations/email_invoice') + pdf = create_pdf("cotisations/factures.tex", ctx) + template = get_template("cotisations/email_invoice") ctx = { - 'name': "{} {}".format( - invoice.user.name, - invoice.user.surname - ), - 'contact_mail': AssoOption.get_cached_value('contact'), - 'asso_name': AssoOption.get_cached_value('name') + "name": "{} {}".format(invoice.user.name, invoice.user.surname), + "contact_mail": AssoOption.get_cached_value("contact"), + "asso_name": AssoOption.get_cached_value("name"), } mail = EmailMessage( - 'Votre facture / Your invoice', + "Votre facture / Your invoice", template.render(ctx), - GeneralOption.get_cached_value('email_from'), + GeneralOption.get_cached_value("email_from"), [invoice.user.get_mail], - attachments=[('invoice.pdf', pdf, 'application/pdf')] + attachments=[("invoice.pdf", pdf, "application/pdf")], ) mail.send() @@ -101,34 +96,33 @@ def send_mail_voucher(invoice): """Creates a voucher from an invoice and sends it by email to the client""" president = Mandate.get_mandate(invoice.date).president ctx = { - 'asso_name': AssoOption.get_cached_value('name'), - 'pres_name': ' '.join([president.name, president.surname]), - 'firstname': invoice.user.name, - 'lastname': invoice.user.surname, - 'email': invoice.user.email, - 'phone': invoice.user.telephone, - 'date_end': invoice.get_subscription().latest('date_end').date_end, - 'date_begin': invoice.get_subscription().earliest('date_start').date_start + "asso_name": AssoOption.get_cached_value("name"), + "pres_name": " ".join([president.name, president.surname]), + "firstname": invoice.user.name, + "lastname": invoice.user.surname, + "email": invoice.user.email, + "phone": invoice.user.telephone, + "date_end": invoice.get_subscription().latest("date_end").date_end, + "date_begin": invoice.get_subscription().earliest("date_start").date_start, } - templatename = CotisationsOption.get_cached_value('voucher_template').template.name.split('/')[-1] + templatename = CotisationsOption.get_cached_value( + "voucher_template" + ).template.name.split("/")[-1] pdf = create_pdf(templatename, ctx) - template = get_template('cotisations/email_subscription_accepted') + template = get_template("cotisations/email_subscription_accepted") ctx = { - 'name': "{} {}".format( - invoice.user.name, - invoice.user.surname - ), - 'asso_email': AssoOption.get_cached_value('contact'), - 'asso_name': AssoOption.get_cached_value('name'), - 'date_end': invoice.get_subscription().latest('date_end').date_end, + "name": "{} {}".format(invoice.user.name, invoice.user.surname), + "asso_email": AssoOption.get_cached_value("contact"), + "asso_name": AssoOption.get_cached_value("name"), + "date_end": invoice.get_subscription().latest("date_end").date_end, } mail = EmailMessage( - 'Votre reçu / Your voucher', + "Votre reçu / Your voucher", template.render(ctx), - GeneralOption.get_cached_value('email_from'), + GeneralOption.get_cached_value("email_from"), [invoice.user.get_mail], - attachments=[('voucher.pdf', pdf, 'application/pdf')] + attachments=[("voucher.pdf", pdf, "application/pdf")], ) mail.send() diff --git a/cotisations/validators.py b/cotisations/validators.py index b1683e82..91a3b627 100644 --- a/cotisations/validators.py +++ b/cotisations/validators.py @@ -12,11 +12,9 @@ def check_no_balance(is_balance): ValidationError: if such a Paiement exists. """ from .models import Paiement + if not is_balance: return p = Paiement.objects.filter(is_balance=True) if len(p) > 0: - raise ValidationError( - _("There is already a payment method for user balance.") - ) - + raise ValidationError(_("There is already a payment method for user balance.")) diff --git a/cotisations/views.py b/cotisations/views.py index 2a262704..4510aff9 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -47,10 +47,7 @@ from users.models import User from re2o.settings import LOGO_PATH from re2o import settings from re2o.views import form -from re2o.base import ( - SortTable, - re2o_paginator, -) +from re2o.base import SortTable, re2o_paginator from re2o.acl import ( can_create, can_edit, @@ -105,19 +102,15 @@ def new_facture(request, user, userid): invoice = Facture(user=user) # The template needs the list of articles (for the JS part) article_list = Article.objects.filter( - Q(type_user='All') | Q(type_user=request.user.class_name) + Q(type_user="All") | Q(type_user=request.user.class_name) ) # Building the invoice form and the article formset invoice_form = FactureForm( - request.POST or None, - instance=invoice, - user=request.user, - creation=True + request.POST or None, instance=invoice, user=request.user, creation=True ) article_formset = formset_factory(SelectArticleForm)( - request.POST or None, - form_kwargs={'user': request.user, 'target_user': user} + request.POST or None, form_kwargs={"user": request.user, "target_user": user} ) if invoice_form.is_valid() and article_formset.is_valid(): @@ -130,9 +123,9 @@ def new_facture(request, user, userid): total_price = 0 for art_item in articles: if art_item.cleaned_data: - article = art_item.cleaned_data['article'] - quantity = art_item.cleaned_data['quantity'] - total_price += article.prix*quantity + article = art_item.cleaned_data["article"] + quantity = art_item.cleaned_data["quantity"] + total_price += article.prix * quantity new_purchase = Vente( facture=new_invoice_instance, name=article.name, @@ -140,11 +133,11 @@ def new_facture(request, user, userid): type_cotisation=article.type_cotisation, duration=article.duration, duration_days=article.duration_days, - number=quantity + number=quantity, ) purchases.append(new_purchase) p = find_payment_method(new_invoice_instance.paiement) - if hasattr(p, 'check_price'): + if hasattr(p, "check_price"): price_ok, msg = p.check_price(total_price, user) invoice_form.add_error(None, msg) else: @@ -156,14 +149,10 @@ def new_facture(request, user, userid): p.save() return new_invoice_instance.paiement.end_payment( - new_invoice_instance, - request + new_invoice_instance, request ) else: - messages.error( - request, - _("You need to choose at least one article.") - ) + messages.error(request, _("You need to choose at least one article.")) p = Paiement.objects.filter(is_balance=True) if len(p) and p[0].can_use_payment(request.user): balance = user.solde @@ -172,13 +161,14 @@ def new_facture(request, user, userid): return form( { - 'factureform': invoice_form, - 'articlesformset': article_formset, - 'articlelist': article_list, - 'balance': balance, - 'action_name': _('Confirm'), + "factureform": invoice_form, + "articlesformset": article_formset, + "articlelist": article_list, + "balance": balance, + "action_name": _("Confirm"), }, - 'cotisations/facture.html', request + "cotisations/facture.html", + request, ) @@ -192,47 +182,51 @@ def new_cost_estimate(request): """ # The template needs the list of articles (for the JS part) articles = Article.objects.filter( - Q(type_user='All') | Q(type_user=request.user.class_name) + Q(type_user="All") | Q(type_user=request.user.class_name) ) # Building the invocie form and the article formset cost_estimate_form = CostEstimateForm(request.POST or None) articles_formset = formset_factory(SelectArticleForm)( - request.POST or None, - form_kwargs={'user': request.user} + request.POST or None, form_kwargs={"user": request.user} ) discount_form = DiscountForm(request.POST or None) - if cost_estimate_form.is_valid() and articles_formset.is_valid() and discount_form.is_valid(): + if ( + cost_estimate_form.is_valid() + and articles_formset.is_valid() + and discount_form.is_valid() + ): cost_estimate_instance = cost_estimate_form.save() for art_item in articles_formset: if art_item.cleaned_data: - article = art_item.cleaned_data['article'] - quantity = art_item.cleaned_data['quantity'] + article = art_item.cleaned_data["article"] + quantity = art_item.cleaned_data["quantity"] Vente.objects.create( facture=cost_estimate_instance, name=article.name, prix=article.prix, type_cotisation=article.type_cotisation, duration=article.duration, - number=quantity + number=quantity, ) discount_form.apply_to_invoice(cost_estimate_instance) - messages.success( - request, - _("The cost estimate was created.") - ) - return redirect(reverse('cotisations:index-cost-estimate')) + messages.success(request, _("The cost estimate was created.")) + return redirect(reverse("cotisations:index-cost-estimate")) - return form({ - 'factureform': cost_estimate_form, - 'action_name': _("Confirm"), - 'articlesformset': articles_formset, - 'articlelist': articles, - 'discount_form': discount_form, - 'title': _("Cost estimate"), - }, 'cotisations/facture.html', request) + return form( + { + "factureform": cost_estimate_form, + "action_name": _("Confirm"), + "articlesformset": articles_formset, + "articlelist": articles, + "discount_form": discount_form, + "title": _("Cost estimate"), + }, + "cotisations/facture.html", + request, + ) @login_required @@ -245,45 +239,49 @@ def new_custom_invoice(request): """ # The template needs the list of articles (for the JS part) articles = Article.objects.filter( - Q(type_user='All') | Q(type_user=request.user.class_name) + Q(type_user="All") | Q(type_user=request.user.class_name) ) # Building the invocie form and the article formset invoice_form = CustomInvoiceForm(request.POST or None) articles_formset = formset_factory(SelectArticleForm)( - request.POST or None, - form_kwargs={'user': request.user} + request.POST or None, form_kwargs={"user": request.user} ) discount_form = DiscountForm(request.POST or None) - if invoice_form.is_valid() and articles_formset.is_valid() and discount_form.is_valid(): + if ( + invoice_form.is_valid() + and articles_formset.is_valid() + and discount_form.is_valid() + ): new_invoice_instance = invoice_form.save() for art_item in articles_formset: if art_item.cleaned_data: - article = art_item.cleaned_data['article'] - quantity = art_item.cleaned_data['quantity'] + article = art_item.cleaned_data["article"] + quantity = art_item.cleaned_data["quantity"] Vente.objects.create( facture=new_invoice_instance, name=article.name, prix=article.prix, type_cotisation=article.type_cotisation, duration=article.duration, - number=quantity + number=quantity, ) discount_form.apply_to_invoice(new_invoice_instance) - messages.success( - request, - _("The custom invoice was created.") - ) - return redirect(reverse('cotisations:index-custom-invoice')) + messages.success(request, _("The custom invoice was created.")) + return redirect(reverse("cotisations:index-custom-invoice")) - return form({ - 'factureform': invoice_form, - 'action_name': _("Confirm"), - 'articlesformset': articles_formset, - 'articlelist': articles, - 'discount_form': discount_form - }, 'cotisations/facture.html', request) + return form( + { + "factureform": invoice_form, + "action_name": _("Confirm"), + "articlesformset": articles_formset, + "articlelist": articles, + "discount_form": discount_form, + }, + "cotisations/facture.html", + request, + ) # TODO : change facture to invoice @@ -302,32 +300,34 @@ def facture_pdf(request, facture, **_kwargs): # contiaining (article_name, article_price, quantity, total_price) purchases_info = [] for purchase in purchases_objects: - purchases_info.append({ - 'name': purchase.name, - 'price': purchase.prix, - 'quantity': purchase.number, - 'total_price': purchase.prix_total - }) - return render_invoice(request, { - 'paid': True, - 'fid': facture.id, - 'DATE': facture.date, - 'recipient_name': "{} {}".format( - facture.user.name, - facture.user.surname - ), - 'address': facture.user.room, - 'article': purchases_info, - 'total': facture.prix_total(), - 'asso_name': AssoOption.get_cached_value('name'), - 'line1': AssoOption.get_cached_value('adresse1'), - 'line2': AssoOption.get_cached_value('adresse2'), - 'siret': AssoOption.get_cached_value('siret'), - 'email': AssoOption.get_cached_value('contact'), - 'phone': AssoOption.get_cached_value('telephone'), - 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH), - 'payment_method': facture.paiement.moyen, - }) + purchases_info.append( + { + "name": purchase.name, + "price": purchase.prix, + "quantity": purchase.number, + "total_price": purchase.prix_total, + } + ) + return render_invoice( + request, + { + "paid": True, + "fid": facture.id, + "DATE": facture.date, + "recipient_name": "{} {}".format(facture.user.name, facture.user.surname), + "address": facture.user.room, + "article": purchases_info, + "total": facture.prix_total(), + "asso_name": AssoOption.get_cached_value("name"), + "line1": AssoOption.get_cached_value("adresse1"), + "line2": AssoOption.get_cached_value("adresse2"), + "siret": AssoOption.get_cached_value("siret"), + "email": AssoOption.get_cached_value("contact"), + "phone": AssoOption.get_cached_value("telephone"), + "tpl_path": os.path.join(settings.BASE_DIR, LOGO_PATH), + "payment_method": facture.paiement.moyen, + }, + ) # TODO : change facture to invoice @@ -341,34 +341,24 @@ def edit_facture(request, facture, **_kwargs): an invoice. """ invoice_form = FactureForm( - request.POST or None, - instance=facture, - user=request.user + request.POST or None, instance=facture, user=request.user ) purchases_objects = Vente.objects.filter(facture=facture) purchase_form_set = modelformset_factory( - Vente, - fields=('name', 'number'), - extra=0, - max_num=len(purchases_objects) - ) - purchase_form = purchase_form_set( - request.POST or None, - queryset=purchases_objects + Vente, fields=("name", "number"), extra=0, max_num=len(purchases_objects) ) + purchase_form = purchase_form_set(request.POST or None, queryset=purchases_objects) if invoice_form.is_valid() and purchase_form.is_valid(): if invoice_form.changed_data: invoice_form.save() purchase_form.save() - messages.success( - request, - _("The invoice was edited.") - ) - return redirect(reverse('cotisations:index')) - return form({ - 'factureform': invoice_form, - 'venteform': purchase_form - }, 'cotisations/edit_facture.html', request) + messages.success(request, _("The invoice was edited.")) + return redirect(reverse("cotisations:index")) + return form( + {"factureform": invoice_form, "venteform": purchase_form}, + "cotisations/edit_facture.html", + request, + ) # TODO : change facture to invoice @@ -380,51 +370,41 @@ def del_facture(request, facture, **_kwargs): """ if request.method == "POST": facture.delete() - messages.success( - request, - _("The invoice was deleted.") - ) - return redirect(reverse('cotisations:index')) - return form({ - 'objet': facture, - 'objet_name': _("Invoice") - }, 'cotisations/delete.html', request) + messages.success(request, _("The invoice was deleted.")) + return redirect(reverse("cotisations:index")) + return form( + {"objet": facture, "objet_name": _("Invoice")}, + "cotisations/delete.html", + request, + ) @login_required @can_edit(CostEstimate) def edit_cost_estimate(request, invoice, **kwargs): # Building the invocie form and the article formset - invoice_form = CostEstimateForm( - request.POST or None, - instance=invoice - ) + invoice_form = CostEstimateForm(request.POST or None, instance=invoice) purchases_objects = Vente.objects.filter(facture=invoice) purchase_form_set = modelformset_factory( - Vente, - fields=('name', 'number'), - extra=0, - max_num=len(purchases_objects) - ) - purchase_form = purchase_form_set( - request.POST or None, - queryset=purchases_objects + Vente, fields=("name", "number"), extra=0, max_num=len(purchases_objects) ) + purchase_form = purchase_form_set(request.POST or None, queryset=purchases_objects) if invoice_form.is_valid() and purchase_form.is_valid(): if invoice_form.changed_data: invoice_form.save() purchase_form.save() - messages.success( - request, - _("The cost estimate was edited.") - ) - return redirect(reverse('cotisations:index-cost-estimate')) + messages.success(request, _("The cost estimate was edited.")) + return redirect(reverse("cotisations:index-cost-estimate")) - return form({ - 'factureform': invoice_form, - 'venteform': purchase_form, - 'title': _("Edit cost estimate") - }, 'cotisations/edit_facture.html', request) + return form( + { + "factureform": invoice_form, + "venteform": purchase_form, + "title": _("Edit cost estimate"), + }, + "cotisations/edit_facture.html", + request, + ) @login_required @@ -434,45 +414,33 @@ def cost_estimate_to_invoice(request, cost_estimate, **_kwargs): """Create a custom invoice from a cos estimate""" cost_estimate.create_invoice() messages.success( - request, - _("An invoice was successfully created from your cost estimate.") + request, _("An invoice was successfully created from your cost estimate.") ) - return redirect(reverse('cotisations:index-custom-invoice')) + return redirect(reverse("cotisations:index-custom-invoice")) @login_required @can_edit(CustomInvoice) def edit_custom_invoice(request, invoice, **kwargs): # Building the invocie form and the article formset - invoice_form = CustomInvoiceForm( - request.POST or None, - instance=invoice - ) + invoice_form = CustomInvoiceForm(request.POST or None, instance=invoice) purchases_objects = Vente.objects.filter(facture=invoice) purchase_form_set = modelformset_factory( - Vente, - fields=('name', 'number'), - extra=0, - max_num=len(purchases_objects) - ) - purchase_form = purchase_form_set( - request.POST or None, - queryset=purchases_objects + Vente, fields=("name", "number"), extra=0, max_num=len(purchases_objects) ) + purchase_form = purchase_form_set(request.POST or None, queryset=purchases_objects) if invoice_form.is_valid() and purchase_form.is_valid(): if invoice_form.changed_data: invoice_form.save() purchase_form.save() - messages.success( - request, - _("The invoice was edited.") - ) - return redirect(reverse('cotisations:index-custom-invoice')) + messages.success(request, _("The invoice was edited.")) + return redirect(reverse("cotisations:index-custom-invoice")) - return form({ - 'factureform': invoice_form, - 'venteform': purchase_form - }, 'cotisations/edit_facture.html', request) + return form( + {"factureform": invoice_form, "venteform": purchase_form}, + "cotisations/edit_facture.html", + request, + ) @login_required @@ -489,32 +457,37 @@ def cost_estimate_pdf(request, invoice, **_kwargs): # contiaining (article_name, article_price, quantity, total_price) purchases_info = [] for purchase in purchases_objects: - purchases_info.append({ - 'name': escape_chars(purchase.name), - 'price': purchase.prix, - 'quantity': purchase.number, - 'total_price': purchase.prix_total - }) - return render_invoice(request, { - 'paid': invoice.paid, - 'fid': invoice.id, - 'DATE': invoice.date, - 'recipient_name': invoice.recipient, - 'address': invoice.address, - 'article': purchases_info, - 'total': invoice.prix_total(), - 'asso_name': AssoOption.get_cached_value('name'), - 'line1': AssoOption.get_cached_value('adresse1'), - 'line2': AssoOption.get_cached_value('adresse2'), - 'siret': AssoOption.get_cached_value('siret'), - 'email': AssoOption.get_cached_value('contact'), - 'phone': AssoOption.get_cached_value('telephone'), - 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH), - 'payment_method': invoice.payment, - 'remark': invoice.remark, - 'end_validity': invoice.date + invoice.validity, - 'is_estimate': True, - }) + purchases_info.append( + { + "name": escape_chars(purchase.name), + "price": purchase.prix, + "quantity": purchase.number, + "total_price": purchase.prix_total, + } + ) + return render_invoice( + request, + { + "paid": invoice.paid, + "fid": invoice.id, + "DATE": invoice.date, + "recipient_name": invoice.recipient, + "address": invoice.address, + "article": purchases_info, + "total": invoice.prix_total(), + "asso_name": AssoOption.get_cached_value("name"), + "line1": AssoOption.get_cached_value("adresse1"), + "line2": AssoOption.get_cached_value("adresse2"), + "siret": AssoOption.get_cached_value("siret"), + "email": AssoOption.get_cached_value("contact"), + "phone": AssoOption.get_cached_value("telephone"), + "tpl_path": os.path.join(settings.BASE_DIR, LOGO_PATH), + "payment_method": invoice.payment, + "remark": invoice.remark, + "end_validity": invoice.date + invoice.validity, + "is_estimate": True, + }, + ) @login_required @@ -525,15 +498,13 @@ def del_cost_estimate(request, estimate, **_kwargs): """ if request.method == "POST": estimate.delete() - messages.success( - request, - _("The cost estimate was deleted.") - ) - return redirect(reverse('cotisations:index-cost-estimate')) - return form({ - 'objet': estimate, - 'objet_name': _("Cost estimate") - }, 'cotisations/delete.html', request) + messages.success(request, _("The cost estimate was deleted.")) + return redirect(reverse("cotisations:index-cost-estimate")) + return form( + {"objet": estimate, "objet_name": _("Cost estimate")}, + "cotisations/delete.html", + request, + ) @login_required @@ -551,30 +522,35 @@ def custom_invoice_pdf(request, invoice, **_kwargs): # contiaining (article_name, article_price, quantity, total_price) purchases_info = [] for purchase in purchases_objects: - purchases_info.append({ - 'name': escape_chars(purchase.name), - 'price': purchase.prix, - 'quantity': purchase.number, - 'total_price': purchase.prix_total - }) - return render_invoice(request, { - 'paid': invoice.paid, - 'fid': invoice.id, - 'DATE': invoice.date, - 'recipient_name': invoice.recipient, - 'address': invoice.address, - 'article': purchases_info, - 'total': invoice.prix_total(), - 'asso_name': AssoOption.get_cached_value('name'), - 'line1': AssoOption.get_cached_value('adresse1'), - 'line2': AssoOption.get_cached_value('adresse2'), - 'siret': AssoOption.get_cached_value('siret'), - 'email': AssoOption.get_cached_value('contact'), - 'phone': AssoOption.get_cached_value('telephone'), - 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH), - 'payment_method': invoice.payment, - 'remark': invoice.remark, - }) + purchases_info.append( + { + "name": escape_chars(purchase.name), + "price": purchase.prix, + "quantity": purchase.number, + "total_price": purchase.prix_total, + } + ) + return render_invoice( + request, + { + "paid": invoice.paid, + "fid": invoice.id, + "DATE": invoice.date, + "recipient_name": invoice.recipient, + "address": invoice.address, + "article": purchases_info, + "total": invoice.prix_total(), + "asso_name": AssoOption.get_cached_value("name"), + "line1": AssoOption.get_cached_value("adresse1"), + "line2": AssoOption.get_cached_value("adresse2"), + "siret": AssoOption.get_cached_value("siret"), + "email": AssoOption.get_cached_value("contact"), + "phone": AssoOption.get_cached_value("telephone"), + "tpl_path": os.path.join(settings.BASE_DIR, LOGO_PATH), + "payment_method": invoice.payment, + "remark": invoice.remark, + }, + ) @login_required @@ -585,15 +561,13 @@ def del_custom_invoice(request, invoice, **_kwargs): """ if request.method == "POST": invoice.delete() - messages.success( - request, - _("The invoice was deleted.") - ) - return redirect(reverse('cotisations:index-custom-invoice')) - return form({ - 'objet': invoice, - 'objet_name': _("Invoice") - }, 'cotisations/delete.html', request) + messages.success(request, _("The invoice was deleted.")) + return redirect(reverse("cotisations:index-custom-invoice")) + return form( + {"objet": invoice, "objet_name": _("Invoice")}, + "cotisations/delete.html", + request, + ) @login_required @@ -611,16 +585,13 @@ def add_article(request): article = ArticleForm(request.POST or None) if article.is_valid(): article.save() - messages.success( - request, - _("The article was created.") - ) - return redirect(reverse('cotisations:index-article')) - return form({ - 'factureform': article, - 'action_name': _("Add"), - 'title': _("New article") - }, 'cotisations/facture.html', request) + messages.success(request, _("The article was created.")) + return redirect(reverse("cotisations:index-article")) + return form( + {"factureform": article, "action_name": _("Add"), "title": _("New article")}, + "cotisations/facture.html", + request, + ) @login_required @@ -633,16 +604,13 @@ def edit_article(request, article_instance, **_kwargs): if article.is_valid(): if article.changed_data: article.save() - messages.success( - request, - _("The article was edited.") - ) - return redirect(reverse('cotisations:index-article')) - return form({ - 'factureform': article, - 'action_name': _('Edit'), - 'title': _("Edit article") - }, 'cotisations/facture.html', request) + messages.success(request, _("The article was edited.")) + return redirect(reverse("cotisations:index-article")) + return form( + {"factureform": article, "action_name": _("Edit"), "title": _("Edit article")}, + "cotisations/facture.html", + request, + ) @login_required @@ -653,18 +621,19 @@ def del_article(request, instances): """ article = DelArticleForm(request.POST or None, instances=instances) if article.is_valid(): - article_del = article.cleaned_data['articles'] + article_del = article.cleaned_data["articles"] article_del.delete() - messages.success( - request, - _("The articles were deleted.") - ) - return redirect(reverse('cotisations:index-article')) - return form({ - 'factureform': article, - 'action_name': _("Delete"), - 'title': _("Delete article") - }, 'cotisations/facture.html', request) + messages.success(request, _("The articles were deleted.")) + return redirect(reverse("cotisations:index-article")) + return form( + { + "factureform": article, + "action_name": _("Delete"), + "title": _("Delete article"), + }, + "cotisations/facture.html", + request, + ) # TODO : change paiement to payment @@ -674,26 +643,25 @@ def add_paiement(request): """ View used to add a payment method. """ - payment = PaiementForm(request.POST or None, prefix='payment') + payment = PaiementForm(request.POST or None, prefix="payment") payment_method = payment_method_factory( - payment.instance, - request.POST or None, - prefix='payment_method' + payment.instance, request.POST or None, prefix="payment_method" ) if payment.is_valid() and payment_method.is_valid(): payment = payment.save() payment_method.save(payment) - messages.success( - request, - _("The payment method was created.") - ) - return redirect(reverse('cotisations:index-paiement')) - return form({ - 'factureform': payment, - 'payment_method': payment_method, - 'action_name': _("Add"), - 'title': _("New payment method") - }, 'cotisations/facture.html', request) + messages.success(request, _("The payment method was created.")) + return redirect(reverse("cotisations:index-paiement")) + return form( + { + "factureform": payment, + "payment_method": payment_method, + "action_name": _("Add"), + "title": _("New payment method"), + }, + "cotisations/facture.html", + request, + ) # TODO : chnage paiement to Payment @@ -704,32 +672,28 @@ def edit_paiement(request, paiement_instance, **_kwargs): View used to edit a payment method. """ payment = PaiementForm( - request.POST or None, - instance=paiement_instance, - prefix="payment" + request.POST or None, instance=paiement_instance, prefix="payment" ) payment_method = payment_method_factory( - paiement_instance, - request.POST or None, - prefix='payment_method', - creation=False + paiement_instance, request.POST or None, prefix="payment_method", creation=False ) - if payment.is_valid() and \ - (payment_method is None or payment_method.is_valid()): + if payment.is_valid() and (payment_method is None or payment_method.is_valid()): payment.save() if payment_method is not None: payment_method.save() - messages.success( - request, _("The payment method was edited.") - ) - return redirect(reverse('cotisations:index-paiement')) - return form({ - 'factureform': payment, - 'payment_method': payment_method, - 'action_name': _("Edit"), - 'title': _("Edit payment method") - }, 'cotisations/facture.html', request) + messages.success(request, _("The payment method was edited.")) + return redirect(reverse("cotisations:index-paiement")) + return form( + { + "factureform": payment, + "payment_method": payment_method, + "action_name": _("Edit"), + "title": _("Edit payment method"), + }, + "cotisations/facture.html", + request, + ) # TODO : change paiement to payment @@ -741,30 +705,34 @@ def del_paiement(request, instances): """ payment = DelPaiementForm(request.POST or None, instances=instances) if payment.is_valid(): - payment_dels = payment.cleaned_data['paiements'] + payment_dels = payment.cleaned_data["paiements"] for payment_del in payment_dels: try: payment_del.delete() messages.success( request, - _("The payment method %(method_name)s was deleted.") % { - 'method_name': payment_del - } + _("The payment method %(method_name)s was deleted.") + % {"method_name": payment_del}, ) except ProtectedError: messages.error( request, - _("The payment method %(method_name)s can't be deleted \ - because there are invoices using it.") % { - 'method_name': payment_del - } + _( + "The payment method %(method_name)s can't be deleted \ + because there are invoices using it." + ) + % {"method_name": payment_del}, ) - return redirect(reverse('cotisations:index-paiement')) - return form({ - 'factureform': payment, - 'action_name': _("Delete"), - 'title': _("Delete payment method") - }, 'cotisations/facture.html', request) + return redirect(reverse("cotisations:index-paiement")) + return form( + { + "factureform": payment, + "action_name": _("Delete"), + "title": _("Delete payment method"), + }, + "cotisations/facture.html", + request, + ) # TODO : change banque to bank @@ -777,16 +745,13 @@ def add_banque(request): bank = BanqueForm(request.POST or None) if bank.is_valid(): bank.save() - messages.success( - request, - _("The bank was created.") - ) - return redirect(reverse('cotisations:index-banque')) - return form({ - 'factureform': bank, - 'action_name': _("Add"), - 'title': _("New bank") - }, 'cotisations/facture.html', request) + messages.success(request, _("The bank was created.")) + return redirect(reverse("cotisations:index-banque")) + return form( + {"factureform": bank, "action_name": _("Add"), "title": _("New bank")}, + "cotisations/facture.html", + request, + ) # TODO : change banque to bank @@ -800,16 +765,13 @@ def edit_banque(request, banque_instance, **_kwargs): if bank.is_valid(): if bank.changed_data: bank.save() - messages.success( - request, - _("The bank was edited.") - ) - return redirect(reverse('cotisations:index-banque')) - return form({ - 'factureform': bank, - 'action_name': _("Edit"), - 'title': _("Edit bank") - }, 'cotisations/facture.html', request) + messages.success(request, _("The bank was edited.")) + return redirect(reverse("cotisations:index-banque")) + return form( + {"factureform": bank, "action_name": _("Edit"), "title": _("Edit bank")}, + "cotisations/facture.html", + request, + ) # TODO : chnage banque to bank @@ -821,71 +783,66 @@ def del_banque(request, instances): """ bank = DelBanqueForm(request.POST or None, instances=instances) if bank.is_valid(): - bank_dels = bank.cleaned_data['banques'] + bank_dels = bank.cleaned_data["banques"] for bank_del in bank_dels: try: bank_del.delete() messages.success( request, - _("The bank %(bank_name)s was deleted.") % { - 'bank_name': bank_del - } + _("The bank %(bank_name)s was deleted.") % {"bank_name": bank_del}, ) except ProtectedError: messages.error( request, - _("The bank %(bank_name)s can't be deleted because there" - " are invoices using it.") % { - 'bank_name': bank_del - } + _( + "The bank %(bank_name)s can't be deleted because there" + " are invoices using it." + ) + % {"bank_name": bank_del}, ) - return redirect(reverse('cotisations:index-banque')) - return form({ - 'factureform': bank, - 'action_name': _("Delete"), - 'title': _("Delete bank") - }, 'cotisations/facture.html', request) + return redirect(reverse("cotisations:index-banque")) + return form( + {"factureform": bank, "action_name": _("Delete"), "title": _("Delete bank")}, + "cotisations/facture.html", + request, + ) # TODO : change facture to invoice @login_required @can_view_all(Facture) -@can_change(Facture, 'control') +@can_change(Facture, "control") def control(request): """ View used to control the invoices all at once. """ - pagination_number = GeneralOption.get_cached_value('pagination_number') - invoice_list = (Facture.objects.select_related('user'). - select_related('paiement')) + pagination_number = GeneralOption.get_cached_value("pagination_number") + invoice_list = Facture.objects.select_related("user").select_related("paiement") invoice_list = SortTable.sort( invoice_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.COTISATIONS_CONTROL + request.GET.get("col"), + request.GET.get("order"), + SortTable.COTISATIONS_CONTROL, ) control_invoices_formset = modelformset_factory( - Facture, - fields=('control', 'valid'), - extra=0 + Facture, fields=("control", "valid"), extra=0 ) invoice_list = re2o_paginator(request, invoice_list, pagination_number) control_invoices_form = control_invoices_formset( - request.POST or None, - queryset=invoice_list.object_list + request.POST or None, queryset=invoice_list.object_list ) if control_invoices_form.is_valid(): control_invoices_form.save() reversion.set_comment("Controle") messages.success( - request, - _("Your changes have been properly taken into account.") + request, _("Your changes have been properly taken into account.") ) - return redirect(reverse('cotisations:control')) - return render(request, 'cotisations/control.html', { - 'facture_list': invoice_list, - 'controlform': control_invoices_form - }) + return redirect(reverse("cotisations:control")) + return render( + request, + "cotisations/control.html", + {"facture_list": invoice_list, "controlform": control_invoices_form}, + ) @login_required @@ -895,10 +852,10 @@ def index_article(request): View used to display the list of all available articles. """ # TODO : Offer other means of sorting - article_list = Article.objects.order_by('name') - return render(request, 'cotisations/index_article.html', { - 'article_list': article_list - }) + article_list = Article.objects.order_by("name") + return render( + request, "cotisations/index_article.html", {"article_list": article_list} + ) # TODO : change paiement to payment @@ -908,10 +865,10 @@ def index_paiement(request): """ View used to display the list of all available payment methods. """ - payment_list = Paiement.objects.order_by('moyen') - return render(request, 'cotisations/index_paiement.html', { - 'paiement_list': payment_list - }) + payment_list = Paiement.objects.order_by("moyen") + return render( + request, "cotisations/index_paiement.html", {"paiement_list": payment_list} + ) # TODO : change banque to bank @@ -921,56 +878,53 @@ def index_banque(request): """ View used to display the list of all available banks. """ - bank_list = Banque.objects.order_by('name') - return render(request, 'cotisations/index_banque.html', { - 'banque_list': bank_list - }) + bank_list = Banque.objects.order_by("name") + return render(request, "cotisations/index_banque.html", {"banque_list": bank_list}) @login_required @can_view_all(CustomInvoice) def index_cost_estimate(request): """View used to display every custom invoice.""" - pagination_number = GeneralOption.get_cached_value('pagination_number') - cost_estimate_list = CostEstimate.objects.prefetch_related('vente_set') + pagination_number = GeneralOption.get_cached_value("pagination_number") + cost_estimate_list = CostEstimate.objects.prefetch_related("vente_set") cost_estimate_list = SortTable.sort( cost_estimate_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.COTISATIONS_CUSTOM + request.GET.get("col"), + request.GET.get("order"), + SortTable.COTISATIONS_CUSTOM, ) - cost_estimate_list = re2o_paginator( + cost_estimate_list = re2o_paginator(request, cost_estimate_list, pagination_number) + return render( request, - cost_estimate_list, - pagination_number, + "cotisations/index_cost_estimate.html", + {"cost_estimate_list": cost_estimate_list}, ) - return render(request, 'cotisations/index_cost_estimate.html', { - 'cost_estimate_list': cost_estimate_list - }) @login_required @can_view_all(CustomInvoice) def index_custom_invoice(request): """View used to display every custom invoice.""" - pagination_number = GeneralOption.get_cached_value('pagination_number') - cost_estimate_ids = [i for i, in CostEstimate.objects.values_list('id')] - custom_invoice_list = CustomInvoice.objects.prefetch_related( - 'vente_set').exclude(id__in=cost_estimate_ids) + pagination_number = GeneralOption.get_cached_value("pagination_number") + cost_estimate_ids = [i for i, in CostEstimate.objects.values_list("id")] + custom_invoice_list = CustomInvoice.objects.prefetch_related("vente_set").exclude( + id__in=cost_estimate_ids + ) custom_invoice_list = SortTable.sort( custom_invoice_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.COTISATIONS_CUSTOM + request.GET.get("col"), + request.GET.get("order"), + SortTable.COTISATIONS_CUSTOM, ) custom_invoice_list = re2o_paginator( - request, - custom_invoice_list, - pagination_number, + request, custom_invoice_list, pagination_number + ) + return render( + request, + "cotisations/index_custom_invoice.html", + {"custom_invoice_list": custom_invoice_list}, ) - return render(request, 'cotisations/index_custom_invoice.html', { - 'custom_invoice_list': custom_invoice_list - }) @login_required @@ -980,19 +934,20 @@ def index(request): """ View used to display the list of all exisitng invoices. """ - pagination_number = GeneralOption.get_cached_value('pagination_number') - invoice_list = Facture.objects.select_related('user')\ - .select_related('paiement').prefetch_related('vente_set') + pagination_number = GeneralOption.get_cached_value("pagination_number") + invoice_list = ( + Facture.objects.select_related("user") + .select_related("paiement") + .prefetch_related("vente_set") + ) invoice_list = SortTable.sort( invoice_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.COTISATIONS_INDEX + request.GET.get("col"), + request.GET.get("order"), + SortTable.COTISATIONS_INDEX, ) invoice_list = re2o_paginator(request, invoice_list, pagination_number) - return render(request, 'cotisations/index.html', { - 'facture_list': invoice_list, - }) + return render(request, "cotisations/index.html", {"facture_list": invoice_list}) # TODO : change solde to balance @@ -1008,28 +963,22 @@ def credit_solde(request, user, **_kwargs): except Paiement.DoesNotExist: credit_allowed = False else: - credit_allowed = ( - balance is not None - and balance.can_credit_balance(request.user) + credit_allowed = balance is not None and balance.can_credit_balance( + request.user ) if not credit_allowed: - messages.error( - request, - _("You are not allowed to credit your balance.") - ) - return redirect(reverse( - 'users:profil', - kwargs={'userid': user.id} - )) + messages.error(request, _("You are not allowed to credit your balance.")) + return redirect(reverse("users:profil", kwargs={"userid": user.id})) refill_form = RechargeForm( - request.POST or None, user=user, user_source=request.user) + request.POST or None, user=user, user_source=request.user + ) if refill_form.is_valid(): - price = refill_form.cleaned_data['value'] + price = refill_form.cleaned_data["value"] invoice = Facture(user=user) - invoice.paiement = refill_form.cleaned_data['payment'] + invoice.paiement = refill_form.cleaned_data["payment"] p = find_payment_method(invoice.paiement) - if hasattr(p, 'check_price'): + if hasattr(p, "check_price"): price_ok, msg = p.check_price(price, user) refill_form.add_error(None, msg) else: @@ -1038,20 +987,24 @@ def credit_solde(request, user, **_kwargs): invoice.save() Vente.objects.create( facture=invoice, - name='solde', - prix=refill_form.cleaned_data['value'], - number=1 + name="solde", + prix=refill_form.cleaned_data["value"], + number=1, ) return invoice.paiement.end_payment(invoice, request) p = get_object_or_404(Paiement, is_balance=True) - return form({ - 'factureform': refill_form, - 'balance': user.solde, - 'title': _("Refill your balance"), - 'action_name': _("Pay"), - 'max_balance': find_payment_method(p).maximum_balance, - }, 'cotisations/facture.html', request) + return form( + { + "factureform": refill_form, + "balance": user.solde, + "title": _("Refill your balance"), + "action_name": _("Pay"), + "max_balance": find_payment_method(p).maximum_balance, + }, + "cotisations/facture.html", + request, + ) @login_required @@ -1064,19 +1017,19 @@ def voucher_pdf(request, invoice, **_kwargs): legal information for the user. """ if not invoice.control: - messages.error( - request, - _("Could not find a voucher for that invoice.") - ) - return redirect(reverse('cotisations:index')) + messages.error(request, _("Could not find a voucher for that invoice.")) + return redirect(reverse("cotisations:index")) president = Mandate.get_mandate(invoice.date).president - return render_voucher(request, { - 'asso_name': AssoOption.get_cached_value('name'), - 'pres_name': ' '.join([president.name, president.surname]), - 'firstname': invoice.user.name, - 'lastname': invoice.user.surname, - 'email': invoice.user.email, - 'phone': invoice.user.telephone, - 'date_end': invoice.get_subscription().latest('date_end').date_end, - 'date_begin': invoice.date - }) + return render_voucher( + request, + { + "asso_name": AssoOption.get_cached_value("name"), + "pres_name": " ".join([president.name, president.surname]), + "firstname": invoice.user.name, + "lastname": invoice.user.surname, + "email": invoice.user.email, + "phone": invoice.user.telephone, + "date_end": invoice.get_subscription().latest("date_end").date_end, + "date_begin": invoice.date, + }, + ) diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index 212ada1e..496f2f3f 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -62,7 +62,7 @@ from preferences.models import RadiusOption #: Serveur radius de test (pas la prod) -TEST_SERVER = bool(os.getenv('DBG_FREERADIUS', False)) +TEST_SERVER = bool(os.getenv("DBG_FREERADIUS", False)) # Logging @@ -77,13 +77,13 @@ class RadiusdHandler(logging.Handler): rad_sig = radiusd.L_INFO else: rad_sig = radiusd.L_DBG - radiusd.radlog(rad_sig, record.msg.encode('utf-8')) + radiusd.radlog(rad_sig, record.msg.encode("utf-8")) # Initialisation d'un logger (pour logguer unifié) -logger = logging.getLogger('auth.py') +logger = logging.getLogger("auth.py") logger.setLevel(logging.DEBUG) -formatter = logging.Formatter('%(name)s: [%(levelname)s] %(message)s') +formatter = logging.Formatter("%(name)s: [%(levelname)s] %(message)s") handler = RadiusdHandler() handler.setFormatter(formatter) logger.addHandler(handler) @@ -111,17 +111,16 @@ def radius_event(fun): for (key, value) in auth_data or []: # Beware: les valeurs scalaires sont entre guillemets # Ex: Calling-Station-Id: "une_adresse_mac" - data[key] = value.replace('"', '') + data[key] = value.replace('"', "") try: # TODO s'assurer ici que les tuples renvoyés sont bien des # (str,str) : rlm_python ne digère PAS les unicodes return fun(data) except Exception as err: exc_type, exc_instance, exc_traceback = sys.exc_info() - formatted_traceback = ''.join(traceback.format_tb( - exc_traceback)) - logger.error('Failed %r on data %r' % (err, auth_data)) - logger.error('Function %r, Traceback : %r' % (fun, formatted_traceback)) + formatted_traceback = "".join(traceback.format_tb(exc_traceback)) + logger.error("Failed %r on data %r" % (err, auth_data)) + logger.error("Function %r, Traceback : %r" % (fun, formatted_traceback)) return radiusd.RLM_MODULE_FAIL return new_f @@ -131,9 +130,9 @@ def radius_event(fun): def instantiate(*_): """Utile pour initialiser les connexions ldap une première fois (otherwise, do nothing)""" - logger.info('Instantiation') + logger.info("Instantiation") if TEST_SERVER: - logger.info(u'DBG_FREERADIUS is enabled') + logger.info(u"DBG_FREERADIUS is enabled") @radius_event @@ -146,23 +145,19 @@ def authorize(data): accept en authorize """ # Pour les requetes proxifiees, on split - nas = data.get('NAS-IP-Address', data.get('NAS-Identifier', None)) + nas = data.get("NAS-IP-Address", data.get("NAS-Identifier", None)) nas_instance = find_nas_from_request(nas) # Toutes les reuquètes non proxifiées nas_type = None if nas_instance: nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first() - if not nas_type or nas_type.port_access_mode == '802.1X': - user = data.get('User-Name', '').decode('utf-8', errors='replace') - user = user.split('@', 1)[0] - mac = data.get('Calling-Station-Id', '') - result, log, password = check_user_machine_and_register( - nas_type, - user, - mac - ) - logger.info(log.encode('utf-8')) - logger.info(user.encode('utf-8')) + if not nas_type or nas_type.port_access_mode == "802.1X": + user = data.get("User-Name", "").decode("utf-8", errors="replace") + user = user.split("@", 1)[0] + mac = data.get("Calling-Station-Id", "") + result, log, password = check_user_machine_and_register(nas_type, user, mac) + logger.info(log.encode("utf-8")) + logger.info(user.encode("utf-8")) if not result: return radiusd.RLM_MODULE_REJECT @@ -170,19 +165,11 @@ def authorize(data): return ( radiusd.RLM_MODULE_UPDATED, (), - ( - (str("NT-Password"), str(password)), - ), + ((str("NT-Password"), str(password)),), ) else: - return ( - radiusd.RLM_MODULE_UPDATED, - (), - ( - ("Auth-Type", "Accept"), - ), - ) + return (radiusd.RLM_MODULE_UPDATED, (), (("Auth-Type", "Accept"),)) @radius_event @@ -190,52 +177,49 @@ def post_auth(data): """ Function called after the user is authenticated """ - nas = data.get('NAS-IP-Address', data.get('NAS-Identifier', None)) + nas = data.get("NAS-IP-Address", data.get("NAS-Identifier", None)) nas_instance = find_nas_from_request(nas) # Toutes les reuquètes non proxifiées if not nas_instance: - logger.info(u"Requete proxifiee, nas inconnu".encode('utf-8')) + logger.info(u"Requete proxifiee, nas inconnu".encode("utf-8")) return radiusd.RLM_MODULE_OK nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first() if not nas_type: - logger.info( - u"Type de nas non enregistre dans la bdd!".encode('utf-8') - ) + logger.info(u"Type de nas non enregistre dans la bdd!".encode("utf-8")) return radiusd.RLM_MODULE_OK - mac = data.get('Calling-Station-Id', None) + mac = data.get("Calling-Station-Id", None) # Switch et bornes héritent de machine et peuvent avoir plusieurs # interfaces filles nas_machine = nas_instance.machine # Si il s'agit d'un switch - if hasattr(nas_machine, 'switch'): - port = data.get('NAS-Port-Id', data.get('NAS-Port', None)) + if hasattr(nas_machine, "switch"): + port = data.get("NAS-Port-Id", data.get("NAS-Port", None)) # Pour les infrastructures possédant des switchs Juniper : # On vérifie si le switch fait partie d'un stack Juniper instance_stack = nas_machine.switch.stack if instance_stack: # Si c'est le cas, on resélectionne le bon switch dans la stack - id_stack_member = port.split("-")[1].split('/')[0] - nas_machine = (Switch.objects - .filter(stack=instance_stack) - .filter(stack_member_id=id_stack_member) - .prefetch_related( - 'interface_set__domain__extension' - ) - .first()) + id_stack_member = port.split("-")[1].split("/")[0] + nas_machine = ( + Switch.objects.filter(stack=instance_stack) + .filter(stack_member_id=id_stack_member) + .prefetch_related("interface_set__domain__extension") + .first() + ) # On récupère le numéro du port sur l'output de freeradius. # La ligne suivante fonctionne pour cisco, HP et Juniper - port = port.split(".")[0].split('/')[-1][-2:] + port = port.split(".")[0].split("/")[-1][-2:] out = decide_vlan_switch(nas_machine, nas_type, port, mac) sw_name, room, reason, vlan_id, decision, attributes = out if decision: - log_message = '(fil) %s -> %s [%s%s]' % ( + log_message = "(fil) %s -> %s [%s%s]" % ( sw_name + u":" + port + u"/" + str(room), mac, vlan_id, - (reason and u': ' + reason).encode('utf-8') + (reason and u": " + reason).encode("utf-8"), ) logger.info(log_message) @@ -245,23 +229,20 @@ def post_auth(data): ( ("Tunnel-Type", "VLAN"), ("Tunnel-Medium-Type", "IEEE-802"), - ("Tunnel-Private-Group-Id", '%d' % int(vlan_id)), - ) + tuple(attributes), - () + ("Tunnel-Private-Group-Id", "%d" % int(vlan_id)), + ) + + tuple(attributes), + (), ) else: - log_message = '(fil) %s -> %s [Reject:%s]' % ( + log_message = "(fil) %s -> %s [Reject:%s]" % ( sw_name + u":" + port + u"/" + str(room), mac, - (reason and u': ' + reason).encode('utf-8') + (reason and u": " + reason).encode("utf-8"), ) logger.info(log_message) - return ( - radiusd.RLM_MODULE_REJECT, - tuple(attributes), - () - ) + return (radiusd.RLM_MODULE_REJECT, tuple(attributes), ()) else: return radiusd.RLM_MODULE_OK @@ -282,13 +263,14 @@ def detach(_=None): def find_nas_from_request(nas_id): """ Get the nas object from its ID """ - nas = (Interface.objects - .filter( - Q(domain=Domain.objects.filter(name=nas_id)) | - Q(ipv4=IpList.objects.filter(ipv4=nas_id)) - ) - .select_related('machine_type') - .select_related('machine__switch__stack')) + nas = ( + Interface.objects.filter( + Q(domain=Domain.objects.filter(name=nas_id)) + | Q(ipv4=IpList.objects.filter(ipv4=nas_id)) + ) + .select_related("machine_type") + .select_related("machine__switch__stack") + ) return nas.first() @@ -300,17 +282,18 @@ def check_user_machine_and_register(nas_type, username, mac_address): interface = Interface.objects.filter(mac_address=mac_address).first() user = User.objects.filter(pseudo__iexact=username).first() if not user: - return (False, u"User inconnu", '') + return (False, u"User inconnu", "") if not user.has_access(): - return (False, u"Adherent non cotisant", '') + return (False, u"Adherent non cotisant", "") if interface: if interface.machine.user != user: - return (False, - u"Machine enregistree sur le compte d'un autre " - "user...", - '') + return ( + False, + u"Machine enregistree sur le compte d'un autre " "user...", + "", + ) elif not interface.is_active: - return (False, u"Machine desactivee", '') + return (False, u"Machine desactivee", "") elif not interface.ipv4: interface.assign_ipv4() return (True, u"Ok, Reassignation de l'ipv4", user.pwd_ntlm) @@ -320,19 +303,16 @@ def check_user_machine_and_register(nas_type, username, mac_address): if nas_type.autocapture_mac: result, reason = user.autoregister_machine(mac_address, nas_type) if result: - return (True, - u'Access Ok, Capture de la mac...', - user.pwd_ntlm) + return (True, u"Access Ok, Capture de la mac...", user.pwd_ntlm) else: - return (False, u'Erreur dans le register mac %s' % reason, '') + return (False, u"Erreur dans le register mac %s" % reason, "") else: - return (False, u'Machine inconnue', '') + return (False, u"Machine inconnue", "") else: - return (False, u"Machine inconnue", '') + return (False, u"Machine inconnue", "") -def decide_vlan_switch(nas_machine, nas_type, port_number, - mac_address): +def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address): """Fonction de placement vlan pour un switch en radius filaire auth par mac. Plusieurs modes : @@ -373,32 +353,27 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, - Attributs supplémentaires (attribut:str, operateur:str, valeur:str) """ attributes_kwargs = { - 'client_mac' : str(mac_address), - 'switch_port' : str(port_number), + "client_mac": str(mac_address), + "switch_port": str(port_number), } # Get port from switch and port number extra_log = "" # Si le NAS est inconnu, on place sur le vlan defaut if not nas_machine: return ( - '?', - u'Chambre inconnue', - u'Nas inconnu', - RadiusOption.get_cached_value('vlan_decision_ok').vlan_id, + "?", + u"Chambre inconnue", + u"Nas inconnu", + RadiusOption.get_cached_value("vlan_decision_ok").vlan_id, True, - RadiusOption.get_attributes('ok_attributes', attributes_kwargs) + RadiusOption.get_attributes("ok_attributes", attributes_kwargs), ) - sw_name = str(getattr(nas_machine, 'short_name', str(nas_machine))) + sw_name = str(getattr(nas_machine, "short_name", str(nas_machine))) switch = Switch.objects.filter(machine_ptr=nas_machine).first() - attributes_kwargs['switch_ip'] = str(switch.ipv4) - port = (Port.objects - .filter( - switch=switch, - port=port_number - ) - .first()) + attributes_kwargs["switch_ip"] = str(switch.ipv4) + port = Port.objects.filter(switch=switch, port=port_number).first() # Si le port est inconnu, on place sur le vlan defaut # Aucune information particulière ne permet de déterminer quelle @@ -407,10 +382,12 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, return ( sw_name, "Port inconnu", - u'Port inconnu', - getattr(RadiusOption.get_cached_value('unknown_port_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('unknown_port')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_port_attributes', attributes_kwargs) + u"Port inconnu", + getattr( + RadiusOption.get_cached_value("unknown_port_vlan"), "vlan_id", None + ), + RadiusOption.get_cached_value("unknown_port") != RadiusOption.REJECT, + RadiusOption.get_attributes("unknown_port_attributes", attributes_kwargs), ) # On récupère le profil du port @@ -423,35 +400,36 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, extra_log = u"Force sur vlan " + str(DECISION_VLAN) attributes = () else: - DECISION_VLAN = RadiusOption.get_cached_value('vlan_decision_ok').vlan_id - attributes = RadiusOption.get_attributes('ok_attributes', attributes_kwargs) + DECISION_VLAN = RadiusOption.get_cached_value("vlan_decision_ok").vlan_id + attributes = RadiusOption.get_attributes("ok_attributes", attributes_kwargs) # Si le port est désactivé, on rejette la connexion if not port.state: - return (sw_name, port.room, u'Port desactive', None, False, ()) + return (sw_name, port.room, u"Port desactive", None, False, ()) # Si radius est désactivé, on laisse passer - if port_profile.radius_type == 'NO': - return (sw_name, - "", - u"Pas d'authentification sur ce port" + extra_log, - DECISION_VLAN, - True, - attributes - ) + if port_profile.radius_type == "NO": + return ( + sw_name, + "", + u"Pas d'authentification sur ce port" + extra_log, + DECISION_VLAN, + True, + attributes, + ) # Si le 802.1X est activé sur ce port, cela veut dire que la personne a # été accept précédemment # Par conséquent, on laisse passer sur le bon vlan - if (nas_type.port_access_mode, port_profile.radius_type) == ('802.1X', '802.1X'): + if (nas_type.port_access_mode, port_profile.radius_type) == ("802.1X", "802.1X"): room = port.room or "Chambre/local inconnu" return ( sw_name, room, - u'Acceptation authentification 802.1X', + u"Acceptation authentification 802.1X", DECISION_VLAN, True, - attributes + attributes, ) # Sinon, cela veut dire qu'on fait de l'auth radius par mac @@ -460,16 +438,20 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, # (anti squattage) # Il n'est pas possible de se connecter sur une prise strict sans adhérent # à jour de cotis dedans - if port_profile.radius_mode == 'STRICT': + if port_profile.radius_mode == "STRICT": room = port.room if not room: return ( sw_name, "Inconnue", - u'Chambre inconnue', - getattr(RadiusOption.get_cached_value('unknown_room_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('unknown_room')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_room_attributes', attributes_kwargs), + u"Chambre inconnue", + getattr( + RadiusOption.get_cached_value("unknown_room_vlan"), "vlan_id", None + ), + RadiusOption.get_cached_value("unknown_room") != RadiusOption.REJECT, + RadiusOption.get_attributes( + "unknown_room_attributes", attributes_kwargs + ), ) room_user = User.objects.filter( @@ -479,41 +461,52 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, return ( sw_name, room, - u'Chambre non cotisante', - getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, - RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), + u"Chambre non cotisante", + getattr( + RadiusOption.get_cached_value("non_member_vlan"), "vlan_id", None + ), + RadiusOption.get_cached_value("non_member") != RadiusOption.REJECT, + RadiusOption.get_attributes("non_member_attributes", attributes_kwargs), ) for user in room_user: if user.is_ban() or user.state != User.STATE_ACTIVE: return ( sw_name, room, - u'Utilisateur banni ou desactive', - getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT, - RadiusOption.get_attributes('banned_attributes', attributes_kwargs), + u"Utilisateur banni ou desactive", + getattr( + RadiusOption.get_cached_value("banned_vlan"), "vlan_id", None + ), + RadiusOption.get_cached_value("banned") != RadiusOption.REJECT, + RadiusOption.get_attributes("banned_attributes", attributes_kwargs), ) elif not (user.is_connected() or user.is_whitelisted()): return ( sw_name, room, - u'Utilisateur non cotisant', - getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, - RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), + u"Utilisateur non cotisant", + getattr( + RadiusOption.get_cached_value("non_member_vlan"), + "vlan_id", + None, + ), + RadiusOption.get_cached_value("non_member") != RadiusOption.REJECT, + RadiusOption.get_attributes( + "non_member_attributes", attributes_kwargs + ), ) # else: user OK, on passe à la verif MAC # Si on fait de l'auth par mac, on cherche l'interface # via sa mac dans la bdd - if port_profile.radius_mode == 'COMMON' or port_profile.radius_mode == 'STRICT': + if port_profile.radius_mode == "COMMON" or port_profile.radius_mode == "STRICT": # Authentification par mac - interface = (Interface.objects - .filter(mac_address=mac_address) - .select_related('machine__user') - .select_related('ipv4') - .first()) + interface = ( + Interface.objects.filter(mac_address=mac_address) + .select_related("machine__user") + .select_related("ipv4") + .first() + ) if not interface: room = port.room # On essaye de register la mac, si l'autocapture a été activée, @@ -522,10 +515,17 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, return ( sw_name, room, - u'Machine Inconnue', - getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_machine_attributes', attributes_kwargs), + u"Machine Inconnue", + getattr( + RadiusOption.get_cached_value("unknown_machine_vlan"), + "vlan_id", + None, + ), + RadiusOption.get_cached_value("unknown_machine") + != RadiusOption.REJECT, + RadiusOption.get_attributes( + "unknown_machine_attributes", attributes_kwargs + ), ) # Sinon on bascule sur la politique définie dans les options # radius. @@ -533,10 +533,17 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, return ( sw_name, "", - u'Machine inconnue', - getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_machine_attributes', attributes_kwargs), + u"Machine inconnue", + getattr( + RadiusOption.get_cached_value("unknown_machine_vlan"), + "vlan_id", + None, + ), + RadiusOption.get_cached_value("unknown_machine") + != RadiusOption.REJECT, + RadiusOption.get_attributes( + "unknown_machine_attributes", attributes_kwargs + ), ) # L'interface a été trouvée, on vérifie qu'elle est active, @@ -549,23 +556,31 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, return ( sw_name, room, - u'Adherent banni', - getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT, - RadiusOption.get_attributes('banned_attributes', attributes_kwargs), + u"Adherent banni", + getattr( + RadiusOption.get_cached_value("banned_vlan"), "vlan_id", None + ), + RadiusOption.get_cached_value("banned") != RadiusOption.REJECT, + RadiusOption.get_attributes("banned_attributes", attributes_kwargs), ) if not interface.is_active: return ( sw_name, room, - u'Machine non active / adherent non cotisant', - getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), - RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, - RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), + u"Machine non active / adherent non cotisant", + getattr( + RadiusOption.get_cached_value("non_member_vlan"), + "vlan_id", + None, + ), + RadiusOption.get_cached_value("non_member") != RadiusOption.REJECT, + RadiusOption.get_attributes( + "non_member_attributes", attributes_kwargs + ), ) # Si on choisi de placer les machines sur le vlan # correspondant à leur type : - if RadiusOption.get_cached_value('radius_general_policy') == 'MACHINE': + if RadiusOption.get_cached_value("radius_general_policy") == "MACHINE": DECISION_VLAN = interface.machine_type.ip_type.vlan.vlan_id if not interface.ipv4: interface.assign_ipv4() @@ -575,14 +590,14 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u"Ok, Reassignation de l'ipv4" + extra_log, DECISION_VLAN, True, - attributes + attributes, ) else: return ( sw_name, room, - u'Machine OK' + extra_log, + u"Machine OK" + extra_log, DECISION_VLAN, True, - attributes + attributes, ) diff --git a/logs/acl.py b/logs/acl.py index 7c68add1..f6be8183 100644 --- a/logs/acl.py +++ b/logs/acl.py @@ -38,11 +38,9 @@ def can_view(user): A couple (allowed, msg) where allowed is a boolean which is True if viewing is granted and msg is a message (can be None). """ - can = user.has_module_perms('admin') + can = user.has_module_perms("admin") return ( can, - None if can else _("You don't have the right to view this" - " application."), - 'admin' + None if can else _("You don't have the right to view this" " application."), + "admin", ) - diff --git a/logs/templatetags/logs_extra.py b/logs/templatetags/logs_extra.py index 8aba7563..c436c1fa 100644 --- a/logs/templatetags/logs_extra.py +++ b/logs/templatetags/logs_extra.py @@ -34,12 +34,14 @@ def classname(obj): """ Returns the object class name """ return obj.__class__.__name__ + @register.filter def is_facture(baseinvoice): """Returns True if a baseinvoice has a `Facture` child.""" - return hasattr(baseinvoice, 'facture') + return hasattr(baseinvoice, "facture") -@register.inclusion_tag('buttons/history.html') + +@register.inclusion_tag("buttons/history.html") def history_button(instance, text=False, html_class=True): """Creates the correct history button for an instance. @@ -51,9 +53,9 @@ def history_button(instance, text=False, html_class=True): """ return { - 'application': instance._meta.app_label, - 'name': instance._meta.model_name, - 'id': instance.id, - 'text': text, - 'class': html_class, + "application": instance._meta.app_label, + "name": instance._meta.model_name, + "id": instance.id, + "text": text, + "class": html_class, } diff --git a/logs/urls.py b/logs/urls.py index 7496b50a..8fa0f469 100644 --- a/logs/urls.py +++ b/logs/urls.py @@ -30,18 +30,20 @@ from django.conf.urls import url from . import views urlpatterns = [ - url(r'^$', views.index, name='index'), - url(r'^stats_logs$', views.stats_logs, name='stats-logs'), - url(r'^revert_action/(?P[0-9]+)$', - views.revert_action, - name='revert-action'), - url(r'^stats_general/$', views.stats_general, name='stats-general'), - url(r'^stats_models/$', views.stats_models, name='stats-models'), - url(r'^stats_users/$', views.stats_users, name='stats-users'), - url(r'^stats_actions/$', views.stats_actions, name='stats-actions'), + url(r"^$", views.index, name="index"), + url(r"^stats_logs$", views.stats_logs, name="stats-logs"), url( - r'(?P\w+)/(?P\w+)/(?P[0-9]+)$', + r"^revert_action/(?P[0-9]+)$", + views.revert_action, + name="revert-action", + ), + url(r"^stats_general/$", views.stats_general, name="stats-general"), + url(r"^stats_models/$", views.stats_models, name="stats-models"), + url(r"^stats_users/$", views.stats_users, name="stats-users"), + url(r"^stats_actions/$", views.stats_actions, name="stats-actions"), + url( + r"(?P\w+)/(?P\w+)/(?P[0-9]+)$", views.history, - name='history', + name="history", ), ] diff --git a/logs/views.py b/logs/views.py index 9e4629a4..be71f7cc 100644 --- a/logs/views.py +++ b/logs/views.py @@ -60,16 +60,9 @@ from users.models import ( Ban, Whitelist, Adherent, - Club -) -from cotisations.models import ( - Facture, - Vente, - Article, - Banque, - Paiement, - Cotisation + Club, ) +from cotisations.models import Facture, Vente, Article, Banque, Paiement, Cotisation from machines.models import ( Machine, MachineType, @@ -84,7 +77,7 @@ from machines.models import ( Nas, SOA, Mx, - Ns + Ns, ) from topologie.models import ( Switch, @@ -93,7 +86,7 @@ from topologie.models import ( Stack, ModelSwitch, ConstructorSwitch, - AccessPoint + AccessPoint, ) from preferences.models import GeneralOption from re2o.views import form @@ -105,36 +98,24 @@ from re2o.utils import ( all_active_assigned_interfaces_count, all_active_interfaces_count, ) -from re2o.base import ( - re2o_paginator, - SortTable -) -from re2o.acl import ( - can_view_all, - can_view_app, - can_edit_history, -) +from re2o.base import re2o_paginator, SortTable +from re2o.acl import can_view_all, can_view_app, can_edit_history @login_required -@can_view_app('logs') +@can_view_app("logs") def index(request): """Affiche les logs affinés, date reformatées, selectionne les event importants (ajout de droits, ajout de ban/whitelist)""" - pagination_number = GeneralOption.get_cached_value('pagination_number') + pagination_number = GeneralOption.get_cached_value("pagination_number") # The types of content kept for display - content_type_filter = ['ban', 'whitelist', 'vente', 'interface', 'user'] + content_type_filter = ["ban", "whitelist", "vente", "interface", "user"] # Select only wanted versions versions = Version.objects.filter( - content_type__in=ContentType.objects.filter( - model__in=content_type_filter - ) - ).select_related('revision') + content_type__in=ContentType.objects.filter(model__in=content_type_filter) + ).select_related("revision") versions = SortTable.sort( - versions, - request.GET.get('col'), - request.GET.get('order'), - SortTable.LOGS_INDEX + versions, request.GET.get("col"), request.GET.get("order"), SortTable.LOGS_INDEX ) versions = re2o_paginator(request, versions, pagination_number) # Force to have a list instead of QuerySet @@ -146,20 +127,21 @@ def index(request): if versions.object_list[i].object: version = versions.object_list[i] versions.object_list[i] = { - 'rev_id': version.revision.id, - 'comment': version.revision.comment, - 'datetime': version.revision.date_created, - 'username': - version.revision.user.get_username() - if version.revision.user else '?', - 'user_id': version.revision.user_id, - 'version': version} + "rev_id": version.revision.id, + "comment": version.revision.comment, + "datetime": version.revision.date_created, + "username": version.revision.user.get_username() + if version.revision.user + else "?", + "user_id": version.revision.user_id, + "version": version, + } else: to_remove.insert(0, i) # Remove all tagged invalid items for i in to_remove: versions.object_list.pop(i) - return render(request, 'logs/index.html', {'versions_list': versions}) + return render(request, "logs/index.html", {"versions_list": versions}) @login_required @@ -167,19 +149,20 @@ def index(request): def stats_logs(request): """Affiche l'ensemble des logs et des modifications sur les objets, classés par date croissante, en vrac""" - pagination_number = GeneralOption.get_cached_value('pagination_number') - revisions = Revision.objects.all().select_related('user')\ - .prefetch_related('version_set__object') + pagination_number = GeneralOption.get_cached_value("pagination_number") + revisions = ( + Revision.objects.all() + .select_related("user") + .prefetch_related("version_set__object") + ) revisions = SortTable.sort( revisions, - request.GET.get('col'), - request.GET.get('order'), - SortTable.LOGS_STATS_LOGS + request.GET.get("col"), + request.GET.get("order"), + SortTable.LOGS_STATS_LOGS, ) revisions = re2o_paginator(request, revisions, pagination_number) - return render(request, 'logs/stats_logs.html', { - 'revisions_list': revisions - }) + return render(request, "logs/stats_logs.html", {"revisions_list": revisions}) @login_required @@ -193,11 +176,12 @@ def revert_action(request, revision_id): if request.method == "POST": revision.revert() messages.success(request, _("The action was deleted.")) - return redirect(reverse('logs:index')) - return form({ - 'objet': revision, - 'objet_name': revision.__class__.__name__ - }, 'logs/delete.html', request) + return redirect(reverse("logs:index")) + return form( + {"objet": revision, "objet_name": revision.__class__.__name__}, + "logs/delete.html", + request, + ) @login_required @@ -207,226 +191,221 @@ def stats_general(request): range, et les statistiques générales sur les users : users actifs, cotisants, activés, archivés, etc""" ip_dict = dict() - for ip_range in IpType.objects.select_related('vlan').all(): + for ip_range in IpType.objects.select_related("vlan").all(): all_ip = IpList.objects.filter(ip_type=ip_range) used_ip = Interface.objects.filter(ipv4__in=all_ip).count() - active_ip = all_active_assigned_interfaces_count().filter( - ipv4__in=IpList.objects.filter(ip_type=ip_range) - ).count() - ip_dict[ip_range] = [ip_range, ip_range.vlan, all_ip.count(), - used_ip, active_ip, all_ip.count()-used_ip] + active_ip = ( + all_active_assigned_interfaces_count() + .filter(ipv4__in=IpList.objects.filter(ip_type=ip_range)) + .count() + ) + ip_dict[ip_range] = [ + ip_range, + ip_range.vlan, + all_ip.count(), + used_ip, + active_ip, + all_ip.count() - used_ip, + ] _all_adherent = all_adherent(including_asso=False) _all_has_access = all_has_access(including_asso=False) _all_baned = all_baned() _all_whitelisted = all_whitelisted() _all_active_interfaces_count = all_active_interfaces_count() - _all_active_assigned_interfaces_count = \ - all_active_assigned_interfaces_count() + _all_active_assigned_interfaces_count = all_active_assigned_interfaces_count() stats = [ - [ # First set of data (about users) - [ # Headers + [ # First set of data (about users) + [ # Headers _("Category"), _("Number of users (members and clubs)"), _("Number of members"), - _("Number of clubs") + _("Number of clubs"), ], - { # Data - 'active_users': [ + { # Data + "active_users": [ _("Activated users"), User.objects.filter(state=User.STATE_ACTIVE).count(), - (Adherent.objects - .filter(state=Adherent.STATE_ACTIVE) - .count()), - Club.objects.filter(state=Club.STATE_ACTIVE).count() + (Adherent.objects.filter(state=Adherent.STATE_ACTIVE).count()), + Club.objects.filter(state=Club.STATE_ACTIVE).count(), ], - 'inactive_users': [ + "inactive_users": [ _("Disabled users"), User.objects.filter(state=User.STATE_DISABLED).count(), - (Adherent.objects - .filter(state=Adherent.STATE_DISABLED) - .count()), - Club.objects.filter(state=Club.STATE_DISABLED).count() + (Adherent.objects.filter(state=Adherent.STATE_DISABLED).count()), + Club.objects.filter(state=Club.STATE_DISABLED).count(), ], - 'archive_users': [ + "archive_users": [ _("Archived users"), User.objects.filter(state=User.STATE_ARCHIVE).count(), - (Adherent.objects - .filter(state=Adherent.STATE_ARCHIVE) - .count()), - Club.objects.filter(state=Club.STATE_ARCHIVE).count() + (Adherent.objects.filter(state=Adherent.STATE_ARCHIVE).count()), + Club.objects.filter(state=Club.STATE_ARCHIVE).count(), ], - 'full_archive_users': [ + "full_archive_users": [ _("Full Archived users"), User.objects.filter(state=User.STATE_FULL_ARCHIVE).count(), - (Adherent.objects - .filter(state=Adherent.STATE_FULL_ARCHIVE) - .count()), - Club.objects.filter(state=Club.STATE_FULL_ARCHIVE).count() + ( + Adherent.objects.filter( + state=Adherent.STATE_FULL_ARCHIVE + ).count() + ), + Club.objects.filter(state=Club.STATE_FULL_ARCHIVE).count(), ], - 'not_active_users': [ + "not_active_users": [ _("Not yet active users"), User.objects.filter(state=User.STATE_NOT_YET_ACTIVE).count(), - (Adherent.objects - .filter(state=Adherent.STATE_NOT_YET_ACTIVE) - .count()), - Club.objects.filter(state=Club.STATE_NOT_YET_ACTIVE).count() + ( + Adherent.objects.filter( + state=Adherent.STATE_NOT_YET_ACTIVE + ).count() + ), + Club.objects.filter(state=Club.STATE_NOT_YET_ACTIVE).count(), ], - 'adherent_users': [ + "adherent_users": [ _("Contributing members"), _all_adherent.count(), _all_adherent.exclude(adherent__isnull=True).count(), - _all_adherent.exclude(club__isnull=True).count() + _all_adherent.exclude(club__isnull=True).count(), ], - 'connexion_users': [ + "connexion_users": [ _("Users benefiting from a connection"), _all_has_access.count(), _all_has_access.exclude(adherent__isnull=True).count(), - _all_has_access.exclude(club__isnull=True).count() + _all_has_access.exclude(club__isnull=True).count(), ], - 'ban_users': [ + "ban_users": [ _("Banned users"), _all_baned.count(), _all_baned.exclude(adherent__isnull=True).count(), - _all_baned.exclude(club__isnull=True).count() + _all_baned.exclude(club__isnull=True).count(), ], - 'whitelisted_user': [ + "whitelisted_user": [ _("Users benefiting from a free connection"), _all_whitelisted.count(), _all_whitelisted.exclude(adherent__isnull=True).count(), - _all_whitelisted.exclude(club__isnull=True).count() + _all_whitelisted.exclude(club__isnull=True).count(), ], - 'actives_interfaces': [ + "actives_interfaces": [ _("Active interfaces (with access to the network)"), _all_active_interfaces_count.count(), - (_all_active_interfaces_count - .exclude(machine__user__adherent__isnull=True) - .count()), - (_all_active_interfaces_count - .exclude(machine__user__club__isnull=True) - .count()) + ( + _all_active_interfaces_count.exclude( + machine__user__adherent__isnull=True + ).count() + ), + ( + _all_active_interfaces_count.exclude( + machine__user__club__isnull=True + ).count() + ), ], - 'actives_assigned_interfaces': [ + "actives_assigned_interfaces": [ _("Active interfaces assigned IPv4"), _all_active_assigned_interfaces_count.count(), - (_all_active_assigned_interfaces_count - .exclude(machine__user__adherent__isnull=True) - .count()), - (_all_active_assigned_interfaces_count - .exclude(machine__user__club__isnull=True) - .count()) - ] - } + ( + _all_active_assigned_interfaces_count.exclude( + machine__user__adherent__isnull=True + ).count() + ), + ( + _all_active_assigned_interfaces_count.exclude( + machine__user__club__isnull=True + ).count() + ), + ], + }, ], - [ # Second set of data (about ip adresses) - [ # Headers + [ # Second set of data (about ip adresses) + [ # Headers _("IP range"), _("VLAN"), _("Total number of IP addresses"), _("Number of assigned IP addresses"), _("Number of IP address assigned to an activated machine"), - _("Number of nonassigned IP addresses") + _("Number of nonassigned IP addresses"), ], - ip_dict # Data already prepared - ] + ip_dict, # Data already prepared + ], ] - return render(request, 'logs/stats_general.html', {'stats_list': stats}) + return render(request, "logs/stats_general.html", {"stats_list": stats}) @login_required -@can_view_app('users', 'cotisations', 'machines', 'topologie') +@can_view_app("users", "cotisations", "machines", "topologie") def stats_models(request): """Statistiques générales, affiche les comptages par models: nombre d'users, d'écoles, de droits, de bannissements, de factures, de ventes, de banque, de machines, etc""" stats = { _("Users"): { - 'users': [User._meta.verbose_name, User.objects.count()], - 'adherents': [Adherent._meta.verbose_name, Adherent.objects.count()], - 'clubs': [Club._meta.verbose_name, Club.objects.count()], - 'serviceuser': [ServiceUser._meta.verbose_name, - ServiceUser.objects.count()], - 'school': [School._meta.verbose_name, School.objects.count()], - 'listright': [ListRight._meta.verbose_name, ListRight.objects.count()], - 'listshell': [ListShell._meta.verbose_name, ListShell.objects.count()], - 'ban': [Ban._meta.verbose_name, Ban.objects.count()], - 'whitelist': [Whitelist._meta.verbose_name, Whitelist.objects.count()] + "users": [User._meta.verbose_name, User.objects.count()], + "adherents": [Adherent._meta.verbose_name, Adherent.objects.count()], + "clubs": [Club._meta.verbose_name, Club.objects.count()], + "serviceuser": [ + ServiceUser._meta.verbose_name, + ServiceUser.objects.count(), + ], + "school": [School._meta.verbose_name, School.objects.count()], + "listright": [ListRight._meta.verbose_name, ListRight.objects.count()], + "listshell": [ListShell._meta.verbose_name, ListShell.objects.count()], + "ban": [Ban._meta.verbose_name, Ban.objects.count()], + "whitelist": [Whitelist._meta.verbose_name, Whitelist.objects.count()], }, _("Subscriptions"): { - 'factures': [ - Facture._meta.verbose_name, - Facture.objects.count() - ], - 'vente': [ - Vente._meta.verbose_name, - Vente.objects.count() - ], - 'cotisation': [ - Cotisation._meta.verbose_name, - Cotisation.objects.count() - ], - 'article': [ - Article._meta.verbose_name, - Article.objects.count() - ], - 'banque': [ - Banque._meta.verbose_name, - Banque.objects.count() - ], + "factures": [Facture._meta.verbose_name, Facture.objects.count()], + "vente": [Vente._meta.verbose_name, Vente.objects.count()], + "cotisation": [Cotisation._meta.verbose_name, Cotisation.objects.count()], + "article": [Article._meta.verbose_name, Article.objects.count()], + "banque": [Banque._meta.verbose_name, Banque.objects.count()], }, _("Machines"): { - 'machine': [Machine._meta.verbose_name, - Machine.objects.count()], - 'typemachine': [MachineType._meta.verbose_name, - MachineType.objects.count()], - 'typeip': [IpType._meta.verbose_name, - IpType.objects.count()], - 'extension': [Extension._meta.verbose_name, - Extension.objects.count()], - 'interface': [Interface._meta.verbose_name, - Interface.objects.count()], - 'alias': [Domain._meta.verbose_name, - Domain.objects.exclude(cname=None).count()], - 'iplist': [IpList._meta.verbose_name, - IpList.objects.count()], - 'service': [Service._meta.verbose_name, - Service.objects.count()], - 'ouvertureportlist': [ - OuverturePortList._meta.verbose_name, - OuverturePortList.objects.count() + "machine": [Machine._meta.verbose_name, Machine.objects.count()], + "typemachine": [ + MachineType._meta.verbose_name, + MachineType.objects.count(), ], - 'vlan': [Vlan._meta.verbose_name, Vlan.objects.count()], - 'SOA': [SOA._meta.verbose_name, SOA.objects.count()], - 'Mx': [Mx._meta.verbose_name, Mx.objects.count()], - 'Ns': [Ns._meta.verbose_name, Ns.objects.count()], - 'nas': [Nas._meta.verbose_name, Nas.objects.count()], + "typeip": [IpType._meta.verbose_name, IpType.objects.count()], + "extension": [Extension._meta.verbose_name, Extension.objects.count()], + "interface": [Interface._meta.verbose_name, Interface.objects.count()], + "alias": [ + Domain._meta.verbose_name, + Domain.objects.exclude(cname=None).count(), + ], + "iplist": [IpList._meta.verbose_name, IpList.objects.count()], + "service": [Service._meta.verbose_name, Service.objects.count()], + "ouvertureportlist": [ + OuverturePortList._meta.verbose_name, + OuverturePortList.objects.count(), + ], + "vlan": [Vlan._meta.verbose_name, Vlan.objects.count()], + "SOA": [SOA._meta.verbose_name, SOA.objects.count()], + "Mx": [Mx._meta.verbose_name, Mx.objects.count()], + "Ns": [Ns._meta.verbose_name, Ns.objects.count()], + "nas": [Nas._meta.verbose_name, Nas.objects.count()], }, _("Topology"): { - 'switch': [Switch._meta.verbose_name, - Switch.objects.count()], - 'bornes': [AccessPoint._meta.verbose_name, - AccessPoint.objects.count()], - 'port': [Port._meta.verbose_name, Port.objects.count()], - 'chambre': [Room._meta.verbose_name, Room.objects.count()], - 'stack': [Stack._meta.verbose_name, Stack.objects.count()], - 'modelswitch': [ + "switch": [Switch._meta.verbose_name, Switch.objects.count()], + "bornes": [AccessPoint._meta.verbose_name, AccessPoint.objects.count()], + "port": [Port._meta.verbose_name, Port.objects.count()], + "chambre": [Room._meta.verbose_name, Room.objects.count()], + "stack": [Stack._meta.verbose_name, Stack.objects.count()], + "modelswitch": [ ModelSwitch._meta.verbose_name, - ModelSwitch.objects.count() + ModelSwitch.objects.count(), ], - 'constructorswitch': [ + "constructorswitch": [ ConstructorSwitch._meta.verbose_name, - ConstructorSwitch.objects.count() + ConstructorSwitch.objects.count(), ], }, - _("Actions performed"): - { - 'revision': [_("Number of actions"), Revision.objects.count()], + _("Actions performed"): { + "revision": [_("Number of actions"), Revision.objects.count()] }, } - return render(request, 'logs/stats_models.html', {'stats_list': stats}) + return render(request, "logs/stats_models.html", {"stats_list": stats}) @login_required -@can_view_app('users') +@can_view_app("users") def stats_users(request): """Affiche les statistiques base de données aggrégées par user : nombre de machines par user, d'etablissements par user, @@ -434,55 +413,51 @@ def stats_users(request): de bannissement par user, etc""" stats = { _("User"): { - _("Machines"): User.objects.annotate( - num=Count('machine') - ).order_by('-num')[:10], - _("Invoice"): User.objects.annotate( - num=Count('facture') - ).order_by('-num')[:10], - _("Ban"): User.objects.annotate( - num=Count('ban') - ).order_by('-num')[:10], - _("Whitelist"): User.objects.annotate( - num=Count('whitelist') - ).order_by('-num')[:10], - _("Rights"): User.objects.annotate( - num=Count('groups') - ).order_by('-num')[:10], + _("Machines"): User.objects.annotate(num=Count("machine")).order_by("-num")[ + :10 + ], + _("Invoice"): User.objects.annotate(num=Count("facture")).order_by("-num")[ + :10 + ], + _("Ban"): User.objects.annotate(num=Count("ban")).order_by("-num")[:10], + _("Whitelist"): User.objects.annotate(num=Count("whitelist")).order_by( + "-num" + )[:10], + _("Rights"): User.objects.annotate(num=Count("groups")).order_by("-num")[ + :10 + ], }, _("School"): { - _("User"): School.objects.annotate( - num=Count('user') - ).order_by('-num')[:10], + _("User"): School.objects.annotate(num=Count("user")).order_by("-num")[:10] }, _("Payment method"): { - _("User"): Paiement.objects.annotate( - num=Count('facture') - ).order_by('-num')[:10], + _("User"): Paiement.objects.annotate(num=Count("facture")).order_by("-num")[ + :10 + ] }, _("Bank"): { - _("User"): Banque.objects.annotate( - num=Count('facture') - ).order_by('-num')[:10], + _("User"): Banque.objects.annotate(num=Count("facture")).order_by("-num")[ + :10 + ] }, } - return render(request, 'logs/stats_users.html', {'stats_list': stats}) + return render(request, "logs/stats_users.html", {"stats_list": stats}) @login_required -@can_view_app('users') +@can_view_app("users") def stats_actions(request): """Vue qui affiche les statistiques de modifications d'objets par utilisateurs. Affiche le nombre de modifications aggrégées par utilisateurs""" stats = { _("User"): { - _("Action"): User.objects.annotate( - num=Count('revision') - ).order_by('-num')[:40], - }, + _("Action"): User.objects.annotate(num=Count("revision")).order_by("-num")[ + :40 + ] + } } - return render(request, 'logs/stats_users.html', {'stats_list': stats}) + return render(request, "logs/stats_users.html", {"stats_list": stats}) def history(request, application, object_name, object_id): @@ -509,33 +484,29 @@ def history(request, application, object_name, object_id): model = apps.get_model(application, object_name) except LookupError: raise Http404(_("No model found.")) - object_name_id = object_name + 'id' + object_name_id = object_name + "id" kwargs = {object_name_id: object_id} try: instance = model.get_instance(**kwargs) except model.DoesNotExist: messages.error(request, _("Nonexistent entry.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(request.user.id)} - )) + return redirect( + reverse("users:profil", kwargs={"userid": str(request.user.id)}) + ) can, msg, _permissions = instance.can_view(request.user) if not can: - messages.error(request, msg or _("You don't have the right to access this menu.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(request.user.id)} - )) - pagination_number = GeneralOption.get_cached_value('pagination_number') + messages.error( + request, msg or _("You don't have the right to access this menu.") + ) + return redirect( + reverse("users:profil", kwargs={"userid": str(request.user.id)}) + ) + pagination_number = GeneralOption.get_cached_value("pagination_number") reversions = Version.objects.get_for_object(instance) - if hasattr(instance, 'linked_objects'): + if hasattr(instance, "linked_objects"): for related_object in chain(instance.linked_objects()): - reversions = (reversions | - Version.objects.get_for_object(related_object)) + reversions = reversions | Version.objects.get_for_object(related_object) reversions = re2o_paginator(request, reversions, pagination_number) return render( - request, - 're2o/history.html', - {'reversions': reversions, 'object': instance} + request, "re2o/history.html", {"reversions": reversions, "object": instance} ) - diff --git a/machines/acl.py b/machines/acl.py index b61ac5ae..55b48145 100644 --- a/machines/acl.py +++ b/machines/acl.py @@ -38,11 +38,9 @@ def can_view(user): A couple (allowed, msg) where allowed is a boolean which is True if viewing is granted and msg is a message (can be None). """ - can = user.has_module_perms('machines') + can = user.has_module_perms("machines") return ( can, - None if can else _("You don't have the right to view this" - " application."), - ('machines',) + None if can else _("You don't have the right to view this" " application."), + ("machines",), ) - diff --git a/machines/admin.py b/machines/admin.py index 2d763cb4..ee6ea6f1 100644 --- a/machines/admin.py +++ b/machines/admin.py @@ -51,106 +51,127 @@ from .models import IpType, Machine, MachineType, Domain, IpList, Interface class MachineAdmin(VersionAdmin): """ Admin view of a Machine object """ + pass class Ipv6ListAdmin(VersionAdmin): """ Admin view of a Ipv6List object """ + pass class IpTypeAdmin(VersionAdmin): """ Admin view of a IpType object """ + pass class MachineTypeAdmin(VersionAdmin): """ Admin view of a MachineType object """ + pass class VlanAdmin(VersionAdmin): """ Admin view of a Vlan object """ + pass class ExtensionAdmin(VersionAdmin): """ Admin view of a Extension object """ + pass class SOAAdmin(VersionAdmin): """ Admin view of a SOA object """ + pass class MxAdmin(VersionAdmin): """ Admin view of a MX object """ + pass class NsAdmin(VersionAdmin): """ Admin view of a NS object """ + pass class TxtAdmin(VersionAdmin): """ Admin view of a TXT object """ + pass class DNameAdmin(VersionAdmin): """ Admin view of a DName object """ + pass class SrvAdmin(VersionAdmin): """ Admin view of a SRV object """ + pass class SshFpAdmin(VersionAdmin): """ Admin view of a SSHFP object """ + pass class NasAdmin(VersionAdmin): """ Admin view of a Nas object """ + pass class IpListAdmin(VersionAdmin): """ Admin view of a Ipv4List object """ + pass class OuverturePortAdmin(VersionAdmin): """ Admin view of a OuverturePort object """ + pass class OuverturePortListAdmin(VersionAdmin): """ Admin view of a OuverturePortList object """ + pass class InterfaceAdmin(VersionAdmin): """ Admin view of a Interface object """ - list_display = ('machine', 'machine_type', 'mac_address', 'ipv4', 'details') + + list_display = ("machine", "machine_type", "mac_address", "ipv4", "details") class DomainAdmin(VersionAdmin): """ Admin view of a Domain object """ - list_display = ('interface_parent', 'name', 'extension', 'cname') + + list_display = ("interface_parent", "name", "extension", "cname") class ServiceAdmin(VersionAdmin): """ Admin view of a ServiceAdmin object """ - list_display = ('service_type', 'min_time_regen', 'regular_time_regen') + + list_display = ("service_type", "min_time_regen", "regular_time_regen") class RoleAdmin(VersionAdmin): """ Admin view of a RoleAdmin object """ + pass diff --git a/machines/forms.py b/machines/forms.py index b85fd967..80379bc3 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -70,19 +70,19 @@ class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class Meta: model = Machine - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditMachineForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['name'].label = _("Machine name") + self.fields["name"].label = _("Machine name") class NewMachineForm(EditMachineForm): """Creation d'une machine, ne renseigne que le nom""" class Meta(EditMachineForm.Meta): - fields = ['name'] + fields = ["name"] class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): @@ -90,39 +90,38 @@ class EditInterfaceForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class Meta: model = Interface - fields = ['machine', 'machine_type', 'ipv4', 'mac_address', 'details'] + fields = ["machine", "machine_type", "ipv4", "mac_address", "details"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - user = kwargs.get('user') + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + user = kwargs.get("user") super(EditInterfaceForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['mac_address'].label = _("MAC address") - self.fields['machine_type'].label = _("Machine type") - self.fields['machine_type'].empty_label = _("Select a machine type") + self.fields["mac_address"].label = _("MAC address") + self.fields["machine_type"].label = _("Machine type") + self.fields["machine_type"].empty_label = _("Select a machine type") if "ipv4" in self.fields: - self.fields['ipv4'].empty_label = _("Automatic IPv4 assignment") - self.fields['ipv4'].queryset = IpList.objects.filter( - interface__isnull=True - ) + self.fields["ipv4"].empty_label = _("Automatic IPv4 assignment") + self.fields["ipv4"].queryset = IpList.objects.filter(interface__isnull=True) can_use_all_iptype, _reason, _permissions = IpType.can_use_all(user) if not can_use_all_iptype: - self.fields['ipv4'].queryset = IpList.objects.filter( + 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( + self.fields["ipv4"].queryset = IpList.objects.filter( interface__isnull=True ) # Add it's own address - self.fields['ipv4'].queryset |= IpList.objects.filter( + 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" + ) can_use_all_machinetype, _reason, _permissions = MachineType.can_use_all(user) if not can_use_all_machinetype: - self.fields['machine_type'].queryset = MachineType.objects.filter( + self.fields["machine_type"].queryset = MachineType.objects.filter( ip_type__in=IpType.objects.filter(need_infra=False) ) @@ -132,7 +131,7 @@ class AddInterfaceForm(EditInterfaceForm): affiche ou non l'ensemble des ip disponibles""" class Meta(EditInterfaceForm.Meta): - fields = ['machine_type', 'ipv4', 'mac_address', 'details'] + fields = ["machine_type", "ipv4", "mac_address", "details"] class AliasForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): @@ -140,15 +139,15 @@ class AliasForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class Meta: model = Domain - fields = ['name', 'extension', 'ttl'] + fields = ["name", "extension", "ttl"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - user = kwargs['user'] + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + user = kwargs["user"] super(AliasForm, self).__init__(*args, prefix=prefix, **kwargs) can_use_all, _reason, _permissions = Extension.can_use_all(user) if not can_use_all: - self.fields['extension'].queryset = Extension.objects.filter( + self.fields["extension"].queryset = Extension.objects.filter( need_infra=False ) @@ -158,30 +157,31 @@ class DomainForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class Meta: model = Domain - fields = ['name', 'ttl'] + fields = ["name", "ttl"] def __init__(self, *args, **kwargs): - if 'user' in kwargs: - user = kwargs['user'] - initial = kwargs.get('initial', {}) - initial['name'] = user.get_next_domain_name() - kwargs['initial'] = initial - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + if "user" in kwargs: + user = kwargs["user"] + initial = kwargs.get("initial", {}) + initial["name"] = user.get_next_domain_name() + kwargs["initial"] = initial + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(DomainForm, self).__init__(*args, prefix=prefix, **kwargs) class DelAliasForm(FormRevMixin, Form): """Suppression d'un ou plusieurs objets alias""" + alias = forms.ModelMultipleChoiceField( queryset=Domain.objects.all(), label=_("Current aliases"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - interface = kwargs.pop('interface') + interface = kwargs.pop("interface") super(DelAliasForm, self).__init__(*args, **kwargs) - self.fields['alias'].queryset = Domain.objects.filter( + self.fields["alias"].queryset = Domain.objects.filter( cname__in=Domain.objects.filter(interface_parent=interface) ) @@ -191,30 +191,31 @@ class MachineTypeForm(FormRevMixin, ModelForm): class Meta: model = MachineType - fields = ['name', 'ip_type'] + fields = ["name", "ip_type"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(MachineTypeForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['name'].label = _("Machine type to add") - self.fields['ip_type'].label = _("Related IP type") + self.fields["name"].label = _("Machine type to add") + self.fields["ip_type"].label = _("Related IP type") class DelMachineTypeForm(FormRevMixin, Form): """Suppression d'un ou plusieurs machinetype""" + machinetypes = forms.ModelMultipleChoiceField( queryset=MachineType.objects.none(), label=_("Current machine types"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelMachineTypeForm, self).__init__(*args, **kwargs) if instances: - self.fields['machinetypes'].queryset = instances + self.fields["machinetypes"].queryset = instances else: - self.fields['machinetypes'].queryset = MachineType.objects.all() + self.fields["machinetypes"].queryset = MachineType.objects.all() class IpTypeForm(FormRevMixin, ModelForm): @@ -223,12 +224,12 @@ class IpTypeForm(FormRevMixin, ModelForm): class Meta: model = IpType - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(IpTypeForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['name'].label = _("IP type to add") + self.fields["name"].label = _("IP type to add") class EditIpTypeForm(IpTypeForm): @@ -236,27 +237,37 @@ class EditIpTypeForm(IpTypeForm): synchroniser les objets iplist""" class Meta(IpTypeForm.Meta): - fields = ['extension', 'name', 'need_infra', 'domaine_ip_network', 'domaine_ip_netmask', - 'prefix_v6', 'prefix_v6_length', - 'vlan', 'reverse_v4', 'reverse_v6', - 'ouverture_ports'] + fields = [ + "extension", + "name", + "need_infra", + "domaine_ip_network", + "domaine_ip_netmask", + "prefix_v6", + "prefix_v6_length", + "vlan", + "reverse_v4", + "reverse_v6", + "ouverture_ports", + ] class DelIpTypeForm(FormRevMixin, Form): """Suppression d'un ou plusieurs iptype""" + iptypes = forms.ModelMultipleChoiceField( queryset=IpType.objects.none(), label=_("Current IP types"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelIpTypeForm, self).__init__(*args, **kwargs) if instances: - self.fields['iptypes'].queryset = instances + self.fields["iptypes"].queryset = instances else: - self.fields['iptypes'].queryset = IpType.objects.all() + self.fields["iptypes"].queryset = IpType.objects.all() class ExtensionForm(FormRevMixin, ModelForm): @@ -264,33 +275,34 @@ class ExtensionForm(FormRevMixin, ModelForm): class Meta: model = Extension - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(ExtensionForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['name'].label = _("Extension to add") - self.fields['origin'].label = _("A record origin") - self.fields['origin_v6'].label = _("AAAA record origin") - self.fields['soa'].label = _("SOA record to use") - self.fields['dnssec'].label = _("Sign with DNSSEC") + self.fields["name"].label = _("Extension to add") + self.fields["origin"].label = _("A record origin") + self.fields["origin_v6"].label = _("AAAA record origin") + self.fields["soa"].label = _("SOA record to use") + self.fields["dnssec"].label = _("Sign with DNSSEC") class DelExtensionForm(FormRevMixin, Form): """Suppression d'une ou plusieurs extensions""" + extensions = forms.ModelMultipleChoiceField( queryset=Extension.objects.none(), label=_("Current extensions"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelExtensionForm, self).__init__(*args, **kwargs) if instances: - self.fields['extensions'].queryset = instances + self.fields["extensions"].queryset = instances else: - self.fields['extensions'].queryset = Extension.objects.all() + self.fields["extensions"].queryset = Extension.objects.all() class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): @@ -298,10 +310,10 @@ class Ipv6ListForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): class Meta: model = Ipv6List - fields = ['ipv6', 'slaac_ip'] + fields = ["ipv6", "slaac_ip"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(Ipv6ListForm, self).__init__(*args, prefix=prefix, **kwargs) @@ -310,28 +322,29 @@ class SOAForm(FormRevMixin, ModelForm): class Meta: model = SOA - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(SOAForm, self).__init__(*args, prefix=prefix, **kwargs) class DelSOAForm(FormRevMixin, Form): """Suppression d'un ou plusieurs SOA""" + soa = forms.ModelMultipleChoiceField( queryset=SOA.objects.none(), label=_("Current SOA records"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelSOAForm, self).__init__(*args, **kwargs) if instances: - self.fields['soa'].queryset = instances + self.fields["soa"].queryset = instances else: - self.fields['soa'].queryset = SOA.objects.all() + self.fields["soa"].queryset = SOA.objects.all() class MxForm(FormRevMixin, ModelForm): @@ -339,31 +352,32 @@ class MxForm(FormRevMixin, ModelForm): class Meta: model = Mx - fields = ['zone', 'priority', 'name', 'ttl'] + fields = ["zone", "priority", "name", "ttl"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(MxForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['name'].queryset = Domain.objects.exclude( + self.fields["name"].queryset = Domain.objects.exclude( interface_parent=None - ).select_related('extension') + ).select_related("extension") class DelMxForm(FormRevMixin, Form): """Suppression d'un ou plusieurs MX""" + mx = forms.ModelMultipleChoiceField( queryset=Mx.objects.none(), label=_("Current MX records"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelMxForm, self).__init__(*args, **kwargs) if instances: - self.fields['mx'].queryset = instances + self.fields["mx"].queryset = instances else: - self.fields['mx'].queryset = Mx.objects.all() + self.fields["mx"].queryset = Mx.objects.all() class NsForm(FormRevMixin, ModelForm): @@ -373,31 +387,32 @@ class NsForm(FormRevMixin, ModelForm): class Meta: model = Ns - fields = ['zone', 'ns', 'ttl'] + fields = ["zone", "ns", "ttl"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(NsForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['ns'].queryset = Domain.objects.exclude( + self.fields["ns"].queryset = Domain.objects.exclude( interface_parent=None - ).select_related('extension') + ).select_related("extension") class DelNsForm(FormRevMixin, Form): """Suppresion d'un ou plusieurs NS""" + ns = forms.ModelMultipleChoiceField( queryset=Ns.objects.none(), label=_("Current NS records"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelNsForm, self).__init__(*args, **kwargs) if instances: - self.fields['ns'].queryset = instances + self.fields["ns"].queryset = instances else: - self.fields['ns'].queryset = Ns.objects.all() + self.fields["ns"].queryset = Ns.objects.all() class TxtForm(FormRevMixin, ModelForm): @@ -405,28 +420,29 @@ class TxtForm(FormRevMixin, ModelForm): class Meta: model = Txt - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(TxtForm, self).__init__(*args, prefix=prefix, **kwargs) class DelTxtForm(FormRevMixin, Form): """Suppression d'un ou plusieurs TXT""" + txt = forms.ModelMultipleChoiceField( queryset=Txt.objects.none(), label=_("Current TXT records"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelTxtForm, self).__init__(*args, **kwargs) if instances: - self.fields['txt'].queryset = instances + self.fields["txt"].queryset = instances else: - self.fields['txt'].queryset = Txt.objects.all() + self.fields["txt"].queryset = Txt.objects.all() class DNameForm(FormRevMixin, ModelForm): @@ -434,28 +450,29 @@ class DNameForm(FormRevMixin, ModelForm): class Meta: model = DName - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(DNameForm, self).__init__(*args, prefix=prefix, **kwargs) class DelDNameForm(FormRevMixin, Form): """Delete a set of DNAME entries""" + dnames = forms.ModelMultipleChoiceField( queryset=Txt.objects.none(), label=_("Current DNAME records"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelDNameForm, self).__init__(*args, **kwargs) if instances: - self.fields['dnames'].queryset = instances + self.fields["dnames"].queryset = instances else: - self.fields['dnames'].queryset = DName.objects.all() + self.fields["dnames"].queryset = DName.objects.all() class SrvForm(FormRevMixin, ModelForm): @@ -463,28 +480,29 @@ class SrvForm(FormRevMixin, ModelForm): class Meta: model = Srv - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(SrvForm, self).__init__(*args, prefix=prefix, **kwargs) class DelSrvForm(FormRevMixin, Form): """Suppression d'un ou plusieurs Srv""" + srv = forms.ModelMultipleChoiceField( queryset=Srv.objects.none(), label=_("Current SRV records"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelSrvForm, self).__init__(*args, **kwargs) if instances: - self.fields['srv'].queryset = instances + self.fields["srv"].queryset = instances else: - self.fields['srv'].queryset = Srv.objects.all() + self.fields["srv"].queryset = Srv.objects.all() class NasForm(FormRevMixin, ModelForm): @@ -493,28 +511,29 @@ class NasForm(FormRevMixin, ModelForm): class Meta: model = Nas - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(NasForm, self).__init__(*args, prefix=prefix, **kwargs) class DelNasForm(FormRevMixin, Form): """Suppression d'un ou plusieurs nas""" + nas = forms.ModelMultipleChoiceField( queryset=Nas.objects.none(), label=_("Current NAS devices"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelNasForm, self).__init__(*args, **kwargs) if instances: - self.fields['nas'].queryset = instances + self.fields["nas"].queryset = instances else: - self.fields['nas'].queryset = Nas.objects.all() + self.fields["nas"].queryset = Nas.objects.all() class RoleForm(FormRevMixin, ModelForm): @@ -522,32 +541,32 @@ class RoleForm(FormRevMixin, ModelForm): class Meta: model = Role - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(RoleForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['servers'].queryset = (Interface.objects.all() - .select_related( - 'domain__extension' - )) + self.fields["servers"].queryset = Interface.objects.all().select_related( + "domain__extension" + ) class DelRoleForm(FormRevMixin, Form): """Deletion of one or several roles.""" + role = forms.ModelMultipleChoiceField( queryset=Role.objects.none(), label=_("Current roles"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelRoleForm, self).__init__(*args, **kwargs) if instances: - self.fields['role'].queryset = instances + self.fields["role"].queryset = instances else: - self.fields['role'].queryset = Role.objects.all() + self.fields["role"].queryset = Role.objects.all() class ServiceForm(FormRevMixin, ModelForm): @@ -555,15 +574,14 @@ class ServiceForm(FormRevMixin, ModelForm): class Meta: model = Service - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + 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' - )) + self.fields["servers"].queryset = Interface.objects.all().select_related( + "domain__extension" + ) def save(self, commit=True): # TODO : None of the parents of ServiceForm use the commit @@ -571,25 +589,26 @@ class ServiceForm(FormRevMixin, ModelForm): instance = super(ServiceForm, self).save(commit=False) if commit: instance.save() - instance.process_link(self.cleaned_data.get('servers')) + instance.process_link(self.cleaned_data.get("servers")) return instance class DelServiceForm(FormRevMixin, Form): """Suppression d'un ou plusieurs service""" + service = forms.ModelMultipleChoiceField( queryset=Service.objects.none(), label=_("Current services"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelServiceForm, self).__init__(*args, **kwargs) if instances: - self.fields['service'].queryset = instances + self.fields["service"].queryset = instances else: - self.fields['service'].queryset = Service.objects.all() + self.fields["service"].queryset = Service.objects.all() class VlanForm(FormRevMixin, ModelForm): @@ -597,39 +616,41 @@ class VlanForm(FormRevMixin, ModelForm): class Meta: model = Vlan - fields = ['vlan_id', 'name', 'comment'] + fields = ["vlan_id", "name", "comment"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(VlanForm, self).__init__(*args, prefix=prefix, **kwargs) class EditOptionVlanForm(FormRevMixin, ModelForm): """Ajout d'un vlan : id, nom""" + class Meta: model = Vlan - fields = ['dhcp_snooping', 'dhcpv6_snooping', 'arp_protect', 'igmp', 'mld'] + fields = ["dhcp_snooping", "dhcpv6_snooping", "arp_protect", "igmp", "mld"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditOptionVlanForm, self).__init__(*args, prefix=prefix, **kwargs) class DelVlanForm(FormRevMixin, Form): """Suppression d'un ou plusieurs vlans""" + vlan = forms.ModelMultipleChoiceField( queryset=Vlan.objects.none(), label=_("Current VLANs"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelVlanForm, self).__init__(*args, **kwargs) if instances: - self.fields['vlan'].queryset = instances + self.fields["vlan"].queryset = instances else: - self.fields['vlan'].queryset = Vlan.objects.all() + self.fields["vlan"].queryset = Vlan.objects.all() class EditOuverturePortConfigForm(FormRevMixin, ModelForm): @@ -638,14 +659,12 @@ class EditOuverturePortConfigForm(FormRevMixin, ModelForm): class Meta: model = Interface - fields = ['port_lists'] + fields = ["port_lists"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditOuverturePortConfigForm, self).__init__( - *args, - prefix=prefix, - **kwargs + *args, prefix=prefix, **kwargs ) @@ -655,15 +674,11 @@ class EditOuverturePortListForm(FormRevMixin, ModelForm): class Meta: model = OuverturePortList - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditOuverturePortListForm, self).__init__( - *args, - prefix=prefix, - **kwargs - ) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditOuverturePortListForm, self).__init__(*args, prefix=prefix, **kwargs) class SshFpForm(FormRevMixin, ModelForm): @@ -671,12 +686,8 @@ class SshFpForm(FormRevMixin, ModelForm): class Meta: model = SshFp - exclude = ('machine',) + exclude = ("machine",) def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(SshFpForm, self).__init__( - *args, - prefix=prefix, - **kwargs - ) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(SshFpForm, self).__init__(*args, prefix=prefix, **kwargs) diff --git a/machines/migrations/0001_initial.py b/machines/migrations/0001_initial.py index 64eb9d3b..e253acdd 100644 --- a/machines/migrations/0001_initial.py +++ b/machines/migrations/0001_initial.py @@ -29,32 +29,50 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0005_auto_20160702_0006'), - ] + dependencies = [("users", "0005_auto_20160702_0006")] operations = [ migrations.CreateModel( - name='Machine', + name="Machine", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ) ], ), migrations.CreateModel( - name='MachineType', + name="MachineType", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('type', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("type", models.CharField(max_length=255)), ], ), migrations.AddField( - model_name='machine', - name='type', - field=models.ForeignKey(to='machines.MachineType', on_delete=django.db.models.deletion.PROTECT), + model_name="machine", + name="type", + field=models.ForeignKey( + to="machines.MachineType", on_delete=django.db.models.deletion.PROTECT + ), ), migrations.AddField( - model_name='machine', - name='user', - field=models.ForeignKey(to='users.User', on_delete=django.db.models.deletion.PROTECT), + model_name="machine", + name="user", + field=models.ForeignKey( + to="users.User", on_delete=django.db.models.deletion.PROTECT + ), ), ] diff --git a/machines/migrations/0002_auto_20160703_1444.py b/machines/migrations/0002_auto_20160703_1444.py index 6b3d8588..83d820a4 100644 --- a/machines/migrations/0002_auto_20160703_1444.py +++ b/machines/migrations/0002_auto_20160703_1444.py @@ -30,36 +30,57 @@ import macaddress.fields class Migration(migrations.Migration): - dependencies = [ - ('machines', '0001_initial'), - ] + dependencies = [("machines", "0001_initial")] operations = [ migrations.CreateModel( - name='Interface', + name="Interface", fields=[ - ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), - ('ipv6', models.GenericIPAddressField(protocol='IPv6')), - ('mac_address', macaddress.fields.MACAddressField(integer=True)), - ('details', models.CharField(max_length=255)), - ('name', models.CharField(max_length=255, blank=True, unique=True)), + ( + "id", + models.AutoField( + serialize=False, + verbose_name="ID", + auto_created=True, + primary_key=True, + ), + ), + ("ipv6", models.GenericIPAddressField(protocol="IPv6")), + ("mac_address", macaddress.fields.MACAddressField(integer=True)), + ("details", models.CharField(max_length=255)), + ("name", models.CharField(max_length=255, blank=True, unique=True)), ], ), migrations.CreateModel( - name='IpList', + name="IpList", fields=[ - ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), - ('ipv4', models.GenericIPAddressField(protocol='IPv4')), + ( + "id", + models.AutoField( + serialize=False, + verbose_name="ID", + auto_created=True, + primary_key=True, + ), + ), + ("ipv4", models.GenericIPAddressField(protocol="IPv4")), ], ), migrations.AddField( - model_name='interface', - name='ipv4', - field=models.OneToOneField(null=True, to='machines.IpList', blank=True, on_delete=django.db.models.deletion.PROTECT), + model_name="interface", + name="ipv4", + field=models.OneToOneField( + null=True, + to="machines.IpList", + blank=True, + on_delete=django.db.models.deletion.PROTECT, + ), ), migrations.AddField( - model_name='interface', - name='machine', - field=models.ForeignKey(to='machines.Machine', on_delete=django.db.models.deletion.PROTECT), + model_name="interface", + name="machine", + field=models.ForeignKey( + to="machines.Machine", on_delete=django.db.models.deletion.PROTECT + ), ), ] diff --git a/machines/migrations/0003_auto_20160703_1450.py b/machines/migrations/0003_auto_20160703_1450.py index 89b22311..33c3642e 100644 --- a/machines/migrations/0003_auto_20160703_1450.py +++ b/machines/migrations/0003_auto_20160703_1450.py @@ -29,14 +29,12 @@ import macaddress.fields class Migration(migrations.Migration): - dependencies = [ - ('machines', '0002_auto_20160703_1444'), - ] + dependencies = [("machines", "0002_auto_20160703_1444")] operations = [ migrations.AlterField( - model_name='interface', - name='mac_address', + model_name="interface", + name="mac_address", field=macaddress.fields.MACAddressField(integer=True, unique=True), - ), + ) ] diff --git a/machines/migrations/0004_auto_20160703_1451.py b/machines/migrations/0004_auto_20160703_1451.py index 29061e15..df36fb0f 100644 --- a/machines/migrations/0004_auto_20160703_1451.py +++ b/machines/migrations/0004_auto_20160703_1451.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0003_auto_20160703_1450'), - ] + dependencies = [("machines", "0003_auto_20160703_1450")] operations = [ migrations.AlterField( - model_name='iplist', - name='ipv4', - field=models.GenericIPAddressField(protocol='IPv4', unique=True), - ), + model_name="iplist", + name="ipv4", + field=models.GenericIPAddressField(protocol="IPv4", unique=True), + ) ] diff --git a/machines/migrations/0005_auto_20160703_1523.py b/machines/migrations/0005_auto_20160703_1523.py index 0666147a..481a113d 100644 --- a/machines/migrations/0005_auto_20160703_1523.py +++ b/machines/migrations/0005_auto_20160703_1523.py @@ -28,19 +28,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0004_auto_20160703_1451'), - ] + dependencies = [("machines", "0004_auto_20160703_1451")] operations = [ - migrations.RenameField( - model_name='interface', - old_name='name', - new_name='dns', - ), + migrations.RenameField(model_name="interface", old_name="name", new_name="dns"), migrations.AddField( - model_name='machine', - name='name', - field=models.CharField(blank=True, unique=True, max_length=255, help_text='Optionnel'), + model_name="machine", + name="name", + field=models.CharField( + blank=True, unique=True, max_length=255, help_text="Optionnel" + ), ), ] diff --git a/machines/migrations/0006_auto_20160703_1813.py b/machines/migrations/0006_auto_20160703_1813.py index ae408269..19ce0a75 100644 --- a/machines/migrations/0006_auto_20160703_1813.py +++ b/machines/migrations/0006_auto_20160703_1813.py @@ -28,19 +28,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0005_auto_20160703_1523'), - ] + dependencies = [("machines", "0005_auto_20160703_1523")] operations = [ migrations.AlterField( - model_name='interface', - name='details', + model_name="interface", + name="details", field=models.CharField(max_length=255, blank=True), ), migrations.AlterField( - model_name='interface', - name='dns', + model_name="interface", + name="dns", field=models.CharField(max_length=255, unique=True), ), ] diff --git a/machines/migrations/0007_auto_20160703_1816.py b/machines/migrations/0007_auto_20160703_1816.py index 0f3cd574..be74d8b7 100644 --- a/machines/migrations/0007_auto_20160703_1816.py +++ b/machines/migrations/0007_auto_20160703_1816.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0006_auto_20160703_1813'), - ] + dependencies = [("machines", "0006_auto_20160703_1813")] operations = [ migrations.AlterField( - model_name='interface', - name='ipv6', - field=models.GenericIPAddressField(null=True, protocol='IPv6'), - ), + model_name="interface", + name="ipv6", + field=models.GenericIPAddressField(null=True, protocol="IPv6"), + ) ] diff --git a/machines/migrations/0008_remove_interface_ipv6.py b/machines/migrations/0008_remove_interface_ipv6.py index 1e569c25..f4ebdfbb 100644 --- a/machines/migrations/0008_remove_interface_ipv6.py +++ b/machines/migrations/0008_remove_interface_ipv6.py @@ -28,13 +28,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0007_auto_20160703_1816'), - ] + dependencies = [("machines", "0007_auto_20160703_1816")] - operations = [ - migrations.RemoveField( - model_name='interface', - name='ipv6', - ), - ] + operations = [migrations.RemoveField(model_name="interface", name="ipv6")] diff --git a/machines/migrations/0009_auto_20160703_2358.py b/machines/migrations/0009_auto_20160703_2358.py index eef5659e..682f490e 100644 --- a/machines/migrations/0009_auto_20160703_2358.py +++ b/machines/migrations/0009_auto_20160703_2358.py @@ -29,14 +29,14 @@ import macaddress.fields class Migration(migrations.Migration): - dependencies = [ - ('machines', '0008_remove_interface_ipv6'), - ] + dependencies = [("machines", "0008_remove_interface_ipv6")] operations = [ migrations.AlterField( - model_name='interface', - name='mac_address', - field=macaddress.fields.MACAddressField(integer=False, max_length=17, unique=True), - ), + model_name="interface", + name="mac_address", + field=macaddress.fields.MACAddressField( + integer=False, max_length=17, unique=True + ), + ) ] diff --git a/machines/migrations/0010_auto_20160704_0104.py b/machines/migrations/0010_auto_20160704_0104.py index de60578d..79ffc90e 100644 --- a/machines/migrations/0010_auto_20160704_0104.py +++ b/machines/migrations/0010_auto_20160704_0104.py @@ -28,14 +28,18 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0009_auto_20160703_2358'), - ] + dependencies = [("machines", "0009_auto_20160703_2358")] operations = [ migrations.AlterField( - model_name='machine', - name='name', - field=models.CharField(blank=True, unique=True, max_length=255, help_text='Optionnel', null=True), - ), + model_name="machine", + name="name", + field=models.CharField( + blank=True, + unique=True, + max_length=255, + help_text="Optionnel", + null=True, + ), + ) ] diff --git a/machines/migrations/0011_auto_20160704_0105.py b/machines/migrations/0011_auto_20160704_0105.py index c2bd2158..b780b951 100644 --- a/machines/migrations/0011_auto_20160704_0105.py +++ b/machines/migrations/0011_auto_20160704_0105.py @@ -28,14 +28,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0010_auto_20160704_0104'), - ] + dependencies = [("machines", "0010_auto_20160704_0104")] operations = [ migrations.AlterField( - model_name='machine', - name='name', - field=models.CharField(help_text='Optionnel', blank=True, null=True, max_length=255), - ), + model_name="machine", + name="name", + field=models.CharField( + help_text="Optionnel", blank=True, null=True, max_length=255 + ), + ) ] diff --git a/machines/migrations/0012_auto_20160704_0118.py b/machines/migrations/0012_auto_20160704_0118.py index 6d924e01..222b55a5 100644 --- a/machines/migrations/0012_auto_20160704_0118.py +++ b/machines/migrations/0012_auto_20160704_0118.py @@ -28,14 +28,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0011_auto_20160704_0105'), - ] + dependencies = [("machines", "0011_auto_20160704_0105")] operations = [ migrations.AlterField( - model_name='interface', - name='dns', - field=models.CharField(max_length=255, help_text='Obligatoire et unique', unique=True), - ), + model_name="interface", + name="dns", + field=models.CharField( + max_length=255, help_text="Obligatoire et unique", unique=True + ), + ) ] diff --git a/machines/migrations/0013_auto_20160705_1014.py b/machines/migrations/0013_auto_20160705_1014.py index ed497ac2..5ee18020 100644 --- a/machines/migrations/0013_auto_20160705_1014.py +++ b/machines/migrations/0013_auto_20160705_1014.py @@ -28,19 +28,19 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0012_auto_20160704_0118'), - ] + dependencies = [("machines", "0012_auto_20160704_0118")] operations = [ migrations.AddField( - model_name='machine', - name='active', - field=models.BooleanField(default=True), + model_name="machine", name="active", field=models.BooleanField(default=True) ), migrations.AlterField( - model_name='interface', - name='dns', - field=models.CharField(max_length=255, unique=True, help_text='Obligatoire et unique, doit se terminer en .rez et ne pas comporter de points'), + model_name="interface", + name="dns", + field=models.CharField( + max_length=255, + unique=True, + help_text="Obligatoire et unique, doit se terminer en .rez et ne pas comporter de points", + ), ), ] diff --git a/machines/migrations/0014_auto_20160706_1220.py b/machines/migrations/0014_auto_20160706_1220.py index 8f5d63da..2d3fc351 100644 --- a/machines/migrations/0014_auto_20160706_1220.py +++ b/machines/migrations/0014_auto_20160706_1220.py @@ -29,14 +29,16 @@ import machines.models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0013_auto_20160705_1014'), - ] + dependencies = [("machines", "0013_auto_20160705_1014")] operations = [ migrations.AlterField( - model_name='interface', - name='dns', - field=models.CharField(unique=True, max_length=255, help_text="Obligatoire et unique, doit se terminer en .rez et ne pas comporter d'autres points"), - ), + model_name="interface", + name="dns", + field=models.CharField( + unique=True, + max_length=255, + help_text="Obligatoire et unique, doit se terminer en .rez et ne pas comporter d'autres points", + ), + ) ] diff --git a/machines/migrations/0015_auto_20160707_0105.py b/machines/migrations/0015_auto_20160707_0105.py index 7e670949..19022f55 100644 --- a/machines/migrations/0015_auto_20160707_0105.py +++ b/machines/migrations/0015_auto_20160707_0105.py @@ -29,14 +29,16 @@ import machines.models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0014_auto_20160706_1220'), - ] + dependencies = [("machines", "0014_auto_20160706_1220")] operations = [ migrations.AlterField( - model_name='interface', - name='dns', - field=models.CharField(unique=True, help_text="Obligatoire et unique, doit se terminer en .example et ne pas comporter d'autres points", max_length=255), - ), + model_name="interface", + name="dns", + field=models.CharField( + unique=True, + help_text="Obligatoire et unique, doit se terminer en .example et ne pas comporter d'autres points", + max_length=255, + ), + ) ] diff --git a/machines/migrations/0016_auto_20160708_1633.py b/machines/migrations/0016_auto_20160708_1633.py index ab3f3c19..1b4a6bd0 100644 --- a/machines/migrations/0016_auto_20160708_1633.py +++ b/machines/migrations/0016_auto_20160708_1633.py @@ -30,26 +30,41 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0015_auto_20160707_0105'), - ] + dependencies = [("machines", "0015_auto_20160707_0105")] operations = [ migrations.CreateModel( - name='Extension', + name="Extension", fields=[ - ('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)), - ('name', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + primary_key=True, + verbose_name="ID", + serialize=False, + auto_created=True, + ), + ), + ("name", models.CharField(max_length=255)), ], ), migrations.AlterField( - model_name='interface', - name='dns', - field=models.CharField(unique=True, max_length=255, help_text="Obligatoire et unique, doit se terminer en .rez et ne pas comporter d'autres points"), + model_name="interface", + name="dns", + field=models.CharField( + unique=True, + max_length=255, + help_text="Obligatoire et unique, doit se terminer en .rez et ne pas comporter d'autres points", + ), ), migrations.AddField( - model_name='machinetype', - name='extension', - field=models.ForeignKey(null=True, blank=True, on_delete=django.db.models.deletion.PROTECT, to='machines.Extension'), + model_name="machinetype", + name="extension", + field=models.ForeignKey( + null=True, + blank=True, + on_delete=django.db.models.deletion.PROTECT, + to="machines.Extension", + ), ), ] diff --git a/machines/migrations/0017_auto_20160708_1645.py b/machines/migrations/0017_auto_20160708_1645.py index da8253a1..455070e4 100644 --- a/machines/migrations/0017_auto_20160708_1645.py +++ b/machines/migrations/0017_auto_20160708_1645.py @@ -29,15 +29,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0016_auto_20160708_1633'), - ] + dependencies = [("machines", "0016_auto_20160708_1633")] operations = [ migrations.AlterField( - model_name='machinetype', - name='extension', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, default=1, to='machines.Extension'), + model_name="machinetype", + name="extension", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + default=1, + to="machines.Extension", + ), preserve_default=False, - ), + ) ] diff --git a/machines/migrations/0018_auto_20160708_1813.py b/machines/migrations/0018_auto_20160708_1813.py index 164e986f..bf2806cc 100644 --- a/machines/migrations/0018_auto_20160708_1813.py +++ b/machines/migrations/0018_auto_20160708_1813.py @@ -28,14 +28,16 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0017_auto_20160708_1645'), - ] + dependencies = [("machines", "0017_auto_20160708_1645")] operations = [ migrations.AlterField( - model_name='interface', - name='dns', - field=models.CharField(help_text="Obligatoire et unique, doit se terminer en .rez et ne pas comporter d'autres points", unique=True, max_length=255), - ), + model_name="interface", + name="dns", + field=models.CharField( + help_text="Obligatoire et unique, doit se terminer en .rez et ne pas comporter d'autres points", + unique=True, + max_length=255, + ), + ) ] diff --git a/machines/migrations/0019_auto_20160718_1141.py b/machines/migrations/0019_auto_20160718_1141.py index ba34c076..6990d85f 100644 --- a/machines/migrations/0019_auto_20160718_1141.py +++ b/machines/migrations/0019_auto_20160718_1141.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0018_auto_20160708_1813'), - ] + dependencies = [("machines", "0018_auto_20160708_1813")] operations = [ migrations.AlterField( - model_name='interface', - name='machine', - field=models.ForeignKey(to='machines.Machine'), - ), + model_name="interface", + name="machine", + field=models.ForeignKey(to="machines.Machine"), + ) ] diff --git a/machines/migrations/0020_auto_20160718_1849.py b/machines/migrations/0020_auto_20160718_1849.py index 83cd66ae..925e9cd5 100644 --- a/machines/migrations/0020_auto_20160718_1849.py +++ b/machines/migrations/0020_auto_20160718_1849.py @@ -29,19 +29,18 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0019_auto_20160718_1141'), - ] + dependencies = [("machines", "0019_auto_20160718_1141")] operations = [ - migrations.RemoveField( - model_name='machine', - name='type', - ), + migrations.RemoveField(model_name="machine", name="type"), migrations.AddField( - model_name='interface', - name='type', - field=models.ForeignKey(to='machines.MachineType', default=1, on_delete=django.db.models.deletion.PROTECT), + model_name="interface", + name="type", + field=models.ForeignKey( + to="machines.MachineType", + default=1, + on_delete=django.db.models.deletion.PROTECT, + ), preserve_default=False, ), ] diff --git a/machines/migrations/0021_auto_20161006_1943.py b/machines/migrations/0021_auto_20161006_1943.py index e0a90ed9..688fe503 100644 --- a/machines/migrations/0021_auto_20161006_1943.py +++ b/machines/migrations/0021_auto_20161006_1943.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0020_auto_20160718_1849'), - ] + dependencies = [("machines", "0020_auto_20160718_1849")] operations = [ migrations.AlterField( - model_name='interface', - name='dns', + model_name="interface", + name="dns", field=models.CharField(unique=True, max_length=255), - ), + ) ] diff --git a/machines/migrations/0022_auto_20161011_1829.py b/machines/migrations/0022_auto_20161011_1829.py index 3d88148a..bae2d679 100644 --- a/machines/migrations/0022_auto_20161011_1829.py +++ b/machines/migrations/0022_auto_20161011_1829.py @@ -28,14 +28,16 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0021_auto_20161006_1943'), - ] + dependencies = [("machines", "0021_auto_20161006_1943")] operations = [ migrations.AlterField( - model_name='interface', - name='dns', - field=models.CharField(help_text="Obligatoire et unique, doit se terminer par exemple en .rez et ne pas comporter d'autres points", unique=True, max_length=255), - ), + model_name="interface", + name="dns", + field=models.CharField( + help_text="Obligatoire et unique, doit se terminer par exemple en .rez et ne pas comporter d'autres points", + unique=True, + max_length=255, + ), + ) ] diff --git a/machines/migrations/0023_iplist_ip_type.py b/machines/migrations/0023_iplist_ip_type.py index a1412b4f..23f1a0f7 100644 --- a/machines/migrations/0023_iplist_ip_type.py +++ b/machines/migrations/0023_iplist_ip_type.py @@ -29,15 +29,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0022_auto_20161011_1829'), - ] + dependencies = [("machines", "0022_auto_20161011_1829")] operations = [ migrations.AddField( - model_name='iplist', - name='ip_type', - field=models.ForeignKey(to='machines.MachineType', on_delete=django.db.models.deletion.PROTECT, default=1), + model_name="iplist", + name="ip_type", + field=models.ForeignKey( + to="machines.MachineType", + on_delete=django.db.models.deletion.PROTECT, + default=1, + ), preserve_default=False, - ), + ) ] diff --git a/machines/migrations/0024_machinetype_need_infra.py b/machines/migrations/0024_machinetype_need_infra.py index 019ae2b0..4caf9fa0 100644 --- a/machines/migrations/0024_machinetype_need_infra.py +++ b/machines/migrations/0024_machinetype_need_infra.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0023_iplist_ip_type'), - ] + dependencies = [("machines", "0023_iplist_ip_type")] operations = [ migrations.AddField( - model_name='machinetype', - name='need_infra', + model_name="machinetype", + name="need_infra", field=models.BooleanField(default=False), - ), + ) ] diff --git a/machines/migrations/0025_auto_20161023_0038.py b/machines/migrations/0025_auto_20161023_0038.py index 6c20d4bf..285e9271 100644 --- a/machines/migrations/0025_auto_20161023_0038.py +++ b/machines/migrations/0025_auto_20161023_0038.py @@ -29,36 +29,49 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0024_machinetype_need_infra'), - ] + dependencies = [("machines", "0024_machinetype_need_infra")] operations = [ migrations.CreateModel( - name='IpType', + name="IpType", fields=[ - ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), - ('type', models.CharField(max_length=255)), - ('need_infra', models.BooleanField(default=False)), - ('extension', models.ForeignKey(to='machines.Extension', on_delete=django.db.models.deletion.PROTECT)), + ( + "id", + models.AutoField( + verbose_name="ID", + primary_key=True, + serialize=False, + auto_created=True, + ), + ), + ("type", models.CharField(max_length=255)), + ("need_infra", models.BooleanField(default=False)), + ( + "extension", + models.ForeignKey( + to="machines.Extension", + on_delete=django.db.models.deletion.PROTECT, + ), + ), ], ), - migrations.RemoveField( - model_name='machinetype', - name='extension', - ), - migrations.RemoveField( - model_name='machinetype', - name='need_infra', - ), + migrations.RemoveField(model_name="machinetype", name="extension"), + migrations.RemoveField(model_name="machinetype", name="need_infra"), migrations.AlterField( - model_name='iplist', - name='ip_type', - field=models.ForeignKey(to='machines.IpType', on_delete=django.db.models.deletion.PROTECT), + model_name="iplist", + name="ip_type", + field=models.ForeignKey( + to="machines.IpType", on_delete=django.db.models.deletion.PROTECT + ), ), migrations.AddField( - model_name='machinetype', - name='ip_type', - field=models.ForeignKey(to='machines.IpType', null=True, blank=True, on_delete=django.db.models.deletion.PROTECT), + model_name="machinetype", + name="ip_type", + field=models.ForeignKey( + to="machines.IpType", + null=True, + blank=True, + on_delete=django.db.models.deletion.PROTECT, + ), ), ] diff --git a/machines/migrations/0026_auto_20161026_1348.py b/machines/migrations/0026_auto_20161026_1348.py index 60cf9635..22911933 100644 --- a/machines/migrations/0026_auto_20161026_1348.py +++ b/machines/migrations/0026_auto_20161026_1348.py @@ -28,14 +28,16 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0025_auto_20161023_0038'), - ] + dependencies = [("machines", "0025_auto_20161023_0038")] operations = [ migrations.AlterField( - model_name='interface', - name='dns', - field=models.CharField(unique=True, max_length=255, help_text='Obligatoire et unique, ne doit pas comporter de points'), - ), + model_name="interface", + name="dns", + field=models.CharField( + unique=True, + max_length=255, + help_text="Obligatoire et unique, ne doit pas comporter de points", + ), + ) ] diff --git a/machines/migrations/0027_alias.py b/machines/migrations/0027_alias.py index e5182352..c4d85cd7 100644 --- a/machines/migrations/0027_alias.py +++ b/machines/migrations/0027_alias.py @@ -28,17 +28,30 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0026_auto_20161026_1348'), - ] + dependencies = [("machines", "0026_auto_20161026_1348")] operations = [ migrations.CreateModel( - name='Alias', + name="Alias", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')), - ('alias', models.CharField(max_length=255, help_text='Obligatoire et unique, ne doit pas comporter de points', unique=True)), - ('interface_parent', models.ForeignKey(to='machines.Interface')), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + auto_created=True, + verbose_name="ID", + ), + ), + ( + "alias", + models.CharField( + max_length=255, + help_text="Obligatoire et unique, ne doit pas comporter de points", + unique=True, + ), + ), + ("interface_parent", models.ForeignKey(to="machines.Interface")), ], - ), + ) ] diff --git a/machines/migrations/0028_iptype_domaine_ip.py b/machines/migrations/0028_iptype_domaine_ip.py index 6cd5e4bc..d0bfa5b4 100644 --- a/machines/migrations/0028_iptype_domaine_ip.py +++ b/machines/migrations/0028_iptype_domaine_ip.py @@ -28,14 +28,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0027_alias'), - ] + dependencies = [("machines", "0027_alias")] operations = [ migrations.AddField( - model_name='iptype', - name='domaine_ip', - field=models.GenericIPAddressField(blank=True, unique=True, null=True, protocol='IPv4'), - ), + model_name="iptype", + name="domaine_ip", + field=models.GenericIPAddressField( + blank=True, unique=True, null=True, protocol="IPv4" + ), + ) ] diff --git a/machines/migrations/0029_iptype_domaine_range.py b/machines/migrations/0029_iptype_domaine_range.py index 80b9fdee..30159868 100644 --- a/machines/migrations/0029_iptype_domaine_range.py +++ b/machines/migrations/0029_iptype_domaine_range.py @@ -29,14 +29,19 @@ import django.core.validators class Migration(migrations.Migration): - dependencies = [ - ('machines', '0028_iptype_domaine_ip'), - ] + dependencies = [("machines", "0028_iptype_domaine_ip")] operations = [ migrations.AddField( - model_name='iptype', - name='domaine_range', - field=models.IntegerField(null=True, validators=[django.core.validators.MinValueValidator(8), django.core.validators.MaxValueValidator(32)], blank=True), - ), + model_name="iptype", + name="domaine_range", + field=models.IntegerField( + null=True, + validators=[ + django.core.validators.MinValueValidator(8), + django.core.validators.MaxValueValidator(32), + ], + blank=True, + ), + ) ] diff --git a/machines/migrations/0030_auto_20161118_1730.py b/machines/migrations/0030_auto_20161118_1730.py index f6c67314..e958fe3e 100644 --- a/machines/migrations/0030_auto_20161118_1730.py +++ b/machines/migrations/0030_auto_20161118_1730.py @@ -29,24 +29,28 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0029_iptype_domaine_range'), - ] + dependencies = [("machines", "0029_iptype_domaine_range")] operations = [ migrations.AddField( - model_name='alias', - name='extension', - field=models.ForeignKey(to='machines.Extension', default=1, on_delete=django.db.models.deletion.PROTECT), + model_name="alias", + name="extension", + field=models.ForeignKey( + to="machines.Extension", + default=1, + on_delete=django.db.models.deletion.PROTECT, + ), preserve_default=False, ), migrations.AlterField( - model_name='alias', - name='alias', - field=models.CharField(max_length=255, help_text='Obligatoire et unique, ne doit pas comporter de points'), + model_name="alias", + name="alias", + field=models.CharField( + max_length=255, + help_text="Obligatoire et unique, ne doit pas comporter de points", + ), ), migrations.AlterUniqueTogether( - name='alias', - unique_together=set([('alias', 'extension')]), + name="alias", unique_together=set([("alias", "extension")]) ), ] diff --git a/machines/migrations/0031_auto_20161119_1709.py b/machines/migrations/0031_auto_20161119_1709.py index 87814fcc..ae2ff82f 100644 --- a/machines/migrations/0031_auto_20161119_1709.py +++ b/machines/migrations/0031_auto_20161119_1709.py @@ -30,36 +30,78 @@ import django.core.validators class Migration(migrations.Migration): - dependencies = [ - ('machines', '0030_auto_20161118_1730'), - ] + dependencies = [("machines", "0030_auto_20161118_1730")] operations = [ migrations.CreateModel( - name='Mx', + name="Mx", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)), - ('priority', models.IntegerField(unique=True)), - ('name', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='machines.Alias')), - ('zone', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.Extension')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + verbose_name="ID", + serialize=False, + ), + ), + ("priority", models.IntegerField(unique=True)), + ( + "name", + models.OneToOneField( + on_delete=django.db.models.deletion.PROTECT, to="machines.Alias" + ), + ), + ( + "zone", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="machines.Extension", + ), + ), ], ), migrations.CreateModel( - name='Ns', + name="Ns", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)), - ('interface', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='machines.Interface')), - ('zone', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.Extension')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + verbose_name="ID", + serialize=False, + ), + ), + ( + "interface", + models.OneToOneField( + on_delete=django.db.models.deletion.PROTECT, + to="machines.Interface", + ), + ), + ( + "zone", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="machines.Extension", + ), + ), ], ), migrations.AlterField( - model_name='iptype', - name='domaine_ip', - field=models.GenericIPAddressField(protocol='IPv4'), + model_name="iptype", + name="domaine_ip", + field=models.GenericIPAddressField(protocol="IPv4"), ), migrations.AlterField( - model_name='iptype', - name='domaine_range', - field=models.IntegerField(validators=[django.core.validators.MinValueValidator(8), django.core.validators.MaxValueValidator(32)]), + model_name="iptype", + name="domaine_range", + field=models.IntegerField( + validators=[ + django.core.validators.MinValueValidator(8), + django.core.validators.MaxValueValidator(32), + ] + ), ), ] diff --git a/machines/migrations/0032_auto_20161119_1850.py b/machines/migrations/0032_auto_20161119_1850.py index 15daff9a..7a788b42 100644 --- a/machines/migrations/0032_auto_20161119_1850.py +++ b/machines/migrations/0032_auto_20161119_1850.py @@ -29,19 +29,22 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0031_auto_20161119_1709'), - ] + dependencies = [("machines", "0031_auto_20161119_1709")] operations = [ migrations.AddField( - model_name='extension', - name='origin', - field=models.OneToOneField(null=True, to='machines.IpList', blank=True, on_delete=django.db.models.deletion.PROTECT), + model_name="extension", + name="origin", + field=models.OneToOneField( + null=True, + to="machines.IpList", + blank=True, + on_delete=django.db.models.deletion.PROTECT, + ), ), migrations.AlterField( - model_name='extension', - name='name', + model_name="extension", + name="name", field=models.CharField(max_length=255, unique=True), ), ] diff --git a/machines/migrations/0033_extension_need_infra.py b/machines/migrations/0033_extension_need_infra.py index 9a68f1de..1f42f153 100644 --- a/machines/migrations/0033_extension_need_infra.py +++ b/machines/migrations/0033_extension_need_infra.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0032_auto_20161119_1850'), - ] + dependencies = [("machines", "0032_auto_20161119_1850")] operations = [ migrations.AddField( - model_name='extension', - name='need_infra', + model_name="extension", + name="need_infra", field=models.BooleanField(default=False), - ), + ) ] diff --git a/machines/migrations/0034_iplist_need_infra.py b/machines/migrations/0034_iplist_need_infra.py index 2eae9caa..0e0dad85 100644 --- a/machines/migrations/0034_iplist_need_infra.py +++ b/machines/migrations/0034_iplist_need_infra.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0033_extension_need_infra'), - ] + dependencies = [("machines", "0033_extension_need_infra")] operations = [ migrations.AddField( - model_name='iplist', - name='need_infra', + model_name="iplist", + name="need_infra", field=models.BooleanField(default=False), - ), + ) ] diff --git a/machines/migrations/0035_auto_20161224_1201.py b/machines/migrations/0035_auto_20161224_1201.py index 742568eb..2f46f048 100644 --- a/machines/migrations/0035_auto_20161224_1201.py +++ b/machines/migrations/0035_auto_20161224_1201.py @@ -28,10 +28,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0034_iplist_need_infra'), - ] + dependencies = [("machines", "0034_iplist_need_infra")] - operations = [ - migrations.RenameModel('Alias', 'Domain') - ] + operations = [migrations.RenameModel("Alias", "Domain")] diff --git a/machines/migrations/0036_auto_20161224_1204.py b/machines/migrations/0036_auto_20161224_1204.py index 58de1c85..80ee84be 100644 --- a/machines/migrations/0036_auto_20161224_1204.py +++ b/machines/migrations/0036_auto_20161224_1204.py @@ -28,23 +28,16 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0035_auto_20161224_1201'), - ] + dependencies = [("machines", "0035_auto_20161224_1201")] operations = [ - migrations.RenameField( - model_name='domain', - old_name='alias', - new_name='name', - ), + migrations.RenameField(model_name="domain", old_name="alias", new_name="name"), migrations.AlterField( - model_name='domain', - name='interface_parent', - field=models.ForeignKey(to='machines.Interface', null=True, blank=True), + model_name="domain", + name="interface_parent", + field=models.ForeignKey(to="machines.Interface", null=True, blank=True), ), migrations.AlterUniqueTogether( - name='domain', - unique_together=set([('name', 'extension')]), + name="domain", unique_together=set([("name", "extension")]) ), ] diff --git a/machines/migrations/0037_domain_cname.py b/machines/migrations/0037_domain_cname.py index 9e33c5d9..08570133 100644 --- a/machines/migrations/0037_domain_cname.py +++ b/machines/migrations/0037_domain_cname.py @@ -28,14 +28,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0036_auto_20161224_1204'), - ] + dependencies = [("machines", "0036_auto_20161224_1204")] operations = [ migrations.AddField( - model_name='domain', - name='cname', - field=models.OneToOneField(related_name='related_domain', null=True, to='machines.Domain', blank=True), - ), + model_name="domain", + name="cname", + field=models.OneToOneField( + related_name="related_domain", + null=True, + to="machines.Domain", + blank=True, + ), + ) ] diff --git a/machines/migrations/0038_auto_20161224_1721.py b/machines/migrations/0038_auto_20161224_1721.py index 5e481e42..0056c308 100644 --- a/machines/migrations/0038_auto_20161224_1721.py +++ b/machines/migrations/0038_auto_20161224_1721.py @@ -28,14 +28,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0037_domain_cname'), - ] + dependencies = [("machines", "0037_domain_cname")] operations = [ migrations.AlterField( - model_name='domain', - name='cname', - field=models.ForeignKey(null=True, to='machines.Domain', related_name='related_domain', blank=True), - ), + model_name="domain", + name="cname", + field=models.ForeignKey( + null=True, + to="machines.Domain", + related_name="related_domain", + blank=True, + ), + ) ] diff --git a/machines/migrations/0039_auto_20161224_1732.py b/machines/migrations/0039_auto_20161224_1732.py index e7bcc6f2..8136fc9c 100644 --- a/machines/migrations/0039_auto_20161224_1732.py +++ b/machines/migrations/0039_auto_20161224_1732.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0038_auto_20161224_1721'), - ] + dependencies = [("machines", "0038_auto_20161224_1721")] operations = [ migrations.AlterField( - model_name='domain', - name='interface_parent', - field=models.OneToOneField(blank=True, null=True, to='machines.Interface'), - ), + model_name="domain", + name="interface_parent", + field=models.OneToOneField(blank=True, null=True, to="machines.Interface"), + ) ] diff --git a/machines/migrations/0040_remove_interface_dns.py b/machines/migrations/0040_remove_interface_dns.py index 38c2a107..232e65e7 100644 --- a/machines/migrations/0040_remove_interface_dns.py +++ b/machines/migrations/0040_remove_interface_dns.py @@ -28,13 +28,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0039_auto_20161224_1732'), - ] + dependencies = [("machines", "0039_auto_20161224_1732")] - operations = [ - migrations.RemoveField( - model_name='interface', - name='dns', - ), - ] + operations = [migrations.RemoveField(model_name="interface", name="dns")] diff --git a/machines/migrations/0041_remove_ns_interface.py b/machines/migrations/0041_remove_ns_interface.py index a4808c67..8906abd5 100644 --- a/machines/migrations/0041_remove_ns_interface.py +++ b/machines/migrations/0041_remove_ns_interface.py @@ -28,13 +28,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0040_remove_interface_dns'), - ] + dependencies = [("machines", "0040_remove_interface_dns")] - operations = [ - migrations.RemoveField( - model_name='ns', - name='interface', - ), - ] + operations = [migrations.RemoveField(model_name="ns", name="interface")] diff --git a/machines/migrations/0042_ns_ns.py b/machines/migrations/0042_ns_ns.py index 009715aa..1c0d27d1 100644 --- a/machines/migrations/0042_ns_ns.py +++ b/machines/migrations/0042_ns_ns.py @@ -29,15 +29,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0041_remove_ns_interface'), - ] + dependencies = [("machines", "0041_remove_ns_interface")] operations = [ migrations.AddField( - model_name='ns', - name='ns', - field=models.OneToOneField(to='machines.Domain', default=1, on_delete=django.db.models.deletion.PROTECT), + model_name="ns", + name="ns", + field=models.OneToOneField( + to="machines.Domain", + default=1, + on_delete=django.db.models.deletion.PROTECT, + ), preserve_default=False, - ), + ) ] diff --git a/machines/migrations/0043_auto_20170721_0350.py b/machines/migrations/0043_auto_20170721_0350.py index 497367bf..607d6949 100644 --- a/machines/migrations/0043_auto_20170721_0350.py +++ b/machines/migrations/0043_auto_20170721_0350.py @@ -8,18 +8,15 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0042_ns_ns'), - ] + dependencies = [("machines", "0042_ns_ns")] operations = [ - migrations.RemoveField( - model_name='iplist', - name='need_infra', - ), + migrations.RemoveField(model_name="iplist", name="need_infra"), migrations.AlterField( - model_name='iplist', - name='ip_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='machines.IpType'), + model_name="iplist", + name="ip_type", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="machines.IpType" + ), ), ] diff --git a/machines/migrations/0044_auto_20170808_0233.py b/machines/migrations/0044_auto_20170808_0233.py index 864505a2..9028a865 100644 --- a/machines/migrations/0044_auto_20170808_0233.py +++ b/machines/migrations/0044_auto_20170808_0233.py @@ -8,32 +8,63 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0043_auto_20170721_0350'), - ] + dependencies = [("machines", "0043_auto_20170721_0350")] operations = [ migrations.CreateModel( - name='Service', + name="Service", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('service_type', models.CharField(blank=True, max_length=255, unique=True)), - ('time_regen', models.DurationField()), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "service_type", + models.CharField(blank=True, max_length=255, unique=True), + ), + ("time_regen", models.DurationField()), ], ), migrations.CreateModel( - name='Service_link', + name="Service_link", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('last_regen', models.DateTimeField()), - ('asked_regen', models.BooleanField()), - ('server', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='machines.Interface')), - ('service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='machines.Service')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("last_regen", models.DateTimeField()), + ("asked_regen", models.BooleanField()), + ( + "server", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="machines.Interface", + ), + ), + ( + "service", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="machines.Service", + ), + ), ], ), migrations.AddField( - model_name='service', - name='servers', - field=models.ManyToManyField(through='machines.Service_link', to='machines.Interface'), + model_name="service", + name="servers", + field=models.ManyToManyField( + through="machines.Service_link", to="machines.Interface" + ), ), ] diff --git a/machines/migrations/0045_auto_20170808_0348.py b/machines/migrations/0045_auto_20170808_0348.py index 16a6bb0a..b44a1a8a 100644 --- a/machines/migrations/0045_auto_20170808_0348.py +++ b/machines/migrations/0045_auto_20170808_0348.py @@ -7,19 +7,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0044_auto_20170808_0233'), - ] + dependencies = [("machines", "0044_auto_20170808_0233")] operations = [ migrations.AlterField( - model_name='service_link', - name='asked_regen', + model_name="service_link", + name="asked_regen", field=models.BooleanField(default=False), ), migrations.AlterField( - model_name='service_link', - name='last_regen', + model_name="service_link", + name="last_regen", field=models.DateTimeField(auto_now_add=True), ), ] diff --git a/machines/migrations/0046_auto_20170808_1423.py b/machines/migrations/0046_auto_20170808_1423.py index b7ffbced..86a69c6d 100644 --- a/machines/migrations/0046_auto_20170808_1423.py +++ b/machines/migrations/0046_auto_20170808_1423.py @@ -8,14 +8,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0045_auto_20170808_0348'), - ] + dependencies = [("machines", "0045_auto_20170808_0348")] operations = [ migrations.AlterField( - model_name='service', - name='time_regen', + model_name="service", + name="time_regen", field=models.DurationField(default=datetime.timedelta(0, 60)), - ), + ) ] diff --git a/machines/migrations/0047_auto_20170809_0606.py b/machines/migrations/0047_auto_20170809_0606.py index 65cd3d1f..99337be2 100644 --- a/machines/migrations/0047_auto_20170809_0606.py +++ b/machines/migrations/0047_auto_20170809_0606.py @@ -8,23 +8,24 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0046_auto_20170808_1423'), - ] + dependencies = [("machines", "0046_auto_20170808_1423")] operations = [ - migrations.RemoveField( - model_name='service', - name='time_regen', + migrations.RemoveField(model_name="service", name="time_regen"), + migrations.AddField( + model_name="service", + name="min_time_regen", + field=models.DurationField( + default=datetime.timedelta(0, 60), + help_text="Temps minimal avant nouvelle génération du service", + ), ), migrations.AddField( - model_name='service', - name='min_time_regen', - field=models.DurationField(default=datetime.timedelta(0, 60), help_text='Temps minimal avant nouvelle génération du service'), - ), - migrations.AddField( - model_name='service', - name='regular_time_regen', - field=models.DurationField(default=datetime.timedelta(0, 3600), help_text='Temps maximal avant nouvelle génération du service'), + model_name="service", + name="regular_time_regen", + field=models.DurationField( + default=datetime.timedelta(0, 3600), + help_text="Temps maximal avant nouvelle génération du service", + ), ), ] diff --git a/machines/migrations/0048_auto_20170823_2315.py b/machines/migrations/0048_auto_20170823_2315.py index 0c0a48f3..28b1fd48 100644 --- a/machines/migrations/0048_auto_20170823_2315.py +++ b/machines/migrations/0048_auto_20170823_2315.py @@ -8,14 +8,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0047_auto_20170809_0606'), - ] + dependencies = [("machines", "0047_auto_20170809_0606")] operations = [ migrations.AlterField( - model_name='iptype', - name='domaine_range', - field=models.IntegerField(validators=[django.core.validators.MinValueValidator(16), django.core.validators.MaxValueValidator(32)]), - ), + model_name="iptype", + name="domaine_range", + field=models.IntegerField( + validators=[ + django.core.validators.MinValueValidator(16), + django.core.validators.MaxValueValidator(32), + ] + ), + ) ] diff --git a/machines/migrations/0049_vlan.py b/machines/migrations/0049_vlan.py index 20a6905b..fa892bb7 100644 --- a/machines/migrations/0049_vlan.py +++ b/machines/migrations/0049_vlan.py @@ -7,18 +7,24 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0048_auto_20170823_2315'), - ] + dependencies = [("machines", "0048_auto_20170823_2315")] operations = [ migrations.CreateModel( - name='Vlan', + name="Vlan", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('vlan_id', models.IntegerField()), - ('name', models.CharField(max_length=256)), - ('comment', models.CharField(max_length=256)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("vlan_id", models.IntegerField()), + ("name", models.CharField(max_length=256)), + ("comment", models.CharField(max_length=256)), ], - ), + ) ] diff --git a/machines/migrations/0050_auto_20170826_0022.py b/machines/migrations/0050_auto_20170826_0022.py index 0f49a08b..a528fb8c 100644 --- a/machines/migrations/0050_auto_20170826_0022.py +++ b/machines/migrations/0050_auto_20170826_0022.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0049_vlan'), - ] + dependencies = [("machines", "0049_vlan")] operations = [ migrations.AlterField( - model_name='vlan', - name='comment', + model_name="vlan", + name="comment", field=models.CharField(blank=True, max_length=256), - ), + ) ] diff --git a/machines/migrations/0051_iptype_vlan.py b/machines/migrations/0051_iptype_vlan.py index 27b641b2..66570cae 100644 --- a/machines/migrations/0051_iptype_vlan.py +++ b/machines/migrations/0051_iptype_vlan.py @@ -8,14 +8,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0050_auto_20170826_0022'), - ] + dependencies = [("machines", "0050_auto_20170826_0022")] operations = [ migrations.AddField( - model_name='iptype', - name='vlan', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.Vlan'), - ), + model_name="iptype", + name="vlan", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="machines.Vlan", + ), + ) ] diff --git a/machines/migrations/0052_auto_20170828_2322.py b/machines/migrations/0052_auto_20170828_2322.py index b8ab65ca..4a3bfc1e 100644 --- a/machines/migrations/0052_auto_20170828_2322.py +++ b/machines/migrations/0052_auto_20170828_2322.py @@ -7,24 +7,19 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0051_iptype_vlan'), - ] + dependencies = [("machines", "0051_iptype_vlan")] operations = [ migrations.RenameField( - model_name='iptype', - old_name='domaine_ip', - new_name='domaine_ip_start', - ), - migrations.RemoveField( - model_name='iptype', - name='domaine_range', + model_name="iptype", old_name="domaine_ip", new_name="domaine_ip_start" ), + migrations.RemoveField(model_name="iptype", name="domaine_range"), migrations.AddField( - model_name='iptype', - name='domaine_ip_stop', - field=models.GenericIPAddressField(default='255.255.254.254', protocol='IPv4'), + model_name="iptype", + name="domaine_ip_stop", + field=models.GenericIPAddressField( + default="255.255.254.254", protocol="IPv4" + ), preserve_default=False, ), ] diff --git a/machines/migrations/0053_text.py b/machines/migrations/0053_text.py index ee7679fc..4697dab9 100644 --- a/machines/migrations/0053_text.py +++ b/machines/migrations/0053_text.py @@ -7,17 +7,23 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0052_auto_20170828_2322'), - ] + dependencies = [("machines", "0052_auto_20170828_2322")] operations = [ migrations.CreateModel( - name='Text', + name="Text", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field1', models.CharField(max_length=255)), - ('field2', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("field1", models.CharField(max_length=255)), + ("field2", models.CharField(max_length=255)), ], - ), + ) ] diff --git a/machines/migrations/0054_text_zone.py b/machines/migrations/0054_text_zone.py index f3447f35..31250fc6 100644 --- a/machines/migrations/0054_text_zone.py +++ b/machines/migrations/0054_text_zone.py @@ -8,15 +8,15 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0053_text'), - ] + dependencies = [("machines", "0053_text")] operations = [ migrations.AddField( - model_name='text', - name='zone', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.Extension'), + model_name="text", + name="zone", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="machines.Extension" + ), preserve_default=False, - ), + ) ] diff --git a/machines/migrations/0055_nas.py b/machines/migrations/0055_nas.py index 9e0466ae..260a894f 100644 --- a/machines/migrations/0055_nas.py +++ b/machines/migrations/0055_nas.py @@ -8,18 +8,38 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0054_text_zone'), - ] + dependencies = [("machines", "0054_text_zone")] operations = [ migrations.CreateModel( - name='Nas', + name="Nas", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255, unique=True)), - ('machine_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='machinetype_on_nas', to='machines.MachineType')), - ('nas_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='nas_type', to='machines.MachineType')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255, unique=True)), + ( + "machine_type", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="machinetype_on_nas", + to="machines.MachineType", + ), + ), + ( + "nas_type", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="nas_type", + to="machines.MachineType", + ), + ), ], - ), + ) ] diff --git a/machines/migrations/0056_nas_port_access_mode.py b/machines/migrations/0056_nas_port_access_mode.py index 20e5ba42..a714af49 100644 --- a/machines/migrations/0056_nas_port_access_mode.py +++ b/machines/migrations/0056_nas_port_access_mode.py @@ -7,14 +7,16 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0055_nas'), - ] + dependencies = [("machines", "0055_nas")] operations = [ migrations.AddField( - model_name='nas', - name='port_access_mode', - field=models.CharField(choices=[('802.1X', '802.1X'), ('Mac-address', 'Mac-address')], default='802.1X', max_length=32), - ), + model_name="nas", + name="port_access_mode", + field=models.CharField( + choices=[("802.1X", "802.1X"), ("Mac-address", "Mac-address")], + default="802.1X", + max_length=32, + ), + ) ] diff --git a/machines/migrations/0057_nas_autocapture_mac.py b/machines/migrations/0057_nas_autocapture_mac.py index feefa25f..37b2f68a 100644 --- a/machines/migrations/0057_nas_autocapture_mac.py +++ b/machines/migrations/0057_nas_autocapture_mac.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0056_nas_port_access_mode'), - ] + dependencies = [("machines", "0056_nas_port_access_mode")] operations = [ migrations.AddField( - model_name='nas', - name='autocapture_mac', + model_name="nas", + name="autocapture_mac", field=models.BooleanField(default=False), - ), + ) ] diff --git a/machines/migrations/0058_auto_20171002_0350.py b/machines/migrations/0058_auto_20171002_0350.py index bc6b2508..ca452b10 100644 --- a/machines/migrations/0058_auto_20171002_0350.py +++ b/machines/migrations/0058_auto_20171002_0350.py @@ -8,36 +8,68 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0057_nas_autocapture_mac'), - ] + dependencies = [("machines", "0057_nas_autocapture_mac")] operations = [ migrations.CreateModel( - name='OuverturePort', + name="OuverturePort", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('begin', models.IntegerField()), - ('end', models.IntegerField()), - ('protocole', models.CharField(choices=[('T', 'TCP'), ('U', 'UDP')], default='T', max_length=1)), - ('io', models.CharField(choices=[('I', 'IN'), ('O', 'OUT')], default='O', max_length=1)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("begin", models.IntegerField()), + ("end", models.IntegerField()), + ( + "protocole", + models.CharField( + choices=[("T", "TCP"), ("U", "UDP")], default="T", max_length=1 + ), + ), + ( + "io", + models.CharField( + choices=[("I", "IN"), ("O", "OUT")], default="O", max_length=1 + ), + ), ], ), migrations.CreateModel( - name='OuverturePortList', + name="OuverturePortList", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(help_text='Nom de la configuration des ports.', max_length=255)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField( + help_text="Nom de la configuration des ports.", max_length=255 + ), + ), ], ), migrations.AddField( - model_name='ouvertureport', - name='port_list', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='machines.OuverturePortList'), + model_name="ouvertureport", + name="port_list", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="machines.OuverturePortList", + ), ), migrations.AddField( - model_name='interface', - name='port_lists', - field=models.ManyToManyField(blank=True, to='machines.OuverturePortList'), + model_name="interface", + name="port_lists", + field=models.ManyToManyField(blank=True, to="machines.OuverturePortList"), ), ] diff --git a/machines/migrations/0059_iptype_prefix_v6.py b/machines/migrations/0059_iptype_prefix_v6.py index 464fc5e6..7df10904 100644 --- a/machines/migrations/0059_iptype_prefix_v6.py +++ b/machines/migrations/0059_iptype_prefix_v6.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0058_auto_20171002_0350'), - ] + dependencies = [("machines", "0058_auto_20171002_0350")] operations = [ migrations.AddField( - model_name='iptype', - name='prefix_v6', - field=models.GenericIPAddressField(blank=True, null=True, protocol='IPv6'), - ), + model_name="iptype", + name="prefix_v6", + field=models.GenericIPAddressField(blank=True, null=True, protocol="IPv6"), + ) ] diff --git a/machines/migrations/0060_iptype_ouverture_ports.py b/machines/migrations/0060_iptype_ouverture_ports.py index e35f398f..5515acb5 100644 --- a/machines/migrations/0060_iptype_ouverture_ports.py +++ b/machines/migrations/0060_iptype_ouverture_ports.py @@ -8,14 +8,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0059_iptype_prefix_v6'), - ] + 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'), - ), + 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/migrations/0061_auto_20171015_2033.py b/machines/migrations/0061_auto_20171015_2033.py index 6153bbd0..b89099f4 100644 --- a/machines/migrations/0061_auto_20171015_2033.py +++ b/machines/migrations/0061_auto_20171015_2033.py @@ -8,29 +8,33 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0060_iptype_ouverture_ports'), - ] + dependencies = [("machines", "0060_iptype_ouverture_ports")] operations = [ migrations.AlterField( - model_name='mx', - name='priority', + 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)]), + 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)]), + 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)]), + model_name="vlan", + name="vlan_id", + field=models.PositiveIntegerField( + validators=[django.core.validators.MaxValueValidator(4095)] + ), ), ] diff --git a/machines/migrations/0062_extension_origin_v6.py b/machines/migrations/0062_extension_origin_v6.py index 1c3d869a..d78fb49c 100644 --- a/machines/migrations/0062_extension_origin_v6.py +++ b/machines/migrations/0062_extension_origin_v6.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0061_auto_20171015_2033'), - ] + dependencies = [("machines", "0061_auto_20171015_2033")] operations = [ migrations.AddField( - model_name='extension', - name='origin_v6', - field=models.GenericIPAddressField(blank=True, null=True, protocol='IPv6'), - ), + model_name="extension", + name="origin_v6", + field=models.GenericIPAddressField(blank=True, null=True, protocol="IPv6"), + ) ] diff --git a/machines/migrations/0063_auto_20171020_0040.py b/machines/migrations/0063_auto_20171020_0040.py index 0e049881..8b9b7d24 100644 --- a/machines/migrations/0063_auto_20171020_0040.py +++ b/machines/migrations/0063_auto_20171020_0040.py @@ -10,26 +10,66 @@ import machines.models class Migration(migrations.Migration): dependencies = [ - ('machines', '0062_extension_origin_v6'), - ('reversion', '0001_squashed_0004_auto_20160611_1202') + ("machines", "0062_extension_origin_v6"), + ("reversion", "0001_squashed_0004_auto_20160611_1202"), ] operations = [ migrations.CreateModel( - name='SOA', + name="SOA", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), - ('mail', models.EmailField(help_text='Email du contact pour la zone', max_length=254)), - ('refresh', models.PositiveIntegerField(default=86400, help_text='Secondes avant que les DNS secondaires doivent demander le serial du DNS primaire pour détecter une modification')), - ('retry', models.PositiveIntegerField(default=7200, help_text='Secondes avant que les DNS secondaires fassent une nouvelle demande de serial en cas de timeout du DNS primaire')), - ('expire', models.PositiveIntegerField(default=3600000, help_text='Secondes après lesquelles les DNS secondaires arrêtent de de répondre aux requêtes en cas de timeout du DNS primaire')), - ('ttl', models.PositiveIntegerField(default=172800, help_text='Time To Live')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), + ( + "mail", + models.EmailField( + help_text="Email du contact pour la zone", max_length=254 + ), + ), + ( + "refresh", + models.PositiveIntegerField( + default=86400, + help_text="Secondes avant que les DNS secondaires doivent demander le serial du DNS primaire pour détecter une modification", + ), + ), + ( + "retry", + models.PositiveIntegerField( + default=7200, + help_text="Secondes avant que les DNS secondaires fassent une nouvelle demande de serial en cas de timeout du DNS primaire", + ), + ), + ( + "expire", + models.PositiveIntegerField( + default=3600000, + help_text="Secondes après lesquelles les DNS secondaires arrêtent de de répondre aux requêtes en cas de timeout du DNS primaire", + ), + ), + ( + "ttl", + models.PositiveIntegerField( + default=172800, help_text="Time To Live" + ), + ), ], ), migrations.AddField( - model_name='extension', - name='soa', - field=models.ForeignKey(default=machines.models.SOA.new_default_soa, on_delete=django.db.models.deletion.CASCADE, to='machines.SOA'), + model_name="extension", + name="soa", + field=models.ForeignKey( + default=machines.models.SOA.new_default_soa, + on_delete=django.db.models.deletion.CASCADE, + to="machines.SOA", + ), ), ] diff --git a/machines/migrations/0064_auto_20171115_0253.py b/machines/migrations/0064_auto_20171115_0253.py index a028e2cb..0c644b46 100644 --- a/machines/migrations/0064_auto_20171115_0253.py +++ b/machines/migrations/0064_auto_20171115_0253.py @@ -7,14 +7,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0063_auto_20171020_0040'), - ] + dependencies = [("machines", "0063_auto_20171020_0040")] operations = [ migrations.AlterField( - model_name='text', - name='field2', - field=models.TextField(max_length=2047), - ), + model_name="text", name="field2", field=models.TextField(max_length=2047) + ) ] diff --git a/machines/migrations/0065_auto_20171115_1514.py b/machines/migrations/0065_auto_20171115_1514.py index c8c5699b..d5b11c9a 100644 --- a/machines/migrations/0065_auto_20171115_1514.py +++ b/machines/migrations/0065_auto_20171115_1514.py @@ -7,13 +7,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('machines', '0064_auto_20171115_0253'), - ] + dependencies = [("machines", "0064_auto_20171115_0253")] - operations = [ - migrations.RenameModel( - old_name='Text', - new_name='Txt', - ), - ] + operations = [migrations.RenameModel(old_name="Text", new_name="Txt")] diff --git a/machines/migrations/0066_srv.py b/machines/migrations/0066_srv.py index 94b7d0ce..895806b7 100644 --- a/machines/migrations/0066_srv.py +++ b/machines/migrations/0066_srv.py @@ -9,23 +9,68 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0065_auto_20171115_1514'), - ] + dependencies = [("machines", "0065_auto_20171115_1514")] operations = [ migrations.CreateModel( - name='Srv', + name="Srv", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('service', models.CharField(max_length=31)), - ('protocole', models.CharField(choices=[('TCP', 'TCP'), ('UDP', 'UDP')], default='TCP', max_length=3)), - ('ttl', models.PositiveIntegerField(default=172800, help_text='Time To Live')), - ('priority', models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(65535)])), - ('weight', models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(65535)])), - ('port', models.PositiveIntegerField(validators=[django.core.validators.MaxValueValidator(65535)])), - ('extension', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.Extension')), - ('target', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.Domain')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("service", models.CharField(max_length=31)), + ( + "protocole", + models.CharField( + choices=[("TCP", "TCP"), ("UDP", "UDP")], + default="TCP", + max_length=3, + ), + ), + ( + "ttl", + models.PositiveIntegerField( + default=172800, help_text="Time To Live" + ), + ), + ( + "priority", + models.PositiveIntegerField( + validators=[django.core.validators.MaxValueValidator(65535)] + ), + ), + ( + "weight", + models.PositiveIntegerField( + validators=[django.core.validators.MaxValueValidator(65535)] + ), + ), + ( + "port", + models.PositiveIntegerField( + validators=[django.core.validators.MaxValueValidator(65535)] + ), + ), + ( + "extension", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="machines.Extension", + ), + ), + ( + "target", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="machines.Domain", + ), + ), ], - ), + ) ] diff --git a/machines/migrations/0067_auto_20171116_0152.py b/machines/migrations/0067_auto_20171116_0152.py index dec7f865..095210de 100644 --- a/machines/migrations/0067_auto_20171116_0152.py +++ b/machines/migrations/0067_auto_20171116_0152.py @@ -9,29 +9,40 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0066_srv'), - ] + dependencies = [("machines", "0066_srv")] operations = [ migrations.AlterField( - model_name='srv', - name='port', - field=models.PositiveIntegerField(help_text='Port (tcp/udp)', validators=[django.core.validators.MaxValueValidator(65535)]), + model_name="srv", + name="port", + field=models.PositiveIntegerField( + help_text="Port (tcp/udp)", + validators=[django.core.validators.MaxValueValidator(65535)], + ), ), migrations.AlterField( - model_name='srv', - name='priority', - field=models.PositiveIntegerField(help_text="La priorité du serveur cible (valeur entière non négative, plus elle est faible, plus ce serveur sera utilisé s'il est disponible)", validators=[django.core.validators.MaxValueValidator(65535)]), + model_name="srv", + name="priority", + field=models.PositiveIntegerField( + help_text="La priorité du serveur cible (valeur entière non négative, plus elle est faible, plus ce serveur sera utilisé s'il est disponible)", + validators=[django.core.validators.MaxValueValidator(65535)], + ), ), migrations.AlterField( - model_name='srv', - name='target', - field=models.ForeignKey(help_text='Serveur cible', on_delete=django.db.models.deletion.PROTECT, to='machines.Domain'), + model_name="srv", + name="target", + field=models.ForeignKey( + help_text="Serveur cible", + on_delete=django.db.models.deletion.PROTECT, + to="machines.Domain", + ), ), migrations.AlterField( - model_name='srv', - name='weight', - field=models.PositiveIntegerField(help_text='Poids relatif pour les enregistrements de même priorité (valeur entière de 0 à 65535)', validators=[django.core.validators.MaxValueValidator(65535)]), + model_name="srv", + name="weight", + field=models.PositiveIntegerField( + help_text="Poids relatif pour les enregistrements de même priorité (valeur entière de 0 à 65535)", + validators=[django.core.validators.MaxValueValidator(65535)], + ), ), ] diff --git a/machines/migrations/0068_auto_20171116_0252.py b/machines/migrations/0068_auto_20171116_0252.py index 781f1038..1cf0b6f0 100644 --- a/machines/migrations/0068_auto_20171116_0252.py +++ b/machines/migrations/0068_auto_20171116_0252.py @@ -9,34 +9,55 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0067_auto_20171116_0152'), - ] + dependencies = [("machines", "0067_auto_20171116_0152")] operations = [ migrations.AlterField( - model_name='extension', - name='name', - field=models.CharField(help_text='Nom de la zone, doit commencer par un point (.example.org)', max_length=255, unique=True), + model_name="extension", + name="name", + field=models.CharField( + help_text="Nom de la zone, doit commencer par un point (.example.org)", + max_length=255, + unique=True, + ), ), migrations.AlterField( - model_name='extension', - name='origin', - field=models.OneToOneField(blank=True, help_text='Enregistrement A associé à la zone', null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.IpList'), + model_name="extension", + name="origin", + field=models.OneToOneField( + blank=True, + help_text="Enregistrement A associé à la zone", + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="machines.IpList", + ), ), migrations.AlterField( - model_name='extension', - name='origin_v6', - field=models.GenericIPAddressField(blank=True, help_text='Enregistremen AAAA associé à la zone', null=True, protocol='IPv6'), + model_name="extension", + name="origin_v6", + field=models.GenericIPAddressField( + blank=True, + help_text="Enregistremen AAAA associé à la zone", + null=True, + protocol="IPv6", + ), ), migrations.AlterField( - model_name='srv', - name='priority', - field=models.PositiveIntegerField(default=0, help_text="La priorité du serveur cible (valeur entière non négative, plus elle est faible, plus ce serveur sera utilisé s'il est disponible)", validators=[django.core.validators.MaxValueValidator(65535)]), + model_name="srv", + name="priority", + field=models.PositiveIntegerField( + default=0, + help_text="La priorité du serveur cible (valeur entière non négative, plus elle est faible, plus ce serveur sera utilisé s'il est disponible)", + validators=[django.core.validators.MaxValueValidator(65535)], + ), ), migrations.AlterField( - model_name='srv', - name='weight', - field=models.PositiveIntegerField(default=0, help_text='Poids relatif pour les enregistrements de même priorité (valeur entière de 0 à 65535)', validators=[django.core.validators.MaxValueValidator(65535)]), + model_name="srv", + name="weight", + field=models.PositiveIntegerField( + default=0, + help_text="Poids relatif pour les enregistrements de même priorité (valeur entière de 0 à 65535)", + validators=[django.core.validators.MaxValueValidator(65535)], + ), ), ] diff --git a/machines/migrations/0069_auto_20171116_0822.py b/machines/migrations/0069_auto_20171116_0822.py index 90d4b309..8b880635 100644 --- a/machines/migrations/0069_auto_20171116_0822.py +++ b/machines/migrations/0069_auto_20171116_0822.py @@ -7,14 +7,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0068_auto_20171116_0252'), - ] + dependencies = [("machines", "0068_auto_20171116_0252")] operations = [ migrations.AlterField( - model_name='extension', - name='origin_v6', - field=models.GenericIPAddressField(blank=True, help_text='Enregistrement AAAA associé à la zone', null=True, protocol='IPv6'), - ), + model_name="extension", + name="origin_v6", + field=models.GenericIPAddressField( + blank=True, + help_text="Enregistrement AAAA associé à la zone", + null=True, + protocol="IPv6", + ), + ) ] diff --git a/machines/migrations/0070_auto_20171231_1947.py b/machines/migrations/0070_auto_20171231_1947.py index ef441d01..52fec594 100644 --- a/machines/migrations/0070_auto_20171231_1947.py +++ b/machines/migrations/0070_auto_20171231_1947.py @@ -7,73 +7,101 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('machines', '0069_auto_20171116_0822'), - ] + dependencies = [("machines", "0069_auto_20171116_0822")] operations = [ migrations.AlterModelOptions( - name='domain', - options={'permissions': (('view_domain', 'Peut voir un objet domain'),)}, + name="domain", + options={"permissions": (("view_domain", "Peut voir un objet domain"),)}, ), migrations.AlterModelOptions( - name='extension', - options={'permissions': (('view_extension', 'Peut voir un objet extension'), ('use_all_extension', 'Peut utiliser toutes les extension'))}, + name="extension", + options={ + "permissions": ( + ("view_extension", "Peut voir un objet extension"), + ("use_all_extension", "Peut utiliser toutes les extension"), + ) + }, ), migrations.AlterModelOptions( - name='interface', - options={'permissions': (('view_interface', 'Peut voir un objet interface'),)}, + name="interface", + options={ + "permissions": (("view_interface", "Peut voir un objet interface"),) + }, ), migrations.AlterModelOptions( - name='iplist', - options={'permissions': (('view_iplist', 'Peut voir un objet iplist'),)}, + name="iplist", + options={"permissions": (("view_iplist", "Peut voir un objet iplist"),)}, ), migrations.AlterModelOptions( - name='iptype', - options={'permissions': (('view_iptype', 'Peut voir un objet iptype'), ('use_all_iptype', 'Peut utiliser tous les iptype'))}, + name="iptype", + options={ + "permissions": ( + ("view_iptype", "Peut voir un objet iptype"), + ("use_all_iptype", "Peut utiliser tous les iptype"), + ) + }, ), migrations.AlterModelOptions( - name='machine', - options={'permissions': (('view_machine', 'Peut voir un objet machine quelquonque'), ('change_machine_user', "Peut changer le propriétaire d'une machine"))}, + name="machine", + options={ + "permissions": ( + ("view_machine", "Peut voir un objet machine quelquonque"), + ( + "change_machine_user", + "Peut changer le propriétaire d'une machine", + ), + ) + }, ), migrations.AlterModelOptions( - name='machinetype', - options={'permissions': (('view_machinetype', 'Peut voir un objet machinetype'), ('use_all_machinetype', "Peut utiliser n'importe quel type de machine"))}, + name="machinetype", + options={ + "permissions": ( + ("view_machinetype", "Peut voir un objet machinetype"), + ( + "use_all_machinetype", + "Peut utiliser n'importe quel type de machine", + ), + ) + }, ), migrations.AlterModelOptions( - name='mx', - options={'permissions': (('view_mx', 'Peut voir un objet mx'),)}, + name="mx", options={"permissions": (("view_mx", "Peut voir un objet mx"),)} ), migrations.AlterModelOptions( - name='nas', - options={'permissions': (('view_nas', 'Peut voir un objet Nas'),)}, + name="nas", + options={"permissions": (("view_nas", "Peut voir un objet Nas"),)}, ), migrations.AlterModelOptions( - name='ns', - options={'permissions': (('view_nx', 'Peut voir un objet nx'),)}, + name="ns", options={"permissions": (("view_nx", "Peut voir un objet nx"),)} ), migrations.AlterModelOptions( - name='ouvertureportlist', - options={'permissions': (('view_ouvertureportlist', 'Peut voir un objet ouvertureport'),)}, + name="ouvertureportlist", + options={ + "permissions": ( + ("view_ouvertureportlist", "Peut voir un objet ouvertureport"), + ) + }, ), migrations.AlterModelOptions( - name='service', - options={'permissions': (('view_service', 'Peut voir un objet service'),)}, + name="service", + options={"permissions": (("view_service", "Peut voir un objet service"),)}, ), migrations.AlterModelOptions( - name='soa', - options={'permissions': (('view_soa', 'Peut voir un objet soa'),)}, + name="soa", + options={"permissions": (("view_soa", "Peut voir un objet soa"),)}, ), migrations.AlterModelOptions( - name='srv', - options={'permissions': (('view_soa', 'Peut voir un objet soa'),)}, + name="srv", + options={"permissions": (("view_soa", "Peut voir un objet soa"),)}, ), migrations.AlterModelOptions( - name='txt', - options={'permissions': (('view_txt', 'Peut voir un objet txt'),)}, + name="txt", + options={"permissions": (("view_txt", "Peut voir un objet txt"),)}, ), migrations.AlterModelOptions( - name='vlan', - options={'permissions': (('view_vlan', 'Peut voir un objet vlan'),)}, + name="vlan", + options={"permissions": (("view_vlan", "Peut voir un objet vlan"),)}, ), ] diff --git a/machines/migrations/0071_auto_20171231_2100.py b/machines/migrations/0071_auto_20171231_2100.py index 776edd82..1545f0b1 100644 --- a/machines/migrations/0071_auto_20171231_2100.py +++ b/machines/migrations/0071_auto_20171231_2100.py @@ -7,13 +7,10 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('machines', '0070_auto_20171231_1947'), - ] + dependencies = [("machines", "0070_auto_20171231_1947")] operations = [ migrations.AlterModelOptions( - name='ns', - options={'permissions': (('view_ns', 'Peut voir un objet ns'),)}, - ), + name="ns", options={"permissions": (("view_ns", "Peut voir un objet ns"),)} + ) ] diff --git a/machines/migrations/0072_auto_20180108_1822.py b/machines/migrations/0072_auto_20180108_1822.py index 64999764..c3cd72da 100644 --- a/machines/migrations/0072_auto_20180108_1822.py +++ b/machines/migrations/0072_auto_20180108_1822.py @@ -7,13 +7,19 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('machines', '0071_auto_20171231_2100'), - ] + dependencies = [("machines", "0071_auto_20171231_2100")] operations = [ migrations.AlterModelOptions( - name='interface', - options={'permissions': (('view_interface', 'Peut voir un objet interface'), ('change_interface_machine', "Peut changer le propriétaire d'une interface"))}, - ), + name="interface", + options={ + "permissions": ( + ("view_interface", "Peut voir un objet interface"), + ( + "change_interface_machine", + "Peut changer le propriétaire d'une interface", + ), + ) + }, + ) ] diff --git a/machines/migrations/0073_auto_20180128_2203.py b/machines/migrations/0073_auto_20180128_2203.py index b09b9c47..a79689fe 100644 --- a/machines/migrations/0073_auto_20180128_2203.py +++ b/machines/migrations/0073_auto_20180128_2203.py @@ -8,22 +8,33 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0072_auto_20180108_1822'), - ] + dependencies = [("machines", "0072_auto_20180108_1822")] operations = [ migrations.CreateModel( - name='Ipv6List', + name="Ipv6List", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('ipv6', models.GenericIPAddressField(protocol='IPv6', unique=True)), - ('slaac_ip', models.BooleanField(default=False)), - ('interface', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='machines.Interface')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("ipv6", models.GenericIPAddressField(protocol="IPv6", unique=True)), + ("slaac_ip", models.BooleanField(default=False)), + ( + "interface", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="machines.Interface", + ), + ), ], ), migrations.AlterUniqueTogether( - name='ipv6list', - unique_together=set([('interface', 'slaac_ip')]), + name="ipv6list", unique_together=set([("interface", "slaac_ip")]) ), ] diff --git a/machines/migrations/0074_auto_20180129_0352.py b/machines/migrations/0074_auto_20180129_0352.py index 298f2a8e..f61ded5e 100644 --- a/machines/migrations/0074_auto_20180129_0352.py +++ b/machines/migrations/0074_auto_20180129_0352.py @@ -7,13 +7,19 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('machines', '0073_auto_20180128_2203'), - ] + dependencies = [("machines", "0073_auto_20180128_2203")] operations = [ migrations.AlterModelOptions( - name='ipv6list', - options={'permissions': (('view_ipv6list', 'Peut voir un objet ipv6'), ('change_ipv6list_slaac_ip', 'Peut changer la valeur slaac sur une ipv6'))}, - ), + name="ipv6list", + options={ + "permissions": ( + ("view_ipv6list", "Peut voir un objet ipv6"), + ( + "change_ipv6list_slaac_ip", + "Peut changer la valeur slaac sur une ipv6", + ), + ) + }, + ) ] diff --git a/machines/migrations/0075_auto_20180130_0052.py b/machines/migrations/0075_auto_20180130_0052.py index 473824b8..befd100c 100644 --- a/machines/migrations/0075_auto_20180130_0052.py +++ b/machines/migrations/0075_auto_20180130_0052.py @@ -7,13 +7,8 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('machines', '0074_auto_20180129_0352'), - ] + dependencies = [("machines", "0074_auto_20180129_0352")] operations = [ - migrations.AlterUniqueTogether( - name='ipv6list', - unique_together=set([]), - ), + migrations.AlterUniqueTogether(name="ipv6list", unique_together=set([])) ] diff --git a/machines/migrations/0076_auto_20180130_1623.py b/machines/migrations/0076_auto_20180130_1623.py index 9aab328b..906e11e2 100644 --- a/machines/migrations/0076_auto_20180130_1623.py +++ b/machines/migrations/0076_auto_20180130_1623.py @@ -8,14 +8,16 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0075_auto_20180130_0052'), - ] + dependencies = [("machines", "0075_auto_20180130_0052")] operations = [ migrations.AlterField( - model_name='ipv6list', - name='interface', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ipv6list', to='machines.Interface'), - ), + model_name="ipv6list", + name="interface", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="ipv6list", + to="machines.Interface", + ), + ) ] diff --git a/machines/migrations/0077_auto_20180409_2243.py b/machines/migrations/0077_auto_20180409_2243.py index 3ac63072..33114d33 100644 --- a/machines/migrations/0077_auto_20180409_2243.py +++ b/machines/migrations/0077_auto_20180409_2243.py @@ -8,14 +8,18 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0076_auto_20180130_1623'), - ] + dependencies = [("machines", "0076_auto_20180130_1623")] operations = [ migrations.AlterField( - model_name='extension', - name='origin', - field=models.ForeignKey(blank=True, help_text='Enregistrement A associé à la zone', null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.IpList'), - ), + model_name="extension", + name="origin", + field=models.ForeignKey( + blank=True, + help_text="Enregistrement A associé à la zone", + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="machines.IpList", + ), + ) ] diff --git a/machines/migrations/0078_auto_20180415_1252.py b/machines/migrations/0078_auto_20180415_1252.py index 909ae847..161b9303 100644 --- a/machines/migrations/0078_auto_20180415_1252.py +++ b/machines/migrations/0078_auto_20180415_1252.py @@ -8,14 +8,16 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0077_auto_20180409_2243'), - ] + dependencies = [("machines", "0077_auto_20180409_2243")] operations = [ migrations.AlterField( - model_name='srv', - name='priority', - field=models.PositiveIntegerField(default=0, help_text="La priorité du serveur cible (valeur entière non négative, plus elle est faible, plus ce serveur sera utilisé s'il est disponible)", validators=[django.core.validators.MaxValueValidator(65535)]), - ), + model_name="srv", + name="priority", + field=models.PositiveIntegerField( + default=0, + help_text="La priorité du serveur cible (valeur entière non négative, plus elle est faible, plus ce serveur sera utilisé s'il est disponible)", + validators=[django.core.validators.MaxValueValidator(65535)], + ), + ) ] diff --git a/machines/migrations/0079_auto_20180416_0107.py b/machines/migrations/0079_auto_20180416_0107.py index df73f74b..a2244ada 100644 --- a/machines/migrations/0079_auto_20180416_0107.py +++ b/machines/migrations/0079_auto_20180416_0107.py @@ -4,33 +4,31 @@ from __future__ import unicode_literals from django.db import migrations + def rename_permission_soa_to_srv(apps, schema_editor): - Permission = apps.get_model('auth', 'Permission') + Permission = apps.get_model("auth", "Permission") # The Permission called 'view_soa' but in the Srv object try: to_rename = Permission.objects.get( - codename='view_soa', - content_type__model='srv' + codename="view_soa", content_type__model="srv" ) except Permission.DoesNotExist: # The permission is missing so no problem pass else: - to_rename.name = 'Peut voir un object srv' - to_rename.codename = 'view_srv' + to_rename.name = "Peut voir un object srv" + to_rename.codename = "view_srv" to_rename.save() class Migration(migrations.Migration): - dependencies = [ - ('machines', '0078_auto_20180415_1252'), - ] + dependencies = [("machines", "0078_auto_20180415_1252")] operations = [ migrations.RunPython(rename_permission_soa_to_srv), migrations.AlterModelOptions( - name='srv', - options={'permissions': (('view_srv', 'Peut voir un objet srv'),)}, + name="srv", + options={"permissions": (("view_srv", "Peut voir un objet srv"),)}, ), ] diff --git a/machines/migrations/0080_auto_20180502_2334.py b/machines/migrations/0080_auto_20180502_2334.py index 7097dde2..997fc151 100644 --- a/machines/migrations/0080_auto_20180502_2334.py +++ b/machines/migrations/0080_auto_20180502_2334.py @@ -8,14 +8,14 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0079_auto_20180416_0107'), - ] + dependencies = [("machines", "0079_auto_20180416_0107")] operations = [ migrations.AlterField( - model_name='ns', - name='ns', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.Domain'), - ), + model_name="ns", + name="ns", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="machines.Domain" + ), + ) ] diff --git a/machines/migrations/0081_auto_20180521_1413.py b/machines/migrations/0081_auto_20180521_1413.py index 7948796a..7e5509aa 100644 --- a/machines/migrations/0081_auto_20180521_1413.py +++ b/machines/migrations/0081_auto_20180521_1413.py @@ -8,14 +8,14 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0080_auto_20180502_2334'), - ] + dependencies = [("machines", "0080_auto_20180502_2334")] operations = [ migrations.AlterField( - model_name='extension', - name='soa', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='machines.SOA'), - ), + model_name="extension", + name="soa", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="machines.SOA" + ), + ) ] diff --git a/machines/migrations/0082_auto_20180525_2209.py b/machines/migrations/0082_auto_20180525_2209.py index 1da2370c..3691946d 100644 --- a/machines/migrations/0082_auto_20180525_2209.py +++ b/machines/migrations/0082_auto_20180525_2209.py @@ -7,13 +7,15 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('machines', '0081_auto_20180521_1413'), - ] + dependencies = [("machines", "0081_auto_20180521_1413")] operations = [ migrations.AlterModelOptions( - name='service_link', - options={'permissions': (('view_service_link', 'Peut voir un objet service_link'),)}, - ), + name="service_link", + options={ + "permissions": ( + ("view_service_link", "Peut voir un objet service_link"), + ) + }, + ) ] diff --git a/machines/migrations/0083_remove_duplicate_rights.py b/machines/migrations/0083_remove_duplicate_rights.py index 05ad2938..a4f4ec32 100644 --- a/machines/migrations/0083_remove_duplicate_rights.py +++ b/machines/migrations/0083_remove_duplicate_rights.py @@ -3,14 +3,14 @@ from __future__ import unicode_literals from django.db import migrations + def remove_permission_alias(apps, schema_editor): - Permission = apps.get_model('auth', 'Permission') - for codename in ['add_alias', 'change_alias', 'delete_alias']: + Permission = apps.get_model("auth", "Permission") + for codename in ["add_alias", "change_alias", "delete_alias"]: # Retrieve the wrong permission try: to_remove = Permission.objects.get( - codename=codename, - content_type__model='domain' + codename=codename, content_type__model="domain" ) except Permission.DoesNotExist: # The permission is missing so no problem @@ -20,13 +20,12 @@ def remove_permission_alias(apps, schema_editor): def remove_permission_text(apps, schema_editor): - Permission = apps.get_model('auth', 'Permission') - for codename in ['add_text', 'change_text', 'delete_text']: + Permission = apps.get_model("auth", "Permission") + for codename in ["add_text", "change_text", "delete_text"]: # Retrieve the wrong permission try: to_remove = Permission.objects.get( - codename=codename, - content_type__model='txt' + codename=codename, content_type__model="txt" ) except Permission.DoesNotExist: # The permission is missing so no problem @@ -37,9 +36,7 @@ def remove_permission_text(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('machines', '0082_auto_20180525_2209'), - ] + dependencies = [("machines", "0082_auto_20180525_2209")] operations = [ migrations.RunPython(remove_permission_text), diff --git a/machines/migrations/0084_dname.py b/machines/migrations/0084_dname.py index 4cbeb492..37dfe623 100644 --- a/machines/migrations/0084_dname.py +++ b/machines/migrations/0084_dname.py @@ -9,23 +9,35 @@ import re2o.mixins class Migration(migrations.Migration): - dependencies = [ - ('machines', '0083_remove_duplicate_rights'), - ] + dependencies = [("machines", "0083_remove_duplicate_rights")] operations = [ migrations.CreateModel( - name='DName', + name="DName", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('alias', models.CharField(max_length=255)), - ('zone', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.Extension')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("alias", models.CharField(max_length=255)), + ( + "zone", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="machines.Extension", + ), + ), ], options={ - 'permissions': (('view_dname', 'Can see a dname object'),), - 'verbose_name': 'DNAME entry', - 'verbose_name_plural': 'DNAME entries' + "permissions": (("view_dname", "Can see a dname object"),), + "verbose_name": "DNAME entry", + "verbose_name_plural": "DNAME entries", }, bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), - ), + ) ] diff --git a/machines/migrations/0085_sshfingerprint.py b/machines/migrations/0085_sshfingerprint.py index 47f11d07..74ca610f 100644 --- a/machines/migrations/0085_sshfingerprint.py +++ b/machines/migrations/0085_sshfingerprint.py @@ -9,25 +9,57 @@ import re2o.mixins class Migration(migrations.Migration): - dependencies = [ - ('machines', '0084_dname'), - ] + dependencies = [("machines", "0084_dname")] operations = [ migrations.CreateModel( - name='SshFp', + name="SshFp", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('pub_key_entry', models.TextField(help_text='SSH public key', max_length=2048)), - ('algo', models.CharField(choices=[('ssh-rsa', 'ssh-rsa'), ('ssh-ed25519', 'ssh-ed25519'), ('ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp256'), ('ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp384'), ('ecdsa-sha2-nistp521', 'ecdsa-sha2-nistp521')], max_length=32)), - ('comment', models.CharField(blank=True, help_text='Comment', max_length=255, null=True)), - ('machine', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='machines.Machine')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "pub_key_entry", + models.TextField(help_text="SSH public key", max_length=2048), + ), + ( + "algo", + models.CharField( + choices=[ + ("ssh-rsa", "ssh-rsa"), + ("ssh-ed25519", "ssh-ed25519"), + ("ecdsa-sha2-nistp256", "ecdsa-sha2-nistp256"), + ("ecdsa-sha2-nistp384", "ecdsa-sha2-nistp384"), + ("ecdsa-sha2-nistp521", "ecdsa-sha2-nistp521"), + ], + max_length=32, + ), + ), + ( + "comment", + models.CharField( + blank=True, help_text="Comment", max_length=255, null=True + ), + ), + ( + "machine", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="machines.Machine", + ), + ), ], options={ - 'verbose_name': 'SSHFP record', - 'verbose_name_plural': 'SSHFP records', - 'permissions': (('view_sshfp', 'Can see an SSHFP record'),), + "verbose_name": "SSHFP record", + "verbose_name_plural": "SSHFP records", + "permissions": (("view_sshfp", "Can see an SSHFP record"),), }, bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), - ), + ) ] diff --git a/machines/migrations/0086_role.py b/machines/migrations/0086_role.py index a23de26f..c0956a5f 100644 --- a/machines/migrations/0086_role.py +++ b/machines/migrations/0086_role.py @@ -8,20 +8,51 @@ import re2o.mixins class Migration(migrations.Migration): - dependencies = [ - ('machines', '0085_sshfingerprint'), - ] + dependencies = [("machines", "0085_sshfingerprint")] operations = [ migrations.CreateModel( - name='Role', + name="Role", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('role_type', models.CharField(max_length=255, unique=True)), - ('servers', models.ManyToManyField(to='machines.Interface')), - ('specific_role', models.CharField(blank=True, choices=[('dhcp-server', 'DHCP server'), ('switch-conf-server', 'Switches configuration server'), ('dns-recursif-server', 'Recursive DNS server'), ('ntp-server', 'NTP server'), ('radius-server', 'Radius server'), ('log-server', 'Log server'), ('ldap-master-server', 'LDAP master server'), ('ldap-backup-server', 'LDAP backup server'), ('smtp-server', 'SMTP server'), ('postgresql-server', 'postgreSQL server'), ('mysql-server', 'mySQL server'), ('sql-client', 'SQL client'), ('gateway', 'Gatewaw')], max_length=32, null=True)) + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("role_type", models.CharField(max_length=255, unique=True)), + ("servers", models.ManyToManyField(to="machines.Interface")), + ( + "specific_role", + models.CharField( + blank=True, + choices=[ + ("dhcp-server", "DHCP server"), + ("switch-conf-server", "Switches configuration server"), + ("dns-recursif-server", "Recursive DNS server"), + ("ntp-server", "NTP server"), + ("radius-server", "Radius server"), + ("log-server", "Log server"), + ("ldap-master-server", "LDAP master server"), + ("ldap-backup-server", "LDAP backup server"), + ("smtp-server", "SMTP server"), + ("postgresql-server", "postgreSQL server"), + ("mysql-server", "mySQL server"), + ("sql-client", "SQL client"), + ("gateway", "Gatewaw"), + ], + max_length=32, + null=True, + ), + ), ], - options={'permissions': (('view_role', 'Can view a role.'),), 'verbose_name': 'Server role'}, + options={ + "permissions": (("view_role", "Can view a role."),), + "verbose_name": "Server role", + }, bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), - ), + ) ] diff --git a/machines/migrations/0087_dnssec.py b/machines/migrations/0087_dnssec.py index cc2a25ec..de505ea5 100644 --- a/machines/migrations/0087_dnssec.py +++ b/machines/migrations/0087_dnssec.py @@ -7,19 +7,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0086_role'), - ] + dependencies = [("machines", "0086_role")] operations = [ migrations.AddField( - model_name='iptype', - name='dnssec_reverse_v4', - field=models.BooleanField(default=False, help_text='Activer DNSSEC sur le reverse DNS IPv4'), + model_name="iptype", + name="dnssec_reverse_v4", + field=models.BooleanField( + default=False, help_text="Activer DNSSEC sur le reverse DNS IPv4" + ), ), migrations.AddField( - model_name='iptype', - name='dnssec_reverse_v6', - field=models.BooleanField(default=False, help_text='Activer DNSSEC sur le reverse DNS IPv6'), + model_name="iptype", + name="dnssec_reverse_v6", + field=models.BooleanField( + default=False, help_text="Activer DNSSEC sur le reverse DNS IPv6" + ), ), ] diff --git a/machines/migrations/0088_iptype_prefix_v6_length.py b/machines/migrations/0088_iptype_prefix_v6_length.py index e061167c..5380eb41 100644 --- a/machines/migrations/0088_iptype_prefix_v6_length.py +++ b/machines/migrations/0088_iptype_prefix_v6_length.py @@ -8,14 +8,18 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0087_dnssec'), - ] + dependencies = [("machines", "0087_dnssec")] operations = [ migrations.AddField( - model_name='iptype', - name='prefix_v6_length', - field=models.IntegerField(default=64, validators=[django.core.validators.MaxValueValidator(128), django.core.validators.MinValueValidator(0)]), - ), + model_name="iptype", + name="prefix_v6_length", + field=models.IntegerField( + default=64, + validators=[ + django.core.validators.MaxValueValidator(128), + django.core.validators.MinValueValidator(0), + ], + ), + ) ] diff --git a/machines/migrations/0089_auto_20180805_1148.py b/machines/migrations/0089_auto_20180805_1148.py index 76962283..3ad70d15 100644 --- a/machines/migrations/0089_auto_20180805_1148.py +++ b/machines/migrations/0089_auto_20180805_1148.py @@ -8,14 +8,12 @@ import macaddress.fields class Migration(migrations.Migration): - dependencies = [ - ('machines', '0088_iptype_prefix_v6_length'), - ] + dependencies = [("machines", "0088_iptype_prefix_v6_length")] operations = [ migrations.AlterField( - model_name='interface', - name='mac_address', + model_name="interface", + name="mac_address", field=macaddress.fields.MACAddressField(integer=False, max_length=17), - ), + ) ] diff --git a/machines/migrations/0090_auto_20180805_1459.py b/machines/migrations/0090_auto_20180805_1459.py index 08af8587..cc5f3efd 100644 --- a/machines/migrations/0090_auto_20180805_1459.py +++ b/machines/migrations/0090_auto_20180805_1459.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0089_auto_20180805_1148'), - ] + dependencies = [("machines", "0089_auto_20180805_1148")] operations = [ migrations.AlterField( - model_name='ipv6list', - name='ipv6', - field=models.GenericIPAddressField(protocol='IPv6'), - ), + model_name="ipv6list", + name="ipv6", + field=models.GenericIPAddressField(protocol="IPv6"), + ) ] diff --git a/machines/migrations/0091_auto_20180806_2310.py b/machines/migrations/0091_auto_20180806_2310.py index cd756cad..918f2215 100644 --- a/machines/migrations/0091_auto_20180806_2310.py +++ b/machines/migrations/0091_auto_20180806_2310.py @@ -8,19 +8,29 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0090_auto_20180805_1459'), - ] + dependencies = [("machines", "0090_auto_20180805_1459")] operations = [ migrations.AddField( - model_name='iptype', - name='domaine_ip_netmask', - field=models.IntegerField(default=24, help_text='Netmask for the ipv4 range domain', validators=[django.core.validators.MaxValueValidator(31), django.core.validators.MinValueValidator(8)]), + model_name="iptype", + name="domaine_ip_netmask", + field=models.IntegerField( + default=24, + help_text="Netmask for the ipv4 range domain", + validators=[ + django.core.validators.MaxValueValidator(31), + django.core.validators.MinValueValidator(8), + ], + ), ), migrations.AddField( - model_name='iptype', - name='domaine_ip_network', - field=models.GenericIPAddressField(blank=True, help_text='Network containing the ipv4 range domain ip start/stop. Optional', null=True, protocol='IPv4'), + model_name="iptype", + name="domaine_ip_network", + field=models.GenericIPAddressField( + blank=True, + help_text="Network containing the ipv4 range domain ip start/stop. Optional", + null=True, + protocol="IPv4", + ), ), ] diff --git a/machines/migrations/0092_auto_20180807_0926.py b/machines/migrations/0092_auto_20180807_0926.py index f109a650..9ef5657c 100644 --- a/machines/migrations/0092_auto_20180807_0926.py +++ b/machines/migrations/0092_auto_20180807_0926.py @@ -7,19 +7,13 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('machines', '0091_auto_20180806_2310'), - ] + dependencies = [("machines", "0091_auto_20180806_2310")] operations = [ migrations.RenameField( - model_name='iptype', - old_name='dnssec_reverse_v4', - new_name='reverse_v4', + model_name="iptype", old_name="dnssec_reverse_v4", new_name="reverse_v4" ), migrations.RenameField( - model_name='iptype', - old_name='dnssec_reverse_v6', - new_name='reverse_v6', + model_name="iptype", old_name="dnssec_reverse_v6", new_name="reverse_v6" ), ] diff --git a/machines/migrations/0093_auto_20180807_1115.py b/machines/migrations/0093_auto_20180807_1115.py index 866cb87d..04112c0d 100644 --- a/machines/migrations/0093_auto_20180807_1115.py +++ b/machines/migrations/0093_auto_20180807_1115.py @@ -8,19 +8,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0092_auto_20180807_0926'), - ] + dependencies = [("machines", "0092_auto_20180807_0926")] operations = [ migrations.AlterField( - model_name='mx', - name='name', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.Domain'), + model_name="mx", + name="name", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="machines.Domain" + ), ), migrations.AlterField( - model_name='mx', - name='priority', - field=models.PositiveIntegerField(), + model_name="mx", name="priority", field=models.PositiveIntegerField() ), ] diff --git a/machines/migrations/0094_auto_20180815_1918.py b/machines/migrations/0094_auto_20180815_1918.py index 775ac2c7..0465e489 100644 --- a/machines/migrations/0094_auto_20180815_1918.py +++ b/machines/migrations/0094_auto_20180815_1918.py @@ -10,212 +10,411 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0093_auto_20180807_1115'), - ] + dependencies = [("machines", "0093_auto_20180807_1115")] operations = [ migrations.AlterModelOptions( - name='dname', - options={'permissions': (('view_dname', 'Can view a DNAME record object'),), 'verbose_name': 'DNAME record', 'verbose_name_plural': 'DNAME records'}, + name="dname", + options={ + "permissions": (("view_dname", "Can view a DNAME record object"),), + "verbose_name": "DNAME record", + "verbose_name_plural": "DNAME records", + }, ), migrations.AlterModelOptions( - name='domain', - options={'permissions': (('view_domain', 'Can view a domain object'),), 'verbose_name': 'domain', 'verbose_name_plural': 'domains'}, + name="domain", + options={ + "permissions": (("view_domain", "Can view a domain object"),), + "verbose_name": "domain", + "verbose_name_plural": "domains", + }, ), migrations.AlterModelOptions( - name='extension', - options={'permissions': (('view_extension', 'Can view an extension object'), ('use_all_extension', 'Can use all extensions')), 'verbose_name': 'DNS extension', 'verbose_name_plural': 'DNS extensions'}, + name="extension", + options={ + "permissions": ( + ("view_extension", "Can view an extension object"), + ("use_all_extension", "Can use all extensions"), + ), + "verbose_name": "DNS extension", + "verbose_name_plural": "DNS extensions", + }, ), migrations.AlterModelOptions( - name='interface', - options={'permissions': (('view_interface', 'Can view an interface object'), ('change_interface_machine', 'Can change the owner of an interface')), 'verbose_name': 'interface', 'verbose_name_plural': 'interfaces'}, + name="interface", + options={ + "permissions": ( + ("view_interface", "Can view an interface object"), + ( + "change_interface_machine", + "Can change the owner of an interface", + ), + ), + "verbose_name": "interface", + "verbose_name_plural": "interfaces", + }, ), migrations.AlterModelOptions( - name='iplist', - options={'permissions': (('view_iplist', 'Can view an IPv4 addresses list object'),), 'verbose_name': 'IPv4 addresses list', 'verbose_name_plural': 'IPv4 addresses lists'}, + name="iplist", + options={ + "permissions": ( + ("view_iplist", "Can view an IPv4 addresses list object"), + ), + "verbose_name": "IPv4 addresses list", + "verbose_name_plural": "IPv4 addresses lists", + }, ), migrations.AlterModelOptions( - name='iptype', - options={'permissions': (('view_iptype', 'Can view an IP type object'), ('use_all_iptype', 'Can use all IP types')), 'verbose_name': 'IP type', 'verbose_name_plural': 'IP types'}, + name="iptype", + options={ + "permissions": ( + ("view_iptype", "Can view an IP type object"), + ("use_all_iptype", "Can use all IP types"), + ), + "verbose_name": "IP type", + "verbose_name_plural": "IP types", + }, ), migrations.AlterModelOptions( - name='ipv6list', - options={'permissions': (('view_ipv6list', 'Can view an IPv6 addresses list object'), ('change_ipv6list_slaac_ip', 'Can change the SLAAC value of an IPv6 addresses list')), 'verbose_name': 'IPv6 addresses list', 'verbose_name_plural': 'IPv6 addresses lists'}, + name="ipv6list", + options={ + "permissions": ( + ("view_ipv6list", "Can view an IPv6 addresses list object"), + ( + "change_ipv6list_slaac_ip", + "Can change the SLAAC value of an IPv6 addresses list", + ), + ), + "verbose_name": "IPv6 addresses list", + "verbose_name_plural": "IPv6 addresses lists", + }, ), migrations.AlterModelOptions( - name='machine', - options={'permissions': (('view_machine', 'Can view a machine object'), ('change_machine_user', 'Can change the user of a machine')), 'verbose_name': 'machine', 'verbose_name_plural': 'machines'}, + name="machine", + options={ + "permissions": ( + ("view_machine", "Can view a machine object"), + ("change_machine_user", "Can change the user of a machine"), + ), + "verbose_name": "machine", + "verbose_name_plural": "machines", + }, ), migrations.AlterModelOptions( - name='machinetype', - options={'permissions': (('view_machinetype', 'Can view a machine type object'), ('use_all_machinetype', 'Can use all machine types')), 'verbose_name': 'machine type', 'verbose_name_plural': 'machine types'}, + name="machinetype", + options={ + "permissions": ( + ("view_machinetype", "Can view a machine type object"), + ("use_all_machinetype", "Can use all machine types"), + ), + "verbose_name": "machine type", + "verbose_name_plural": "machine types", + }, ), migrations.AlterModelOptions( - name='mx', - options={'permissions': (('view_mx', 'Can view an MX record object'),), 'verbose_name': 'MX record', 'verbose_name_plural': 'MX records'}, + name="mx", + options={ + "permissions": (("view_mx", "Can view an MX record object"),), + "verbose_name": "MX record", + "verbose_name_plural": "MX records", + }, ), migrations.AlterModelOptions( - name='nas', - options={'permissions': (('view_nas', 'Can view a NAS device object'),), 'verbose_name': 'NAS device', 'verbose_name_plural': 'NAS devices'}, + name="nas", + options={ + "permissions": (("view_nas", "Can view a NAS device object"),), + "verbose_name": "NAS device", + "verbose_name_plural": "NAS devices", + }, ), migrations.AlterModelOptions( - name='ns', - options={'permissions': (('view_ns', 'Can view an NS record object'),), 'verbose_name': 'NS record', 'verbose_name_plural': 'NS records'}, + name="ns", + options={ + "permissions": (("view_ns", "Can view an NS record object"),), + "verbose_name": "NS record", + "verbose_name_plural": "NS records", + }, ), migrations.AlterModelOptions( - name='ouvertureport', - options={'verbose_name': 'ports openings'}, + name="ouvertureport", options={"verbose_name": "ports openings"} ), migrations.AlterModelOptions( - name='ouvertureportlist', - options={'permissions': (('view_ouvertureportlist', 'Can view a ports opening list object'),), 'verbose_name': 'ports opening list', 'verbose_name_plural': 'ports opening lists'}, + name="ouvertureportlist", + options={ + "permissions": ( + ("view_ouvertureportlist", "Can view a ports opening list object"), + ), + "verbose_name": "ports opening list", + "verbose_name_plural": "ports opening lists", + }, ), migrations.AlterModelOptions( - name='role', - options={'permissions': (('view_role', 'Can view a role object'),), 'verbose_name': 'server role', 'verbose_name_plural': 'server roles'}, + name="role", + options={ + "permissions": (("view_role", "Can view a role object"),), + "verbose_name": "server role", + "verbose_name_plural": "server roles", + }, ), migrations.AlterModelOptions( - name='service', - options={'permissions': (('view_service', 'Can view a service object'),), 'verbose_name': 'service to generate (DHCP, DNS, ...)', 'verbose_name_plural': 'services to generate (DHCP, DNS, ...)'}, + name="service", + options={ + "permissions": (("view_service", "Can view a service object"),), + "verbose_name": "service to generate (DHCP, DNS, ...)", + "verbose_name_plural": "services to generate (DHCP, DNS, ...)", + }, ), migrations.AlterModelOptions( - name='service_link', - options={'permissions': (('view_service_link', 'Can view a service server link object'),), 'verbose_name': 'link between service and server', 'verbose_name_plural': 'links between service and server'}, + name="service_link", + options={ + "permissions": ( + ("view_service_link", "Can view a service server link object"), + ), + "verbose_name": "link between service and server", + "verbose_name_plural": "links between service and server", + }, ), migrations.AlterModelOptions( - name='soa', - options={'permissions': (('view_soa', 'Can view an SOA record object'),), 'verbose_name': 'SOA record', 'verbose_name_plural': 'SOA records'}, + name="soa", + options={ + "permissions": (("view_soa", "Can view an SOA record object"),), + "verbose_name": "SOA record", + "verbose_name_plural": "SOA records", + }, ), migrations.AlterModelOptions( - name='srv', - options={'permissions': (('view_srv', 'Can view an SRV record object'),), 'verbose_name': 'SRV record', 'verbose_name_plural': 'SRV records'}, + name="srv", + options={ + "permissions": (("view_srv", "Can view an SRV record object"),), + "verbose_name": "SRV record", + "verbose_name_plural": "SRV records", + }, ), migrations.AlterModelOptions( - name='sshfp', - options={'permissions': (('view_sshfp', 'Can view an SSHFP record object'),), 'verbose_name': 'SSHFP record', 'verbose_name_plural': 'SSHFP records'}, + name="sshfp", + options={ + "permissions": (("view_sshfp", "Can view an SSHFP record object"),), + "verbose_name": "SSHFP record", + "verbose_name_plural": "SSHFP records", + }, ), migrations.AlterModelOptions( - name='txt', - options={'permissions': (('view_txt', 'Can view a TXT record object'),), 'verbose_name': 'TXT record', 'verbose_name_plural': 'TXT records'}, + name="txt", + options={ + "permissions": (("view_txt", "Can view a TXT record object"),), + "verbose_name": "TXT record", + "verbose_name_plural": "TXT records", + }, ), migrations.AlterModelOptions( - name='vlan', - options={'permissions': (('view_vlan', 'Can view a VLAN object'),), 'verbose_name': 'VLAN', 'verbose_name_plural': 'VLANs'}, + name="vlan", + options={ + "permissions": (("view_vlan", "Can view a VLAN object"),), + "verbose_name": "VLAN", + "verbose_name_plural": "VLANs", + }, ), migrations.AlterField( - model_name='domain', - name='name', - field=models.CharField(help_text='Mandatory and unique, must not contain dots.', max_length=255), + model_name="domain", + name="name", + field=models.CharField( + help_text="Mandatory and unique, must not contain dots.", max_length=255 + ), ), migrations.AlterField( - model_name='extension', - name='name', - field=models.CharField(help_text='Zone name, must begin with a dot (.example.org)', max_length=255, unique=True), + model_name="extension", + name="name", + field=models.CharField( + help_text="Zone name, must begin with a dot (.example.org)", + max_length=255, + unique=True, + ), ), migrations.AlterField( - model_name='extension', - name='origin', - field=models.ForeignKey(blank=True, help_text='A record associated with the zone', null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.IpList'), + model_name="extension", + name="origin", + field=models.ForeignKey( + blank=True, + help_text="A record associated with the zone", + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="machines.IpList", + ), ), migrations.AlterField( - model_name='extension', - name='origin_v6', - field=models.GenericIPAddressField(blank=True, help_text='AAAA record associated with the zone', null=True, protocol='IPv6'), + model_name="extension", + name="origin_v6", + field=models.GenericIPAddressField( + blank=True, + help_text="AAAA record associated with the zone", + null=True, + protocol="IPv6", + ), ), migrations.AlterField( - model_name='iptype', - name='domaine_ip_netmask', - field=models.IntegerField(default=24, help_text="Netmask for the domain's IPv4 range", validators=[django.core.validators.MaxValueValidator(31), django.core.validators.MinValueValidator(8)]), + model_name="iptype", + name="domaine_ip_netmask", + field=models.IntegerField( + default=24, + help_text="Netmask for the domain's IPv4 range", + validators=[ + django.core.validators.MaxValueValidator(31), + django.core.validators.MinValueValidator(8), + ], + ), ), migrations.AlterField( - model_name='iptype', - name='domaine_ip_network', - field=models.GenericIPAddressField(blank=True, help_text="Network containing the domain's IPv4 range (optional)", null=True, protocol='IPv4'), + model_name="iptype", + name="domaine_ip_network", + field=models.GenericIPAddressField( + blank=True, + help_text="Network containing the domain's IPv4 range (optional)", + null=True, + protocol="IPv4", + ), ), migrations.AlterField( - model_name='iptype', - name='reverse_v4', - field=models.BooleanField(default=False, help_text='Enable reverse DNS for IPv4'), + model_name="iptype", + name="reverse_v4", + field=models.BooleanField( + default=False, help_text="Enable reverse DNS for IPv4" + ), ), migrations.AlterField( - model_name='iptype', - name='reverse_v6', - field=models.BooleanField(default=False, help_text='Enable reverse DNS for IPv6'), + model_name="iptype", + name="reverse_v6", + field=models.BooleanField( + default=False, help_text="Enable reverse DNS for IPv6" + ), ), migrations.AlterField( - model_name='machine', - name='name', - field=models.CharField(blank=True, help_text='Optional', max_length=255, null=True), + model_name="machine", + name="name", + field=models.CharField( + blank=True, help_text="Optional", max_length=255, null=True + ), ), migrations.AlterField( - model_name='ouvertureportlist', - name='name', - field=models.CharField(help_text='Name of the ports configuration', max_length=255), + model_name="ouvertureportlist", + name="name", + field=models.CharField( + help_text="Name of the ports configuration", max_length=255 + ), ), migrations.AlterField( - model_name='role', - name='specific_role', - field=models.CharField(blank=True, choices=[('dhcp-server', 'DHCP server'), ('switch-conf-server', 'Switches configuration server'), ('dns-recursif-server', 'Recursive DNS server'), ('ntp-server', 'NTP server'), ('radius-server', 'RADIUS server'), ('log-server', 'Log server'), ('ldap-master-server', 'LDAP master server'), ('ldap-backup-server', 'LDAP backup server'), ('smtp-server', 'SMTP server'), ('postgresql-server', 'postgreSQL server'), ('mysql-server', 'mySQL server'), ('sql-client', 'SQL client'), ('gateway', 'Gateway')], max_length=32, null=True), + model_name="role", + name="specific_role", + field=models.CharField( + blank=True, + choices=[ + ("dhcp-server", "DHCP server"), + ("switch-conf-server", "Switches configuration server"), + ("dns-recursif-server", "Recursive DNS server"), + ("ntp-server", "NTP server"), + ("radius-server", "RADIUS server"), + ("log-server", "Log server"), + ("ldap-master-server", "LDAP master server"), + ("ldap-backup-server", "LDAP backup server"), + ("smtp-server", "SMTP server"), + ("postgresql-server", "postgreSQL server"), + ("mysql-server", "mySQL server"), + ("sql-client", "SQL client"), + ("gateway", "Gateway"), + ], + max_length=32, + null=True, + ), ), migrations.AlterField( - model_name='service', - name='min_time_regen', - field=models.DurationField(default=datetime.timedelta(0, 60), help_text='Minimal time before regeneration of the service.'), + model_name="service", + name="min_time_regen", + field=models.DurationField( + default=datetime.timedelta(0, 60), + help_text="Minimal time before regeneration of the service.", + ), ), migrations.AlterField( - model_name='service', - name='regular_time_regen', - field=models.DurationField(default=datetime.timedelta(0, 3600), help_text='Maximal time before regeneration of the service.'), + model_name="service", + name="regular_time_regen", + field=models.DurationField( + default=datetime.timedelta(0, 3600), + help_text="Maximal time before regeneration of the service.", + ), ), migrations.AlterField( - model_name='soa', - name='expire', - field=models.PositiveIntegerField(default=3600000, help_text='Seconds before the secondary DNS stop answering requests in case of primary DNS timeout'), + model_name="soa", + name="expire", + field=models.PositiveIntegerField( + default=3600000, + help_text="Seconds before the secondary DNS stop answering requests in case of primary DNS timeout", + ), ), migrations.AlterField( - model_name='soa', - name='mail', - field=models.EmailField(help_text='Contact email address for the zone', max_length=254), + model_name="soa", + name="mail", + field=models.EmailField( + help_text="Contact email address for the zone", max_length=254 + ), ), migrations.AlterField( - model_name='soa', - name='refresh', - field=models.PositiveIntegerField(default=86400, help_text='Seconds before the secondary DNS have to ask the primary DNS serial to detect a modification'), + model_name="soa", + name="refresh", + field=models.PositiveIntegerField( + default=86400, + help_text="Seconds before the secondary DNS have to ask the primary DNS serial to detect a modification", + ), ), migrations.AlterField( - model_name='soa', - name='retry', - field=models.PositiveIntegerField(default=7200, help_text='Seconds before the secondary DNS ask the serial again in case of a primary DNS timeout'), + model_name="soa", + name="retry", + field=models.PositiveIntegerField( + default=7200, + help_text="Seconds before the secondary DNS ask the serial again in case of a primary DNS timeout", + ), ), migrations.AlterField( - model_name='soa', - name='ttl', - field=models.PositiveIntegerField(default=172800, help_text='Time to Live'), + model_name="soa", + name="ttl", + field=models.PositiveIntegerField(default=172800, help_text="Time to Live"), ), migrations.AlterField( - model_name='srv', - name='port', - field=models.PositiveIntegerField(help_text='TCP/UDP port', validators=[django.core.validators.MaxValueValidator(65535)]), + model_name="srv", + name="port", + field=models.PositiveIntegerField( + help_text="TCP/UDP port", + validators=[django.core.validators.MaxValueValidator(65535)], + ), ), migrations.AlterField( - model_name='srv', - name='priority', - field=models.PositiveIntegerField(default=0, help_text='Priority of the target server (positive integer value, the lower it is, the more the server will be used if available)', validators=[django.core.validators.MaxValueValidator(65535)]), + model_name="srv", + name="priority", + field=models.PositiveIntegerField( + default=0, + help_text="Priority of the target server (positive integer value, the lower it is, the more the server will be used if available)", + validators=[django.core.validators.MaxValueValidator(65535)], + ), ), migrations.AlterField( - model_name='srv', - name='target', - field=models.ForeignKey(help_text='Target server', on_delete=django.db.models.deletion.PROTECT, to='machines.Domain'), + model_name="srv", + name="target", + field=models.ForeignKey( + help_text="Target server", + on_delete=django.db.models.deletion.PROTECT, + to="machines.Domain", + ), ), migrations.AlterField( - model_name='srv', - name='ttl', - field=models.PositiveIntegerField(default=172800, help_text='Time to Live'), + model_name="srv", + name="ttl", + field=models.PositiveIntegerField(default=172800, help_text="Time to Live"), ), migrations.AlterField( - model_name='srv', - name='weight', - field=models.PositiveIntegerField(default=0, help_text='Relative weight for records with the same priority (integer value between 0 and 65535)', validators=[django.core.validators.MaxValueValidator(65535)]), + model_name="srv", + name="weight", + field=models.PositiveIntegerField( + default=0, + help_text="Relative weight for records with the same priority (integer value between 0 and 65535)", + validators=[django.core.validators.MaxValueValidator(65535)], + ), ), ] diff --git a/machines/migrations/0095_auto_20180919_2225.py b/machines/migrations/0095_auto_20180919_2225.py index 66c082ff..6a7536ee 100644 --- a/machines/migrations/0095_auto_20180919_2225.py +++ b/machines/migrations/0095_auto_20180919_2225.py @@ -7,34 +7,32 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0094_auto_20180815_1918'), - ] + dependencies = [("machines", "0094_auto_20180815_1918")] operations = [ migrations.AddField( - model_name='vlan', - name='arp_protect', + model_name="vlan", + name="arp_protect", field=models.BooleanField(default=False), ), migrations.AddField( - model_name='vlan', - name='dhcp_snooping', + model_name="vlan", + name="dhcp_snooping", field=models.BooleanField(default=False), ), migrations.AddField( - model_name='vlan', - name='dhcpv6_snooping', + model_name="vlan", + name="dhcpv6_snooping", field=models.BooleanField(default=False), ), migrations.AddField( - model_name='vlan', - name='igmp', - field=models.BooleanField(default=False, help_text='Gestion multicast v4'), + model_name="vlan", + name="igmp", + field=models.BooleanField(default=False, help_text="Gestion multicast v4"), ), migrations.AddField( - model_name='vlan', - name='mld', - field=models.BooleanField(default=False, help_text='Gestion multicast v6'), + model_name="vlan", + name="mld", + field=models.BooleanField(default=False, help_text="Gestion multicast v6"), ), ] diff --git a/machines/migrations/0096_auto_20181013_1417.py b/machines/migrations/0096_auto_20181013_1417.py index 745fb523..0017ead9 100644 --- a/machines/migrations/0096_auto_20181013_1417.py +++ b/machines/migrations/0096_auto_20181013_1417.py @@ -9,14 +9,14 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('machines', '0095_auto_20180919_2225'), - ] + dependencies = [("machines", "0095_auto_20180919_2225")] operations = [ migrations.AlterField( - model_name='machine', - name='user', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), + model_name="machine", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + ), + ) ] diff --git a/machines/migrations/0097_extension_dnssec.py b/machines/migrations/0097_extension_dnssec.py index 48e41f77..6da514ac 100644 --- a/machines/migrations/0097_extension_dnssec.py +++ b/machines/migrations/0097_extension_dnssec.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0096_auto_20181013_1417'), - ] + dependencies = [("machines", "0096_auto_20181013_1417")] operations = [ migrations.AddField( - model_name='extension', - name='dnssec', - field=models.BooleanField(default=False, help_text='Should the zone be signed with DNSSEC'), - ), + model_name="extension", + name="dnssec", + field=models.BooleanField( + default=False, help_text="Should the zone be signed with DNSSEC" + ), + ) ] diff --git a/machines/migrations/0098_auto_20190102_1745.py b/machines/migrations/0098_auto_20190102_1745.py index e886e8a1..55ec21ea 100644 --- a/machines/migrations/0098_auto_20190102_1745.py +++ b/machines/migrations/0098_auto_20190102_1745.py @@ -7,14 +7,32 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0097_extension_dnssec'), - ] + dependencies = [("machines", "0097_extension_dnssec")] operations = [ migrations.AlterField( - model_name='role', - name='specific_role', - field=models.CharField(blank=True, choices=[('dhcp-server', 'DHCP server'), ('switch-conf-server', 'Switches configuration server'), ('dns-recursif-server', 'Recursive DNS server'), ('dns-recursive-server', 'Recursive DNS server'), ('ntp-server', 'NTP server'), ('radius-server', 'RADIUS server'), ('log-server', 'Log server'), ('ldap-master-server', 'LDAP master server'), ('ldap-backup-server', 'LDAP backup server'), ('smtp-server', 'SMTP server'), ('postgresql-server', 'postgreSQL server'), ('mysql-server', 'mySQL server'), ('sql-client', 'SQL client'), ('gateway', 'Gateway')], max_length=32, null=True), - ), + model_name="role", + name="specific_role", + field=models.CharField( + blank=True, + choices=[ + ("dhcp-server", "DHCP server"), + ("switch-conf-server", "Switches configuration server"), + ("dns-recursif-server", "Recursive DNS server"), + ("dns-recursive-server", "Recursive DNS server"), + ("ntp-server", "NTP server"), + ("radius-server", "RADIUS server"), + ("log-server", "Log server"), + ("ldap-master-server", "LDAP master server"), + ("ldap-backup-server", "LDAP backup server"), + ("smtp-server", "SMTP server"), + ("postgresql-server", "postgreSQL server"), + ("mysql-server", "mySQL server"), + ("sql-client", "SQL client"), + ("gateway", "Gateway"), + ], + max_length=32, + null=True, + ), + ) ] diff --git a/machines/migrations/0099_role_recursive_dns.py b/machines/migrations/0099_role_recursive_dns.py index c1ce3965..bc1b8ab8 100644 --- a/machines/migrations/0099_role_recursive_dns.py +++ b/machines/migrations/0099_role_recursive_dns.py @@ -6,21 +6,15 @@ from django.db import migrations, models def migrate(apps, schema_editor): - Role = apps.get_model('machines', 'Role') + Role = apps.get_model("machines", "Role") - for role in Role.objects.filter(specific_role='dns-recursif-server'): - role.specific_role = 'dns-recursive-server' + for role in Role.objects.filter(specific_role="dns-recursif-server"): + role.specific_role = "dns-recursive-server" role.save() class Migration(migrations.Migration): - dependencies = [ - ('machines', '0098_auto_20190102_1745'), - ] - - operations = [ - migrations.RunPython(migrate), - ] - + dependencies = [("machines", "0098_auto_20190102_1745")] + operations = [migrations.RunPython(migrate)] diff --git a/machines/migrations/0100_auto_20190102_1753.py b/machines/migrations/0100_auto_20190102_1753.py index 35f7b78d..3d3e315f 100644 --- a/machines/migrations/0100_auto_20190102_1753.py +++ b/machines/migrations/0100_auto_20190102_1753.py @@ -7,14 +7,31 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0099_role_recursive_dns'), - ] + dependencies = [("machines", "0099_role_recursive_dns")] operations = [ migrations.AlterField( - model_name='role', - name='specific_role', - field=models.CharField(blank=True, choices=[('dhcp-server', 'DHCP server'), ('switch-conf-server', 'Switches configuration server'), ('dns-recursive-server', 'Recursive DNS server'), ('ntp-server', 'NTP server'), ('radius-server', 'RADIUS server'), ('log-server', 'Log server'), ('ldap-master-server', 'LDAP master server'), ('ldap-backup-server', 'LDAP backup server'), ('smtp-server', 'SMTP server'), ('postgresql-server', 'postgreSQL server'), ('mysql-server', 'mySQL server'), ('sql-client', 'SQL client'), ('gateway', 'Gateway')], max_length=32, null=True), - ), + model_name="role", + name="specific_role", + field=models.CharField( + blank=True, + choices=[ + ("dhcp-server", "DHCP server"), + ("switch-conf-server", "Switches configuration server"), + ("dns-recursive-server", "Recursive DNS server"), + ("ntp-server", "NTP server"), + ("radius-server", "RADIUS server"), + ("log-server", "Log server"), + ("ldap-master-server", "LDAP master server"), + ("ldap-backup-server", "LDAP backup server"), + ("smtp-server", "SMTP server"), + ("postgresql-server", "postgreSQL server"), + ("mysql-server", "mySQL server"), + ("sql-client", "SQL client"), + ("gateway", "Gateway"), + ], + max_length=32, + null=True, + ), + ) ] diff --git a/machines/migrations/0101_auto_20190108_1623.py b/machines/migrations/0101_auto_20190108_1623.py index 856721ac..009e11b4 100644 --- a/machines/migrations/0101_auto_20190108_1623.py +++ b/machines/migrations/0101_auto_20190108_1623.py @@ -7,28 +7,37 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0100_auto_20190102_1753'), - ] + dependencies = [("machines", "0100_auto_20190102_1753")] operations = [ migrations.AlterModelOptions( - name='ouvertureport', - options={'verbose_name': 'ports opening', 'verbose_name_plural': 'ports openings'}, + name="ouvertureport", + options={ + "verbose_name": "ports opening", + "verbose_name_plural": "ports openings", + }, ), migrations.AlterField( - model_name='nas', - name='port_access_mode', - field=models.CharField(choices=[('802.1X', '802.1X'), ('Mac-address', 'MAC-address')], default='802.1X', max_length=32), + model_name="nas", + name="port_access_mode", + field=models.CharField( + choices=[("802.1X", "802.1X"), ("Mac-address", "MAC-address")], + default="802.1X", + max_length=32, + ), ), migrations.AlterField( - model_name='vlan', - name='igmp', - field=models.BooleanField(default=False, help_text='v4 multicast management'), + model_name="vlan", + name="igmp", + field=models.BooleanField( + default=False, help_text="v4 multicast management" + ), ), migrations.AlterField( - model_name='vlan', - name='mld', - field=models.BooleanField(default=False, help_text='v6 multicast management'), + model_name="vlan", + name="mld", + field=models.BooleanField( + default=False, help_text="v6 multicast management" + ), ), ] diff --git a/machines/migrations/0102_auto_20190303_1611.py b/machines/migrations/0102_auto_20190303_1611.py index 3531fb11..29f97700 100644 --- a/machines/migrations/0102_auto_20190303_1611.py +++ b/machines/migrations/0102_auto_20190303_1611.py @@ -7,24 +7,14 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('machines', '0101_auto_20190108_1623'), - ] + dependencies = [("machines", "0101_auto_20190108_1623")] operations = [ migrations.RenameField( - model_name='interface', - old_name='type', - new_name='machine_type', + model_name="interface", old_name="type", new_name="machine_type" ), + migrations.RenameField(model_name="iptype", old_name="type", new_name="name"), migrations.RenameField( - model_name='iptype', - old_name='type', - new_name='name', - ), - migrations.RenameField( - model_name='machinetype', - old_name='type', - new_name='name', + model_name="machinetype", old_name="type", new_name="name" ), ] diff --git a/machines/migrations/0103_auto_20191002_2222.py b/machines/migrations/0103_auto_20191002_2222.py index 43adac74..3c74721b 100644 --- a/machines/migrations/0103_auto_20191002_2222.py +++ b/machines/migrations/0103_auto_20191002_2222.py @@ -9,29 +9,37 @@ import machines.models class Migration(migrations.Migration): dependencies = [ - ('machines', '0102_auto_20190303_1611'), - ('preferences', '0066_optionalmachine_default_dns_ttl'), + ("machines", "0102_auto_20190303_1611"), + ("preferences", "0066_optionalmachine_default_dns_ttl"), ] operations = [ migrations.AddField( - model_name='domain', - name='ttl', - field=models.PositiveIntegerField(default=0, verbose_name='Time To Live (TTL)'), + model_name="domain", + name="ttl", + field=models.PositiveIntegerField( + default=0, verbose_name="Time To Live (TTL)" + ), ), migrations.AddField( - model_name='mx', - name='ttl', - field=models.PositiveIntegerField(default=172800, verbose_name='Time To Live (TTL)'), + model_name="mx", + name="ttl", + field=models.PositiveIntegerField( + default=172800, verbose_name="Time To Live (TTL)" + ), ), migrations.AddField( - model_name='ns', - name='ttl', - field=models.PositiveIntegerField(default=172800, verbose_name='Time To Live (TTL)'), + model_name="ns", + name="ttl", + field=models.PositiveIntegerField( + default=172800, verbose_name="Time To Live (TTL)" + ), ), migrations.AddField( - model_name='txt', - name='ttl', - field=models.PositiveIntegerField(default=172800, verbose_name='Time To Live (TTL)'), + model_name="txt", + name="ttl", + field=models.PositiveIntegerField( + default=172800, verbose_name="Time To Live (TTL)" + ), ), ] diff --git a/machines/migrations/0104_auto_20191002_2231.py b/machines/migrations/0104_auto_20191002_2231.py index 344bddb7..3f2c22e2 100644 --- a/machines/migrations/0104_auto_20191002_2231.py +++ b/machines/migrations/0104_auto_20191002_2231.py @@ -7,13 +7,18 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('machines', '0103_auto_20191002_2222'), - ] + dependencies = [("machines", "0103_auto_20191002_2222")] operations = [ migrations.AlterModelOptions( - name='domain', - options={'permissions': (('view_domain', 'Can view a domain object'), ('change_ttl', 'Can change TTL of a domain object')), 'verbose_name': 'domain', 'verbose_name_plural': 'domains'}, - ), + name="domain", + options={ + "permissions": ( + ("view_domain", "Can view a domain object"), + ("change_ttl", "Can change TTL of a domain object"), + ), + "verbose_name": "domain", + "verbose_name_plural": "domains", + }, + ) ] diff --git a/machines/migrations/0105_dname_ttl.py b/machines/migrations/0105_dname_ttl.py index d3c38073..6cdca097 100644 --- a/machines/migrations/0105_dname_ttl.py +++ b/machines/migrations/0105_dname_ttl.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('machines', '0104_auto_20191002_2231'), - ] + dependencies = [("machines", "0104_auto_20191002_2231")] operations = [ migrations.AddField( - model_name='dname', - name='ttl', - field=models.PositiveIntegerField(default=172800, verbose_name='Time To Live (TTL)'), - ), + model_name="dname", + name="ttl", + field=models.PositiveIntegerField( + default=172800, verbose_name="Time To Live (TTL)" + ), + ) ] diff --git a/machines/migrations/__init__.py b/machines/migrations/__init__.py index b2b50566..b409e525 100644 --- a/machines/migrations/__init__.py +++ b/machines/migrations/__init__.py @@ -19,4 +19,3 @@ # 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. - diff --git a/machines/models.py b/machines/models.py index ca881033..8b83e256 100644 --- a/machines/models.py +++ b/machines/models.py @@ -46,7 +46,15 @@ from reversion import revisions as reversion from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from macaddress.fields import MACAddressField, default_dialect -from netaddr import mac_bare, EUI, NotRegisteredError, IPSet, IPRange, IPNetwork, IPAddress +from netaddr import ( + mac_bare, + EUI, + NotRegisteredError, + IPSet, + IPRange, + IPNetwork, + IPAddress, +) import preferences.models import users.models @@ -57,20 +65,17 @@ from re2o.mixins import AclMixin, RevMixin class Machine(RevMixin, FieldPermissionModelMixin, models.Model): """ Class définissant une machine, object parent user, objets fils interfaces""" - user = models.ForeignKey('users.User', on_delete=models.CASCADE) + + user = models.ForeignKey("users.User", on_delete=models.CASCADE) name = models.CharField( - max_length=255, - help_text=_("Optional"), - blank=True, - null=True + max_length=255, help_text=_("Optional"), blank=True, null=True ) active = models.BooleanField(default=True) class Meta: permissions = ( ("view_machine", _("Can view a machine object")), - ("change_machine_user", - _("Can change the user of a machine")), + ("change_machine_user", _("Can change the user of a machine")), ) verbose_name = _("machine") verbose_name_plural = _("machines") @@ -88,9 +93,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): Usefull in history display""" return chain( self.interface_set.all(), - Domain.objects.filter( - interface_parent__in=self.interface_set.all() - ) + Domain.objects.filter(interface_parent__in=self.interface_set.all()), ) @staticmethod @@ -105,11 +108,13 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): A tuple with a boolean stating if edition is allowed and an explanation message. """ - can = user_request.has_perm('machines.change_machine_user') + can = user_request.has_perm("machines.change_machine_user") return ( can, - _("You don't have the right to change the machine's user.") if not can else None, - ('machines.change_machine_user',) + _("You don't have the right to change the machine's user.") + if not can + else None, + ("machines.change_machine_user",), ) @staticmethod @@ -118,11 +123,11 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): droit particulier correspondant :param user_request: instance user qui fait l'edition :return: True ou False avec la raison de l'échec le cas échéant""" - if not user_request.has_perm('machines.view_machine'): + if not user_request.has_perm("machines.view_machine"): return ( False, _("You don't have the right to view all the machines."), - ('machines.view_machine',) + ("machines.view_machine",), ) return True, None, None @@ -137,29 +142,34 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): user = users.models.User.objects.get(pk=userid) except users.models.User.DoesNotExist: return False, _("Nonexistent user."), None - max_lambdauser_interfaces = (preferences.models.OptionalMachine - .get_cached_value( - 'max_lambdauser_interfaces' - )) - if not user_request.has_perm('machines.add_machine'): - if not (preferences.models.OptionalMachine - .get_cached_value('create_machine')): + max_lambdauser_interfaces = preferences.models.OptionalMachine.get_cached_value( + "max_lambdauser_interfaces" + ) + if not user_request.has_perm("machines.add_machine"): + if not ( + preferences.models.OptionalMachine.get_cached_value("create_machine") + ): return ( False, _("You don't have the right to add a machine."), - ('machines.add_machine',) + ("machines.add_machine",), ) if user != user_request: return ( False, - _("You don't have the right to add a machine" - " to another user."), - ('machines.add_machine',) + _("You don't have the right to add a machine" " to another user."), + ("machines.add_machine",), ) if user.user_interfaces().count() >= max_lambdauser_interfaces: - return False, _("You reached the maximum number of interfaces" - " that you are allowed to create yourself" - " (%s)." % max_lambdauser_interfaces), None + return ( + False, + _( + "You reached the maximum number of interfaces" + " that you are allowed to create yourself" + " (%s)." % max_lambdauser_interfaces + ), + None, + ) return True, None, None def can_edit(self, user_request, *args, **kwargs): @@ -170,19 +180,13 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): :return: True ou False avec la raison le cas échéant""" if self.user != user_request: can_user, _message, permissions = self.user.can_edit( - self.user, - user_request, - *args, - **kwargs + self.user, user_request, *args, **kwargs ) - if not ( - user_request.has_perm('machines.change_interface') and - can_user): + if not (user_request.has_perm("machines.change_interface") and can_user): return ( False, - _("You don't have the right to edit a machine" - " of another user."), - ('machines.change_interface',) + permissions + _("You don't have the right to edit a machine" " of another user."), + ("machines.change_interface",) + permissions, ) return True, None, None @@ -194,19 +198,16 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): :return: True ou False avec la raison de l'échec le cas échéant""" if self.user != user_request: can_user, _message, permissions = self.user.can_edit( - self.user, - user_request, - *args, - **kwargs + self.user, user_request, *args, **kwargs ) - if not ( - user_request.has_perm('machines.change_interface') and - can_user): + if not (user_request.has_perm("machines.change_interface") and can_user): return ( False, - _("You don't have the right to delete a machine" - " of another user."), - ('machines.change_interface',) + permissions + _( + "You don't have the right to delete a machine" + " of another user." + ), + ("machines.change_interface",) + permissions, ) return True, None, None @@ -216,13 +217,14 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): :param self: instance machine à éditer :param user_request: instance user qui fait l'edition :return: True ou False avec la raison de l'échec le cas échéant""" - if (not user_request.has_perm('machines.view_machine') and - self.user != user_request): + if ( + not user_request.has_perm("machines.view_machine") + and self.user != user_request + ): return ( False, - _("You don't have the right to view other machines" - " than yours."), - ('machines.view_machine',) + _("You don't have the right to view other machines" " than yours."), + ("machines.view_machine",), ) return True, None, None @@ -246,9 +248,11 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): def all_short_names(self): """Renvoie de manière unique, le nom des interfaces de cette machine""" - return Domain.objects.filter( - interface_parent__machine=self - ).values_list('name', flat=True).distinct() + return ( + Domain.objects.filter(interface_parent__machine=self) + .values_list("name", flat=True) + .distinct() + ) @cached_property def get_name(self): @@ -259,39 +263,52 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): def mass_delete(cls, machine_queryset): """Mass delete for machine queryset""" from topologie.models import AccessPoint - Domain.objects.filter(cname__interface_parent__machine__in=machine_queryset)._raw_delete(machine_queryset.db) - Domain.objects.filter(interface_parent__machine__in=machine_queryset)._raw_delete(machine_queryset.db) - Ipv6List.objects.filter(interface__machine__in=machine_queryset)._raw_delete(machine_queryset.db) - Interface.objects.filter(machine__in=machine_queryset).filter(port_lists__isnull=False).delete() - Interface.objects.filter(machine__in=machine_queryset)._raw_delete(machine_queryset.db) - AccessPoint.objects.filter(machine_ptr__in=machine_queryset)._raw_delete(machine_queryset.db) + + Domain.objects.filter( + cname__interface_parent__machine__in=machine_queryset + )._raw_delete(machine_queryset.db) + Domain.objects.filter( + interface_parent__machine__in=machine_queryset + )._raw_delete(machine_queryset.db) + Ipv6List.objects.filter(interface__machine__in=machine_queryset)._raw_delete( + machine_queryset.db + ) + Interface.objects.filter(machine__in=machine_queryset).filter( + port_lists__isnull=False + ).delete() + Interface.objects.filter(machine__in=machine_queryset)._raw_delete( + machine_queryset.db + ) + AccessPoint.objects.filter(machine_ptr__in=machine_queryset)._raw_delete( + machine_queryset.db + ) machine_queryset._raw_delete(machine_queryset.db) @cached_property def all_complete_names(self): """Renvoie tous les tls complets de la machine""" - return [str(domain) for domain in Domain.objects.filter( - Q(cname__interface_parent__machine=self) | Q(interface_parent__machine=self) - )] + return [ + str(domain) + for domain in Domain.objects.filter( + Q(cname__interface_parent__machine=self) + | Q(interface_parent__machine=self) + ) + ] def __init__(self, *args, **kwargs): super(Machine, self).__init__(*args, **kwargs) - self.field_permissions = { - 'user': self.can_change_user, - } + self.field_permissions = {"user": self.can_change_user} 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(RevMixin, AclMixin, models.Model): """ Type de machine, relié à un type d'ip, affecté aux interfaces""" + name = models.CharField(max_length=255) ip_type = models.ForeignKey( - 'IpType', - on_delete=models.PROTECT, - blank=True, - null=True + "IpType", on_delete=models.PROTECT, blank=True, null=True ) class Meta: @@ -317,11 +334,11 @@ class MachineType(RevMixin, AclMixin, models.Model): A tuple with a boolean stating if user can acces and an explanation message is acces is not allowed. """ - if not user_request.has_perm('machines.use_all_machinetype'): + if not user_request.has_perm("machines.use_all_machinetype"): return ( False, _("You don't have the right to use all machine types."), - ('machines.use_all_machinetype',) + ("machines.use_all_machinetype",), ) return True, None, None @@ -331,56 +348,35 @@ class MachineType(RevMixin, AclMixin, models.Model): class IpType(RevMixin, AclMixin, models.Model): """ Type d'ip, définissant un range d'ip, affecté aux machine types""" + name = models.CharField(max_length=255) - extension = models.ForeignKey('Extension', on_delete=models.PROTECT) + extension = models.ForeignKey("Extension", on_delete=models.PROTECT) need_infra = models.BooleanField(default=False) - domaine_ip_start = models.GenericIPAddressField(protocol='IPv4') - domaine_ip_stop = models.GenericIPAddressField(protocol='IPv4') + domaine_ip_start = models.GenericIPAddressField(protocol="IPv4") + domaine_ip_stop = models.GenericIPAddressField(protocol="IPv4") domaine_ip_network = models.GenericIPAddressField( - protocol='IPv4', + protocol="IPv4", null=True, blank=True, - help_text=_("Network containing the domain's IPv4 range (optional)") + help_text=_("Network containing the domain's IPv4 range (optional)"), ) domaine_ip_netmask = models.IntegerField( default=24, - validators=[ - MaxValueValidator(31), - MinValueValidator(8) - ], - help_text=_("Netmask for the domain's IPv4 range") + validators=[MaxValueValidator(31), MinValueValidator(8)], + help_text=_("Netmask for the domain's IPv4 range"), ) reverse_v4 = models.BooleanField( - default=False, - help_text=_("Enable reverse DNS for IPv4"), - ) - prefix_v6 = models.GenericIPAddressField( - protocol='IPv6', - null=True, - blank=True + default=False, help_text=_("Enable reverse DNS for IPv4") ) + prefix_v6 = models.GenericIPAddressField(protocol="IPv6", null=True, blank=True) prefix_v6_length = models.IntegerField( - default=64, - validators=[ - MaxValueValidator(128), - MinValueValidator(0) - ] + default=64, validators=[MaxValueValidator(128), MinValueValidator(0)] ) reverse_v6 = models.BooleanField( - default=False, - help_text=_("Enable reverse DNS for IPv6"), - ) - vlan = models.ForeignKey( - 'Vlan', - on_delete=models.PROTECT, - blank=True, - null=True - ) - ouverture_ports = models.ForeignKey( - 'OuverturePortList', - blank=True, - null=True + default=False, help_text=_("Enable reverse DNS for IPv6") ) + vlan = models.ForeignKey("Vlan", on_delete=models.PROTECT, blank=True, null=True) + ouverture_ports = models.ForeignKey("OuverturePortList", blank=True, null=True) class Meta: permissions = ( @@ -415,24 +411,25 @@ class IpType(RevMixin, AclMixin, models.Model): """Iter sur les range cidr, et renvoie network, broacast , etc""" return [ { - 'network': str(ip_set.network), - 'netmask': str(ip_set.netmask), - 'netmask_cidr': str(ip_set.prefixlen), - 'broadcast': str(ip_set.broadcast), - 'vlan': str(self.vlan), - 'vlan_id': self.vlan.vlan_id - } for ip_set in self.ip_set.iter_cidrs() + "network": str(ip_set.network), + "netmask": str(ip_set.netmask), + "netmask_cidr": str(ip_set.prefixlen), + "broadcast": str(ip_set.broadcast), + "vlan": str(self.vlan), + "vlan_id": self.vlan.vlan_id, + } + for ip_set in self.ip_set.iter_cidrs() ] @cached_property def ip6_set_full_info(self): if self.prefix_v6: return { - 'network': str(self.prefix_v6), - 'netmask': 'ffff:ffff:ffff:ffff::', - 'netmask_cidr': str(self.prefix_v6_length), - 'vlan': str(self.vlan), - 'vlan_id': self.vlan.vlan_id + "network": str(self.prefix_v6), + "netmask": "ffff:ffff:ffff:ffff::", + "netmask_cidr": str(self.prefix_v6_length), + "vlan": str(self.vlan), + "vlan_id": self.vlan.vlan_id, } else: return None @@ -442,7 +439,9 @@ class IpType(RevMixin, AclMixin, models.Model): """Renvoie le network parent du range start-stop, si spécifié Différent de ip_set_cidrs ou iP_set, car lui est supérieur ou égal""" if self.domaine_ip_network: - return IPNetwork(str(self.domaine_ip_network) + '/' + str(self.domaine_ip_netmask)) + return IPNetwork( + str(self.domaine_ip_network) + "/" + str(self.domaine_ip_netmask) + ) return None @cached_property @@ -450,12 +449,12 @@ class IpType(RevMixin, AclMixin, models.Model): """Renvoie les infos du network contenant du range""" if self.ip_network: return { - 'network': str(self.ip_network.network), - 'netmask': str(self.ip_network.netmask), - 'broadcast': str(self.ip_network.broadcast), - 'netmask_cidr': str(self.ip_network.prefixlen), - 'vlan': str(self.vlan), - 'vlan_id': self.vlan.vlan_id + "network": str(self.ip_network.network), + "netmask": str(self.ip_network.netmask), + "broadcast": str(self.ip_network.broadcast), + "netmask_cidr": str(self.ip_network.prefixlen), + "vlan": str(self.vlan), + "vlan_id": self.vlan.vlan_id, } else: return None @@ -471,9 +470,7 @@ class IpType(RevMixin, AclMixin, 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 @@ -481,9 +478,7 @@ class IpType(RevMixin, AclMixin, models.Model): associé à l'ip""" # Creation du range d'ip dans les objets iplist ip_obj = [IpList(ip_type=self, ipv4=str(ip)) for ip in self.ip_range] - listes_ip = IpList.objects.filter( - ipv4__in=[str(ip) for ip in self.ip_range] - ) + listes_ip = IpList.objects.filter(ipv4__in=[str(ip) for ip in self.ip_range]) # Si il n'y a pas d'ip, on les crée if not listes_ip: IpList.objects.bulk_create(ip_obj) @@ -496,9 +491,13 @@ class IpType(RevMixin, AclMixin, models.Model): """ Methode dépréciée, IpList est en mode cascade et supprimé automatiquement""" if Interface.objects.filter(ipv4__in=self.ip_objects()): - raise ValidationError(_("One or several IP addresses from the" - " range are affected, impossible to delete" - " the range.")) + raise ValidationError( + _( + "One or several IP addresses from the" + " range are affected, impossible to delete" + " the range." + ) + ) for ip in self.ip_objects(): ip.delete() @@ -508,26 +507,29 @@ class IpType(RevMixin, AclMixin, models.Model): return else: for ipv6 in Ipv6List.objects.filter( - interface__in=Interface.objects.filter( - machine_type__in=MachineType.objects.filter(ip_type=self) - ) + interface__in=Interface.objects.filter( + machine_type__in=MachineType.objects.filter(ip_type=self) + ) ): ipv6.check_and_replace_prefix(prefix=self.prefix_v6) def get_associated_ptr_records(self): from re2o.utils import all_active_assigned_interfaces + if self.reverse_v4: - return (all_active_assigned_interfaces() - .filter(machine_type__ip_type=self) - .filter(ipv4__isnull=False)) + return ( + all_active_assigned_interfaces() + .filter(machine_type__ip_type=self) + .filter(ipv4__isnull=False) + ) else: return None def get_associated_ptr_v6_records(self): from re2o.utils import all_active_interfaces + if self.reverse_v6: - return (all_active_interfaces(full=True) - .filter(machine_type__ip_type=self)) + return all_active_interfaces(full=True).filter(machine_type__ip_type=self) else: return None @@ -541,22 +543,34 @@ class IpType(RevMixin, AclMixin, models.Model): raise ValidationError(_("Range end must be after range start...")) # On ne crée pas plus grand qu'un /16 if self.ip_range.size > 65536: - raise ValidationError(_("The range is too large, you can't create" - " a larger one than a /16.")) + raise ValidationError( + _( + "The range is too large, you can't create" + " a larger one than a /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(_("The specified range is not disjoint" - " from existing ranges.")) + raise ValidationError( + _("The specified range is not disjoint" " from existing ranges.") + ) # On formate le prefix v6 if self.prefix_v6: - self.prefix_v6 = str(IPNetwork(self.prefix_v6 + '/64').network) + self.prefix_v6 = str(IPNetwork(self.prefix_v6 + "/64").network) # On vérifie qu'un domaine network/netmask contiens bien le domaine ip start-stop if self.domaine_ip_network: - if not self.domaine_ip_start in self.ip_network or not self.domaine_ip_stop in self.ip_network: - raise ValidationError(_("If you specify a domain network or" - " netmask, it must contain the" - " domain's IP range.")) + if ( + not self.domaine_ip_start in self.ip_network + or not self.domaine_ip_stop in self.ip_network + ): + raise ValidationError( + _( + "If you specify a domain network or" + " netmask, it must contain the" + " domain's IP range." + ) + ) return def save(self, *args, **kwargs): @@ -570,9 +584,9 @@ class IpType(RevMixin, AclMixin, models.Model): :param user_request: instance user qui fait l'edition :return: True ou False avec la raison de l'échec le cas échéant""" return ( - user_request.has_perm('machines.use_all_iptype'), + user_request.has_perm("machines.use_all_iptype"), None, - ('machines.use_all_iptype',) + ("machines.use_all_iptype",), ) def __str__(self): @@ -582,26 +596,19 @@ class IpType(RevMixin, AclMixin, models.Model): class Vlan(RevMixin, AclMixin, models.Model): """ Un vlan : vlan_id et nom On limite le vlan id entre 0 et 4096, comme défini par la norme""" + vlan_id = models.PositiveIntegerField(validators=[MaxValueValidator(4095)]) name = models.CharField(max_length=256) comment = models.CharField(max_length=256, blank=True) - #Réglages supplémentaires + # Réglages supplémentaires arp_protect = models.BooleanField(default=False) dhcp_snooping = models.BooleanField(default=False) dhcpv6_snooping = models.BooleanField(default=False) - igmp = models.BooleanField( - default=False, - help_text=_("v4 multicast management") - ) - mld = models.BooleanField( - default=False, - help_text=_("v6 multicast management") - ) + igmp = models.BooleanField(default=False, help_text=_("v4 multicast management")) + mld = models.BooleanField(default=False, help_text=_("v6 multicast management")) class Meta: - permissions = ( - ("view_vlan", _("Can view a VLAN object")), - ) + permissions = (("view_vlan", _("Can view a VLAN object")),) verbose_name = _("VLAN") verbose_name_plural = _("VLANs") @@ -613,34 +620,24 @@ class Nas(RevMixin, AclMixin, models.Model): """ 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""" - default_mode = '802.1X' - AUTH = ( - ('802.1X', '802.1X'), - ('Mac-address', _("MAC-address")), - ) + + default_mode = "802.1X" + AUTH = (("802.1X", "802.1X"), ("Mac-address", _("MAC-address"))) name = models.CharField(max_length=255, unique=True) nas_type = models.ForeignKey( - 'MachineType', - on_delete=models.PROTECT, - related_name='nas_type' + "MachineType", on_delete=models.PROTECT, related_name="nas_type" ) machine_type = models.ForeignKey( - 'MachineType', - on_delete=models.PROTECT, - related_name='machinetype_on_nas' + "MachineType", on_delete=models.PROTECT, related_name="machinetype_on_nas" ) port_access_mode = models.CharField( - choices=AUTH, - default=default_mode, - max_length=32 + choices=AUTH, default=default_mode, max_length=32 ) autocapture_mac = models.BooleanField(default=False) class Meta: - permissions = ( - ("view_nas", _("Can view a NAS device object")), - ) + permissions = (("view_nas", _("Can view a NAS device object")),) verbose_name = _("NAS device") verbose_name_plural = _("NAS devices") @@ -654,34 +651,36 @@ class SOA(RevMixin, AclMixin, models.Model): Les valeurs par défault viennent des recommandations RIPE : https://www.ripe.net/publications/docs/ripe-203 """ + name = models.CharField(max_length=255) - mail = models.EmailField( - help_text=_("Contact email address for the zone") - ) + mail = models.EmailField(help_text=_("Contact email address for the zone")) refresh = models.PositiveIntegerField( default=86400, # 24 hours - help_text=_("Seconds before the secondary DNS have to ask the primary" - " DNS serial to detect a modification") + help_text=_( + "Seconds before the secondary DNS have to ask the primary" + " DNS serial to detect a modification" + ), ) retry = models.PositiveIntegerField( default=7200, # 2 hours - help_text=_("Seconds before the secondary DNS ask the serial again in" - " case of a primary DNS timeout") + help_text=_( + "Seconds before the secondary DNS ask the serial again in" + " case of a primary DNS timeout" + ), ) expire = models.PositiveIntegerField( default=3600000, # 1000 hours - help_text=_("Seconds before the secondary DNS stop answering requests" - " in case of primary DNS timeout") + help_text=_( + "Seconds before the secondary DNS stop answering requests" + " in case of primary DNS timeout" + ), ) ttl = models.PositiveIntegerField( - default=172800, # 2 days - help_text=_("Time to Live") + default=172800, help_text=_("Time to Live") # 2 days ) class Meta: - permissions = ( - ("view_soa", _("Can view an SOA record object")), - ) + permissions = (("view_soa", _("Can view an SOA record object")),) verbose_name = _("SOA record") verbose_name_plural = _("SOA records") @@ -698,22 +697,22 @@ class SOA(RevMixin, AclMixin, models.Model): ; TTL """ return ( - ' {refresh}; refresh\n' - ' {retry}; retry\n' - ' {expire}; expire\n' - ' {ttl}; TTL' + " {refresh}; refresh\n" + " {retry}; retry\n" + " {expire}; expire\n" + " {ttl}; TTL" ).format( refresh=str(self.refresh).ljust(12), retry=str(self.retry).ljust(12), expire=str(self.expire).ljust(12), - ttl=str(self.ttl).ljust(12) + ttl=str(self.ttl).ljust(12), ) @cached_property def dns_soa_mail(self): """ Renvoie le mail dans l'enregistrement SOA """ - mail_fields = str(self.mail).split('@') - return mail_fields[0].replace('.', '\\.') + '.' + mail_fields[1] + '.' + mail_fields = str(self.mail).split("@") + return mail_fields[0].replace(".", "\\.") + "." + mail_fields[1] + "." @classmethod def new_default_soa(cls): @@ -722,40 +721,36 @@ class SOA(RevMixin, AclMixin, models.Model): /!\ Ne jamais supprimer ou renommer cette fonction car elle est utilisée dans les migrations de la BDD. """ return cls.objects.get_or_create( - name=_("SOA to edit"), - mail="postmaster@example.com" + name=_("SOA to edit"), mail="postmaster@example.com" )[0].pk class Extension(RevMixin, AclMixin, models.Model): """ Extension dns type example.org. Précise si tout le monde peut l'utiliser, associé à un origin (ip d'origine)""" + name = models.CharField( max_length=255, unique=True, - help_text=_("Zone name, must begin with a dot (.example.org)") + help_text=_("Zone name, must begin with a dot (.example.org)"), ) need_infra = models.BooleanField(default=False) origin = models.ForeignKey( - 'IpList', + "IpList", on_delete=models.PROTECT, blank=True, null=True, - help_text=_("A record associated with the zone") + help_text=_("A record associated with the zone"), ) origin_v6 = models.GenericIPAddressField( - protocol='IPv6', + protocol="IPv6", null=True, blank=True, - help_text=_("AAAA record associated with the zone") - ) - soa = models.ForeignKey( - 'SOA', - on_delete=models.CASCADE + help_text=_("AAAA record associated with the zone"), ) + soa = models.ForeignKey("SOA", on_delete=models.CASCADE) dnssec = models.BooleanField( - default=False, - help_text=_("Should the zone be signed with DNSSEC") + default=False, help_text=_("Should the zone be signed with DNSSEC") ) class Meta: @@ -780,30 +775,40 @@ class Extension(RevMixin, AclMixin, models.Model): def get_associated_sshfp_records(self): from re2o.utils import all_active_assigned_interfaces - return (all_active_assigned_interfaces() - .filter(machine_type__ip_type__extension=self) - .filter(machine__id__in=SshFp.objects.values('machine'))) + + return ( + all_active_assigned_interfaces() + .filter(machine_type__ip_type__extension=self) + .filter(machine__id__in=SshFp.objects.values("machine")) + ) def get_associated_a_records(self): from re2o.utils import all_active_assigned_interfaces - return (all_active_assigned_interfaces() - .filter(machine_type__ip_type__extension=self) - .filter(ipv4__isnull=False)) + + return ( + all_active_assigned_interfaces() + .filter(machine_type__ip_type__extension=self) + .filter(ipv4__isnull=False) + ) def get_associated_aaaa_records(self): from re2o.utils import all_active_interfaces - return (all_active_interfaces(full=True) - .filter(machine_type__ip_type__extension=self)) + + return all_active_interfaces(full=True).filter( + machine_type__ip_type__extension=self + ) def get_associated_cname_records(self): from re2o.utils import all_active_assigned_interfaces - return (Domain.objects - .filter(extension=self) - .filter(cname__interface_parent__in=all_active_assigned_interfaces()) - .prefetch_related('cname')) + + return ( + Domain.objects.filter(extension=self) + .filter(cname__interface_parent__in=all_active_assigned_interfaces()) + .prefetch_related("cname") + ) def get_associated_dname_records(self): - return (DName.objects.filter(alias=self)) + return DName.objects.filter(alias=self) @staticmethod def can_use_all(user_request, *_args, **_kwargs): @@ -811,18 +816,18 @@ class Extension(RevMixin, AclMixin, models.Model): restrictions :param user_request: instance user qui fait l'edition :return: True ou False avec la raison de l'échec le cas échéant""" - can = user_request.has_perm('machines.use_all_extension') + can = user_request.has_perm("machines.use_all_extension") return ( can, _("You cannot use all extensions.") if not can else None, - ('machines.use_all_extension',) + ("machines.use_all_extension",), ) def __str__(self): return self.name def clean(self, *args, **kwargs): - if self.name and self.name[0] != '.': + if self.name and self.name[0] != ".": raise ValidationError(_("An extension must begin with a dot.")) super(Extension, self).clean(*args, **kwargs) @@ -831,18 +836,16 @@ class Mx(RevMixin, AclMixin, models.Model): """ Entrées des MX. Enregistre la zone (extension) associée et la priorité Todo : pouvoir associer un MX à une interface """ - zone = models.ForeignKey('Extension', on_delete=models.PROTECT) + + zone = models.ForeignKey("Extension", on_delete=models.PROTECT) priority = models.PositiveIntegerField() - name = models.ForeignKey('Domain', on_delete=models.PROTECT) + name = models.ForeignKey("Domain", on_delete=models.PROTECT) ttl = models.PositiveIntegerField( - verbose_name=_("Time To Live (TTL)"), - default=172800, # 2 days + verbose_name=_("Time To Live (TTL)"), default=172800 # 2 days ) class Meta: - permissions = ( - ("view_mx", _("Can view an MX record object")), - ) + permissions = (("view_mx", _("Can view an MX record object")),) verbose_name = _("MX record") verbose_name_plural = _("MX records") @@ -851,27 +854,24 @@ class Mx(RevMixin, AclMixin, models.Model): """Renvoie l'entrée DNS complète pour un MX à mettre dans les fichiers de zones""" return "@ IN MX {prior} {name}".format( - prior=str(self.priority).ljust(3), - name=str(self.name) + prior=str(self.priority).ljust(3), name=str(self.name) ) def __str__(self): - return str(self.zone) + ' ' + str(self.priority) + ' ' + str(self.name) + return str(self.zone) + " " + str(self.priority) + " " + str(self.name) class Ns(RevMixin, AclMixin, models.Model): """Liste des enregistrements name servers par zone considéérée""" - zone = models.ForeignKey('Extension', on_delete=models.PROTECT) - ns = models.ForeignKey('Domain', on_delete=models.PROTECT) + + zone = models.ForeignKey("Extension", on_delete=models.PROTECT) + ns = models.ForeignKey("Domain", on_delete=models.PROTECT) ttl = models.PositiveIntegerField( - verbose_name=_("Time To Live (TTL)"), - default=172800, # 2 days + verbose_name=_("Time To Live (TTL)"), default=172800 # 2 days ) class Meta: - permissions = ( - ("view_ns", _("Can view an NS record object")), - ) + permissions = (("view_ns", _("Can view an NS record object")),) verbose_name = _("NS record") verbose_name_plural = _("NS records") @@ -881,29 +881,26 @@ class Ns(RevMixin, AclMixin, models.Model): return "@ IN NS " + str(self.ns) def __str__(self): - return str(self.zone) + ' ' + str(self.ns) + return str(self.zone) + " " + str(self.ns) class Txt(RevMixin, AclMixin, models.Model): """ Un enregistrement TXT associé à une extension""" - zone = models.ForeignKey('Extension', on_delete=models.PROTECT) + + zone = models.ForeignKey("Extension", on_delete=models.PROTECT) field1 = models.CharField(max_length=255) field2 = models.TextField(max_length=2047) ttl = models.PositiveIntegerField( - verbose_name=_("Time To Live (TTL)"), - default=172800, # 2 days + verbose_name=_("Time To Live (TTL)"), default=172800 # 2 days ) class Meta: - permissions = ( - ("view_txt", _("Can view a TXT record object")), - ) + permissions = (("view_txt", _("Can view a TXT record object")),) verbose_name = _("TXT record") verbose_name_plural = _("TXT records") 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): @@ -913,17 +910,15 @@ class Txt(RevMixin, AclMixin, models.Model): class DName(RevMixin, AclMixin, models.Model): """A DNAME entry for the DNS.""" - zone = models.ForeignKey('Extension', on_delete=models.PROTECT) + + zone = models.ForeignKey("Extension", on_delete=models.PROTECT) alias = models.CharField(max_length=255) ttl = models.PositiveIntegerField( - verbose_name=_("Time To Live (TTL)"), - default=172800, # 2 days + verbose_name=_("Time To Live (TTL)"), default=172800 # 2 days ) class Meta: - permissions = ( - ("view_dname", _("Can view a DNAME record object")), - ) + permissions = (("view_dname", _("Can view a DNAME record object")),) verbose_name = _("DNAME record") verbose_name_plural = _("DNAME records") @@ -938,65 +933,82 @@ class DName(RevMixin, AclMixin, models.Model): class Srv(RevMixin, AclMixin, models.Model): """ A SRV record """ - TCP = 'TCP' - UDP = 'UDP' + + TCP = "TCP" + UDP = "UDP" service = models.CharField(max_length=31) protocole = models.CharField( - max_length=3, - choices=( - (TCP, 'TCP'), - (UDP, 'UDP'), - ), - default=TCP, + max_length=3, choices=((TCP, "TCP"), (UDP, "UDP")), default=TCP ) - extension = models.ForeignKey('Extension', on_delete=models.PROTECT) + extension = models.ForeignKey("Extension", on_delete=models.PROTECT) ttl = models.PositiveIntegerField( - default=172800, # 2 days - help_text=_("Time to Live") + default=172800, help_text=_("Time to Live") # 2 days ) priority = models.PositiveIntegerField( default=0, validators=[MaxValueValidator(65535)], - help_text=_("Priority of the target server (positive integer value," - " the lower it is, the more the server will be used if" - " available)") + help_text=_( + "Priority of the target server (positive integer value," + " the lower it is, the more the server will be used if" + " available)" + ), ) weight = models.PositiveIntegerField( default=0, validators=[MaxValueValidator(65535)], - help_text=_("Relative weight for records with the same priority" - " (integer value between 0 and 65535)") + help_text=_( + "Relative weight for records with the same priority" + " (integer value between 0 and 65535)" + ), ) port = models.PositiveIntegerField( - validators=[MaxValueValidator(65535)], - help_text=_("TCP/UDP port") + validators=[MaxValueValidator(65535)], help_text=_("TCP/UDP port") ) target = models.ForeignKey( - 'Domain', - on_delete=models.PROTECT, - help_text=_("Target server") + "Domain", on_delete=models.PROTECT, help_text=_("Target server") ) class Meta: - permissions = ( - ("view_srv", _("Can view an SRV record object")), - ) + permissions = (("view_srv", _("Can view an SRV record object")),) verbose_name = _("SRV record") verbose_name_plural = _("SRV records") def __str__(self): - return str(self.service) + ' ' + str(self.protocole) + ' ' + \ - str(self.extension) + ' ' + str(self.priority) + \ - ' ' + str(self.weight) + str(self.port) + str(self.target) + return ( + str(self.service) + + " " + + str(self.protocole) + + " " + + str(self.extension) + + " " + + str(self.priority) + + " " + + str(self.weight) + + str(self.port) + + str(self.target) + ) @cached_property def dns_entry(self): """Renvoie l'enregistrement SRV complet pour le fichier de zone""" - return str(self.service) + '._' + str(self.protocole).lower() + \ - str(self.extension) + '. ' + str(self.ttl) + ' IN SRV ' + \ - str(self.priority) + ' ' + str(self.weight) + ' ' + \ - str(self.port) + ' ' + str(self.target) + '.' + return ( + str(self.service) + + "._" + + str(self.protocole).lower() + + str(self.extension) + + ". " + + str(self.ttl) + + " IN SRV " + + str(self.priority) + + " " + + str(self.weight) + + " " + + str(self.port) + + " " + + str(self.target) + + "." + ) class SshFp(RevMixin, AclMixin, models.Model): @@ -1010,20 +1022,11 @@ class SshFp(RevMixin, AclMixin, models.Model): ("ecdsa-sha2-nistp521", "ecdsa-sha2-nistp521"), ) - machine = models.ForeignKey('Machine', on_delete=models.CASCADE) - pub_key_entry = models.TextField( - help_text=_("SSH public key"), - max_length=2048 - ) - algo = models.CharField( - choices=ALGO, - max_length=32 - ) + machine = models.ForeignKey("Machine", on_delete=models.CASCADE) + pub_key_entry = models.TextField(help_text=_("SSH public key"), max_length=2048) + algo = models.CharField(choices=ALGO, max_length=32) comment = models.CharField( - help_text=_("Comment"), - max_length=255, - null=True, - blank=True + help_text=_("Comment"), max_length=255, null=True, blank=True ) @cached_property @@ -1046,9 +1049,7 @@ class SshFp(RevMixin, AclMixin, models.Model): } class Meta: - permissions = ( - ("view_sshfp", _("Can view an SSHFP record object")), - ) + permissions = (("view_sshfp", _("Can view an SSHFP record object")),) verbose_name = _("SSHFP record") verbose_name_plural = _("SSHFP records") @@ -1062,7 +1063,7 @@ class SshFp(RevMixin, AclMixin, models.Model): return self.machine.can_delete(user_request, *args, **kwargs) def __str__(self): - return str(self.algo) + ' ' + str(self.comment) + return str(self.algo) + " " + str(self.comment) class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): @@ -1073,23 +1074,20 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): - le type parent associé au range ip et à l'extension - un objet domain associé contenant son nom - la liste des ports oiuvert""" + ipv4 = models.OneToOneField( - 'IpList', - on_delete=models.PROTECT, - blank=True, - null=True + "IpList", on_delete=models.PROTECT, blank=True, null=True ) mac_address = MACAddressField(integer=False) - machine = models.ForeignKey('Machine', on_delete=models.CASCADE) - machine_type = models.ForeignKey('MachineType', on_delete=models.PROTECT) + machine = models.ForeignKey("Machine", on_delete=models.CASCADE) + machine_type = models.ForeignKey("MachineType", on_delete=models.PROTECT) details = models.CharField(max_length=255, blank=True) - port_lists = models.ManyToManyField('OuverturePortList', blank=True) + port_lists = models.ManyToManyField("OuverturePortList", blank=True) class Meta: permissions = ( ("view_interface", _("Can view an interface object")), - ("change_interface_machine", - _("Can change the owner of an interface")), + ("change_interface_machine", _("Can change the owner of an interface")), ) verbose_name = _("interface") verbose_name_plural = _("interfaces") @@ -1115,23 +1113,23 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): @cached_property def gen_ipv6_dhcpv6(self): """Cree une ip, à assigner avec dhcpv6 sur une machine""" - prefix_v6 = self.machine_type.ip_type.prefix_v6.encode().decode('utf-8') + prefix_v6 = self.machine_type.ip_type.prefix_v6.encode().decode("utf-8") if not prefix_v6: return None return IPv6Address( - IPv6Address(prefix_v6).exploded[:20] + - IPv6Address(self.id).exploded[20:] + IPv6Address(prefix_v6).exploded[:20] + IPv6Address(self.id).exploded[20:] ) + @cached_property def get_vendor(self): """Retourne le vendeur associé à la mac de l'interface""" mac = EUI(self.mac_address) try: - oui = mac.oui - vendor = oui.registration().org + oui = mac.oui + vendor = oui.registration().org except NotRegisteredError: - vendor = "Unknown vendor" - return(vendor) + vendor = "Unknown vendor" + return vendor def sync_ipv6_dhcpv6(self): """Affecte une ipv6 dhcpv6 calculée à partir de l'id de la machine""" @@ -1153,9 +1151,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ipv6_slaac = self.ipv6_slaac if not ipv6_slaac: return - ipv6_object = (Ipv6List.objects - .filter(interface=self, slaac_ip=True) - .first()) + ipv6_object = Ipv6List.objects.filter(interface=self, slaac_ip=True).first() if not ipv6_object: ipv6_object = Ipv6List(interface=self, slaac_ip=True) if ipv6_object.ipv6 != str(ipv6_slaac): @@ -1164,11 +1160,11 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): def sync_ipv6(self): """Cree et met à jour l'ensemble des ipv6 en fonction du mode choisi""" - if (preferences.models.OptionalMachine - .get_cached_value('ipv6_mode') == 'SLAAC'): + if preferences.models.OptionalMachine.get_cached_value("ipv6_mode") == "SLAAC": self.sync_ipv6_slaac() - elif (preferences.models.OptionalMachine - .get_cached_value('ipv6_mode') == 'DHCPV6'): + elif ( + preferences.models.OptionalMachine.get_cached_value("ipv6_mode") == "DHCPV6" + ): self.sync_ipv6_dhcpv6() else: return @@ -1177,11 +1173,11 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): """ Renvoie le queryset de la liste des ipv6 On renvoie l'ipv6 slaac que si le mode slaac est activé (et non dhcpv6)""" - if (preferences.models.OptionalMachine - .get_cached_value('ipv6_mode') == 'SLAAC'): + if preferences.models.OptionalMachine.get_cached_value("ipv6_mode") == "SLAAC": return self.ipv6list.all() - elif (preferences.models.OptionalMachine - .get_cached_value('ipv6_mode') == 'DHCPV6'): + elif ( + preferences.models.OptionalMachine.get_cached_value("ipv6_mode") == "DHCPV6" + ): return self.ipv6list.filter(slaac_ip=False) else: return [] @@ -1204,8 +1200,9 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): if free_ips: self.ipv4 = free_ips[0] else: - raise ValidationError(_("There is no IP address available in the" - " slash.")) + raise ValidationError( + _("There is no IP address available in the" " slash.") + ) return def unassign_ipv4(self): @@ -1255,7 +1252,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): # instance. # But in our case, it's impossible to create a type value so we raise # the error. - if not hasattr(self, 'machine_type'): + if not hasattr(self, "machine_type"): raise ValidationError(_("The selected IP type is invalid.")) self.filter_macaddress() if not self.ipv4 or self.machine_type.ip_type != self.ipv4.ip_type: @@ -1264,17 +1261,23 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): def validate_unique(self, *args, **kwargs): super(Interface, self).validate_unique(*args, **kwargs) - interfaces_similar = Interface.objects.filter(mac_address=self.mac_address, machine_type__ip_type=self.machine_type.ip_type) + interfaces_similar = Interface.objects.filter( + mac_address=self.mac_address, + machine_type__ip_type=self.machine_type.ip_type, + ) if interfaces_similar and interfaces_similar.first() != self: - raise ValidationError(_("Mac address already registered in this Machine Type/Subnet")) + raise ValidationError( + _("Mac address already registered in this Machine Type/Subnet") + ) def save(self, *args, **kwargs): self.filter_macaddress() # On verifie la cohérence en forçant l'extension par la méthode if self.ipv4: if self.machine_type.ip_type != self.ipv4.ip_type: - raise ValidationError(_("The IPv4 address and the machine type" - " don't match.")) + raise ValidationError( + _("The IPv4 address and the machine type" " don't match.") + ) self.validate_unique() super(Interface, self).save(*args, **kwargs) @@ -1289,29 +1292,32 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): machine = Machine.objects.get(pk=machineid) except Machine.DoesNotExist: return False, _("Nonexistent machine."), None - if not user_request.has_perm('machines.add_interface'): - if not (preferences.models.OptionalMachine - .get_cached_value('create_machine')): - return False, _("You can't add a machine."), ('machines.add_interface',) - max_lambdauser_interfaces = (preferences.models.OptionalMachine - .get_cached_value( - 'max_lambdauser_interfaces' - )) + if not user_request.has_perm("machines.add_interface"): + if not ( + preferences.models.OptionalMachine.get_cached_value("create_machine") + ): + return False, _("You can't add a machine."), ("machines.add_interface",) + max_lambdauser_interfaces = preferences.models.OptionalMachine.get_cached_value( + "max_lambdauser_interfaces" + ) if machine.user != user_request: return ( False, - _("You don't have the right to add an interface" - " to a machine of another user."), - ('machines.add_interface',) + _( + "You don't have the right to add an interface" + " to a machine of another user." + ), + ("machines.add_interface",), ) - if (machine.user.user_interfaces().count() >= - max_lambdauser_interfaces): + if machine.user.user_interfaces().count() >= max_lambdauser_interfaces: return ( False, - _("You reached the maximum number of interfaces" - " that you are allowed to create yourself" - " (%s)." % max_lambdauser_interfaces), - ('machines.add_interface',) + _( + "You reached the maximum number of interfaces" + " that you are allowed to create yourself" + " (%s)." % max_lambdauser_interfaces + ), + ("machines.add_interface",), ) return True, None, None @@ -1319,11 +1325,11 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): def can_change_machine(user_request, *_args, **_kwargs): """Check if a user can change the machine associated with an Interface object """ - can = user_request.has_perm('machines.change_interface_machine') + can = user_request.has_perm("machines.change_interface_machine") return ( can, _("Permission required to edit the machine.") if not can else None, - ('machines.change_interface_machine',) + ("machines.change_interface_machine",), ) def can_edit(self, user_request, *args, **kwargs): @@ -1334,18 +1340,13 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): :return: soit True, soit False avec la raison de l'échec""" if self.machine.user != user_request: can_user, _message, permissions = self.machine.user.can_edit( - user_request, - *args, - **kwargs + user_request, *args, **kwargs ) - if not ( - user_request.has_perm('machines.change_interface') and - can_user ): + if not (user_request.has_perm("machines.change_interface") and can_user): return ( False, - _("You don't have the right to edit a machine of" - " another user."), - ('machines.change_interface',) + permissions + _("You don't have the right to edit a machine of" " another user."), + ("machines.change_interface",) + permissions, ) return True, None, None @@ -1357,18 +1358,13 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): :return: soit True, soit False avec la raison de l'échec""" if self.machine.user != user_request: can_user, _message, permissions = self.machine.user.can_edit( - user_request, - *args, - **kwargs + user_request, *args, **kwargs ) - if not ( - user_request.has_perm('machines.change_interface') and - can_user): + if not (user_request.has_perm("machines.change_interface") and can_user): return ( False, - _("You don't have the right to edit a machine of" - " another user."), - ('machines.change_interface',) + permissions + _("You don't have the right to edit a machine of" " another user."), + ("machines.change_interface",) + permissions, ) return True, None, None @@ -1378,20 +1374,20 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): :param self: instance interface à voir :param user_request: instance user qui fait l'edition :return: True ou False avec la raison de l'échec le cas échéant""" - if (not user_request.has_perm('machines.view_interface') and - self.machine.user != user_request): + if ( + not user_request.has_perm("machines.view_interface") + and self.machine.user != user_request + ): return ( False, _("You don't have the right to view machines other than yours."), - ('machines.view_interface',) + ("machines.view_interface",), ) return True, None, None def __init__(self, *args, **kwargs): super(Interface, self).__init__(*args, **kwargs) - self.field_permissions = { - 'machine': self.can_change_machine, - } + self.field_permissions = {"machine": self.can_change_machine} def __str__(self): try: @@ -1404,21 +1400,19 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): """ A list of IPv6 """ - ipv6 = models.GenericIPAddressField( - protocol='IPv6', - ) + ipv6 = models.GenericIPAddressField(protocol="IPv6") interface = models.ForeignKey( - 'Interface', - on_delete=models.CASCADE, - related_name='ipv6list' + "Interface", on_delete=models.CASCADE, related_name="ipv6list" ) slaac_ip = models.BooleanField(default=False) class Meta: permissions = ( ("view_ipv6list", _("Can view an IPv6 addresses list object")), - ("change_ipv6list_slaac_ip", _("Can change the SLAAC value of an" - " IPv6 addresses list")), + ( + "change_ipv6list_slaac_ip", + _("Can change the SLAAC value of an" " IPv6 addresses list"), + ), ) verbose_name = _("IPv6 addresses list") verbose_name_plural = _("IPv6 addresses lists") @@ -1434,25 +1428,28 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): interface = Interface.objects.get(pk=interfaceid) except Interface.DoesNotExist: return False, _("Nonexistent interface."), None - if not user_request.has_perm('machines.add_ipv6list'): + if not user_request.has_perm("machines.add_ipv6list"): if interface.machine.user != user_request: return ( False, - _("You don't have the right to add an alias to a" - " machine of another user."), - ('machines.add_ipv6list',) + _( + "You don't have the right to add an alias to a" + " machine of another user." + ), + ("machines.add_ipv6list",), ) return True, None, None @staticmethod def can_change_slaac_ip(user_request, *_args, **_kwargs): """ Check if a user can change the slaac value """ - can = user_request.has_perm('machines.change_ipv6list_slaac_ip') + can = user_request.has_perm("machines.change_ipv6list_slaac_ip") return ( can, - _("Permission required to change the SLAAC value of an IPv6" - " address") if not can else None, - ('machines.change_ipv6list_slaac_ip',) + _("Permission required to change the SLAAC value of an IPv6" " address") + if not can + else None, + ("machines.change_ipv6list_slaac_ip",), ) def can_edit(self, user_request, *args, **kwargs): @@ -1463,18 +1460,13 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): :return: soit True, soit False avec la raison de l'échec""" if self.interface.machine.user != user_request: can_user, _message, permissions = self.interface.machine.user.can_edit( - user_request, - *args, - **kwargs + user_request, *args, **kwargs ) - if not ( - user_request.has_perm('machines.change_ipv6list') and - can_user): + if not (user_request.has_perm("machines.change_ipv6list") and can_user): return ( False, - _("You don't have the right to edit a machine of" - " another user."), - ('machines.change_ipv6list',) + _("You don't have the right to edit a machine of" " another user."), + ("machines.change_ipv6list",), ) return True, None, None @@ -1486,17 +1478,13 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): :return: soit True, soit False avec la raison de l'échec""" if self.interface.machine.user != user_request: can_user, _message, permissions = self.interface.machine.user.can_edit( - user_request, - *args, - **kwargs + user_request, *args, **kwargs ) - if not (user_request.has_perm('machines.change_ipv6list') and - can_user): + if not (user_request.has_perm("machines.change_ipv6list") and can_user): return ( False, - _("You don't have the right to edit a machine of" - " another user."), - ('machines.change_ipv6list',) + permissions + _("You don't have the right to edit a machine of" " another user."), + ("machines.change_ipv6list",) + permissions, ) return True, None, None @@ -1506,49 +1494,63 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): :param self: instance interface à voir :param user_request: instance user qui fait l'edition :return: True ou False avec la raison de l'échec le cas échéant""" - if (not user_request.has_perm('machines.view_ipv6list') and - self.interface.machine.user != user_request): + if ( + not user_request.has_perm("machines.view_ipv6list") + and self.interface.machine.user != user_request + ): return ( False, _("You don't have the right to view machines other than yours."), - ('machines.view_ipv6list',) + ("machines.view_ipv6list",), ) return True, None, None def __init__(self, *args, **kwargs): super(Ipv6List, self).__init__(*args, **kwargs) - self.field_permissions = { - 'slaac_ip': self.can_change_slaac_ip, - } + self.field_permissions = {"slaac_ip": self.can_change_slaac_ip} def check_and_replace_prefix(self, prefix=None): """Si le prefixe v6 est incorrect, on maj l'ipv6""" - prefix_v6 = prefix or self.interface.machine_type.ip_type.prefix_v6.encode().decode('utf-8') + prefix_v6 = prefix or self.interface.machine_type.ip_type.prefix_v6.encode().decode( + "utf-8" + ) if not prefix_v6: return - if (IPv6Address(self.ipv6.encode().decode('utf-8')).exploded[:20] != - IPv6Address(prefix_v6).exploded[:20]): + if ( + IPv6Address(self.ipv6.encode().decode("utf-8")).exploded[:20] + != IPv6Address(prefix_v6).exploded[:20] + ): self.ipv6 = IPv6Address( - IPv6Address(prefix_v6).exploded[:20] + - IPv6Address(self.ipv6.encode().decode('utf-8')).exploded[20:] + IPv6Address(prefix_v6).exploded[:20] + + IPv6Address(self.ipv6.encode().decode("utf-8")).exploded[20:] ) self.save() def clean(self, *args, **kwargs): - if self.slaac_ip and (Ipv6List.objects - .filter(interface=self.interface, slaac_ip=True) - .exclude(id=self.id)): + if self.slaac_ip and ( + Ipv6List.objects.filter(interface=self.interface, slaac_ip=True).exclude( + id=self.id + ) + ): raise ValidationError(_("A SLAAC IP address is already registered.")) try: - prefix_v6 = self.interface.machine_type.ip_type.prefix_v6.encode().decode('utf-8') - except AttributeError: # Prevents from crashing when there is no defined prefix_v6 + prefix_v6 = self.interface.machine_type.ip_type.prefix_v6.encode().decode( + "utf-8" + ) + except AttributeError: # Prevents from crashing when there is no defined prefix_v6 prefix_v6 = None if prefix_v6: - if (IPv6Address(self.ipv6.encode().decode('utf-8')).exploded[:20] != - IPv6Address(prefix_v6).exploded[:20]): - raise ValidationError(_("The v6 prefix is incorrect and" - " doesn't match the type associated" - " with the machine.")) + if ( + IPv6Address(self.ipv6.encode().decode("utf-8")).exploded[:20] + != IPv6Address(prefix_v6).exploded[:20] + ): + raise ValidationError( + _( + "The v6 prefix is incorrect and" + " doesn't match the type associated" + " with the machine." + ) + ) super(Ipv6List, self).clean(*args, **kwargs) def save(self, *args, **kwargs): @@ -1566,25 +1568,18 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ou cname sont remplis""" interface_parent = models.OneToOneField( - 'Interface', - on_delete=models.CASCADE, - blank=True, - null=True + "Interface", on_delete=models.CASCADE, blank=True, null=True ) name = models.CharField( - help_text=_("Mandatory and unique, must not contain dots."), - max_length=255 + help_text=_("Mandatory and unique, must not contain dots."), max_length=255 ) - extension = models.ForeignKey('Extension', on_delete=models.PROTECT) + extension = models.ForeignKey("Extension", on_delete=models.PROTECT) cname = models.ForeignKey( - 'self', - null=True, - blank=True, - related_name='related_domain' + "self", null=True, blank=True, related_name="related_domain" ) ttl = models.PositiveIntegerField( verbose_name=_("Time To Live (TTL)"), - default=0 # 0 means that the re2o-service for DNS should retrieve the + default=0 # 0 means that the re2o-service for DNS should retrieve the # default TTL ) @@ -1602,7 +1597,7 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): Retourne l'extension propre si c'est un cname, renvoie None sinon""" if self.interface_parent: return self.interface_parent.machine_type.ip_type.extension - elif hasattr(self, 'extension'): + elif hasattr(self, "extension"): return self.extension else: return None @@ -1617,22 +1612,21 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): if self.get_extension(): self.extension = self.get_extension() if self.interface_parent and self.cname: - raise ValidationError(_("You can't create a both A and CNAME" - " record.")) + raise ValidationError(_("You can't create a both A and CNAME" " record.")) if self.cname == self: - raise ValidationError(_("You can't create a CNAME record pointing" - " to itself.")) - HOSTNAME_LABEL_PATTERN = re.compile( - r"(?!-)[A-Z\d-]+(? 63: - raise ValidationError(_("The domain name %s is too long (over 63" - " characters).") % dns) + raise ValidationError( + _("The domain name %s is too long (over 63" " characters).") % dns + ) if not HOSTNAME_LABEL_PATTERN.match(dns): - raise ValidationError(_("The domain name %s contains forbidden" - " characters.") % dns) + raise ValidationError( + _("The domain name %s contains forbidden" " characters.") % dns + ) self.validate_unique() super(Domain, self).clean() @@ -1641,8 +1635,7 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): """ Une entrée DNS""" if self.cname: return "{name} IN CNAME {cname}.".format( - name=str(self.name).ljust(15), - cname=str(self.cname) + name=str(self.name).ljust(15), cname=str(self.cname) ) def save(self, *args, **kwargs): @@ -1676,30 +1669,35 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): interface = Interface.objects.get(pk=interfaceid) except Interface.DoesNotExist: return False, _("Nonexistent interface."), None - if not user_request.has_perm('machines.add_domain'): - max_lambdauser_aliases = (preferences.models.OptionalMachine - .get_cached_value( - 'max_lambdauser_aliases' - )) + if not user_request.has_perm("machines.add_domain"): + max_lambdauser_aliases = preferences.models.OptionalMachine.get_cached_value( + "max_lambdauser_aliases" + ) if interface.machine.user != user_request: return ( False, - _("You don't have the right to add an alias to a" - " machine of another user."), - ('machines.add_domain',) + _( + "You don't have the right to add an alias to a" + " machine of another user." + ), + ("machines.add_domain",), ) - if Domain.objects.filter( + if ( + Domain.objects.filter( cname__in=Domain.objects.filter( - interface_parent__in=(interface.machine.user - .user_interfaces()) + interface_parent__in=(interface.machine.user.user_interfaces()) ) - ).count() >= max_lambdauser_aliases: + ).count() + >= max_lambdauser_aliases + ): return ( False, - _("You reached the maximum number of alias that" - " you are allowed to create yourself (%s). " - % max_lambdauser_aliases), - ('machines.add_domain',) + _( + "You reached the maximum number of alias that" + " you are allowed to create yourself (%s). " + % max_lambdauser_aliases + ), + ("machines.add_domain",), ) return True, None, None @@ -1709,13 +1707,17 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): :param self: Instance domain à editer :param user_request: Utilisateur qui fait la requête :return: soit True, soit False avec la raison de l'échec""" - if (not user_request.has_perm('machines.change_domain') and - self.get_source_interface.machine.user != user_request): + if ( + not user_request.has_perm("machines.change_domain") + and self.get_source_interface.machine.user != user_request + ): return ( False, - _("You don't have the right to edit an alias of a" - " machine of another user."), - ('machines.change_domain',) + _( + "You don't have the right to edit an alias of a" + " machine of another user." + ), + ("machines.change_domain",), ) return True, None, None @@ -1725,13 +1727,17 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): :param self: Instance domain à del :param user_request: Utilisateur qui fait la requête :return: soit True, soit False avec la raison de l'échec""" - if (not user_request.has_perm('machines.delete_domain') and - self.get_source_interface.machine.user != user_request): + if ( + not user_request.has_perm("machines.delete_domain") + and self.get_source_interface.machine.user != user_request + ): return ( False, - _("You don't have the right to delete an alias of a" - " machine of another user."), - ('machines.delete_domain',) + _( + "You don't have the right to delete an alias of a" + " machine of another user." + ), + ("machines.delete_domain",), ) return True, None, None @@ -1741,22 +1747,26 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): :param self: instance domain à voir :param user_request: instance user qui fait l'edition :return: True ou False avec la raison de l'échec le cas échéant""" - if (not user_request.has_perm('machines.view_domain') and - self.get_source_interface.machine.user != user_request): + if ( + not user_request.has_perm("machines.view_domain") + and self.get_source_interface.machine.user != user_request + ): return ( False, _("You don't have the right to view machines other than yours."), - ('machines.view_domain',) + ("machines.view_domain",), ) return True, None, None @staticmethod def can_change_ttl(user_request, *_args, **_kwargs): - can = user_request.has_perm('machines.change_ttl') + can = user_request.has_perm("machines.change_ttl") return ( can, - _("You don't have the right to change the domain's TTL.") if not can else None, - ('machines.change_ttl',) + _("You don't have the right to change the domain's TTL.") + if not can + else None, + ("machines.change_ttl",), ) def __str__(self): @@ -1766,13 +1776,11 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): class IpList(RevMixin, AclMixin, models.Model): """ A list of IPv4 """ - ipv4 = models.GenericIPAddressField(protocol='IPv4', unique=True) - ip_type = models.ForeignKey('IpType', on_delete=models.CASCADE) + ipv4 = models.GenericIPAddressField(protocol="IPv4", unique=True) + ip_type = models.ForeignKey("IpType", on_delete=models.CASCADE) class Meta: - permissions = ( - ("view_iplist", _("Can view an IPv4 addresses list object")), - ) + permissions = (("view_iplist", _("Can view an IPv4 addresses list object")),) verbose_name = _("IPv4 addresses list") verbose_name_plural = _("IPv4 addresses lists") @@ -1785,8 +1793,9 @@ class IpList(RevMixin, AclMixin, models.Model): 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(_("The IPv4 address and the range of the IP" - " type don't match.")) + raise ValidationError( + _("The IPv4 address and the range of the IP" " type don't match.") + ) return def save(self, *args, **kwargs): @@ -1803,43 +1812,34 @@ class Role(RevMixin, AclMixin, models.Model): """ ROLE = ( - ('dhcp-server', _("DHCP server")), - ('switch-conf-server', _("Switches configuration server")), - ('dns-recursive-server', _("Recursive DNS server")), - ('ntp-server', _("NTP server")), - ('radius-server', _("RADIUS server")), - ('log-server', _("Log server")), - ('ldap-master-server', _("LDAP master server")), - ('ldap-backup-server', _("LDAP backup server")), - ('smtp-server', _("SMTP server")), - ('postgresql-server', _("postgreSQL server")), - ('mysql-server', _("mySQL server")), - ('sql-client', _("SQL client")), - ('gateway', _("Gateway")), + ("dhcp-server", _("DHCP server")), + ("switch-conf-server", _("Switches configuration server")), + ("dns-recursive-server", _("Recursive DNS server")), + ("ntp-server", _("NTP server")), + ("radius-server", _("RADIUS server")), + ("log-server", _("Log server")), + ("ldap-master-server", _("LDAP master server")), + ("ldap-backup-server", _("LDAP backup server")), + ("smtp-server", _("SMTP server")), + ("postgresql-server", _("postgreSQL server")), + ("mysql-server", _("mySQL server")), + ("sql-client", _("SQL client")), + ("gateway", _("Gateway")), ) role_type = models.CharField(max_length=255, unique=True) - servers = models.ManyToManyField('Interface') - specific_role = models.CharField( - choices=ROLE, - null=True, - blank=True, - max_length=32, - ) + servers = models.ManyToManyField("Interface") + specific_role = models.CharField(choices=ROLE, null=True, blank=True, max_length=32) class Meta: - permissions = ( - ("view_role", _("Can view a role object")), - ) + permissions = (("view_role", _("Can view a role object")),) verbose_name = _("server role") verbose_name_plural = _("server roles") @classmethod def interface_for_roletype(cls, roletype): """Return interfaces for a roletype""" - return Interface.objects.filter( - role=cls.objects.filter(specific_role=roletype) - ) + return Interface.objects.filter(role=cls.objects.filter(specific_role=roletype)) @classmethod def all_interfaces_for_roletype(cls, roletype): @@ -1866,37 +1866,33 @@ class Service(RevMixin, AclMixin, models.Model): service_type = models.CharField(max_length=255, blank=True, unique=True) min_time_regen = models.DurationField( default=timedelta(minutes=1), - help_text=_("Minimal time before regeneration of the service.") + help_text=_("Minimal time before regeneration of the service."), ) regular_time_regen = models.DurationField( default=timedelta(hours=1), - help_text=_("Maximal time before regeneration of the service.") + help_text=_("Maximal time before regeneration of the service."), ) - servers = models.ManyToManyField('Interface', through='Service_link') + servers = models.ManyToManyField("Interface", through="Service_link") class Meta: - permissions = ( - ("view_service", _("Can view a service object")), - ) + permissions = (("view_service", _("Can view a service object")),) verbose_name = _("service to generate (DHCP, DNS, ...)") verbose_name_plural = _("services to generate (DHCP, DNS, ...)") 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) - ): + 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): @@ -1918,8 +1914,8 @@ def regen(service): class Service_link(RevMixin, AclMixin, models.Model): """ Definition du lien entre serveurs et services""" - service = models.ForeignKey('Service', on_delete=models.CASCADE) - server = models.ForeignKey('Interface', on_delete=models.CASCADE) + service = models.ForeignKey("Service", on_delete=models.CASCADE) + server = models.ForeignKey("Interface", on_delete=models.CASCADE) last_regen = models.DateTimeField(auto_now_add=True) asked_regen = models.BooleanField(default=False) @@ -1941,12 +1937,11 @@ class Service_link(RevMixin, AclMixin, models.Model): """ 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() + ( + 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() ) @need_regen.setter @@ -1970,14 +1965,12 @@ class OuverturePortList(RevMixin, AclMixin, models.Model): """Liste des ports ouverts sur une interface.""" name = models.CharField( - help_text=_("Name of the ports configuration"), - max_length=255 + help_text=_("Name of the ports configuration"), max_length=255 ) class Meta: permissions = ( - ("view_ouvertureportlist", _("Can view a ports opening list" - " object")), + ("view_ouvertureportlist", _("Can view a ports opening list" " object")), ) verbose_name = _("ports opening list") verbose_name_plural = _("ports opening lists") @@ -1988,11 +1981,11 @@ class OuverturePortList(RevMixin, AclMixin, models.Model): :param self: Instance ouvertureportlist à delete :param user_request: Utilisateur qui fait la requête :return: soit True, soit False avec la raison de l'échec""" - if not user_request.has_perm('machines.delete_ouvertureportlist'): + if not user_request.has_perm("machines.delete_ouvertureportlist"): return ( False, _("You don't have the right to delete a ports opening list."), - ('machines.delete_ouvertureportlist',) + ("machines.delete_ouvertureportlist",), ) if self.interface_set.all(): return False, _("This ports opening list is used."), None @@ -2004,29 +1997,25 @@ class OuverturePortList(RevMixin, AclMixin, models.Model): def tcp_ports_in(self): """Renvoie la liste des ports ouverts en TCP IN pour ce profil""" return self.ouvertureport_set.filter( - protocole=OuverturePort.TCP, - io=OuverturePort.IN + protocole=OuverturePort.TCP, io=OuverturePort.IN ) def udp_ports_in(self): """Renvoie la liste des ports ouverts en UDP IN pour ce profil""" return self.ouvertureport_set.filter( - protocole=OuverturePort.UDP, - io=OuverturePort.IN + protocole=OuverturePort.UDP, io=OuverturePort.IN ) def tcp_ports_out(self): """Renvoie la liste des ports ouverts en TCP OUT pour ce profil""" return self.ouvertureport_set.filter( - protocole=OuverturePort.TCP, - io=OuverturePort.OUT + protocole=OuverturePort.TCP, io=OuverturePort.OUT ) def udp_ports_out(self): """Renvoie la liste des ports ouverts en UDP OUT pour ce profil""" return self.ouvertureport_set.filter( - protocole=OuverturePort.UDP, - io=OuverturePort.OUT + protocole=OuverturePort.UDP, io=OuverturePort.OUT ) @@ -2040,32 +2029,17 @@ class OuverturePort(RevMixin, AclMixin, models.Model): On limite les ports entre 0 et 65535, tels que défini par la RFC """ - TCP = 'T' - UDP = 'U' - IN = 'I' - OUT = 'O' + TCP = "T" + UDP = "U" + IN = "I" + 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, - ) - io = models.CharField( - max_length=1, - choices=( - (IN, 'IN'), - (OUT, 'OUT'), - ), - default=OUT, + max_length=1, choices=((TCP, "TCP"), (UDP, "UDP")), default=TCP ) + io = models.CharField(max_length=1, choices=((IN, "IN"), (OUT, "OUT")), default=OUT) class Meta: verbose_name = _("ports opening") @@ -2074,7 +2048,7 @@ class OuverturePort(RevMixin, AclMixin, models.Model): def __str__(self): if self.begin == self.end: return str(self.begin) - return ':'.join([str(self.begin), str(self.end)]) + return ":".join([str(self.begin), str(self.end)]) def show_port(self): """Formatage plus joli, alias pour str""" @@ -2085,41 +2059,41 @@ class OuverturePort(RevMixin, AclMixin, models.Model): def machine_post_save(**kwargs): """Synchronisation ldap et régen parefeu/dhcp lors de la modification d'une machine""" - user = kwargs['instance'].user + user = kwargs["instance"].user user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) - regen('dhcp') - regen('mac_ip_list') + regen("dhcp") + regen("mac_ip_list") @receiver(post_delete, sender=Machine) def machine_post_delete(**kwargs): """Synchronisation ldap et régen parefeu/dhcp lors de la suppression d'une machine""" - machine = kwargs['instance'] + machine = kwargs["instance"] user = machine.user user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) - regen('dhcp') - regen('mac_ip_list') + regen("dhcp") + regen("mac_ip_list") @receiver(post_save, sender=Interface) def interface_post_save(**kwargs): """Synchronisation ldap et régen parefeu/dhcp lors de la modification d'une interface""" - interface = kwargs['instance'] + interface = kwargs["instance"] interface.sync_ipv6() user = interface.machine.user user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) # Regen services - regen('dhcp') - regen('mac_ip_list') + regen("dhcp") + regen("mac_ip_list") @receiver(post_delete, sender=Interface) def interface_post_delete(**kwargs): """Synchronisation ldap et régen parefeu/dhcp lors de la suppression d'une interface""" - interface = kwargs['instance'] + interface = kwargs["instance"] user = interface.machine.user user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) @@ -2127,7 +2101,7 @@ def interface_post_delete(**kwargs): @receiver(post_save, sender=IpType) def iptype_post_save(**kwargs): """Generation des objets ip après modification d'un range ip""" - iptype = kwargs['instance'] + iptype = kwargs["instance"] iptype.gen_ip_range() iptype.check_replace_prefixv6() @@ -2136,7 +2110,7 @@ def iptype_post_save(**kwargs): def machinetype_post_save(**kwargs): """Mise à jour des interfaces lorsque changement d'attribution d'une machinetype (changement iptype parent)""" - machinetype = kwargs['instance'] + machinetype = kwargs["instance"] for interface in machinetype.all_interfaces(): interface.update_type() @@ -2144,94 +2118,94 @@ def machinetype_post_save(**kwargs): @receiver(post_save, sender=Domain) def domain_post_save(**_kwargs): """Regeneration dns après modification d'un domain object""" - regen('dns') + regen("dns") @receiver(post_delete, sender=Domain) def domain_post_delete(**_kwargs): """Regeneration dns après suppression d'un domain object""" - regen('dns') + regen("dns") @receiver(post_save, sender=Extension) def extension_post_save(**_kwargs): """Regeneration dns après modification d'une extension""" - regen('dns') + regen("dns") @receiver(post_delete, sender=Extension) def extension_post_selete(**_kwargs): """Regeneration dns après suppression d'une extension""" - regen('dns') + regen("dns") @receiver(post_save, sender=SOA) def soa_post_save(**_kwargs): """Regeneration dns après modification d'un SOA""" - regen('dns') + regen("dns") @receiver(post_delete, sender=SOA) def soa_post_delete(**_kwargs): """Regeneration dns après suppresson d'un SOA""" - regen('dns') + regen("dns") @receiver(post_save, sender=Mx) def mx_post_save(**_kwargs): """Regeneration dns après modification d'un MX""" - regen('dns') + regen("dns") @receiver(post_delete, sender=Mx) def mx_post_delete(**_kwargs): """Regeneration dns après suppresson d'un MX""" - regen('dns') + regen("dns") @receiver(post_save, sender=Ns) def ns_post_save(**_kwargs): """Regeneration dns après modification d'un NS""" - regen('dns') + regen("dns") @receiver(post_delete, sender=Ns) def ns_post_delete(**_kwargs): """Regeneration dns après modification d'un NS""" - regen('dns') + regen("dns") @receiver(post_save, sender=Txt) def text_post_save(**_kwargs): """Regeneration dns après modification d'un TXT""" - regen('dns') + regen("dns") @receiver(post_delete, sender=Txt) def text_post_delete(**_kwargs): """Regeneration dns après modification d'un TX""" - regen('dns') + regen("dns") @receiver(post_save, sender=DName) def dname_post_save(**_kwargs): """Updates the DNS regen after modification of a DName object.""" - regen('dns') + regen("dns") @receiver(post_delete, sender=DName) def dname_post_delete(**_kwargs): """Updates the DNS regen after deletion of a DName object.""" - regen('dns') + regen("dns") @receiver(post_save, sender=Srv) def srv_post_save(**_kwargs): """Regeneration dns après modification d'un SRV""" - regen('dns') + regen("dns") @receiver(post_delete, sender=Srv) def srv_post_delete(**_kwargs): """Regeneration dns après modification d'un SRV""" - regen('dns') + regen("dns") diff --git a/machines/serializers.py b/machines/serializers.py index 8e716e9f..a6c523ab 100644 --- a/machines/serializers.py +++ b/machines/serializers.py @@ -40,7 +40,7 @@ from machines.models import ( Service_link, Ns, OuverturePort, - Ipv6List + Ipv6List, ) @@ -61,7 +61,7 @@ class IpListSerializer(serializers.ModelSerializer): class Meta: model = IpList - fields = ('ipv4', 'ip_type') + fields = ("ipv4", "ip_type") class Ipv6ListSerializer(serializers.ModelSerializer): @@ -69,7 +69,7 @@ class Ipv6ListSerializer(serializers.ModelSerializer): class Meta: model = Ipv6List - fields = ('ipv6', 'slaac_ip') + fields = ("ipv6", "slaac_ip") class InterfaceSerializer(serializers.ModelSerializer): @@ -78,13 +78,13 @@ class InterfaceSerializer(serializers.ModelSerializer): ipv4 = IpListSerializer(read_only=True) # TODO : use serializer.RelatedField to avoid duplicate code - mac_address = serializers.SerializerMethodField('get_macaddress') - domain = serializers.SerializerMethodField('get_dns') - extension = serializers.SerializerMethodField('get_interface_extension') + mac_address = serializers.SerializerMethodField("get_macaddress") + domain = serializers.SerializerMethodField("get_dns") + extension = serializers.SerializerMethodField("get_interface_extension") class Meta: model = Interface - fields = ('ipv4', 'mac_address', 'domain', 'extension') + fields = ("ipv4", "mac_address", "domain", "extension") @staticmethod def get_dns(obj): @@ -109,13 +109,13 @@ class FullInterfaceSerializer(serializers.ModelSerializer): ipv4 = IpListSerializer(read_only=True) ipv6 = Ipv6ListSerializer(read_only=True, many=True) # TODO : use serializer.RelatedField to avoid duplicate code - mac_address = serializers.SerializerMethodField('get_macaddress') - domain = serializers.SerializerMethodField('get_dns') - extension = serializers.SerializerMethodField('get_interface_extension') + mac_address = serializers.SerializerMethodField("get_macaddress") + domain = serializers.SerializerMethodField("get_dns") + extension = serializers.SerializerMethodField("get_interface_extension") class Meta: model = Interface - fields = ('ipv4', 'ipv6', 'mac_address', 'domain', 'extension') + fields = ("ipv4", "ipv6", "mac_address", "domain", "extension") @staticmethod def get_dns(obj): @@ -148,21 +148,32 @@ class TypeSerializer(serializers.ModelSerializer): get ForeignKey values. Infos about the general port policy is added """ 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', - 'prefix_v6', - '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", + "prefix_v6", + "ouverture_ports_tcp_in", + "ouverture_ports_tcp_out", + "ouverture_ports_udp_in", + "ouverture_ports_udp_out", + ) @staticmethod def get_port_policy(obj, protocole, io): @@ -172,9 +183,9 @@ class TypeSerializer(serializers.ModelSerializer): return [] return map( str, - obj.ouverture_ports.ouvertureport_set.filter( - protocole=protocole - ).filter(io=io) + obj.ouverture_ports.ouvertureport_set.filter(protocole=protocole).filter( + io=io + ), ) def get_port_policy_input_tcp(self, obj): @@ -197,13 +208,14 @@ class TypeSerializer(serializers.ModelSerializer): 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') - soa = serializers.SerializerMethodField('get_soa_data') + + origin = serializers.SerializerMethodField("get_origin_ip") + zone_entry = serializers.SerializerMethodField("get_zone_name") + soa = serializers.SerializerMethodField("get_soa_data") class Meta: model = Extension - fields = ('name', 'origin', 'origin_v6', 'zone_entry', 'soa') + fields = ("name", "origin", "origin_v6", "zone_entry", "soa") @staticmethod def get_origin_ip(obj): @@ -218,19 +230,20 @@ class ExtensionSerializer(serializers.ModelSerializer): @staticmethod def get_soa_data(obj): """ The representation of the associated SOA """ - return {'mail': obj.soa.dns_soa_mail, 'param': obj.soa.dns_soa_param} + return {"mail": obj.soa.dns_soa_mail, "param": obj.soa.dns_soa_param} 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') + + name = serializers.SerializerMethodField("get_entry_name") + zone = serializers.SerializerMethodField("get_zone_name") + mx_entry = serializers.SerializerMethodField("get_mx_name") class Meta: model = Mx - fields = ('zone', 'priority', 'name', 'mx_entry') + fields = ("zone", "priority", "name", "mx_entry") @staticmethod def get_entry_name(obj): @@ -251,12 +264,13 @@ class MxSerializer(serializers.ModelSerializer): class TxtSerializer(serializers.ModelSerializer): """Serialisation d'un txt : zone cible et l'entrée txt sont evaluées à part""" - zone = serializers.SerializerMethodField('get_zone_name') - txt_entry = serializers.SerializerMethodField('get_txt_name') + + zone = serializers.SerializerMethodField("get_zone_name") + txt_entry = serializers.SerializerMethodField("get_txt_name") class Meta: model = Txt - fields = ('zone', 'txt_entry', 'field1', 'field2') + fields = ("zone", "txt_entry", "field1", "field2") @staticmethod def get_zone_name(obj): @@ -271,21 +285,22 @@ class TxtSerializer(serializers.ModelSerializer): class SrvSerializer(serializers.ModelSerializer): """Serialisation d'un srv : zone cible et l'entrée txt""" - extension = serializers.SerializerMethodField('get_extension_name') - srv_entry = serializers.SerializerMethodField('get_srv_name') + + extension = serializers.SerializerMethodField("get_extension_name") + srv_entry = serializers.SerializerMethodField("get_srv_name") class Meta: model = Srv fields = ( - 'service', - 'protocole', - 'extension', - 'ttl', - 'priority', - 'weight', - 'port', - 'target', - 'srv_entry' + "service", + "protocole", + "extension", + "ttl", + "priority", + "weight", + "port", + "target", + "srv_entry", ) @staticmethod @@ -302,13 +317,14 @@ class SrvSerializer(serializers.ModelSerializer): 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') + + zone = serializers.SerializerMethodField("get_zone_name") + ns = serializers.SerializerMethodField("get_domain_name") + ns_entry = serializers.SerializerMethodField("get_text_name") class Meta: model = Ns - fields = ('zone', 'ns', 'ns_entry') + fields = ("zone", "ns", "ns_entry") @staticmethod def get_zone_name(obj): @@ -329,13 +345,14 @@ class NsSerializer(serializers.ModelSerializer): 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') + + extension = serializers.SerializerMethodField("get_zone_name") + cname = serializers.SerializerMethodField("get_alias_name") + cname_entry = serializers.SerializerMethodField("get_cname_name") class Meta: model = Domain - fields = ('name', 'extension', 'cname', 'cname_entry') + fields = ("name", "extension", "cname", "cname_entry") @staticmethod def get_zone_name(obj): @@ -355,13 +372,14 @@ class DomainSerializer(serializers.ModelSerializer): 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') + + server = serializers.SerializerMethodField("get_server_name") + service = serializers.SerializerMethodField("get_service_name") + need_regen = serializers.SerializerMethodField("get_regen_status") class Meta: model = Service_link - fields = ('server', 'service', 'need_regen') + fields = ("server", "service", "need_regen") @staticmethod def get_server_name(obj): @@ -381,6 +399,7 @@ class ServiceServersSerializer(serializers.ModelSerializer): class OuverturePortsSerializer(serializers.Serializer): """Serialisation de l'ouverture des ports""" + ipv4 = serializers.SerializerMethodField() ipv6 = serializers.SerializerMethodField() @@ -404,7 +423,8 @@ class OuverturePortsSerializer(serializers.Serializer): "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 + for i in Interface.objects.all() + if i.ipv4 } @staticmethod @@ -417,5 +437,6 @@ class OuverturePortsSerializer(serializers.Serializer): "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 + for i in Interface.objects.all() + if i.ipv6 } diff --git a/machines/urls.py b/machines/urls.py index f8518460..8fb08d99 100644 --- a/machines/urls.py +++ b/machines/urls.py @@ -31,144 +31,138 @@ from django.conf.urls import url from . import views urlpatterns = [ - url(r'^new_machine/(?P[0-9]+)$', - views.new_machine, - name='new-machine'), - url(r'^edit_interface/(?P[0-9]+)$', + url(r"^new_machine/(?P[0-9]+)$", views.new_machine, name="new-machine"), + url( + r"^edit_interface/(?P[0-9]+)$", views.edit_interface, - name='edit-interface'), - url(r'^del_machine/(?P[0-9]+)$', - views.del_machine, - name='del-machine'), - url(r'^new_interface/(?P[0-9]+)$', + name="edit-interface", + ), + url(r"^del_machine/(?P[0-9]+)$", views.del_machine, name="del-machine"), + url( + r"^new_interface/(?P[0-9]+)$", views.new_interface, - name='new-interface'), - url(r'^del_interface/(?P[0-9]+)$', + name="new-interface", + ), + url( + r"^del_interface/(?P[0-9]+)$", views.del_interface, - name='del-interface'), - url(r'^add_machinetype/$', views.add_machinetype, name='add-machinetype'), - url(r'^edit_machinetype/(?P[0-9]+)$', + name="del-interface", + ), + url(r"^add_machinetype/$", views.add_machinetype, name="add-machinetype"), + url( + r"^edit_machinetype/(?P[0-9]+)$", views.edit_machinetype, - name='edit-machinetype'), - url(r'^del_machinetype/$', views.del_machinetype, name='del-machinetype'), - url(r'^index_machinetype/$', - views.index_machinetype, - name='index-machinetype'), - url(r'^add_iptype/$', views.add_iptype, name='add-iptype'), - url(r'^edit_iptype/(?P[0-9]+)$', - views.edit_iptype, - name='edit-iptype'), - url(r'^del_iptype/$', views.del_iptype, name='del-iptype'), - url(r'^index_iptype/$', views.index_iptype, name='index-iptype'), - url(r'^add_extension/$', views.add_extension, name='add-extension'), - url(r'^edit_extension/(?P[0-9]+)$', + name="edit-machinetype", + ), + url(r"^del_machinetype/$", views.del_machinetype, name="del-machinetype"), + url(r"^index_machinetype/$", views.index_machinetype, name="index-machinetype"), + url(r"^add_iptype/$", views.add_iptype, name="add-iptype"), + url(r"^edit_iptype/(?P[0-9]+)$", views.edit_iptype, name="edit-iptype"), + url(r"^del_iptype/$", views.del_iptype, name="del-iptype"), + url(r"^index_iptype/$", views.index_iptype, name="index-iptype"), + url(r"^add_extension/$", views.add_extension, name="add-extension"), + url( + r"^edit_extension/(?P[0-9]+)$", views.edit_extension, - name='edit-extension'), - url(r'^del_extension/$', views.del_extension, name='del-extension'), - url(r'^add_soa/$', views.add_soa, name='add-soa'), - url(r'^edit_soa/(?P[0-9]+)$', views.edit_soa, name='edit-soa'), - url(r'^del_soa/$', views.del_soa, name='del-soa'), - url(r'^add_mx/$', views.add_mx, name='add-mx'), - url(r'^edit_mx/(?P[0-9]+)$', views.edit_mx, name='edit-mx'), - url(r'^del_mx/$', views.del_mx, name='del-mx'), - url(r'^add_txt/$', views.add_txt, name='add-txt'), - url(r'^edit_txt/(?P[0-9]+)$', views.edit_txt, name='edit-txt'), - url(r'^del_txt/$', views.del_txt, name='del-txt'), - url(r'^add_dname/$', views.add_dname, name='add-dname'), - url(r'^edit_dname/(?P[0-9]+)$', views.edit_dname, name='edit-dname'), - url(r'^del_dname/$', views.del_dname, name='del-dname'), - url(r'^add_ns/$', views.add_ns, name='add-ns'), - url(r'^edit_ns/(?P[0-9]+)$', views.edit_ns, name='edit-ns'), - url(r'^del_ns/$', views.del_ns, name='del-ns'), - url(r'^add_srv/$', views.add_srv, name='add-srv'), - url(r'^edit_srv/(?P[0-9]+)$', views.edit_srv, name='edit-srv'), - url(r'^del_srv/$', views.del_srv, name='del-srv'), - url(r'^new_sshfp/(?P[0-9]+)$', - views.new_sshfp, - name='new-sshfp'), - url(r'^edit_sshfp/(?P[0-9]+)$', - views.edit_sshfp, - name='edit-sshfp'), - url(r'^del_sshfp/(?P[0-9]+)$', - views.del_sshfp, - name='del-sshfp'), - url(r'^index_sshfp/(?P[0-9]+)$', - views.index_sshfp, - name='index-sshfp'), - url(r'^index_extension/$', views.index_extension, name='index-extension'), - url(r'^add_alias/(?P[0-9]+)$', - views.add_alias, - name='add-alias'), - url(r'^edit_alias/(?P[0-9]+)$', - views.edit_alias, - name='edit-alias'), - url(r'^del_alias/(?P[0-9]+)$', - views.del_alias, - name='del-alias'), - url(r'^index_alias/(?P[0-9]+)$', - views.index_alias, - name='index-alias'), - url(r'^new_ipv6list/(?P[0-9]+)$', + name="edit-extension", + ), + url(r"^del_extension/$", views.del_extension, name="del-extension"), + url(r"^add_soa/$", views.add_soa, name="add-soa"), + url(r"^edit_soa/(?P[0-9]+)$", views.edit_soa, name="edit-soa"), + url(r"^del_soa/$", views.del_soa, name="del-soa"), + url(r"^add_mx/$", views.add_mx, name="add-mx"), + url(r"^edit_mx/(?P[0-9]+)$", views.edit_mx, name="edit-mx"), + url(r"^del_mx/$", views.del_mx, name="del-mx"), + url(r"^add_txt/$", views.add_txt, name="add-txt"), + url(r"^edit_txt/(?P[0-9]+)$", views.edit_txt, name="edit-txt"), + url(r"^del_txt/$", views.del_txt, name="del-txt"), + url(r"^add_dname/$", views.add_dname, name="add-dname"), + url(r"^edit_dname/(?P[0-9]+)$", views.edit_dname, name="edit-dname"), + url(r"^del_dname/$", views.del_dname, name="del-dname"), + url(r"^add_ns/$", views.add_ns, name="add-ns"), + url(r"^edit_ns/(?P[0-9]+)$", views.edit_ns, name="edit-ns"), + url(r"^del_ns/$", views.del_ns, name="del-ns"), + url(r"^add_srv/$", views.add_srv, name="add-srv"), + url(r"^edit_srv/(?P[0-9]+)$", views.edit_srv, name="edit-srv"), + url(r"^del_srv/$", views.del_srv, name="del-srv"), + url(r"^new_sshfp/(?P[0-9]+)$", views.new_sshfp, name="new-sshfp"), + url(r"^edit_sshfp/(?P[0-9]+)$", views.edit_sshfp, name="edit-sshfp"), + url(r"^del_sshfp/(?P[0-9]+)$", views.del_sshfp, name="del-sshfp"), + url(r"^index_sshfp/(?P[0-9]+)$", views.index_sshfp, name="index-sshfp"), + url(r"^index_extension/$", views.index_extension, name="index-extension"), + url(r"^add_alias/(?P[0-9]+)$", views.add_alias, name="add-alias"), + url(r"^edit_alias/(?P[0-9]+)$", views.edit_alias, name="edit-alias"), + url(r"^del_alias/(?P[0-9]+)$", views.del_alias, name="del-alias"), + url( + r"^index_alias/(?P[0-9]+)$", views.index_alias, name="index-alias" + ), + url( + r"^new_ipv6list/(?P[0-9]+)$", views.new_ipv6list, - name='new-ipv6list'), - url(r'^edit_ipv6list/(?P[0-9]+)$', + name="new-ipv6list", + ), + url( + r"^edit_ipv6list/(?P[0-9]+)$", views.edit_ipv6list, - name='edit-ipv6list'), - url(r'^del_ipv6list/(?P[0-9]+)$', + name="edit-ipv6list", + ), + url( + r"^del_ipv6list/(?P[0-9]+)$", views.del_ipv6list, - name='del-ipv6list'), - url(r'^index_ipv6/(?P[0-9]+)$', - views.index_ipv6, - name='index-ipv6'), - url(r'^add_service/$', views.add_service, name='add-service'), - url(r'^edit_service/(?P[0-9]+)$', - views.edit_service, - name='edit-service'), - url(r'^del_service/$', views.del_service, name='del-service'), - url(r'^regen_service/(?P[0-9]+)$', views.regen_service, name='regen-service'), - url(r'^index_service/$', views.index_service, name='index-service'), - url(r'^add_role/$', views.add_role, name='add-role'), - url(r'^edit_role/(?P[0-9]+)$', - views.edit_role, - name='edit-role'), - url(r'^del_role/$', views.del_role, name='del-role'), - url(r'^index_role/$', views.index_role, name='index-role'), - url(r'^add_vlan/$', views.add_vlan, name='add-vlan'), - url(r'^edit_vlan/(?P[0-9]+)$', views.edit_vlan, name='edit-vlan'), - url(r'^del_vlan/$', views.del_vlan, name='del-vlan'), - url(r'^index_vlan/$', views.index_vlan, name='index-vlan'), - url(r'^add_nas/$', views.add_nas, name='add-nas'), - url(r'^edit_nas/(?P[0-9]+)$', views.edit_nas, name='edit-nas'), - url(r'^del_nas/$', views.del_nas, name='del-nas'), - url(r'^index_nas/$', views.index_nas, name='index-nas'), - url(r'^$', views.index, name='index'), - url(r'^rest/mac-ip/$', views.mac_ip, name='mac-ip'), - url(r'^rest/regen-achieved/$', - views.regen_achieved, - name='regen-achieved'), - url(r'^rest/mac-ip-dns/$', views.mac_ip_dns, name='mac-ip-dns'), - url(r'^rest/alias/$', views.alias, name='alias'), - url(r'^rest/corresp/$', views.corresp, name='corresp'), - url(r'^rest/mx/$', views.mx, name='mx'), - url(r'^rest/ns/$', views.ns, name='ns'), - url(r'^rest/txt/$', views.txt, name='txt'), - url(r'^rest/srv/$', views.srv, name='srv'), - 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]+)$', + name="del-ipv6list", + ), + url(r"^index_ipv6/(?P[0-9]+)$", views.index_ipv6, name="index-ipv6"), + url(r"^add_service/$", views.add_service, name="add-service"), + url( + r"^edit_service/(?P[0-9]+)$", views.edit_service, name="edit-service" + ), + url(r"^del_service/$", views.del_service, name="del-service"), + url( + r"^regen_service/(?P[0-9]+)$", + views.regen_service, + name="regen-service", + ), + url(r"^index_service/$", views.index_service, name="index-service"), + url(r"^add_role/$", views.add_role, name="add-role"), + url(r"^edit_role/(?P[0-9]+)$", views.edit_role, name="edit-role"), + url(r"^del_role/$", views.del_role, name="del-role"), + url(r"^index_role/$", views.index_role, name="index-role"), + url(r"^add_vlan/$", views.add_vlan, name="add-vlan"), + url(r"^edit_vlan/(?P[0-9]+)$", views.edit_vlan, name="edit-vlan"), + url(r"^del_vlan/$", views.del_vlan, name="del-vlan"), + url(r"^index_vlan/$", views.index_vlan, name="index-vlan"), + url(r"^add_nas/$", views.add_nas, name="add-nas"), + url(r"^edit_nas/(?P[0-9]+)$", views.edit_nas, name="edit-nas"), + url(r"^del_nas/$", views.del_nas, name="del-nas"), + url(r"^index_nas/$", views.index_nas, name="index-nas"), + url(r"^$", views.index, name="index"), + url(r"^rest/mac-ip/$", views.mac_ip, name="mac-ip"), + url(r"^rest/regen-achieved/$", views.regen_achieved, name="regen-achieved"), + url(r"^rest/mac-ip-dns/$", views.mac_ip_dns, name="mac-ip-dns"), + url(r"^rest/alias/$", views.alias, name="alias"), + url(r"^rest/corresp/$", views.corresp, name="corresp"), + url(r"^rest/mx/$", views.mx, name="mx"), + url(r"^rest/ns/$", views.ns, name="ns"), + url(r"^rest/txt/$", views.txt, name="txt"), + url(r"^rest/srv/$", views.srv, name="srv"), + 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]+)$', + name="edit-portlist", + ), + url( + r"^del_portlist/(?P[0-9]+)$", views.del_portlist, - name='del-portlist'), - url(r'^add_portlist/$', views.add_portlist, name='add-portlist'), - url(r'^port_config/(?P[0-9]+)$', + name="del-portlist", + ), + url(r"^add_portlist/$", views.add_portlist, name="add-portlist"), + url( + r"^port_config/(?P[0-9]+)$", views.configure_ports, - name='port-config'), + name="port-config", + ), ] diff --git a/machines/views.py b/machines/views.py index 34f63a59..e2858f7d 100644 --- a/machines/views.py +++ b/machines/views.py @@ -52,14 +52,8 @@ from re2o.acl import ( can_view_all, can_delete_set, ) -from re2o.utils import ( - all_active_assigned_interfaces, - filter_active_interfaces, -) -from re2o.base import ( - SortTable, - re2o_paginator, -) +from re2o.utils import all_active_assigned_interfaces, filter_active_interfaces +from re2o.base import SortTable, re2o_paginator from re2o.views import form from users.models import User from .forms import ( @@ -144,36 +138,36 @@ def f_type_id(is_type_tt): """ The id that will be used in HTML to store the value of the field type. Depends on the fact that type is generate using typeahead or not """ - return 'id_Interface-machine_type_hidden' if is_type_tt else 'id_Interface-machine_type' + return ( + "id_Interface-machine_type_hidden" + if is_type_tt + else "id_Interface-machine_type" + ) def generate_ipv4_choices(form_obj): """ Generate the parameter choices for the massive_bootstrap_form tag """ - f_ipv4 = form_obj.fields['ipv4'] + f_ipv4 = form_obj.fields["ipv4"] used_mtype_id = [] choices = '{"":[{key:"",value:"' + _("Select a machine type first.") + '"}' 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) choices += '],"{t}":[{{key:"",value:"{v}"}},'.format( - t=mtype_id, - v=f_ipv4.empty_label or '""' + t=mtype_id, v=f_ipv4.empty_label or '""' ) - choices += '{{key:{k},value:"{v}"}},'.format( - k=ip.id, - v=ip.ipv4 - ) + choices += '{{key:{k},value:"{v}"}},'.format(k=ip.id, v=ip.ipv4) - for t in form_obj.fields['machine_type'].queryset.exclude(id__in=used_mtype_id): + for t in form_obj.fields["machine_type"].queryset.exclude(id__in=used_mtype_id): choices += '], "' + str(t.id) + '": [' choices += '{key: "", value: "' + str(f_ipv4.empty_label) + '"},' - choices += ']}' + choices += "]}" return choices @@ -181,49 +175,45 @@ def generate_ipv4_engine(is_type_tt): """ Generate the parameter engine for the massive_bootstrap_form tag """ return ( - 'new Bloodhound( {{' + "new Bloodhound( {{" 'datumTokenizer: Bloodhound.tokenizers.obj.whitespace( "value" ),' - 'queryTokenizer: Bloodhound.tokenizers.whitespace,' + "queryTokenizer: Bloodhound.tokenizers.whitespace," 'local: choices_ipv4[ $( "#{machine_type_id}" ).val() ],' - 'identify: function( obj ) {{ return obj.key; }}' - '}} )' - ).format( - machine_type_id=f_type_id(is_type_tt) - ) + "identify: function( obj ) {{ return obj.key; }}" + "}} )" + ).format(machine_type_id=f_type_id(is_type_tt)) def generate_ipv4_match_func(is_type_tt): """ Generate the parameter match_func for the massive_bootstrap_form tag """ return ( - 'function(q, sync) {{' + "function(q, sync) {{" 'if (q === "") {{' 'var first = choices_ipv4[$("#{machine_type_id}").val()].slice(0, 5);' - 'first = first.map( function (obj) {{ return obj.key; }} );' - 'sync(engine_ipv4.get(first));' - '}} else {{' - 'engine_ipv4.search(q, sync);' - '}}' - '}}' - ).format( - machine_type_id=f_type_id(is_type_tt) - ) + "first = first.map( function (obj) {{ return obj.key; }} );" + "sync(engine_ipv4.get(first));" + "}} else {{" + "engine_ipv4.search(q, sync);" + "}}" + "}}" + ).format(machine_type_id=f_type_id(is_type_tt)) def generate_ipv4_mbf_param(form_obj, is_type_tt): """ Generate all the parameters to use with the massive_bootstrap_form tag """ - i_choices = {'ipv4': generate_ipv4_choices(form_obj)} - i_engine = {'ipv4': generate_ipv4_engine(is_type_tt)} - i_match_func = {'ipv4': generate_ipv4_match_func(is_type_tt)} - i_update_on = {'ipv4': [f_type_id(is_type_tt)]} - i_gen_select = {'ipv4': False} + i_choices = {"ipv4": generate_ipv4_choices(form_obj)} + i_engine = {"ipv4": generate_ipv4_engine(is_type_tt)} + i_match_func = {"ipv4": generate_ipv4_match_func(is_type_tt)} + i_update_on = {"ipv4": [f_type_id(is_type_tt)]} + i_gen_select = {"ipv4": False} i_mbf_param = { - 'choices': i_choices, - 'engine': i_engine, - 'match_func': i_match_func, - 'update_on': i_update_on, - 'gen_select': i_gen_select + "choices": i_choices, + "engine": i_engine, + "match_func": i_match_func, + "update_on": i_update_on, + "gen_select": i_gen_select, } return i_mbf_param @@ -237,10 +227,7 @@ def new_machine(request, user, **_kwargs): Trop complexe, devrait être simplifié""" machine = NewMachineForm(request.POST or None, user=request.user) - interface = AddInterfaceForm( - request.POST or None, - user=request.user - ) + interface = AddInterfaceForm(request.POST or None, user=request.user) domain = DomainForm(request.POST or None, user=user) if machine.is_valid() and interface.is_valid(): new_machine_obj = machine.save(commit=False) @@ -255,21 +242,18 @@ def new_machine(request, user, **_kwargs): new_domain.interface_parent = new_interface_obj new_domain.save() messages.success(request, _("The machine was created.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(user.id)} - )) + return redirect(reverse("users:profil", kwargs={"userid": str(user.id)})) i_mbf_param = generate_ipv4_mbf_param(interface, False) return form( { - 'machineform': machine, - 'interfaceform': interface, - 'domainform': domain, - 'i_mbf_param': i_mbf_param, - 'action_name': _("Create a machine") + "machineform": machine, + "interfaceform": interface, + "domainform": domain, + "i_mbf_param": i_mbf_param, + "action_name": _("Create a machine"), }, - 'machines/machine.html', - request + "machines/machine.html", + request, ) @@ -281,23 +265,15 @@ def edit_interface(request, interface_instance, **_kwargs): modifier le propriétaire""" machine_form = EditMachineForm( - request.POST or None, - instance=interface_instance.machine, - user=request.user + request.POST or None, instance=interface_instance.machine, user=request.user ) interface_form = EditInterfaceForm( - request.POST or None, - instance=interface_instance, - user=request.user + request.POST or None, instance=interface_instance, user=request.user ) domain_form = DomainForm( - request.POST or None, - instance=interface_instance.domain, - user=request.user + request.POST or None, instance=interface_instance.domain, user=request.user ) - if (machine_form.is_valid() and - interface_form.is_valid() and - domain_form.is_valid()): + if machine_form.is_valid() and interface_form.is_valid() and domain_form.is_valid(): new_machine_obj = machine_form.save(commit=False) new_interface_obj = interface_form.save(commit=False) new_domain_obj = domain_form.save(commit=False) @@ -307,21 +283,23 @@ def edit_interface(request, interface_instance, **_kwargs): new_interface_obj.save() new_domain_obj.save() messages.success(request, _("The machine was edited.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(interface_instance.machine.user.id)} - )) + return redirect( + reverse( + "users:profil", + kwargs={"userid": str(interface_instance.machine.user.id)}, + ) + ) i_mbf_param = generate_ipv4_mbf_param(interface_form, False) return form( { - 'machineform': machine_form, - 'interfaceform': interface_form, - 'domainform': domain_form, - 'i_mbf_param': i_mbf_param, - 'action_name': _("Edit") + "machineform": machine_form, + "interfaceform": interface_form, + "domainform": domain_form, + "i_mbf_param": i_mbf_param, + "action_name": _("Edit"), }, - 'machines/machine.html', - request + "machines/machine.html", + request, ) @@ -332,14 +310,11 @@ def del_machine(request, machine, **_kwargs): if request.method == "POST": machine.delete() messages.success(request, _("The machine was deleted.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(machine.user.id)} - )) + return redirect( + reverse("users:profil", kwargs={"userid": str(machine.user.id)}) + ) return form( - {'objet': machine, 'objet_name': 'machine'}, - 'machines/delete.html', - request + {"objet": machine, "objet_name": "machine"}, "machines/delete.html", request ) @@ -361,20 +336,19 @@ def new_interface(request, machine, **_kwargs): new_domain_obj.interface_parent = new_interface_obj new_domain_obj.save() messages.success(request, _("The interface was created.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(machine.user.id)} - )) + return redirect( + reverse("users:profil", kwargs={"userid": str(machine.user.id)}) + ) i_mbf_param = generate_ipv4_mbf_param(interface_form, False) return form( { - 'interfaceform': interface_form, - 'domainform': domain_form, - 'i_mbf_param': i_mbf_param, - 'action_name': _("Create an interface") + "interfaceform": interface_form, + "domainform": domain_form, + "i_mbf_param": i_mbf_param, + "action_name": _("Create an interface"), }, - 'machines/machine.html', - request + "machines/machine.html", + request, ) @@ -388,14 +362,11 @@ def del_interface(request, interface, **_kwargs): if not machine.interface_set.all(): machine.delete() messages.success(request, _("The interface was deleted.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(request.user.id)} - )) + return redirect( + reverse("users:profil", kwargs={"userid": str(request.user.id)}) + ) return form( - {'objet': interface, 'objet_name': 'interface'}, - 'machines/delete.html', - request + {"objet": interface, "objet_name": "interface"}, "machines/delete.html", request ) @@ -406,21 +377,18 @@ def new_ipv6list(request, interface, **_kwargs): """Nouvelle ipv6""" ipv6list_instance = Ipv6List(interface=interface) ipv6 = Ipv6ListForm( - request.POST or None, - instance=ipv6list_instance, - user=request.user + request.POST or None, instance=ipv6list_instance, user=request.user ) if ipv6.is_valid(): ipv6.save() messages.success(request, _("The IPv6 addresses list was created.")) - return redirect(reverse( - 'machines:index-ipv6', - kwargs={'interfaceid': str(interface.id)} - )) + return redirect( + reverse("machines:index-ipv6", kwargs={"interfaceid": str(interface.id)}) + ) return form( - {'ipv6form': ipv6, 'action_name': _("Create an IPv6 addresses list")}, - 'machines/machine.html', - request + {"ipv6form": ipv6, "action_name": _("Create an IPv6 addresses list")}, + "machines/machine.html", + request, ) @@ -429,22 +397,20 @@ def new_ipv6list(request, interface, **_kwargs): def edit_ipv6list(request, ipv6list_instance, **_kwargs): """Edition d'une ipv6""" ipv6 = Ipv6ListForm( - request.POST or None, - instance=ipv6list_instance, - user=request.user + request.POST or None, instance=ipv6list_instance, user=request.user ) if ipv6.is_valid(): if ipv6.changed_data: ipv6.save() messages.success(request, _("The IPv6 addresses list was edited.")) - return redirect(reverse( - 'machines:index-ipv6', - kwargs={'interfaceid': str(ipv6list_instance.interface.id)} - )) + return redirect( + reverse( + "machines:index-ipv6", + kwargs={"interfaceid": str(ipv6list_instance.interface.id)}, + ) + ) return form( - {'ipv6form': ipv6, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"ipv6form": ipv6, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -456,14 +422,11 @@ def del_ipv6list(request, ipv6list, **_kwargs): interfaceid = ipv6list.interface.id ipv6list.delete() messages.success(request, _("The IPv6 addresses list was deleted.")) - return redirect(reverse( - 'machines:index-ipv6', - kwargs={'interfaceid': str(interfaceid)} - )) + return redirect( + reverse("machines:index-ipv6", kwargs={"interfaceid": str(interfaceid)}) + ) return form( - {'objet': ipv6list, 'objet_name': 'ipv6'}, - 'machines/delete.html', - request + {"objet": ipv6list, "objet_name": "ipv6"}, "machines/delete.html", request ) @@ -473,21 +436,17 @@ def del_ipv6list(request, ipv6list, **_kwargs): def new_sshfp(request, machine, **_kwargs): """Creates an SSHFP record associated with a machine""" sshfp_instance = SshFp(machine=machine) - sshfp = SshFpForm( - request.POST or None, - instance=sshfp_instance - ) + sshfp = SshFpForm(request.POST or None, instance=sshfp_instance) if sshfp.is_valid(): sshfp.save() messages.success(request, _("The SSHFP record was created.")) - return redirect(reverse( - 'machines:index-sshfp', - kwargs={'machineid': str(machine.id)} - )) + return redirect( + reverse("machines:index-sshfp", kwargs={"machineid": str(machine.id)}) + ) return form( - {'sshfpform': sshfp, 'action_name': _("Create a SSHFP record")}, - 'machines/machine.html', - request + {"sshfpform": sshfp, "action_name": _("Create a SSHFP record")}, + "machines/machine.html", + request, ) @@ -495,22 +454,19 @@ def new_sshfp(request, machine, **_kwargs): @can_edit(SshFp) def edit_sshfp(request, sshfp_instance, **_kwargs): """Edits an SSHFP record""" - sshfp = SshFpForm( - request.POST or None, - instance=sshfp_instance - ) + sshfp = SshFpForm(request.POST or None, instance=sshfp_instance) if sshfp.is_valid(): if sshfp.changed_data: sshfp.save() messages.success(request, _("The SSHFP record was edited.")) - return redirect(reverse( - 'machines:index-sshfp', - kwargs={'machineid': str(sshfp_instance.machine.id)} - )) + return redirect( + reverse( + "machines:index-sshfp", + kwargs={"machineid": str(sshfp_instance.machine.id)}, + ) + ) return form( - {'sshfpform': sshfp, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"sshfpform": sshfp, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -522,14 +478,11 @@ def del_sshfp(request, sshfp, **_kwargs): machineid = sshfp.machine.id sshfp.delete() messages.success(request, _("The SSHFP record was deleted.")) - return redirect(reverse( - 'machines:index-sshfp', - kwargs={'machineid': str(machineid)} - )) + return redirect( + reverse("machines:index-sshfp", kwargs={"machineid": str(machineid)}) + ) return form( - {'objet': sshfp, 'objet_name': 'sshfp'}, - 'machines/delete.html', - request + {"objet": sshfp, "objet_name": "sshfp"}, "machines/delete.html", request ) @@ -543,11 +496,11 @@ def add_iptype(request): if iptype.is_valid(): iptype.save() messages.success(request, _("The IP type was created.")) - return redirect(reverse('machines:index-iptype')) + return redirect(reverse("machines:index-iptype")) return form( - {'iptypeform': iptype, 'action_name': _("Create an IP type")}, - 'machines/machine.html', - request + {"iptypeform": iptype, "action_name": _("Create an IP type")}, + "machines/machine.html", + request, ) @@ -562,11 +515,11 @@ def edit_iptype(request, iptype_instance, **_kwargs): if iptype.changed_data: iptype.save() messages.success(request, _("The IP type was edited.")) - return redirect(reverse('machines:index-iptype')) + return redirect(reverse("machines:index-iptype")) return form( - {'iptypeform': iptype, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"iptypeform": iptype, "action_name": _("Edit")}, + "machines/machine.html", + request, ) @@ -576,7 +529,7 @@ def del_iptype(request, instances): """ Suppression d'un range ip. Supprime les objets ip associés""" iptype = DelIpTypeForm(request.POST or None, instances=instances) if iptype.is_valid(): - iptype_dels = iptype.cleaned_data['iptypes'] + iptype_dels = iptype.cleaned_data["iptypes"] for iptype_del in iptype_dels: try: iptype_del.delete() @@ -584,14 +537,19 @@ def del_iptype(request, instances): except ProtectedError: messages.error( request, - (_("The IP type %s is assigned to at least one machine," - " you can't delete it.") % iptype_del) + ( + _( + "The IP type %s is assigned to at least one machine," + " you can't delete it." + ) + % iptype_del + ), ) - return redirect(reverse('machines:index-iptype')) + return redirect(reverse("machines:index-iptype")) return form( - {'iptypeform': iptype, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"iptypeform": iptype, "action_name": _("Delete")}, + "machines/machine.html", + request, ) @@ -603,12 +561,11 @@ def add_machinetype(request): if machinetype.is_valid(): machinetype.save() messages.success(request, _("The machine type was created.")) - return redirect(reverse('machines:index-machinetype')) + return redirect(reverse("machines:index-machinetype")) return form( - {'machinetypeform': machinetype, 'action_name': _("Create a machine" - " type")}, - 'machines/machine.html', - request + {"machinetypeform": machinetype, "action_name": _("Create a machine" " type")}, + "machines/machine.html", + request, ) @@ -616,19 +573,16 @@ def add_machinetype(request): @can_edit(MachineType) def edit_machinetype(request, machinetype_instance, **_kwargs): """ View used to edit a MachineType object """ - machinetype = MachineTypeForm( - request.POST or None, - instance=machinetype_instance - ) + machinetype = MachineTypeForm(request.POST or None, instance=machinetype_instance) if machinetype.is_valid(): if machinetype.changed_data: machinetype.save() messages.success(request, _("The machine type was edited.")) - return redirect(reverse('machines:index-machinetype')) + return redirect(reverse("machines:index-machinetype")) return form( - {'machinetypeform': machinetype, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"machinetypeform": machinetype, "action_name": _("Edit")}, + "machines/machine.html", + request, ) @@ -638,7 +592,7 @@ def del_machinetype(request, instances): """ View used to delete a MachineType object """ machinetype = DelMachineTypeForm(request.POST or None, instances=instances) if machinetype.is_valid(): - machinetype_dels = machinetype.cleaned_data['machinetypes'] + machinetype_dels = machinetype.cleaned_data["machinetypes"] for machinetype_del in machinetype_dels: try: machinetype_del.delete() @@ -646,14 +600,19 @@ def del_machinetype(request, instances): except ProtectedError: messages.error( request, - (_("The machine type %s is assigned to at least one" - " machine, you can't delete it.") % machinetype_del) + ( + _( + "The machine type %s is assigned to at least one" + " machine, you can't delete it." + ) + % machinetype_del + ), ) - return redirect(reverse('machines:index-machinetype')) + return redirect(reverse("machines:index-machinetype")) return form( - {'machinetypeform': machinetype, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"machinetypeform": machinetype, "action_name": _("Delete")}, + "machines/machine.html", + request, ) @@ -665,11 +624,11 @@ def add_extension(request): if extension.is_valid(): extension.save() messages.success(request, _("The extension was created.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'extensionform': extension, 'action_name': _("Create an extension")}, - 'machines/machine.html', - request + {"extensionform": extension, "action_name": _("Create an extension")}, + "machines/machine.html", + request, ) @@ -677,19 +636,16 @@ def add_extension(request): @can_edit(Extension) def edit_extension(request, extension_instance, **_kwargs): """ View used to edit an Extension object """ - extension = ExtensionForm( - request.POST or None, - instance=extension_instance - ) + extension = ExtensionForm(request.POST or None, instance=extension_instance) if extension.is_valid(): if extension.changed_data: extension.save() messages.success(request, _("The extension was edited.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'extensionform': extension, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"extensionform": extension, "action_name": _("Edit")}, + "machines/machine.html", + request, ) @@ -699,7 +655,7 @@ def del_extension(request, instances): """ View used to delete an Extension object """ extension = DelExtensionForm(request.POST or None, instances=instances) if extension.is_valid(): - extension_dels = extension.cleaned_data['extensions'] + extension_dels = extension.cleaned_data["extensions"] for extension_del in extension_dels: try: extension_del.delete() @@ -707,14 +663,18 @@ def del_extension(request, instances): except ProtectedError: messages.error( request, - (_("The extension %s is assigned to at least one machine" - " type, you can't delete it." % extension_del)) + ( + _( + "The extension %s is assigned to at least one machine" + " type, you can't delete it." % extension_del + ) + ), ) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'extensionform': extension, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"extensionform": extension, "action_name": _("Delete")}, + "machines/machine.html", + request, ) @@ -726,11 +686,11 @@ def add_soa(request): if soa.is_valid(): soa.save() messages.success(request, _("The SOA record was created.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'soaform': soa, 'action_name': _("Create an SOA record")}, - 'machines/machine.html', - request + {"soaform": soa, "action_name": _("Create an SOA record")}, + "machines/machine.html", + request, ) @@ -743,11 +703,9 @@ def edit_soa(request, soa_instance, **_kwargs): if soa.changed_data: soa.save() messages.success(request, _("The SOA record was edited.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'soaform': soa, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"soaform": soa, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -757,21 +715,18 @@ def del_soa(request, instances): """ View used to delete a SOA object """ soa = DelSOAForm(request.POST or None, instances=instances) if soa.is_valid(): - soa_dels = soa.cleaned_data['soa'] + soa_dels = soa.cleaned_data["soa"] for soa_del in soa_dels: try: soa_del.delete() messages.success(request, _("The SOA record was deleted.")) except ProtectedError: messages.error( - request, - (_("Error: the SOA record %s can't be deleted.") % soa_del) + request, (_("Error: the SOA record %s can't be deleted.") % soa_del) ) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'soaform': soa, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"soaform": soa, "action_name": _("Delete")}, "machines/machine.html", request ) @@ -783,11 +738,11 @@ def add_mx(request): if mx.is_valid(): mx.save() messages.success(request, _("The MX record was created.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'mxform': mx, 'action_name': _("Create an MX record")}, - 'machines/machine.html', - request + {"mxform": mx, "action_name": _("Create an MX record")}, + "machines/machine.html", + request, ) @@ -800,11 +755,9 @@ def edit_mx(request, mx_instance, **_kwargs): if mx.changed_data: mx.save() messages.success(request, _("The MX record was edited.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'mxform': mx, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"mxform": mx, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -814,21 +767,18 @@ def del_mx(request, instances): """ View used to delete a MX object """ mx = DelMxForm(request.POST or None, instances=instances) if mx.is_valid(): - mx_dels = mx.cleaned_data['mx'] + mx_dels = mx.cleaned_data["mx"] for mx_del in mx_dels: try: mx_del.delete() messages.success(request, _("The MX record was deleted.")) except ProtectedError: messages.error( - request, - (_("Error: the MX record %s can't be deleted.") % mx_del) + request, (_("Error: the MX record %s can't be deleted.") % mx_del) ) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'mxform': mx, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"mxform": mx, "action_name": _("Delete")}, "machines/machine.html", request ) @@ -840,11 +790,11 @@ def add_ns(request): if ns.is_valid(): ns.save() messages.success(request, _("The NS record was created.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'nsform': ns, 'action_name': _("Create an NS record")}, - 'machines/machine.html', - request + {"nsform": ns, "action_name": _("Create an NS record")}, + "machines/machine.html", + request, ) @@ -857,11 +807,9 @@ def edit_ns(request, ns_instance, **_kwargs): if ns.changed_data: ns.save() messages.success(request, _("The NS record was edited.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'nsform': ns, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"nsform": ns, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -871,21 +819,18 @@ def del_ns(request, instances): """ View used to delete a NS object """ ns = DelNsForm(request.POST or None, instances=instances) if ns.is_valid(): - ns_dels = ns.cleaned_data['ns'] + ns_dels = ns.cleaned_data["ns"] for ns_del in ns_dels: try: ns_del.delete() messages.success(request, _("The NS record was deleted.")) except ProtectedError: messages.error( - request, - (_("Error: the NS record %s can't be deleted.") % ns_del) + request, (_("Error: the NS record %s can't be deleted.") % ns_del) ) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'nsform': ns, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"nsform": ns, "action_name": _("Delete")}, "machines/machine.html", request ) @@ -897,11 +842,11 @@ def add_dname(request): if dname.is_valid(): dname.save() messages.success(request, _("The DNAME record was created.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'dnameform': dname, 'action_name': _("Create a DNAME record")}, - 'machines/machine.html', - request + {"dnameform": dname, "action_name": _("Create a DNAME record")}, + "machines/machine.html", + request, ) @@ -914,11 +859,9 @@ def edit_dname(request, dname_instance, **_kwargs): if dname.changed_data: dname.save() messages.success(request, _("The DNAME record was edited.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'dnameform': dname, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"dnameform": dname, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -928,7 +871,7 @@ def del_dname(request, instances): """ View used to delete a DName object """ dname = DelDNameForm(request.POST or None, instances=instances) if dname.is_valid(): - dname_dels = dname.cleaned_data['dname'] + dname_dels = dname.cleaned_data["dname"] for dname_del in dname_dels: try: dname_del.delete() @@ -936,14 +879,13 @@ def del_dname(request, instances): except ProtectedError: messages.error( request, - _("Error: the DNAME record %s can't be deleted.") - % dname_del + _("Error: the DNAME record %s can't be deleted.") % dname_del, ) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'dnameform': dname, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"dnameform": dname, "action_name": _("Delete")}, + "machines/machine.html", + request, ) @@ -955,11 +897,11 @@ def add_txt(request): if txt.is_valid(): txt.save() messages.success(request, _("The TXT record was created.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'txtform': txt, 'action_name': _("Create a TXT record")}, - 'machines/machine.html', - request + {"txtform": txt, "action_name": _("Create a TXT record")}, + "machines/machine.html", + request, ) @@ -972,11 +914,9 @@ def edit_txt(request, txt_instance, **_kwargs): if txt.changed_data: txt.save() messages.success(request, _("The TXT record was edited.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'txtform': txt, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"txtform": txt, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -986,21 +926,18 @@ def del_txt(request, instances): """ View used to delete a TXT object """ txt = DelTxtForm(request.POST or None, instances=instances) if txt.is_valid(): - txt_dels = txt.cleaned_data['txt'] + txt_dels = txt.cleaned_data["txt"] for txt_del in txt_dels: try: txt_del.delete() messages.success(request, _("The TXT record was deleted.")) except ProtectedError: messages.error( - request, - (_("Error: the TXT record %s can't be deleted.") % txt_del) + request, (_("Error: the TXT record %s can't be deleted.") % txt_del) ) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'txtform': txt, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"txtform": txt, "action_name": _("Delete")}, "machines/machine.html", request ) @@ -1012,11 +949,11 @@ def add_srv(request): if srv.is_valid(): srv.save() messages.success(request, _("The SRV record was created.")) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'srvform': srv, 'action_name': _("Create an SRV record")}, - 'machines/machine.html', - request + {"srvform": srv, "action_name": _("Create an SRV record")}, + "machines/machine.html", + request, ) @@ -1029,11 +966,9 @@ def edit_srv(request, srv_instance, **_kwargs): if srv.changed_data: srv.save() messages.success(request, _("The SRV record was edited.")) - return redirect(reverse('machines:1index-extension')) + return redirect(reverse("machines:1index-extension")) return form( - {'srvform': srv, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"srvform": srv, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -1043,21 +978,18 @@ def del_srv(request, instances): """ View used to delete a SRV object """ srv = DelSrvForm(request.POST or None, instances=instances) if srv.is_valid(): - srv_dels = srv.cleaned_data['srv'] + srv_dels = srv.cleaned_data["srv"] for srv_del in srv_dels: try: srv_del.delete() messages.success(request, _("The SRV record was deleted.")) except ProtectedError: messages.error( - request, - (_("Error: the SRV record %s can't be deleted.") % srv_del) + request, (_("Error: the SRV record %s can't be deleted.") % srv_del) ) - return redirect(reverse('machines:index-extension')) + return redirect(reverse("machines:index-extension")) return form( - {'srvform': srv, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"srvform": srv, "action_name": _("Delete")}, "machines/machine.html", request ) @@ -1072,14 +1004,13 @@ def add_alias(request, interface, interfaceid): alias.cname = interface.domain alias.save() messages.success(request, _("The alias was created.")) - return redirect(reverse( - 'machines:index-alias', - kwargs={'interfaceid': str(interfaceid)} - )) + return redirect( + reverse("machines:index-alias", kwargs={"interfaceid": str(interfaceid)}) + ) return form( - {'aliasform': alias, 'action_name': _("Create an alias")}, - 'machines/machine.html', - request + {"aliasform": alias, "action_name": _("Create an alias")}, + "machines/machine.html", + request, ) @@ -1087,25 +1018,19 @@ def add_alias(request, interface, interfaceid): @can_edit(Domain) def edit_alias(request, domain_instance, **_kwargs): """ View used to edit an Alias object """ - alias = AliasForm( - request.POST or None, - instance=domain_instance, - user=request.user - ) + alias = AliasForm(request.POST or None, instance=domain_instance, user=request.user) if alias.is_valid(): if alias.changed_data: domain_instance = alias.save() messages.success(request, _("The alias was edited.")) - return redirect(reverse( - 'machines:index-alias', - kwargs={ - 'interfaceid': str(domain_instance.cname.interface_parent.id) - } - )) + return redirect( + reverse( + "machines:index-alias", + kwargs={"interfaceid": str(domain_instance.cname.interface_parent.id)}, + ) + ) return form( - {'aliasform': alias, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"aliasform": alias, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -1115,27 +1040,22 @@ def del_alias(request, interface, interfaceid): """ View used to delete an Alias object """ alias = DelAliasForm(request.POST or None, interface=interface) if alias.is_valid(): - alias_dels = alias.cleaned_data['alias'] + alias_dels = alias.cleaned_data["alias"] for alias_del in alias_dels: try: alias_del.delete() - messages.success( - request, - _("The alias %s was deleted.") % alias_del - ) + messages.success(request, _("The alias %s was deleted.") % alias_del) except ProtectedError: messages.error( - request, - (_("Error: the alias %s can't be deleted.") % alias_del) + request, (_("Error: the alias %s can't be deleted.") % alias_del) ) - return redirect(reverse( - 'machines:index-alias', - kwargs={'interfaceid': str(interfaceid)} - )) + return redirect( + reverse("machines:index-alias", kwargs={"interfaceid": str(interfaceid)}) + ) return form( - {'aliasform': alias, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"aliasform": alias, "action_name": _("Delete")}, + "machines/machine.html", + request, ) @@ -1147,11 +1067,11 @@ def add_role(request): if role.is_valid(): role.save() messages.success(request, _("The role was created.")) - return redirect(reverse('machines:index-role')) + return redirect(reverse("machines:index-role")) return form( - {'roleform': role, 'action_name': _("Create a role")}, - 'machines/machine.html', - request + {"roleform": role, "action_name": _("Create a role")}, + "machines/machine.html", + request, ) @@ -1164,11 +1084,9 @@ def edit_role(request, role_instance, **_kwargs): if role.changed_data: role.save() messages.success(request, _("The role was edited.")) - return redirect(reverse('machines:index-role')) + return redirect(reverse("machines:index-role")) return form( - {'roleform': role, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"roleform": role, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -1178,21 +1096,18 @@ def del_role(request, instances): """ View used to delete a Service object """ role = DelRoleForm(request.POST or None, instances=instances) if role.is_valid(): - role_dels = role.cleaned_data['role'] + role_dels = role.cleaned_data["role"] for role_del in role_dels: try: role_del.delete() messages.success(request, _("The role was deleted.")) except ProtectedError: messages.error( - request, - (_("Error: the role %s can't be deleted.") % role_del) + request, (_("Error: the role %s can't be deleted.") % role_del) ) - return redirect(reverse('machines:index-role')) + return redirect(reverse("machines:index-role")) return form( - {'roleform': role, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"roleform": role, "action_name": _("Delete")}, "machines/machine.html", request ) @@ -1204,11 +1119,11 @@ def add_service(request): if service.is_valid(): service.save() messages.success(request, _("The service was created.")) - return redirect(reverse('machines:index-service')) + return redirect(reverse("machines:index-service")) return form( - {'serviceform': service, 'action_name': _("Create a service")}, - 'machines/machine.html', - request + {"serviceform": service, "action_name": _("Create a service")}, + "machines/machine.html", + request, ) @@ -1221,11 +1136,11 @@ def edit_service(request, service_instance, **_kwargs): if service.changed_data: service.save() messages.success(request, _("The service was edited.")) - return redirect(reverse('machines:index-service')) + return redirect(reverse("machines:index-service")) return form( - {'serviceform': service, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"serviceform": service, "action_name": _("Edit")}, + "machines/machine.html", + request, ) @@ -1235,7 +1150,7 @@ def del_service(request, instances): """ View used to delete a Service object """ service = DelServiceForm(request.POST or None, instances=instances) if service.is_valid(): - service_dels = service.cleaned_data['service'] + service_dels = service.cleaned_data["service"] for service_del in service_dels: try: service_del.delete() @@ -1243,13 +1158,13 @@ def del_service(request, instances): except ProtectedError: messages.error( request, - (_("Error: the service %s can't be deleted.") % service_del) + (_("Error: the service %s can't be deleted.") % service_del), ) - return redirect(reverse('machines:index-service')) + return redirect(reverse("machines:index-service")) return form( - {'serviceform': service, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"serviceform": service, "action_name": _("Delete")}, + "machines/machine.html", + request, ) @@ -1270,11 +1185,11 @@ def add_vlan(request): if vlan.is_valid(): vlan.save() messages.success(request, _("The VLAN was created.")) - return redirect(reverse('machines:index-vlan')) + return redirect(reverse("machines:index-vlan")) return form( - {'vlanform': vlan, 'action_name': _("Create a VLAN")}, - 'machines/machine.html', - request + {"vlanform": vlan, "action_name": _("Create a VLAN")}, + "machines/machine.html", + request, ) @@ -1287,11 +1202,9 @@ def edit_vlan(request, vlan_instance, **_kwargs): if vlan.changed_data: vlan.save() messages.success(request, _("The VLAN was edited.")) - return redirect(reverse('machines:index-vlan')) + return redirect(reverse("machines:index-vlan")) return form( - {'vlanform': vlan, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"vlanform": vlan, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -1301,21 +1214,18 @@ def del_vlan(request, instances): """ View used to delete a VLAN object """ vlan = DelVlanForm(request.POST or None, instances=instances) if vlan.is_valid(): - vlan_dels = vlan.cleaned_data['vlan'] + vlan_dels = vlan.cleaned_data["vlan"] for vlan_del in vlan_dels: try: vlan_del.delete() messages.success(request, _("The VLAN was deleted.")) except ProtectedError: messages.error( - request, - (_("Error: the VLAN %s can't be deleted.") % vlan_del) + request, (_("Error: the VLAN %s can't be deleted.") % vlan_del) ) - return redirect(reverse('machines:index-vlan')) + return redirect(reverse("machines:index-vlan")) return form( - {'vlanform': vlan, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"vlanform": vlan, "action_name": _("Delete")}, "machines/machine.html", request ) @@ -1327,11 +1237,11 @@ def add_nas(request): if nas.is_valid(): nas.save() messages.success(request, _("The NAS device was created.")) - return redirect(reverse('machines:index-nas')) + return redirect(reverse("machines:index-nas")) return form( - {'nasform': nas, 'action_name': _("Create a NAS device")}, - 'machines/machine.html', - request + {"nasform": nas, "action_name": _("Create a NAS device")}, + "machines/machine.html", + request, ) @@ -1344,11 +1254,9 @@ def edit_nas(request, nas_instance, **_kwargs): if nas.changed_data: nas.save() messages.success(request, _("The NAS device was edited.")) - return redirect(reverse('machines:index-nas')) + return redirect(reverse("machines:index-nas")) return form( - {'nasform': nas, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"nasform": nas, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -1358,21 +1266,18 @@ def del_nas(request, instances): """ View used to delete a NAS object """ nas = DelNasForm(request.POST or None, instances=instances) if nas.is_valid(): - nas_dels = nas.cleaned_data['nas'] + nas_dels = nas.cleaned_data["nas"] for nas_del in nas_dels: try: nas_del.delete() messages.success(request, _("The NAS device was deleted.")) except ProtectedError: messages.error( - request, - (_("Error: the NAS device %s can't be deleted.") % nas_del) + request, (_("Error: the NAS device %s can't be deleted.") % nas_del) ) - return redirect(reverse('machines:index-nas')) + return redirect(reverse("machines:index-nas")) return form( - {'nasform': nas, 'action_name': _("Delete")}, - 'machines/machine.html', - request + {"nasform": nas, "action_name": _("Delete")}, "machines/machine.html", request ) @@ -1381,73 +1286,54 @@ def del_nas(request, instances): def index(request): """ The home view for this app. Displays the list of registered machines in Re2o """ - pagination_large_number = (GeneralOption - .get_cached_value('pagination_large_number')) - machines_list = (Machine.objects - .select_related('user') - .prefetch_related('interface_set__domain__extension') - .prefetch_related('interface_set__ipv4__ip_type') - .prefetch_related( - 'interface_set__machine_type__ip_type__extension' - ).prefetch_related( - 'interface_set__domain__related_domain__extension' - ).prefetch_related('interface_set__ipv6list')) + pagination_large_number = GeneralOption.get_cached_value("pagination_large_number") + machines_list = ( + Machine.objects.select_related("user") + .prefetch_related("interface_set__domain__extension") + .prefetch_related("interface_set__ipv4__ip_type") + .prefetch_related("interface_set__machine_type__ip_type__extension") + .prefetch_related("interface_set__domain__related_domain__extension") + .prefetch_related("interface_set__ipv6list") + ) machines_list = SortTable.sort( machines_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.MACHINES_INDEX - ) - machines_list = re2o_paginator( - request, - machines_list, - pagination_large_number - ) - return render( - request, - 'machines/index.html', - {'machines_list': machines_list} + request.GET.get("col"), + request.GET.get("order"), + SortTable.MACHINES_INDEX, ) + machines_list = re2o_paginator(request, machines_list, pagination_large_number) + return render(request, "machines/index.html", {"machines_list": machines_list}) @login_required @can_view_all(IpType) def index_iptype(request): """ View displaying the list of existing types of IP """ - iptype_list = (IpType.objects - .select_related('extension') - .select_related('vlan') - .order_by('name')) - return render( - request, - 'machines/index_iptype.html', - {'iptype_list': iptype_list} + iptype_list = ( + IpType.objects.select_related("extension") + .select_related("vlan") + .order_by("name") ) + return render(request, "machines/index_iptype.html", {"iptype_list": iptype_list}) @login_required @can_view_all(Vlan) def index_vlan(request): """ View displaying the list of existing VLANs """ - vlan_list = Vlan.objects.prefetch_related('iptype_set').order_by('vlan_id') - return render( - request, - 'machines/index_vlan.html', - {'vlan_list': vlan_list} - ) + vlan_list = Vlan.objects.prefetch_related("iptype_set").order_by("vlan_id") + return render(request, "machines/index_vlan.html", {"vlan_list": vlan_list}) @login_required @can_view_all(MachineType) def index_machinetype(request): """ View displaying the list of existing types of machines """ - machinetype_list = (MachineType.objects - .select_related('ip_type') - .order_by('name')) + machinetype_list = MachineType.objects.select_related("ip_type").order_by("name") return render( request, - 'machines/index_machinetype.html', - {'machinetype_list': machinetype_list} + "machines/index_machinetype.html", + {"machinetype_list": machinetype_list}, ) @@ -1455,11 +1341,12 @@ def index_machinetype(request): @can_view_all(Nas) def index_nas(request): """ View displaying the list of existing NAS """ - nas_list = (Nas.objects - .select_related('machine_type') - .select_related('nas_type') - .order_by('name')) - return render(request, 'machines/index_nas.html', {'nas_list': nas_list}) + nas_list = ( + Nas.objects.select_related("machine_type") + .select_related("nas_type") + .order_by("name") + ) + return render(request, "machines/index_nas.html", {"nas_list": nas_list}) @login_required @@ -1469,37 +1356,41 @@ def index_extension(request): existing SOA records, the list of existing MX records , the list of existing NS records, the list of existing TXT records and the list of existing SRV records """ - extension_list = (Extension.objects - .select_related('origin') - .select_related('soa') - .order_by('name')) - soa_list = SOA.objects.order_by('name') - mx_list = (Mx.objects - .order_by('zone') - .select_related('zone') - .select_related('name__extension')) - ns_list = (Ns.objects - .order_by('zone') - .select_related('zone') - .select_related('ns__extension')) - txt_list = Txt.objects.all().select_related('zone') - dname_list = DName.objects.all().select_related('zone') - srv_list = (Srv.objects - .all() - .select_related('extension') - .select_related('target__extension')) + extension_list = ( + Extension.objects.select_related("origin") + .select_related("soa") + .order_by("name") + ) + soa_list = SOA.objects.order_by("name") + mx_list = ( + Mx.objects.order_by("zone") + .select_related("zone") + .select_related("name__extension") + ) + ns_list = ( + Ns.objects.order_by("zone") + .select_related("zone") + .select_related("ns__extension") + ) + txt_list = Txt.objects.all().select_related("zone") + dname_list = DName.objects.all().select_related("zone") + srv_list = ( + Srv.objects.all() + .select_related("extension") + .select_related("target__extension") + ) return render( request, - 'machines/index_extension.html', + "machines/index_extension.html", { - 'extension_list': extension_list, - 'soa_list': soa_list, - 'mx_list': mx_list, - 'ns_list': ns_list, - 'txt_list': txt_list, - 'dname_list': dname_list, - 'srv_list': srv_list - } + "extension_list": extension_list, + "soa_list": soa_list, + "mx_list": mx_list, + "ns_list": ns_list, + "txt_list": txt_list, + "dname_list": dname_list, + "srv_list": srv_list, + }, ) @@ -1509,11 +1400,11 @@ def index_alias(request, interface, interfaceid): """ View used to display the list of existing alias of an interface """ alias_list = Domain.objects.filter( cname=Domain.objects.filter(interface_parent=interface) - ).order_by('name') + ).order_by("name") return render( request, - 'machines/index_alias.html', - {'alias_list': alias_list, 'interface_id': interfaceid} + "machines/index_alias.html", + {"alias_list": alias_list, "interface_id": interfaceid}, ) @@ -1525,8 +1416,8 @@ def index_sshfp(request, machine, machineid): sshfp_list = SshFp.objects.filter(machine=machine) return render( request, - 'machines/index_sshfp.html', - {'sshfp_list': sshfp_list, 'machine_id': machineid} + "machines/index_sshfp.html", + {"sshfp_list": sshfp_list, "machine_id": machineid}, ) @@ -1537,8 +1428,8 @@ def index_ipv6(request, interface, interfaceid): ipv6_list = Ipv6List.objects.filter(interface=interface) return render( request, - 'machines/index_ipv6.html', - {'ipv6_list': ipv6_list, 'interface_id': interfaceid} + "machines/index_ipv6.html", + {"ipv6_list": ipv6_list, "interface_id": interfaceid}, ) @@ -1546,33 +1437,26 @@ def index_ipv6(request, interface, interfaceid): @can_view_all(Role) def index_role(request): """ View used to display the list of existing roles """ - role_list = (Role.objects - .prefetch_related( - 'servers__domain__extension' - ).all()) - return render( - request, - 'machines/index_role.html', - {'role_list': role_list} - ) + role_list = Role.objects.prefetch_related("servers__domain__extension").all() + return render(request, "machines/index_role.html", {"role_list": role_list}) @login_required @can_view_all(Service) def index_service(request): """ View used to display the list of existing services """ - service_list = (Service.objects - .prefetch_related( - 'service_link_set__server__domain__extension' - ).all()) - servers_list = (Service_link.objects - .select_related('server__domain__extension') - .select_related('service') - .all()) + service_list = Service.objects.prefetch_related( + "service_link_set__server__domain__extension" + ).all() + servers_list = ( + Service_link.objects.select_related("server__domain__extension") + .select_related("service") + .all() + ) return render( request, - 'machines/index_service.html', - {'service_list': service_list, 'servers_list': servers_list} + "machines/index_service.html", + {"service_list": service_list, "servers_list": servers_list}, ) @@ -1580,16 +1464,13 @@ def index_service(request): @can_view_all(OuverturePortList) def index_portlist(request): """ View used to display the list of existing port policies """ - 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} + 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 @@ -1597,20 +1478,16 @@ def index_portlist(request): def edit_portlist(request, ouvertureportlist_instance, **_kwargs): """ View used to edit a port policy """ port_list = EditOuverturePortListForm( - request.POST or None, - instance=ouvertureportlist_instance + request.POST or None, instance=ouvertureportlist_instance ) port_formset = modelformset_factory( OuverturePort, - fields=('begin', 'end', 'protocole', 'io'), + fields=("begin", "end", "protocole", "io"), extra=0, can_delete=True, min_num=1, validate_min=True, - )( - request.POST or None, - queryset=ouvertureportlist_instance.ouvertureport_set.all() - ) + )(request.POST or None, queryset=ouvertureportlist_instance.ouvertureport_set.all()) if port_list.is_valid() and port_formset.is_valid(): if port_list.changed_data: pl = port_list.save() @@ -1623,11 +1500,11 @@ def edit_portlist(request, ouvertureportlist_instance, **_kwargs): port.port_list = pl port.save() messages.success(request, _("The ports list was edited.")) - return redirect(reverse('machines:index-portlist')) + return redirect(reverse("machines:index-portlist")) return form( - {'port_list': port_list, 'ports': port_formset}, - 'machines/edit_portlist.html', - request + {"port_list": port_list, "ports": port_formset}, + "machines/edit_portlist.html", + request, ) @@ -1637,7 +1514,7 @@ def del_portlist(request, port_list_instance, **_kwargs): """ View used to delete a port policy """ port_list_instance.delete() messages.success(request, _("The ports list was deleted.")) - return redirect(reverse('machines:index-portlist')) + return redirect(reverse("machines:index-portlist")) @login_required @@ -1647,7 +1524,7 @@ def add_portlist(request): port_list = EditOuverturePortListForm(request.POST or None) port_formset = modelformset_factory( OuverturePort, - fields=('begin', 'end', 'protocole', 'io'), + fields=("begin", "end", "protocole", "io"), extra=0, can_delete=True, min_num=1, @@ -1662,11 +1539,11 @@ def add_portlist(request): port.port_list = pl port.save() messages.success(request, _("The ports list was created.")) - return redirect(reverse('machines:index-portlist')) + return redirect(reverse("machines:index-portlist")) return form( - {'port_list': port_list, 'ports': port_formset}, - 'machines/edit_portlist.html', - request + {"port_list": port_list, "ports": port_formset}, + "machines/edit_portlist.html", + request, ) @@ -1679,23 +1556,25 @@ def configure_ports(request, interface_instance, **_kwargs): if not interface_instance.may_have_port_open(): messages.error( request, - (_("Warning: the IPv4 isn't public, the opening won't have effect" - " in v4.")) + ( + _( + "Warning: the IPv4 isn't public, the opening won't have effect" + " in v4." + ) + ), ) interface = EditOuverturePortConfigForm( - request.POST or None, - instance=interface_instance + request.POST or None, instance=interface_instance ) if interface.is_valid(): if interface.changed_data: interface.save() messages.success(request, _("The ports configuration was edited.")) - return redirect(reverse('machines:index')) + return redirect(reverse("machines:index")) return form( - {'interfaceform': interface, 'action_name': _("Edit the" - " configuration")}, - 'machines/machine.html', - request + {"interfaceform": interface, "action_name": _("Edit the" " configuration")}, + "machines/machine.html", + request, ) @@ -1707,13 +1586,13 @@ class JSONResponse(HttpResponse): def __init__(self, data, **kwargs): content = JSONRenderer().render(data) - kwargs['content_type'] = 'application/json' + kwargs["content_type"] = "application/json" super(JSONResponse, self).__init__(content, **kwargs) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def mac_ip_list(_request): """ API view to list the active and assigned interfaces """ interfaces = all_active_assigned_interfaces() @@ -1723,7 +1602,7 @@ def mac_ip_list(_request): @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def full_mac_ip_list(_request): """ API view to list the active and assigned interfaces. More detailed than mac_ip_list(request) """ @@ -1734,95 +1613,98 @@ def full_mac_ip_list(_request): @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def alias(_request): """ API view to list the alias (CNAME) for all assigned interfaces """ - alias = (Domain.objects - .filter(interface_parent=None) - .filter( - cname__in=Domain.objects.filter( - interface_parent__in=Interface.objects.exclude(ipv4=None) + alias = ( + Domain.objects.filter(interface_parent=None) + .filter( + cname__in=Domain.objects.filter( + interface_parent__in=Interface.objects.exclude(ipv4=None) + ) ) - ).select_related('extension') - .select_related('cname__extension')) + .select_related("extension") + .select_related("cname__extension") + ) seria = DomainSerializer(alias, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def corresp(_request): """ API view to list the types of IP and infos about it """ - type = IpType.objects.all().select_related('extension') + type = IpType.objects.all().select_related("extension") seria = TypeSerializer(type, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def mx(_request): """ API view to list the MX records """ - mx = (Mx.objects.all() - .select_related('zone') - .select_related('name__extension')) + mx = Mx.objects.all().select_related("zone").select_related("name__extension") seria = MxSerializer(mx, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def txt(_request): """ API view to list the TXT records """ - txt = Txt.objects.all().select_related('zone') + txt = Txt.objects.all().select_related("zone") seria = TxtSerializer(txt, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def srv(_request): """ API view to list the SRV records """ - srv = (Srv.objects - .all() - .select_related('extension') - .select_related('target__extension')) + srv = ( + Srv.objects.all() + .select_related("extension") + .select_related("target__extension") + ) seria = SrvSerializer(srv, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def ns(_request): """ API view to list the NS records """ - ns = (Ns.objects - .exclude( - ns__in=Domain.objects.filter( - interface_parent__in=Interface.objects.filter(ipv4=None) + ns = ( + Ns.objects.exclude( + ns__in=Domain.objects.filter( + interface_parent__in=Interface.objects.filter(ipv4=None) + ) ) - ).select_related('zone') - .select_related('ns__extension')) + .select_related("zone") + .select_related("ns__extension") + ) seria = NsSerializer(ns, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def zones(_request): """ API view to list the DNS zones """ - zones = Extension.objects.all().select_related('origin') + zones = Extension.objects.all().select_related("origin") seria = ExtensionSerializer(zones, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def mac_ip(request): """ API view to list the active and assigned interfaces """ seria = mac_ip_list(request) @@ -1831,7 +1713,7 @@ def mac_ip(request): @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def mac_ip_dns(request): """ API view to list the active and assigned interfaces. More detailed than mac_ip_list(request) """ @@ -1841,101 +1723,94 @@ def mac_ip_dns(request): @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def service_servers(_request): """ API view to list the service links """ - service_link = (Service_link.objects - .all() - .select_related('server__domain') - .select_related('service')) + service_link = ( + Service_link.objects.all() + .select_related("server__domain") + .select_related("service") + ) seria = ServiceServersSerializer(service_link, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def ouverture_ports(_request): """ API view to list the port policies for each IP """ - r = {'ipv4': {}, 'ipv6': {}} - for o in (OuverturePortList.objects - .all() - .prefetch_related('ouvertureport_set') - .prefetch_related('interface_set', 'interface_set__ipv4')): + r = {"ipv4": {}, "ipv6": {}} + for o in ( + OuverturePortList.objects.all() + .prefetch_related("ouvertureport_set") + .prefetch_related("interface_set", "interface_set__ipv4") + ): pl = { - "tcp_in": set(map( - str, - o.ouvertureport_set.filter( - protocole=OuverturePort.TCP, - io=OuverturePort.IN + "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 + ), + "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_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 + ), + "udp_out": set( + map( + str, + o.ouvertureport_set.filter( + protocole=OuverturePort.UDP, io=OuverturePort.OUT + ), ) - )), + ), } 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"])) - 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 + 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(): for ipv6 in i.ipv6(): - d = r['ipv6'].get(ipv6.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'][ipv6.ipv6] = d + d = r["ipv6"].get(ipv6.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"][ipv6.ipv6] = d return JSONResponse(r) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def regen_achieved(request): """ API view to list the regen status for each (Service link, Server) couple """ - obj = (Service_link.objects - .filter( - service__in=Service.objects.filter( - service_type=request.POST['service'] - ), + 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'] - ) - ) - )) + domain__in=Domain.objects.filter(name=request.POST["server"]) + ), + ) if obj: obj.first().done_regen() return HttpResponse("Ok") diff --git a/multi_op/apps.py b/multi_op/apps.py index ae633793..4e28cab6 100644 --- a/multi_op/apps.py +++ b/multi_op/apps.py @@ -30,4 +30,4 @@ from django.apps import AppConfig class MultiOpConfig(AppConfig): - name = 'multi_op' + name = "multi_op" diff --git a/multi_op/forms.py b/multi_op/forms.py index bedebb0a..297c03c8 100644 --- a/multi_op/forms.py +++ b/multi_op/forms.py @@ -32,23 +32,18 @@ from re2o.field_permissions import FieldPermissionFormMixin from re2o.mixins import FormRevMixin from django.utils.translation import ugettext_lazy as _ -from topologie.models import( - Dormitory, -) +from topologie.models import Dormitory class DormitoryForm(FormRevMixin, Form): """Select a dorm""" + dormitory = forms.ModelMultipleChoiceField( queryset=Dormitory.objects.all(), label=_("Dormitory"), widget=forms.CheckboxSelectMultiple, - required=False + required=False, ) def __init__(self, *args, **kwargs): super(DormitoryForm, self).__init__(*args, **kwargs) - - - - diff --git a/multi_op/preferences/forms.py b/multi_op/preferences/forms.py index d5e6ce80..b6958546 100644 --- a/multi_op/preferences/forms.py +++ b/multi_op/preferences/forms.py @@ -32,8 +32,10 @@ from django.utils.translation import ugettext_lazy as _ from .models import Preferences + class EditPreferencesForm(ModelForm): """ Edit the ticket's settings""" + class Meta: model = Preferences - fields = '__all__' + fields = "__all__" diff --git a/multi_op/preferences/models.py b/multi_op/preferences/models.py index 89e82fb2..6f6f8066 100644 --- a/multi_op/preferences/models.py +++ b/multi_op/preferences/models.py @@ -26,14 +26,15 @@ Fichier définissant les administration des models de preference from django.db import models from django.utils.translation import ugettext_lazy as _ + class Preferences(models.Model): """ Definition of the app settings""" enabled_dorm = models.ManyToManyField( - 'topologie.Dormitory', - related_name='vlan_tagged', + "topologie.Dormitory", + related_name="vlan_tagged", blank=True, - verbose_name=_("Enabled dorm") + verbose_name=_("Enabled dorm"), ) class Meta: diff --git a/multi_op/urls.py b/multi_op/urls.py index 866de712..f1a6d941 100644 --- a/multi_op/urls.py +++ b/multi_op/urls.py @@ -30,9 +30,25 @@ from django.conf.urls import url from . import views urlpatterns = [ - url(r'^$', views.aff_state_global, name='aff-state-global'), - url(r'^(?P[0-9]+)$', views.aff_state_dormitory, name='aff-state-dormitory'), - url(r'^pending-connection$', views.aff_pending_connection, name='aff-pending-connection'), - url(r'^pending-disconnection$', views.aff_pending_disconnection, name='aff-pending-disconnection'), - url(r'^disconnect-room/(?P[0-9]+)$', views.disconnect_room, name='disconnect-room'), + url(r"^$", views.aff_state_global, name="aff-state-global"), + url( + r"^(?P[0-9]+)$", + views.aff_state_dormitory, + name="aff-state-dormitory", + ), + url( + r"^pending-connection$", + views.aff_pending_connection, + name="aff-pending-connection", + ), + url( + r"^pending-disconnection$", + views.aff_pending_disconnection, + name="aff-pending-disconnection", + ), + url( + r"^disconnect-room/(?P[0-9]+)$", + views.disconnect_room, + name="disconnect-room", + ), ] diff --git a/multi_op/views.py b/multi_op/views.py index 7debd02e..64b9eeee 100644 --- a/multi_op/views.py +++ b/multi_op/views.py @@ -37,51 +37,37 @@ from django.db.models import Q from re2o.views import form from re2o.utils import all_has_access, all_adherent -from re2o.base import ( - re2o_paginator, - SortTable, -) +from re2o.base import re2o_paginator, SortTable -from re2o.acl import( - can_view, - can_view_all, - can_edit, - can_create, -) +from re2o.acl import can_view, can_view_all, can_edit, can_create from preferences.models import GeneralOption from .forms import DormitoryForm -from .preferences.models import( - Preferences, -) +from .preferences.models import Preferences from topologie.models import Room, Dormitory -from .preferences.forms import ( - EditPreferencesForm, -) +from .preferences.forms import EditPreferencesForm def display_rooms_connection(request, dormitory=None): """View to display global state of connection state""" - room_list = Room.objects.select_related('building__dormitory').order_by('building_dormitory', 'port') + room_list = Room.objects.select_related("building__dormitory").order_by( + "building_dormitory", "port" + ) if dormitory: room_list = room_list.filter(building__dormitory=dormitory) room_list = SortTable.sort( room_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_ROOM + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_ROOM, ) - pagination_number = GeneralOption.get_cached_value('pagination_number') + pagination_number = GeneralOption.get_cached_value("pagination_number") room_list = re2o_paginator(request, room_list, pagination_number) - return render( - request, - 'multi_op/index_room_state.html', - {'room_list': room_list} - ) + return render(request, "multi_op/index_room_state.html", {"room_list": room_list}) @login_required @@ -100,22 +86,29 @@ def aff_state_dormitory(request, dormitory, dormitoryid): @can_view_all(Room) def aff_pending_connection(request): """Aff pending Rooms to connect on our network""" - room_list = Room.objects.select_related('building__dormitory').filter(port__isnull=True).filter(adherent__in=all_has_access()).order_by('building_dormitory', 'port') + room_list = ( + Room.objects.select_related("building__dormitory") + .filter(port__isnull=True) + .filter(adherent__in=all_has_access()) + .order_by("building_dormitory", "port") + ) dormitory_form = DormitoryForm(request.POST or None) if dormitory_form.is_valid(): - room_list = room_list.filter(building__dormitory__in=dormitory_form.cleaned_data['dormitory']) + room_list = room_list.filter( + building__dormitory__in=dormitory_form.cleaned_data["dormitory"] + ) room_list = SortTable.sort( room_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_ROOM + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_ROOM, ) - pagination_number = GeneralOption.get_cached_value('pagination_number') + pagination_number = GeneralOption.get_cached_value("pagination_number") room_list = re2o_paginator(request, room_list, pagination_number) return render( request, - 'multi_op/index_room_state.html', - {'room_list': room_list, 'dormitory_form': dormitory_form} + "multi_op/index_room_state.html", + {"room_list": room_list, "dormitory_form": dormitory_form}, ) @@ -123,22 +116,29 @@ def aff_pending_connection(request): @can_view_all(Room) def aff_pending_disconnection(request): """Aff pending Rooms to disconnect from our network""" - room_list = Room.objects.select_related('building__dormitory').filter(port__isnull=False).exclude(Q(adherent__in=all_has_access()) | Q(adherent__in=all_adherent())).order_by('building_dormitory', 'port') + room_list = ( + Room.objects.select_related("building__dormitory") + .filter(port__isnull=False) + .exclude(Q(adherent__in=all_has_access()) | Q(adherent__in=all_adherent())) + .order_by("building_dormitory", "port") + ) dormitory_form = DormitoryForm(request.POST or None) if dormitory_form.is_valid(): - room_list = room_list.filter(building__dormitory__in=dormitory_form.cleaned_data['dormitory']) + room_list = room_list.filter( + building__dormitory__in=dormitory_form.cleaned_data["dormitory"] + ) room_list = SortTable.sort( room_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_ROOM + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_ROOM, ) - pagination_number = GeneralOption.get_cached_value('pagination_number') + pagination_number = GeneralOption.get_cached_value("pagination_number") room_list = re2o_paginator(request, room_list, pagination_number) return render( request, - 'multi_op/index_room_state.html', - {'room_list': room_list, 'dormitory_form': dormitory_form} + "multi_op/index_room_state.html", + {"room_list": room_list, "dormitory_form": dormitory_form}, ) @@ -148,16 +148,10 @@ def disconnect_room(request, room, roomid): """Action of disconnecting a room""" room.port_set.clear() room.save() - messages.success(request,'Room %s disconnected' % room) - return redirect(reverse( - 'multi_op:aff-pending-disconnection' - )) + messages.success(request, "Room %s disconnected" % room) + return redirect(reverse("multi_op:aff-pending-disconnection")) def navbar_user(): """View to display the app in user's dropdown in the navbar""" - return ('topologie', render_to_string('multi_op/navbar.html')) - - - - + return ("topologie", render_to_string("multi_op/navbar.html")) diff --git a/preferences/acl.py b/preferences/acl.py index bfa83dec..27b209b7 100644 --- a/preferences/acl.py +++ b/preferences/acl.py @@ -38,11 +38,9 @@ def can_view(user): A couple (allowed, msg) where allowed is a boolean which is True if viewing is granted and msg is a message (can be None). """ - can = user.has_module_perms('preferences') + can = user.has_module_perms("preferences") return ( can, - None if can else _("You don't have the right to view this" - " application."), - ('preferences',) + None if can else _("You don't have the right to view this" " application."), + ("preferences",), ) - diff --git a/preferences/admin.py b/preferences/admin.py index ed42ee4e..f4475c14 100644 --- a/preferences/admin.py +++ b/preferences/admin.py @@ -41,70 +41,85 @@ from .models import ( RadiusKey, SwitchManagementCred, Reminder, - DocumentTemplate + DocumentTemplate, ) class OptionalUserAdmin(VersionAdmin): """Class admin options user""" + pass class OptionalTopologieAdmin(VersionAdmin): """Class admin options topologie""" + pass class OptionalMachineAdmin(VersionAdmin): """Class admin options machines""" + pass class GeneralOptionAdmin(VersionAdmin): """Class admin options générales""" + pass class ServiceAdmin(VersionAdmin): """Class admin gestion des services de la page d'accueil""" + pass class MailContactAdmin(VersionAdmin): """Admin class for contact email adresses""" + pass class AssoOptionAdmin(VersionAdmin): """Class admin options de l'asso""" + pass class MailMessageOptionAdmin(VersionAdmin): """Class admin options mail""" + pass class HomeOptionAdmin(VersionAdmin): """Class admin options home""" + pass class RadiusKeyAdmin(VersionAdmin): """Class radiuskey""" + pass + class SwitchManagementCredAdmin(VersionAdmin): """Class managementcred for switch""" + pass + class ReminderAdmin(VersionAdmin): """Class reminder for switch""" + pass class DocumentTemplateAdmin(VersionAdmin): """Admin class for DocumentTemplate""" + pass diff --git a/preferences/forms.py b/preferences/forms.py index 312d0b2b..ea1079b4 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -47,245 +47,222 @@ from .models import ( CotisationsOption, DocumentTemplate, RadiusAttribute, - Mandate + Mandate, ) from topologie.models import Switch class EditOptionalUserForm(ModelForm): """Formulaire d'édition des options de l'user. (solde, telephone..)""" + class Meta: model = OptionalUser - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditOptionalUserForm, self).__init__( - *args, - prefix=prefix, - **kwargs - ) - self.fields['is_tel_mandatory'].label = ( - _("Telephone number required") - ) - self.fields['gpg_fingerprint'].label = _("GPG fingerprint") - self.fields['all_can_create_club'].label = _("All can create a club") - self.fields['all_can_create_adherent'].label = _("All can create a member") - self.fields['self_adhesion'].label = _("Self registration") - self.fields['shell_default'].label = _("Default shell") + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditOptionalUserForm, self).__init__(*args, prefix=prefix, **kwargs) + self.fields["is_tel_mandatory"].label = _("Telephone number required") + self.fields["gpg_fingerprint"].label = _("GPG fingerprint") + self.fields["all_can_create_club"].label = _("All can create a club") + self.fields["all_can_create_adherent"].label = _("All can create a member") + self.fields["self_adhesion"].label = _("Self registration") + self.fields["shell_default"].label = _("Default shell") class EditOptionalMachineForm(ModelForm): """Options machines (max de machines, etc)""" + class Meta: model = OptionalMachine - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditOptionalMachineForm, self).__init__( - *args, - prefix=prefix, - **kwargs + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditOptionalMachineForm, self).__init__(*args, prefix=prefix, **kwargs) + self.fields["password_machine"].label = _( + "Possibility to set a" " password per machine" ) - self.fields['password_machine'].label = _("Possibility to set a" - " password per machine") - self.fields['max_lambdauser_interfaces'].label = _("Maximum number of" - " interfaces" - " allowed for a" - " standard user") - self.fields['max_lambdauser_aliases'].label = _("Maximum number of DNS" - " aliases allowed for" - " a standard user") - self.fields['ipv6_mode'].label = _("IPv6 mode") - self.fields['create_machine'].label = _("Can create a machine") + self.fields["max_lambdauser_interfaces"].label = _( + "Maximum number of" " interfaces" " allowed for a" " standard user" + ) + self.fields["max_lambdauser_aliases"].label = _( + "Maximum number of DNS" " aliases allowed for" " a standard user" + ) + self.fields["ipv6_mode"].label = _("IPv6 mode") + self.fields["create_machine"].label = _("Can create a machine") class EditOptionalTopologieForm(ModelForm): """Options de topologie, formulaire d'edition (vlan par default etc) On rajoute un champ automatic provision switchs pour gérer facilement l'ajout de switchs au provisionning automatique""" + automatic_provision_switchs = forms.ModelMultipleChoiceField( - Switch.objects.all(), - required=False + Switch.objects.all(), required=False ) class Meta: model = OptionalTopologie - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditOptionalTopologieForm, self).__init__( - *args, - prefix=prefix, - **kwargs - ) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditOptionalTopologieForm, self).__init__(*args, prefix=prefix, **kwargs) - self.initial['automatic_provision_switchs'] = Switch.objects.filter(automatic_provision=True).order_by('interface__domain__name') + self.initial["automatic_provision_switchs"] = Switch.objects.filter( + automatic_provision=True + ).order_by("interface__domain__name") def save(self, commit=True): instance = super().save(commit) Switch.objects.all().update(automatic_provision=False) - self.cleaned_data['automatic_provision_switchs'].update(automatic_provision=True) + self.cleaned_data["automatic_provision_switchs"].update( + automatic_provision=True + ) return instance class EditGeneralOptionForm(ModelForm): """Options générales (affichages de résultats de recherche, etc)""" + class Meta: model = GeneralOption - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditGeneralOptionForm, self).__init__( - *args, - prefix=prefix, - **kwargs + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditGeneralOptionForm, self).__init__(*args, prefix=prefix, **kwargs) + self.fields["general_message_fr"].label = _("General message in French") + self.fields["general_message_en"].label = _("General message in English") + self.fields["search_display_page"].label = _( + "Number of results" " displayed when" " searching" ) - self.fields['general_message_fr'].label = _("General message in French") - self.fields['general_message_en'].label = _("General message in English") - self.fields['search_display_page'].label = _("Number of results" - " displayed when" - " searching") - self.fields['pagination_number'].label = _("Number of items per page," - " standard size (e.g." - " users)") - self.fields['pagination_large_number'].label = _("Number of items per" - " page, large size" - " (e.g. machines)") - self.fields['req_expire_hrs'].label = _("Time before expiration of the" - " reset password link (in" - " hours)") - self.fields['site_name'].label = _("Website name") - self.fields['email_from'].label = _("Email address for automatic" - " emailing") - self.fields['GTU_sum_up'].label = _("Summary of the General Terms of" - " Use") - self.fields['GTU'].label = _("General Terms of Use") + self.fields["pagination_number"].label = _( + "Number of items per page," " standard size (e.g." " users)" + ) + self.fields["pagination_large_number"].label = _( + "Number of items per" " page, large size" " (e.g. machines)" + ) + self.fields["req_expire_hrs"].label = _( + "Time before expiration of the" " reset password link (in" " hours)" + ) + self.fields["site_name"].label = _("Website name") + self.fields["email_from"].label = _("Email address for automatic" " emailing") + self.fields["GTU_sum_up"].label = _("Summary of the General Terms of" " Use") + self.fields["GTU"].label = _("General Terms of Use") class EditAssoOptionForm(ModelForm): """Options de l'asso (addresse, telephone, etc)""" + class Meta: model = AssoOption - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditAssoOptionForm, self).__init__( - *args, - prefix=prefix, - **kwargs + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditAssoOptionForm, self).__init__(*args, prefix=prefix, **kwargs) + self.fields["name"].label = _("Organisation name") + self.fields["siret"].label = _("SIRET number") + self.fields["adresse1"].label = _("Address (line 1)") + self.fields["adresse2"].label = _("Address (line 2)") + self.fields["contact"].label = _("Contact email address") + self.fields["telephone"].label = _("Telephone number") + self.fields["pseudo"].label = _("Usual name") + self.fields["utilisateur_asso"].label = _( + "Account used for editing" " from /admin" ) - self.fields['name'].label = _("Organisation name") - self.fields['siret'].label = _("SIRET number") - self.fields['adresse1'].label = _("Address (line 1)") - self.fields['adresse2'].label = _("Address (line 2)") - self.fields['contact'].label = _("Contact email address") - self.fields['telephone'].label = _("Telephone number") - self.fields['pseudo'].label = _("Usual name") - self.fields['utilisateur_asso'].label = _("Account used for editing" - " from /admin") - self.fields['description'].label = _("Description") + self.fields["description"].label = _("Description") class EditMailMessageOptionForm(ModelForm): """Formulaire d'edition des messages de bienvenue personnalisés""" + class Meta: model = MailMessageOption - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditMailMessageOptionForm, self).__init__( - *args, - prefix=prefix, - **kwargs + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditMailMessageOptionForm, self).__init__(*args, prefix=prefix, **kwargs) + self.fields["welcome_mail_fr"].label = _( + "Message for the French" " welcome email" + ) + self.fields["welcome_mail_en"].label = _( + "Message for the English" " welcome email" ) - self.fields['welcome_mail_fr'].label = _("Message for the French" - " welcome email") - self.fields['welcome_mail_en'].label = _("Message for the English" - " welcome email") class EditHomeOptionForm(ModelForm): """Edition forms of Home options""" + class Meta: model = HomeOption - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditHomeOptionForm, self).__init__( - *args, - prefix=prefix, - **kwargs - ) - self.fields['facebook_url'].label = _("Facebook URL") - self.fields['twitter_url'].label = _("Twitter URL") - self.fields['twitter_account_name'].label = _("Twitter account name") + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditHomeOptionForm, self).__init__(*args, prefix=prefix, **kwargs) + self.fields["facebook_url"].label = _("Facebook URL") + self.fields["twitter_url"].label = _("Twitter URL") + self.fields["twitter_account_name"].label = _("Twitter account name") class EditRadiusOptionForm(ModelForm): """Edition forms for Radius options""" + class Meta: model = RadiusOption - fields = '__all__' + fields = "__all__" def clean(self): cleaned_data = super().clean() - ignored=('radius_general_policy', 'vlan_decision_ok') - fields = ( - f for f in self.fields.keys() - if 'vlan' not in f and f not in ignored - ) + ignored = ("radius_general_policy", "vlan_decision_ok") + fields = (f for f in self.fields.keys() if "vlan" not in f and f not in ignored) for f in fields: choice = cleaned_data.get(f) - vlan = cleaned_data.get(f+'_vlan') + vlan = cleaned_data.get(f + "_vlan") if choice == RadiusOption.SET_VLAN and vlan is None: - self.add_error( - f, - _("You chose to set vlan but did not set any VLAN."), - ) - self.add_error( - f+'_vlan', - _("Please, choose a VLAN."), - ) + self.add_error(f, _("You chose to set vlan but did not set any VLAN.")) + self.add_error(f + "_vlan", _("Please, choose a VLAN.")) return cleaned_data class EditCotisationsOptionForm(ModelForm): """Edition forms for Cotisations options""" + class Meta: model = CotisationsOption - fields = '__all__' + fields = "__all__" class MandateForm(ModelForm): """Edit Mandates""" + class Meta: model = Mandate - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(MandateForm, self).__init__(*args, prefix=prefix, **kwargs) def clean_start_date(self): - date = self.cleaned_data.get('start_date') + date = self.cleaned_data.get("start_date") existing_mandates = Mandate.objects.filter( start_date__gte=date, end_date__lt=date ) if existing_mandates: raise forms.ValidationError( - _("There is already a mandate taking place at the specified start date.") + _( + "There is already a mandate taking place at the specified start date." + ) ) return date def clean_end_date(self): - date = self.cleaned_data.get('end_date') + date = self.cleaned_data.get("end_date") if date is None: return None existing_mandates = Mandate.objects.filter( @@ -299,7 +276,7 @@ class MandateForm(ModelForm): def clean(self): cleaned_data = super(MandateForm, self).clean() - start_date, end_date = cleaned_data['start_date'], cleaned_data['end_date'] + start_date, end_date = cleaned_data["start_date"], cleaned_data["end_date"] if end_date: included_mandates = Mandate.objects.filter( Q(start_date__gte=start_date, start_date__lt=end_date) @@ -308,7 +285,7 @@ class MandateForm(ModelForm): if included_mandates: raise forms.ValidationError( _("The specified dates overlap with an existing mandate."), - code='invalid' + code="invalid", ) return cleaned_data @@ -331,135 +308,139 @@ class MandateForm(ModelForm): class ServiceForm(ModelForm): """Edition, ajout de services sur la page d'accueil""" + class Meta: model = Service - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(ServiceForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['name'].label = _("Name") - self.fields['url'].label = _("URL") - self.fields['description'].label = _("Description") - self.fields['image'].label = _("Image") + self.fields["name"].label = _("Name") + self.fields["url"].label = _("URL") + self.fields["description"].label = _("Description") + self.fields["image"].label = _("Image") class DelServiceForm(Form): """Suppression de services sur la page d'accueil""" + services = forms.ModelMultipleChoiceField( queryset=Service.objects.none(), label=_("Current services"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelServiceForm, self).__init__(*args, **kwargs) if instances: - self.fields['services'].queryset = instances + self.fields["services"].queryset = instances else: - self.fields['services'].queryset = Service.objects.all() + self.fields["services"].queryset = Service.objects.all() + class ReminderForm(FormRevMixin, ModelForm): """Edition, ajout de services sur la page d'accueil""" + class Meta: model = Reminder - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(ReminderForm, self).__init__(*args, prefix=prefix, **kwargs) class RadiusKeyForm(FormRevMixin, ModelForm): """Edition, ajout de clef radius""" + members = forms.ModelMultipleChoiceField( - queryset=Switch.objects.all(), - required=False + queryset=Switch.objects.all(), required=False ) class Meta: model = RadiusKey - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(RadiusKeyForm, self).__init__(*args, prefix=prefix, **kwargs) - instance = kwargs.get('instance', None) + instance = kwargs.get("instance", None) if instance: - self.initial['members'] = Switch.objects.filter(radius_key=instance) + self.initial["members"] = Switch.objects.filter(radius_key=instance) def save(self, commit=True): instance = super().save(commit) - instance.switch_set = self.cleaned_data['members'] + instance.switch_set = self.cleaned_data["members"] return instance class SwitchManagementCredForm(FormRevMixin, ModelForm): """Edition, ajout de creds de management pour gestion et interface rest des switchs""" - members = forms.ModelMultipleChoiceField( - Switch.objects.all(), - required=False - ) + + members = forms.ModelMultipleChoiceField(Switch.objects.all(), required=False) class Meta: model = SwitchManagementCred - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(SwitchManagementCredForm, self).__init__(*args, prefix=prefix, **kwargs) - instance = kwargs.get('instance', None) + instance = kwargs.get("instance", None) if instance: - self.initial['members'] = Switch.objects.filter(management_creds=instance) + self.initial["members"] = Switch.objects.filter(management_creds=instance) def save(self, commit=True): instance = super().save(commit) - instance.switch_set = self.cleaned_data['members'] + instance.switch_set = self.cleaned_data["members"] return instance class MailContactForm(ModelForm): """Edition, ajout d'adresse de contact""" + class Meta: model = MailContact - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(MailContactForm, self).__init__(*args, prefix=prefix, **kwargs) class DelMailContactForm(Form): """Delete contact email adress""" + mailcontacts = forms.ModelMultipleChoiceField( queryset=MailContact.objects.none(), label=_("Current email addresses"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelMailContactForm, self).__init__(*args, **kwargs) if instances: - self.fields['mailcontacts'].queryset = instances + self.fields["mailcontacts"].queryset = instances else: - self.fields['mailcontacts'].queryset = MailContact.objects.all() + self.fields["mailcontacts"].queryset = MailContact.objects.all() class DocumentTemplateForm(FormRevMixin, ModelForm): """ Form used to create a document template. """ + class Meta: model = DocumentTemplate - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(DocumentTemplateForm, self).__init__( - *args, prefix=prefix, **kwargs) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(DocumentTemplateForm, self).__init__(*args, prefix=prefix, **kwargs) class DelDocumentTemplateForm(FormRevMixin, Form): @@ -467,46 +448,47 @@ class DelDocumentTemplateForm(FormRevMixin, Form): Form used to delete one or more document templatess. The use must choose the one to delete by checking the boxes. """ + document_templates = forms.ModelMultipleChoiceField( queryset=DocumentTemplate.objects.none(), label=_("Available document templates"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelDocumentTemplateForm, self).__init__(*args, **kwargs) if instances: - self.fields['document_templates'].queryset = instances + self.fields["document_templates"].queryset = instances else: - self.fields['document_templates'].queryset = Banque.objects.all() + self.fields["document_templates"].queryset = Banque.objects.all() class RadiusAttributeForm(ModelForm): """Edit and add RADIUS attributes.""" + class Meta: model = RadiusAttribute - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(RadiusAttributeForm, self).__init__(*args, prefix=prefix, **kwargs) class DelRadiusAttributeForm(Form): """Delete RADIUS attributes""" + attributes = forms.ModelMultipleChoiceField( queryset=RadiusAttribute.objects.none(), label=_("Current attributes"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelServiceForm, self).__init__(*args, **kwargs) if instances: - self.fields['attributes'].queryset = instances + self.fields["attributes"].queryset = instances else: - self.fields['attributes'].queryset = Attributes.objects.all() - - + self.fields["attributes"].queryset = Attributes.objects.all() diff --git a/preferences/migrations/0001_initial.py b/preferences/migrations/0001_initial.py index 8604dc84..4514181e 100644 --- a/preferences/migrations/0001_initial.py +++ b/preferences/migrations/0001_initial.py @@ -9,32 +9,55 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='GeneralOption', + name="GeneralOption", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('search_display_page', models.IntegerField(default=15)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("search_display_page", models.IntegerField(default=15)), ], ), migrations.CreateModel( - name='OptionalMachine', + name="OptionalMachine", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('password_machine', models.BooleanField(default=True)), - ('max_lambdauser_interfaces', models.IntegerField(default=10)), - ('max_lambdauser_aliases', models.IntegerField(default=10)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("password_machine", models.BooleanField(default=True)), + ("max_lambdauser_interfaces", models.IntegerField(default=10)), + ("max_lambdauser_aliases", models.IntegerField(default=10)), ], ), migrations.CreateModel( - name='OptionalUser', + name="OptionalUser", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('is_tel_mandatory', models.BooleanField(default=True)), - ('user_solde', models.BooleanField(default=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("is_tel_mandatory", models.BooleanField(default=True)), + ("user_solde", models.BooleanField(default=True)), ], ), ] diff --git a/preferences/migrations/0002_auto_20170625_1923.py b/preferences/migrations/0002_auto_20170625_1923.py index 9244811a..2d655f21 100644 --- a/preferences/migrations/0002_auto_20170625_1923.py +++ b/preferences/migrations/0002_auto_20170625_1923.py @@ -7,34 +7,32 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0001_initial'), - ] + dependencies = [("preferences", "0001_initial")] operations = [ migrations.AddField( - model_name='generaloption', - name='pagination_large_number', + model_name="generaloption", + name="pagination_large_number", field=models.IntegerField(default=8), ), migrations.AddField( - model_name='generaloption', - name='pagination_number', + model_name="generaloption", + name="pagination_number", field=models.IntegerField(default=25), ), migrations.AddField( - model_name='optionaluser', - name='gpg_fingerprint', + model_name="optionaluser", + name="gpg_fingerprint", field=models.BooleanField(default=True), ), migrations.AlterField( - model_name='optionalmachine', - name='password_machine', + model_name="optionalmachine", + name="password_machine", field=models.BooleanField(default=False), ), migrations.AlterField( - model_name='optionaluser', - name='user_solde', + model_name="optionaluser", + name="user_solde", field=models.BooleanField(default=False), ), ] diff --git a/preferences/migrations/0003_optionaluser_solde_negatif.py b/preferences/migrations/0003_optionaluser_solde_negatif.py index 970b67ee..acca8aaa 100644 --- a/preferences/migrations/0003_optionaluser_solde_negatif.py +++ b/preferences/migrations/0003_optionaluser_solde_negatif.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0002_auto_20170625_1923'), - ] + dependencies = [("preferences", "0002_auto_20170625_1923")] operations = [ migrations.AddField( - model_name='optionaluser', - name='solde_negatif', + model_name="optionaluser", + name="solde_negatif", field=models.DecimalField(decimal_places=2, default=0, max_digits=5), - ), + ) ] diff --git a/preferences/migrations/0004_assooption_services.py b/preferences/migrations/0004_assooption_services.py index b8601a7f..c4be07f5 100644 --- a/preferences/migrations/0004_assooption_services.py +++ b/preferences/migrations/0004_assooption_services.py @@ -7,31 +7,58 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0003_optionaluser_solde_negatif'), - ] + dependencies = [("preferences", "0003_optionaluser_solde_negatif")] operations = [ migrations.CreateModel( - name='AssoOption', + name="AssoOption", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(default="Association réseau de l'école machin", max_length=32)), - ('siret', models.CharField(default='00000000000000', max_length=32)), - ('adresse', models.CharField(default="1 Rue de l'exemple, 94230 Cachan", max_length=128)), - ('contact', models.EmailField(default='contact@example.org', max_length=254)), - ('telephone', models.CharField(default='0000000000', max_length=15)), - ('pseudo', models.CharField(default='Asso', max_length=32)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField( + default="Association réseau de l'école machin", max_length=32 + ), + ), + ("siret", models.CharField(default="00000000000000", max_length=32)), + ( + "adresse", + models.CharField( + default="1 Rue de l'exemple, 94230 Cachan", max_length=128 + ), + ), + ( + "contact", + models.EmailField(default="contact@example.org", max_length=254), + ), + ("telephone", models.CharField(default="0000000000", max_length=15)), + ("pseudo", models.CharField(default="Asso", max_length=32)), ], ), migrations.CreateModel( - name='Services', + name="Services", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=32)), - ('url', models.URLField()), - ('description', models.TextField()), - ('image', models.ImageField(upload_to='logo')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=32)), + ("url", models.URLField()), + ("description", models.TextField()), + ("image", models.ImageField(upload_to="logo")), ], ), ] diff --git a/preferences/migrations/0005_auto_20170824_0139.py b/preferences/migrations/0005_auto_20170824_0139.py index c1fb68c7..1bb5530e 100644 --- a/preferences/migrations/0005_auto_20170824_0139.py +++ b/preferences/migrations/0005_auto_20170824_0139.py @@ -7,13 +7,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0004_assooption_services'), - ] + dependencies = [("preferences", "0004_assooption_services")] - operations = [ - migrations.RenameModel( - old_name='Services', - new_name='Service', - ), - ] + operations = [migrations.RenameModel(old_name="Services", new_name="Service")] diff --git a/preferences/migrations/0006_auto_20170824_0143.py b/preferences/migrations/0006_auto_20170824_0143.py index 782bbbdc..32d83d5e 100644 --- a/preferences/migrations/0006_auto_20170824_0143.py +++ b/preferences/migrations/0006_auto_20170824_0143.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0005_auto_20170824_0139'), - ] + dependencies = [("preferences", "0005_auto_20170824_0139")] operations = [ migrations.AlterField( - model_name='service', - name='image', - field=models.ImageField(blank=True, upload_to='logo'), - ), + model_name="service", + name="image", + field=models.ImageField(blank=True, upload_to="logo"), + ) ] diff --git a/preferences/migrations/0007_auto_20170824_2056.py b/preferences/migrations/0007_auto_20170824_2056.py index 55a74e08..f7f88036 100644 --- a/preferences/migrations/0007_auto_20170824_2056.py +++ b/preferences/migrations/0007_auto_20170824_2056.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0006_auto_20170824_0143'), - ] + dependencies = [("preferences", "0006_auto_20170824_0143")] operations = [ migrations.AlterField( - model_name='assooption', - name='name', - field=models.CharField(default="Association réseau de l'école machin", max_length=256), - ), + model_name="assooption", + name="name", + field=models.CharField( + default="Association réseau de l'école machin", max_length=256 + ), + ) ] diff --git a/preferences/migrations/0008_auto_20170824_2122.py b/preferences/migrations/0008_auto_20170824_2122.py index 183607aa..26f2c785 100644 --- a/preferences/migrations/0008_auto_20170824_2122.py +++ b/preferences/migrations/0008_auto_20170824_2122.py @@ -7,28 +7,25 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0007_auto_20170824_2056'), - ] + dependencies = [("preferences", "0007_auto_20170824_2056")] operations = [ - migrations.RemoveField( - model_name='assooption', - name='adresse', + migrations.RemoveField(model_name="assooption", name="adresse"), + migrations.AddField( + model_name="assooption", + name="adresse1", + field=models.CharField(default="1 Rue de exemple", max_length=128), ), migrations.AddField( - model_name='assooption', - name='adresse1', - field=models.CharField(default='1 Rue de exemple', max_length=128), - ), - migrations.AddField( - model_name='assooption', - name='adresse2', - field=models.CharField(default='94230 Cachan', max_length=128), + model_name="assooption", + name="adresse2", + field=models.CharField(default="94230 Cachan", max_length=128), ), migrations.AlterField( - model_name='assooption', - name='name', - field=models.CharField(default='Association réseau école machin', max_length=256), + model_name="assooption", + name="name", + field=models.CharField( + default="Association réseau école machin", max_length=256 + ), ), ] diff --git a/preferences/migrations/0009_assooption_utilisateur_asso.py b/preferences/migrations/0009_assooption_utilisateur_asso.py index 68bcc382..35e92885 100644 --- a/preferences/migrations/0009_assooption_utilisateur_asso.py +++ b/preferences/migrations/0009_assooption_utilisateur_asso.py @@ -11,13 +11,18 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('preferences', '0008_auto_20170824_2122'), + ("preferences", "0008_auto_20170824_2122"), ] operations = [ migrations.AddField( - model_name='assooption', - name='utilisateur_asso', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), - ), + model_name="assooption", + name="utilisateur_asso", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to=settings.AUTH_USER_MODEL, + ), + ) ] diff --git a/preferences/migrations/0010_auto_20170825_0459.py b/preferences/migrations/0010_auto_20170825_0459.py index 9d8a2cb5..f29ceefc 100644 --- a/preferences/migrations/0010_auto_20170825_0459.py +++ b/preferences/migrations/0010_auto_20170825_0459.py @@ -8,33 +8,59 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0009_assooption_utilisateur_asso'), - ] + dependencies = [("preferences", "0009_assooption_utilisateur_asso")] operations = [ migrations.CreateModel( - name='OptionalTopologie', + name="OptionalTopologie", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ) ], ), migrations.CreateModel( - name='Vlan', + name="Vlan", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('vlan_id', models.IntegerField()), - ('comment', models.CharField(max_length=256)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("vlan_id", models.IntegerField()), + ("comment", models.CharField(max_length=256)), ], ), migrations.AddField( - model_name='optionaltopologie', - name='vlan_decision_nok', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='decision_nok', to='preferences.Vlan'), + model_name="optionaltopologie", + name="vlan_decision_nok", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="decision_nok", + to="preferences.Vlan", + ), ), migrations.AddField( - model_name='optionaltopologie', - name='vlan_decision_ok', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='decision_ok', to='preferences.Vlan'), + model_name="optionaltopologie", + name="vlan_decision_ok", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="decision_ok", + to="preferences.Vlan", + ), ), ] diff --git a/preferences/migrations/0011_auto_20170825_2307.py b/preferences/migrations/0011_auto_20170825_2307.py index 58ad054f..057721c7 100644 --- a/preferences/migrations/0011_auto_20170825_2307.py +++ b/preferences/migrations/0011_auto_20170825_2307.py @@ -8,22 +8,30 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0010_auto_20170825_0459'), - ] + dependencies = [("preferences", "0010_auto_20170825_0459")] operations = [ migrations.AlterField( - model_name='optionaltopologie', - name='vlan_decision_nok', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='decision_nok', to='machines.Vlan'), + model_name="optionaltopologie", + name="vlan_decision_nok", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="decision_nok", + to="machines.Vlan", + ), ), migrations.AlterField( - model_name='optionaltopologie', - name='vlan_decision_ok', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='decision_ok', to='machines.Vlan'), - ), - migrations.DeleteModel( - name='Vlan', + model_name="optionaltopologie", + name="vlan_decision_ok", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="decision_ok", + to="machines.Vlan", + ), ), + migrations.DeleteModel(name="Vlan"), ] diff --git a/preferences/migrations/0012_generaloption_req_expire_hrs.py b/preferences/migrations/0012_generaloption_req_expire_hrs.py index e12baf19..82b138f7 100644 --- a/preferences/migrations/0012_generaloption_req_expire_hrs.py +++ b/preferences/migrations/0012_generaloption_req_expire_hrs.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0011_auto_20170825_2307'), - ] + dependencies = [("preferences", "0011_auto_20170825_2307")] operations = [ migrations.AddField( - model_name='generaloption', - name='req_expire_hrs', + model_name="generaloption", + name="req_expire_hrs", field=models.IntegerField(default=48), - ), + ) ] diff --git a/preferences/migrations/0013_generaloption_site_name.py b/preferences/migrations/0013_generaloption_site_name.py index 06a2a5e3..6c5c919b 100644 --- a/preferences/migrations/0013_generaloption_site_name.py +++ b/preferences/migrations/0013_generaloption_site_name.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0012_generaloption_req_expire_hrs'), - ] + dependencies = [("preferences", "0012_generaloption_req_expire_hrs")] operations = [ migrations.AddField( - model_name='generaloption', - name='site_name', - field=models.CharField(default='Re2o', max_length=32), - ), + model_name="generaloption", + name="site_name", + field=models.CharField(default="Re2o", max_length=32), + ) ] diff --git a/preferences/migrations/0014_generaloption_email_from.py b/preferences/migrations/0014_generaloption_email_from.py index ac109fd5..cf867e34 100644 --- a/preferences/migrations/0014_generaloption_email_from.py +++ b/preferences/migrations/0014_generaloption_email_from.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0013_generaloption_site_name'), - ] + dependencies = [("preferences", "0013_generaloption_site_name")] operations = [ migrations.AddField( - model_name='generaloption', - name='email_from', - field=models.EmailField(default='www-data@serveur.net', max_length=254), - ), + model_name="generaloption", + name="email_from", + field=models.EmailField(default="www-data@serveur.net", max_length=254), + ) ] diff --git a/preferences/migrations/0015_optionaltopologie_radius_general_policy.py b/preferences/migrations/0015_optionaltopologie_radius_general_policy.py index d07ac378..3e3ea4b8 100644 --- a/preferences/migrations/0015_optionaltopologie_radius_general_policy.py +++ b/preferences/migrations/0015_optionaltopologie_radius_general_policy.py @@ -7,14 +7,19 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0014_generaloption_email_from'), - ] + dependencies = [("preferences", "0014_generaloption_email_from")] operations = [ migrations.AddField( - model_name='optionaltopologie', - name='radius_general_policy', - field=models.CharField(choices=[('MACHINE', 'Sur le vlan de la plage ip machine'), ('DEFINED', 'Prédéfini')], default='DEFINED', max_length=32), - ), + model_name="optionaltopologie", + name="radius_general_policy", + field=models.CharField( + choices=[ + ("MACHINE", "Sur le vlan de la plage ip machine"), + ("DEFINED", "Prédéfini"), + ], + default="DEFINED", + max_length=32, + ), + ) ] diff --git a/preferences/migrations/0016_auto_20170902_1520.py b/preferences/migrations/0016_auto_20170902_1520.py index 1779d712..5d234e2c 100644 --- a/preferences/migrations/0016_auto_20170902_1520.py +++ b/preferences/migrations/0016_auto_20170902_1520.py @@ -7,14 +7,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0015_optionaltopologie_radius_general_policy'), - ] + dependencies = [("preferences", "0015_optionaltopologie_radius_general_policy")] 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), - ), + 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/0017_mailmessageoption.py b/preferences/migrations/0017_mailmessageoption.py index 31fb145c..26103d7f 100644 --- a/preferences/migrations/0017_mailmessageoption.py +++ b/preferences/migrations/0017_mailmessageoption.py @@ -7,17 +7,23 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0016_auto_20170902_1520'), - ] + dependencies = [("preferences", "0016_auto_20170902_1520")] operations = [ migrations.CreateModel( - name='MailMessageOption', + name="MailMessageOption", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('welcome_mail_fr', models.TextField(default='')), - ('welcome_mail_en', models.TextField(default='')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("welcome_mail_fr", models.TextField(default="")), + ("welcome_mail_en", models.TextField(default="")), ], - ), + ) ] diff --git a/preferences/migrations/0018_optionaltopologie_mac_autocapture.py b/preferences/migrations/0018_optionaltopologie_mac_autocapture.py index 386da143..62c44573 100644 --- a/preferences/migrations/0018_optionaltopologie_mac_autocapture.py +++ b/preferences/migrations/0018_optionaltopologie_mac_autocapture.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0017_mailmessageoption'), - ] + dependencies = [("preferences", "0017_mailmessageoption")] operations = [ migrations.AddField( - model_name='optionaltopologie', - name='mac_autocapture', + model_name="optionaltopologie", + name="mac_autocapture", field=models.BooleanField(default=False), - ), + ) ] diff --git a/preferences/migrations/0019_remove_optionaltopologie_mac_autocapture.py b/preferences/migrations/0019_remove_optionaltopologie_mac_autocapture.py index f423994c..f446a74a 100644 --- a/preferences/migrations/0019_remove_optionaltopologie_mac_autocapture.py +++ b/preferences/migrations/0019_remove_optionaltopologie_mac_autocapture.py @@ -7,13 +7,8 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0018_optionaltopologie_mac_autocapture'), - ] + dependencies = [("preferences", "0018_optionaltopologie_mac_autocapture")] operations = [ - migrations.RemoveField( - model_name='optionaltopologie', - name='mac_autocapture', - ), + migrations.RemoveField(model_name="optionaltopologie", name="mac_autocapture") ] diff --git a/preferences/migrations/0020_optionalmachine_ipv6.py b/preferences/migrations/0020_optionalmachine_ipv6.py index 77f0c07f..66758c20 100644 --- a/preferences/migrations/0020_optionalmachine_ipv6.py +++ b/preferences/migrations/0020_optionalmachine_ipv6.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0019_remove_optionaltopologie_mac_autocapture'), - ] + dependencies = [("preferences", "0019_remove_optionaltopologie_mac_autocapture")] operations = [ migrations.AddField( - model_name='optionalmachine', - name='ipv6', + model_name="optionalmachine", + name="ipv6", field=models.BooleanField(default=False), - ), + ) ] diff --git a/preferences/migrations/0021_auto_20171015_1741.py b/preferences/migrations/0021_auto_20171015_1741.py index cc94720a..c3100249 100644 --- a/preferences/migrations/0021_auto_20171015_1741.py +++ b/preferences/migrations/0021_auto_20171015_1741.py @@ -7,14 +7,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0020_optionalmachine_ipv6'), - ] + 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), - ), + 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 index ea389a32..a0173f2c 100644 --- a/preferences/migrations/0022_auto_20171015_1758.py +++ b/preferences/migrations/0022_auto_20171015_1758.py @@ -7,14 +7,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0021_auto_20171015_1741'), - ] + 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), - ), + 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 index 3235e49f..bb210bcb 100644 --- a/preferences/migrations/0023_auto_20171015_2033.py +++ b/preferences/migrations/0023_auto_20171015_2033.py @@ -7,14 +7,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0022_auto_20171015_1758'), - ] + 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), - ), + 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/0024_optionaluser_all_can_create.py b/preferences/migrations/0024_optionaluser_all_can_create.py index 3f7cf56e..14a0a531 100644 --- a/preferences/migrations/0024_optionaluser_all_can_create.py +++ b/preferences/migrations/0024_optionaluser_all_can_create.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0023_auto_20171015_2033'), - ] + dependencies = [("preferences", "0023_auto_20171015_2033")] operations = [ migrations.AddField( - model_name='optionaluser', - name='all_can_create', - field=models.BooleanField(default=False, help_text="Tous les users peuvent en créer d'autres"), - ), + model_name="optionaluser", + name="all_can_create", + field=models.BooleanField( + default=False, help_text="Tous les users peuvent en créer d'autres" + ), + ) ] diff --git a/preferences/migrations/0025_auto_20171231_2142.py b/preferences/migrations/0025_auto_20171231_2142.py index d54b8215..e90b9487 100644 --- a/preferences/migrations/0025_auto_20171231_2142.py +++ b/preferences/migrations/0025_auto_20171231_2142.py @@ -7,37 +7,59 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0024_optionaluser_all_can_create'), - ] + dependencies = [("preferences", "0024_optionaluser_all_can_create")] operations = [ migrations.AlterModelOptions( - name='assooption', - options={'permissions': (('view_assooption', "Peut voir les options de l'asso"),)}, + name="assooption", + options={ + "permissions": (("view_assooption", "Peut voir les options de l'asso"),) + }, ), migrations.AlterModelOptions( - name='generaloption', - options={'permissions': (('view_generaloption', 'Peut voir les options générales'),)}, + name="generaloption", + options={ + "permissions": ( + ("view_generaloption", "Peut voir les options générales"), + ) + }, ), migrations.AlterModelOptions( - name='mailmessageoption', - options={'permissions': (('view_mailmessageoption', 'Peut voir les options de mail'),)}, + name="mailmessageoption", + options={ + "permissions": ( + ("view_mailmessageoption", "Peut voir les options de mail"), + ) + }, ), migrations.AlterModelOptions( - name='optionalmachine', - options={'permissions': (('view_optionalmachine', 'Peut voir les options de machine'),)}, + name="optionalmachine", + options={ + "permissions": ( + ("view_optionalmachine", "Peut voir les options de machine"), + ) + }, ), migrations.AlterModelOptions( - name='optionaltopologie', - options={'permissions': (('view_optionaltopologie', 'Peut voir les options de topologie'),)}, + name="optionaltopologie", + options={ + "permissions": ( + ("view_optionaltopologie", "Peut voir les options de topologie"), + ) + }, ), migrations.AlterModelOptions( - name='optionaluser', - options={'permissions': (('view_optionaluser', "Peut voir les options de l'user"),)}, + name="optionaluser", + options={ + "permissions": ( + ("view_optionaluser", "Peut voir les options de l'user"), + ) + }, ), migrations.AlterModelOptions( - name='service', - options={'permissions': (('view_service', 'Peut voir les options de service'),)}, + name="service", + options={ + "permissions": (("view_service", "Peut voir les options de service"),) + }, ), ] diff --git a/preferences/migrations/0025_generaloption_general_message.py b/preferences/migrations/0025_generaloption_general_message.py index 073ec44f..042ad2ff 100644 --- a/preferences/migrations/0025_generaloption_general_message.py +++ b/preferences/migrations/0025_generaloption_general_message.py @@ -7,14 +7,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0024_optionaluser_all_can_create'), - ] + dependencies = [("preferences", "0024_optionaluser_all_can_create")] operations = [ migrations.AddField( - model_name='generaloption', - name='general_message', - field=models.TextField(default='', help_text='Message général affiché sur le site (maintenance, etc'), - ), + model_name="generaloption", + name="general_message", + field=models.TextField( + default="", + help_text="Message général affiché sur le site (maintenance, etc", + ), + ) ] diff --git a/preferences/migrations/0026_auto_20171216_0401.py b/preferences/migrations/0026_auto_20171216_0401.py index 4adba4cd..c5dc4d65 100644 --- a/preferences/migrations/0026_auto_20171216_0401.py +++ b/preferences/migrations/0026_auto_20171216_0401.py @@ -7,14 +7,16 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0025_generaloption_general_message'), - ] + dependencies = [("preferences", "0025_generaloption_general_message")] operations = [ migrations.AlterField( - model_name='generaloption', - name='general_message', - field=models.TextField(blank=True, default='', help_text='Message général affiché sur le site (maintenance, etc'), - ), + model_name="generaloption", + name="general_message", + field=models.TextField( + blank=True, + default="", + help_text="Message général affiché sur le site (maintenance, etc", + ), + ) ] diff --git a/preferences/migrations/0027_merge_20180106_2019.py b/preferences/migrations/0027_merge_20180106_2019.py index 68ce34fb..d2aefe50 100644 --- a/preferences/migrations/0027_merge_20180106_2019.py +++ b/preferences/migrations/0027_merge_20180106_2019.py @@ -8,9 +8,8 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('preferences', '0025_auto_20171231_2142'), - ('preferences', '0026_auto_20171216_0401'), + ("preferences", "0025_auto_20171231_2142"), + ("preferences", "0026_auto_20171216_0401"), ] - operations = [ - ] + operations = [] diff --git a/preferences/migrations/0028_assooption_description.py b/preferences/migrations/0028_assooption_description.py index 7c955d86..ad73f11b 100644 --- a/preferences/migrations/0028_assooption_description.py +++ b/preferences/migrations/0028_assooption_description.py @@ -8,14 +8,14 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('preferences', '0027_merge_20180106_2019'), - ('preferences', '0043_optionalmachine_create_machine'), + ("preferences", "0027_merge_20180106_2019"), + ("preferences", "0043_optionalmachine_create_machine"), ] operations = [ migrations.AddField( - model_name='assooption', - name='description', - field=models.TextField(default=''), - ), + model_name="assooption", + name="description", + field=models.TextField(default=""), + ) ] diff --git a/preferences/migrations/0028_auto_20180111_1129.py b/preferences/migrations/0028_auto_20180111_1129.py index c6c03719..08d75b37 100644 --- a/preferences/migrations/0028_auto_20180111_1129.py +++ b/preferences/migrations/0028_auto_20180111_1129.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0027_merge_20180106_2019'), - ] + dependencies = [("preferences", "0027_merge_20180106_2019")] operations = [ migrations.AddField( - model_name='optionaluser', - name='max_recharge', + model_name="optionaluser", + name="max_recharge", field=models.DecimalField(decimal_places=2, default=100, max_digits=5), - ), + ) ] diff --git a/preferences/migrations/0028_auto_20180128_2203.py b/preferences/migrations/0028_auto_20180128_2203.py index ac8894fd..582e7eb0 100644 --- a/preferences/migrations/0028_auto_20180128_2203.py +++ b/preferences/migrations/0028_auto_20180128_2203.py @@ -7,18 +7,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0027_merge_20180106_2019'), - ] + dependencies = [("preferences", "0027_merge_20180106_2019")] operations = [ - migrations.RemoveField( - model_name='optionalmachine', - name='ipv6', - ), + migrations.RemoveField(model_name="optionalmachine", name="ipv6"), migrations.AddField( - model_name='optionalmachine', - name='ipv6_mode', - field=models.CharField(choices=[('SLAAC', 'Autoconfiguration par RA'), ('DHCPV6', 'Attribution des ip par dhcpv6'), ('DISABLED', 'Désactivé')], default='DISABLED', max_length=32), + model_name="optionalmachine", + name="ipv6_mode", + field=models.CharField( + choices=[ + ("SLAAC", "Autoconfiguration par RA"), + ("DHCPV6", "Attribution des ip par dhcpv6"), + ("DISABLED", "Désactivé"), + ], + default="DISABLED", + max_length=32, + ), ), ] diff --git a/preferences/migrations/0029_auto_20180111_1134.py b/preferences/migrations/0029_auto_20180111_1134.py index 92220312..556c332b 100644 --- a/preferences/migrations/0029_auto_20180111_1134.py +++ b/preferences/migrations/0029_auto_20180111_1134.py @@ -7,14 +7,16 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0028_auto_20180111_1129'), - ] + dependencies = [("preferences", "0028_auto_20180111_1129")] operations = [ migrations.AddField( - model_name='assooption', - name='payment', - field=models.CharField(choices=[('NONE', 'NONE'), ('COMNPAY', 'COMNPAY')], default='NONE', max_length=255), - ), + model_name="assooption", + name="payment", + field=models.CharField( + choices=[("NONE", "NONE"), ("COMNPAY", "COMNPAY")], + default="NONE", + max_length=255, + ), + ) ] diff --git a/preferences/migrations/0029_auto_20180318_0213.py b/preferences/migrations/0029_auto_20180318_0213.py index 83d135b4..4252e839 100644 --- a/preferences/migrations/0029_auto_20180318_0213.py +++ b/preferences/migrations/0029_auto_20180318_0213.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0028_assooption_description'), - ] + dependencies = [("preferences", "0028_assooption_description")] operations = [ migrations.AlterField( - model_name='assooption', - name='description', + model_name="assooption", + name="description", field=models.TextField(blank=True, null=True), - ), + ) ] diff --git a/preferences/migrations/0029_auto_20180318_1005.py b/preferences/migrations/0029_auto_20180318_1005.py index f94fcb57..8d202955 100644 --- a/preferences/migrations/0029_auto_20180318_1005.py +++ b/preferences/migrations/0029_auto_20180318_1005.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0028_assooption_description'), - ] + dependencies = [("preferences", "0028_assooption_description")] operations = [ migrations.AlterField( - model_name='assooption', - name='payment_id', - field=models.CharField(blank=True, default='', max_length=255), - ), + model_name="assooption", + name="payment_id", + field=models.CharField(blank=True, default="", max_length=255), + ) ] diff --git a/preferences/migrations/0030_auto_20180111_2346.py b/preferences/migrations/0030_auto_20180111_2346.py index 7f912bbd..7e23e2ff 100644 --- a/preferences/migrations/0030_auto_20180111_2346.py +++ b/preferences/migrations/0030_auto_20180111_2346.py @@ -7,18 +7,13 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0029_auto_20180111_1134'), - ] + dependencies = [("preferences", "0029_auto_20180111_1134")] operations = [ - migrations.RemoveField( - model_name='optionaluser', - name='max_recharge', - ), + migrations.RemoveField(model_name="optionaluser", name="max_recharge"), migrations.AddField( - model_name='optionaluser', - name='max_solde', + model_name="optionaluser", + name="max_solde", field=models.DecimalField(decimal_places=2, default=50, max_digits=5), ), ] diff --git a/preferences/migrations/0030_merge_20180320_1419.py b/preferences/migrations/0030_merge_20180320_1419.py index 90d70370..c13777a0 100644 --- a/preferences/migrations/0030_merge_20180320_1419.py +++ b/preferences/migrations/0030_merge_20180320_1419.py @@ -8,9 +8,8 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('preferences', '0029_auto_20180318_1005'), - ('preferences', '0029_auto_20180318_0213'), + ("preferences", "0029_auto_20180318_1005"), + ("preferences", "0029_auto_20180318_0213"), ] - operations = [ - ] + operations = [] diff --git a/preferences/migrations/0031_auto_20180323_0218.py b/preferences/migrations/0031_auto_20180323_0218.py index 25c98cbf..9d767700 100644 --- a/preferences/migrations/0031_auto_20180323_0218.py +++ b/preferences/migrations/0031_auto_20180323_0218.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0030_merge_20180320_1419'), - ] + dependencies = [("preferences", "0030_merge_20180320_1419")] operations = [ migrations.AlterField( - model_name='generaloption', - name='email_from', - field=models.EmailField(default='www-data@example.com', max_length=254), - ), + model_name="generaloption", + name="email_from", + field=models.EmailField(default="www-data@example.com", max_length=254), + ) ] diff --git a/preferences/migrations/0031_optionaluser_self_adhesion.py b/preferences/migrations/0031_optionaluser_self_adhesion.py index 48a95044..a6ce5ecf 100644 --- a/preferences/migrations/0031_optionaluser_self_adhesion.py +++ b/preferences/migrations/0031_optionaluser_self_adhesion.py @@ -7,14 +7,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0030_auto_20180111_2346'), - ] + dependencies = [("preferences", "0030_auto_20180111_2346")] operations = [ migrations.AddField( - model_name='optionaluser', - name='self_adhesion', - field=models.BooleanField(default=False, help_text='Un nouvel utilisateur peut se créer son compte sur re2o'), - ), + model_name="optionaluser", + name="self_adhesion", + field=models.BooleanField( + default=False, + help_text="Un nouvel utilisateur peut se créer son compte sur re2o", + ), + ) ] diff --git a/preferences/migrations/0032_optionaluser_min_online_payment.py b/preferences/migrations/0032_optionaluser_min_online_payment.py index ef78d012..910d98dd 100644 --- a/preferences/migrations/0032_optionaluser_min_online_payment.py +++ b/preferences/migrations/0032_optionaluser_min_online_payment.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0031_optionaluser_self_adhesion'), - ] + dependencies = [("preferences", "0031_optionaluser_self_adhesion")] operations = [ migrations.AddField( - model_name='optionaluser', - name='min_online_payment', + model_name="optionaluser", + name="min_online_payment", field=models.DecimalField(decimal_places=2, default=10, max_digits=5), - ), + ) ] diff --git a/preferences/migrations/0032_optionaluser_shell_default.py b/preferences/migrations/0032_optionaluser_shell_default.py index 365a616e..268fed6a 100644 --- a/preferences/migrations/0032_optionaluser_shell_default.py +++ b/preferences/migrations/0032_optionaluser_shell_default.py @@ -9,14 +9,19 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('users', '0070_auto_20180324_1906'), - ('preferences', '0031_auto_20180323_0218'), + ("users", "0070_auto_20180324_1906"), + ("preferences", "0031_auto_20180323_0218"), ] operations = [ migrations.AddField( - model_name='optionaluser', - name='shell_default', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.ListShell'), - ), + model_name="optionaluser", + name="shell_default", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="users.ListShell", + ), + ) ] diff --git a/preferences/migrations/0033_accueiloption.py b/preferences/migrations/0033_accueiloption.py index 1b665e61..7722dc13 100644 --- a/preferences/migrations/0033_accueiloption.py +++ b/preferences/migrations/0033_accueiloption.py @@ -8,22 +8,48 @@ import re2o.mixins class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0032_optionaluser_shell_default'), - ] + dependencies = [("preferences", "0032_optionaluser_shell_default")] operations = [ migrations.CreateModel( - name='AccueilOption', + name="AccueilOption", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('facebook_url', models.URLField(blank=True, help_text='Url du compte facebook', null=True)), - ('twitter_url', models.URLField(blank=True, help_text='Url du compte twitter', null=True)), - ('twitter_account_name', models.CharField(blank=True, help_text='Nom du compte à afficher', max_length=32, null=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "facebook_url", + models.URLField( + blank=True, help_text="Url du compte facebook", null=True + ), + ), + ( + "twitter_url", + models.URLField( + blank=True, help_text="Url du compte twitter", null=True + ), + ), + ( + "twitter_account_name", + models.CharField( + blank=True, + help_text="Nom du compte à afficher", + max_length=32, + null=True, + ), + ), ], options={ - 'permissions': (('view_accueiloption', "Peut voir les options de l'accueil"),), + "permissions": ( + ("view_accueiloption", "Peut voir les options de l'accueil"), + ) }, bases=(re2o.mixins.AclMixin, models.Model), - ), + ) ] diff --git a/preferences/migrations/0033_generaloption_gtu_sum_up.py b/preferences/migrations/0033_generaloption_gtu_sum_up.py index 63c2df5e..81013c39 100644 --- a/preferences/migrations/0033_generaloption_gtu_sum_up.py +++ b/preferences/migrations/0033_generaloption_gtu_sum_up.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0032_optionaluser_min_online_payment'), - ] + dependencies = [("preferences", "0032_optionaluser_min_online_payment")] operations = [ migrations.AddField( - model_name='generaloption', - name='GTU_sum_up', - field=models.TextField(blank=True, default='', help_text='Résumé des CGU'), - ), + model_name="generaloption", + name="GTU_sum_up", + field=models.TextField(blank=True, default="", help_text="Résumé des CGU"), + ) ] diff --git a/preferences/migrations/0034_auto_20180114_2025.py b/preferences/migrations/0034_auto_20180114_2025.py index b6969021..96742c6c 100644 --- a/preferences/migrations/0034_auto_20180114_2025.py +++ b/preferences/migrations/0034_auto_20180114_2025.py @@ -7,19 +7,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0033_generaloption_gtu_sum_up'), - ] + dependencies = [("preferences", "0033_generaloption_gtu_sum_up")] operations = [ migrations.AddField( - model_name='generaloption', - name='GTU', - field=models.FileField(default='', upload_to='GTU'), + model_name="generaloption", + name="GTU", + field=models.FileField(default="", upload_to="GTU"), ), migrations.AlterField( - model_name='generaloption', - name='GTU_sum_up', - field=models.TextField(blank=True, default=''), + model_name="generaloption", + name="GTU_sum_up", + field=models.TextField(blank=True, default=""), ), ] diff --git a/preferences/migrations/0034_auto_20180416_1120.py b/preferences/migrations/0034_auto_20180416_1120.py index 5f27ffe5..14b50f1e 100644 --- a/preferences/migrations/0034_auto_20180416_1120.py +++ b/preferences/migrations/0034_auto_20180416_1120.py @@ -7,17 +7,16 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0033_accueiloption'), - ] + dependencies = [("preferences", "0033_accueiloption")] operations = [ - migrations.RenameModel( - old_name='AccueilOption', - new_name='HomeOption', - ), + migrations.RenameModel(old_name="AccueilOption", new_name="HomeOption"), migrations.AlterModelOptions( - name='homeoption', - options={'permissions': (('view_homeoption', "Peut voir les options de l'accueil"),)}, + name="homeoption", + options={ + "permissions": ( + ("view_homeoption", "Peut voir les options de l'accueil"), + ) + }, ), ] diff --git a/preferences/migrations/0035_auto_20180114_2132.py b/preferences/migrations/0035_auto_20180114_2132.py index e3767828..0e851954 100644 --- a/preferences/migrations/0035_auto_20180114_2132.py +++ b/preferences/migrations/0035_auto_20180114_2132.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0034_auto_20180114_2025'), - ] + dependencies = [("preferences", "0034_auto_20180114_2025")] operations = [ migrations.AlterField( - model_name='generaloption', - name='GTU', - field=models.FileField(default='', upload_to='/var/www/static/'), - ), + model_name="generaloption", + name="GTU", + field=models.FileField(default="", upload_to="/var/www/static/"), + ) ] diff --git a/preferences/migrations/0035_optionaluser_allow_self_subscription.py b/preferences/migrations/0035_optionaluser_allow_self_subscription.py index 5fc45714..8bc879b3 100644 --- a/preferences/migrations/0035_optionaluser_allow_self_subscription.py +++ b/preferences/migrations/0035_optionaluser_allow_self_subscription.py @@ -7,14 +7,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0034_auto_20180416_1120'), - ] + dependencies = [("preferences", "0034_auto_20180416_1120")] operations = [ migrations.AddField( - model_name='optionaluser', - name='allow_self_subscription', - field=models.BooleanField(default=False, help_text="Autoriser les utilisateurs à cotiser par eux mêmes via les moyens de paiement permettant l'auto-cotisation."), - ), + model_name="optionaluser", + name="allow_self_subscription", + field=models.BooleanField( + default=False, + help_text="Autoriser les utilisateurs à cotiser par eux mêmes via les moyens de paiement permettant l'auto-cotisation.", + ), + ) ] diff --git a/preferences/migrations/0036_auto_20180114_2141.py b/preferences/migrations/0036_auto_20180114_2141.py index 1b844ac8..1d67f357 100644 --- a/preferences/migrations/0036_auto_20180114_2141.py +++ b/preferences/migrations/0036_auto_20180114_2141.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0035_auto_20180114_2132'), - ] + dependencies = [("preferences", "0035_auto_20180114_2132")] operations = [ migrations.AlterField( - model_name='generaloption', - name='GTU', - field=models.FileField(default='', upload_to=''), - ), + model_name="generaloption", + name="GTU", + field=models.FileField(default="", upload_to=""), + ) ] diff --git a/preferences/migrations/0037_auto_20180114_2156.py b/preferences/migrations/0037_auto_20180114_2156.py index efafa806..d8e65a87 100644 --- a/preferences/migrations/0037_auto_20180114_2156.py +++ b/preferences/migrations/0037_auto_20180114_2156.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0036_auto_20180114_2141'), - ] + dependencies = [("preferences", "0036_auto_20180114_2141")] operations = [ migrations.AlterField( - model_name='generaloption', - name='GTU', - field=models.FileField(default='', null=True, upload_to=''), - ), + model_name="generaloption", + name="GTU", + field=models.FileField(default="", null=True, upload_to=""), + ) ] diff --git a/preferences/migrations/0038_auto_20180114_2209.py b/preferences/migrations/0038_auto_20180114_2209.py index 3077ebff..4f2e4913 100644 --- a/preferences/migrations/0038_auto_20180114_2209.py +++ b/preferences/migrations/0038_auto_20180114_2209.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0037_auto_20180114_2156'), - ] + dependencies = [("preferences", "0037_auto_20180114_2156")] operations = [ migrations.AlterField( - model_name='generaloption', - name='GTU', - field=models.FileField(blank=True, default='', null=True, upload_to=''), - ), + model_name="generaloption", + name="GTU", + field=models.FileField(blank=True, default="", null=True, upload_to=""), + ) ] diff --git a/preferences/migrations/0039_auto_20180115_0003.py b/preferences/migrations/0039_auto_20180115_0003.py index f8da5c27..577a4c2d 100644 --- a/preferences/migrations/0039_auto_20180115_0003.py +++ b/preferences/migrations/0039_auto_20180115_0003.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0038_auto_20180114_2209'), - ] + dependencies = [("preferences", "0038_auto_20180114_2209")] operations = [ migrations.AddField( - model_name='assooption', - name='payment_id', + model_name="assooption", + name="payment_id", field=models.CharField(max_length=255, null=True), - ), + ) ] diff --git a/preferences/migrations/0040_auto_20180129_1745.py b/preferences/migrations/0040_auto_20180129_1745.py index 7e657079..55f25633 100644 --- a/preferences/migrations/0040_auto_20180129_1745.py +++ b/preferences/migrations/0040_auto_20180129_1745.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from django.db import migrations, models + try: import preferences.aes_field as aes_field except ImportError: @@ -11,19 +12,17 @@ except ImportError: class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0039_auto_20180115_0003'), - ] + dependencies = [("preferences", "0039_auto_20180115_0003")] operations = [ migrations.AddField( - model_name='assooption', - name='payment_pass', + model_name="assooption", + name="payment_pass", field=aes_field.AESEncryptedField(blank=True, max_length=255, null=True), ), migrations.AlterField( - model_name='assooption', - name='payment_id', - field=models.CharField(default='', max_length=255), + model_name="assooption", + name="payment_id", + field=models.CharField(default="", max_length=255), ), ] diff --git a/preferences/migrations/0041_merge_20180130_0052.py b/preferences/migrations/0041_merge_20180130_0052.py index ce2a1e5c..0a4d3daa 100644 --- a/preferences/migrations/0041_merge_20180130_0052.py +++ b/preferences/migrations/0041_merge_20180130_0052.py @@ -8,9 +8,8 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('preferences', '0028_auto_20180128_2203'), - ('preferences', '0040_auto_20180129_1745'), + ("preferences", "0028_auto_20180128_2203"), + ("preferences", "0040_auto_20180129_1745"), ] - operations = [ - ] + operations = [] diff --git a/preferences/migrations/0042_auto_20180222_1743.py b/preferences/migrations/0042_auto_20180222_1743.py index b7ab7abe..f6b7f3f6 100644 --- a/preferences/migrations/0042_auto_20180222_1743.py +++ b/preferences/migrations/0042_auto_20180222_1743.py @@ -7,23 +7,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0041_merge_20180130_0052'), - ] + dependencies = [("preferences", "0041_merge_20180130_0052")] operations = [ - migrations.RemoveField( - model_name='optionaluser', - name='all_can_create', + migrations.RemoveField(model_name="optionaluser", name="all_can_create"), + migrations.AddField( + model_name="optionaluser", + name="all_can_create_adherent", + field=models.BooleanField( + default=False, help_text="Les users peuvent créer d'autres adhérents" + ), ), migrations.AddField( - model_name='optionaluser', - name='all_can_create_adherent', - field=models.BooleanField(default=False, help_text="Les users peuvent créer d'autres adhérents"), - ), - migrations.AddField( - model_name='optionaluser', - name='all_can_create_club', - field=models.BooleanField(default=False, help_text='Les users peuvent créer un club'), + model_name="optionaluser", + name="all_can_create_club", + field=models.BooleanField( + default=False, help_text="Les users peuvent créer un club" + ), ), ] diff --git a/preferences/migrations/0043_optionalmachine_create_machine.py b/preferences/migrations/0043_optionalmachine_create_machine.py index e01a5878..b62e7c09 100644 --- a/preferences/migrations/0043_optionalmachine_create_machine.py +++ b/preferences/migrations/0043_optionalmachine_create_machine.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0042_auto_20180222_1743'), - ] + dependencies = [("preferences", "0042_auto_20180222_1743")] operations = [ migrations.AddField( - model_name='optionalmachine', - name='create_machine', - field=models.BooleanField(default=True, help_text="Permet à l'user de créer une machine"), - ), + model_name="optionalmachine", + name="create_machine", + field=models.BooleanField( + default=True, help_text="Permet à l'user de créer une machine" + ), + ) ] diff --git a/preferences/migrations/0044_remove_payment_pass.py b/preferences/migrations/0044_remove_payment_pass.py index 23d45145..b9f51ce8 100644 --- a/preferences/migrations/0044_remove_payment_pass.py +++ b/preferences/migrations/0044_remove_payment_pass.py @@ -7,14 +7,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0035_optionaluser_allow_self_subscription'), - ] - - operations = [ - migrations.RemoveField( - model_name='assooption', - name='payment_pass', - ), - ] + dependencies = [("preferences", "0035_optionaluser_allow_self_subscription")] + operations = [migrations.RemoveField(model_name="assooption", name="payment_pass")] diff --git a/preferences/migrations/0045_remove_unused_payment_fields.py b/preferences/migrations/0045_remove_unused_payment_fields.py index 6944f58c..2ed40a42 100644 --- a/preferences/migrations/0045_remove_unused_payment_fields.py +++ b/preferences/migrations/0045_remove_unused_payment_fields.py @@ -8,37 +8,18 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('preferences', '0044_remove_payment_pass'), - ('cotisations', '0030_custom_payment'), + ("preferences", "0044_remove_payment_pass"), + ("cotisations", "0030_custom_payment"), ] operations = [ + migrations.RemoveField(model_name="assooption", name="payment"), + migrations.RemoveField(model_name="assooption", name="payment_id"), migrations.RemoveField( - model_name='assooption', - name='payment', - ), - migrations.RemoveField( - model_name='assooption', - name='payment_id', - ), - migrations.RemoveField( - model_name='optionaluser', - name='allow_self_subscription', - ), - migrations.RemoveField( - model_name='optionaluser', - name='max_solde', - ), - migrations.RemoveField( - model_name='optionaluser', - name='min_online_payment', - ), - migrations.RemoveField( - model_name='optionaluser', - name='solde_negatif', - ), - migrations.RemoveField( - model_name='optionaluser', - name='user_solde', + model_name="optionaluser", name="allow_self_subscription" ), + migrations.RemoveField(model_name="optionaluser", name="max_solde"), + migrations.RemoveField(model_name="optionaluser", name="min_online_payment"), + migrations.RemoveField(model_name="optionaluser", name="solde_negatif"), + migrations.RemoveField(model_name="optionaluser", name="user_solde"), ] diff --git a/preferences/migrations/0046_optionaluser_mail_extension.py b/preferences/migrations/0046_optionaluser_mail_extension.py index 9de1608a..ff6f27a1 100644 --- a/preferences/migrations/0046_optionaluser_mail_extension.py +++ b/preferences/migrations/0046_optionaluser_mail_extension.py @@ -7,24 +7,31 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0045_remove_unused_payment_fields'), - ] + dependencies = [("preferences", "0045_remove_unused_payment_fields")] operations = [ migrations.AddField( - model_name='optionaluser', - name='local_email_accounts_enabled', - field=models.BooleanField(default=False, help_text='Enable local email accounts for users'), + model_name="optionaluser", + name="local_email_accounts_enabled", + field=models.BooleanField( + default=False, help_text="Enable local email accounts for users" + ), ), migrations.AddField( - model_name='optionaluser', - name='local_email_domain', - field=models.CharField(default='@example.org', help_text='Domain to use for local email accounts', max_length=32), + model_name="optionaluser", + name="local_email_domain", + field=models.CharField( + default="@example.org", + help_text="Domain to use for local email accounts", + max_length=32, + ), ), migrations.AddField( - model_name='optionaluser', - name='max_email_address', - field=models.IntegerField(default=15, help_text='Maximum number of local email address for a standard user'), + model_name="optionaluser", + name="max_email_address", + field=models.IntegerField( + default=15, + help_text="Maximum number of local email address for a standard user", + ), ), ] diff --git a/preferences/migrations/0047_mailcontact.py b/preferences/migrations/0047_mailcontact.py index c7b7eda5..f6d84c47 100644 --- a/preferences/migrations/0047_mailcontact.py +++ b/preferences/migrations/0047_mailcontact.py @@ -8,21 +8,40 @@ import re2o.mixins class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0046_optionaluser_mail_extension'), - ] + dependencies = [("preferences", "0046_optionaluser_mail_extension")] operations = [ migrations.CreateModel( - name='MailContact', + name="MailContact", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('address', models.EmailField(default='contact@example.org', help_text="Contact email adress", max_length=254)), - ('commentary', models.CharField(blank=True, help_text="Description of the associated email adress.", max_length=256, null=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "address", + models.EmailField( + default="contact@example.org", + help_text="Contact email adress", + max_length=254, + ), + ), + ( + "commentary", + models.CharField( + blank=True, + help_text="Description of the associated email adress.", + max_length=256, + null=True, + ), + ), ], - options={ - 'permissions': (('view_mailcontact', "Can see contact email"),), - }, + options={"permissions": (("view_mailcontact", "Can see contact email"),)}, bases=(re2o.mixins.AclMixin, models.Model), - ), + ) ] diff --git a/preferences/migrations/0048_auto_20180811_1515.py b/preferences/migrations/0048_auto_20180811_1515.py index cf55a660..24b8ec81 100644 --- a/preferences/migrations/0048_auto_20180811_1515.py +++ b/preferences/migrations/0048_auto_20180811_1515.py @@ -7,24 +7,30 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0047_mailcontact'), - ] + dependencies = [("preferences", "0047_mailcontact")] operations = [ migrations.RenameField( - model_name='generaloption', - old_name='general_message', - new_name='general_message_fr', + model_name="generaloption", + old_name="general_message", + new_name="general_message_fr", ), migrations.AddField( - model_name='generaloption', - name='general_message_en', - field=models.TextField(blank=True, default='', help_text='General message displayed on the English version of the website.'), + model_name="generaloption", + name="general_message_en", + field=models.TextField( + blank=True, + default="", + help_text="General message displayed on the English version of the website.", + ), ), migrations.AlterField( - model_name='generaloption', - name='general_message_fr', - field=models.TextField(blank=True, default='', help_text='Message général affiché sur le site (maintenance, etc)'), + model_name="generaloption", + name="general_message_fr", + field=models.TextField( + blank=True, + default="", + help_text="Message général affiché sur le site (maintenance, etc)", + ), ), ] diff --git a/preferences/migrations/0049_optionaluser_self_change_shell.py b/preferences/migrations/0049_optionaluser_self_change_shell.py index 161792eb..65ee58b9 100644 --- a/preferences/migrations/0049_optionaluser_self_change_shell.py +++ b/preferences/migrations/0049_optionaluser_self_change_shell.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0048_auto_20180811_1515'), - ] + dependencies = [("preferences", "0048_auto_20180811_1515")] operations = [ migrations.AddField( - model_name='optionaluser', - name='self_change_shell', - field=models.BooleanField(default=False, help_text='Users can change their shell'), - ), + model_name="optionaluser", + name="self_change_shell", + field=models.BooleanField( + default=False, help_text="Users can change their shell" + ), + ) ] diff --git a/preferences/migrations/0050_auto_20180818_1329.py b/preferences/migrations/0050_auto_20180818_1329.py index 1cd4a269..eb783d63 100644 --- a/preferences/migrations/0050_auto_20180818_1329.py +++ b/preferences/migrations/0050_auto_20180818_1329.py @@ -7,140 +7,224 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0049_optionaluser_self_change_shell'), - ] + dependencies = [("preferences", "0049_optionaluser_self_change_shell")] operations = [ migrations.AlterModelOptions( - name='assooption', - options={'permissions': (('view_assooption', 'Can view the organisation options'),), 'verbose_name': 'organisation options'}, + name="assooption", + options={ + "permissions": ( + ("view_assooption", "Can view the organisation options"), + ), + "verbose_name": "organisation options", + }, ), migrations.AlterModelOptions( - name='generaloption', - options={'permissions': (('view_generaloption', 'Can view the general options'),), 'verbose_name': 'general options'}, + name="generaloption", + options={ + "permissions": ( + ("view_generaloption", "Can view the general options"), + ), + "verbose_name": "general options", + }, ), migrations.AlterModelOptions( - name='homeoption', - options={'permissions': (('view_homeoption', 'Can view the homepage options'),), 'verbose_name': 'homepage options'}, + name="homeoption", + options={ + "permissions": (("view_homeoption", "Can view the homepage options"),), + "verbose_name": "homepage options", + }, ), migrations.AlterModelOptions( - name='mailcontact', - options={'permissions': (('view_mailcontact', 'Can view a contact email address object'),), 'verbose_name': 'contact email address', 'verbose_name_plural': 'contact email addresses'}, + name="mailcontact", + options={ + "permissions": ( + ("view_mailcontact", "Can view a contact email address object"), + ), + "verbose_name": "contact email address", + "verbose_name_plural": "contact email addresses", + }, ), migrations.AlterModelOptions( - name='mailmessageoption', - options={'permissions': (('view_mailmessageoption', 'Can view the email message options'),), 'verbose_name': 'email message options'}, + name="mailmessageoption", + options={ + "permissions": ( + ("view_mailmessageoption", "Can view the email message options"), + ), + "verbose_name": "email message options", + }, ), migrations.AlterModelOptions( - name='optionalmachine', - options={'permissions': (('view_optionalmachine', 'Can view the machine options'),), 'verbose_name': 'machine options'}, + name="optionalmachine", + options={ + "permissions": ( + ("view_optionalmachine", "Can view the machine options"), + ), + "verbose_name": "machine options", + }, ), migrations.AlterModelOptions( - name='optionaltopologie', - options={'permissions': (('view_optionaltopologie', 'Can view the topology options'),), 'verbose_name': 'topology options'}, + name="optionaltopologie", + options={ + "permissions": ( + ("view_optionaltopologie", "Can view the topology options"), + ), + "verbose_name": "topology options", + }, ), migrations.AlterModelOptions( - name='optionaluser', - options={'permissions': (('view_optionaluser', 'Can view the user options'),), 'verbose_name': 'user options'}, + name="optionaluser", + options={ + "permissions": (("view_optionaluser", "Can view the user options"),), + "verbose_name": "user options", + }, ), migrations.AlterModelOptions( - name='service', - options={'permissions': (('view_service', 'Can view the service options'),), 'verbose_name': 'service', 'verbose_name_plural': 'services'}, + name="service", + options={ + "permissions": (("view_service", "Can view the service options"),), + "verbose_name": "service", + "verbose_name_plural": "services", + }, ), migrations.AlterField( - model_name='assooption', - name='adresse1', - field=models.CharField(default='Threadneedle Street', max_length=128), + model_name="assooption", + name="adresse1", + field=models.CharField(default="Threadneedle Street", max_length=128), ), migrations.AlterField( - model_name='assooption', - name='adresse2', - field=models.CharField(default='London EC2R 8AH', max_length=128), + model_name="assooption", + name="adresse2", + field=models.CharField(default="London EC2R 8AH", max_length=128), ), migrations.AlterField( - model_name='assooption', - name='name', - field=models.CharField(default='Networking organisation school Something', max_length=256), + model_name="assooption", + name="name", + field=models.CharField( + default="Networking organisation school Something", max_length=256 + ), ), migrations.AlterField( - model_name='assooption', - name='pseudo', - field=models.CharField(default='Organisation', max_length=32), + model_name="assooption", + name="pseudo", + field=models.CharField(default="Organisation", max_length=32), ), migrations.AlterField( - model_name='generaloption', - name='general_message_en', - field=models.TextField(blank=True, default='', help_text='General message displayed on the English version of the website (e.g. in case of maintenance)'), + model_name="generaloption", + name="general_message_en", + field=models.TextField( + blank=True, + default="", + help_text="General message displayed on the English version of the website (e.g. in case of maintenance)", + ), ), migrations.AlterField( - model_name='generaloption', - name='general_message_fr', - field=models.TextField(blank=True, default='', help_text='General message displayed on the French version of the website (e.g. in case of maintenance)'), + model_name="generaloption", + name="general_message_fr", + field=models.TextField( + blank=True, + default="", + help_text="General message displayed on the French version of the website (e.g. in case of maintenance)", + ), ), migrations.AlterField( - model_name='homeoption', - name='facebook_url', + model_name="homeoption", + name="facebook_url", field=models.URLField(blank=True, null=True), ), migrations.AlterField( - model_name='homeoption', - name='twitter_account_name', + model_name="homeoption", + name="twitter_account_name", field=models.CharField(blank=True, max_length=32, null=True), ), migrations.AlterField( - model_name='homeoption', - name='twitter_url', + model_name="homeoption", + name="twitter_url", field=models.URLField(blank=True, null=True), ), migrations.AlterField( - model_name='mailcontact', - name='address', - field=models.EmailField(default='contact@example.org', help_text='Contact email address', max_length=254), + model_name="mailcontact", + name="address", + field=models.EmailField( + default="contact@example.org", + help_text="Contact email address", + max_length=254, + ), ), migrations.AlterField( - model_name='mailcontact', - name='commentary', - field=models.CharField(blank=True, help_text='Description of the associated email address.', max_length=256, null=True), + model_name="mailcontact", + name="commentary", + field=models.CharField( + blank=True, + help_text="Description of the associated email address.", + max_length=256, + null=True, + ), ), migrations.AlterField( - model_name='optionalmachine', - name='create_machine', + model_name="optionalmachine", + name="create_machine", field=models.BooleanField(default=True), ), migrations.AlterField( - model_name='optionalmachine', - name='ipv6_mode', - field=models.CharField(choices=[('SLAAC', 'Autoconfiguration by RA'), ('DHCPV6', 'IP addresses assigning by DHCPv6'), ('DISABLED', 'Disabled')], default='DISABLED', max_length=32), + model_name="optionalmachine", + name="ipv6_mode", + field=models.CharField( + choices=[ + ("SLAAC", "Autoconfiguration by RA"), + ("DHCPV6", "IP addresses assigning by DHCPv6"), + ("DISABLED", "Disabled"), + ], + default="DISABLED", + max_length=32, + ), ), migrations.AlterField( - model_name='optionaltopologie', - name='radius_general_policy', - field=models.CharField(choices=[('MACHINE', "On the IP range's VLAN of the machine"), ('DEFINED', "Preset in 'VLAN for machines accepted by RADIUS'")], default='DEFINED', max_length=32), + model_name="optionaltopologie", + name="radius_general_policy", + field=models.CharField( + choices=[ + ("MACHINE", "On the IP range's VLAN of the machine"), + ("DEFINED", "Preset in 'VLAN for machines accepted by RADIUS'"), + ], + default="DEFINED", + max_length=32, + ), ), migrations.AlterField( - model_name='optionaluser', - name='all_can_create_adherent', - field=models.BooleanField(default=False, help_text='Users can create a member'), + model_name="optionaluser", + name="all_can_create_adherent", + field=models.BooleanField( + default=False, help_text="Users can create a member" + ), ), migrations.AlterField( - model_name='optionaluser', - name='all_can_create_club', - field=models.BooleanField(default=False, help_text='Users can create a club'), + model_name="optionaluser", + name="all_can_create_club", + field=models.BooleanField( + default=False, help_text="Users can create a club" + ), ), migrations.AlterField( - model_name='optionaluser', - name='max_email_address', - field=models.IntegerField(default=15, help_text='Maximum number of local email addresses for a standard user'), + model_name="optionaluser", + name="max_email_address", + field=models.IntegerField( + default=15, + help_text="Maximum number of local email addresses for a standard user", + ), ), migrations.AlterField( - model_name='optionaluser', - name='self_adhesion', - field=models.BooleanField(default=False, help_text='A new user can create their account on Re2o'), + model_name="optionaluser", + name="self_adhesion", + field=models.BooleanField( + default=False, help_text="A new user can create their account on Re2o" + ), ), migrations.AlterField( - model_name='optionaluser', - name='self_change_shell', - field=models.BooleanField(default=False, help_text='Users can edit their shell'), + model_name="optionaluser", + name="self_change_shell", + field=models.BooleanField( + default=False, help_text="Users can edit their shell" + ), ), ] diff --git a/preferences/migrations/0051_auto_20180919_2225.py b/preferences/migrations/0051_auto_20180919_2225.py index f776a9a6..c570e147 100644 --- a/preferences/migrations/0051_auto_20180919_2225.py +++ b/preferences/migrations/0051_auto_20180919_2225.py @@ -11,92 +11,199 @@ import re2o.mixins class Migration(migrations.Migration): dependencies = [ - ('machines', '0095_auto_20180919_2225'), - ('preferences', '0050_auto_20180818_1329'), + ("machines", "0095_auto_20180919_2225"), + ("preferences", "0050_auto_20180818_1329"), ] operations = [ migrations.CreateModel( - name='RadiusKey', + name="RadiusKey", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('radius_key', re2o.aes_field.AESEncryptedField(help_text='Clef radius', max_length=255)), - ('comment', models.CharField(blank=True, help_text='Commentaire de cette clef', max_length=255, null=True)), - ('default_switch', models.BooleanField(default=True, help_text='Clef par défaut des switchs', unique=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "radius_key", + re2o.aes_field.AESEncryptedField( + help_text="Clef radius", max_length=255 + ), + ), + ( + "comment", + models.CharField( + blank=True, + help_text="Commentaire de cette clef", + max_length=255, + null=True, + ), + ), + ( + "default_switch", + models.BooleanField( + default=True, + help_text="Clef par défaut des switchs", + unique=True, + ), + ), ], options={ - 'permissions': (('view_radiuskey', 'Peut voir un objet radiuskey'),), + "permissions": (("view_radiuskey", "Peut voir un objet radiuskey"),) }, bases=(re2o.mixins.AclMixin, models.Model), ), migrations.CreateModel( - name='Reminder', + name="Reminder", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('days', models.IntegerField(default=7, help_text="Délais entre le mail et la fin d'adhésion", unique=True)), - ('message', models.CharField(blank=True, default='', help_text='Message affiché spécifiquement pour ce rappel', max_length=255, null=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "days", + models.IntegerField( + default=7, + help_text="Délais entre le mail et la fin d'adhésion", + unique=True, + ), + ), + ( + "message", + models.CharField( + blank=True, + default="", + help_text="Message affiché spécifiquement pour ce rappel", + max_length=255, + null=True, + ), + ), ], options={ - 'permissions': (('view_reminder', 'Peut voir un objet reminder'),), + "permissions": (("view_reminder", "Peut voir un objet reminder"),) }, bases=(re2o.mixins.AclMixin, models.Model), ), migrations.CreateModel( - name='SwitchManagementCred', + name="SwitchManagementCred", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('management_id', models.CharField(help_text='Login du switch', max_length=63)), - ('management_pass', re2o.aes_field.AESEncryptedField(help_text='Mot de passe', max_length=63)), - ('default_switch', models.BooleanField(default=True, help_text='Creds par défaut des switchs', unique=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "management_id", + models.CharField(help_text="Login du switch", max_length=63), + ), + ( + "management_pass", + re2o.aes_field.AESEncryptedField( + help_text="Mot de passe", max_length=63 + ), + ), + ( + "default_switch", + models.BooleanField( + default=True, + help_text="Creds par défaut des switchs", + unique=True, + ), + ), ], options={ - 'permissions': (('view_switchmanagementcred', 'Peut voir un objet switchmanagementcred'),), + "permissions": ( + ( + "view_switchmanagementcred", + "Peut voir un objet switchmanagementcred", + ), + ) }, bases=(re2o.mixins.AclMixin, models.Model), ), migrations.AddField( - model_name='optionaltopologie', - name='sftp_login', - field=models.CharField(blank=True, help_text='Login sftp des switchs', max_length=32, null=True), + model_name="optionaltopologie", + name="sftp_login", + field=models.CharField( + blank=True, help_text="Login sftp des switchs", max_length=32, null=True + ), ), migrations.AddField( - model_name='optionaltopologie', - name='sftp_pass', - field=re2o.aes_field.AESEncryptedField(blank=True, help_text='Mot de passe sftp', max_length=63, null=True), + model_name="optionaltopologie", + name="sftp_pass", + field=re2o.aes_field.AESEncryptedField( + blank=True, help_text="Mot de passe sftp", max_length=63, null=True + ), ), migrations.AddField( - model_name='optionaltopologie', - name='switchs_ip_type', - field=models.OneToOneField(blank=True, help_text="Plage d'ip de management des switchs", null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.IpType'), + model_name="optionaltopologie", + name="switchs_ip_type", + field=models.OneToOneField( + blank=True, + help_text="Plage d'ip de management des switchs", + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="machines.IpType", + ), ), migrations.AddField( - model_name='optionaltopologie', - name='switchs_provision', - field=models.CharField(choices=[('sftp', 'sftp'), ('tftp', 'tftp')], default='tftp', help_text='Mode de récupération des confs par les switchs', max_length=32), + model_name="optionaltopologie", + name="switchs_provision", + field=models.CharField( + choices=[("sftp", "sftp"), ("tftp", "tftp")], + default="tftp", + help_text="Mode de récupération des confs par les switchs", + max_length=32, + ), ), migrations.AddField( - model_name='optionaltopologie', - name='switchs_rest_management', - field=models.BooleanField(default=False, help_text='Rest management, activé si provision auto'), + model_name="optionaltopologie", + name="switchs_rest_management", + field=models.BooleanField( + default=False, help_text="Rest management, activé si provision auto" + ), ), migrations.AddField( - model_name='optionaltopologie', - name='switchs_web_management', - field=models.BooleanField(default=False, help_text='Web management, activé si provision automatique'), + model_name="optionaltopologie", + name="switchs_web_management", + field=models.BooleanField( + default=False, + help_text="Web management, activé si provision automatique", + ), ), migrations.AddField( - model_name='optionaltopologie', - name='switchs_web_management_ssl', - field=models.BooleanField(default=False, help_text='Web management ssl. Assurez-vous que un certif est installé sur le switch !'), + model_name="optionaltopologie", + name="switchs_web_management_ssl", + field=models.BooleanField( + default=False, + help_text="Web management ssl. Assurez-vous que un certif est installé sur le switch !", + ), ), migrations.AlterField( - model_name='mailmessageoption', - name='welcome_mail_en', - field=models.TextField(default='', help_text='Mail de bienvenue en anglais'), + model_name="mailmessageoption", + name="welcome_mail_en", + field=models.TextField( + default="", help_text="Mail de bienvenue en anglais" + ), ), migrations.AlterField( - model_name='mailmessageoption', - name='welcome_mail_fr', - field=models.TextField(default='', help_text='Mail de bienvenue en français'), + model_name="mailmessageoption", + name="welcome_mail_fr", + field=models.TextField( + default="", help_text="Mail de bienvenue en français" + ), ), ] diff --git a/preferences/migrations/0052_optionaluser_delete_notyetactive.py b/preferences/migrations/0052_optionaluser_delete_notyetactive.py index 589c6dc7..ec25f8d2 100644 --- a/preferences/migrations/0052_optionaluser_delete_notyetactive.py +++ b/preferences/migrations/0052_optionaluser_delete_notyetactive.py @@ -7,14 +7,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0051_auto_20180919_2225'), - ] + dependencies = [("preferences", "0051_auto_20180919_2225")] operations = [ migrations.AddField( - model_name='optionaluser', - name='delete_notyetactive', - field=models.IntegerField(default=15, help_text='Inactive users will be deleted after this number of days'), - ), + model_name="optionaluser", + name="delete_notyetactive", + field=models.IntegerField( + default=15, + help_text="Inactive users will be deleted after this number of days", + ), + ) ] diff --git a/preferences/migrations/0053_optionaluser_self_change_room.py b/preferences/migrations/0053_optionaluser_self_change_room.py index 07840c5d..43190c21 100644 --- a/preferences/migrations/0053_optionaluser_self_change_room.py +++ b/preferences/migrations/0053_optionaluser_self_change_room.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0052_optionaluser_delete_notyetactive'), - ] + dependencies = [("preferences", "0052_optionaluser_delete_notyetactive")] operations = [ migrations.AddField( - model_name='optionaluser', - name='self_change_room', - field=models.BooleanField(default=False, help_text='Users can edit their room'), - ), + model_name="optionaluser", + name="self_change_room", + field=models.BooleanField( + default=False, help_text="Users can edit their room" + ), + ) ] diff --git a/preferences/migrations/0055_generaloption_main_site_url.py b/preferences/migrations/0055_generaloption_main_site_url.py index 655c0b07..6e4ba49d 100644 --- a/preferences/migrations/0055_generaloption_main_site_url.py +++ b/preferences/migrations/0055_generaloption_main_site_url.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0053_optionaluser_self_change_room'), - ] + dependencies = [("preferences", "0053_optionaluser_self_change_room")] operations = [ migrations.AddField( - model_name='generaloption', - name='main_site_url', - field=models.URLField(default='http://re2o.example.org', max_length=255), - ), + model_name="generaloption", + name="main_site_url", + field=models.URLField(default="http://re2o.example.org", max_length=255), + ) ] diff --git a/preferences/migrations/0056_1_radiusoption.py b/preferences/migrations/0056_1_radiusoption.py index 8a7cb45c..5b0c483f 100644 --- a/preferences/migrations/0056_1_radiusoption.py +++ b/preferences/migrations/0056_1_radiusoption.py @@ -10,75 +10,180 @@ import re2o.mixins class Migration(migrations.Migration): dependencies = [ - ('machines', '0095_auto_20180919_2225'), - ('preferences', '0055_generaloption_main_site_url'), + ("machines", "0095_auto_20180919_2225"), + ("preferences", "0055_generaloption_main_site_url"), ] operations = [ migrations.CreateModel( - name='RadiusOption', + name="RadiusOption", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('radius_general_policy', models.CharField(choices=[('MACHINE', "On the IP range's VLAN of the machine"), ('DEFINED', "Preset in 'VLAN for machines accepted by RADIUS'")], default='DEFINED', max_length=32)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "radius_general_policy", + models.CharField( + choices=[ + ("MACHINE", "On the IP range's VLAN of the machine"), + ( + "DEFINED", + "Preset in 'VLAN for machines accepted by RADIUS'", + ), + ], + default="DEFINED", + max_length=32, + ), + ), ], - options={ - 'verbose_name': 'radius policies', - }, + options={"verbose_name": "radius policies"}, bases=(re2o.mixins.AclMixin, models.Model), ), migrations.AddField( - model_name='radiusoption', - name='banned_vlan', - field=models.ForeignKey(blank=True, help_text='Vlan for banned if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='banned_vlan', to='machines.Vlan', verbose_name='Banned Vlan'), + model_name="radiusoption", + name="banned_vlan", + field=models.ForeignKey( + blank=True, + help_text="Vlan for banned if not rejected.", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="banned_vlan", + to="machines.Vlan", + verbose_name="Banned Vlan", + ), ), migrations.AddField( - model_name='radiusoption', - name='non_member_vlan', - field=models.ForeignKey(blank=True, help_text='Vlan for non members if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='non_member_vlan', to='machines.Vlan', verbose_name='Non member Vlan'), + model_name="radiusoption", + name="non_member_vlan", + field=models.ForeignKey( + blank=True, + help_text="Vlan for non members if not rejected.", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="non_member_vlan", + to="machines.Vlan", + verbose_name="Non member Vlan", + ), ), migrations.AddField( - model_name='radiusoption', - name='unknown_machine_vlan', - field=models.ForeignKey(blank=True, help_text='Vlan for unknown machines if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_machine_vlan', to='machines.Vlan', verbose_name='Unknown machine Vlan'), + model_name="radiusoption", + name="unknown_machine_vlan", + field=models.ForeignKey( + blank=True, + help_text="Vlan for unknown machines if not rejected.", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="unknown_machine_vlan", + to="machines.Vlan", + verbose_name="Unknown machine Vlan", + ), ), migrations.AddField( - model_name='radiusoption', - name='unknown_port_vlan', - field=models.ForeignKey(blank=True, help_text='Vlan for unknown ports if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_port_vlan', to='machines.Vlan', verbose_name='Unknown port Vlan'), + model_name="radiusoption", + name="unknown_port_vlan", + field=models.ForeignKey( + blank=True, + help_text="Vlan for unknown ports if not rejected.", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="unknown_port_vlan", + to="machines.Vlan", + verbose_name="Unknown port Vlan", + ), ), migrations.AddField( - model_name='radiusoption', - name='unknown_room_vlan', - field=models.ForeignKey(blank=True, help_text='Vlan for unknown room if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_room_vlan', to='machines.Vlan', verbose_name='Unknown room Vlan'), + model_name="radiusoption", + name="unknown_room_vlan", + field=models.ForeignKey( + blank=True, + help_text="Vlan for unknown room if not rejected.", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="unknown_room_vlan", + to="machines.Vlan", + verbose_name="Unknown room Vlan", + ), ), migrations.AddField( - model_name='radiusoption', - name='banned', - field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for banned users.'), + model_name="radiusoption", + name="banned", + field=models.CharField( + choices=[ + ("REJECT", "Reject the machine"), + ("SET_VLAN", "Place the machine on the VLAN"), + ], + default="REJECT", + max_length=32, + verbose_name="Policy for banned users.", + ), ), migrations.AddField( - model_name='radiusoption', - name='non_member', - field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy non member users.'), + model_name="radiusoption", + name="non_member", + field=models.CharField( + choices=[ + ("REJECT", "Reject the machine"), + ("SET_VLAN", "Place the machine on the VLAN"), + ], + default="REJECT", + max_length=32, + verbose_name="Policy non member users.", + ), ), migrations.AddField( - model_name='radiusoption', - name='unknown_machine', - field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for unknown machines'), + model_name="radiusoption", + name="unknown_machine", + field=models.CharField( + choices=[ + ("REJECT", "Reject the machine"), + ("SET_VLAN", "Place the machine on the VLAN"), + ], + default="REJECT", + max_length=32, + verbose_name="Policy for unknown machines", + ), ), migrations.AddField( - model_name='radiusoption', - name='unknown_port', - field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for unknown machines'), + model_name="radiusoption", + name="unknown_port", + field=models.CharField( + choices=[ + ("REJECT", "Reject the machine"), + ("SET_VLAN", "Place the machine on the VLAN"), + ], + default="REJECT", + max_length=32, + verbose_name="Policy for unknown machines", + ), ), migrations.AddField( - model_name='radiusoption', - name='unknown_room', - field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for machine connecting from unregistered room (relevant on ports with STRICT radius mode)'), + model_name="radiusoption", + name="unknown_room", + field=models.CharField( + choices=[ + ("REJECT", "Reject the machine"), + ("SET_VLAN", "Place the machine on the VLAN"), + ], + default="REJECT", + max_length=32, + verbose_name="Policy for machine connecting from unregistered room (relevant on ports with STRICT radius mode)", + ), ), migrations.AddField( - model_name='radiusoption', - name='vlan_decision_ok', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vlan_ok_option', to='machines.Vlan'), + model_name="radiusoption", + name="vlan_decision_ok", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="vlan_ok_option", + to="machines.Vlan", + ), ), ] diff --git a/preferences/migrations/0056_2_radiusoption.py b/preferences/migrations/0056_2_radiusoption.py index 1a8ecccd..b753b7a3 100644 --- a/preferences/migrations/0056_2_radiusoption.py +++ b/preferences/migrations/0056_2_radiusoption.py @@ -8,10 +8,10 @@ import re2o.mixins def create_radius_policy(apps, schema_editor): - OptionalTopologie = apps.get_model('preferences', 'OptionalTopologie') - RadiusOption = apps.get_model('preferences', 'RadiusOption') + OptionalTopologie = apps.get_model("preferences", "OptionalTopologie") + RadiusOption = apps.get_model("preferences", "RadiusOption") - option,_ = OptionalTopologie.objects.get_or_create() + option, _ = OptionalTopologie.objects.get_or_create() radius_option = RadiusOption() radius_option.radius_general_policy = option.radius_general_policy @@ -19,6 +19,7 @@ def create_radius_policy(apps, schema_editor): radius_option.save() + def revert_radius(apps, schema_editor): pass @@ -26,11 +27,9 @@ def revert_radius(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('machines', '0095_auto_20180919_2225'), - ('preferences', '0055_generaloption_main_site_url'), - ('preferences', '0056_1_radiusoption'), + ("machines", "0095_auto_20180919_2225"), + ("preferences", "0055_generaloption_main_site_url"), + ("preferences", "0056_1_radiusoption"), ] - operations = [ - migrations.RunPython(create_radius_policy, revert_radius), - ] + operations = [migrations.RunPython(create_radius_policy, revert_radius)] diff --git a/preferences/migrations/0056_3_radiusoption.py b/preferences/migrations/0056_3_radiusoption.py index f3e5f98c..ec99efd9 100644 --- a/preferences/migrations/0056_3_radiusoption.py +++ b/preferences/migrations/0056_3_radiusoption.py @@ -10,22 +10,17 @@ import re2o.mixins class Migration(migrations.Migration): dependencies = [ - ('machines', '0095_auto_20180919_2225'), - ('preferences', '0055_generaloption_main_site_url'), - ('preferences', '0056_2_radiusoption'), + ("machines", "0095_auto_20180919_2225"), + ("preferences", "0055_generaloption_main_site_url"), + ("preferences", "0056_2_radiusoption"), ] operations = [ migrations.RemoveField( - model_name='optionaltopologie', - name='radius_general_policy', + model_name="optionaltopologie", name="radius_general_policy" ), migrations.RemoveField( - model_name='optionaltopologie', - name='vlan_decision_nok', - ), - migrations.RemoveField( - model_name='optionaltopologie', - name='vlan_decision_ok', + model_name="optionaltopologie", name="vlan_decision_nok" ), + migrations.RemoveField(model_name="optionaltopologie", name="vlan_decision_ok"), ] diff --git a/preferences/migrations/0056_4_radiusoption.py b/preferences/migrations/0056_4_radiusoption.py index 8d93fff9..57a08802 100644 --- a/preferences/migrations/0056_4_radiusoption.py +++ b/preferences/migrations/0056_4_radiusoption.py @@ -7,14 +7,20 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0056_3_radiusoption'), - ] + dependencies = [("preferences", "0056_3_radiusoption")] operations = [ migrations.AlterField( - model_name='radiusoption', - name='unknown_port', - field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for unknown port'), - ), + model_name="radiusoption", + name="unknown_port", + field=models.CharField( + choices=[ + ("REJECT", "Reject the machine"), + ("SET_VLAN", "Place the machine on the VLAN"), + ], + default="REJECT", + max_length=32, + verbose_name="Policy for unknown port", + ), + ) ] diff --git a/preferences/migrations/0057_optionaluser_all_users_active.py b/preferences/migrations/0057_optionaluser_all_users_active.py index 3f0cc8c1..9a236f2b 100644 --- a/preferences/migrations/0057_optionaluser_all_users_active.py +++ b/preferences/migrations/0057_optionaluser_all_users_active.py @@ -7,14 +7,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0056_4_radiusoption'), - ] + dependencies = [("preferences", "0056_4_radiusoption")] operations = [ migrations.AddField( - model_name='optionaluser', - name='all_users_active', - field=models.BooleanField(default=False, help_text='If True, all new created and connected users are active. If False, only when a valid registration has been paid'), - ), + model_name="optionaluser", + name="all_users_active", + field=models.BooleanField( + default=False, + help_text="If True, all new created and connected users are active. If False, only when a valid registration has been paid", + ), + ) ] diff --git a/preferences/migrations/0058_auto_20190108_1650.py b/preferences/migrations/0058_auto_20190108_1650.py index e90b6067..fe8e8fd1 100644 --- a/preferences/migrations/0058_auto_20190108_1650.py +++ b/preferences/migrations/0058_auto_20190108_1650.py @@ -9,200 +9,355 @@ import re2o.aes_field class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0057_optionaluser_all_users_active'), - ] + dependencies = [("preferences", "0057_optionaluser_all_users_active")] operations = [ migrations.AlterModelOptions( - name='radiuskey', - options={'permissions': (('view_radiuskey', 'Can view a RADIUS key object'),), 'verbose_name': 'RADIUS key', 'verbose_name_plural': 'RADIUS keys'}, + name="radiuskey", + options={ + "permissions": (("view_radiuskey", "Can view a RADIUS key object"),), + "verbose_name": "RADIUS key", + "verbose_name_plural": "RADIUS keys", + }, ), migrations.AlterModelOptions( - name='radiusoption', - options={'verbose_name': 'RADIUS policy', 'verbose_name_plural': 'RADIUS policies'}, + name="radiusoption", + options={ + "verbose_name": "RADIUS policy", + "verbose_name_plural": "RADIUS policies", + }, ), migrations.AlterModelOptions( - name='reminder', - options={'permissions': (('view_reminder', 'Can view a reminder object'),), 'verbose_name': 'reminder', 'verbose_name_plural': 'reminders'}, + name="reminder", + options={ + "permissions": (("view_reminder", "Can view a reminder object"),), + "verbose_name": "reminder", + "verbose_name_plural": "reminders", + }, ), migrations.AlterModelOptions( - name='switchmanagementcred', - options={'permissions': (('view_switchmanagementcred', 'Can view a switch management credentials object'),), 'verbose_name': 'switch management credentials'}, + name="switchmanagementcred", + options={ + "permissions": ( + ( + "view_switchmanagementcred", + "Can view a switch management credentials object", + ), + ), + "verbose_name": "switch management credentials", + }, ), migrations.AlterField( - model_name='mailmessageoption', - name='welcome_mail_en', - field=models.TextField(default='', help_text='Welcome email in English'), + model_name="mailmessageoption", + name="welcome_mail_en", + field=models.TextField(default="", help_text="Welcome email in English"), ), migrations.AlterField( - model_name='mailmessageoption', - name='welcome_mail_fr', - field=models.TextField(default='', help_text='Welcome email in French'), + model_name="mailmessageoption", + name="welcome_mail_fr", + field=models.TextField(default="", help_text="Welcome email in French"), ), migrations.AlterField( - model_name='optionaltopologie', - name='sftp_login', - field=models.CharField(blank=True, help_text='SFTP login for switches', max_length=32, null=True), + model_name="optionaltopologie", + name="sftp_login", + field=models.CharField( + blank=True, + help_text="SFTP login for switches", + max_length=32, + null=True, + ), ), migrations.AlterField( - model_name='optionaltopologie', - name='sftp_pass', - field=re2o.aes_field.AESEncryptedField(blank=True, help_text='SFTP password', max_length=63, null=True), + model_name="optionaltopologie", + name="sftp_pass", + field=re2o.aes_field.AESEncryptedField( + blank=True, help_text="SFTP password", max_length=63, null=True + ), ), migrations.AlterField( - model_name='optionaltopologie', - name='switchs_ip_type', - field=models.OneToOneField(blank=True, help_text='IP range for the management of switches', null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.IpType'), + model_name="optionaltopologie", + name="switchs_ip_type", + field=models.OneToOneField( + blank=True, + help_text="IP range for the management of switches", + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="machines.IpType", + ), ), migrations.AlterField( - model_name='optionaltopologie', - name='switchs_provision', - field=models.CharField(choices=[('sftp', 'sftp'), ('tftp', 'tftp')], default='tftp', help_text='Provision of configuration mode for switches', max_length=32), + model_name="optionaltopologie", + name="switchs_provision", + field=models.CharField( + choices=[("sftp", "sftp"), ("tftp", "tftp")], + default="tftp", + help_text="Provision of configuration mode for switches", + max_length=32, + ), ), migrations.AlterField( - model_name='optionaltopologie', - name='switchs_rest_management', - field=models.BooleanField(default=False, help_text='REST management, activated in case of automatic provision'), + model_name="optionaltopologie", + name="switchs_rest_management", + field=models.BooleanField( + default=False, + help_text="REST management, activated in case of automatic provision", + ), ), migrations.AlterField( - model_name='optionaltopologie', - name='switchs_web_management', - field=models.BooleanField(default=False, help_text='Web management, activated in case of automatic provision'), + model_name="optionaltopologie", + name="switchs_web_management", + field=models.BooleanField( + default=False, + help_text="Web management, activated in case of automatic provision", + ), ), migrations.AlterField( - model_name='optionaltopologie', - name='switchs_web_management_ssl', - field=models.BooleanField(default=False, help_text='SSL web management, make sure that a certificate is installed on the switch'), + model_name="optionaltopologie", + name="switchs_web_management_ssl", + field=models.BooleanField( + default=False, + help_text="SSL web management, make sure that a certificate is installed on the switch", + ), ), migrations.AlterField( - model_name='optionaluser', - name='all_can_create_adherent', - field=models.BooleanField(default=False, help_text='Users can create a member.'), + model_name="optionaluser", + name="all_can_create_adherent", + field=models.BooleanField( + default=False, help_text="Users can create a member." + ), ), migrations.AlterField( - model_name='optionaluser', - name='all_can_create_club', - field=models.BooleanField(default=False, help_text='Users can create a club.'), + model_name="optionaluser", + name="all_can_create_club", + field=models.BooleanField( + default=False, help_text="Users can create a club." + ), ), migrations.AlterField( - model_name='optionaluser', - name='all_users_active', - field=models.BooleanField(default=False, help_text='If True, all new created and connected users are active. If False, only when a valid registration has been paid.'), + model_name="optionaluser", + name="all_users_active", + field=models.BooleanField( + default=False, + help_text="If True, all new created and connected users are active. If False, only when a valid registration has been paid.", + ), ), migrations.AlterField( - model_name='optionaluser', - name='delete_notyetactive', - field=models.IntegerField(default=15, help_text='Not yet active users will be deleted after this number of days.'), + model_name="optionaluser", + name="delete_notyetactive", + field=models.IntegerField( + default=15, + help_text="Not yet active users will be deleted after this number of days.", + ), ), migrations.AlterField( - model_name='optionaluser', - name='local_email_accounts_enabled', - field=models.BooleanField(default=False, help_text='Enable local email accounts for users.'), + model_name="optionaluser", + name="local_email_accounts_enabled", + field=models.BooleanField( + default=False, help_text="Enable local email accounts for users." + ), ), migrations.AlterField( - model_name='optionaluser', - name='max_email_address', - field=models.IntegerField(default=15, help_text='Maximum number of local email addresses for a standard user.'), + model_name="optionaluser", + name="max_email_address", + field=models.IntegerField( + default=15, + help_text="Maximum number of local email addresses for a standard user.", + ), ), migrations.AlterField( - model_name='optionaluser', - name='self_adhesion', - field=models.BooleanField(default=False, help_text='A new user can create their account on Re2o.'), + model_name="optionaluser", + name="self_adhesion", + field=models.BooleanField( + default=False, help_text="A new user can create their account on Re2o." + ), ), migrations.AlterField( - model_name='optionaluser', - name='self_change_room', - field=models.BooleanField(default=False, help_text='Users can edit their room.'), + model_name="optionaluser", + name="self_change_room", + field=models.BooleanField( + default=False, help_text="Users can edit their room." + ), ), migrations.AlterField( - model_name='optionaluser', - name='self_change_shell', - field=models.BooleanField(default=False, help_text='Users can edit their shell.'), + model_name="optionaluser", + name="self_change_shell", + field=models.BooleanField( + default=False, help_text="Users can edit their shell." + ), ), migrations.AlterField( - model_name='radiuskey', - name='comment', - field=models.CharField(blank=True, help_text='Comment for this key', max_length=255, null=True), + model_name="radiuskey", + name="comment", + field=models.CharField( + blank=True, help_text="Comment for this key", max_length=255, null=True + ), ), migrations.AlterField( - model_name='radiuskey', - name='default_switch', - field=models.BooleanField(default=True, help_text='Default key for switches', unique=True), + model_name="radiuskey", + name="default_switch", + field=models.BooleanField( + default=True, help_text="Default key for switches", unique=True + ), ), migrations.AlterField( - model_name='radiuskey', - name='radius_key', - field=re2o.aes_field.AESEncryptedField(help_text='RADIUS key', max_length=255), + model_name="radiuskey", + name="radius_key", + field=re2o.aes_field.AESEncryptedField( + help_text="RADIUS key", max_length=255 + ), ), migrations.AlterField( - model_name='radiusoption', - name='banned', - field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for banned users'), + model_name="radiusoption", + name="banned", + field=models.CharField( + choices=[ + ("REJECT", "Reject the machine"), + ("SET_VLAN", "Place the machine on the VLAN"), + ], + default="REJECT", + max_length=32, + verbose_name="Policy for banned users", + ), ), migrations.AlterField( - model_name='radiusoption', - name='banned_vlan', - field=models.ForeignKey(blank=True, help_text='VLAN for banned users if not rejected', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='banned_vlan', to='machines.Vlan', verbose_name='Banned users VLAN'), + model_name="radiusoption", + name="banned_vlan", + field=models.ForeignKey( + blank=True, + help_text="VLAN for banned users if not rejected", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="banned_vlan", + to="machines.Vlan", + verbose_name="Banned users VLAN", + ), ), migrations.AlterField( - model_name='radiusoption', - name='non_member', - field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for non members'), + model_name="radiusoption", + name="non_member", + field=models.CharField( + choices=[ + ("REJECT", "Reject the machine"), + ("SET_VLAN", "Place the machine on the VLAN"), + ], + default="REJECT", + max_length=32, + verbose_name="Policy for non members", + ), ), migrations.AlterField( - model_name='radiusoption', - name='non_member_vlan', - field=models.ForeignKey(blank=True, help_text='VLAN for non members if not rejected', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='non_member_vlan', to='machines.Vlan', verbose_name='Non members VLAN'), + model_name="radiusoption", + name="non_member_vlan", + field=models.ForeignKey( + blank=True, + help_text="VLAN for non members if not rejected", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="non_member_vlan", + to="machines.Vlan", + verbose_name="Non members VLAN", + ), ), migrations.AlterField( - model_name='radiusoption', - name='unknown_machine_vlan', - field=models.ForeignKey(blank=True, help_text='VLAN for unknown machines if not rejected', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_machine_vlan', to='machines.Vlan', verbose_name='Unknown machines VLAN'), + model_name="radiusoption", + name="unknown_machine_vlan", + field=models.ForeignKey( + blank=True, + help_text="VLAN for unknown machines if not rejected", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="unknown_machine_vlan", + to="machines.Vlan", + verbose_name="Unknown machines VLAN", + ), ), migrations.AlterField( - model_name='radiusoption', - name='unknown_port', - field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for unknown ports'), + model_name="radiusoption", + name="unknown_port", + field=models.CharField( + choices=[ + ("REJECT", "Reject the machine"), + ("SET_VLAN", "Place the machine on the VLAN"), + ], + default="REJECT", + max_length=32, + verbose_name="Policy for unknown ports", + ), ), migrations.AlterField( - model_name='radiusoption', - name='unknown_port_vlan', - field=models.ForeignKey(blank=True, help_text='VLAN for unknown ports if not rejected', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_port_vlan', to='machines.Vlan', verbose_name='Unknown ports VLAN'), + model_name="radiusoption", + name="unknown_port_vlan", + field=models.ForeignKey( + blank=True, + help_text="VLAN for unknown ports if not rejected", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="unknown_port_vlan", + to="machines.Vlan", + verbose_name="Unknown ports VLAN", + ), ), migrations.AlterField( - model_name='radiusoption', - name='unknown_room', - field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for machines connecting from unregistered rooms (relevant on ports with STRICT RADIUS mode)'), + model_name="radiusoption", + name="unknown_room", + field=models.CharField( + choices=[ + ("REJECT", "Reject the machine"), + ("SET_VLAN", "Place the machine on the VLAN"), + ], + default="REJECT", + max_length=32, + verbose_name="Policy for machines connecting from unregistered rooms (relevant on ports with STRICT RADIUS mode)", + ), ), migrations.AlterField( - model_name='radiusoption', - name='unknown_room_vlan', - field=models.ForeignKey(blank=True, help_text='VLAN for unknown rooms if not rejected', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_room_vlan', to='machines.Vlan', verbose_name='Unknown rooms VLAN'), + model_name="radiusoption", + name="unknown_room_vlan", + field=models.ForeignKey( + blank=True, + help_text="VLAN for unknown rooms if not rejected", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="unknown_room_vlan", + to="machines.Vlan", + verbose_name="Unknown rooms VLAN", + ), ), migrations.AlterField( - model_name='reminder', - name='days', - field=models.IntegerField(default=7, help_text="Delay between the email and the membership's end", unique=True), + model_name="reminder", + name="days", + field=models.IntegerField( + default=7, + help_text="Delay between the email and the membership's end", + unique=True, + ), ), migrations.AlterField( - model_name='reminder', - name='message', - field=models.CharField(blank=True, default='', help_text='Message displayed specifically for this reminder', max_length=255, null=True), + model_name="reminder", + name="message", + field=models.CharField( + blank=True, + default="", + help_text="Message displayed specifically for this reminder", + max_length=255, + null=True, + ), ), migrations.AlterField( - model_name='switchmanagementcred', - name='default_switch', - field=models.BooleanField(default=True, help_text='Default credentials for switches', unique=True), + model_name="switchmanagementcred", + name="default_switch", + field=models.BooleanField( + default=True, help_text="Default credentials for switches", unique=True + ), ), migrations.AlterField( - model_name='switchmanagementcred', - name='management_id', - field=models.CharField(help_text='Switch login', max_length=63), + model_name="switchmanagementcred", + name="management_id", + field=models.CharField(help_text="Switch login", max_length=63), ), migrations.AlterField( - model_name='switchmanagementcred', - name='management_pass', - field=re2o.aes_field.AESEncryptedField(help_text='Password', max_length=63), + model_name="switchmanagementcred", + name="management_pass", + field=re2o.aes_field.AESEncryptedField(help_text="Password", max_length=63), ), ] diff --git a/preferences/migrations/0059_auto_20190120_1739.py b/preferences/migrations/0059_auto_20190120_1739.py index 23447ce8..44e0d506 100644 --- a/preferences/migrations/0059_auto_20190120_1739.py +++ b/preferences/migrations/0059_auto_20190120_1739.py @@ -9,54 +9,96 @@ import re2o.mixins def create_defaults(apps, schema_editor): - CotisationsOption = apps.get_model('preferences', 'CotisationsOption') + CotisationsOption = apps.get_model("preferences", "CotisationsOption") CotisationsOption.objects.get_or_create() + class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0058_auto_20190108_1650'), - ] + dependencies = [("preferences", "0058_auto_20190108_1650")] operations = [ migrations.CreateModel( - name='CotisationsOption', + name="CotisationsOption", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('send_voucher_mail', models.BooleanField(default=False, verbose_name='Send voucher by email when the invoice is controlled.')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "send_voucher_mail", + models.BooleanField( + default=False, + verbose_name="Send voucher by email when the invoice is controlled.", + ), + ), ], - options={ - 'verbose_name': 'cotisations options', - }, + options={"verbose_name": "cotisations options"}, bases=(re2o.mixins.AclMixin, models.Model), ), migrations.CreateModel( - name='DocumentTemplate', + name="DocumentTemplate", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('template', models.FileField(upload_to='templates/', verbose_name='template')), - ('name', models.CharField(max_length=125, unique=True, verbose_name='name')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "template", + models.FileField(upload_to="templates/", verbose_name="template"), + ), + ( + "name", + models.CharField(max_length=125, unique=True, verbose_name="name"), + ), ], options={ - 'verbose_name': 'document template', - 'verbose_name_plural': 'document templates', + "verbose_name": "document template", + "verbose_name_plural": "document templates", }, bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), ), migrations.AddField( - model_name='assooption', - name='pres_name', - field=models.CharField(default='', help_text='Displayed on subscription vouchers', max_length=255, verbose_name='President of the association'), + model_name="assooption", + name="pres_name", + field=models.CharField( + default="", + help_text="Displayed on subscription vouchers", + max_length=255, + verbose_name="President of the association", + ), ), migrations.AddField( - model_name='cotisationsoption', - name='invoice_template', - field=models.OneToOneField(default=preferences.models.default_invoice, on_delete=django.db.models.deletion.PROTECT, related_name='invoice_template', to='preferences.DocumentTemplate', verbose_name='Template for invoices'), + model_name="cotisationsoption", + name="invoice_template", + field=models.OneToOneField( + default=preferences.models.default_invoice, + on_delete=django.db.models.deletion.PROTECT, + related_name="invoice_template", + to="preferences.DocumentTemplate", + verbose_name="Template for invoices", + ), ), migrations.AddField( - model_name='cotisationsoption', - name='voucher_template', - field=models.OneToOneField(default=preferences.models.default_voucher, on_delete=django.db.models.deletion.PROTECT, related_name='voucher_template', to='preferences.DocumentTemplate', verbose_name='Template for subscription voucher'), + model_name="cotisationsoption", + name="voucher_template", + field=models.OneToOneField( + default=preferences.models.default_voucher, + on_delete=django.db.models.deletion.PROTECT, + related_name="voucher_template", + to="preferences.DocumentTemplate", + verbose_name="Template for subscription voucher", + ), ), migrations.RunPython(create_defaults), ] diff --git a/preferences/migrations/0060_auto_20190712_1821.py b/preferences/migrations/0060_auto_20190712_1821.py index e1eb76e8..185a2d3f 100644 --- a/preferences/migrations/0060_auto_20190712_1821.py +++ b/preferences/migrations/0060_auto_20190712_1821.py @@ -7,14 +7,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0059_auto_20190120_1739'), - ] + dependencies = [("preferences", "0059_auto_20190120_1739")] operations = [ migrations.AlterField( - model_name='reminder', - name='message', - field=models.TextField(blank=True, default='', help_text='Message displayed specifically for this reminder', null=True), - ), + model_name="reminder", + name="message", + field=models.TextField( + blank=True, + default="", + help_text="Message displayed specifically for this reminder", + null=True, + ), + ) ] diff --git a/preferences/migrations/0061_optionaluser_allow_archived_connexion.py b/preferences/migrations/0061_optionaluser_allow_archived_connexion.py index 505f940b..a3b2898b 100644 --- a/preferences/migrations/0061_optionaluser_allow_archived_connexion.py +++ b/preferences/migrations/0061_optionaluser_allow_archived_connexion.py @@ -7,14 +7,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0060_auto_20190712_1821'), - ] + dependencies = [("preferences", "0060_auto_20190712_1821")] operations = [ migrations.AddField( - model_name='optionaluser', - name='allow_archived_connexion', - field=models.BooleanField(default=False, help_text='If True, archived users are allowed to connect.'), - ), + model_name="optionaluser", + name="allow_archived_connexion", + field=models.BooleanField( + default=False, + help_text="If True, archived users are allowed to connect.", + ), + ) ] diff --git a/preferences/migrations/0062_auto_20190910_1909.py b/preferences/migrations/0062_auto_20190910_1909.py index d121ba7c..f7168b34 100644 --- a/preferences/migrations/0062_auto_20190910_1909.py +++ b/preferences/migrations/0062_auto_20190910_1909.py @@ -8,53 +8,110 @@ import re2o.mixins class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0061_optionaluser_allow_archived_connexion'), - ] + dependencies = [("preferences", "0061_optionaluser_allow_archived_connexion")] operations = [ migrations.CreateModel( - name='RadiusAttribute', + name="RadiusAttribute", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('attribute', models.CharField(help_text='See http://freeradius.org/rfc/attributes.html', max_length=255, verbose_name='Attribute')), - ('value', models.CharField(max_length=255, verbose_name='Value')), - ('comment', models.TextField(blank=True, default='', help_text='Use this field to document this attribute.', verbose_name='Comment')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "attribute", + models.CharField( + help_text="See http://freeradius.org/rfc/attributes.html", + max_length=255, + verbose_name="Attribute", + ), + ), + ("value", models.CharField(max_length=255, verbose_name="Value")), + ( + "comment", + models.TextField( + blank=True, + default="", + help_text="Use this field to document this attribute.", + verbose_name="Comment", + ), + ), ], options={ - 'verbose_name': 'RADIUS attribute', - 'verbose_name_plural': 'RADIUS attributes', + "verbose_name": "RADIUS attribute", + "verbose_name_plural": "RADIUS attributes", }, bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), ), migrations.AddField( - model_name='radiusoption', - name='banned_attributes', - field=models.ManyToManyField(blank=True, help_text='Answer attributes for banned users.', related_name='banned_attribute', to='preferences.RadiusAttribute', verbose_name='Banned attributes.'), + model_name="radiusoption", + name="banned_attributes", + field=models.ManyToManyField( + blank=True, + help_text="Answer attributes for banned users.", + related_name="banned_attribute", + to="preferences.RadiusAttribute", + verbose_name="Banned attributes.", + ), ), migrations.AddField( - model_name='radiusoption', - name='non_member_attributes', - field=models.ManyToManyField(blank=True, help_text='Answer attributes for non members.', related_name='non_member_attribute', to='preferences.RadiusAttribute', verbose_name='Non member attributes.'), + model_name="radiusoption", + name="non_member_attributes", + field=models.ManyToManyField( + blank=True, + help_text="Answer attributes for non members.", + related_name="non_member_attribute", + to="preferences.RadiusAttribute", + verbose_name="Non member attributes.", + ), ), migrations.AddField( - model_name='radiusoption', - name='ok_attributes', - field=models.ManyToManyField(blank=True, help_text='Answer attributes for accepted users.', related_name='ok_attribute', to='preferences.RadiusAttribute', verbose_name='Accepted users attributes.'), + model_name="radiusoption", + name="ok_attributes", + field=models.ManyToManyField( + blank=True, + help_text="Answer attributes for accepted users.", + related_name="ok_attribute", + to="preferences.RadiusAttribute", + verbose_name="Accepted users attributes.", + ), ), migrations.AddField( - model_name='radiusoption', - name='unknown_machine_attributes', - field=models.ManyToManyField(blank=True, help_text='Answer attributes for unknown machines.', related_name='unknown_machine_attribute', to='preferences.RadiusAttribute', verbose_name='Unknown machines attributes.'), + model_name="radiusoption", + name="unknown_machine_attributes", + field=models.ManyToManyField( + blank=True, + help_text="Answer attributes for unknown machines.", + related_name="unknown_machine_attribute", + to="preferences.RadiusAttribute", + verbose_name="Unknown machines attributes.", + ), ), migrations.AddField( - model_name='radiusoption', - name='unknown_port_attributes', - field=models.ManyToManyField(blank=True, help_text='Answer attributes for unknown ports.', related_name='unknown_port_attribute', to='preferences.RadiusAttribute', verbose_name='Unknown ports attributes.'), + model_name="radiusoption", + name="unknown_port_attributes", + field=models.ManyToManyField( + blank=True, + help_text="Answer attributes for unknown ports.", + related_name="unknown_port_attribute", + to="preferences.RadiusAttribute", + verbose_name="Unknown ports attributes.", + ), ), migrations.AddField( - model_name='radiusoption', - name='unknown_room_attributes', - field=models.ManyToManyField(blank=True, help_text='Answer attributes for unknown rooms.', related_name='unknown_room_attribute', to='preferences.RadiusAttribute', verbose_name='Unknown rooms attributes.'), + model_name="radiusoption", + name="unknown_room_attributes", + field=models.ManyToManyField( + blank=True, + help_text="Answer attributes for unknown rooms.", + related_name="unknown_room_attribute", + to="preferences.RadiusAttribute", + verbose_name="Unknown rooms attributes.", + ), ), ] diff --git a/preferences/migrations/0063_mandate.py b/preferences/migrations/0063_mandate.py index 16e52b29..2c242938 100644 --- a/preferences/migrations/0063_mandate.py +++ b/preferences/migrations/0063_mandate.py @@ -10,59 +10,84 @@ import re2o.mixins def create_current_mandate(apps, schema_editor): - AssoOption = apps.get_model('preferences', 'AssoOption') - Mandate = apps.get_model('preferences', 'Mandate') - Adherent = apps.get_model('users', 'Adherent') + AssoOption = apps.get_model("preferences", "AssoOption") + Mandate = apps.get_model("preferences", "Mandate") + Adherent = apps.get_model("users", "Adherent") assooption = AssoOption.objects.get_or_create()[0] pres_name = assooption.pres_name - l = pres_name.split(' ') + l = pres_name.split(" ") try: name, surname = l[0], l[1] - president = Adherent.objects.get(name__icontains=name, surname__icontains=surname) - Mandate.objects.create( - president=president, - start_date=timezone.now(), + president = Adherent.objects.get( + name__icontains=name, surname__icontains=surname ) + Mandate.objects.create(president=president, start_date=timezone.now()) except Exception as e: - print("Warning : I was unable to find an adherent corresponding to %s. You might want to edit your preferences afterward. I will disable the sending of vouchers by email." % pres_name) - CotisationsOption = apps.get_model('preferences', 'CotisationsOption') + print( + "Warning : I was unable to find an adherent corresponding to %s. You might want to edit your preferences afterward. I will disable the sending of vouchers by email." + % pres_name + ) + CotisationsOption = apps.get_model("preferences", "CotisationsOption") cotisoption = CotisationsOption.objects.get_or_create()[0] cotisoption.send_voucher_mail = False cotisoption.save() - class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('preferences', '0062_auto_20190910_1909'), + ("preferences", "0062_auto_20190910_1909"), ] operations = [ migrations.CreateModel( - name='Mandate', + name="Mandate", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('start_date', models.DateTimeField(verbose_name='start date')), - ('end_date', models.DateTimeField(blank=True, null=True, verbose_name='end date')), - ('president', models.ForeignKey(blank=True, help_text='Displayed on subscription vouchers', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='President of the association')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("start_date", models.DateTimeField(verbose_name="start date")), + ( + "end_date", + models.DateTimeField( + blank=True, null=True, verbose_name="end date" + ), + ), + ( + "president", + models.ForeignKey( + blank=True, + help_text="Displayed on subscription vouchers", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + verbose_name="President of the association", + ), + ), ], options={ - 'verbose_name': 'Mandate', - 'verbose_name_plural': 'Mandates', - 'permissions': (('view_mandate', 'Can view a mandate'),), + "verbose_name": "Mandate", + "verbose_name_plural": "Mandates", + "permissions": (("view_mandate", "Can view a mandate"),), }, bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), ), migrations.RunPython(create_current_mandate), migrations.AlterField( - model_name='cotisationsoption', - name='send_voucher_mail', - field=models.BooleanField(default=False, help_text='Be carefull, if no mandate is defined on the preferences page, errors will be triggered when generating vouchers.', verbose_name='Send voucher by email when the invoice is controlled.'), - ), - migrations.RemoveField( - model_name='assooption', - name='pres_name', + model_name="cotisationsoption", + name="send_voucher_mail", + field=models.BooleanField( + default=False, + help_text="Be carefull, if no mandate is defined on the preferences page, errors will be triggered when generating vouchers.", + verbose_name="Send voucher by email when the invoice is controlled.", + ), ), + migrations.RemoveField(model_name="assooption", name="pres_name"), ] diff --git a/preferences/migrations/0064_auto_20191008_1335.py b/preferences/migrations/0064_auto_20191008_1335.py index a1bdb9fc..1055de4b 100644 --- a/preferences/migrations/0064_auto_20191008_1335.py +++ b/preferences/migrations/0064_auto_20191008_1335.py @@ -7,19 +7,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0063_mandate'), - ] + dependencies = [("preferences", "0063_mandate")] operations = [ migrations.AlterField( - model_name='mailmessageoption', - name='welcome_mail_en', - field=models.TextField(blank=True, default='', help_text='Welcome email in English'), + model_name="mailmessageoption", + name="welcome_mail_en", + field=models.TextField( + blank=True, default="", help_text="Welcome email in English" + ), ), migrations.AlterField( - model_name='mailmessageoption', - name='welcome_mail_fr', - field=models.TextField(blank=True, default='', help_text='Welcome email in French'), + model_name="mailmessageoption", + name="welcome_mail_fr", + field=models.TextField( + blank=True, default="", help_text="Welcome email in French" + ), ), ] diff --git a/preferences/migrations/0065_auto_20191010_1227.py b/preferences/migrations/0065_auto_20191010_1227.py index 175dfd5b..2420beea 100644 --- a/preferences/migrations/0065_auto_20191010_1227.py +++ b/preferences/migrations/0065_auto_20191010_1227.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0064_auto_20191008_1335'), - ] + dependencies = [("preferences", "0064_auto_20191008_1335")] operations = [ migrations.AlterField( - model_name='radiuskey', - name='default_switch', - field=models.BooleanField(default=False, help_text='Default key for switches'), - ), + model_name="radiuskey", + name="default_switch", + field=models.BooleanField( + default=False, help_text="Default key for switches" + ), + ) ] diff --git a/preferences/migrations/0066_optionalmachine_default_dns_ttl.py b/preferences/migrations/0066_optionalmachine_default_dns_ttl.py index 47e3519e..978957d4 100644 --- a/preferences/migrations/0066_optionalmachine_default_dns_ttl.py +++ b/preferences/migrations/0066_optionalmachine_default_dns_ttl.py @@ -7,14 +7,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('preferences', '0065_auto_20191010_1227'), - ] + dependencies = [("preferences", "0065_auto_20191010_1227")] operations = [ migrations.AddField( - model_name='optionalmachine', - name='default_dns_ttl', - field=models.PositiveIntegerField(default=172800, verbose_name='Default Time To Live (TTL) for CNAME, A and AAA records.'), - ), + model_name="optionalmachine", + name="default_dns_ttl", + field=models.PositiveIntegerField( + default=172800, + verbose_name="Default Time To Live (TTL) for CNAME, A and AAA records.", + ), + ) ] diff --git a/preferences/models.py b/preferences/models.py index b7153e72..7ef8979b 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -47,6 +47,7 @@ class PreferencesModel(models.Model): """ Base object for the Preferences objects Defines methods to handle the cache of the settings (they should not change a lot) """ + @classmethod def set_in_cache(cls): """ Save the preferences in a server-side cache """ @@ -73,65 +74,55 @@ class OptionalUser(AclMixin, PreferencesModel): is_tel_mandatory = models.BooleanField(default=True) gpg_fingerprint = models.BooleanField(default=True) all_can_create_club = models.BooleanField( - default=False, - help_text=_("Users can create a club.") + default=False, help_text=_("Users can create a club.") ) all_can_create_adherent = models.BooleanField( - default=False, - help_text=_("Users can create a member."), + default=False, help_text=_("Users can create a member.") ) shell_default = models.OneToOneField( - 'users.ListShell', - on_delete=models.PROTECT, - blank=True, - null=True + "users.ListShell", on_delete=models.PROTECT, blank=True, null=True ) self_change_shell = models.BooleanField( - default=False, - help_text=_("Users can edit their shell.") + default=False, help_text=_("Users can edit their shell.") ) self_change_room = models.BooleanField( - default=False, - help_text=_("Users can edit their room.") + default=False, help_text=_("Users can edit their room.") ) local_email_accounts_enabled = models.BooleanField( - default=False, - help_text=_("Enable local email accounts for users.") + default=False, help_text=_("Enable local email accounts for users.") ) local_email_domain = models.CharField( max_length=32, default="@example.org", - help_text=_("Domain to use for local email accounts") + help_text=_("Domain to use for local email accounts"), ) max_email_address = models.IntegerField( default=15, - help_text=_("Maximum number of local email addresses for a standard" - " user.") + help_text=_("Maximum number of local email addresses for a standard" " user."), ) delete_notyetactive = models.IntegerField( default=15, - help_text=_("Not yet active users will be deleted after this number of" - " days.") + help_text=_( + "Not yet active users will be deleted after this number of" " days." + ), ) self_adhesion = models.BooleanField( - default=False, - help_text=_("A new user can create their account on Re2o.") + default=False, help_text=_("A new user can create their account on Re2o.") ) all_users_active = models.BooleanField( default=False, - help_text=_("If True, all new created and connected users are active." - " If False, only when a valid registration has been paid.") + help_text=_( + "If True, all new created and connected users are active." + " If False, only when a valid registration has been paid." + ), ) allow_archived_connexion = models.BooleanField( - default=False, - help_text=_("If True, archived users are allowed to connect.") + default=False, help_text=_("If True, archived users are allowed to connect.") ) class Meta: - permissions = ( - ("view_optionaluser", _("Can view the user options")), - ) + permissions = (("view_optionaluser", _("Can view the user options")),) verbose_name = _("user options") def clean(self): @@ -145,7 +136,7 @@ class OptionalUser(AclMixin, PreferencesModel): @receiver(post_save, sender=OptionalUser) def optionaluser_post_save(**kwargs): """Ecriture dans le cache""" - user_pref = kwargs['instance'] + user_pref = kwargs["instance"] user_pref.set_in_cache() @@ -153,9 +144,9 @@ class OptionalMachine(AclMixin, PreferencesModel): """Options pour les machines : maximum de machines ou d'alias par user sans droit, activation de l'ipv6""" - SLAAC = 'SLAAC' - DHCPV6 = 'DHCPV6' - DISABLED = 'DISABLED' + SLAAC = "SLAAC" + DHCPV6 = "DHCPV6" + DISABLED = "DISABLED" CHOICE_IPV6 = ( (SLAAC, _("Autoconfiguration by RA")), (DHCPV6, _("IP addresses assigning by DHCPv6")), @@ -165,14 +156,8 @@ class OptionalMachine(AclMixin, PreferencesModel): password_machine = models.BooleanField(default=False) max_lambdauser_interfaces = models.IntegerField(default=10) max_lambdauser_aliases = models.IntegerField(default=10) - ipv6_mode = models.CharField( - max_length=32, - choices=CHOICE_IPV6, - default='DISABLED' - ) - create_machine = models.BooleanField( - default=True - ) + ipv6_mode = models.CharField(max_length=32, choices=CHOICE_IPV6, default="DISABLED") + create_machine = models.BooleanField(default=True) default_dns_ttl = models.PositiveIntegerField( verbose_name=_("Default Time To Live (TTL) for CNAME, A and AAA records."), default=172800, # 2 days @@ -181,19 +166,17 @@ class OptionalMachine(AclMixin, PreferencesModel): @cached_property def ipv6(self): """ Check if the IPv6 option is activated """ - return not self.get_cached_value('ipv6_mode') == 'DISABLED' + return not self.get_cached_value("ipv6_mode") == "DISABLED" class Meta: - permissions = ( - ("view_optionalmachine", _("Can view the machine options")), - ) + permissions = (("view_optionalmachine", _("Can view the machine options")),) verbose_name = _("machine options") @receiver(post_save, sender=OptionalMachine) def optionalmachine_post_save(**kwargs): """Synchronisation ipv6 et ecriture dans le cache""" - machine_pref = kwargs['instance'] + machine_pref = kwargs["instance"] machine_pref.set_in_cache() if machine_pref.ipv6_mode != "DISABLED": for interface in machines.models.Interface.objects.all(): @@ -203,68 +186,74 @@ def optionalmachine_post_save(**kwargs): class OptionalTopologie(AclMixin, PreferencesModel): """Reglages pour la topologie : mode d'accès radius, vlan où placer les machines en accept ou reject""" - MACHINE = 'MACHINE' - DEFINED = 'DEFINED' + + MACHINE = "MACHINE" + DEFINED = "DEFINED" CHOICE_RADIUS = ( (MACHINE, _("On the IP range's VLAN of the machine")), (DEFINED, _("Preset in 'VLAN for machines accepted by RADIUS'")), ) - CHOICE_PROVISION = ( - ('sftp', 'sftp'), - ('tftp', 'tftp'), - ) + CHOICE_PROVISION = (("sftp", "sftp"), ("tftp", "tftp")) switchs_web_management = models.BooleanField( default=False, - help_text=_("Web management, activated in case of automatic provision") + help_text=_("Web management, activated in case of automatic provision"), ) switchs_web_management_ssl = models.BooleanField( default=False, - help_text=_("SSL web management, make sure that a certificate is" - " installed on the switch") + help_text=_( + "SSL web management, make sure that a certificate is" + " installed on the switch" + ), ) switchs_rest_management = models.BooleanField( default=False, - help_text=_("REST management, activated in case of automatic provision") + help_text=_("REST management, activated in case of automatic provision"), ) switchs_ip_type = models.OneToOneField( - 'machines.IpType', + "machines.IpType", on_delete=models.PROTECT, blank=True, null=True, - help_text=_("IP range for the management of switches") + help_text=_("IP range for the management of switches"), ) switchs_provision = models.CharField( max_length=32, choices=CHOICE_PROVISION, - default='tftp', - help_text=_("Provision of configuration mode for switches") + default="tftp", + help_text=_("Provision of configuration mode for switches"), ) sftp_login = models.CharField( - max_length=32, - null=True, - blank=True, - help_text=_("SFTP login for switches") + max_length=32, null=True, blank=True, help_text=_("SFTP login for switches") ) sftp_pass = AESEncryptedField( - max_length=63, - null=True, - blank=True, - help_text=_("SFTP password") + max_length=63, null=True, blank=True, help_text=_("SFTP password") ) @cached_property def provisioned_switchs(self): """Liste des switches provisionnés""" from topologie.models import Switch - return Switch.objects.filter(automatic_provision=True).order_by('interface__domain__name') + + return Switch.objects.filter(automatic_provision=True).order_by( + "interface__domain__name" + ) @cached_property def switchs_management_interface(self): """Return the ip of the interface that the switch have to contact to get it's config""" if self.switchs_ip_type: from machines.models import Role, Interface - return Interface.objects.filter(machine__interface__in=Role.interface_for_roletype("switch-conf-server")).filter(machine_type__ip_type=self.switchs_ip_type).first() + + return ( + Interface.objects.filter( + machine__interface__in=Role.interface_for_roletype( + "switch-conf-server" + ) + ) + .filter(machine_type__ip_type=self.switchs_ip_type) + .first() + ) else: return None @@ -279,7 +268,7 @@ class OptionalTopologie(AclMixin, PreferencesModel): def switchs_management_sftp_creds(self): """Credentials des switchs pour provion sftp""" if self.sftp_login and self.sftp_pass: - return {'login' : self.sftp_login, 'pass' : self.sftp_pass} + return {"login": self.sftp_login, "pass": self.sftp_pass} else: return None @@ -287,61 +276,85 @@ class OptionalTopologie(AclMixin, PreferencesModel): def switchs_management_utils(self): """Used for switch_conf, return a list of ip on vlans""" from machines.models import Role, Ipv6List, Interface - def return_ips_dict(interfaces): - return {'ipv4' : [str(interface.ipv4) for interface in interfaces], 'ipv6' : Ipv6List.objects.filter(interface__in=interfaces).values_list('ipv6', flat=True)} - ntp_servers = Role.all_interfaces_for_roletype("ntp-server").filter(machine_type__ip_type=self.switchs_ip_type) - log_servers = Role.all_interfaces_for_roletype("log-server").filter(machine_type__ip_type=self.switchs_ip_type) - radius_servers = Role.all_interfaces_for_roletype("radius-server").filter(machine_type__ip_type=self.switchs_ip_type) + def return_ips_dict(interfaces): + return { + "ipv4": [str(interface.ipv4) for interface in interfaces], + "ipv6": Ipv6List.objects.filter(interface__in=interfaces).values_list( + "ipv6", flat=True + ), + } + + ntp_servers = Role.all_interfaces_for_roletype("ntp-server").filter( + machine_type__ip_type=self.switchs_ip_type + ) + log_servers = Role.all_interfaces_for_roletype("log-server").filter( + machine_type__ip_type=self.switchs_ip_type + ) + radius_servers = Role.all_interfaces_for_roletype("radius-server").filter( + machine_type__ip_type=self.switchs_ip_type + ) dhcp_servers = Role.all_interfaces_for_roletype("dhcp-server") - dns_recursive_servers = Role.all_interfaces_for_roletype("dns-recursive-server").filter(machine_type__ip_type=self.switchs_ip_type) + dns_recursive_servers = Role.all_interfaces_for_roletype( + "dns-recursive-server" + ).filter(machine_type__ip_type=self.switchs_ip_type) subnet = None subnet6 = None if self.switchs_ip_type: - subnet = self.switchs_ip_type.ip_net_full_info or self.switchs_ip_type.ip_set_full_info[0] + subnet = ( + self.switchs_ip_type.ip_net_full_info + or self.switchs_ip_type.ip_set_full_info[0] + ) subnet6 = self.switchs_ip_type.ip6_set_full_info - return {'ntp_servers': return_ips_dict(ntp_servers), 'log_servers': return_ips_dict(log_servers), 'radius_servers': return_ips_dict(radius_servers), 'dhcp_servers': return_ips_dict(dhcp_servers), 'dns_recursive_servers': return_ips_dict(dns_recursive_servers), 'subnet': subnet, 'subnet6': subnet6} + return { + "ntp_servers": return_ips_dict(ntp_servers), + "log_servers": return_ips_dict(log_servers), + "radius_servers": return_ips_dict(radius_servers), + "dhcp_servers": return_ips_dict(dhcp_servers), + "dns_recursive_servers": return_ips_dict(dns_recursive_servers), + "subnet": subnet, + "subnet6": subnet6, + } @cached_property def provision_switchs_enabled(self): """Return true if all settings are ok : switchs on automatic provision, ip_type""" - return bool(self.provisioned_switchs and self.switchs_ip_type and SwitchManagementCred.objects.filter(default_switch=True).exists() and self.switchs_management_interface_ip and bool(self.switchs_provision != 'sftp' or self.switchs_management_sftp_creds)) - class Meta: - permissions = ( - ("view_optionaltopologie", _("Can view the topology options")), + return bool( + self.provisioned_switchs + and self.switchs_ip_type + and SwitchManagementCred.objects.filter(default_switch=True).exists() + and self.switchs_management_interface_ip + and bool( + self.switchs_provision != "sftp" or self.switchs_management_sftp_creds + ) ) + + class Meta: + permissions = (("view_optionaltopologie", _("Can view the topology options")),) verbose_name = _("topology options") @receiver(post_save, sender=OptionalTopologie) def optionaltopologie_post_save(**kwargs): """Ecriture dans le cache""" - topologie_pref = kwargs['instance'] + topologie_pref = kwargs["instance"] topologie_pref.set_in_cache() class RadiusKey(AclMixin, models.Model): """Class of a radius key""" - radius_key = AESEncryptedField( - max_length=255, - help_text=_("RADIUS key") - ) + + radius_key = AESEncryptedField(max_length=255, help_text=_("RADIUS key")) comment = models.CharField( - max_length=255, - null=True, - blank=True, - help_text=_("Comment for this key") + max_length=255, null=True, blank=True, help_text=_("Comment for this key") ) default_switch = models.BooleanField( - default=False, - help_text=_("Default key for switches") + default=False, help_text=_("Default key for switches") ) class Meta: - permissions = ( - ("view_radiuskey", _("Can view a RADIUS key object")), - ) + permissions = (("view_radiuskey", _("Can view a RADIUS key object")),) verbose_name = _("RADIUS key") verbose_name_plural = _("RADIUS keys") @@ -358,24 +371,19 @@ class RadiusKey(AclMixin, models.Model): class SwitchManagementCred(AclMixin, models.Model): """Class of a management creds of a switch, for rest management""" - management_id = models.CharField( - max_length=63, - help_text=_("Switch login") - ) - management_pass = AESEncryptedField( - max_length=63, - help_text=_("Password") - ) + + management_id = models.CharField(max_length=63, help_text=_("Switch login")) + management_pass = AESEncryptedField(max_length=63, help_text=_("Password")) default_switch = models.BooleanField( - default=True, - unique=True, - help_text=_("Default credentials for switches") + default=True, unique=True, help_text=_("Default credentials for switches") ) class Meta: permissions = ( - ("view_switchmanagementcred", _("Can view a switch management" - " credentials object")), + ( + "view_switchmanagementcred", + _("Can view a switch management" " credentials object"), + ), ) verbose_name = _("switch management credentials") @@ -392,27 +400,28 @@ class Reminder(AclMixin, models.Model): days = models.IntegerField( default=7, unique=True, - help_text=_("Delay between the email and the membership's end") + help_text=_("Delay between the email and the membership's end"), ) message = models.TextField( default="", null=True, blank=True, - help_text=_("Message displayed specifically for this reminder") + help_text=_("Message displayed specifically for this reminder"), ) class Meta: - permissions = ( - ("view_reminder", _("Can view a reminder object")), - ) + permissions = (("view_reminder", _("Can view a reminder object")),) verbose_name = _("reminder") verbose_name_plural = _("reminders") def users_to_remind(self): from re2o.utils import all_has_access - date = timezone.now().replace(minute=0,hour=0) + + date = timezone.now().replace(minute=0, hour=0) futur_date = date + timedelta(days=self.days) - users = all_has_access(futur_date).exclude(pk__in = all_has_access(futur_date + timedelta(days=1))) + users = all_has_access(futur_date).exclude( + pk__in=all_has_access(futur_date + timedelta(days=1)) + ) return users @@ -423,14 +432,18 @@ class GeneralOption(AclMixin, PreferencesModel): general_message_fr = models.TextField( default="", blank=True, - help_text=_("General message displayed on the French version of the" - " website (e.g. in case of maintenance)") + help_text=_( + "General message displayed on the French version of the" + " website (e.g. in case of maintenance)" + ), ) general_message_en = models.TextField( default="", blank=True, - help_text=_("General message displayed on the English version of the" - " website (e.g. in case of maintenance)") + help_text=_( + "General message displayed on the English version of the" + " website (e.g. in case of maintenance)" + ), ) search_display_page = models.IntegerField(default=15) pagination_number = models.IntegerField(default=25) @@ -439,62 +452,51 @@ class GeneralOption(AclMixin, PreferencesModel): site_name = models.CharField(max_length=32, default="Re2o") email_from = models.EmailField(default="www-data@example.com") main_site_url = models.URLField(max_length=255, default="http://re2o.example.org") - GTU_sum_up = models.TextField( - default="", - blank=True, - ) - GTU = models.FileField( - upload_to='', - default="", - null=True, - blank=True, - ) + GTU_sum_up = models.TextField(default="", blank=True) + GTU = models.FileField(upload_to="", default="", null=True, blank=True) class Meta: - permissions = ( - ("view_generaloption", _("Can view the general options")), - ) + permissions = (("view_generaloption", _("Can view the general options")),) verbose_name = _("general options") @receiver(post_save, sender=GeneralOption) def generaloption_post_save(**kwargs): """Ecriture dans le cache""" - general_pref = kwargs['instance'] + general_pref = kwargs["instance"] general_pref.set_in_cache() class Service(AclMixin, models.Model): """Liste des services affichés sur la page d'accueil : url, description, image et nom""" + name = models.CharField(max_length=32) url = models.URLField() description = models.TextField() - image = models.ImageField(upload_to='logo', blank=True) + image = models.ImageField(upload_to="logo", blank=True) class Meta: - permissions = ( - ("view_service", _("Can view the service options")), - ) + permissions = (("view_service", _("Can view the service options")),) verbose_name = _("service") - verbose_name_plural =_("services") + verbose_name_plural = _("services") def __str__(self): return str(self.name) + class MailContact(AclMixin, models.Model): """Contact email adress with a commentary.""" address = models.EmailField( - default = "contact@example.org", - help_text = _("Contact email address") + default="contact@example.org", help_text=_("Contact email address") ) commentary = models.CharField( - blank = True, - null = True, - help_text = _("Description of the associated email address."), - max_length = 256 + blank=True, + null=True, + help_text=_("Description of the associated email address."), + max_length=256, ) @cached_property @@ -509,57 +511,53 @@ class MailContact(AclMixin, models.Model): verbose_name_plural = _("contact email addresses") def __str__(self): - return(self.address) + return self.address + class Mandate(RevMixin, AclMixin, models.Model): class Meta: verbose_name = _("Mandate") verbose_name_plural = _("Mandates") - permissions = ( - ("view_mandate", _("Can view a mandate")), - ) + permissions = (("view_mandate", _("Can view a mandate")),) president = models.ForeignKey( - 'users.User', + "users.User", on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("President of the association"), - help_text=_("Displayed on subscription vouchers") - ) - start_date = models.DateTimeField( - verbose_name=_("start date") - ) - end_date = models.DateTimeField( - verbose_name=_("end date"), - blank=True, - null=True + help_text=_("Displayed on subscription vouchers"), ) + start_date = models.DateTimeField(verbose_name=_("start date")) + end_date = models.DateTimeField(verbose_name=_("end date"), blank=True, null=True) @classmethod def get_mandate(cls, date=timezone.now): """"Find the mandate taking place at the given date.""" if callable(date): date = date() - mandate = cls.objects.exclude(end_date__lte=date).order_by('start_date').first() or cls.objects.order_by('start_date').last() + mandate = ( + cls.objects.exclude(end_date__lte=date).order_by("start_date").first() + or cls.objects.order_by("start_date").last() + ) if not mandate: - raise cls.DoesNotExist("No mandate have been created. Please go to the preferences page to create one.") + raise cls.DoesNotExist( + "No mandate have been created. Please go to the preferences page to create one." + ) return mandate - def is_over(self): return self.end_date is None def __str__(self): - return str(self.president) + ' ' + str(self.start_date.year) + return str(self.president) + " " + str(self.start_date.year) class AssoOption(AclMixin, PreferencesModel): """Options générales de l'asso : siret, addresse, nom, etc""" name = models.CharField( - default=_("Networking organisation school Something"), - max_length=256 + default=_("Networking organisation school Something"), max_length=256 ) siret = models.CharField(default="00000000000000", max_length=32) adresse1 = models.CharField(default=_("Threadneedle Street"), max_length=128) @@ -568,58 +566,38 @@ class AssoOption(AclMixin, PreferencesModel): telephone = models.CharField(max_length=15, default="0000000000") pseudo = models.CharField(default=_("Organisation"), max_length=32) utilisateur_asso = models.OneToOneField( - 'users.User', - on_delete=models.PROTECT, - blank=True, - null=True - ) - description = models.TextField( - null=True, - blank=True, + "users.User", on_delete=models.PROTECT, blank=True, null=True ) + description = models.TextField(null=True, blank=True) class Meta: - permissions = ( - ("view_assooption", _("Can view the organisation options")), - ) + permissions = (("view_assooption", _("Can view the organisation options")),) verbose_name = _("organisation options") @receiver(post_save, sender=AssoOption) def assooption_post_save(**kwargs): """Ecriture dans le cache""" - asso_pref = kwargs['instance'] + asso_pref = kwargs["instance"] asso_pref.set_in_cache() class HomeOption(AclMixin, PreferencesModel): """Settings of the home page (facebook/twitter etc)""" - facebook_url = models.URLField( - null=True, - blank=True - ) - twitter_url = models.URLField( - null=True, - blank=True - ) - twitter_account_name = models.CharField( - max_length=32, - null=True, - blank=True - ) + facebook_url = models.URLField(null=True, blank=True) + twitter_url = models.URLField(null=True, blank=True) + twitter_account_name = models.CharField(max_length=32, null=True, blank=True) class Meta: - permissions = ( - ("view_homeoption", _("Can view the homepage options")), - ) + permissions = (("view_homeoption", _("Can view the homepage options")),) verbose_name = _("homepage options") @receiver(post_save, sender=HomeOption) def homeoption_post_save(**kwargs): """Ecriture dans le cache""" - home_pref = kwargs['instance'] + home_pref = kwargs["instance"] home_pref.set_in_cache() @@ -627,20 +605,15 @@ class MailMessageOption(AclMixin, models.Model): """Reglages, mail de bienvenue et autre""" welcome_mail_fr = models.TextField( - default="", - blank=True, - help_text=_("Welcome email in French") + default="", blank=True, help_text=_("Welcome email in French") ) welcome_mail_en = models.TextField( - default="", - blank=True, - help_text=_("Welcome email in English") + default="", blank=True, help_text=_("Welcome email in English") ) class Meta: permissions = ( - ("view_mailmessageoption", _("Can view the email message" - " options")), + ("view_mailmessageoption", _("Can view the email message" " options")), ) verbose_name = _("email message options") @@ -655,20 +628,16 @@ class RadiusAttribute(RevMixin, AclMixin, models.Model): verbose_name=_("Attribute"), help_text=_("See http://freeradius.org/rfc/attributes.html"), ) - value = models.CharField( - max_length=255, - verbose_name=_("Value") - ) + value = models.CharField(max_length=255, verbose_name=_("Value")) comment = models.TextField( verbose_name=_("Comment"), help_text=_("Use this field to document this attribute."), blank=True, - default="" + default="", ) def __str__(self): - return ' '.join([self.attribute, '=', self.value]) - + return " ".join([self.attribute, "=", self.value]) class RadiusOption(AclMixin, PreferencesModel): @@ -676,22 +645,20 @@ class RadiusOption(AclMixin, PreferencesModel): verbose_name = _("RADIUS policy") verbose_name_plural = _("RADIUS policies") - MACHINE = 'MACHINE' - DEFINED = 'DEFINED' + MACHINE = "MACHINE" + DEFINED = "DEFINED" CHOICE_RADIUS = ( (MACHINE, _("On the IP range's VLAN of the machine")), (DEFINED, _("Preset in 'VLAN for machines accepted by RADIUS'")), ) - REJECT = 'REJECT' - SET_VLAN = 'SET_VLAN' + REJECT = "REJECT" + SET_VLAN = "SET_VLAN" CHOICE_POLICY = ( (REJECT, _("Reject the machine")), - (SET_VLAN, _("Place the machine on the VLAN")) + (SET_VLAN, _("Place the machine on the VLAN")), ) radius_general_policy = models.CharField( - max_length=32, - choices=CHOICE_RADIUS, - default='DEFINED' + max_length=32, choices=CHOICE_RADIUS, default="DEFINED" ) unknown_machine = models.CharField( max_length=32, @@ -700,17 +667,17 @@ class RadiusOption(AclMixin, PreferencesModel): verbose_name=_("Policy for unknown machines"), ) unknown_machine_vlan = models.ForeignKey( - 'machines.Vlan', + "machines.Vlan", on_delete=models.PROTECT, - related_name='unknown_machine_vlan', + related_name="unknown_machine_vlan", blank=True, null=True, verbose_name=_("Unknown machines VLAN"), - help_text=_("VLAN for unknown machines if not rejected") + help_text=_("VLAN for unknown machines if not rejected"), ) unknown_machine_attributes = models.ManyToManyField( RadiusAttribute, - related_name='unknown_machine_attribute', + related_name="unknown_machine_attribute", blank=True, verbose_name=_("Unknown machines attributes."), help_text=_("Answer attributes for unknown machines."), @@ -722,17 +689,17 @@ class RadiusOption(AclMixin, PreferencesModel): verbose_name=_("Policy for unknown ports"), ) unknown_port_vlan = models.ForeignKey( - 'machines.Vlan', + "machines.Vlan", on_delete=models.PROTECT, - related_name='unknown_port_vlan', + related_name="unknown_port_vlan", blank=True, null=True, verbose_name=_("Unknown ports VLAN"), - help_text=_("VLAN for unknown ports if not rejected") + help_text=_("VLAN for unknown ports if not rejected"), ) unknown_port_attributes = models.ManyToManyField( RadiusAttribute, - related_name='unknown_port_attribute', + related_name="unknown_port_attribute", blank=True, verbose_name=_("Unknown ports attributes."), help_text=_("Answer attributes for unknown ports."), @@ -741,21 +708,23 @@ class RadiusOption(AclMixin, PreferencesModel): max_length=32, choices=CHOICE_POLICY, default=REJECT, - verbose_name=_("Policy for machines connecting from unregistered rooms" - " (relevant on ports with STRICT RADIUS mode)"), + verbose_name=_( + "Policy for machines connecting from unregistered rooms" + " (relevant on ports with STRICT RADIUS mode)" + ), ) unknown_room_vlan = models.ForeignKey( - 'machines.Vlan', - related_name='unknown_room_vlan', + "machines.Vlan", + related_name="unknown_room_vlan", on_delete=models.PROTECT, blank=True, null=True, verbose_name=_("Unknown rooms VLAN"), - help_text=_("VLAN for unknown rooms if not rejected") + help_text=_("VLAN for unknown rooms if not rejected"), ) unknown_room_attributes = models.ManyToManyField( RadiusAttribute, - related_name='unknown_room_attribute', + related_name="unknown_room_attribute", blank=True, verbose_name=_("Unknown rooms attributes."), help_text=_("Answer attributes for unknown rooms."), @@ -767,17 +736,17 @@ class RadiusOption(AclMixin, PreferencesModel): verbose_name=_("Policy for non members"), ) non_member_vlan = models.ForeignKey( - 'machines.Vlan', - related_name='non_member_vlan', + "machines.Vlan", + related_name="non_member_vlan", on_delete=models.PROTECT, blank=True, null=True, verbose_name=_("Non members VLAN"), - help_text=_("VLAN for non members if not rejected") + help_text=_("VLAN for non members if not rejected"), ) non_member_attributes = models.ManyToManyField( RadiusAttribute, - related_name='non_member_attribute', + related_name="non_member_attribute", blank=True, verbose_name=_("Non member attributes."), help_text=_("Answer attributes for non members."), @@ -789,31 +758,31 @@ class RadiusOption(AclMixin, PreferencesModel): verbose_name=_("Policy for banned users"), ) banned_vlan = models.ForeignKey( - 'machines.Vlan', - related_name='banned_vlan', + "machines.Vlan", + related_name="banned_vlan", on_delete=models.PROTECT, blank=True, null=True, verbose_name=_("Banned users VLAN"), - help_text=_("VLAN for banned users if not rejected") + help_text=_("VLAN for banned users if not rejected"), ) banned_attributes = models.ManyToManyField( RadiusAttribute, - related_name='banned_attribute', + related_name="banned_attribute", blank=True, verbose_name=_("Banned attributes."), help_text=_("Answer attributes for banned users."), ) vlan_decision_ok = models.OneToOneField( - 'machines.Vlan', + "machines.Vlan", on_delete=models.PROTECT, - related_name='vlan_ok_option', + related_name="vlan_ok_option", blank=True, - null=True + null=True, ) ok_attributes = models.ManyToManyField( RadiusAttribute, - related_name='ok_attribute', + related_name="ok_attribute", blank=True, verbose_name=_("Accepted users attributes."), help_text=_("Answer attributes for accepted users."), @@ -822,26 +791,21 @@ class RadiusOption(AclMixin, PreferencesModel): @classmethod def get_attributes(cls, name, attribute_kwargs={}): return ( - ( - str(attribute.attribute), - str(attribute.value % attribute_kwargs) - ) + (str(attribute.attribute), str(attribute.value % attribute_kwargs)) for attribute in cls.get_cached_value(name).all() ) def default_invoice(): tpl, _ = DocumentTemplate.objects.get_or_create( - name="Re2o default invoice", - template="templates/default_invoice.tex" + name="Re2o default invoice", template="templates/default_invoice.tex" ) return tpl.id def default_voucher(): tpl, _ = DocumentTemplate.objects.get_or_create( - name="Re2o default voucher", - template="templates/default_voucher.tex" + name="Re2o default voucher", template="templates/default_voucher.tex" ) return tpl.id @@ -851,14 +815,14 @@ class CotisationsOption(AclMixin, PreferencesModel): verbose_name = _("cotisations options") invoice_template = models.OneToOneField( - 'preferences.DocumentTemplate', + "preferences.DocumentTemplate", verbose_name=_("Template for invoices"), related_name="invoice_template", on_delete=models.PROTECT, default=default_invoice, ) voucher_template = models.OneToOneField( - 'preferences.DocumentTemplate', + "preferences.DocumentTemplate", verbose_name=_("Template for subscription voucher"), related_name="voucher_template", on_delete=models.PROTECT, @@ -866,7 +830,9 @@ class CotisationsOption(AclMixin, PreferencesModel): ) send_voucher_mail = models.BooleanField( verbose_name=_("Send voucher by email when the invoice is controlled."), - help_text=_("Be carefull, if no mandate is defined on the preferences page, errors will be triggered when generating vouchers."), + help_text=_( + "Be carefull, if no mandate is defined on the preferences page, errors will be triggered when generating vouchers." + ), default=False, ) @@ -875,15 +841,9 @@ class DocumentTemplate(RevMixin, AclMixin, models.Model): """Represent a template in order to create documents such as invoice or subscription voucher. """ - template = models.FileField( - upload_to='templates/', - verbose_name=_('template') - ) - name = models.CharField( - max_length=125, - verbose_name=_('name'), - unique=True - ) + + template = models.FileField(upload_to="templates/", verbose_name=_("template")) + name = models.CharField(max_length=125, verbose_name=_("name"), unique=True) class Meta: verbose_name = _("document template") @@ -892,6 +852,7 @@ class DocumentTemplate(RevMixin, AclMixin, models.Model): def __str__(self): return str(self.name) + @receiver(models.signals.post_delete, sender=DocumentTemplate) def auto_delete_file_on_delete(sender, instance, **kwargs): """ diff --git a/preferences/templatetags/__init__.py b/preferences/templatetags/__init__.py index c0a03b85..7b69b281 100644 --- a/preferences/templatetags/__init__.py +++ b/preferences/templatetags/__init__.py @@ -1,5 +1,5 @@ # -*- mode: python; coding: utf-8 -*- -#re2o est un logiciel d'administration développé initiallement au rezometz. Il +# re2o est un logiciel d'administration développé initiallement au rezometz. Il # se veut agnostique au réseau considéré, de manière à être installable en # quelques clics. # diff --git a/preferences/urls.py b/preferences/urls.py index a03d7412..4e5b1bcf 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -32,121 +32,131 @@ from . import views urlpatterns = [ url( - r'^edit_options/(?P
    OptionalUser)$', + r"^edit_options/(?P
    OptionalUser)$", views.edit_options, - name='edit-options' - ), + name="edit-options", + ), url( - r'^edit_options/(?P
    OptionalMachine)$', + r"^edit_options/(?P
    OptionalMachine)$", views.edit_options, - name='edit-options' - ), + name="edit-options", + ), url( - r'^edit_options/(?P
    OptionalTopologie)$', + r"^edit_options/(?P
    OptionalTopologie)$", views.edit_options, - name='edit-options' - ), + name="edit-options", + ), url( - r'^edit_options/(?P
    GeneralOption)$', + r"^edit_options/(?P
    GeneralOption)$", views.edit_options, - name='edit-options' - ), + name="edit-options", + ), url( - r'^edit_options/(?P
    AssoOption)$', + r"^edit_options/(?P
    AssoOption)$", views.edit_options, - name='edit-options' - ), + name="edit-options", + ), url( - r'^edit_options/(?P
    HomeOption)$', + r"^edit_options/(?P
    HomeOption)$", views.edit_options, - name='edit-options' - ), + name="edit-options", + ), url( - r'^edit_options/(?P
    MailMessageOption)$', + r"^edit_options/(?P
    MailMessageOption)$", views.edit_options, - name='edit-options' - ), + name="edit-options", + ), url( - r'^edit_options/(?P
    RadiusOption)$', + r"^edit_options/(?P
    RadiusOption)$", views.edit_options, - name='edit-options' - ), + name="edit-options", + ), url( - r'^edit_options/(?P
    CotisationsOption)$', + r"^edit_options/(?P
    CotisationsOption)$", views.edit_options, - name='edit-options' - ), - url(r'^add_service/$', views.add_service, name='add-service'), + name="edit-options", + ), + url(r"^add_service/$", views.add_service, name="add-service"), url( - r'^edit_service/(?P[0-9]+)$', - views.edit_service, - name='edit-service' - ), - url(r'^del_service/(?P[0-9]+)$', views.del_service, name='del-service'), - url(r'^add_mailcontact/$', views.add_mailcontact, name='add-mailcontact'), + r"^edit_service/(?P[0-9]+)$", views.edit_service, name="edit-service" + ), + url(r"^del_service/(?P[0-9]+)$", views.del_service, name="del-service"), + url(r"^add_mailcontact/$", views.add_mailcontact, name="add-mailcontact"), url( - r'^edit_mailcontact/(?P[0-9]+)$', + r"^edit_mailcontact/(?P[0-9]+)$", views.edit_mailcontact, - name='edit-mailcontact' - ), - url(r'^del_mailcontact/$', views.del_mailcontact, name='del-mailcontact'), - url(r'^add_reminder/$', views.add_reminder, name='add-reminder'), + name="edit-mailcontact", + ), + url(r"^del_mailcontact/$", views.del_mailcontact, name="del-mailcontact"), + url(r"^add_reminder/$", views.add_reminder, name="add-reminder"), url( - r'^edit_reminder/(?P[0-9]+)$', + r"^edit_reminder/(?P[0-9]+)$", views.edit_reminder, - name='edit-reminder' - ), - url(r'^del_reminder/(?P[0-9]+)$', views.del_reminder, name='del-reminder'), - url(r'^add_radiuskey/$', views.add_radiuskey, name='add-radiuskey'), + name="edit-reminder", + ), url( - r'^edit_radiuskey/(?P[0-9]+)$', + r"^del_reminder/(?P[0-9]+)$", + views.del_reminder, + name="del-reminder", + ), + url(r"^add_radiuskey/$", views.add_radiuskey, name="add-radiuskey"), + url( + r"^edit_radiuskey/(?P[0-9]+)$", views.edit_radiuskey, - name='edit-radiuskey' - ), - url(r'^del_radiuskey/(?P[0-9]+)$', views.del_radiuskey, name='del-radiuskey'), - url(r'^add_switchmanagementcred/$', views.add_switchmanagementcred, name='add-switchmanagementcred'), + name="edit-radiuskey", + ), url( - r'^edit_switchmanagementcred/(?P[0-9]+)$', + r"^del_radiuskey/(?P[0-9]+)$", + views.del_radiuskey, + name="del-radiuskey", + ), + url( + r"^add_switchmanagementcred/$", + views.add_switchmanagementcred, + name="add-switchmanagementcred", + ), + url( + r"^edit_switchmanagementcred/(?P[0-9]+)$", views.edit_switchmanagementcred, - name='edit-switchmanagementcred' - ), - url(r'^del_switchmanagementcred/(?P[0-9]+)$', views.del_switchmanagementcred, name='del-switchmanagementcred'), + name="edit-switchmanagementcred", + ), url( - r'^add_document_template/$', + r"^del_switchmanagementcred/(?P[0-9]+)$", + views.del_switchmanagementcred, + name="del-switchmanagementcred", + ), + url( + r"^add_document_template/$", views.add_document_template, - name='add-document-template' + name="add-document-template", ), url( - r'^edit_document_template/(?P[0-9]+)$', + r"^edit_document_template/(?P[0-9]+)$", views.edit_document_template, - name='edit-document-template' + name="edit-document-template", ), url( - r'^del_document_template/$', + r"^del_document_template/$", views.del_document_template, - name='del-document-template' + name="del-document-template", + ), + url(r"^add_mandate/$", views.add_mandate, name="add-mandate"), + url( + r"^edit_mandate/(?P[0-9]+)$", views.edit_mandate, name="edit-mandate" + ), + url(r"^del_mandate/(?P[0-9]+)$", views.del_mandate, name="del-mandate"), + url( + r"^add_radiusattribute/$", views.add_radiusattribute, name="add-radiusattribute" ), url( - r'^add_mandate/$', - views.add_mandate, - name='add-mandate' - ), - url( - r'^edit_mandate/(?P[0-9]+)$', - views.edit_mandate, - name='edit-mandate' - ), - url( - r'^del_mandate/(?P[0-9]+)$', - views.del_mandate, - name='del-mandate' - ), - url(r'^add_radiusattribute/$', views.add_radiusattribute, name='add-radiusattribute'), - url( - r'^edit_radiusattribute/(?P[0-9]+)$', + r"^edit_radiusattribute/(?P[0-9]+)$", views.edit_radiusattribute, - name='edit-radiusattribute' - ), - url(r'^del_radiusattribute/(?P[0-9]+)$', views.del_radiusattribute, name='del-radiusattribute'), - url(r'^$', views.display_options, name='display-options'), + name="edit-radiusattribute", + ), + url( + r"^del_radiusattribute/(?P[0-9]+)$", + views.del_radiusattribute, + name="del-radiusattribute", + ), + url(r"^$", views.display_options, name="display-options"), ] diff --git a/preferences/views.py b/preferences/views.py index d27cdb4f..91ced9b3 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -43,7 +43,14 @@ from reversion import revisions as reversion from importlib import import_module from re2o.settings_local import OPTIONNAL_APPS_RE2O from re2o.views import form -from re2o.acl import can_create, can_edit, can_delete_set, can_view_all, can_delete, acl_error_message +from re2o.acl import ( + can_create, + can_edit, + can_delete_set, + can_view_all, + can_delete, + acl_error_message, +) from .forms import MailContactForm, DelMailContactForm from .forms import ( @@ -55,7 +62,7 @@ from .forms import ( DelDocumentTemplateForm, RadiusAttributeForm, DelRadiusAttributeForm, - MandateForm + MandateForm, ) from .models import ( Service, @@ -74,15 +81,22 @@ from .models import ( CotisationsOption, DocumentTemplate, RadiusAttribute, - Mandate + Mandate, ) from . import models from . import forms @login_required -@can_view_all(OptionalUser, OptionalMachine, OptionalTopologie, GeneralOption, - AssoOption, MailMessageOption, HomeOption) +@can_view_all( + OptionalUser, + OptionalMachine, + OptionalTopologie, + GeneralOption, + AssoOption, + MailMessageOption, + HomeOption, +) def display_options(request): """Vue pour affichage des options (en vrac) classé selon les models correspondants dans un tableau""" @@ -91,7 +105,7 @@ def display_options(request): topologieoptions, _created = OptionalTopologie.objects.get_or_create() generaloptions, _created = GeneralOption.objects.get_or_create() assooptions, _created = AssoOption.objects.get_or_create() - mandate_list = Mandate.objects.order_by('start_date') + mandate_list = Mandate.objects.order_by("start_date") homeoptions, _created = HomeOption.objects.get_or_create() mailmessageoptions, _created = MailMessageOption.objects.get_or_create() service_list = Service.objects.all() @@ -102,70 +116,69 @@ def display_options(request): radiusoptions, _ = RadiusOption.objects.get_or_create() radius_attributes = RadiusAttribute.objects.all() cotisationsoptions, _created = CotisationsOption.objects.get_or_create() - document_template_list = DocumentTemplate.objects.order_by('name') + document_template_list = DocumentTemplate.objects.order_by("name") optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] - optionnal_templates_list = [app.views.preferences(request) for app in optionnal_apps if hasattr(app.views, 'preferences')] + optionnal_templates_list = [ + app.views.preferences(request) + for app in optionnal_apps + if hasattr(app.views, "preferences") + ] - return form({ - 'useroptions': useroptions, - 'machineoptions': machineoptions, - 'topologieoptions': topologieoptions, - 'generaloptions': generaloptions, - 'assooptions': assooptions, - 'mandate_list': mandate_list, - 'homeoptions': homeoptions, - 'mailmessageoptions': mailmessageoptions, - 'service_list': service_list, - 'mailcontact_list': mailcontact_list, - 'reminder_list': reminder_list, - 'radiuskey_list' : radiuskey_list, - 'switchmanagementcred_list': switchmanagementcred_list, - 'radiusoptions' : radiusoptions, - 'radius_attributes' : radius_attributes, - 'cotisationsoptions': cotisationsoptions, - 'optionnal_templates_list': optionnal_templates_list, - 'document_template_list': document_template_list, - }, 'preferences/display_preferences.html', request) + return form( + { + "useroptions": useroptions, + "machineoptions": machineoptions, + "topologieoptions": topologieoptions, + "generaloptions": generaloptions, + "assooptions": assooptions, + "mandate_list": mandate_list, + "homeoptions": homeoptions, + "mailmessageoptions": mailmessageoptions, + "service_list": service_list, + "mailcontact_list": mailcontact_list, + "reminder_list": reminder_list, + "radiuskey_list": radiuskey_list, + "switchmanagementcred_list": switchmanagementcred_list, + "radiusoptions": radiusoptions, + "radius_attributes": radius_attributes, + "cotisationsoptions": cotisationsoptions, + "optionnal_templates_list": optionnal_templates_list, + "document_template_list": document_template_list, + }, + "preferences/display_preferences.html", + request, + ) @login_required def edit_options(request, section): """ Edition des préférences générales""" model = getattr(models, section, None) - form_instance = getattr(forms, 'Edit' + section + 'Form', None) + form_instance = getattr(forms, "Edit" + section + "Form", None) if not (model or form_instance): messages.error(request, _("Unknown object.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) options_instance, _created = model.objects.get_or_create() can, msg, permissions = options_instance.can_edit(request.user) if not can: messages.error(request, acl_error_message(msg, permissions)) - return redirect(reverse('index')) + return redirect(reverse("index")) options = form_instance( - request.POST or None, - request.FILES or None, - instance=options_instance + request.POST or None, request.FILES or None, instance=options_instance ) if options.is_valid(): with transaction.atomic(), reversion.create_revision(): options.save() reversion.set_user(request.user) reversion.set_comment( - "Field(s) edited: %s" % ', '.join( - field for field in options.changed_data - ) + "Field(s) edited: %s" + % ", ".join(field for field in options.changed_data) ) messages.success(request, _("The preferences were edited.")) - return redirect(reverse('preferences:display-options')) - return form( - { - 'options': options, - }, - 'preferences/edit_preferences.html', - request - ) + return redirect(reverse("preferences:display-options")) + return form({"options": options}, "preferences/edit_preferences.html", request) @login_required @@ -176,12 +189,12 @@ def add_service(request): if service.is_valid(): service.save() messages.success(request, _("The service was added.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': service, 'action_name': _("Add a service")}, - 'preferences/preferences.html', - request - ) + {"preferenceform": service, "action_name": _("Add a service")}, + "preferences/preferences.html", + request, + ) @login_required @@ -189,20 +202,19 @@ def add_service(request): def edit_service(request, service_instance, **_kwargs): """Edition des services affichés sur la page d'accueil""" service = ServiceForm( - request.POST or None, - request.FILES or None, - instance=service_instance + request.POST or None, request.FILES or None, instance=service_instance ) if service.is_valid(): service.save() messages.success(request, _("The service was edited.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': service, 'action_name': _("Edit")}, - 'preferences/preferences.html', - request + {"preferenceform": service, "action_name": _("Edit")}, + "preferences/preferences.html", + request, ) + @login_required @can_delete(Service) def del_service(request, service_instance, **_kwargs): @@ -210,12 +222,13 @@ def del_service(request, service_instance, **_kwargs): if request.method == "POST": service_instance.delete() messages.success(request, _("The service was deleted.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'objet': service_instance, 'objet_name': 'service'}, - 'preferences/delete.html', - request - ) + {"objet": service_instance, "objet_name": "service"}, + "preferences/delete.html", + request, + ) + @login_required @can_create(Reminder) @@ -225,34 +238,32 @@ def add_reminder(request): if reminder.is_valid(): reminder.save() messages.success(request, _("The reminder was added.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': reminder, 'action_name': _("Add a reminder")}, - 'preferences/preferences.html', - request - ) + {"preferenceform": reminder, "action_name": _("Add a reminder")}, + "preferences/preferences.html", + request, + ) + @login_required @can_edit(Reminder) def edit_reminder(request, reminder_instance, **_kwargs): """Edition reminder""" reminder = ReminderForm( - request.POST or None, - request.FILES or None, - instance=reminder_instance + request.POST or None, request.FILES or None, instance=reminder_instance ) if reminder.is_valid(): reminder.save() messages.success(request, _("The reminder was edited.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': reminder, 'action_name': _("Edit")}, - 'preferences/preferences.html', - request + {"preferenceform": reminder, "action_name": _("Edit")}, + "preferences/preferences.html", + request, ) - @login_required @can_delete(Reminder) def del_reminder(request, reminder_instance, **_kwargs): @@ -260,12 +271,12 @@ def del_reminder(request, reminder_instance, **_kwargs): if request.method == "POST": reminder_instance.delete() messages.success(request, _("The reminder was deleted.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'objet': reminder_instance, 'objet_name': 'reminder'}, - 'preferences/delete.html', - request - ) + {"objet": reminder_instance, "objet_name": "reminder"}, + "preferences/delete.html", + request, + ) @login_required @@ -276,12 +287,13 @@ def add_radiuskey(request): if radiuskey.is_valid(): radiuskey.save() messages.success(request, _("The RADIUS key was added.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': radiuskey, 'action_name': _("Add a RADIUS key")}, - 'preferences/preferences.html', - request - ) + {"preferenceform": radiuskey, "action_name": _("Add a RADIUS key")}, + "preferences/preferences.html", + request, + ) + @can_edit(RadiusKey) def edit_radiuskey(request, radiuskey_instance, **_kwargs): @@ -290,11 +302,11 @@ def edit_radiuskey(request, radiuskey_instance, **_kwargs): if radiuskey.is_valid(): radiuskey.save() messages.success(request, _("The RADIUS key was edited.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': radiuskey, 'action_name': _("Edit")}, - 'preferences/preferences.html', - request + {"preferenceform": radiuskey, "action_name": _("Edit")}, + "preferences/preferences.html", + request, ) @@ -307,14 +319,19 @@ def del_radiuskey(request, radiuskey_instance, **_kwargs): radiuskey_instance.delete() messages.success(request, _("The RADIUS key was deleted.")) except ProtectedError: - messages.error(request, _("The RADIUS key is assigned to at least" - " one switch, you can't delete it.")) - return redirect(reverse('preferences:display-options')) + messages.error( + request, + _( + "The RADIUS key is assigned to at least" + " one switch, you can't delete it." + ), + ) + return redirect(reverse("preferences:display-options")) return form( - {'objet': radiuskey_instance, 'objet_name': 'radiuskey'}, - 'preferences/delete.html', - request - ) + {"objet": radiuskey_instance, "objet_name": "radiuskey"}, + "preferences/delete.html", + request, + ) @login_required @@ -325,25 +342,31 @@ def add_switchmanagementcred(request): if switchmanagementcred.is_valid(): switchmanagementcred.save() messages.success(request, _("The switch management credentials were added.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': switchmanagementcred, 'action_name': _("Add switch management credentials")}, - 'preferences/preferences.html', - request - ) + { + "preferenceform": switchmanagementcred, + "action_name": _("Add switch management credentials"), + }, + "preferences/preferences.html", + request, + ) + @can_edit(SwitchManagementCred) def edit_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs): """Edition des creds de management""" - switchmanagementcred = SwitchManagementCredForm(request.POST or None, instance=switchmanagementcred_instance) + switchmanagementcred = SwitchManagementCredForm( + request.POST or None, instance=switchmanagementcred_instance + ) if switchmanagementcred.is_valid(): switchmanagementcred.save() messages.success(request, _("The switch management credentials were edited.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': switchmanagementcred, 'action_name': _("Edit")}, - 'preferences/preferences.html', - request + {"preferenceform": switchmanagementcred, "action_name": _("Edit")}, + "preferences/preferences.html", + request, ) @@ -354,37 +377,43 @@ def del_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs): if request.method == "POST": try: switchmanagementcred_instance.delete() - messages.success(request, _("The switch management credentials were deleted.")) + messages.success( + request, _("The switch management credentials were deleted.") + ) except ProtectedError: - messages.error(request, _("The switch management credentials are" - " assigned to at least one switch, you" - " can't delete them.")) - return redirect(reverse('preferences:display-options')) + messages.error( + request, + _( + "The switch management credentials are" + " assigned to at least one switch, you" + " can't delete them." + ), + ) + return redirect(reverse("preferences:display-options")) return form( - {'objet': switchmanagementcred_instance, 'objet_name': 'switchmanagementcred'}, - 'preferences/delete.html', - request - ) + {"objet": switchmanagementcred_instance, "objet_name": "switchmanagementcred"}, + "preferences/delete.html", + request, + ) @login_required @can_create(MailContact) def add_mailcontact(request): """Add a contact email adress.""" - mailcontact = MailContactForm( - request.POST or None, - request.FILES or None - ) + mailcontact = MailContactForm(request.POST or None, request.FILES or None) if mailcontact.is_valid(): mailcontact.save() messages.success(request, _("The contact email address was created.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': mailcontact, - 'action_name': _("Add a contact email address")}, - 'preferences/preferences.html', - request - ) + { + "preferenceform": mailcontact, + "action_name": _("Add a contact email address"), + }, + "preferences/preferences.html", + request, + ) @login_required @@ -392,18 +421,16 @@ def add_mailcontact(request): def edit_mailcontact(request, mailcontact_instance, **_kwargs): """Edit contact email adress.""" mailcontact = MailContactForm( - request.POST or None, - request.FILES or None, - instance=mailcontact_instance + request.POST or None, request.FILES or None, instance=mailcontact_instance ) if mailcontact.is_valid(): mailcontact.save() messages.success(request, _("The contact email address was edited.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': mailcontact, 'action_name': _("Edit")}, - 'preferences/preferences.html', - request + {"preferenceform": mailcontact, "action_name": _("Edit")}, + "preferences/preferences.html", + request, ) @@ -411,21 +438,17 @@ def edit_mailcontact(request, mailcontact_instance, **_kwargs): @can_delete_set(MailContact) def del_mailcontact(request, instances): """Delete an email adress""" - mailcontacts = DelMailContactForm( - request.POST or None, - instances=instances - ) + mailcontacts = DelMailContactForm(request.POST or None, instances=instances) if mailcontacts.is_valid(): - mailcontacts_dels = mailcontacts.cleaned_data['mailcontacts'] + mailcontacts_dels = mailcontacts.cleaned_data["mailcontacts"] for mailcontacts_del in mailcontacts_dels: mailcontacts_del.delete() - messages.success(request, - _("The contact email adress was deleted.")) - return redirect(reverse('preferences:display-options')) + messages.success(request, _("The contact email adress was deleted.")) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': mailcontacts, 'action_name': _("Delete")}, - 'preferences/preferences.html', - request + {"preferenceform": mailcontacts, "action_name": _("Delete")}, + "preferences/preferences.html", + request, ) @@ -436,21 +459,21 @@ def add_document_template(request): View used to add a document template. """ document_template = DocumentTemplateForm( - request.POST or None, - request.FILES or None, + request.POST or None, request.FILES or None ) if document_template.is_valid(): document_template.save() - messages.success( - request, - _("The document template was created.") - ) - return redirect(reverse('preferences:display-options')) - return form({ - 'preferenceform': document_template, - 'action_name': _("Add"), - 'title': _("New document template") - }, 'preferences/preferences.html', request) + messages.success(request, _("The document template was created.")) + return redirect(reverse("preferences:display-options")) + return form( + { + "preferenceform": document_template, + "action_name": _("Add"), + "title": _("New document template"), + }, + "preferences/preferences.html", + request, + ) @login_required @@ -460,22 +483,22 @@ def edit_document_template(request, document_template_instance, **_kwargs): View used to edit a document_template. """ document_template = DocumentTemplateForm( - request.POST or None, - request.FILES or None, - instance=document_template_instance) + request.POST or None, request.FILES or None, instance=document_template_instance + ) if document_template.is_valid(): if document_template.changed_data: document_template.save() - messages.success( - request, - _("The document template was edited.") - ) - return redirect(reverse('preferences:display-options')) - return form({ - 'preferenceform': document_template, - 'action_name': _("Edit"), - 'title': _("Edit document template") - }, 'preferences/preferences.html', request) + messages.success(request, _("The document template was edited.")) + return redirect(reverse("preferences:display-options")) + return form( + { + "preferenceform": document_template, + "action_name": _("Edit"), + "title": _("Edit document template"), + }, + "preferences/preferences.html", + request, + ) @login_required @@ -485,32 +508,37 @@ def del_document_template(request, instances): View used to delete a set of document template. """ document_template = DelDocumentTemplateForm( - request.POST or None, instances=instances) + request.POST or None, instances=instances + ) if document_template.is_valid(): - document_template_del = document_template.cleaned_data['document_templates'] + document_template_del = document_template.cleaned_data["document_templates"] for document_template in document_template_del: try: document_template.delete() messages.success( request, - _("The document template %(document_template)s was deleted.") % { - 'document_template': document_template - } + _("The document template %(document_template)s was deleted.") + % {"document_template": document_template}, ) except ProtectedError: messages.error( request, - _("The document template %(document_template)s can't be deleted \ - because it is currently being used.") % { - 'document_template': document_template - } + _( + "The document template %(document_template)s can't be deleted \ + because it is currently being used." + ) + % {"document_template": document_template}, ) - return redirect(reverse('preferences:display-options')) - return form({ - 'preferenceform': document_template, - 'action_name': _("Delete"), - 'title': _("Delete document template") - }, 'preferences/preferences.html', request) + return redirect(reverse("preferences:display-options")) + return form( + { + "preferenceform": document_template, + "action_name": _("Delete"), + "title": _("Delete document template"), + }, + "preferences/preferences.html", + request, + ) @login_required @@ -521,12 +549,12 @@ def add_radiusattribute(request): if attribute.is_valid(): attribute.save() messages.success(request, _("The attribute was added.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': attribute, 'action_name': _("Add a RADIUS attribute")}, - 'preferences/preferences.html', - request - ) + {"preferenceform": attribute, "action_name": _("Add a RADIUS attribute")}, + "preferences/preferences.html", + request, + ) @login_required @@ -534,19 +562,19 @@ def add_radiusattribute(request): def edit_radiusattribute(request, radiusattribute_instance, **_kwargs): """Edit a RADIUS attribute.""" attribute = RadiusAttributeForm( - request.POST or None, - instance=radiusattribute_instance + request.POST or None, instance=radiusattribute_instance ) if attribute.is_valid(): attribute.save() messages.success(request, _("The attribute was edited.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': attribute, 'action_name': _("Edit")}, - 'preferences/preferences.html', - request + {"preferenceform": attribute, "action_name": _("Edit")}, + "preferences/preferences.html", + request, ) + @login_required @can_delete(RadiusAttribute) def del_radiusattribute(request, radiusattribute_instance, **_kwargs): @@ -554,12 +582,12 @@ def del_radiusattribute(request, radiusattribute_instance, **_kwargs): if request.method == "POST": radiusattribute_instance.delete() messages.success(request, _("The attribute was deleted.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'objet': radiusattribute_instance, 'objet_name': 'attribute'}, - 'preferences/delete.html', - request - ) + {"objet": radiusattribute_instance, "objet_name": "attribute"}, + "preferences/delete.html", + request, + ) @login_required @@ -570,32 +598,30 @@ def add_mandate(request): if mandate.is_valid(): mandate.save() messages.success(request, _("The mandate was added.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': mandate, 'action_name': _("Add a mandate")}, - 'preferences/preferences.html', - request - ) + {"preferenceform": mandate, "action_name": _("Add a mandate")}, + "preferences/preferences.html", + request, + ) @login_required @can_edit(Mandate) def edit_mandate(request, mandate_instance, **_kwargs): """Edit a mandate.""" - mandate = MandateForm( - request.POST or None, - instance=mandate_instance - ) + mandate = MandateForm(request.POST or None, instance=mandate_instance) if mandate.is_valid(): mandate.save() messages.success(request, _("The mandate was edited.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'preferenceform': mandate, 'action_name': _("Edit")}, - 'preferences/preferences.html', - request + {"preferenceform": mandate, "action_name": _("Edit")}, + "preferences/preferences.html", + request, ) + @login_required @can_delete(Mandate) def del_mandate(request, mandate_instance, **_kwargs): @@ -603,13 +629,9 @@ def del_mandate(request, mandate_instance, **_kwargs): if request.method == "POST": mandate_instance.delete() messages.success(request, _("The mandate was deleted.")) - return redirect(reverse('preferences:display-options')) + return redirect(reverse("preferences:display-options")) return form( - {'objet': mandate_instance, 'objet_name': 'attribute'}, - 'preferences/delete.html', - request - ) - - - - + {"objet": mandate_instance, "objet_name": "attribute"}, + "preferences/delete.html", + request, + ) diff --git a/re2o/acl.py b/re2o/acl.py index b36fd48c..5991df02 100644 --- a/re2o/acl.py +++ b/re2o/acl.py @@ -43,21 +43,18 @@ def acl_error_message(msg, permissions): """Create an error message for msg and permissions.""" if permissions is None: return msg - groups = ", ".join([ - g.name for g in get_group_having_permission(*permissions) - ]) - message = msg or _("You don't have the right to edit" - " this option.") + groups = ", ".join([g.name for g in get_group_having_permission(*permissions)]) + message = msg or _("You don't have the right to edit" " this option.") if groups: - return message + _( - " You need to be a member of one of those" - " groups : %s" - ) % groups + return ( + message + + _(" You need to be a member of one of those" " groups : %s") % groups + ) else: - return message + " No group have the %s permission(s) !" % " or ".join([ - ",".join(permissions[:-1]), - permissions[-1]] - if len(permissions) > 2 else permissions + return message + " No group have the %s permission(s) !" % " or ".join( + [",".join(permissions[:-1]), permissions[-1]] + if len(permissions) > 2 + else permissions ) @@ -151,6 +148,7 @@ ModelC) def decorator(view): """The decorator to use on a specific view """ + def wrapper(request, *args, **kwargs): """The wrapper used for a specific request""" instances = [] @@ -172,7 +170,7 @@ ModelC) can_fct = getattr(target, method_name) yield can_fct(request.user, *args, **kwargs) for field in fields: - can_change_fct = getattr(target, 'can_change_' + field) + can_change_fct = getattr(target, "can_change_" + field) yield can_change_fct(request.user, *args, **kwargs) error_messages = [] @@ -191,19 +189,19 @@ ModelC) if error_messages: for msg in error_messages: messages.error( - request, msg or _("You don't have the right to access" - " this menu.")) + request, + msg or _("You don't have the right to access" " this menu."), + ) if request.user.id is not None: - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(request.user.id)} - )) + return redirect( + reverse("users:profil", kwargs={"userid": str(request.user.id)}) + ) else: - return redirect(reverse( - 'index', - )) + return redirect(reverse("index")) return view(request, *chain(instances, args), **kwargs) + return wrapper + return decorator @@ -212,7 +210,7 @@ def can_create(*models): `acl_base_decorator` with the flag `on_instance=False` and the method 'can_create'. See `acl_base_decorator` documentation for further details. """ - return acl_base_decorator('can_create', *models, on_instance=False) + return acl_base_decorator("can_create", *models, on_instance=False) def can_edit(*targets): @@ -221,7 +219,7 @@ def can_edit(*targets): method 'can_edit'. See `acl_base_decorator` documentation for further details. """ - return acl_base_decorator('can_edit', *targets) + return acl_base_decorator("can_edit", *targets) def can_change(*targets): @@ -231,7 +229,7 @@ def can_change(*targets): method 'can_change'. See `acl_base_decorator` documentation for further details. """ - return acl_base_decorator('can_change', *targets, on_instance=False) + return acl_base_decorator("can_change", *targets, on_instance=False) def can_delete(*targets): @@ -240,15 +238,17 @@ def can_delete(*targets): method 'can_edit'. See `acl_base_decorator` documentation for further details. """ - return acl_base_decorator('can_delete', *targets) + return acl_base_decorator("can_delete", *targets) def can_delete_set(model): """Decorator which returns a list of detable models by request user. If none of them, return an error""" + def decorator(view): """The decorator to use on a specific view """ + def wrapper(request, *args, **kwargs): """The wrapper used for a specific request """ @@ -263,12 +263,13 @@ def can_delete_set(model): messages.error( request, _("You don't have the right to access this menu.") ) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(request.user.id)} - )) + return redirect( + reverse("users:profil", kwargs={"userid": str(request.user.id)}) + ) return view(request, instances, *args, **kwargs) + return wrapper + return decorator @@ -278,7 +279,7 @@ def can_view(*targets): method 'can_view'. See `acl_base_decorator` documentation for further details. """ - return acl_base_decorator('can_view', *targets) + return acl_base_decorator("can_view", *targets) def can_view_all(*targets): @@ -287,7 +288,7 @@ def can_view_all(*targets): method 'can_view_all'. See `acl_base_decorator` documentation for further details. """ - return acl_base_decorator('can_view_all', *targets, on_instance=False) + return acl_base_decorator("can_view_all", *targets, on_instance=False) def can_view_app(*apps_name): @@ -296,7 +297,7 @@ def can_view_app(*apps_name): for app_name in apps_name: assert app_name in sys.modules.keys() return acl_base_decorator( - 'can_view', + "can_view", *chain(sys.modules[app_name] for app_name in apps_name), on_instance=False ) @@ -304,18 +305,15 @@ def can_view_app(*apps_name): def can_edit_history(view): """Decorator to check if an user can edit history.""" + def wrapper(request, *args, **kwargs): """The wrapper used for a specific request """ - if request.user.has_perm('admin.change_logentry'): + if request.user.has_perm("admin.change_logentry"): return view(request, *args, **kwargs) - messages.error( - request, - _("You don't have the right to edit the history.") + messages.error(request, _("You don't have the right to edit the history.")) + return redirect( + reverse("users:profil", kwargs={"userid": str(request.user.id)}) ) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(request.user.id)} - )) - return wrapper + return wrapper diff --git a/re2o/aes_field.py b/re2o/aes_field.py index edabfc40..f5c98002 100644 --- a/re2o/aes_field.py +++ b/re2o/aes_field.py @@ -37,13 +37,14 @@ from django.db import models from django import forms from django.conf import settings -EOD_asbyte = b'`%EofD%`' # This should be something that will not occur in strings -EOD = EOD_asbyte.decode('utf-8') +EOD_asbyte = b"`%EofD%`" # This should be something that will not occur in strings +EOD = EOD_asbyte.decode("utf-8") + def genstring(length=16, chars=string.printable): """ Generate a random string of length `length` and composed of the characters in `chars` """ - return ''.join([choice(chars) for i in range(length)]) + return "".join([choice(chars) for i in range(length)]) def encrypt(key, secret): @@ -54,7 +55,7 @@ def encrypt(key, secret): saltlength = 16 - datalength else: saltlength = 16 - datalength % 16 - encrypted_secret = ''.join([secret, EOD, genstring(saltlength)]) + encrypted_secret = "".join([secret, EOD, genstring(saltlength)]) return obj.encrypt(encrypted_secret) @@ -74,14 +75,17 @@ class AESEncryptedField(models.CharField): of AES ecnrypted fields """ def save_form_data(self, instance, data): - setattr(instance, self.name, binascii.b2a_base64( - encrypt(settings.AES_KEY, data)).decode('utf-8')) + setattr( + instance, + self.name, + binascii.b2a_base64(encrypt(settings.AES_KEY, data)).decode("utf-8"), + ) def to_python(self, value): if value is None: return None try: - return decrypt(settings.AES_KEY, binascii.a2b_base64(value)).decode('utf-8') + return decrypt(settings.AES_KEY, binascii.a2b_base64(value)).decode("utf-8") except UnicodeDecodeError as e: raise ValueError( "Could not decode your field %s, your settings.AES_KEY " @@ -92,7 +96,7 @@ class AESEncryptedField(models.CharField): if value is None: return value try: - return decrypt(settings.AES_KEY, binascii.a2b_base64(value)).decode('utf-8') + return decrypt(settings.AES_KEY, binascii.a2b_base64(value)).decode("utf-8") except UnicodeDecodeError as e: raise ValueError( "Could not decode your field %s, your settings.AES_KEY " @@ -102,9 +106,9 @@ class AESEncryptedField(models.CharField): def get_prep_value(self, value): if value is None: return value - return binascii.b2a_base64(encrypt(settings.AES_KEY, value)).decode('utf-8') + return binascii.b2a_base64(encrypt(settings.AES_KEY, value)).decode("utf-8") def formfield(self, **kwargs): - defaults = {'form_class': AESEncryptedFormField} + defaults = {"form_class": AESEncryptedFormField} defaults.update(kwargs) return super().formfield(**defaults) diff --git a/re2o/base.py b/re2o/base.py index 1397b1b0..e70c6612 100644 --- a/re2o/base.py +++ b/re2o/base.py @@ -36,31 +36,31 @@ from re2o.settings import EMAIL_HOST # Mapping of srtftime format for better understanding # https://docs.python.org/3.6/library/datetime.html#strftime-strptime-behavior -datetime_mapping={ - '%a': '%a', - '%A': '%A', - '%w': '%w', - '%d': 'dd', - '%b': '%b', - '%B': '%B', - '%m': 'mm', - '%y': 'yy', - '%Y': 'yyyy', - '%H': 'HH', - '%I': 'HH(12h)', - '%p': 'AMPM', - '%M': 'MM', - '%S': 'SS', - '%f': 'µµ', - '%z': 'UTC(+/-HHMM)', - '%Z': 'UTC(TZ)', - '%j': '%j', - '%U': 'ww', - '%W': 'ww', - '%c': '%c', - '%x': '%x', - '%X': '%X', - '%%': '%%', +datetime_mapping = { + "%a": "%a", + "%A": "%A", + "%w": "%w", + "%d": "dd", + "%b": "%b", + "%B": "%B", + "%m": "mm", + "%y": "yy", + "%Y": "yyyy", + "%H": "HH", + "%I": "HH(12h)", + "%p": "AMPM", + "%M": "MM", + "%S": "SS", + "%f": "µµ", + "%z": "UTC(+/-HHMM)", + "%Z": "UTC(TZ)", + "%j": "%j", + "%U": "ww", + "%W": "ww", + "%c": "%c", + "%x": "%x", + "%X": "%X", + "%%": "%%", } @@ -80,11 +80,11 @@ def smtp_check(local_part): def convert_datetime_format(format): - i=0 + i = 0 new_format = "" while i < len(format): - if format[i] == '%': - char = format[i:i+2] + if format[i] == "%": + char = format[i : i + 2] new_format += datetime_mapping.get(char, char) i += 2 else: @@ -96,15 +96,15 @@ def convert_datetime_format(format): def get_input_formats_help_text(input_formats): """Returns a help text about the possible input formats""" if len(input_formats) > 1: - help_text_template="Format: {main} {more}" + help_text_template = "Format: {main} {more}" else: - help_text_template="Format: {main}" - more_text_template="" + help_text_template = "Format: {main}" + more_text_template = '' help_text = help_text_template.format( main=convert_datetime_format(input_formats[0]), more=more_text_template.format( - '\n'.join(map(convert_datetime_format, input_formats)) - ) + "\n".join(map(convert_datetime_format, input_formats)) + ), ) return help_text @@ -123,121 +123,109 @@ class SortTable: # doesn't match any keys. USERS_INDEX = { - 'user_name': ['name'], - 'user_surname': ['surname'], - 'user_pseudo': ['pseudo'], - 'user_room': ['room'], - 'default': ['state', 'pseudo'] + "user_name": ["name"], + "user_surname": ["surname"], + "user_pseudo": ["pseudo"], + "user_room": ["room"], + "default": ["state", "pseudo"], } USERS_INDEX_BAN = { - 'ban_user': ['user__pseudo'], - 'ban_start': ['date_start'], - 'ban_end': ['date_end'], - 'default': ['-date_end'] + "ban_user": ["user__pseudo"], + "ban_start": ["date_start"], + "ban_end": ["date_end"], + "default": ["-date_end"], } USERS_INDEX_WHITE = { - 'white_user': ['user__pseudo'], - 'white_start': ['date_start'], - 'white_end': ['date_end'], - 'default': ['-date_end'] - } - USERS_INDEX_SCHOOL = { - 'school_name': ['name'], - 'default': ['name'] - } - MACHINES_INDEX = { - 'machine_name': ['name'], - 'default': ['pk'] + "white_user": ["user__pseudo"], + "white_start": ["date_start"], + "white_end": ["date_end"], + "default": ["-date_end"], } + USERS_INDEX_SCHOOL = {"school_name": ["name"], "default": ["name"]} + MACHINES_INDEX = {"machine_name": ["name"], "default": ["pk"]} COTISATIONS_INDEX = { - 'cotis_user': ['user__pseudo'], - 'cotis_paiement': ['paiement__moyen'], - 'cotis_date': ['date'], - 'cotis_id': ['id'], - 'default': ['-date'] + "cotis_user": ["user__pseudo"], + "cotis_paiement": ["paiement__moyen"], + "cotis_date": ["date"], + "cotis_id": ["id"], + "default": ["-date"], } COTISATIONS_CUSTOM = { - 'invoice_date': ['date'], - 'invoice_id': ['id'], - 'invoice_recipient': ['recipient'], - 'invoice_address': ['address'], - 'invoice_payment': ['payment'], - 'default': ['-date'] + "invoice_date": ["date"], + "invoice_id": ["id"], + "invoice_recipient": ["recipient"], + "invoice_address": ["address"], + "invoice_payment": ["payment"], + "default": ["-date"], } COTISATIONS_CONTROL = { - 'control_name': ['user__adherent__name'], - 'control_surname': ['user__surname'], - 'control_paiement': ['paiement'], - 'control_date': ['date'], - 'control_valid': ['valid'], - 'control_control': ['control'], - 'control_id': ['id'], - 'control_user-id': ['user__id'], - 'default': ['-date'] + "control_name": ["user__adherent__name"], + "control_surname": ["user__surname"], + "control_paiement": ["paiement"], + "control_date": ["date"], + "control_valid": ["valid"], + "control_control": ["control"], + "control_id": ["id"], + "control_user-id": ["user__id"], + "default": ["-date"], } TOPOLOGIE_INDEX = { - 'switch_dns': ['interface__domain__name'], - 'switch_ip': ['interface__ipv4__ipv4'], - 'switch_loc': ['switchbay__name'], - 'switch_ports': ['number'], - 'switch_stack': ['stack__name'], - 'default': ['switchbay', 'stack', 'stack_member_id'] + "switch_dns": ["interface__domain__name"], + "switch_ip": ["interface__ipv4__ipv4"], + "switch_loc": ["switchbay__name"], + "switch_ports": ["number"], + "switch_stack": ["stack__name"], + "default": ["switchbay", "stack", "stack_member_id"], } TOPOLOGIE_INDEX_PORT = { - 'port_port': ['port'], - 'port_room': ['room__name'], - 'port_interface': ['machine_interface__domain__name'], - 'port_related': ['related__switch__name'], - 'port_radius': ['radius'], - 'port_vlan': ['vlan_force__name'], - 'default': ['port'] + "port_port": ["port"], + "port_room": ["room__name"], + "port_interface": ["machine_interface__domain__name"], + "port_related": ["related__switch__name"], + "port_radius": ["radius"], + "port_vlan": ["vlan_force__name"], + "default": ["port"], } TOPOLOGIE_INDEX_ROOM = { - 'room_name': ['name'], - 'building_name': ['building__name'], - 'default': ['building__name', 'name'] - } - TOPOLOGIE_INDEX_BUILDING = { - 'building_name': ['name'], - 'default': ['name'] - } - TOPOLOGIE_INDEX_DORMITORY = { - 'dormitory_name': ['name'], - 'default': ['name'] + "room_name": ["name"], + "building_name": ["building__name"], + "default": ["building__name", "name"], } + TOPOLOGIE_INDEX_BUILDING = {"building_name": ["name"], "default": ["name"]} + TOPOLOGIE_INDEX_DORMITORY = {"dormitory_name": ["name"], "default": ["name"]} TOPOLOGIE_INDEX_BORNE = { - 'ap_name': ['interface__domain__name'], - 'ap_ip': ['interface__ipv4__ipv4'], - 'ap_mac': ['interface__mac_address'], - 'default': ['interface__domain__name'] + "ap_name": ["interface__domain__name"], + "ap_ip": ["interface__ipv4__ipv4"], + "ap_mac": ["interface__mac_address"], + "default": ["interface__domain__name"], } TOPOLOGIE_INDEX_STACK = { - 'stack_name': ['name'], - 'stack_id': ['stack_id'], - 'default': ['stack_id'], + "stack_name": ["name"], + "stack_id": ["stack_id"], + "default": ["stack_id"], } TOPOLOGIE_INDEX_MODEL_SWITCH = { - 'model-switch_name': ['reference'], - 'model-switch_contructor': ['constructor__name'], - 'default': ['reference'], + "model-switch_name": ["reference"], + "model-switch_contructor": ["constructor__name"], + "default": ["reference"], } TOPOLOGIE_INDEX_SWITCH_BAY = { - 'switch-bay_name': ['name'], - 'switch-bay_building': ['building__name'], - 'default': ['name'], + "switch-bay_name": ["name"], + "switch-bay_building": ["building__name"], + "default": ["name"], } TOPOLOGIE_INDEX_CONSTRUCTOR_SWITCH = { - 'constructor-switch_name': ['name'], - 'default': ['name'], + "constructor-switch_name": ["name"], + "default": ["name"], } LOGS_INDEX = { - 'sum_date': ['revision__date_created'], - 'default': ['-revision__date_created'], + "sum_date": ["revision__date_created"], + "default": ["-revision__date_created"], } LOGS_STATS_LOGS = { - 'logs_author': ['user__name'], - 'logs_date': ['date_created'], - 'default': ['-date_created'] + "logs_author": ["user__name"], + "logs_date": ["date_created"], + "default": ["-date_created"], } @staticmethod @@ -246,9 +234,9 @@ class SortTable: a .reverse() as specified according to those values """ fields = values.get(col, None) if not fields: - fields = values.get('default', []) + fields = values.get("default", []) request = request.order_by(*fields) - if values.get(col, None) and order == 'desc': + if values.get(col, None) and order == "desc": return request.reverse() else: return request @@ -260,7 +248,7 @@ def re2o_paginator(request, query_set, pagination_number): :query_set: Query_set to paginate :pagination_number: Number of entries to display""" paginator = Paginator(query_set, pagination_number) - page = request.GET.get('page') + page = request.GET.get("page") try: results = paginator.page(page) except PageNotAnInteger: diff --git a/re2o/context_processors.py b/re2o/context_processors.py index 97f2d4f8..4bda6712 100644 --- a/re2o/context_processors.py +++ b/re2o/context_processors.py @@ -32,14 +32,15 @@ from django.utils.translation import get_language from importlib import import_module from re2o.settings_local import OPTIONNAL_APPS_RE2O + def context_user(request): """Fonction de context lorsqu'un user est logué (ou non), renvoie les infos sur l'user, la liste de ses droits, ses machines""" user = request.user - if get_language()=='fr': - global_message = GeneralOption.get_cached_value('general_message_fr') + if get_language() == "fr": + global_message = GeneralOption.get_cached_value("general_message_fr") else: - global_message = GeneralOption.get_cached_value('general_message_en') + global_message = GeneralOption.get_cached_value("general_message_en") if global_message: if isinstance(request, HttpRequest): messages.warning(request, global_message) @@ -50,28 +51,39 @@ def context_user(request): else: interfaces = None return { - 'request_user': user, - 'interfaces': interfaces, + "request_user": user, + "interfaces": interfaces, # Must takes a different name because djang.auth.contrib.views.login() # overrides 'site_name' context variable. - 'name_website': GeneralOption.get_cached_value('site_name'), - 'ipv6_enabled': OptionalMachine.get_cached_value('ipv6'), + "name_website": GeneralOption.get_cached_value("site_name"), + "ipv6_enabled": OptionalMachine.get_cached_value("ipv6"), } + def context_optionnal_apps(request): """Fonction de context pour générer la navbar en fonction des apps optionnels""" optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] - optionnal_templates_navbar_user_list = [app.views.navbar_user() for app in optionnal_apps if hasattr(app.views, 'navbar_user')] - optionnal_templates_navbar_logout_list = [app.views.navbar_logout() for app in optionnal_apps if hasattr(app.views, 'navbar_logout')] - return {'optionnal_templates_navbar_user_list':optionnal_templates_navbar_user_list, - 'optionnal_templates_navbar_logout_list':optionnal_templates_navbar_logout_list} + optionnal_templates_navbar_user_list = [ + app.views.navbar_user() + for app in optionnal_apps + if hasattr(app.views, "navbar_user") + ] + optionnal_templates_navbar_logout_list = [ + app.views.navbar_logout() + for app in optionnal_apps + if hasattr(app.views, "navbar_logout") + ] + return { + "optionnal_templates_navbar_user_list": optionnal_templates_navbar_user_list, + "optionnal_templates_navbar_logout_list": optionnal_templates_navbar_logout_list, + } def date_now(request): """Add the current date in the context for quick informations and comparisons""" return { - 'now_aware': datetime.datetime.now(datetime.timezone.utc), - 'now_naive': datetime.datetime.now() + "now_aware": datetime.datetime.now(datetime.timezone.utc), + "now_naive": datetime.datetime.now(), } diff --git a/re2o/contributors.py b/re2o/contributors.py index e9851eb0..f8df11eb 100644 --- a/re2o/contributors.py +++ b/re2o/contributors.py @@ -18,7 +18,7 @@ CONTRIBUTORS = [ 'Pierre "Redstorm" Cadart', 'Éloi "Goslig" Alain', 'Laouen "Volgarr" Fernet', - 'Joanne Steiner', + "Joanne Steiner", '"Krokmou"', 'Thibault "Tipunchetrhum" de Boutray', 'Baptiste "B" Fournier', diff --git a/re2o/field_permissions.py b/re2o/field_permissions.py index b56711bd..90a904be 100644 --- a/re2o/field_permissions.py +++ b/re2o/field_permissions.py @@ -30,11 +30,13 @@ fields of the models, some fields will be removed if the user don't have the rights to change them (can_change_{name}) """ + class FieldPermissionModelMixin: """ The model mixin. Defines the `has_field_perm` function """ + field_permissions = {} # {'field_name': callable} - FIELD_PERM_CODENAME = 'can_change_{model}_{name}' - FIELD_PERMISSION_GETTER = 'can_change_{name}' + FIELD_PERM_CODENAME = "can_change_{model}_{name}" + FIELD_PERMISSION_GETTER = "can_change_{name}" FIELD_PERMISSION_MISSING_DEFAULT = True def has_field_perm(self, user, field): @@ -55,10 +57,9 @@ class FieldPermissionModelMixin: # Try to find a static permission for the field else: - perm_label = self.FIELD_PERM_CODENAME.format(**{ - 'model': self._meta.model_name, - 'name': field, - }) + perm_label = self.FIELD_PERM_CODENAME.format( + **{"model": self._meta.model_name, "name": field} + ) if perm_label in dict(self._meta.permissions): checks.append(perm_label) @@ -86,8 +87,9 @@ class FieldPermissionFormMixin: """ Construit le formulaire et retire les champs interdits """ + def __init__(self, *args, **kwargs): - user = kwargs.pop('user') + user = kwargs.pop("user") super(FieldPermissionFormMixin, self).__init__(*args, **kwargs) to_be_deleted = [] diff --git a/re2o/login.py b/re2o/login.py index 559636ce..1f6989f3 100644 --- a/re2o/login.py +++ b/re2o/login.py @@ -54,7 +54,7 @@ def makeSecret(password): def hashNT(password): """ Build a md4 hash of the password to use as the NT-password """ - hash_str = hashlib.new('md4', password.encode('utf-16le')).digest() + hash_str = hashlib.new("md4", password.encode("utf-16le")).digest() return binascii.hexlify(hash_str).upper() @@ -70,13 +70,13 @@ def checkPassword(challenge_password, password): def hash_password_salt(hashed_password): """ Extract the salt from a given hashed password """ - if hashed_password.upper().startswith('{CRYPT}'): + if hashed_password.upper().startswith("{CRYPT}"): hashed_password = hashed_password[7:] - if hashed_password.startswith('$'): - return '$'.join(hashed_password.split('$')[:-1]) + if hashed_password.startswith("$"): + return "$".join(hashed_password.split("$")[:-1]) else: return hashed_password[:2] - elif hashed_password.upper().startswith('{SSHA}'): + elif hashed_password.upper().startswith("{SSHA}"): try: digest = b64decode(hashed_password[6:]) except TypeError as error: @@ -84,7 +84,7 @@ def hash_password_salt(hashed_password): if len(digest) < 20: raise ValueError("`hashed_password` too short") return digest[20:] - elif hashed_password.upper().startswith('{SMD5}'): + elif hashed_password.upper().startswith("{SMD5}"): try: digest = b64decode(hashed_password[7:]) except TypeError as error: @@ -93,8 +93,9 @@ def hash_password_salt(hashed_password): raise ValueError("`hashed_password` too short") return digest[16:] else: - raise ValueError("`hashed_password` should start with '{SSHA}' or '{CRYPT}' or '{SMD5}'") - + raise ValueError( + "`hashed_password` should start with '{SSHA}' or '{CRYPT}' or '{SMD5}'" + ) class CryptPasswordHasher(hashers.BasePasswordHasher): @@ -115,8 +116,9 @@ class CryptPasswordHasher(hashers.BasePasswordHasher): """ assert encoded.startswith(self.algorithm) salt = hash_password_salt(encoded) - return constant_time_compare(self.algorithm + crypt.crypt(password, salt), - encoded) + return constant_time_compare( + self.algorithm + crypt.crypt(password, salt), encoded + ) def safe_summary(self, encoded): """ @@ -125,12 +127,14 @@ class CryptPasswordHasher(hashers.BasePasswordHasher): assert encoded.startswith(self.algorithm) hash_str = encoded[7:] hash_str = binascii.hexlify(decodestring(hash_str.encode())).decode() - return OrderedDict([ - ('algorithm', self.algorithm), - ('iterations', 0), - ('salt', hashers.mask_hash(hash_str[2*DIGEST_LEN:], show=2)), - ('hash', hashers.mask_hash(hash_str[:2*DIGEST_LEN])), - ]) + return OrderedDict( + [ + ("algorithm", self.algorithm), + ("iterations", 0), + ("salt", hashers.mask_hash(hash_str[2 * DIGEST_LEN :], show=2)), + ("hash", hashers.mask_hash(hash_str[: 2 * DIGEST_LEN])), + ] + ) def harden_runtime(self, password, encoded): """ @@ -140,6 +144,7 @@ class CryptPasswordHasher(hashers.BasePasswordHasher): """ pass + class MD5PasswordHasher(hashers.BasePasswordHasher): """ Salted MD5 password hashing to allow for LDAP auth compatibility @@ -157,9 +162,12 @@ class MD5PasswordHasher(hashers.BasePasswordHasher): """ assert encoded.startswith(self.algorithm) salt = hash_password_salt(encoded) - return constant_time_compare(self.algorithm + "$" + - b64encode(hashlib.md5(password.encode() + salt).digest() + salt).decode(), - encoded) + return constant_time_compare( + self.algorithm + + "$" + + b64encode(hashlib.md5(password.encode() + salt).digest() + salt).decode(), + encoded, + ) def safe_summary(self, encoded): """ @@ -168,12 +176,14 @@ class MD5PasswordHasher(hashers.BasePasswordHasher): assert encoded.startswith(self.algorithm) hash_str = encoded[7:] hash_str = binascii.hexlify(decodestring(hash_str.encode())).decode() - return OrderedDict([ - ('algorithm', self.algorithm), - ('iterations', 0), - ('salt', hashers.mask_hash(hash_str[2*DIGEST_LEN:], show=2)), - ('hash', hashers.mask_hash(hash_str[:2*DIGEST_LEN])), - ]) + return OrderedDict( + [ + ("algorithm", self.algorithm), + ("iterations", 0), + ("salt", hashers.mask_hash(hash_str[2 * DIGEST_LEN :], show=2)), + ("hash", hashers.mask_hash(hash_str[: 2 * DIGEST_LEN])), + ] + ) def harden_runtime(self, password, encoded): """ @@ -183,6 +193,7 @@ class MD5PasswordHasher(hashers.BasePasswordHasher): """ pass + class SSHAPasswordHasher(hashers.BasePasswordHasher): """ Salted SHA-1 password hashing to allow for LDAP auth compatibility @@ -213,12 +224,14 @@ class SSHAPasswordHasher(hashers.BasePasswordHasher): assert encoded.startswith(self.algorithm) hash_str = encoded[ALGO_LEN:] hash_str = binascii.hexlify(decodestring(hash_str.encode())).decode() - return OrderedDict([ - ('algorithm', self.algorithm), - ('iterations', 0), - ('salt', hashers.mask_hash(hash_str[2*DIGEST_LEN:], show=2)), - ('hash', hashers.mask_hash(hash_str[:2*DIGEST_LEN])), - ]) + return OrderedDict( + [ + ("algorithm", self.algorithm), + ("iterations", 0), + ("salt", hashers.mask_hash(hash_str[2 * DIGEST_LEN :], show=2)), + ("hash", hashers.mask_hash(hash_str[: 2 * DIGEST_LEN])), + ] + ) def harden_runtime(self, password, encoded): """ @@ -234,11 +247,11 @@ class RecryptBackend(ModelBackend): # we obtain from the classical auth backend the user user = super(RecryptBackend, self).authenticate(None, username, password) if user: - if not(user.pwd_ntlm): + if not (user.pwd_ntlm): # if we dont have NT hash, we create it user.pwd_ntlm = hashNT(password) user.save() - if not("SSHA" in user.password): + if not ("SSHA" in user.password): # if the hash is too old, we update it user.password = makeSecret(password) user.save() diff --git a/re2o/management/commands/gen_contrib.py b/re2o/management/commands/gen_contrib.py index 2b0afd39..e8de851b 100644 --- a/re2o/management/commands/gen_contrib.py +++ b/re2o/management/commands/gen_contrib.py @@ -30,7 +30,8 @@ from django.core.management.base import BaseCommand class Command(BaseCommand): """ The command object for `gen_contrib` """ - help = 'Update contributors list' + + help = "Update contributors list" @staticmethod def _contrib_file_generator(contributors): @@ -38,9 +39,9 @@ class Command(BaseCommand): Generate the content of contributors.py """ buffer = "# -*- mode: python; coding: utf-8 -*-\n" - buffer += "\"\"\"re2o.contributors\n" + buffer += '"""re2o.contributors\n' buffer += "A list of the proud contributors to Re2o\n" - buffer += "\"\"\"\n" + buffer += '"""\n' buffer += "\n" buffer += "CONTRIBUTORS = [\n" for name in contributors: @@ -59,9 +60,9 @@ class Command(BaseCommand): def handle(self, *args, **options): contributors = [ - item.split('\t')[1] + item.split("\t")[1] for item in os.popen("git shortlog -s -n").read().split("\n") - if '\t' in item + if "\t" in item ] self.stdout.write(self.style.SUCCESS("Exportation Successful")) with open("re2o/contributors.py", "w") as contrib_file: diff --git a/re2o/middleware.py b/re2o/middleware.py index 9a884fad..5ff3df60 100644 --- a/re2o/middleware.py +++ b/re2o/middleware.py @@ -36,8 +36,11 @@ def show_debug_toolbar(request): Returns: The boolean indicating if the debug toolbar should be shown. """ - if hasattr(settings, 'INTERNAL_IPS') and settings.INTERNAL_IPS and \ - request.META.get('REMOTE_ADDR', None) not in settings.INTERNAL_IPS: + if ( + hasattr(settings, "INTERNAL_IPS") + and settings.INTERNAL_IPS + and request.META.get("REMOTE_ADDR", None) not in settings.INTERNAL_IPS + ): return False return bool(settings.DEBUG) diff --git a/re2o/mixins.py b/re2o/mixins.py index dfa6e987..4766d657 100644 --- a/re2o/mixins.py +++ b/re2o/mixins.py @@ -32,6 +32,7 @@ class RevMixin(object): """ A mixin to subclass the save and delete function of a model to enforce the versioning of the object before those actions really happen """ + def save(self, *args, **kwargs): """ Creates a version of this object and save it to database """ if self.pk is None: @@ -50,17 +51,18 @@ class RevMixin(object): class FormRevMixin(object): """ A mixin to subclass the save function of a form to enforce the versionning of the object before it is really edited """ + def save(self, *args, **kwargs): """ Create a version of this object and save it to database """ if reversion.get_comment() != "" and self.changed_data != []: reversion.set_comment( - reversion.get_comment() + ",%s" - % ', '.join(field for field in self.changed_data) + reversion.get_comment() + + ",%s" % ", ".join(field for field in self.changed_data) ) elif self.changed_data: reversion.set_comment( "Field(s) altered : %s" - % ', '.join(field for field in self.changed_data) + % ", ".join(field for field in self.changed_data) ) return super(FormRevMixin, self).save(*args, **kwargs) @@ -88,14 +90,14 @@ class AclMixin(object): @classmethod def get_modulename(cls): """ Returns the name of the module where this mixin is used """ - return str(cls.__module__).split('.')[0].lower() + return str(cls.__module__).split(".")[0].lower() @classmethod def get_instance(cls, *_args, **kwargs): """Récupère une instance :param objectid: Instance id à trouver :return: Une instance de la classe évidemment""" - object_id = kwargs.get(cls.get_classname() + 'id') + object_id = kwargs.get(cls.get_classname() + "id") return cls.objects.get(pk=object_id) @classmethod @@ -104,13 +106,14 @@ class AclMixin(object): un object :param user_request: instance utilisateur qui fait la requête :return: soit True, soit False avec la raison de l'échec""" - permission = cls.get_modulename() + '.add_' + cls.get_classname() + permission = cls.get_modulename() + ".add_" + cls.get_classname() can = user_request.has_perm(permission) return ( can, - _("You don't have the right to create a %s object.") - % cls.get_classname() if not can else None, - (permission,) + _("You don't have the right to create a %s object.") % cls.get_classname() + if not can + else None, + (permission,), ) def can_edit(self, user_request, *_args, **_kwargs): @@ -119,13 +122,14 @@ class AclMixin(object): :param self: Instance à editer :param user_request: Utilisateur qui fait la requête :return: soit True, soit False avec la raison de l'échec""" - permission = self.get_modulename() + '.change_' + self.get_classname() + permission = self.get_modulename() + ".change_" + self.get_classname() can = user_request.has_perm(permission) return ( can, - _("You don't have the right to edit a %s object.") - % self.get_classname() if not can else None, - (permission,) + _("You don't have the right to edit a %s object.") % self.get_classname() + if not can + else None, + (permission,), ) def can_delete(self, user_request, *_args, **_kwargs): @@ -134,13 +138,14 @@ class AclMixin(object): :param self: Instance à delete :param user_request: Utilisateur qui fait la requête :return: soit True, soit False avec la raison de l'échec""" - permission = self.get_modulename() + '.delete_' + self.get_classname() + permission = self.get_modulename() + ".delete_" + self.get_classname() can = user_request.has_perm(permission) return ( can, - _("You don't have the right to delete a %s object.") - % self.get_classname() if not can else None, - (permission,) + _("You don't have the right to delete a %s object.") % self.get_classname() + if not can + else None, + (permission,), ) @classmethod @@ -149,13 +154,14 @@ class AclMixin(object): droit particulier view objet correspondant :param user_request: instance user qui fait l'edition :return: True ou False avec la raison de l'échec le cas échéant""" - permission = cls.get_modulename() + '.view_' + cls.get_classname() + permission = cls.get_modulename() + ".view_" + cls.get_classname() can = user_request.has_perm(permission) return ( can, - _("You don't have the right to view every %s object.") - % cls.get_classname() if not can else None, - (permission,) + _("You don't have the right to view every %s object.") % cls.get_classname() + if not can + else None, + (permission,), ) def can_view(self, user_request, *_args, **_kwargs): @@ -164,12 +170,12 @@ class AclMixin(object): :param self: instance à voir :param user_request: instance user qui fait l'edition :return: True ou False avec la raison de l'échec le cas échéant""" - permission = self.get_modulename() + '.view_' + self.get_classname() + permission = self.get_modulename() + ".view_" + self.get_classname() can = user_request.has_perm(permission) return ( can, - _("You don't have the right to view a %s object.") - % self.get_classname() if not can else None, - (permission,) + _("You don't have the right to view a %s object.") % self.get_classname() + if not can + else None, + (permission,), ) - diff --git a/re2o/script_utils.py b/re2o/script_utils.py index 92c00fab..539f4723 100644 --- a/re2o/script_utils.py +++ b/re2o/script_utils.py @@ -52,8 +52,9 @@ def get_user(pseudo): if len(user) == 0: raise CommandError("Invalid user.") if len(user) > 1: - raise CommandError("Several users match this username. This SHOULD" - " NOT happen.") + raise CommandError( + "Several users match this username. This SHOULD" " NOT happen." + ) return user[0] @@ -73,8 +74,8 @@ def form_cli(Form, user, action, *args, **kwargs): data = {} dumb_form = Form(user=user, *args, **kwargs) for key in dumb_form.fields: - if not dumb_form.fields[key].widget.input_type == 'hidden': - if dumb_form.fields[key].widget.input_type == 'password': + if not dumb_form.fields[key].widget.input_type == "hidden": + if dumb_form.fields[key].widget.input_type == "password": data[key] = getpass("%s : " % dumb_form.fields[key].label) else: data[key] = input("%s : " % dumb_form.fields[key].label) @@ -85,9 +86,7 @@ def form_cli(Form, user, action, *args, **kwargs): for err in form.errors: # Oui, oui, on gère du HTML là où d'autres ont eu la # lumineuse idée de le mettre - sys.stderr.write( - "\t%s : %s\n" % (err, strip_tags(form.errors[err])) - ) + sys.stderr.write("\t%s : %s\n" % (err, strip_tags(form.errors[err]))) raise CommandError("Invalid form.") with transaction.atomic(), reversion.create_revision(): @@ -95,5 +94,6 @@ def form_cli(Form, user, action, *args, **kwargs): reversion.set_user(user) reversion.set_comment(action) - sys.stdout.write("%s : done. The edit may take several minutes to" - " apply.\n" % action) + sys.stdout.write( + "%s : done. The edit may take several minutes to" " apply.\n" % action + ) diff --git a/re2o/settings.py b/re2o/settings.py index 34ad0981..3d883615 100644 --- a/re2o/settings.py +++ b/re2o/settings.py @@ -45,106 +45,99 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Auth definition PASSWORD_HASHERS = ( - 're2o.login.SSHAPasswordHasher', - 're2o.login.MD5PasswordHasher', - 're2o.login.CryptPasswordHasher', - 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + "re2o.login.SSHAPasswordHasher", + "re2o.login.MD5PasswordHasher", + "re2o.login.CryptPasswordHasher", + "django.contrib.auth.hashers.PBKDF2PasswordHasher", ) -AUTH_USER_MODEL = 'users.User' # The class to use for authentication -LOGIN_URL = '/login/' # The URL for login page -LOGIN_REDIRECT_URL = '/' # The URL for redirecting after login +AUTH_USER_MODEL = "users.User" # The class to use for authentication +LOGIN_URL = "/login/" # The URL for login page +LOGIN_REDIRECT_URL = "/" # The URL for redirecting after login # Application definition DJANGO_CONTRIB_APPS = ( - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'django.contrib.humanize', -) -EXTERNAL_CONTRIB_APPS = ( - 'bootstrap3', - 'rest_framework', - 'reversion', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django.contrib.humanize", ) +EXTERNAL_CONTRIB_APPS = ("bootstrap3", "rest_framework", "reversion") LOCAL_APPS = ( - 'users', - 'machines', - 'cotisations', - 'topologie', - 'search', - 're2o', - 'preferences', - 'logs', + "users", + "machines", + "cotisations", + "topologie", + "search", + "re2o", + "preferences", + "logs", ) INSTALLED_APPS = ( - DJANGO_CONTRIB_APPS + - EXTERNAL_CONTRIB_APPS + - LOCAL_APPS + - OPTIONNAL_APPS + DJANGO_CONTRIB_APPS + EXTERNAL_CONTRIB_APPS + LOCAL_APPS + OPTIONNAL_APPS ) MIDDLEWARE_CLASSES = ( - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'django.middleware.security.SecurityMiddleware', - 'reversion.middleware.RevisionMiddleware', + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.auth.middleware.SessionAuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django.middleware.security.SecurityMiddleware", + "reversion.middleware.RevisionMiddleware", ) -AUTHENTICATION_BACKENDS = ['re2o.login.RecryptBackend'] +AUTHENTICATION_BACKENDS = ["re2o.login.RecryptBackend"] # Include debug_toolbar middleware if activated -if 'debug_toolbar' in INSTALLED_APPS: +if "debug_toolbar" in INSTALLED_APPS: # Include this middleware at the beggining MIDDLEWARE_CLASSES = ( - 'debug_toolbar.middleware.DebugToolbarMiddleware', + "debug_toolbar.middleware.DebugToolbarMiddleware", ) + MIDDLEWARE_CLASSES # Change the default show_toolbar middleware DEBUG_TOOLBAR_CONFIG = { - 'SHOW_TOOLBAR_CALLBACK': 're2o.middleware.show_debug_toolbar' + "SHOW_TOOLBAR_CALLBACK": "re2o.middleware.show_debug_toolbar" } # The root url module to define the project URLs -ROOT_URLCONF = 're2o.urls' +ROOT_URLCONF = "re2o.urls" # The templates configuration (see Django documentation) TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [ # Use only absolute paths with '/' delimiters even on Windows - os.path.join(BASE_DIR, 'templates').replace('\\', '/'), - os.path.join(BASE_DIR, 'media', 'templates').replace('\\', '/'), + os.path.join(BASE_DIR, "templates").replace("\\", "/"), + os.path.join(BASE_DIR, "media", "templates").replace("\\", "/"), ], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'django.template.context_processors.request', - 're2o.context_processors.context_user', - 're2o.context_processors.context_optionnal_apps', - 're2o.context_processors.date_now', - ], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "django.template.context_processors.request", + "re2o.context_processors.context_user", + "re2o.context_processors.context_optionnal_apps", + "re2o.context_processors.date_now", + ] }, - }, + } ] # The WSGI module to use in a server environment -WSGI_APPLICATION = 're2o.wsgi.application' +WSGI_APPLICATION = "re2o.wsgi.application" # Internationalization # https://docs.djangoproject.com/en/1.8/topics/i18n/ -LANGUAGE_CODE = 'en' +LANGUAGE_CODE = "en" USE_I18N = True USE_L10N = True # Proritary location search for translations @@ -152,49 +145,44 @@ USE_L10N = True # Use only absolute paths with '/' delimiters even on Windows LOCALE_PATHS = [ # For translations outside of apps - os.path.join(BASE_DIR, 'templates', 'locale').replace('\\', '/') -] -LANGUAGES = [ - ('en', _('English')), - ('fr', _('French')) + os.path.join(BASE_DIR, "templates", "locale").replace("\\", "/") ] +LANGUAGES = [("en", _("English")), ("fr", _("French"))] # Should use time zone ? USE_TZ = True # Router config for database -DATABASE_ROUTERS = ['ldapdb.router.Router'] +DATABASE_ROUTERS = ["ldapdb.router.Router"] # django-bootstrap3 config BOOTSTRAP3 = { - 'jquery_url': '/javascript/jquery/jquery.min.js', - 'base_url': '/javascript/bootstrap/', - 'include_jquery': True, + "jquery_url": "/javascript/jquery/jquery.min.js", + "base_url": "/javascript/bootstrap/", + "include_jquery": True, } -BOOTSTRAP_BASE_URL = '/javascript/bootstrap/' +BOOTSTRAP_BASE_URL = "/javascript/bootstrap/" # Directories where collectstatic should look for static files # Use only absolute paths with '/' delimiters even on Windows STATICFILES_DIRS = ( - os.path.join(BASE_DIR, 'static').replace('\\', '/'), + os.path.join(BASE_DIR, "static").replace("\\", "/"), "/usr/share/fonts-font-awesome/", ) # Directory where the static files served by the server are stored -STATIC_ROOT = os.path.join(BASE_DIR, 'static_files') +STATIC_ROOT = os.path.join(BASE_DIR, "static_files") # The URL to access the static files -STATIC_URL = '/static/' +STATIC_URL = "/static/" # Directory where the media files served by the server are stored -MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/') +MEDIA_ROOT = os.path.join(BASE_DIR, "media").replace("\\", "/") # The URL to access the static files -MEDIA_URL = os.path.join(BASE_DIR,'/media/') +MEDIA_URL = os.path.join(BASE_DIR, "/media/") # Models to use for graphs -GRAPH_MODELS = { - 'all_applications': True, - 'group_models': True, -} +GRAPH_MODELS = {"all_applications": True, "group_models": True} # Activate API -if 'api' in INSTALLED_APPS: +if "api" in INSTALLED_APPS: from api.settings import * + INSTALLED_APPS += API_APPS diff --git a/re2o/settings_local.example.py b/re2o/settings_local.example.py index bb4efa45..c4ec9ff2 100644 --- a/re2o/settings_local.example.py +++ b/re2o/settings_local.example.py @@ -27,48 +27,45 @@ The file with all the available options for a locale configuration of re2o from __future__ import unicode_literals # A secret key used by the server. -SECRET_KEY = 'SUPER_SECRET_KEY' +SECRET_KEY = "SUPER_SECRET_KEY" # The password to access the project database -DB_PASSWORD = 'SUPER_SECRET_DB' +DB_PASSWORD = "SUPER_SECRET_DB" # AES key for secret key encryption. # The length must be a multiple of 16 -AES_KEY = 'A_SECRET_AES_KEY' +AES_KEY = "A_SECRET_AES_KEY" # Should the server run in debug mode ? # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False # A list of admins of the services. Receive mails when an error occurs -ADMINS = [('Example', 'admin@example.net')] +ADMINS = [("Example", "admin@example.net")] # The list of hostname the server will respond to. -ALLOWED_HOSTS = ['URL_SERVER'] +ALLOWED_HOSTS = ["URL_SERVER"] # The time zone the server is runned in -TIME_ZONE = 'Europe/Paris' +TIME_ZONE = "Europe/Paris" # The storage systems parameters to use DATABASES = { - 'default': { # The DB - 'ENGINE': 'db_engine', - 'NAME': 'db_name_value', - 'USER': 'db_user_value', - 'PASSWORD': DB_PASSWORD, - 'HOST': 'db_host_value', - 'TEST': { - 'CHARSET': 'utf8', - 'COLLATION': 'utf8_general_ci' - } + "default": { # The DB + "ENGINE": "db_engine", + "NAME": "db_name_value", + "USER": "db_user_value", + "PASSWORD": DB_PASSWORD, + "HOST": "db_host_value", + "TEST": {"CHARSET": "utf8", "COLLATION": "utf8_general_ci"}, + }, + "ldap": { # The LDAP + "ENGINE": "ldapdb.backends.ldap", + "NAME": "ldap://ldap_host_ip/", + "USER": "ldap_dn", + "TLS": True, + "PASSWORD": "SUPER_SECRET_LDAP", }, - 'ldap': { # The LDAP - 'ENGINE': 'ldapdb.backends.ldap', - 'NAME': 'ldap://ldap_host_ip/', - 'USER': 'ldap_dn', - 'TLS': True, - 'PASSWORD': 'SUPER_SECRET_LDAP', - } } # Security settings for secure https @@ -78,36 +75,31 @@ SECURE_BROWSER_XSS_FILTER = False SESSION_COOKIE_SECURE = False CSRF_COOKIE_SECURE = False CSRF_COOKIE_HTTPONLY = False -X_FRAME_OPTIONS = 'DENY' +X_FRAME_OPTIONS = "DENY" SESSION_COOKIE_AGE = 60 * 60 * 3 # The path where your organization logo is stored LOGO_PATH = "static_files/logo.png" # The mail configuration for Re2o to send mails -SERVER_EMAIL = 'no-reply@example.net' # The mail address to use -EMAIL_HOST = 'MY_EMAIL_HOST' # The host to use -EMAIL_PORT = MY_EMAIL_PORT # The port to use +SERVER_EMAIL = "no-reply@example.net" # The mail address to use +EMAIL_HOST = "MY_EMAIL_HOST" # The host to use +EMAIL_PORT = MY_EMAIL_PORT # The port to use # Settings of the LDAP structure LDAP = { - 'base_user_dn': 'cn=Utilisateurs,dc=example,dc=net', - 'base_userservice_dn': 'ou=service-users,dc=example,dc=net', - 'base_usergroup_dn': 'ou=posix,ou=groups,dc=example,dc=net', - 'base_userservicegroup_dn': 'ou=services,ou=groups,dc=example,dc=net', - 'user_gid': 500, - } + "base_user_dn": "cn=Utilisateurs,dc=example,dc=net", + "base_userservice_dn": "ou=service-users,dc=example,dc=net", + "base_usergroup_dn": "ou=posix,ou=groups,dc=example,dc=net", + "base_userservicegroup_dn": "ou=services,ou=groups,dc=example,dc=net", + "user_gid": 500, +} # A range of UID to use. Used in linux environement -UID_RANGES = { - 'users': [21001, 30000], - 'service-users': [20000, 21000], -} +UID_RANGES = {"users": [21001, 30000], "service-users": [20000, 21000]} # A range of GID to use. Used in linux environement -GID_RANGES = { - 'posix': [501, 600], -} +GID_RANGES = {"posix": [501, 600]} # Some optionnal Re2o Apps OPTIONNAL_APPS_RE2O = () diff --git a/re2o/templatetags/acl.py b/re2o/templatetags/acl.py index f32c8507..095a3717 100644 --- a/re2o/templatetags/acl.py +++ b/re2o/templatetags/acl.py @@ -82,7 +82,7 @@ register = template.Library() def get_model(model_name): """Retrieve the model object from its name""" - splitted = model_name.split('.') + splitted = model_name.split(".") if len(splitted) > 1: try: app_label, name = splitted @@ -95,8 +95,7 @@ def get_model(model_name): try: if app_label is not None: content_type = ContentType.objects.get( - model=name.lower(), - app_label=app_label + model=name.lower(), app_label=app_label ) else: content_type = ContentType.objects.get(model=name.lower()) @@ -106,8 +105,7 @@ def get_model(model_name): ) except ContentType.MultipleObjectsReturned: raise template.TemplateSyntaxError( - "More than one model found for %r. Try with `app.model`." - % model_name + "More than one model found for %r. Try with `app.model`." % model_name ) return content_type.model_class() @@ -115,76 +113,72 @@ def get_model(model_name): def get_callback(tag_name, obj=None): """Return the right function to call back to check for acl""" - if tag_name == 'can_create': + if tag_name == "can_create": return acl_fct(obj.can_create, False) - if tag_name == 'cannot_create': + if tag_name == "cannot_create": return acl_fct(obj.can_create, True) - if tag_name == 'can_edit': + if tag_name == "can_edit": return acl_fct(obj.can_edit, False) - if tag_name == 'cannot_edit': + if tag_name == "cannot_edit": return acl_fct(obj.can_edit, True) - if tag_name == 'can_edit_all': + if tag_name == "can_edit_all": return acl_fct(obj.can_edit_all, False) - if tag_name == 'cannot_edit_all': + if tag_name == "cannot_edit_all": return acl_fct(obj.can_edit_all, True) - if tag_name == 'can_delete': + if tag_name == "can_delete": return acl_fct(obj.can_delete, False) - if tag_name == 'cannot_delete': + if tag_name == "cannot_delete": return acl_fct(obj.can_delete, True) - if tag_name == 'can_delete_all': + if tag_name == "can_delete_all": return acl_fct(obj.can_delete_all, False) - if tag_name == 'cannot_delete_all': + if tag_name == "cannot_delete_all": return acl_fct(obj.can_delete_all, True) - if tag_name == 'can_view': + if tag_name == "can_view": return acl_fct(obj.can_view, False) - if tag_name == 'cannot_view': + if tag_name == "cannot_view": return acl_fct(obj.can_view, True) - if tag_name == 'can_view_all': + if tag_name == "can_view_all": return acl_fct(obj.can_view_all, False) - if tag_name == 'cannot_view_all': + if tag_name == "cannot_view_all": return acl_fct(obj.can_view_all, True) - if tag_name == 'can_view_app': + if tag_name == "can_view_app": return acl_fct( lambda x: ( not any(not sys.modules[o].can_view(x)[0] for o in obj), None, - None + None, ), - False + False, ) - if tag_name == 'cannot_view_app': + if tag_name == "cannot_view_app": return acl_fct( lambda x: ( not any(not sys.modules[o].can_view(x)[0] for o in obj), None, - None + None, ), - True + True, ) - if tag_name == 'can_edit_history': + if tag_name == "can_edit_history": return acl_fct( - lambda user: (user.has_perm('admin.change_logentry'), None, None), - False + lambda user: (user.has_perm("admin.change_logentry"), None, None), False ) - if tag_name == 'cannot_edit_history': + if tag_name == "cannot_edit_history": return acl_fct( - lambda user: (user.has_perm('admin.change_logentry'), None, None), - True + lambda user: (user.has_perm("admin.change_logentry"), None, None), True ) - if tag_name == 'can_view_any_app': + if tag_name == "can_view_any_app": return acl_fct( lambda x: (any(sys.modules[o].can_view(x)[0] for o in obj), None, None), - False + False, ) - if tag_name == 'cannot_view_any_app': + if tag_name == "cannot_view_any_app": return acl_fct( lambda x: (any(sys.modules[o].can_view(x)[0] for o in obj), None, None), - True + True, ) - raise template.TemplateSyntaxError( - "%r tag is not a valid can_xxx tag" % tag_name - ) + raise template.TemplateSyntaxError("%r tag is not a valid can_xxx tag" % tag_name) def acl_fct(callback, reverse): @@ -202,30 +196,30 @@ def acl_fct(callback, reverse): return acl_fct_reverse if reverse else acl_fct_normal -@register.tag('can_edit_history') -@register.tag('cannot_edit_history') +@register.tag("can_edit_history") +@register.tag("cannot_edit_history") def acl_history_filter(parser, token): """Templatetag for acl checking on history.""" tag_name, = token.split_contents() callback = get_callback(tag_name) - oknodes = parser.parse(('acl_else', 'acl_end')) + oknodes = parser.parse(("acl_else", "acl_end")) token = parser.next_token() - if token.contents == 'acl_else': - konodes = parser.parse(('acl_end')) + if token.contents == "acl_else": + konodes = parser.parse(("acl_end")) token = parser.next_token() else: konodes = NodeList() - assert token.contents == 'acl_end' + assert token.contents == "acl_end" return AclNode(tag_name, callback, oknodes, konodes) -@register.tag('can_view_any_app') -@register.tag('cannot_view_any_app') -@register.tag('can_view_app') -@register.tag('cannot_view_app') +@register.tag("can_view_any_app") +@register.tag("cannot_view_any_app") +@register.tag("can_view_app") +@register.tag("cannot_view_app") def acl_app_filter(parser, token): """Templatetag for acl checking on applications.""" try: @@ -234,33 +228,31 @@ def acl_app_filter(parser, token): app_name = contents[1:] except ValueError: raise template.TemplateSyntaxError( - "%r tag require 1 argument: an application" - % token.contents.split()[0] + "%r tag require 1 argument: an application" % token.contents.split()[0] ) for name in app_name: if name not in sys.modules.keys(): raise template.TemplateSyntaxError( - "%r is not a registered application for acl." - % name + "%r is not a registered application for acl." % name ) callback = get_callback(tag_name, app_name) - oknodes = parser.parse(('acl_else', 'acl_end')) + oknodes = parser.parse(("acl_else", "acl_end")) token = parser.next_token() - if token.contents == 'acl_else': - konodes = parser.parse(('acl_end')) + if token.contents == "acl_else": + konodes = parser.parse(("acl_end")) token = parser.next_token() else: konodes = NodeList() - assert token.contents == 'acl_end' + assert token.contents == "acl_end" return AclNode(tag_name, callback, oknodes, konodes) -@register.tag('can_change') -@register.tag('cannot_change') +@register.tag("can_change") +@register.tag("cannot_change") def acl_change_filter(parser, token): """Templatetag for acl checking a can_change_xxx function""" @@ -277,33 +269,33 @@ def acl_change_filter(parser, token): ) model = get_model(model_name) - callback = getattr(model, 'can_change_'+field_name) + callback = getattr(model, "can_change_" + field_name) # {% can_create %} - oknodes = parser.parse(('acl_else', 'acl_end')) + oknodes = parser.parse(("acl_else", "acl_end")) token = parser.next_token() # {% can_create_else %} - if token.contents == 'acl_else': - konodes = parser.parse(('acl_end')) + if token.contents == "acl_else": + konodes = parser.parse(("acl_end")) token = parser.next_token() else: konodes = NodeList() # {% can_create_end %} - assert token.contents == 'acl_end' + assert token.contents == "acl_end" return AclNode(tag_name, callback, oknodes, konodes, *args) -@register.tag('can_create') -@register.tag('cannot_create') -@register.tag('can_edit_all') -@register.tag('cannot_edit_all') -@register.tag('can_delete_all') -@register.tag('cannot_delete_all') -@register.tag('can_view_all') -@register.tag('cannot_view_all') +@register.tag("can_create") +@register.tag("cannot_create") +@register.tag("can_edit_all") +@register.tag("cannot_edit_all") +@register.tag("can_delete_all") +@register.tag("cannot_delete_all") +@register.tag("can_view_all") +@register.tag("cannot_view_all") def acl_model_filter(parser, token): """Generic definition of an acl templatetag for acl based on model""" @@ -314,36 +306,35 @@ def acl_model_filter(parser, token): args = tag_content[2:] except ValueError: raise template.TemplateSyntaxError( - "%r tag require at least 1 argument: the model" - % token.contents.split()[0] + "%r tag require at least 1 argument: the model" % token.contents.split()[0] ) model = get_model(model_name) callback = get_callback(tag_name, model) # {% can_create %} - oknodes = parser.parse(('acl_else', 'acl_end')) + oknodes = parser.parse(("acl_else", "acl_end")) token = parser.next_token() # {% can_create_else %} - if token.contents == 'acl_else': - konodes = parser.parse(('acl_end')) + if token.contents == "acl_else": + konodes = parser.parse(("acl_end")) token = parser.next_token() else: konodes = NodeList() # {% can_create_end %} - assert token.contents == 'acl_end' + assert token.contents == "acl_end" return AclNode(tag_name, callback, oknodes, konodes, *args) -@register.tag('can_edit') -@register.tag('cannot_edit') -@register.tag('can_delete') -@register.tag('cannot_delete') -@register.tag('can_view') -@register.tag('cannot_view') +@register.tag("can_edit") +@register.tag("cannot_edit") +@register.tag("can_delete") +@register.tag("cannot_delete") +@register.tag("can_view") +@register.tag("cannot_view") def acl_instance_filter(parser, token): """Generic definition of an acl templatetag for acl based on instance""" @@ -359,18 +350,18 @@ def acl_instance_filter(parser, token): ) # {% can_create %} - oknodes = parser.parse(('acl_else', 'acl_end')) + oknodes = parser.parse(("acl_else", "acl_end")) token = parser.next_token() # {% can_create_else %} - if token.contents == 'acl_else': - konodes = parser.parse(('acl_end')) + if token.contents == "acl_else": + konodes = parser.parse(("acl_end")) token = parser.next_token() else: konodes = NodeList() # {% can_create_end %} - assert token.contents == 'acl_end' + assert token.contents == "acl_end" return AclInstanceNode(tag_name, instance_name, oknodes, konodes, *args) @@ -388,16 +379,16 @@ class AclNode(Node): def render(self, context): resolved_args = [arg.resolve(context) for arg in self.args] - if context['user'].is_anonymous(): + if context["user"].is_anonymous(): can = False else: - can, _, _ = self.callback(context['user'], *(resolved_args)) + can, _, _ = self.callback(context["user"], *(resolved_args)) if can: return self.oknodes.render(context) return self.konodes.render(context) def __repr__(self): - return '' % self.tag_name + return "" % self.tag_name class AclInstanceNode(Node): @@ -413,13 +404,13 @@ class AclInstanceNode(Node): def render(self, context): callback = get_callback(self.tag_name, self.instance.resolve(context)) resolved_args = [arg.resolve(context) for arg in self.args] - if context['user'].is_anonymous(): + if context["user"].is_anonymous(): can = False else: - can, _, _ = callback(context['user'], *(resolved_args)) + can, _, _ = callback(context["user"], *(resolved_args)) if can: return self.oknodes.render(context) return self.konodes.render(context) def __repr__(self): - return '' % self.tag_name + return "" % self.tag_name diff --git a/re2o/templatetags/design.py b/re2o/templatetags/design.py index 9df37c30..57699f3b 100644 --- a/re2o/templatetags/design.py +++ b/re2o/templatetags/design.py @@ -1,5 +1,5 @@ # -*- mode: python; coding: utf-8 -*- -#re2o est un logiciel d'administration développé initiallement au rezometz. Il +# re2o est un logiciel d'administration développé initiallement au rezometz. Il # se veut agnostique au réseau considéré, de manière à être installable en # quelques clics. # @@ -29,12 +29,12 @@ register = template.Library() @register.filter(needs_autoescape=False) def tick(valeur, autoescape=False): - if isinstance(valeur,bool): + if isinstance(valeur, bool): if valeur == True: result = '' else: result = '' return mark_safe(result) - else: # if the value is not a boolean, display it as if tick was not called + else: # if the value is not a boolean, display it as if tick was not called return valeur diff --git a/re2o/templatetags/massive_bootstrap_form.py b/re2o/templatetags/massive_bootstrap_form.py index 8bfdbee8..20d468a1 100644 --- a/re2o/templatetags/massive_bootstrap_form.py +++ b/re2o/templatetags/massive_bootstrap_form.py @@ -186,11 +186,11 @@ def massive_bootstrap_form(form, mbf_fields, *args, **kwargs): {% massive_bootstrap_form form 'ipv4' choices='[...]' %} """ - mbf_form = MBFForm(form, mbf_fields.split(','), *args, **kwargs) + mbf_form = MBFForm(form, mbf_fields.split(","), *args, **kwargs) return mbf_form.render() -class MBFForm(): +class MBFForm: """ An object to hold all the information and useful methods needed to create and render a massive django form into an actual HTML and JS code able to handle it correctly. @@ -208,15 +208,15 @@ class MBFForm(): self.kwargs = kwargs # Fields to exclude form the form rendering - self.exclude = self.kwargs.get('exclude', '').split(',') + self.exclude = self.kwargs.get("exclude", "").split(",") # All the mbf parameters specified byt the user - param = kwargs.pop('mbf_param', {}) - self.choices = param.get('choices', {}) - self.engine = param.get('engine', {}) - self.match_func = param.get('match_func', {}) - self.update_on = param.get('update_on', {}) - self.gen_select = param.get('gen_select', {}) + param = kwargs.pop("mbf_param", {}) + self.choices = param.get("choices", {}) + self.engine = param.get("engine", {}) + self.match_func = param.get("match_func", {}) + self.update_on = param.get("update_on", {}) + self.gen_select = param.get("gen_select", {}) self.hidden_fields = [h.name for h in self.form.hidden_fields()] # HTML code to insert inside a template @@ -253,7 +253,7 @@ class MBFForm(): return mark_safe(self.html) -class MBFField(): +class MBFField: """ An object to hold all the information and useful methods needed to create and render a massive django form field into an actual HTML and JS code able to handle it correctly. @@ -264,17 +264,27 @@ class MBFField(): the displayed input. It's used to store the actual data that will be sent to the server """ - def __init__(self, name_, field_, bound_, choices_, engine_, match_func_, - update_on_, gen_select_, *args_, **kwargs_): + def __init__( + self, + name_, + field_, + bound_, + choices_, + engine_, + match_func_, + update_on_, + gen_select_, + *args_, + **kwargs_ + ): # Verify this field is a Select (or MultipleSelect) (only supported) if not isinstance(field_.widget, Select): raise ValueError( - ('Field named {f_name} is not a Select and' - 'can\'t be rendered with massive_bootstrap_form.') - .format( - f_name=name_ - ) + ( + "Field named {f_name} is not a Select and" + "can't be rendered with massive_bootstrap_form." + ).format(f_name=name_) ) # Name of the field @@ -287,9 +297,9 @@ class MBFField(): # Id for the main visible input self.input_id = self.bound.auto_id # Id for a hidden input used to store the value - self.hidden_id = self.input_id + '_hidden' + self.hidden_id = self.input_id + "_hidden" # Id for another div containing hidden inputs and script - self.div2_id = self.input_id + '_div' + self.div2_id = self.input_id + "_div" # Should the standard select should be generated self.gen_select = gen_select_ @@ -322,74 +332,67 @@ class MBFField(): if self.gen_select: return ( - 'function plop(o) {{' - 'var c = [];' - 'for( let i=0 ; i """ return ( - 'new Bloodhound({{' + "new Bloodhound({{" ' datumTokenizer: Bloodhound.tokenizers.obj.whitespace("value"),' - ' queryTokenizer: Bloodhound.tokenizers.whitespace,' - ' local: choices_{name},' - ' identify: function(obj) {{ return obj.key; }}' - '}})' - ).format( - name=self.name - ) + " queryTokenizer: Bloodhound.tokenizers.whitespace," + " local: choices_{name}," + " identify: function(obj) {{ return obj.key; }}" + "}})" + ).format(name=self.name) def default_datasets(self): """ Default JS script of the datasets to use with typeahead """ return ( - '{{' - ' hint: true,' - ' highlight: true,' - ' minLength: 0' - '}},' - '{{' + "{{" + " hint: true," + " highlight: true," + " minLength: 0" + "}}," + "{{" ' display: "value",' ' name: "{name}",' - ' source: {match_func}' - '}}' - ).format( - name=self.name, - match_func=self.match_func - ) + " source: {match_func}" + "}}" + ).format(name=self.name, match_func=self.match_func) def default_match_func(self): """ Default JS code of the matching function to use with typeahed """ return ( - 'function ( q, sync ) {{' + "function ( q, sync ) {{" ' if ( q === "" ) {{' - ' var first = choices_{name}.slice( 0, 5 ).map(' - ' function ( obj ) {{ return obj.key; }}' - ' );' - ' sync( engine_{name}.get( first ) );' - ' }} else {{' - ' engine_{name}.search( q, sync );' - ' }}' - '}}' - ).format( - name=self.name - ) + " var first = choices_{name}.slice( 0, 5 ).map(" + " function ( obj ) {{ return obj.key; }}" + " );" + " sync( engine_{name}.get( first ) );" + " }} else {{" + " engine_{name}.search( q, sync );" + " }}" + "}}" + ).format(name=self.name) def render(self): """ HTML code for the fully rendered field """ @@ -400,23 +403,12 @@ class MBFField(): def gen_displayed_div(self): """ Generate HTML code for the div that contains displayed tags """ if self.gen_select: - self.html += render_field( - self.bound, - *self.args, - **self.kwargs - ) + self.html += render_field(self.bound, *self.args, **self.kwargs) self.field.widget = TextInput( - attrs={ - 'name': 'mbf_'+self.name, - 'placeholder': self.field.empty_label - } - ) - self.replace_input = render_field( - self.bound, - *self.args, - **self.kwargs + attrs={"name": "mbf_" + self.name, "placeholder": self.field.empty_label} ) + self.replace_input = render_field(self.bound, *self.args, **self.kwargs) if not self.gen_select: self.html += self.replace_input @@ -429,22 +421,18 @@ class MBFField(): if not self.multiple and not self.gen_select: content += self.hidden_input() - self.html += render_tag( - 'div', - content=content, - attrs={'id': self.div2_id} - ) + self.html += render_tag("div", content=content, attrs={"id": self.div2_id}) def hidden_input(self): """ HTML for the hidden input element """ return render_tag( - 'input', + "input", attrs={ - 'id': self.hidden_id, - 'name': self.bound.html_name, - 'type': 'hidden', - 'value': self.bound.value() or "" - } + "id": self.hidden_id, + "name": self.bound.html_name, + "type": "hidden", + "value": self.bound.value() or "", + }, ) def gen_full_js(self): @@ -460,76 +448,76 @@ class MBFField(): if self.multiple: self.js_script = ( '$( "#{input_id}" ).ready( function() {{' - ' var choices_{f_name} = {choices};' - ' {del_select}' - ' var engine_{f_name};' - ' var setup_{f_name} = function() {{' - ' engine_{f_name} = {engine};' + " var choices_{f_name} = {choices};" + " {del_select}" + " var engine_{f_name};" + " var setup_{f_name} = function() {{" + " engine_{f_name} = {engine};" ' $( "#{input_id}" ).tokenfield( "destroy" );' ' $( "#{input_id}" ).tokenfield({{typeahead: [ {datasets} ] }});' - ' }};' + " }};" ' $( "#{input_id}" ).bind( "tokenfield:createtoken", {tok_create} );' ' $( "#{input_id}" ).bind( "tokenfield:edittoken", {tok_edit} );' ' $( "#{input_id}" ).bind( "tokenfield:removetoken", {tok_remove} );' - ' {tok_updates}' - ' setup_{f_name}();' - ' {tok_init_input}' - '}} );' + " {tok_updates}" + " setup_{f_name}();" + " {tok_init_input}" + "}} );" ) else: self.js_script = ( '$( "#{input_id}" ).ready( function() {{' - ' var choices_{f_name} = {choices};' - ' {del_select}' - ' {gen_hidden}' - ' var engine_{f_name};' - ' var setup_{f_name} = function() {{' - ' engine_{f_name} = {engine};' + " var choices_{f_name} = {choices};" + " {del_select}" + " {gen_hidden}" + " var engine_{f_name};" + " var setup_{f_name} = function() {{" + " engine_{f_name} = {engine};" ' $( "#{input_id}" ).typeahead( "destroy" );' ' $( "#{input_id}" ).typeahead( {datasets} );' - ' }};' + " }};" ' $( "#{input_id}" ).bind( "typeahead:select", {typ_select} );' ' $( "#{input_id}" ).bind( "typeahead:change", {typ_change} );' - ' {typ_updates}' - ' setup_{f_name}();' - ' {typ_init_input}' - '}} );' + " {typ_updates}" + " setup_{f_name}();" + " {typ_init_input}" + "}} );" ) else: if self.multiple: self.js_script = ( - 'var choices_{f_name} = {choices};' - 'var engine_{f_name};' - 'var setup_{f_name} = function() {{' - ' engine_{f_name} = {engine};' + "var choices_{f_name} = {choices};" + "var engine_{f_name};" + "var setup_{f_name} = function() {{" + " engine_{f_name} = {engine};" ' $( "#{input_id}" ).tokenfield( "destroy" );' ' $( "#{input_id}" ).tokenfield({{typeahead: [ {datasets} ] }});' - '}};' + "}};" '$( "#{input_id}" ).bind( "tokenfield:createtoken", {tok_create} );' '$( "#{input_id}" ).bind( "tokenfield:edittoken", {tok_edit} );' '$( "#{input_id}" ).bind( "tokenfield:removetoken", {tok_remove} );' - '{tok_updates}' + "{tok_updates}" '$( "#{input_id}" ).ready( function() {{' - ' setup_{f_name}();' - ' {tok_init_input}' - '}} );' + " setup_{f_name}();" + " {tok_init_input}" + "}} );" ) else: self.js_script = ( - 'var choices_{f_name} ={choices};' - 'var engine_{f_name};' - 'var setup_{f_name} = function() {{' - ' engine_{f_name} = {engine};' + "var choices_{f_name} ={choices};" + "var engine_{f_name};" + "var setup_{f_name} = function() {{" + " engine_{f_name} = {engine};" ' $( "#{input_id}" ).typeahead( "destroy" );' ' $( "#{input_id}" ).typeahead( {datasets} );' - '}};' + "}};" '$( "#{input_id}" ).bind( "typeahead:select", {typ_select} );' '$( "#{input_id}" ).bind( "typeahead:change", {typ_change} );' - '{typ_updates}' + "{typ_updates}" '$( "#{input_id}" ).ready( function() {{' - ' setup_{f_name}();' - ' {typ_init_input}' - '}} );' + " setup_{f_name}();" + " {typ_init_input}" + "}} );" ) def fill_js(self): @@ -550,27 +538,21 @@ class MBFField(): typ_updates=self.typeahead_updates(), tok_updates=self.tokenfield_updates(), tok_init_input=self.tokenfield_init_input(), - typ_init_input=self.typeahead_init_input() + typ_init_input=self.typeahead_init_input(), ) def get_script(self): """ Insert the JS code inside a script tag """ - self.js_script = render_tag( - 'script', - content=mark_safe(self.js_script) - ) + self.js_script = render_tag("script", content=mark_safe(self.js_script)) def del_select(self): """ JS code to delete the select if it has been generated and replace it with an input. """ return ( 'var p = $("#{select_id}").parent()[0];' - 'var new_input = `{replace_input}`;' - 'p.innerHTML = new_input;' - ).format( - select_id=self.input_id, - replace_input=self.replace_input - ) + "var new_input = `{replace_input}`;" + "p.innerHTML = new_input;" + ).format(select_id=self.input_id, replace_input=self.replace_input) def gen_hidden(self): """ JS code to add a hidden tag to store the value. """ @@ -581,11 +563,11 @@ class MBFField(): 'i.name = "{html_name}";' 'i.value = "";' 'i.type = "hidden";' - 'd.appendChild(i);' + "d.appendChild(i);" ).format( div2_id=self.div2_id, hidden_id=self.hidden_id, - html_name=self.bound.html_name + html_name=self.bound.html_name, ) def typeahead_init_input(self): @@ -594,55 +576,46 @@ class MBFField(): return ( '$( "#{input_id}" ).typeahead("val", {init_val});' '$( "#{hidden_id}" ).val( {init_key} );' - ).format( - input_id=self.input_id, - init_val='""' if init_key == '""' else - 'engine_{name}.get( {init_key} )[0].value'.format( - name=self.name, - init_key=init_key - ), - init_key=init_key, - hidden_id=self.hidden_id - ) + ).format( + input_id=self.input_id, + init_val='""' + if init_key == '""' + else "engine_{name}.get( {init_key} )[0].value".format( + name=self.name, init_key=init_key + ), + init_key=init_key, + hidden_id=self.hidden_id, + ) def typeahead_reset_input(self): """ JS code to reset the fields values """ return ( - '$( "#{input_id}" ).typeahead("val", "");' - '$( "#{hidden_id}" ).val( "" );' - ).format( - input_id=self.input_id, - hidden_id=self.hidden_id - ) + '$( "#{input_id}" ).typeahead("val", "");' '$( "#{hidden_id}" ).val( "" );' + ).format(input_id=self.input_id, hidden_id=self.hidden_id) def typeahead_select(self): """ JS code to create the function triggered when an item is selected through typeahead """ return ( - 'function(evt, item) {{' + "function(evt, item) {{" ' $( "#{hidden_id}" ).val( item.key );' ' $( "#{hidden_id}" ).change();' - ' return item;' - '}}' - ).format( - hidden_id=self.hidden_id - ) + " return item;" + "}}" + ).format(hidden_id=self.hidden_id) def typeahead_change(self): """ JS code of the function triggered when an item is changed (i.e. looses focus and value has changed since the moment it gained focus ) """ return ( - 'function(evt) {{' + "function(evt) {{" ' if ( $( "#{input_id}" ).typeahead( "val" ) === "" ) {{' ' $( "#{hidden_id}" ).val( "" );' ' $( "#{hidden_id}" ).change();' - ' }}' - '}}' - ).format( - input_id=self.input_id, - hidden_id=self.hidden_id - ) + " }}" + "}}" + ).format(input_id=self.input_id, hidden_id=self.hidden_id) def typeahead_updates(self): """ JS code for binding external fields changes with a reset """ @@ -650,118 +623,106 @@ class MBFField(): updates = [ ( '$( "#{u_id}" ).change( function() {{' - ' setup_{name}();' - ' {reset_input}' - '}} );' - ).format( - u_id=u_id, - name=self.name, - reset_input=reset_input - ) for u_id in self.update_on] - return ''.join(updates) + " setup_{name}();" + " {reset_input}" + "}} );" + ).format(u_id=u_id, name=self.name, reset_input=reset_input) + for u_id in self.update_on + ] + return "".join(updates) def tokenfield_init_input(self): """ JS code to init the fields values """ init_key = self.bound.value() or '""' - return ( - '$( "#{input_id}" ).tokenfield("setTokens", {init_val});' - ).format( - input_id=self.input_id, - init_val='""' if init_key == '""' else ( - 'engine_{name}.get( {init_key} ).map(' - ' function(o) {{ return o.value; }}' - ')').format( - name=self.name, - init_key=init_key - ) - ) + return ('$( "#{input_id}" ).tokenfield("setTokens", {init_val});').format( + input_id=self.input_id, + init_val='""' + if init_key == '""' + else ( + "engine_{name}.get( {init_key} ).map(" + " function(o) {{ return o.value; }}" + ")" + ).format(name=self.name, init_key=init_key), + ) def tokenfield_reset_input(self): """ JS code to reset the fields values """ - return ( - '$( "#{input_id}" ).tokenfield("setTokens", "");' - ).format( - input_id=self.input_id - ) + return ('$( "#{input_id}" ).tokenfield("setTokens", "");').format( + input_id=self.input_id + ) def tokenfield_create(self): """ JS code triggered when a new token is created in tokenfield. """ return ( - 'function(evt) {{' - ' var k = evt.attrs.key;' - ' if (!k) {{' - ' var data = evt.attrs.value;' - ' var i = 0;' - ' while ( i= len(words): # We are starting a new word - words.append('') + words.append("") if escaping_char: # The last char war a \ so we escape this char escaping_char = False words[i] += char continue - if char == '\\': + if char == "\\": # We need to escape the next char escaping_char = True continue @@ -347,9 +264,9 @@ def get_words(query): # If we are between two ", ignore separators words[i] += char continue - if char == ' ' or char == ',': + if char == " " or char == ",": # If we encouter a separator outside of ", we create a new word - if words[i] is not '': + if words[i] is not "": i += 1 continue # If we haven't encountered any special case, add the char to the word @@ -364,53 +281,43 @@ def get_results(query, request, params): single filter. Then it calls 'finish_results' and return the queryset of objects to display as results""" - start = params.get('s', None) - end = params.get('e', None) - user_state = params.get('u', initial_choices(CHOICES_USER)) - aff = params.get('a', initial_choices(CHOICES_AFF)) + start = params.get("s", None) + end = params.get("e", None) + user_state = params.get("u", initial_choices(CHOICES_USER)) + aff = params.get("a", initial_choices(CHOICES_AFF)) filters = { - 'users': Q(), - 'clubs': Q(), - 'machines': Q(), - 'factures': Q(), - 'bans': Q(), - 'whitelists': Q(), - 'rooms': Q(), - 'ports': Q(), - 'switches': Q() + "users": Q(), + "clubs": Q(), + "machines": Q(), + "factures": Q(), + "bans": Q(), + "whitelists": Q(), + "rooms": Q(), + "ports": Q(), + "switches": Q(), } words = get_words(query) for word in words: filters = search_single_word( - word, - filters, - request.user, - start, - end, - user_state, - aff + word, filters, request.user, start, end, user_state, aff ) results = { - 'users': Adherent.objects.filter(filters['users']), - 'clubs': Club.objects.filter(filters['clubs']), - 'machines': Machine.objects.filter(filters['machines']), - 'factures': Facture.objects.filter(filters['factures']), - 'bans': Ban.objects.filter(filters['bans']), - 'whitelists': Whitelist.objects.filter(filters['whitelists']), - 'rooms': Room.objects.filter(filters['rooms']), - 'ports': Port.objects.filter(filters['ports']), - 'switches': Switch.objects.filter(filters['switches']) + "users": Adherent.objects.filter(filters["users"]), + "clubs": Club.objects.filter(filters["clubs"]), + "machines": Machine.objects.filter(filters["machines"]), + "factures": Facture.objects.filter(filters["factures"]), + "bans": Ban.objects.filter(filters["bans"]), + "whitelists": Whitelist.objects.filter(filters["whitelists"]), + "rooms": Room.objects.filter(filters["rooms"]), + "ports": Port.objects.filter(filters["ports"]), + "switches": Switch.objects.filter(filters["switches"]), } - results = finish_results( - results, - request.GET.get('col'), - request.GET.get('order') - ) - results.update({'search_term': query}) + results = finish_results(results, request.GET.get("col"), request.GET.get("order")) + results.update({"search_term": query}) return results @@ -423,14 +330,12 @@ def search(request): if search_form.is_valid(): return render( request, - 'search/index.html', + "search/index.html", get_results( - search_form.cleaned_data.get('q', ''), - request, - search_form.cleaned_data - ) + search_form.cleaned_data.get("q", ""), request, search_form.cleaned_data + ), ) - return render(request, 'search/search.html', {'search_form': search_form}) + return render(request, "search/search.html", {"search_form": search_form}) @login_required @@ -441,11 +346,9 @@ def searchp(request): if search_form.is_valid(): return render( request, - 'search/index.html', + "search/index.html", get_results( - search_form.cleaned_data.get('q', ''), - request, - search_form.cleaned_data - ) + search_form.cleaned_data.get("q", ""), request, search_form.cleaned_data + ), ) - return render(request, 'search/search.html', {'search_form': search_form}) + return render(request, "search/search.html", {"search_form": search_form}) diff --git a/test_utils/runner.py b/test_utils/runner.py index 77885dcf..6cdd4cae 100644 --- a/test_utils/runner.py +++ b/test_utils/runner.py @@ -34,87 +34,137 @@ from users.models import LdapUser, LdapUserGroup, LdapServiceUser, LdapServiceUs # The path of this file __here = os.path.dirname(os.path.realpath(__file__)) # The absolute path where to find the schemas for the LDAP -schema_path = os.path.abspath(os.path.join(__here, 'ldap', 'schema')) +schema_path = os.path.abspath(os.path.join(__here, "ldap", "schema")) # The absolute path of the "radius.schema" file -radius_schema_path = os.path.join(schema_path, 'radius.schema') +radius_schema_path = os.path.join(schema_path, "radius.schema") # The absolute path of the "samba.schema" file -samba_schema_path = os.path.join(schema_path, 'samba.schema') +samba_schema_path = os.path.join(schema_path, "samba.schema") # The suffix for the LDAP -suffix = 'dc=example,dc=net' +suffix = "dc=example,dc=net" # The admin CN of the LDAP -rootdn = 'cn=admin,'+suffix +rootdn = "cn=admin," + suffix # Defines all ldap_entry mandatory for Re2o under a key-value list format # that can be used directly by volatildap. For more on how to generate this # data, see https://gitlab.federez.net/re2o/scripts/blob/master/print_ldap_entries.py -ldapentry_Utilisateurs = ('cn=Utilisateurs,'+suffix, { - 'cn': ['Utilisateurs'], - 'sambaSID': ['500'], - 'uid': ['Users'], - 'objectClass': ['posixGroup', 'top', 'sambaSamAccount', 'radiusprofile'], - 'gidNumber': ['500'], -}) -ldapentry_groups = ('ou=groups,'+suffix, { - 'ou': ['groups'], - 'objectClass': ['organizationalUnit'], - 'description': ["Groupes d'utilisateurs"], -}) -ldapentry_services = ('ou=services,ou=groups,'+suffix, { - 'ou': ['services'], - 'objectClass': ['organizationalUnit'], - 'description': ['Groupes de comptes techniques'], -}) -ldapentry_service_users = ('ou=service-users,'+suffix, { - 'ou': ['service-users'], - 'objectClass': ['organizationalUnit'], - 'description': ["Utilisateurs techniques de l'annuaire"], -}) -ldapentry_freeradius = ('cn=freeradius,ou=service-users,'+suffix, { - 'cn': ['freeradius'], - 'objectClass': ['applicationProcess', 'simpleSecurityObject'], - 'userPassword': ['FILL_IT'], -}) -ldapentry_nssauth = ('cn=nssauth,ou=service-users,'+suffix, { - 'cn': ['nssauth'], - 'objectClass': ['applicationProcess', 'simpleSecurityObject'], - 'userPassword': ['FILL_IT'], -}) -ldapentry_auth = ('cn=auth,ou=services,ou=groups,'+suffix, { - 'cn': ['auth'], - 'objectClass': ['groupOfNames'], - 'member': ['cn=nssauth,ou=service-users,'+suffix], -}) -ldapentry_posix = ('ou=posix,ou=groups,'+suffix, { - 'ou': ['posix'], - 'objectClass': ['organizationalUnit'], - 'description': ['Groupes de comptes POSIX'], -}) -ldapentry_wifi = ('cn=wifi,ou=service-users,'+suffix, { - 'cn': ['wifi'], - 'objectClass': ['applicationProcess', 'simpleSecurityObject'], - 'userPassword': ['FILL_IT'], -}) -ldapentry_usermgmt = ('cn=usermgmt,ou=services,ou=groups,'+suffix, { - 'cn': ['usermgmt'], - 'objectClass': ['groupOfNames'], - 'member': ['cn=wifi,ou=service-users,'+suffix], -}) -ldapentry_replica = ('cn=replica,ou=service-users,'+suffix, { - 'cn': ['replica'], - 'objectClass': ['applicationProcess', 'simpleSecurityObject'], - 'userPassword': ['FILL_IT'], -}) -ldapentry_readonly = ('cn=readonly,ou=services,ou=groups,'+suffix, { - 'cn': ['readonly'], - 'objectClass': ['groupOfNames'], - 'member': ['cn=replica,ou=service-users,'+suffix, 'cn=freeradius,ou=service-users,'+suffix], -}) -ldapbasic = dict([ldapentry_Utilisateurs, ldapentry_groups, - ldapentry_services, ldapentry_service_users, - ldapentry_freeradius, ldapentry_nssauth, ldapentry_auth, - ldapentry_posix, ldapentry_wifi, ldapentry_usermgmt, - ldapentry_replica, ldapentry_readonly]) +ldapentry_Utilisateurs = ( + "cn=Utilisateurs," + suffix, + { + "cn": ["Utilisateurs"], + "sambaSID": ["500"], + "uid": ["Users"], + "objectClass": ["posixGroup", "top", "sambaSamAccount", "radiusprofile"], + "gidNumber": ["500"], + }, +) +ldapentry_groups = ( + "ou=groups," + suffix, + { + "ou": ["groups"], + "objectClass": ["organizationalUnit"], + "description": ["Groupes d'utilisateurs"], + }, +) +ldapentry_services = ( + "ou=services,ou=groups," + suffix, + { + "ou": ["services"], + "objectClass": ["organizationalUnit"], + "description": ["Groupes de comptes techniques"], + }, +) +ldapentry_service_users = ( + "ou=service-users," + suffix, + { + "ou": ["service-users"], + "objectClass": ["organizationalUnit"], + "description": ["Utilisateurs techniques de l'annuaire"], + }, +) +ldapentry_freeradius = ( + "cn=freeradius,ou=service-users," + suffix, + { + "cn": ["freeradius"], + "objectClass": ["applicationProcess", "simpleSecurityObject"], + "userPassword": ["FILL_IT"], + }, +) +ldapentry_nssauth = ( + "cn=nssauth,ou=service-users," + suffix, + { + "cn": ["nssauth"], + "objectClass": ["applicationProcess", "simpleSecurityObject"], + "userPassword": ["FILL_IT"], + }, +) +ldapentry_auth = ( + "cn=auth,ou=services,ou=groups," + suffix, + { + "cn": ["auth"], + "objectClass": ["groupOfNames"], + "member": ["cn=nssauth,ou=service-users," + suffix], + }, +) +ldapentry_posix = ( + "ou=posix,ou=groups," + suffix, + { + "ou": ["posix"], + "objectClass": ["organizationalUnit"], + "description": ["Groupes de comptes POSIX"], + }, +) +ldapentry_wifi = ( + "cn=wifi,ou=service-users," + suffix, + { + "cn": ["wifi"], + "objectClass": ["applicationProcess", "simpleSecurityObject"], + "userPassword": ["FILL_IT"], + }, +) +ldapentry_usermgmt = ( + "cn=usermgmt,ou=services,ou=groups," + suffix, + { + "cn": ["usermgmt"], + "objectClass": ["groupOfNames"], + "member": ["cn=wifi,ou=service-users," + suffix], + }, +) +ldapentry_replica = ( + "cn=replica,ou=service-users," + suffix, + { + "cn": ["replica"], + "objectClass": ["applicationProcess", "simpleSecurityObject"], + "userPassword": ["FILL_IT"], + }, +) +ldapentry_readonly = ( + "cn=readonly,ou=services,ou=groups," + suffix, + { + "cn": ["readonly"], + "objectClass": ["groupOfNames"], + "member": [ + "cn=replica,ou=service-users," + suffix, + "cn=freeradius,ou=service-users," + suffix, + ], + }, +) +ldapbasic = dict( + [ + ldapentry_Utilisateurs, + ldapentry_groups, + ldapentry_services, + ldapentry_service_users, + ldapentry_freeradius, + ldapentry_nssauth, + ldapentry_auth, + ldapentry_posix, + ldapentry_wifi, + ldapentry_usermgmt, + ldapentry_replica, + ldapentry_readonly, + ] +) class DiscoverLdapRunner(DiscoverRunner): @@ -133,28 +183,35 @@ class DiscoverLdapRunner(DiscoverRunner): suffix=suffix, rootdn=rootdn, initial_data=ldapbasic, - schemas=['core.schema', 'cosine.schema', 'inetorgperson.schema', - 'nis.schema', radius_schema_path, samba_schema_path] + schemas=[ + "core.schema", + "cosine.schema", + "inetorgperson.schema", + "nis.schema", + radius_schema_path, + samba_schema_path, + ], ) def __init__(self, *args, **kwargs): - settings.DATABASES['ldap']['USER'] = self.ldap_server.rootdn - settings.DATABASES['ldap']['PASSWORD'] = self.ldap_server.rootpw - settings.DATABASES['ldap']['NAME'] = self.ldap_server.uri - settings.LDAP['base_user_dn'] = ldapentry_Utilisateurs[0] - settings.LDAP['base_userservice_dn'] = ldapentry_service_users[0] - settings.LDAP['base_usergroup_dn'] = ldapentry_posix[0] - settings.LDAP['base_userservicegroup_dn'] = ldapentry_services[0] - settings.LDAP['user_gid'] = ldapentry_Utilisateurs[1].get('gidNumber', ["500"])[0] - LdapUser.base_dn = settings.LDAP['base_user_dn'] - LdapUserGroup.base_dn = settings.LDAP['base_usergroup_dn'] - LdapServiceUser.base_dn = settings.LDAP['base_userservice_dn'] - LdapServiceUserGroup.base_dn = settings.LDAP['base_userservicegroup_dn'] + settings.DATABASES["ldap"]["USER"] = self.ldap_server.rootdn + settings.DATABASES["ldap"]["PASSWORD"] = self.ldap_server.rootpw + settings.DATABASES["ldap"]["NAME"] = self.ldap_server.uri + settings.LDAP["base_user_dn"] = ldapentry_Utilisateurs[0] + settings.LDAP["base_userservice_dn"] = ldapentry_service_users[0] + settings.LDAP["base_usergroup_dn"] = ldapentry_posix[0] + settings.LDAP["base_userservicegroup_dn"] = ldapentry_services[0] + settings.LDAP["user_gid"] = ldapentry_Utilisateurs[1].get("gidNumber", ["500"])[ + 0 + ] + LdapUser.base_dn = settings.LDAP["base_user_dn"] + LdapUserGroup.base_dn = settings.LDAP["base_usergroup_dn"] + LdapServiceUser.base_dn = settings.LDAP["base_userservice_dn"] + LdapServiceUserGroup.base_dn = settings.LDAP["base_userservicegroup_dn"] super(DiscoverLdapRunner, self).__init__(*args, **kwargs) - def setup_databases(self, *args, **kwargs): - ret = super(DiscoverLdapRunner, self).setup_databases(*args, **kwargs) + ret = super(DiscoverLdapRunner, self).setup_databases(*args, **kwargs) print("Creating test LDAP with volatildap...") self.ldap_server.start() return ret @@ -163,4 +220,3 @@ class DiscoverLdapRunner(DiscoverRunner): self.ldap_server.stop() print("Destroying test LDAP...") super(DiscoverLdapRunner, self).teardown_databases(*args, **kwargs) - diff --git a/tickets/admin.py b/tickets/admin.py index 76763b9c..6a20b775 100644 --- a/tickets/admin.py +++ b/tickets/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin from .models import Ticket + admin.site.register(Ticket) # Register your models here. diff --git a/tickets/apps.py b/tickets/apps.py index 3ea742ac..295e4a1f 100644 --- a/tickets/apps.py +++ b/tickets/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class TicketsConfig(AppConfig): - name = 'tickets' + name = "tickets" diff --git a/tickets/forms.py b/tickets/forms.py index bbeea0c4..00edb0ec 100644 --- a/tickets/forms.py +++ b/tickets/forms.py @@ -4,21 +4,22 @@ from re2o.field_permissions import FieldPermissionFormMixin from re2o.mixins import FormRevMixin from django.utils.translation import ugettext_lazy as _ -from .models import( - Ticket, -) +from .models import Ticket class NewTicketForm(ModelForm): """ Creation of a ticket""" + email = forms.EmailField(required=False) + class Meta: model = Ticket - fields = ['title', 'description', 'email'] + fields = ["title", "description", "email"] + class ChangeStatusTicketForm(ModelForm): """ Change ticket status""" + class Meta: model = Ticket fields = [] - diff --git a/tickets/migrations/0001_initial.py b/tickets/migrations/0001_initial.py index 67e1d0f0..4140c955 100644 --- a/tickets/migrations/0001_initial.py +++ b/tickets/migrations/0001_initial.py @@ -12,37 +12,87 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] + dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)] operations = [ migrations.CreateModel( - name='Preferences', + name="Preferences", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('publish_address', models.EmailField(help_text='Email address to publish the new tickets (leave empty for no publications)', max_length=1000, null=True)), - ('mail_language', models.IntegerField(choices=[(0, 'Français'), (1, 'English')], default=0)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "publish_address", + models.EmailField( + help_text="Email address to publish the new tickets (leave empty for no publications)", + max_length=1000, + null=True, + ), + ), + ( + "mail_language", + models.IntegerField( + choices=[(0, "Français"), (1, "English")], default=0 + ), + ), ], - options={ - 'verbose_name': "Ticket's settings", - }, + options={"verbose_name": "Ticket's settings"}, ), migrations.CreateModel( - name='Ticket', + name="Ticket", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(help_text='Title of the ticket', max_length=255)), - ('description', models.TextField(help_text='Description of the ticket', max_length=3000)), - ('date', models.DateTimeField(auto_now_add=True)), - ('email', models.EmailField(help_text='An email address to get back to you', max_length=100, null=True)), - ('solved', models.BooleanField(default=False)), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tickets', to=settings.AUTH_USER_MODEL)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "title", + models.CharField(help_text="Title of the ticket", max_length=255), + ), + ( + "description", + models.TextField( + help_text="Description of the ticket", max_length=3000 + ), + ), + ("date", models.DateTimeField(auto_now_add=True)), + ( + "email", + models.EmailField( + help_text="An email address to get back to you", + max_length=100, + null=True, + ), + ), + ("solved", models.BooleanField(default=False)), + ( + "user", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="tickets", + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ - 'verbose_name': 'Ticket', - 'verbose_name_plural': 'Tickets', - 'permissions': (('view_tickets', 'Can view a ticket object'),), 'verbose_name': 'Ticket', 'verbose_name_plural': 'Tickets', + "verbose_name": "Ticket", + "verbose_name_plural": "Tickets", + "permissions": (("view_tickets", "Can view a ticket object"),), + "verbose_name": "Ticket", + "verbose_name_plural": "Tickets", }, bases=(re2o.mixins.AclMixin, models.Model), ), diff --git a/tickets/models.py b/tickets/models.py index e9acaf9b..5bc37856 100644 --- a/tickets/models.py +++ b/tickets/models.py @@ -13,72 +13,74 @@ import users.models from .preferences.models import Preferences + class Ticket(AclMixin, models.Model): """Model of a ticket""" user = models.ForeignKey( - 'users.User', + "users.User", on_delete=models.CASCADE, related_name="tickets", blank=True, - null=True) + null=True, + ) title = models.CharField( - max_length=255, - help_text=_("Title of the ticket"), - blank=False, - null=False,) + max_length=255, help_text=_("Title of the ticket"), blank=False, null=False + ) description = models.TextField( max_length=3000, help_text=_("Description of the ticket"), blank=False, - null=False) + null=False, + ) date = models.DateTimeField(auto_now_add=True) email = models.EmailField( - help_text = _("An email address to get back to you"), - max_length=100, - null=True) + help_text=_("An email address to get back to you"), max_length=100, null=True + ) solved = models.BooleanField(default=False) class Meta: - permissions = ( - ("view_tickets", _("Can view a ticket object")), - ) + permissions = (("view_tickets", _("Can view a ticket object")),) verbose_name = _("Ticket") verbose_name_plural = _("Tickets") def __str__(self): if self.user: - return "Ticket from {}. Date: {}".format(self.user.surname,self.date) + return "Ticket from {}. Date: {}".format(self.user.surname, self.date) else: return "Anonymous Ticket. Date: {}".format(self.date) def publish_mail(self): site_url = GeneralOption.objects.first().main_site_url to_addr = Preferences.objects.first().publish_address - context = {'ticket':self,'site_url':site_url} + context = {"ticket": self, "site_url": site_url} lang = Preferences.objects.first().mail_language - if(lang == 0): - obj = 'Nouvelle ouverture de ticket' - template = loader.get_template('tickets/publication_mail_fr') + if lang == 0: + obj = "Nouvelle ouverture de ticket" + template = loader.get_template("tickets/publication_mail_fr") else: - obj = 'New ticket opened' - template = loader.get_template('tickets/publication_mail_en') + obj = "New ticket opened" + template = loader.get_template("tickets/publication_mail_en") send_mail( obj, template.render(context), - GeneralOption.get_cached_value('email_from'), + GeneralOption.get_cached_value("email_from"), [to_addr], - fail_silently = False) + fail_silently=False, + ) def can_view(self, user_request, *_args, **_kwargs): """ Check that the user has the right to view the ticket or that it is the author""" - if (not user_request.has_perm('tickets.view_ticket') and self.user != user_request): + if ( + not user_request.has_perm("tickets.view_ticket") + and self.user != user_request + ): return ( False, _("You don't have the right to view other tickets than yours."), - ('tickets.view_ticket',) + ("tickets.view_ticket",), ) else: return True, None, None @@ -86,21 +88,24 @@ class Ticket(AclMixin, models.Model): @staticmethod def can_view_all(user_request, *_args, **_kwargs): """ Check that the user has access to the list of all tickets""" - can = user_request.has_perm('tickets.view_tickets') - return( + can = user_request.has_perm("tickets.view_tickets") + return ( can, - _("You don't have the right to view the list of tickets.") if not can else None, - ('tickets.view_tickets',) + _("You don't have the right to view the list of tickets.") + if not can + else None, + ("tickets.view_tickets",), ) - def can_create(user_request,*_args, **_kwargs): + def can_create(user_request, *_args, **_kwargs): """ Authorise all users to open tickets """ return True, None, None + @receiver(post_save, sender=Ticket) def ticket_post_save(**kwargs): """ Send the mail to publish the new ticket """ - if kwargs['created']: + if kwargs["created"]: if Preferences.objects.first().publish_address: - ticket = kwargs['instance'] + ticket = kwargs["instance"] ticket.publish_mail() diff --git a/tickets/preferences/forms.py b/tickets/preferences/forms.py index 5bdc65d2..b12bde67 100644 --- a/tickets/preferences/forms.py +++ b/tickets/preferences/forms.py @@ -4,8 +4,10 @@ from django.utils.translation import ugettext_lazy as _ from .models import Preferences + class EditPreferencesForm(ModelForm): """ Edit the ticket's settings""" + class Meta: model = Preferences - fields = '__all__' + fields = "__all__" diff --git a/tickets/preferences/models.py b/tickets/preferences/models.py index da77fdff..8add48bd 100644 --- a/tickets/preferences/models.py +++ b/tickets/preferences/models.py @@ -1,19 +1,21 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ + class Preferences(models.Model): """ Definition of the ticket's settings""" publish_address = models.EmailField( - help_text = _("Email address to publish the new tickets (leave empty for no publications)"), - max_length = 1000, - null = True) + help_text=_( + "Email address to publish the new tickets (leave empty for no publications)" + ), + max_length=1000, + null=True, + ) LANG_FR = 0 LANG_EN = 1 - LANGUES = ( - (0,_("Français")), - (1,_("English")), - ) - mail_language = models.IntegerField(choices=LANGUES,default = LANG_FR) + LANGUES = ((0, _("Français")), (1, _("English"))) + mail_language = models.IntegerField(choices=LANGUES, default=LANG_FR) + class Meta: verbose_name = _("Ticket's settings") diff --git a/tickets/urls.py b/tickets/urls.py index 98556a7a..1dfda475 100644 --- a/tickets/urls.py +++ b/tickets/urls.py @@ -3,8 +3,12 @@ from django.conf.urls import url from . import views urlpatterns = [ - url(r'^$', views.aff_tickets, name='aff-tickets'), - url(r'^ticket/(?P[0-9]+)$', views.aff_ticket, name='aff-ticket'), - url(r'^ticket/edit-preferences-tickets$', views.edit_preferences, name='edit-preferences-tickets'), - url(r'^new_ticket/$',views.new_ticket,name='new-ticket'), + url(r"^$", views.aff_tickets, name="aff-tickets"), + url(r"^ticket/(?P[0-9]+)$", views.aff_ticket, name="aff-ticket"), + url( + r"^ticket/edit-preferences-tickets$", + views.edit_preferences, + name="edit-preferences-tickets", + ), + url(r"^new_ticket/$", views.new_ticket, name="new-ticket"), ] diff --git a/tickets/views.py b/tickets/views.py index e59c69a0..04ecee6d 100644 --- a/tickets/views.py +++ b/tickets/views.py @@ -35,102 +35,107 @@ from django.urls import reverse from django.forms import modelformset_factory from re2o.views import form -from re2o.base import ( - re2o_paginator, -) +from re2o.base import re2o_paginator -from re2o.acl import( - can_view, - can_view_all, - can_edit, - can_create, -) +from re2o.acl import can_view, can_view_all, can_edit, can_create from preferences.models import GeneralOption -from .models import( - Ticket, -) +from .models import Ticket -from .preferences.models import( - Preferences, -) +from .preferences.models import Preferences -from .forms import ( - NewTicketForm, - ChangeStatusTicketForm, -) - -from .preferences.forms import ( - EditPreferencesForm, -) +from .forms import NewTicketForm, ChangeStatusTicketForm +from .preferences.forms import EditPreferencesForm def new_ticket(request): """ Ticket creation view""" ticketform = NewTicketForm(request.POST or None) - if request.method == 'POST': + if request.method == "POST": ticketform = NewTicketForm(request.POST) if ticketform.is_valid(): - email = ticketform.cleaned_data.get('email') + email = ticketform.cleaned_data.get("email") ticket = ticketform.save(commit=False) if request.user.is_authenticated: ticket.user = request.user ticket.save() - messages.success(request,_('Your ticket has been succesfully open. We will take care of it as soon as possible.')) - return redirect(reverse('users:profil',kwargs={'userid':str(request.user.id)})) + messages.success( + request, + _( + "Your ticket has been succesfully open. We will take care of it as soon as possible." + ), + ) + return redirect( + reverse("users:profil", kwargs={"userid": str(request.user.id)}) + ) if not request.user.is_authenticated and email != "": ticket.save() - messages.success(request,_('Your ticket has been succesfully open. We will take care of it as soon as possible.')) - return redirect(reverse('index')) - else: - messages.error(request,_("You are not authenticated. Please login or provide an email address so we can get back to you.")) - return form({'ticketform':ticketform,},'tickets/form_ticket.html',request) - + messages.success( + request, + _( + "Your ticket has been succesfully open. We will take care of it as soon as possible." + ), + ) + return redirect(reverse("index")) + else: + messages.error( + request, + _( + "You are not authenticated. Please login or provide an email address so we can get back to you." + ), + ) + return form( + {"ticketform": ticketform}, "tickets/form_ticket.html", request + ) + else: ticketform = NewTicketForm - return form({'ticketform':ticketform,},'tickets/form_ticket.html',request) + return form({"ticketform": ticketform}, "tickets/form_ticket.html", request) + @login_required @can_view(Ticket) def aff_ticket(request, ticket, ticketid): """View to display only one ticket""" changestatusform = ChangeStatusTicketForm(request.POST) - if request.method == 'POST': + if request.method == "POST": ticket.solved = not ticket.solved ticket.save() - return render(request,'tickets/aff_ticket.html',{'ticket':ticket,'changestatusform':changestatusform}) + return render( + request, + "tickets/aff_ticket.html", + {"ticket": ticket, "changestatusform": changestatusform}, + ) + @login_required @can_view_all(Ticket) def aff_tickets(request): """ View to display all the tickets """ - tickets_list = Ticket.objects.all().order_by('-date') + tickets_list = Ticket.objects.all().order_by("-date") nbr_tickets = tickets_list.count() nbr_tickets_unsolved = tickets_list.filter(solved=False).count() - if nbr_tickets: + if nbr_tickets: last_ticket_date = tickets_list.first().date else: last_ticket_date = _("Never") - - pagination_number = (GeneralOption - .get_cached_value('pagination_number')) - tickets = re2o_paginator( - request, - tickets_list, - pagination_number, - ) + pagination_number = GeneralOption.get_cached_value("pagination_number") - context = {'tickets_list':tickets, - 'last_ticket_date':last_ticket_date, - 'nbr_tickets':nbr_tickets, - 'nbr_tickets_unsolved':nbr_tickets_unsolved} + tickets = re2o_paginator(request, tickets_list, pagination_number) - return render(request,'tickets/index.html',context=context) + context = { + "tickets_list": tickets, + "last_ticket_date": last_ticket_date, + "nbr_tickets": nbr_tickets, + "nbr_tickets_unsolved": nbr_tickets_unsolved, + } + + return render(request, "tickets/index.html", context=context) def edit_preferences(request): @@ -138,60 +143,75 @@ def edit_preferences(request): preferences_instance, created = Preferences.objects.get_or_create(id=1) preferencesform = EditPreferencesForm( - request.POST or None, - instance = preferences_instance,) - + request.POST or None, instance=preferences_instance + ) + if preferencesform.is_valid(): if preferencesform.changed_data: preferencesform.save() - messages.success(request,'Préférences des Tickets mises à jour') - return redirect(reverse('preferences:display-options',)) + messages.success(request, "Préférences des Tickets mises à jour") + return redirect(reverse("preferences:display-options")) else: - messages.error(request,'Formulaire Invalide') - return form({'preferencesform':preferencesform,},'tickets/form_preferences.html',request) - return form({'preferencesform':preferencesform,},'tickets/form_preferences.html',request) - -# views cannoniques des apps optionnels -def profil(request,user): + messages.error(request, "Formulaire Invalide") + return form( + {"preferencesform": preferencesform}, + "tickets/form_preferences.html", + request, + ) + return form( + {"preferencesform": preferencesform}, "tickets/form_preferences.html", request + ) + + +# views cannoniques des apps optionnels +def profil(request, user): """ View to display the ticket's module on the profil""" - tickets_list = Ticket.objects.filter(user=user).all().order_by('-date') + tickets_list = Ticket.objects.filter(user=user).all().order_by("-date") nbr_tickets = tickets_list.count() nbr_tickets_unsolved = tickets_list.filter(solved=False).count() - if nbr_tickets: + if nbr_tickets: last_ticket_date = tickets_list.first().date else: last_ticket_date = _("Never") - pagination_number = (GeneralOption - .get_cached_value('pagination_large_number')) + pagination_number = GeneralOption.get_cached_value("pagination_large_number") - tickets = re2o_paginator( - request, - tickets_list, - pagination_number, + tickets = re2o_paginator(request, tickets_list, pagination_number) + + context = { + "tickets_list": tickets, + "last_ticket_date": last_ticket_date, + "nbr_tickets": nbr_tickets, + "nbr_tickets_unsolved": nbr_tickets_unsolved, + } + return render_to_string( + "tickets/profil.html", context=context, request=request, using=None ) - context = {'tickets_list':tickets, - 'last_ticket_date':last_ticket_date, - 'nbr_tickets':nbr_tickets, - 'nbr_tickets_unsolved':nbr_tickets_unsolved} - return render_to_string('tickets/profil.html', context=context, request=request, using=None) def preferences(request): """ View to display the settings of the tickets in the preferences page""" pref, created = Preferences.objects.get_or_create(id=1) - context = {'preferences':pref,'language':str(pref.LANGUES[pref.mail_language][1])} - return render_to_string('tickets/preferences.html', context=context, request=request, using=None) + context = { + "preferences": pref, + "language": str(pref.LANGUES[pref.mail_language][1]), + } + return render_to_string( + "tickets/preferences.html", context=context, request=request, using=None + ) + def contact(request): """View to display a contact address on the contact page used here to display a link to open a ticket""" - return render_to_string('tickets/contact.html') + return render_to_string("tickets/contact.html") + def navbar_user(): """View to display the ticket link in thet user's dropdown in the navbar""" - return ('users', render_to_string('tickets/navbar.html')) + return ("users", render_to_string("tickets/navbar.html")) + def navbar_logout(): """View to display the ticket link to log out users""" - return render_to_string('tickets/navbar_logout.html') + return render_to_string("tickets/navbar_logout.html") diff --git a/topologie/acl.py b/topologie/acl.py index 6f8f79d4..c0a37084 100644 --- a/topologie/acl.py +++ b/topologie/acl.py @@ -38,11 +38,9 @@ def can_view(user): A couple (allowed, msg) where allowed is a boolean which is True if viewing is granted and msg is a message (can be None). """ - can = user.has_module_perms('topologie') + can = user.has_module_perms("topologie") return ( can, - None if can else _("You don't have the right to view this" - " application."), - ('topologie',) + None if can else _("You don't have the right to view this" " application."), + ("topologie",), ) - diff --git a/topologie/admin.py b/topologie/admin.py index d1e28945..bc4ca81e 100644 --- a/topologie/admin.py +++ b/topologie/admin.py @@ -46,58 +46,70 @@ from .models import ( class StackAdmin(VersionAdmin): """Administration d'une stack de switches (inclus des switches)""" + pass class SwitchAdmin(VersionAdmin): """Administration d'un switch""" + pass class PortAdmin(VersionAdmin): """Administration d'un port de switches""" + pass class AccessPointAdmin(VersionAdmin): """Administration d'une borne""" + pass class RoomAdmin(VersionAdmin): """Administration d'un chambre""" + pass class ModelSwitchAdmin(VersionAdmin): """Administration d'un modèle de switch""" + pass class ConstructorSwitchAdmin(VersionAdmin): """Administration d'un constructeur d'un switch""" + pass class SwitchBayAdmin(VersionAdmin): """Administration d'une baie de brassage""" + pass class BuildingAdmin(VersionAdmin): """Administration d'un batiment""" + pass class DormitoryAdmin(VersionAdmin): """Administration d'une residence""" + pass class PortProfileAdmin(VersionAdmin): """Administration of a port profile""" + pass + admin.site.register(Port, PortAdmin) admin.site.register(AccessPoint, AccessPointAdmin) admin.site.register(Room, RoomAdmin) diff --git a/topologie/forms.py b/topologie/forms.py index 2f4ac411..91cc8367 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -38,10 +38,7 @@ from django.db.models import Prefetch from django.utils.translation import ugettext_lazy as _ from machines.models import Interface -from machines.forms import ( - EditMachineForm, - NewMachineForm -) +from machines.forms import EditMachineForm, NewMachineForm from re2o.mixins import FormRevMixin from .models import ( @@ -64,12 +61,13 @@ from .models import ( class PortForm(FormRevMixin, ModelForm): """Formulaire pour la création d'un port d'un switch Relié directement au modèle port""" + class Meta: model = Port - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(PortForm, self).__init__(*args, prefix=prefix, **kwargs) @@ -82,226 +80,240 @@ class EditPortForm(FormRevMixin, ModelForm): Optimisation sur les queryset pour machines et port_related pour optimiser le temps de chargement avec select_related (vraiment lent sans)""" + class Meta(PortForm.Meta): - fields = ['room', 'related', 'machine_interface', 'custom_profile', - 'state', 'details'] + fields = [ + "room", + "related", + "machine_interface", + "custom_profile", + "state", + "details", + ] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditPortForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['machine_interface'].queryset = ( - Interface.objects.all().select_related('domain__extension') + self.fields[ + "machine_interface" + ].queryset = Interface.objects.all().select_related("domain__extension") + self.fields["related"].queryset = Port.objects.all().prefetch_related( + "switch__machine_ptr__interface_set__domain__extension" + ) + self.fields["room"].queryset = Room.objects.all().select_related( + "building__dormitory" ) - self.fields['related'].queryset = Port.objects.all().prefetch_related('switch__machine_ptr__interface_set__domain__extension') - self.fields['room'].queryset = Room.objects.all().select_related('building__dormitory') class AddPortForm(FormRevMixin, ModelForm): """Permet d'ajouter un port de switch. Voir EditPortForm pour plus d'informations""" + class Meta(PortForm.Meta): fields = [ - 'port', - 'room', - 'machine_interface', - 'related', - 'custom_profile', - 'state', - 'details' + "port", + "room", + "machine_interface", + "related", + "custom_profile", + "state", + "details", ] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + 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().prefetch_related(Prefetch( - 'switch__interface_set', - queryset=(Interface.objects - .select_related('ipv4__ip_type__extension') - .select_related('domain__extension')) - )) + self.fields[ + "machine_interface" + ].queryset = Interface.objects.all().select_related("domain__extension") + self.fields["related"].queryset = Port.objects.all().prefetch_related( + Prefetch( + "switch__interface_set", + queryset=( + Interface.objects.select_related( + "ipv4__ip_type__extension" + ).select_related("domain__extension") + ), + ) ) class StackForm(FormRevMixin, ModelForm): """Permet d'edition d'une stack : stack_id, et switches membres de la stack""" + class Meta: model = Stack - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(StackForm, self).__init__(*args, prefix=prefix, **kwargs) class AddAccessPointForm(NewMachineForm): """Formulaire pour la création d'une borne Relié directement au modèle borne""" + class Meta: model = AccessPoint - fields = ['location', 'name'] + fields = ["location", "name"] class EditAccessPointForm(EditMachineForm): """Edition d'une borne. Edition complète""" + class Meta: model = AccessPoint - fields = '__all__' + fields = "__all__" class EditSwitchForm(EditMachineForm): """Permet d'éditer un switch : nom et nombre de ports""" + class Meta: model = Switch - fields = '__all__' + fields = "__all__" class NewSwitchForm(NewMachineForm): """Permet de créer un switch : emplacement, paramètres machine, membre d'un stack (option), nombre de ports (number)""" + class Meta(EditSwitchForm.Meta): - fields = ['name', 'switchbay', 'number', 'stack', 'stack_member_id'] + fields = ["name", "switchbay", "number", "stack", "stack_member_id"] class EditRoomForm(FormRevMixin, ModelForm): """Permet d'éediter le nom et commentaire d'une prise murale""" + class Meta: model = Room - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditRoomForm, self).__init__(*args, prefix=prefix, **kwargs) class CreatePortsForm(forms.Form): """Permet de créer une liste de ports pour un switch.""" + begin = forms.IntegerField(label=_("Start:"), min_value=0) end = forms.IntegerField(label=_("End:"), min_value=0) class EditModelSwitchForm(FormRevMixin, ModelForm): """Permet d'éediter un modèle de switch : nom et constructeur""" - members = forms.ModelMultipleChoiceField( - Switch.objects.all(), - required=False - ) + + members = forms.ModelMultipleChoiceField(Switch.objects.all(), required=False) class Meta: model = ModelSwitch - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditModelSwitchForm, self).__init__( - *args, - prefix=prefix, - **kwargs - ) - instance = kwargs.get('instance', None) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditModelSwitchForm, self).__init__(*args, prefix=prefix, **kwargs) + instance = kwargs.get("instance", None) if instance: - self.initial['members'] = Switch.objects.filter(model=instance) + self.initial["members"] = Switch.objects.filter(model=instance) def save(self, commit=True): instance = super().save(commit) - instance.switch_set = self.cleaned_data['members'] + instance.switch_set = self.cleaned_data["members"] return instance class EditConstructorSwitchForm(FormRevMixin, ModelForm): """Permet d'éediter le nom d'un constructeur""" + class Meta: model = ConstructorSwitch - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditConstructorSwitchForm, self).__init__( - *args, - prefix=prefix, - **kwargs - ) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditConstructorSwitchForm, self).__init__(*args, prefix=prefix, **kwargs) class EditSwitchBayForm(FormRevMixin, ModelForm): """Permet d'éditer une baie de brassage""" - members = forms.ModelMultipleChoiceField( - Switch.objects.all(), - required=False - ) + + members = forms.ModelMultipleChoiceField(Switch.objects.all(), required=False) class Meta: model = SwitchBay - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditSwitchBayForm, self).__init__(*args, prefix=prefix, **kwargs) - instance = kwargs.get('instance', None) + instance = kwargs.get("instance", None) if instance: - self.initial['members'] = Switch.objects.filter(switchbay=instance) + self.initial["members"] = Switch.objects.filter(switchbay=instance) def save(self, commit=True): instance = super().save(commit) - instance.switch_set = self.cleaned_data['members'] + instance.switch_set = self.cleaned_data["members"] return instance class EditBuildingForm(FormRevMixin, ModelForm): """Permet d'éditer le batiment""" + class Meta: model = Building - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditBuildingForm, self).__init__(*args, prefix=prefix, **kwargs) class EditDormitoryForm(FormRevMixin, ModelForm): """Enable dormitory edition""" + class Meta: model = Dormitory - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditDormitoryForm, self).__init__(*args, prefix=prefix, **kwargs) class EditPortProfileForm(FormRevMixin, ModelForm): """Form to edit a port profile""" + class Meta: model = PortProfile - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(EditPortProfileForm, self).__init__(*args, - prefix=prefix, - **kwargs) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(EditPortProfileForm, self).__init__(*args, prefix=prefix, **kwargs) + class EditModuleForm(FormRevMixin, ModelForm): """Add and edit module instance""" + class Meta: model = ModuleSwitch - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditModuleForm, self).__init__(*args, prefix=prefix, **kwargs) class EditSwitchModuleForm(FormRevMixin, ModelForm): """Add/edit a switch to a module""" + class Meta: model = ModuleOnSwitch - fields = '__all__' + fields = "__all__" def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EditSwitchModuleForm, self).__init__(*args, prefix=prefix, **kwargs) diff --git a/topologie/migrations/0001_initial.py b/topologie/migrations/0001_initial.py index 02fd7076..5f66ecdb 100644 --- a/topologie/migrations/0001_initial.py +++ b/topologie/migrations/0001_initial.py @@ -28,17 +28,24 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Switch', + name="Switch", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)), - ('building', models.CharField(max_length=10)), - ('number', models.IntegerField()), - ('details', models.CharField(max_length=255, blank=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + verbose_name="ID", + serialize=False, + ), + ), + ("building", models.CharField(max_length=10)), + ("number", models.IntegerField()), + ("details", models.CharField(max_length=255, blank=True)), ], - ), + ) ] diff --git a/topologie/migrations/0002_auto_20160703_1118.py b/topologie/migrations/0002_auto_20160703_1118.py index 86736cd9..cae34d32 100644 --- a/topologie/migrations/0002_auto_20160703_1118.py +++ b/topologie/migrations/0002_auto_20160703_1118.py @@ -29,24 +29,39 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ('topologie', '0001_initial'), + ("contenttypes", "0002_remove_content_type_name"), + ("topologie", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Port', + name="Port", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')), - ('port', models.IntegerField()), - ('details', models.CharField(max_length=255, blank=True)), - ('_object_id', models.PositiveIntegerField(null=True, blank=True)), - ('_content_type', models.ForeignKey(null=True, blank=True, to='contenttypes.ContentType')), - ('switch', models.ForeignKey(related_name='ports', to='topologie.Switch')), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + auto_created=True, + verbose_name="ID", + ), + ), + ("port", models.IntegerField()), + ("details", models.CharField(max_length=255, blank=True)), + ("_object_id", models.PositiveIntegerField(null=True, blank=True)), + ( + "_content_type", + models.ForeignKey( + null=True, blank=True, to="contenttypes.ContentType" + ), + ), + ( + "switch", + models.ForeignKey(related_name="ports", to="topologie.Switch"), + ), ], ), migrations.AlterUniqueTogether( - name='port', - unique_together=set([('_content_type', '_object_id')]), + name="port", unique_together=set([("_content_type", "_object_id")]) ), ] diff --git a/topologie/migrations/0003_room.py b/topologie/migrations/0003_room.py index 7a867be2..8d476fcd 100644 --- a/topologie/migrations/0003_room.py +++ b/topologie/migrations/0003_room.py @@ -28,18 +28,24 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0002_auto_20160703_1118'), - ] + dependencies = [("topologie", "0002_auto_20160703_1118")] operations = [ migrations.CreateModel( - name='Room', + name="Room", fields=[ - ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)), - ('details', models.CharField(max_length=255, blank=True)), - ('building', models.CharField(max_length=255, unique=True)), - ('number', models.IntegerField()), + ( + "id", + models.AutoField( + serialize=False, + auto_created=True, + verbose_name="ID", + primary_key=True, + ), + ), + ("details", models.CharField(max_length=255, blank=True)), + ("building", models.CharField(max_length=255, unique=True)), + ("number", models.IntegerField()), ], - ), + ) ] diff --git a/topologie/migrations/0004_auto_20160703_1122.py b/topologie/migrations/0004_auto_20160703_1122.py index 01e75354..5b8a6038 100644 --- a/topologie/migrations/0004_auto_20160703_1122.py +++ b/topologie/migrations/0004_auto_20160703_1122.py @@ -28,13 +28,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0003_room'), - ] + dependencies = [("topologie", "0003_room")] operations = [ migrations.AlterUniqueTogether( - name='switch', - unique_together=set([('building', 'number')]), - ), + name="switch", unique_together=set([("building", "number")]) + ) ] diff --git a/topologie/migrations/0005_auto_20160703_1123.py b/topologie/migrations/0005_auto_20160703_1123.py index fb3a6c1d..78510538 100644 --- a/topologie/migrations/0005_auto_20160703_1123.py +++ b/topologie/migrations/0005_auto_20160703_1123.py @@ -28,13 +28,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0004_auto_20160703_1122'), - ] + dependencies = [("topologie", "0004_auto_20160703_1122")] operations = [ migrations.AlterUniqueTogether( - name='room', - unique_together=set([('building', 'number')]), - ), + name="room", unique_together=set([("building", "number")]) + ) ] diff --git a/topologie/migrations/0006_auto_20160703_1129.py b/topologie/migrations/0006_auto_20160703_1129.py index bfb49574..df20974c 100644 --- a/topologie/migrations/0006_auto_20160703_1129.py +++ b/topologie/migrations/0006_auto_20160703_1129.py @@ -28,29 +28,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0005_auto_20160703_1123'), - ] + dependencies = [("topologie", "0005_auto_20160703_1123")] operations = [ migrations.AddField( - model_name='room', - name='room', + model_name="room", + name="room", field=models.IntegerField(default=1), preserve_default=False, ), migrations.AlterField( - model_name='room', - name='building', - field=models.CharField(max_length=255), + model_name="room", name="building", field=models.CharField(max_length=255) ), migrations.AlterField( - model_name='room', - name='number', - field=models.IntegerField(blank=True), + model_name="room", name="number", field=models.IntegerField(blank=True) ), migrations.AlterUniqueTogether( - name='room', - unique_together=set([('building', 'room', 'number')]), + name="room", unique_together=set([("building", "room", "number")]) ), ] diff --git a/topologie/migrations/0007_auto_20160703_1148.py b/topologie/migrations/0007_auto_20160703_1148.py index b2c30c21..df01f4fa 100644 --- a/topologie/migrations/0007_auto_20160703_1148.py +++ b/topologie/migrations/0007_auto_20160703_1148.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0006_auto_20160703_1129'), - ] + dependencies = [("topologie", "0006_auto_20160703_1129")] operations = [ migrations.AlterField( - model_name='room', - name='number', + model_name="room", + name="number", field=models.IntegerField(null=True, blank=True), - ), + ) ] diff --git a/topologie/migrations/0008_port_room.py b/topologie/migrations/0008_port_room.py index 53a124b6..5dba66aa 100644 --- a/topologie/migrations/0008_port_room.py +++ b/topologie/migrations/0008_port_room.py @@ -29,15 +29,18 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0007_auto_20160703_1148'), - ] + dependencies = [("topologie", "0007_auto_20160703_1148")] operations = [ migrations.AddField( - model_name='port', - name='room', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, default=1, to='topologie.Room'), + model_name="port", + name="room", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + blank=True, + default=1, + to="topologie.Room", + ), preserve_default=False, - ), + ) ] diff --git a/topologie/migrations/0009_auto_20160703_1200.py b/topologie/migrations/0009_auto_20160703_1200.py index 08cf6498..6db065f2 100644 --- a/topologie/migrations/0009_auto_20160703_1200.py +++ b/topologie/migrations/0009_auto_20160703_1200.py @@ -29,14 +29,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0008_port_room'), - ] + dependencies = [("topologie", "0008_port_room")] operations = [ migrations.AlterField( - model_name='port', - name='room', - field=models.ForeignKey(to='topologie.Room', on_delete=django.db.models.deletion.PROTECT, blank=True, null=True), - ), + model_name="port", + name="room", + field=models.ForeignKey( + to="topologie.Room", + on_delete=django.db.models.deletion.PROTECT, + blank=True, + null=True, + ), + ) ] diff --git a/topologie/migrations/0010_auto_20160704_2148.py b/topologie/migrations/0010_auto_20160704_2148.py index 9e408a5f..5e51a5da 100644 --- a/topologie/migrations/0010_auto_20160704_2148.py +++ b/topologie/migrations/0010_auto_20160704_2148.py @@ -28,30 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0009_auto_20160703_1200'), - ] + dependencies = [("topologie", "0009_auto_20160703_1200")] operations = [ - migrations.RenameField( - model_name='room', - old_name='building', - new_name='name', - ), - migrations.AlterUniqueTogether( - name='room', - unique_together=set([]), - ), - migrations.RemoveField( - model_name='room', - name='details', - ), - migrations.RemoveField( - model_name='room', - name='number', - ), - migrations.RemoveField( - model_name='room', - name='room', - ), + migrations.RenameField(model_name="room", old_name="building", new_name="name"), + migrations.AlterUniqueTogether(name="room", unique_together=set([])), + migrations.RemoveField(model_name="room", name="details"), + migrations.RemoveField(model_name="room", name="number"), + migrations.RemoveField(model_name="room", name="room"), ] diff --git a/topologie/migrations/0011_auto_20160704_2153.py b/topologie/migrations/0011_auto_20160704_2153.py index 5b678799..18caec08 100644 --- a/topologie/migrations/0011_auto_20160704_2153.py +++ b/topologie/migrations/0011_auto_20160704_2153.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0010_auto_20160704_2148'), - ] + dependencies = [("topologie", "0010_auto_20160704_2148")] operations = [ migrations.AlterField( - model_name='room', - name='name', + model_name="room", + name="name", field=models.CharField(max_length=255, unique=True), - ), + ) ] diff --git a/topologie/migrations/0012_port_machine_interface.py b/topologie/migrations/0012_port_machine_interface.py index 9c0bb3bb..e9518085 100644 --- a/topologie/migrations/0012_port_machine_interface.py +++ b/topologie/migrations/0012_port_machine_interface.py @@ -30,14 +30,19 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('machines', '0014_auto_20160706_1220'), - ('topologie', '0011_auto_20160704_2153'), + ("machines", "0014_auto_20160706_1220"), + ("topologie", "0011_auto_20160704_2153"), ] operations = [ migrations.AddField( - model_name='port', - name='machine_interface', - field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, null=True, blank=True, to='machines.Interface'), - ), + model_name="port", + name="machine_interface", + field=models.OneToOneField( + on_delete=django.db.models.deletion.PROTECT, + null=True, + blank=True, + to="machines.Interface", + ), + ) ] diff --git a/topologie/migrations/0013_port_related.py b/topologie/migrations/0013_port_related.py index ef7fb986..057dc48c 100644 --- a/topologie/migrations/0013_port_related.py +++ b/topologie/migrations/0013_port_related.py @@ -28,14 +28,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0012_port_machine_interface'), - ] + dependencies = [("topologie", "0012_port_machine_interface")] operations = [ migrations.AddField( - model_name='port', - name='related', - field=models.OneToOneField(null=True, to='topologie.Port', blank=True, related_name='related_port'), - ), + model_name="port", + name="related", + field=models.OneToOneField( + null=True, to="topologie.Port", blank=True, related_name="related_port" + ), + ) ] diff --git a/topologie/migrations/0014_auto_20160706_1238.py b/topologie/migrations/0014_auto_20160706_1238.py index 17971b79..9a3f44e8 100644 --- a/topologie/migrations/0014_auto_20160706_1238.py +++ b/topologie/migrations/0014_auto_20160706_1238.py @@ -28,21 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0013_port_related'), - ] + dependencies = [("topologie", "0013_port_related")] operations = [ migrations.AlterUniqueTogether( - name='port', - unique_together=set([('switch', 'port')]), - ), - migrations.RemoveField( - model_name='port', - name='_content_type', - ), - migrations.RemoveField( - model_name='port', - name='_object_id', + name="port", unique_together=set([("switch", "port")]) ), + migrations.RemoveField(model_name="port", name="_content_type"), + migrations.RemoveField(model_name="port", name="_object_id"), ] diff --git a/topologie/migrations/0015_auto_20160706_1452.py b/topologie/migrations/0015_auto_20160706_1452.py index d9a49edb..dc9c8c4b 100644 --- a/topologie/migrations/0015_auto_20160706_1452.py +++ b/topologie/migrations/0015_auto_20160706_1452.py @@ -28,18 +28,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0014_auto_20160706_1238'), - ] + dependencies = [("topologie", "0014_auto_20160706_1238")] operations = [ - migrations.RemoveField( - model_name='port', - name='related', - ), + migrations.RemoveField(model_name="port", name="related"), migrations.AddField( - model_name='port', - name='related', - field=models.ManyToManyField(related_name='_port_related_+', to='topologie.Port', blank=True), + model_name="port", + name="related", + field=models.ManyToManyField( + related_name="_port_related_+", to="topologie.Port", blank=True + ), ), ] diff --git a/topologie/migrations/0016_auto_20160706_1531.py b/topologie/migrations/0016_auto_20160706_1531.py index a25df3dc..dcbed85e 100644 --- a/topologie/migrations/0016_auto_20160706_1531.py +++ b/topologie/migrations/0016_auto_20160706_1531.py @@ -28,18 +28,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0015_auto_20160706_1452'), - ] + dependencies = [("topologie", "0015_auto_20160706_1452")] operations = [ - migrations.RemoveField( - model_name='port', - name='related', - ), + migrations.RemoveField(model_name="port", name="related"), migrations.AddField( - model_name='port', - name='related', - field=models.OneToOneField(blank=True, to='topologie.Port', related_name='related_port', null=True), + model_name="port", + name="related", + field=models.OneToOneField( + blank=True, to="topologie.Port", related_name="related_port", null=True + ), ), ] diff --git a/topologie/migrations/0017_auto_20160718_1141.py b/topologie/migrations/0017_auto_20160718_1141.py index 226a84c3..0d56607a 100644 --- a/topologie/migrations/0017_auto_20160718_1141.py +++ b/topologie/migrations/0017_auto_20160718_1141.py @@ -29,14 +29,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0016_auto_20160706_1531'), - ] + dependencies = [("topologie", "0016_auto_20160706_1531")] operations = [ migrations.AlterField( - model_name='port', - name='machine_interface', - field=models.OneToOneField(to='machines.Interface', on_delete=django.db.models.deletion.SET_NULL, null=True, blank=True), - ), + model_name="port", + name="machine_interface", + field=models.OneToOneField( + to="machines.Interface", + on_delete=django.db.models.deletion.SET_NULL, + null=True, + blank=True, + ), + ) ] diff --git a/topologie/migrations/0018_room_details.py b/topologie/migrations/0018_room_details.py index ed0dd057..fcb64901 100644 --- a/topologie/migrations/0018_room_details.py +++ b/topologie/migrations/0018_room_details.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0017_auto_20160718_1141'), - ] + dependencies = [("topologie", "0017_auto_20160718_1141")] operations = [ migrations.AddField( - model_name='room', - name='details', + model_name="room", + name="details", field=models.CharField(blank=True, max_length=255), - ), + ) ] diff --git a/topologie/migrations/0019_auto_20161026_1348.py b/topologie/migrations/0019_auto_20161026_1348.py index 2790b7de..9000cc64 100644 --- a/topologie/migrations/0019_auto_20161026_1348.py +++ b/topologie/migrations/0019_auto_20161026_1348.py @@ -29,29 +29,23 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('machines', '0026_auto_20161026_1348'), - ('topologie', '0018_room_details'), + ("machines", "0026_auto_20161026_1348"), + ("topologie", "0018_room_details"), ] operations = [ migrations.AddField( - model_name='switch', - name='location', - field=models.CharField(default='test', max_length=255), + model_name="switch", + name="location", + field=models.CharField(default="test", max_length=255), preserve_default=False, ), migrations.AddField( - model_name='switch', - name='switch_interface', - field=models.OneToOneField(default=1, to='machines.Interface'), + model_name="switch", + name="switch_interface", + field=models.OneToOneField(default=1, to="machines.Interface"), preserve_default=False, ), - migrations.AlterUniqueTogether( - name='switch', - unique_together=set([]), - ), - migrations.RemoveField( - model_name='switch', - name='building', - ), + migrations.AlterUniqueTogether(name="switch", unique_together=set([])), + migrations.RemoveField(model_name="switch", name="building"), ] diff --git a/topologie/migrations/0020_auto_20161119_0033.py b/topologie/migrations/0020_auto_20161119_0033.py index efb6e739..f6714a0b 100644 --- a/topologie/migrations/0020_auto_20161119_0033.py +++ b/topologie/migrations/0020_auto_20161119_0033.py @@ -29,14 +29,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0019_auto_20161026_1348'), - ] + dependencies = [("topologie", "0019_auto_20161026_1348")] operations = [ migrations.AlterField( - model_name='port', - name='machine_interface', - field=models.ForeignKey(blank=True, to='machines.Interface', null=True, on_delete=django.db.models.deletion.SET_NULL), - ), + model_name="port", + name="machine_interface", + field=models.ForeignKey( + blank=True, + to="machines.Interface", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + ), + ) ] diff --git a/topologie/migrations/0021_port_radius.py b/topologie/migrations/0021_port_radius.py index 91571157..db0a401f 100644 --- a/topologie/migrations/0021_port_radius.py +++ b/topologie/migrations/0021_port_radius.py @@ -28,14 +28,25 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0020_auto_20161119_0033'), - ] + dependencies = [("topologie", "0020_auto_20161119_0033")] operations = [ migrations.AddField( - model_name='port', - name='radius', - field=models.CharField(choices=[('NO', 'NO'), ('STRICT', 'STRICT'), ('BLOQ', 'BLOQ'), ('COMMON', 'COMMON'), (7, 7), (8, 8), (42, 42), (69, 69)], max_length=32, default='NO'), - ), + model_name="port", + name="radius", + field=models.CharField( + choices=[ + ("NO", "NO"), + ("STRICT", "STRICT"), + ("BLOQ", "BLOQ"), + ("COMMON", "COMMON"), + (7, 7), + (8, 8), + (42, 42), + (69, 69), + ], + max_length=32, + default="NO", + ), + ) ] diff --git a/topologie/migrations/0022_auto_20161211_1622.py b/topologie/migrations/0022_auto_20161211_1622.py index b1133466..52e0fcbb 100644 --- a/topologie/migrations/0022_auto_20161211_1622.py +++ b/topologie/migrations/0022_auto_20161211_1622.py @@ -28,14 +28,25 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0021_port_radius'), - ] + dependencies = [("topologie", "0021_port_radius")] operations = [ migrations.AlterField( - model_name='port', - name='radius', - field=models.CharField(max_length=32, default='NO', choices=[('NO', 'NO'), ('STRICT', 'STRICT'), ('BLOQ', 'BLOQ'), ('COMMON', 'COMMON'), ('7', '7'), ('8', '8'), ('42', '42'), ('69', '69')]), - ), + model_name="port", + name="radius", + field=models.CharField( + max_length=32, + default="NO", + choices=[ + ("NO", "NO"), + ("STRICT", "STRICT"), + ("BLOQ", "BLOQ"), + ("COMMON", "COMMON"), + ("7", "7"), + ("8", "8"), + ("42", "42"), + ("69", "69"), + ], + ), + ) ] diff --git a/topologie/migrations/0023_auto_20170817_1654.py b/topologie/migrations/0023_auto_20170817_1654.py index 0f84d7de..6808e576 100644 --- a/topologie/migrations/0023_auto_20170817_1654.py +++ b/topologie/migrations/0023_auto_20170817_1654.py @@ -8,34 +8,44 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0022_auto_20161211_1622'), - ] + dependencies = [("topologie", "0022_auto_20161211_1622")] operations = [ migrations.CreateModel( - name='Stack', + name="Stack", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(blank=True, max_length=32, null=True)), - ('stack_id', models.CharField(max_length=32, unique=True)), - ('details', models.CharField(blank=True, max_length=255, null=True)), - ('member_id_min', models.IntegerField()), - ('member_id_max', models.IntegerField()), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(blank=True, max_length=32, null=True)), + ("stack_id", models.CharField(max_length=32, unique=True)), + ("details", models.CharField(blank=True, max_length=255, null=True)), + ("member_id_min", models.IntegerField()), + ("member_id_max", models.IntegerField()), ], ), migrations.AddField( - model_name='switch', - name='stack_member_id', + model_name="switch", + name="stack_member_id", field=models.IntegerField(blank=True, null=True), ), migrations.AddField( - model_name='switch', - name='stack', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='topologie.Stack'), + model_name="switch", + name="stack", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="topologie.Stack", + ), ), migrations.AlterUniqueTogether( - name='switch', - unique_together=set([('stack', 'stack_member_id')]), + name="switch", unique_together=set([("stack", "stack_member_id")]) ), ] diff --git a/topologie/migrations/0023_auto_20170826_1530.py b/topologie/migrations/0023_auto_20170826_1530.py index 594e7e9f..ed879cff 100644 --- a/topologie/migrations/0023_auto_20170826_1530.py +++ b/topologie/migrations/0023_auto_20170826_1530.py @@ -7,14 +7,28 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0022_auto_20161211_1622'), - ] + dependencies = [("topologie", "0022_auto_20161211_1622")] operations = [ migrations.AlterField( - model_name='port', - name='radius', - field=models.CharField(choices=[('NO', 'NO'), ('STRICT', 'STRICT'), ('BLOQ', 'BLOQ'), ('COMMON', 'COMMON'), ('3', '3'), ('7', '7'), ('8', '8'), ('13', '13'), ('20', '20'), ('42', '42'), ('69', '69')], default='NO', max_length=32), - ), + model_name="port", + name="radius", + field=models.CharField( + choices=[ + ("NO", "NO"), + ("STRICT", "STRICT"), + ("BLOQ", "BLOQ"), + ("COMMON", "COMMON"), + ("3", "3"), + ("7", "7"), + ("8", "8"), + ("13", "13"), + ("20", "20"), + ("42", "42"), + ("69", "69"), + ], + default="NO", + max_length=32, + ), + ) ] diff --git a/topologie/migrations/0024_auto_20170818_1021.py b/topologie/migrations/0024_auto_20170818_1021.py index 0d11be65..4caf7d3e 100644 --- a/topologie/migrations/0024_auto_20170818_1021.py +++ b/topologie/migrations/0024_auto_20170818_1021.py @@ -8,14 +8,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0023_auto_20170817_1654'), - ] + dependencies = [("topologie", "0023_auto_20170817_1654")] operations = [ migrations.AlterField( - model_name='switch', - name='stack', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.Stack'), - ), + model_name="switch", + name="stack", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.Stack", + ), + ) ] diff --git a/topologie/migrations/0024_auto_20170826_1800.py b/topologie/migrations/0024_auto_20170826_1800.py index ce108929..ee1ea2d2 100644 --- a/topologie/migrations/0024_auto_20170826_1800.py +++ b/topologie/migrations/0024_auto_20170826_1800.py @@ -7,14 +7,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0023_auto_20170826_1530'), - ] + dependencies = [("topologie", "0023_auto_20170826_1530")] operations = [ migrations.AlterField( - model_name='port', - name='radius', - field=models.CharField(choices=[('NO', 'NO'), ('STRICT', 'STRICT'), ('BLOQ', 'BLOQ'), ('COMMON', 'COMMON')], default='NO', max_length=32), - ), + model_name="port", + name="radius", + field=models.CharField( + choices=[ + ("NO", "NO"), + ("STRICT", "STRICT"), + ("BLOQ", "BLOQ"), + ("COMMON", "COMMON"), + ], + default="NO", + max_length=32, + ), + ) ] diff --git a/topologie/migrations/0025_merge_20170902_1242.py b/topologie/migrations/0025_merge_20170902_1242.py index 23632040..52a5a365 100644 --- a/topologie/migrations/0025_merge_20170902_1242.py +++ b/topologie/migrations/0025_merge_20170902_1242.py @@ -8,9 +8,8 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('topologie', '0024_auto_20170818_1021'), - ('topologie', '0024_auto_20170826_1800'), + ("topologie", "0024_auto_20170818_1021"), + ("topologie", "0024_auto_20170826_1800"), ] - operations = [ - ] + operations = [] diff --git a/topologie/migrations/0026_auto_20170902_1245.py b/topologie/migrations/0026_auto_20170902_1245.py index e6bd4d96..d7389554 100644 --- a/topologie/migrations/0026_auto_20170902_1245.py +++ b/topologie/migrations/0026_auto_20170902_1245.py @@ -7,14 +7,28 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0025_merge_20170902_1242'), - ] + dependencies = [("topologie", "0025_merge_20170902_1242")] operations = [ migrations.AlterField( - model_name='port', - name='radius', - field=models.CharField(choices=[('NO', 'NO'), ('STRICT', 'STRICT'), ('BLOQ', 'BLOQ'), ('COMMON', 'COMMON'), ('3', '3'), ('7', '7'), ('8', '8'), ('13', '13'), ('20', '20'), ('42', '42'), ('69', '69')], default='NO', max_length=32), - ), + model_name="port", + name="radius", + field=models.CharField( + choices=[ + ("NO", "NO"), + ("STRICT", "STRICT"), + ("BLOQ", "BLOQ"), + ("COMMON", "COMMON"), + ("3", "3"), + ("7", "7"), + ("8", "8"), + ("13", "13"), + ("20", "20"), + ("42", "42"), + ("69", "69"), + ], + default="NO", + max_length=32, + ), + ) ] diff --git a/topologie/migrations/0027_auto_20170905_1442.py b/topologie/migrations/0027_auto_20170905_1442.py index 5f6a682e..7a33fab9 100644 --- a/topologie/migrations/0027_auto_20170905_1442.py +++ b/topologie/migrations/0027_auto_20170905_1442.py @@ -7,18 +7,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0026_auto_20170902_1245'), - ] + dependencies = [("topologie", "0026_auto_20170902_1245")] operations = [ - migrations.AlterModelOptions( - name='room', - options={'ordering': ['name']}, - ), + migrations.AlterModelOptions(name="room", options={"ordering": ["name"]}), migrations.AlterField( - model_name='port', - name='radius', - field=models.CharField(choices=[('NO', 'NO'), ('STRICT', 'STRICT'), ('BLOQ', 'BLOQ'), ('COMMON', 'COMMON')], default='NO', max_length=32), + model_name="port", + name="radius", + field=models.CharField( + choices=[ + ("NO", "NO"), + ("STRICT", "STRICT"), + ("BLOQ", "BLOQ"), + ("COMMON", "COMMON"), + ], + default="NO", + max_length=32, + ), ), ] diff --git a/topologie/migrations/0028_auto_20170913_1503.py b/topologie/migrations/0028_auto_20170913_1503.py index 139af559..5ab48720 100644 --- a/topologie/migrations/0028_auto_20170913_1503.py +++ b/topologie/migrations/0028_auto_20170913_1503.py @@ -7,14 +7,27 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0027_auto_20170905_1442'), - ] + dependencies = [("topologie", "0027_auto_20170905_1442")] operations = [ migrations.AlterField( - model_name='port', - name='radius', - field=models.CharField(choices=[('NO', 'NO'), ('STRICT', 'STRICT'), ('BLOQ', 'BLOQ'), ('COMMON', 'COMMON'), ('2', '2'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('20', '20')], default='NO', max_length=32), - ), + model_name="port", + name="radius", + field=models.CharField( + choices=[ + ("NO", "NO"), + ("STRICT", "STRICT"), + ("BLOQ", "BLOQ"), + ("COMMON", "COMMON"), + ("2", "2"), + ("4", "4"), + ("5", "5"), + ("6", "6"), + ("7", "7"), + ("20", "20"), + ], + default="NO", + max_length=32, + ), + ) ] diff --git a/topologie/migrations/0029_auto_20171002_0334.py b/topologie/migrations/0029_auto_20171002_0334.py index 73ddff1b..09b3466a 100644 --- a/topologie/migrations/0029_auto_20171002_0334.py +++ b/topologie/migrations/0029_auto_20171002_0334.py @@ -7,14 +7,28 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0028_auto_20170913_1503'), - ] + dependencies = [("topologie", "0028_auto_20170913_1503")] operations = [ migrations.AlterField( - model_name='port', - name='radius', - field=models.CharField(choices=[('NO', 'NO'), ('STRICT', 'STRICT'), ('BLOQ', 'BLOQ'), ('COMMON', 'COMMON'), ('3', '3'), ('7', '7'), ('8', '8'), ('13', '13'), ('20', '20'), ('42', '42'), ('69', '69')], default='NO', max_length=32), - ), + model_name="port", + name="radius", + field=models.CharField( + choices=[ + ("NO", "NO"), + ("STRICT", "STRICT"), + ("BLOQ", "BLOQ"), + ("COMMON", "COMMON"), + ("3", "3"), + ("7", "7"), + ("8", "8"), + ("13", "13"), + ("20", "20"), + ("42", "42"), + ("69", "69"), + ], + default="NO", + max_length=32, + ), + ) ] diff --git a/topologie/migrations/0030_auto_20171004_0235.py b/topologie/migrations/0030_auto_20171004_0235.py index ac3ceeba..8e0989b2 100644 --- a/topologie/migrations/0030_auto_20171004_0235.py +++ b/topologie/migrations/0030_auto_20171004_0235.py @@ -8,20 +8,31 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0029_auto_20171002_0334'), - ('machines', '0049_vlan'), - ] + dependencies = [("topologie", "0029_auto_20171002_0334"), ("machines", "0049_vlan")] operations = [ migrations.AddField( - model_name='port', - name='vlan_force', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='machines.Vlan'), + model_name="port", + name="vlan_force", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="machines.Vlan", + ), ), migrations.AlterField( - model_name='port', - name='radius', - field=models.CharField(choices=[('NO', 'NO'), ('STRICT', 'STRICT'), ('BLOQ', 'BLOQ'), ('COMMON', 'COMMON')], default='NO', max_length=32), + model_name="port", + name="radius", + field=models.CharField( + choices=[ + ("NO", "NO"), + ("STRICT", "STRICT"), + ("BLOQ", "BLOQ"), + ("COMMON", "COMMON"), + ], + default="NO", + max_length=32, + ), ), ] diff --git a/topologie/migrations/0031_auto_20171015_2033.py b/topologie/migrations/0031_auto_20171015_2033.py index 674af6c6..f222f272 100644 --- a/topologie/migrations/0031_auto_20171015_2033.py +++ b/topologie/migrations/0031_auto_20171015_2033.py @@ -7,34 +7,28 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0030_auto_20171004_0235'), - ] + dependencies = [("topologie", "0030_auto_20171004_0235")] operations = [ migrations.AlterField( - model_name='port', - name='port', + 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_max', + model_name="stack", + name="member_id_min", field=models.PositiveIntegerField(), ), migrations.AlterField( - model_name='stack', - name='member_id_min', - field=models.PositiveIntegerField(), + model_name="switch", name="number", field=models.PositiveIntegerField() ), migrations.AlterField( - model_name='switch', - name='number', - field=models.PositiveIntegerField(), - ), - migrations.AlterField( - model_name='switch', - name='stack_member_id', + model_name="switch", + name="stack_member_id", field=models.PositiveIntegerField(blank=True, null=True), ), ] diff --git a/topologie/migrations/0032_auto_20171026_0338.py b/topologie/migrations/0032_auto_20171026_0338.py index 37548306..cb0f6e88 100644 --- a/topologie/migrations/0032_auto_20171026_0338.py +++ b/topologie/migrations/0032_auto_20171026_0338.py @@ -8,29 +8,54 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0031_auto_20171015_2033'), - ] + dependencies = [("topologie", "0031_auto_20171015_2033")] operations = [ migrations.CreateModel( - name='ConstructorSwitch', + name="ConstructorSwitch", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), ], ), migrations.CreateModel( - name='ModelSwitch', + name="ModelSwitch", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('reference', models.CharField(max_length=255)), - ('constructor', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='topologie.ConstructorSwitch')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("reference", models.CharField(max_length=255)), + ( + "constructor", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="topologie.ConstructorSwitch", + ), + ), ], ), migrations.AddField( - model_name='switch', - name='model', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.ModelSwitch'), + model_name="switch", + name="model", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.ModelSwitch", + ), ), ] diff --git a/topologie/migrations/0033_auto_20171231_1743.py b/topologie/migrations/0033_auto_20171231_1743.py index c79412d7..9e36c82e 100644 --- a/topologie/migrations/0033_auto_20171231_1743.py +++ b/topologie/migrations/0033_auto_20171231_1743.py @@ -7,33 +7,40 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0032_auto_20171026_0338'), - ] + dependencies = [("topologie", "0032_auto_20171026_0338")] operations = [ migrations.AlterModelOptions( - name='constructorswitch', - options={'permissions': (('view_constructorswitch', 'Peut voir un objet constructorswitch'),)}, + name="constructorswitch", + options={ + "permissions": ( + ("view_constructorswitch", "Peut voir un objet constructorswitch"), + ) + }, ), migrations.AlterModelOptions( - name='modelswitch', - options={'permissions': (('view_modelswitch', 'Peut voir un objet modelswitch'),)}, + name="modelswitch", + options={ + "permissions": (("view_modelswitch", "Peut voir un objet modelswitch"),) + }, ), migrations.AlterModelOptions( - name='port', - options={'permissions': (('view_port', 'Peut voir un objet port'),)}, + name="port", + options={"permissions": (("view_port", "Peut voir un objet port"),)}, ), migrations.AlterModelOptions( - name='room', - options={'ordering': ['name'], 'permissions': (('view_room', 'Peut voir un objet chambre'),)}, + name="room", + options={ + "ordering": ["name"], + "permissions": (("view_room", "Peut voir un objet chambre"),), + }, ), migrations.AlterModelOptions( - name='stack', - options={'permissions': (('view_stack', 'Peut voir un objet stack'),)}, + name="stack", + options={"permissions": (("view_stack", "Peut voir un objet stack"),)}, ), migrations.AlterModelOptions( - name='switch', - options={'permissions': (('view_switch', 'Peut voir un objet switch'),)}, + name="switch", + options={"permissions": (("view_switch", "Peut voir un objet switch"),)}, ), ] diff --git a/topologie/migrations/0034_borne.py b/topologie/migrations/0034_borne.py index 6d827f3a..3365b451 100644 --- a/topologie/migrations/0034_borne.py +++ b/topologie/migrations/0034_borne.py @@ -9,20 +9,33 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('machines', '0076_auto_20180130_1623'), - ('topologie', '0033_auto_20171231_1743'), + ("machines", "0076_auto_20180130_1623"), + ("topologie", "0033_auto_20171231_1743"), ] operations = [ migrations.CreateModel( - name='Borne', + name="Borne", fields=[ - ('interface_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='machines.Interface')), - ('location', models.CharField(help_text="Détails sur la localisation de l'AP", max_length=255)), + ( + "interface_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="machines.Interface", + ), + ), + ( + "location", + models.CharField( + help_text="Détails sur la localisation de l'AP", max_length=255 + ), + ), ], - options={ - 'permissions': (('view_borne', 'Peut voir une borne'),), - }, - bases=('machines.interface',), - ), + options={"permissions": (("view_borne", "Peut voir une borne"),)}, + bases=("machines.interface",), + ) ] diff --git a/topologie/migrations/0035_auto_20180324_0023.py b/topologie/migrations/0035_auto_20180324_0023.py index 7fa69d01..419aa82f 100644 --- a/topologie/migrations/0035_auto_20180324_0023.py +++ b/topologie/migrations/0035_auto_20180324_0023.py @@ -7,14 +7,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0034_borne'), - ] + dependencies = [("topologie", "0034_borne")] operations = [ migrations.AlterField( - model_name='borne', - name='location', - field=models.CharField(blank=True, help_text="Détails sur la localisation de l'AP", max_length=255, null=True), - ), + model_name="borne", + name="location", + field=models.CharField( + blank=True, + help_text="Détails sur la localisation de l'AP", + max_length=255, + null=True, + ), + ) ] diff --git a/topologie/migrations/0036_transferborne.py b/topologie/migrations/0036_transferborne.py index f69fbb85..b3603c36 100644 --- a/topologie/migrations/0036_transferborne.py +++ b/topologie/migrations/0036_transferborne.py @@ -7,18 +7,20 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0035_auto_20180324_0023'), - ] + dependencies = [("topologie", "0035_auto_20180324_0023")] def transfer_bornes(apps, schema_editor): db_alias = schema_editor.connection.alias machinetype = apps.get_model("machines", "MachineType") borne = apps.get_model("topologie", "Borne") - interface = apps.get_model("machines", "Interface") - bornes_list = machinetype.objects.using(db_alias).filter(ip_type__name__icontains='borne') + interface = apps.get_model("machines", "Interface") + bornes_list = machinetype.objects.using(db_alias).filter( + ip_type__name__icontains="borne" + ) if bornes_list: - for inter in interface.objects.using(db_alias).filter(machine_type=bornes_list.first()): + for inter in interface.objects.using(db_alias).filter( + machine_type=bornes_list.first() + ): borne_object = borne() borne_object.interface_ptr_id = inter.pk borne_object.__dict__.update(inter.__dict__) @@ -27,6 +29,4 @@ class Migration(migrations.Migration): def untransfer_bornes(apps, schema_editor): return - operations = [ - migrations.RunPython(transfer_bornes, untransfer_bornes), - ] + operations = [migrations.RunPython(transfer_bornes, untransfer_bornes)] diff --git a/topologie/migrations/0037_auto_20180325_0127.py b/topologie/migrations/0037_auto_20180325_0127.py index 30b34e58..4d9edd4c 100644 --- a/topologie/migrations/0037_auto_20180325_0127.py +++ b/topologie/migrations/0037_auto_20180325_0127.py @@ -9,25 +9,50 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('machines', '0076_auto_20180130_1623'), - ('topologie', '0036_transferborne'), + ("machines", "0076_auto_20180130_1623"), + ("topologie", "0036_transferborne"), ] operations = [ migrations.CreateModel( - name='NewSwitch', + name="NewSwitch", fields=[ - ('interface_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='machines.Interface')), - ('location', models.CharField(max_length=255)), - ('number', models.PositiveIntegerField()), - ('stack_member_id', models.PositiveIntegerField(blank=True, null=True)), - ('model', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.ModelSwitch')), - ('stack', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.Stack')), + ( + "interface_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="machines.Interface", + ), + ), + ("location", models.CharField(max_length=255)), + ("number", models.PositiveIntegerField()), + ("stack_member_id", models.PositiveIntegerField(blank=True, null=True)), + ( + "model", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.ModelSwitch", + ), + ), + ( + "stack", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.Stack", + ), + ), ], - bases=('machines.interface',), + bases=("machines.interface",), ), migrations.AlterUniqueTogether( - name='newswitch', - unique_together=set([('stack', 'stack_member_id')]), + name="newswitch", unique_together=set([("stack", "stack_member_id")]) ), ] diff --git a/topologie/migrations/0038_transfersw.py b/topologie/migrations/0038_transfersw.py index 6f79825f..0b1853cd 100644 --- a/topologie/migrations/0038_transfersw.py +++ b/topologie/migrations/0038_transfersw.py @@ -7,15 +7,13 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0037_auto_20180325_0127'), - ] + dependencies = [("topologie", "0037_auto_20180325_0127")] def transfer_sw(apps, schema_editor): db_alias = schema_editor.connection.alias newswitch = apps.get_model("topologie", "NewSwitch") switch = apps.get_model("topologie", "Switch") - interface = apps.get_model("machines", "Interface") + interface = apps.get_model("machines", "Interface") sw_list = switch.objects.using(db_alias).all() for sw in sw_list: new_sw = newswitch() @@ -26,12 +24,10 @@ class Migration(migrations.Migration): new_sw.stack_member_id = sw.stack_member_id new_sw.model = sw.model new_sw.interface_ptr_id = sw.switch_interface.pk - new_sw.__dict__.update(sw.switch_interface.__dict__) + new_sw.__dict__.update(sw.switch_interface.__dict__) new_sw.save() def untransfer_sw(apps, schema_editor): return - operations = [ - migrations.RunPython(transfer_sw, untransfer_sw), - ] + operations = [migrations.RunPython(transfer_sw, untransfer_sw)] diff --git a/topologie/migrations/0039_port_new_switch.py b/topologie/migrations/0039_port_new_switch.py index 33dda2b4..c3dc70dc 100644 --- a/topologie/migrations/0039_port_new_switch.py +++ b/topologie/migrations/0039_port_new_switch.py @@ -8,14 +8,18 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0038_transfersw'), - ] + dependencies = [("topologie", "0038_transfersw")] operations = [ migrations.AddField( - model_name='port', - name='new_switch', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ports', to='topologie.NewSwitch'), - ), + model_name="port", + name="new_switch", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="ports", + to="topologie.NewSwitch", + ), + ) ] diff --git a/topologie/migrations/0040_transferports.py b/topologie/migrations/0040_transferports.py index 7f72edc2..8e572082 100644 --- a/topologie/migrations/0040_transferports.py +++ b/topologie/migrations/0040_transferports.py @@ -7,9 +7,7 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0039_port_new_switch'), - ] + dependencies = [("topologie", "0039_port_new_switch")] def transfer_port(apps, schema_editor): db_alias = schema_editor.connection.alias @@ -17,12 +15,12 @@ class Migration(migrations.Migration): switch = apps.get_model("topologie", "NewSwitch") port_list = port.objects.using(db_alias).all() for p in port_list: - p.new_switch = switch.objects.filter(interface_ptr=p.switch.switch_interface).first() + p.new_switch = switch.objects.filter( + interface_ptr=p.switch.switch_interface + ).first() p.save() def untransfer_port(apps, schema_editor): return - operations = [ - migrations.RunPython(transfer_port, untransfer_port), - ] + operations = [migrations.RunPython(transfer_port, untransfer_port)] diff --git a/topologie/migrations/0041_transferportsw.py b/topologie/migrations/0041_transferportsw.py index 9e1d979a..a0cb4b0a 100644 --- a/topologie/migrations/0041_transferportsw.py +++ b/topologie/migrations/0041_transferportsw.py @@ -7,18 +7,10 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0040_transferports'), - ] + dependencies = [("topologie", "0040_transferports")] operations = [ - migrations.AlterUniqueTogether( - name='port', - unique_together=set([]), - ), - migrations.RemoveField( - model_name='port', - name='switch', - ), - migrations.RenameField('Port', 'new_switch', 'switch') + migrations.AlterUniqueTogether(name="port", unique_together=set([])), + migrations.RemoveField(model_name="port", name="switch"), + migrations.RenameField("Port", "new_switch", "switch"), ] diff --git a/topologie/migrations/0042_transferswitch.py b/topologie/migrations/0042_transferswitch.py index 96ad49dc..098ec7d4 100644 --- a/topologie/migrations/0042_transferswitch.py +++ b/topologie/migrations/0042_transferswitch.py @@ -7,12 +7,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0041_transferportsw'), - ] + dependencies = [("topologie", "0041_transferportsw")] - operations = [ - migrations.DeleteModel( - name='Switch', - ), - ] + operations = [migrations.DeleteModel(name="Switch")] diff --git a/topologie/migrations/0043_renamenewswitch.py b/topologie/migrations/0043_renamenewswitch.py index 3deeced4..90a9d776 100644 --- a/topologie/migrations/0043_renamenewswitch.py +++ b/topologie/migrations/0043_renamenewswitch.py @@ -7,10 +7,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0042_transferswitch'), - ] + dependencies = [("topologie", "0042_transferswitch")] - operations = [ - migrations.RenameModel(old_name='NewSwitch', new_name='Switch'), - ] + operations = [migrations.RenameModel(old_name="NewSwitch", new_name="Switch")] diff --git a/topologie/migrations/0044_auto_20180326_0002.py b/topologie/migrations/0044_auto_20180326_0002.py index f18b4ed9..b1af46d7 100644 --- a/topologie/migrations/0044_auto_20180326_0002.py +++ b/topologie/migrations/0044_auto_20180326_0002.py @@ -8,21 +8,16 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0043_renamenewswitch'), - ] + dependencies = [("topologie", "0043_renamenewswitch")] operations = [ - migrations.RenameModel( - old_name='Borne', - new_name='AccessPoint', + migrations.RenameModel(old_name="Borne", new_name="AccessPoint"), + migrations.AlterModelOptions( + name="accesspoint", + options={"permissions": (("view_ap", "Peut voir une borne"),)}, ), migrations.AlterModelOptions( - name='accesspoint', - options={'permissions': (('view_ap', 'Peut voir une borne'),)}, - ), - migrations.AlterModelOptions( - name='switch', - options={'permissions': (('view_switch', 'Peut voir un objet switch'),)}, + name="switch", + options={"permissions": (("view_switch", "Peut voir un objet switch"),)}, ), ] diff --git a/topologie/migrations/0045_auto_20180326_0123.py b/topologie/migrations/0045_auto_20180326_0123.py index cf621967..f2dd68d0 100644 --- a/topologie/migrations/0045_auto_20180326_0123.py +++ b/topologie/migrations/0045_auto_20180326_0123.py @@ -8,14 +8,16 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0044_auto_20180326_0002'), - ] + dependencies = [("topologie", "0044_auto_20180326_0002")] operations = [ migrations.AlterField( - model_name='port', - name='switch', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ports', to='topologie.Switch'), - ), + model_name="port", + name="switch", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="ports", + to="topologie.Switch", + ), + ) ] diff --git a/topologie/migrations/0046_auto_20180326_0129.py b/topologie/migrations/0046_auto_20180326_0129.py index dc5e849e..7715ad2f 100644 --- a/topologie/migrations/0046_auto_20180326_0129.py +++ b/topologie/migrations/0046_auto_20180326_0129.py @@ -7,13 +7,10 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0045_auto_20180326_0123'), - ] + dependencies = [("topologie", "0045_auto_20180326_0123")] operations = [ migrations.AlterUniqueTogether( - name='port', - unique_together=set([('switch', 'port')]), - ), + name="port", unique_together=set([("switch", "port")]) + ) ] diff --git a/topologie/migrations/0047_ap_machine.py b/topologie/migrations/0047_ap_machine.py index f09ca318..ad8774ed 100644 --- a/topologie/migrations/0047_ap_machine.py +++ b/topologie/migrations/0047_ap_machine.py @@ -8,19 +8,33 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0046_auto_20180326_0129'), - ] - - + dependencies = [("topologie", "0046_auto_20180326_0129")] operations = [ migrations.CreateModel( - name='NewAccessPoint', + name="NewAccessPoint", fields=[ - ('machine_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='machines.Machine')), - ('location', models.CharField(help_text="Détails sur la localisation de l'AP", max_length=255, null=True, blank=True)), + ( + "machine_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="machines.Machine", + ), + ), + ( + "location", + models.CharField( + help_text="Détails sur la localisation de l'AP", + max_length=255, + null=True, + blank=True, + ), + ), ], - bases=('machines.machine',), - ), + bases=("machines.machine",), + ) ] diff --git a/topologie/migrations/0048_ap_machine.py b/topologie/migrations/0048_ap_machine.py index ed1aa2fd..003f7d1e 100644 --- a/topologie/migrations/0048_ap_machine.py +++ b/topologie/migrations/0048_ap_machine.py @@ -8,9 +8,7 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0047_ap_machine'), - ] + dependencies = [("topologie", "0047_ap_machine")] def transfer_ap(apps, schema_editor): db_alias = schema_editor.connection.alias @@ -29,11 +27,6 @@ class Migration(migrations.Migration): operations = [ migrations.RunPython(transfer_ap, untransfer_ap), - migrations.DeleteModel( - name='AccessPoint', - ), - migrations.RenameModel( - old_name='NewAccessPoint', - new_name='AccessPoint', - ), + migrations.DeleteModel(name="AccessPoint"), + migrations.RenameModel(old_name="NewAccessPoint", new_name="AccessPoint"), ] diff --git a/topologie/migrations/0049_switchs_machine.py b/topologie/migrations/0049_switchs_machine.py index 040ab599..f28a2d8e 100644 --- a/topologie/migrations/0049_switchs_machine.py +++ b/topologie/migrations/0049_switchs_machine.py @@ -8,23 +8,45 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0048_ap_machine'), - ] - - + dependencies = [("topologie", "0048_ap_machine")] operations = [ migrations.CreateModel( - name='NewSw', + name="NewSw", fields=[ - ('machine_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='machines.Machine')), - ('location', models.CharField(max_length=255)), - ('number', models.PositiveIntegerField()), - ('stack_member_id', models.PositiveIntegerField(blank=True, null=True)), - ('model', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.ModelSwitch')), - ('stack', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.Stack')), + ( + "machine_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="machines.Machine", + ), + ), + ("location", models.CharField(max_length=255)), + ("number", models.PositiveIntegerField()), + ("stack_member_id", models.PositiveIntegerField(blank=True, null=True)), + ( + "model", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.ModelSwitch", + ), + ), + ( + "stack", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.Stack", + ), + ), ], - bases=('machines.machine',), - ), + bases=("machines.machine",), + ) ] diff --git a/topologie/migrations/0050_port_new_switch.py b/topologie/migrations/0050_port_new_switch.py index b03a8ee5..1efab4dd 100644 --- a/topologie/migrations/0050_port_new_switch.py +++ b/topologie/migrations/0050_port_new_switch.py @@ -8,14 +8,18 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0049_switchs_machine'), - ] + dependencies = [("topologie", "0049_switchs_machine")] operations = [ migrations.AddField( - model_name='port', - name='new_sw', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ports', to='topologie.NewSw'), - ), + model_name="port", + name="new_sw", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="ports", + to="topologie.NewSw", + ), + ) ] diff --git a/topologie/migrations/0051_switchs_machine.py b/topologie/migrations/0051_switchs_machine.py index d7f1da86..3a5744e0 100644 --- a/topologie/migrations/0051_switchs_machine.py +++ b/topologie/migrations/0051_switchs_machine.py @@ -8,15 +8,13 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0050_port_new_switch'), - ] + dependencies = [("topologie", "0050_port_new_switch")] def transfer_sw(apps, schema_editor): db_alias = schema_editor.connection.alias newswitch = apps.get_model("topologie", "NewSw") switch = apps.get_model("topologie", "Switch") - machine = apps.get_model("machines", "Machine") + machine = apps.get_model("machines", "Machine") sw_list = switch.objects.using(db_alias).all() for sw in sw_list: new_sw = newswitch() @@ -27,13 +25,10 @@ class Migration(migrations.Migration): new_sw.stack_member_id = sw.stack_member_id new_sw.model = sw.model new_sw.machine_ptr_id = sw.interface_ptr.machine.pk - new_sw.__dict__.update(sw.interface_ptr.machine.__dict__) + new_sw.__dict__.update(sw.interface_ptr.machine.__dict__) new_sw.save() def untransfer_sw(apps, schema_editor): return - - operations = [ - migrations.RunPython(transfer_sw, untransfer_sw), - ] + operations = [migrations.RunPython(transfer_sw, untransfer_sw)] diff --git a/topologie/migrations/0052_transferports.py b/topologie/migrations/0052_transferports.py index 88badbe6..3f6c7776 100644 --- a/topologie/migrations/0052_transferports.py +++ b/topologie/migrations/0052_transferports.py @@ -7,9 +7,7 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0051_switchs_machine'), - ] + dependencies = [("topologie", "0051_switchs_machine")] def transfer_port(apps, schema_editor): db_alias = schema_editor.connection.alias @@ -24,14 +22,8 @@ class Migration(migrations.Migration): return operations = [ - migrations.AlterUniqueTogether( - name='port', - unique_together=set([]), - ), - migrations.RunPython(transfer_port, untransfer_port), - migrations.RemoveField( - model_name='port', - name='switch', - ), - migrations.RenameField('Port', 'new_sw', 'switch') + migrations.AlterUniqueTogether(name="port", unique_together=set([])), + migrations.RunPython(transfer_port, untransfer_port), + migrations.RemoveField(model_name="port", name="switch"), + migrations.RenameField("Port", "new_sw", "switch"), ] diff --git a/topologie/migrations/0053_finalsw.py b/topologie/migrations/0053_finalsw.py index 2ed7e2ac..be77f071 100644 --- a/topologie/migrations/0053_finalsw.py +++ b/topologie/migrations/0053_finalsw.py @@ -8,18 +8,9 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0052_transferports'), - ] - - + dependencies = [("topologie", "0052_transferports")] operations = [ - migrations.DeleteModel( - name='Switch', - ), - migrations.RenameModel( - old_name='NewSw', - new_name='Switch', - ), + migrations.DeleteModel(name="Switch"), + migrations.RenameModel(old_name="NewSw", new_name="Switch"), ] diff --git a/topologie/migrations/0054_auto_20180326_1742.py b/topologie/migrations/0054_auto_20180326_1742.py index cfaff01b..98567126 100644 --- a/topologie/migrations/0054_auto_20180326_1742.py +++ b/topologie/migrations/0054_auto_20180326_1742.py @@ -8,31 +8,31 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0053_finalsw'), - ] + dependencies = [("topologie", "0053_finalsw")] operations = [ migrations.AlterModelOptions( - name='accesspoint', - options={'permissions': (('view_ap', 'Peut voir une borne'),)}, + name="accesspoint", + options={"permissions": (("view_ap", "Peut voir une borne"),)}, ), migrations.AlterModelOptions( - name='switch', - options={'permissions': (('view_switch', 'Peut voir un objet switch'),)}, + name="switch", + options={"permissions": (("view_switch", "Peut voir un objet switch"),)}, ), migrations.AlterField( - model_name='port', - name='switch', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ports', to='topologie.Switch'), + model_name="port", + name="switch", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="ports", + to="topologie.Switch", + ), preserve_default=False, ), migrations.AlterUniqueTogether( - name='port', - unique_together=set([('switch', 'port')]), + name="port", unique_together=set([("switch", "port")]) ), migrations.AlterUniqueTogether( - name='switch', - unique_together=set([('stack', 'stack_member_id')]), + name="switch", unique_together=set([("stack", "stack_member_id")]) ), ] diff --git a/topologie/migrations/0055_auto_20180329_0431.py b/topologie/migrations/0055_auto_20180329_0431.py index f8633d84..a7b232bf 100644 --- a/topologie/migrations/0055_auto_20180329_0431.py +++ b/topologie/migrations/0055_auto_20180329_0431.py @@ -7,13 +7,11 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0054_auto_20180326_1742'), - ] + dependencies = [("topologie", "0054_auto_20180326_1742")] operations = [ migrations.AlterModelOptions( - name='accesspoint', - options={'permissions': (('view_accesspoint', 'Peut voir une borne'),)}, - ), + name="accesspoint", + options={"permissions": (("view_accesspoint", "Peut voir une borne"),)}, + ) ] diff --git a/topologie/migrations/0056_building_switchbay.py b/topologie/migrations/0056_building_switchbay.py index 3f705263..c166adc7 100644 --- a/topologie/migrations/0056_building_switchbay.py +++ b/topologie/migrations/0056_building_switchbay.py @@ -9,33 +9,68 @@ import re2o.mixins class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0055_auto_20180329_0431'), - ] + dependencies = [("topologie", "0055_auto_20180329_0431")] operations = [ migrations.CreateModel( - name='Building', + name="Building", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), ], options={ - 'permissions': (('view_building', 'Peut voir un objet batiment'),), + "permissions": (("view_building", "Peut voir un objet batiment"),) }, bases=(re2o.mixins.AclMixin, re2o.mixins.RevMixin, models.Model), ), migrations.CreateModel( - name='SwitchBay', + name="SwitchBay", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), - ('info', models.CharField(blank=True, help_text='Informations particulières', max_length=255, null=True)), - ('building', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='topologie.Building')), - ('members', models.ManyToManyField(blank=True, related_name='bay_switches', to='topologie.Switch')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), + ( + "info", + models.CharField( + blank=True, + help_text="Informations particulières", + max_length=255, + null=True, + ), + ), + ( + "building", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="topologie.Building", + ), + ), + ( + "members", + models.ManyToManyField( + blank=True, related_name="bay_switches", to="topologie.Switch" + ), + ), ], options={ - 'permissions': (('view_switchbay', 'Peut voir un objet baie de brassage'),), + "permissions": ( + ("view_switchbay", "Peut voir un objet baie de brassage"), + ) }, bases=(re2o.mixins.AclMixin, re2o.mixins.RevMixin, models.Model), ), diff --git a/topologie/migrations/0057_auto_20180408_0316.py b/topologie/migrations/0057_auto_20180408_0316.py index e4a0d09b..3f512be9 100644 --- a/topologie/migrations/0057_auto_20180408_0316.py +++ b/topologie/migrations/0057_auto_20180408_0316.py @@ -8,18 +8,18 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0056_building_switchbay'), - ] + dependencies = [("topologie", "0056_building_switchbay")] operations = [ - migrations.RemoveField( - model_name='switchbay', - name='members', - ), + migrations.RemoveField(model_name="switchbay", name="members"), migrations.AddField( - model_name='switch', - name='switchbay', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.SwitchBay'), + model_name="switch", + name="switchbay", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.SwitchBay", + ), ), ] diff --git a/topologie/migrations/0058_remove_switch_location.py b/topologie/migrations/0058_remove_switch_location.py index 0d75fc67..7308e993 100644 --- a/topologie/migrations/0058_remove_switch_location.py +++ b/topologie/migrations/0058_remove_switch_location.py @@ -7,13 +7,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0057_auto_20180408_0316'), - ] + dependencies = [("topologie", "0057_auto_20180408_0316")] - operations = [ - migrations.RemoveField( - model_name='switch', - name='location', - ), - ] + operations = [migrations.RemoveField(model_name="switch", name="location")] diff --git a/topologie/migrations/0059_auto_20180415_2249.py b/topologie/migrations/0059_auto_20180415_2249.py index a58b710d..211b5799 100644 --- a/topologie/migrations/0059_auto_20180415_2249.py +++ b/topologie/migrations/0059_auto_20180415_2249.py @@ -8,29 +8,41 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0058_remove_switch_location'), - ] + dependencies = [("topologie", "0058_remove_switch_location")] operations = [ migrations.AlterField( - model_name='switch', - name='model', - field=models.ForeignKey(blank=True, help_text='Modèle du switch', null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.ModelSwitch'), + model_name="switch", + name="model", + field=models.ForeignKey( + blank=True, + help_text="Modèle du switch", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.ModelSwitch", + ), ), migrations.AlterField( - model_name='switch', - name='number', - field=models.PositiveIntegerField(help_text='Nombre de ports'), + model_name="switch", + name="number", + field=models.PositiveIntegerField(help_text="Nombre de ports"), ), migrations.AlterField( - model_name='switch', - name='stack_member_id', - field=models.PositiveIntegerField(blank=True, help_text='Baie de brassage du switch', null=True), + model_name="switch", + name="stack_member_id", + field=models.PositiveIntegerField( + blank=True, help_text="Baie de brassage du switch", null=True + ), ), migrations.AlterField( - model_name='switch', - name='switchbay', - field=models.ForeignKey(blank=True, help_text='Baie de brassage du switch', null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.SwitchBay'), + model_name="switch", + name="switchbay", + field=models.ForeignKey( + blank=True, + help_text="Baie de brassage du switch", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.SwitchBay", + ), ), ] diff --git a/topologie/migrations/0060_server.py b/topologie/migrations/0060_server.py index af067e7b..7d757429 100644 --- a/topologie/migrations/0060_server.py +++ b/topologie/migrations/0060_server.py @@ -8,18 +8,15 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('machines', '0081_auto_20180521_1413'), - ('topologie', '0059_auto_20180415_2249'), + ("machines", "0081_auto_20180521_1413"), + ("topologie", "0059_auto_20180415_2249"), ] operations = [ migrations.CreateModel( - name='Server', - fields=[ - ], - options={ - 'proxy': True, - }, - bases=('machines.machine',), - ), + name="Server", + fields=[], + options={"proxy": True}, + bases=("machines.machine",), + ) ] diff --git a/topologie/migrations/0061_portprofile.py b/topologie/migrations/0061_portprofile.py index 88e2d9ab..dd26f988 100644 --- a/topologie/migrations/0061_portprofile.py +++ b/topologie/migrations/0061_portprofile.py @@ -13,88 +13,298 @@ def transfer_profil(apps, schema_editor): profil = apps.get_model("topologie", "PortProfile") vlan = apps.get_model("machines", "Vlan") port_list = port.objects.using(db_alias).all() - profil_nothing = profil.objects.using(db_alias).create(name='nothing', profil_default='nothing', radius_type='NO') - profil_uplink = profil.objects.using(db_alias).create(name='uplink', profil_default='uplink', radius_type='NO') - profil_machine = profil.objects.using(db_alias).create(name='asso_machine', profil_default='asso_machine', radius_type='NO') - profil_room = profil.objects.using(db_alias).create(name='room', profil_default='room', radius_type='NO') - profil_borne = profil.objects.using(db_alias).create(name='accesspoint', profil_default='accesspoint', radius_type='NO') + profil_nothing = profil.objects.using(db_alias).create( + name="nothing", profil_default="nothing", radius_type="NO" + ) + profil_uplink = profil.objects.using(db_alias).create( + name="uplink", profil_default="uplink", radius_type="NO" + ) + profil_machine = profil.objects.using(db_alias).create( + name="asso_machine", profil_default="asso_machine", radius_type="NO" + ) + profil_room = profil.objects.using(db_alias).create( + name="room", profil_default="room", radius_type="NO" + ) + profil_borne = profil.objects.using(db_alias).create( + name="accesspoint", profil_default="accesspoint", radius_type="NO" + ) for vlan_instance in vlan.objects.using(db_alias).all(): if port.objects.using(db_alias).filter(vlan_force=vlan_instance): - custom_profile = profil.objects.using(db_alias).create(name='vlan-force-' + str(vlan_instance.vlan_id), radius_type='NO', vlan_untagged=vlan_instance) - port.objects.using(db_alias).filter(vlan_force=vlan_instance).update(custom_profile=custom_profile) - if port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').count() and port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').count(): - profil_room.radius_type = 'MAC-radius' - profil_room.radius_mode = 'STRICT' - common_profil = profil.objects.using(db_alias).create(name='mac-radius-common', radius_type='MAC-radius', radius_mode='COMMON') - no_rad_profil = profil.objects.using(db_alias).create(name='no-radius', radius_type='NO') - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').update(custom_profile=common_profil) - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').update(custom_profile=no_rad_profil) - elif port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').count() and port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').count(): - profil_room.radius_type = 'MAC-radius' - profil_room.radius_mode = 'COMMON' - strict_profil = profil.objects.using(db_alias).create(name='mac-radius-strict', radius_type='MAC-radius', radius_mode='STRICT') - no_rad_profil = profil.objects.using(db_alias).create(name='no-radius', radius_type='NO') - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').update(custom_profile=strict_profil) - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').update(custom_profile=no_rad_profil) + custom_profile = profil.objects.using(db_alias).create( + name="vlan-force-" + str(vlan_instance.vlan_id), + radius_type="NO", + vlan_untagged=vlan_instance, + ) + port.objects.using(db_alias).filter(vlan_force=vlan_instance).update( + custom_profile=custom_profile + ) + if ( + port.objects.using(db_alias) + .filter(room__isnull=False) + .filter(radius="STRICT") + .count() + > port.objects.using(db_alias) + .filter(room__isnull=False) + .filter(radius="NO") + .count() + and port.objects.using(db_alias) + .filter(room__isnull=False) + .filter(radius="STRICT") + .count() + > port.objects.using(db_alias) + .filter(room__isnull=False) + .filter(radius="COMMON") + .count() + ): + profil_room.radius_type = "MAC-radius" + profil_room.radius_mode = "STRICT" + common_profil = profil.objects.using(db_alias).create( + name="mac-radius-common", radius_type="MAC-radius", radius_mode="COMMON" + ) + no_rad_profil = profil.objects.using(db_alias).create( + name="no-radius", radius_type="NO" + ) + port.objects.using(db_alias).filter(room__isnull=False).filter( + radius="COMMON" + ).update(custom_profile=common_profil) + port.objects.using(db_alias).filter(room__isnull=False).filter( + radius="NO" + ).update(custom_profile=no_rad_profil) + elif ( + port.objects.using(db_alias) + .filter(room__isnull=False) + .filter(radius="COMMON") + .count() + > port.objects.using(db_alias) + .filter(room__isnull=False) + .filter(radius="NO") + .count() + and port.objects.using(db_alias) + .filter(room__isnull=False) + .filter(radius="COMMON") + .count() + > port.objects.using(db_alias) + .filter(room__isnull=False) + .filter(radius="STRICT") + .count() + ): + profil_room.radius_type = "MAC-radius" + profil_room.radius_mode = "COMMON" + strict_profil = profil.objects.using(db_alias).create( + name="mac-radius-strict", radius_type="MAC-radius", radius_mode="STRICT" + ) + no_rad_profil = profil.objects.using(db_alias).create( + name="no-radius", radius_type="NO" + ) + port.objects.using(db_alias).filter(room__isnull=False).filter( + radius="STRICT" + ).update(custom_profile=strict_profil) + port.objects.using(db_alias).filter(room__isnull=False).filter( + radius="NO" + ).update(custom_profile=no_rad_profil) else: - strict_profil = profil.objects.using(db_alias).create(name='mac-radius-strict', radius_type='MAC-radius', radius_mode='STRICT') - common_profil = profil.objects.using(db_alias).create(name='mac-radius-common', radius_type='MAC-radius', radius_mode='COMMON') - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').update(custom_profile=strict_profil) - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').update(custom_profile=common_profil) + strict_profil = profil.objects.using(db_alias).create( + name="mac-radius-strict", radius_type="MAC-radius", radius_mode="STRICT" + ) + common_profil = profil.objects.using(db_alias).create( + name="mac-radius-common", radius_type="MAC-radius", radius_mode="COMMON" + ) + port.objects.using(db_alias).filter(room__isnull=False).filter( + radius="STRICT" + ).update(custom_profile=strict_profil) + port.objects.using(db_alias).filter(room__isnull=False).filter( + radius="NO" + ).update(custom_profile=common_profil) profil_room.save() class Migration(migrations.Migration): dependencies = [ - ('machines', '0082_auto_20180525_2209'), - ('topologie', '0060_server'), + ("machines", "0082_auto_20180525_2209"), + ("topologie", "0060_server"), ] operations = [ migrations.CreateModel( - name='PortProfile', + name="PortProfile", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255, verbose_name='Name')), - ('profil_default', models.CharField(blank=True, choices=[('room', 'room'), ('accespoint', 'accesspoint'), ('uplink', 'uplink'), ('asso_machine', 'asso_machine'), ('nothing', 'nothing')], max_length=32, null=True, unique=True, verbose_name='profil default')), - ('radius_type', models.CharField(choices=[('NO', 'NO'), ('802.1X', '802.1X'), ('MAC-radius', 'MAC-radius')], help_text='Type of radius auth : inactive, mac-address or 802.1X', max_length=32, verbose_name='RADIUS type')), - ('radius_mode', models.CharField(choices=[('STRICT', 'STRICT'), ('COMMON', 'COMMON')], default='COMMON', help_text='In case of mac-auth : mode common or strict on this port', max_length=32, verbose_name='RADIUS mode')), - ('speed', models.CharField(choices=[('10-half', '10-half'), ('100-half', '100-half'), ('10-full', '10-full'), ('100-full', '100-full'), ('1000-full', '1000-full'), ('auto', 'auto'), ('auto-10', 'auto-10'), ('auto-100', 'auto-100')], default='auto', help_text='Port speed limit', max_length=32, verbose_name='Speed')), - ('mac_limit', models.IntegerField(blank=True, help_text='Limit of mac-address on this port', null=True, verbose_name='Mac limit')), - ('flow_control', models.BooleanField(default=False, help_text='Flow control', verbose_name='Flow control')), - ('dhcp_snooping', models.BooleanField(default=False, help_text='Protect against rogue dhcp', verbose_name='Dhcp snooping')), - ('dhcpv6_snooping', models.BooleanField(default=False, help_text='Protect against rogue dhcpv6', verbose_name='Dhcpv6 snooping')), - ('arp_protect', models.BooleanField(default=False, help_text='Check if ip is dhcp assigned', verbose_name='Arp protect')), - ('ra_guard', models.BooleanField(default=False, help_text='Protect against rogue ra', verbose_name='Ra guard')), - ('loop_protect', models.BooleanField(default=False, help_text='Protect again loop', verbose_name='Loop Protect')), - ('vlan_tagged', models.ManyToManyField(blank=True, related_name='vlan_tagged', to='machines.Vlan', verbose_name='VLAN(s) tagged')), - ('vlan_untagged', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='vlan_untagged', to='machines.Vlan', verbose_name='VLAN untagged')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255, verbose_name="Name")), + ( + "profil_default", + models.CharField( + blank=True, + choices=[ + ("room", "room"), + ("accespoint", "accesspoint"), + ("uplink", "uplink"), + ("asso_machine", "asso_machine"), + ("nothing", "nothing"), + ], + max_length=32, + null=True, + unique=True, + verbose_name="profil default", + ), + ), + ( + "radius_type", + models.CharField( + choices=[ + ("NO", "NO"), + ("802.1X", "802.1X"), + ("MAC-radius", "MAC-radius"), + ], + help_text="Type of radius auth : inactive, mac-address or 802.1X", + max_length=32, + verbose_name="RADIUS type", + ), + ), + ( + "radius_mode", + models.CharField( + choices=[("STRICT", "STRICT"), ("COMMON", "COMMON")], + default="COMMON", + help_text="In case of mac-auth : mode common or strict on this port", + max_length=32, + verbose_name="RADIUS mode", + ), + ), + ( + "speed", + models.CharField( + choices=[ + ("10-half", "10-half"), + ("100-half", "100-half"), + ("10-full", "10-full"), + ("100-full", "100-full"), + ("1000-full", "1000-full"), + ("auto", "auto"), + ("auto-10", "auto-10"), + ("auto-100", "auto-100"), + ], + default="auto", + help_text="Port speed limit", + max_length=32, + verbose_name="Speed", + ), + ), + ( + "mac_limit", + models.IntegerField( + blank=True, + help_text="Limit of mac-address on this port", + null=True, + verbose_name="Mac limit", + ), + ), + ( + "flow_control", + models.BooleanField( + default=False, + help_text="Flow control", + verbose_name="Flow control", + ), + ), + ( + "dhcp_snooping", + models.BooleanField( + default=False, + help_text="Protect against rogue dhcp", + verbose_name="Dhcp snooping", + ), + ), + ( + "dhcpv6_snooping", + models.BooleanField( + default=False, + help_text="Protect against rogue dhcpv6", + verbose_name="Dhcpv6 snooping", + ), + ), + ( + "arp_protect", + models.BooleanField( + default=False, + help_text="Check if ip is dhcp assigned", + verbose_name="Arp protect", + ), + ), + ( + "ra_guard", + models.BooleanField( + default=False, + help_text="Protect against rogue ra", + verbose_name="Ra guard", + ), + ), + ( + "loop_protect", + models.BooleanField( + default=False, + help_text="Protect again loop", + verbose_name="Loop Protect", + ), + ), + ( + "vlan_tagged", + models.ManyToManyField( + blank=True, + related_name="vlan_tagged", + to="machines.Vlan", + verbose_name="VLAN(s) tagged", + ), + ), + ( + "vlan_untagged", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="vlan_untagged", + to="machines.Vlan", + verbose_name="VLAN untagged", + ), + ), ], options={ - 'verbose_name': 'Port profile', - 'permissions': (('view_port_profile', 'Can view a port profile object'),), - 'verbose_name_plural': 'Port profiles', + "verbose_name": "Port profile", + "permissions": ( + ("view_port_profile", "Can view a port profile object"), + ), + "verbose_name_plural": "Port profiles", }, bases=(re2o.mixins.AclMixin, re2o.mixins.RevMixin, models.Model), ), migrations.AddField( - model_name='port', - name='custom_profile', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='topologie.PortProfile'), + model_name="port", + name="custom_profile", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="topologie.PortProfile", + ), ), migrations.RunPython(transfer_profil), - migrations.RemoveField( - model_name='port', - name='radius', - ), - migrations.RemoveField( - model_name='port', - name='vlan_force', - ), + migrations.RemoveField(model_name="port", name="radius"), + migrations.RemoveField(model_name="port", name="vlan_force"), migrations.AddField( - model_name='port', - name='state', - field=models.BooleanField(default=True, help_text='Port state Active', verbose_name='Port State Active'), + model_name="port", + name="state", + field=models.BooleanField( + default=True, + help_text="Port state Active", + verbose_name="Port State Active", + ), ), ] diff --git a/topologie/migrations/0062_auto_20180815_1918.py b/topologie/migrations/0062_auto_20180815_1918.py index fc100258..a36f0ef0 100644 --- a/topologie/migrations/0062_auto_20180815_1918.py +++ b/topologie/migrations/0062_auto_20180815_1918.py @@ -8,139 +8,273 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0061_portprofile'), - ] + dependencies = [("topologie", "0061_portprofile")] operations = [ migrations.AlterModelOptions( - name='accesspoint', - options={'permissions': (('view_accesspoint', 'Can view an access point object'),), 'verbose_name': 'access point', 'verbose_name_plural': 'access points'}, + name="accesspoint", + options={ + "permissions": ( + ("view_accesspoint", "Can view an access point object"), + ), + "verbose_name": "access point", + "verbose_name_plural": "access points", + }, ), migrations.AlterModelOptions( - name='building', - options={'permissions': (('view_building', 'Can view a building object'),), 'verbose_name': 'building', 'verbose_name_plural': 'buildings'}, + name="building", + options={ + "permissions": (("view_building", "Can view a building object"),), + "verbose_name": "building", + "verbose_name_plural": "buildings", + }, ), migrations.AlterModelOptions( - name='constructorswitch', - options={'permissions': (('view_constructorswitch', 'Can view a switch constructor object'),), 'verbose_name': 'switch constructor', 'verbose_name_plural': 'switch constructors'}, + name="constructorswitch", + options={ + "permissions": ( + ("view_constructorswitch", "Can view a switch constructor object"), + ), + "verbose_name": "switch constructor", + "verbose_name_plural": "switch constructors", + }, ), migrations.AlterModelOptions( - name='modelswitch', - options={'permissions': (('view_modelswitch', 'Can view a switch model object'),), 'verbose_name': 'switch model', 'verbose_name_plural': 'switch models'}, + name="modelswitch", + options={ + "permissions": ( + ("view_modelswitch", "Can view a switch model object"), + ), + "verbose_name": "switch model", + "verbose_name_plural": "switch models", + }, ), migrations.AlterModelOptions( - name='port', - options={'permissions': (('view_port', 'Can view a port object'),), 'verbose_name': 'port', 'verbose_name_plural': 'ports'}, + name="port", + options={ + "permissions": (("view_port", "Can view a port object"),), + "verbose_name": "port", + "verbose_name_plural": "ports", + }, ), migrations.AlterModelOptions( - name='portprofile', - options={'permissions': (('view_port_profile', 'Can view a port profile object'),), 'verbose_name': 'port profile', 'verbose_name_plural': 'port profiles'}, + name="portprofile", + options={ + "permissions": ( + ("view_port_profile", "Can view a port profile object"), + ), + "verbose_name": "port profile", + "verbose_name_plural": "port profiles", + }, ), migrations.AlterModelOptions( - name='room', - options={'ordering': ['name'], 'permissions': (('view_room', 'Can view a room object'),), 'verbose_name': 'room', 'verbose_name_plural': 'rooms'}, + name="room", + options={ + "ordering": ["name"], + "permissions": (("view_room", "Can view a room object"),), + "verbose_name": "room", + "verbose_name_plural": "rooms", + }, ), migrations.AlterModelOptions( - name='stack', - options={'permissions': (('view_stack', 'Can view a stack object'),), 'verbose_name': 'switches stack', 'verbose_name_plural': 'switches stacks'}, + name="stack", + options={ + "permissions": (("view_stack", "Can view a stack object"),), + "verbose_name": "switches stack", + "verbose_name_plural": "switches stacks", + }, ), migrations.AlterModelOptions( - name='switch', - options={'permissions': (('view_switch', 'Can view a switch object'),), 'verbose_name': 'switch', 'verbose_name_plural': 'switches'}, + name="switch", + options={ + "permissions": (("view_switch", "Can view a switch object"),), + "verbose_name": "switch", + "verbose_name_plural": "switches", + }, ), migrations.AlterModelOptions( - name='switchbay', - options={'permissions': (('view_switchbay', 'Can view a switch bay object'),), 'verbose_name': 'switch bay', 'verbose_name_plural': 'switch bays'}, + name="switchbay", + options={ + "permissions": (("view_switchbay", "Can view a switch bay object"),), + "verbose_name": "switch bay", + "verbose_name_plural": "switch bays", + }, ), migrations.AlterField( - model_name='accesspoint', - name='location', - field=models.CharField(blank=True, help_text="Details about the AP's location", max_length=255, null=True), + model_name="accesspoint", + name="location", + field=models.CharField( + blank=True, + help_text="Details about the AP's location", + max_length=255, + null=True, + ), ), migrations.AlterField( - model_name='port', - name='state', - field=models.BooleanField(default=True, help_text='Port state Active', verbose_name='Port state Active'), + model_name="port", + name="state", + field=models.BooleanField( + default=True, + help_text="Port state Active", + verbose_name="Port state Active", + ), ), migrations.AlterField( - model_name='portprofile', - name='arp_protect', - field=models.BooleanField(default=False, help_text='Check if IP adress is DHCP assigned', verbose_name='ARP protection'), + model_name="portprofile", + name="arp_protect", + field=models.BooleanField( + default=False, + help_text="Check if IP adress is DHCP assigned", + verbose_name="ARP protection", + ), ), migrations.AlterField( - model_name='portprofile', - name='dhcp_snooping', - field=models.BooleanField(default=False, help_text='Protect against rogue DHCP', verbose_name='DHCP snooping'), + model_name="portprofile", + name="dhcp_snooping", + field=models.BooleanField( + default=False, + help_text="Protect against rogue DHCP", + verbose_name="DHCP snooping", + ), ), migrations.AlterField( - model_name='portprofile', - name='dhcpv6_snooping', - field=models.BooleanField(default=False, help_text='Protect against rogue DHCPv6', verbose_name='DHCPv6 snooping'), + model_name="portprofile", + name="dhcpv6_snooping", + field=models.BooleanField( + default=False, + help_text="Protect against rogue DHCPv6", + verbose_name="DHCPv6 snooping", + ), ), migrations.AlterField( - model_name='portprofile', - name='flow_control', - field=models.BooleanField(default=False, help_text='Flow control'), + model_name="portprofile", + name="flow_control", + field=models.BooleanField(default=False, help_text="Flow control"), ), migrations.AlterField( - model_name='portprofile', - name='loop_protect', - field=models.BooleanField(default=False, help_text='Protect against loop', verbose_name='Loop protection'), + model_name="portprofile", + name="loop_protect", + field=models.BooleanField( + default=False, + help_text="Protect against loop", + verbose_name="Loop protection", + ), ), migrations.AlterField( - model_name='portprofile', - name='mac_limit', - field=models.IntegerField(blank=True, help_text='Limit of MAC-address on this port', null=True, verbose_name='MAC limit'), + model_name="portprofile", + name="mac_limit", + field=models.IntegerField( + blank=True, + help_text="Limit of MAC-address on this port", + null=True, + verbose_name="MAC limit", + ), ), migrations.AlterField( - model_name='portprofile', - name='profil_default', - field=models.CharField(blank=True, choices=[('room', 'room'), ('accespoint', 'accesspoint'), ('uplink', 'uplink'), ('asso_machine', 'asso_machine'), ('nothing', 'nothing')], max_length=32, null=True, unique=True, verbose_name='Default profile'), + model_name="portprofile", + name="profil_default", + field=models.CharField( + blank=True, + choices=[ + ("room", "room"), + ("accespoint", "accesspoint"), + ("uplink", "uplink"), + ("asso_machine", "asso_machine"), + ("nothing", "nothing"), + ], + max_length=32, + null=True, + unique=True, + verbose_name="Default profile", + ), ), migrations.AlterField( - model_name='portprofile', - name='ra_guard', - field=models.BooleanField(default=False, help_text='Protect against rogue RA', verbose_name='RA guard'), + model_name="portprofile", + name="ra_guard", + field=models.BooleanField( + default=False, + help_text="Protect against rogue RA", + verbose_name="RA guard", + ), ), migrations.AlterField( - model_name='portprofile', - name='radius_mode', - field=models.CharField(choices=[('STRICT', 'STRICT'), ('COMMON', 'COMMON')], default='COMMON', help_text='In case of MAC-authentication : mode COMMON or STRICT on this port', max_length=32, verbose_name='RADIUS mode'), + model_name="portprofile", + name="radius_mode", + field=models.CharField( + choices=[("STRICT", "STRICT"), ("COMMON", "COMMON")], + default="COMMON", + help_text="In case of MAC-authentication : mode COMMON or STRICT on this port", + max_length=32, + verbose_name="RADIUS mode", + ), ), migrations.AlterField( - model_name='portprofile', - name='radius_type', - field=models.CharField(choices=[('NO', 'NO'), ('802.1X', '802.1X'), ('MAC-radius', 'MAC-radius')], help_text='Type of RADIUS authentication : inactive, MAC-address or 802.1X', max_length=32, verbose_name='RADIUS type'), + model_name="portprofile", + name="radius_type", + field=models.CharField( + choices=[ + ("NO", "NO"), + ("802.1X", "802.1X"), + ("MAC-radius", "MAC-radius"), + ], + help_text="Type of RADIUS authentication : inactive, MAC-address or 802.1X", + max_length=32, + verbose_name="RADIUS type", + ), ), migrations.AlterField( - model_name='portprofile', - name='speed', - field=models.CharField(choices=[('10-half', '10-half'), ('100-half', '100-half'), ('10-full', '10-full'), ('100-full', '100-full'), ('1000-full', '1000-full'), ('auto', 'auto'), ('auto-10', 'auto-10'), ('auto-100', 'auto-100')], default='auto', help_text='Port speed limit', max_length=32), + model_name="portprofile", + name="speed", + field=models.CharField( + choices=[ + ("10-half", "10-half"), + ("100-half", "100-half"), + ("10-full", "10-full"), + ("100-full", "100-full"), + ("1000-full", "1000-full"), + ("auto", "auto"), + ("auto-10", "auto-10"), + ("auto-100", "auto-100"), + ], + default="auto", + help_text="Port speed limit", + max_length=32, + ), ), migrations.AlterField( - model_name='switch', - name='model', - field=models.ForeignKey(blank=True, help_text='Switch model', null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.ModelSwitch'), + model_name="switch", + name="model", + field=models.ForeignKey( + blank=True, + help_text="Switch model", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.ModelSwitch", + ), ), migrations.AlterField( - model_name='switch', - name='number', - field=models.PositiveIntegerField(help_text='Number of ports'), + model_name="switch", + name="number", + field=models.PositiveIntegerField(help_text="Number of ports"), ), migrations.AlterField( - model_name='switch', - name='stack_member_id', + model_name="switch", + name="stack_member_id", field=models.PositiveIntegerField(blank=True, null=True), ), migrations.AlterField( - model_name='switch', - name='switchbay', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='topologie.SwitchBay'), + model_name="switch", + name="switchbay", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="topologie.SwitchBay", + ), ), migrations.AlterField( - model_name='switchbay', - name='info', + model_name="switchbay", + name="info", field=models.CharField(blank=True, max_length=255, null=True), ), ] diff --git a/topologie/migrations/0063_auto_20180919_2225.py b/topologie/migrations/0063_auto_20180919_2225.py index 45228340..1312f405 100644 --- a/topologie/migrations/0063_auto_20180919_2225.py +++ b/topologie/migrations/0063_auto_20180919_2225.py @@ -9,24 +9,36 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('preferences', '0051_auto_20180919_2225'), - ('topologie', '0062_auto_20180815_1918'), + ("preferences", "0051_auto_20180919_2225"), + ("topologie", "0062_auto_20180815_1918"), ] operations = [ migrations.AddField( - model_name='modelswitch', - name='firmware', + model_name="modelswitch", + name="firmware", field=models.CharField(blank=True, max_length=255, null=True), ), migrations.AddField( - model_name='switch', - name='management_creds', - field=models.ForeignKey(blank=True, help_text='Identifiant de management de ce switch', null=True, on_delete=django.db.models.deletion.PROTECT, to='preferences.SwitchManagementCred'), + model_name="switch", + name="management_creds", + field=models.ForeignKey( + blank=True, + help_text="Identifiant de management de ce switch", + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="preferences.SwitchManagementCred", + ), ), migrations.AddField( - model_name='switch', - name='radius_key', - field=models.ForeignKey(blank=True, help_text='Clef radius du switch', null=True, on_delete=django.db.models.deletion.PROTECT, to='preferences.RadiusKey'), + model_name="switch", + name="radius_key", + field=models.ForeignKey( + blank=True, + help_text="Clef radius du switch", + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="preferences.RadiusKey", + ), ), ] diff --git a/topologie/migrations/0064_switch_automatic_provision.py b/topologie/migrations/0064_switch_automatic_provision.py index d8d280cf..99b68d29 100644 --- a/topologie/migrations/0064_switch_automatic_provision.py +++ b/topologie/migrations/0064_switch_automatic_provision.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0063_auto_20180919_2225'), - ] + dependencies = [("topologie", "0063_auto_20180919_2225")] operations = [ migrations.AddField( - model_name='switch', - name='automatic_provision', - field=models.BooleanField(default=False, help_text='Provision automatique de ce switch'), - ), + model_name="switch", + name="automatic_provision", + field=models.BooleanField( + default=False, help_text="Provision automatique de ce switch" + ), + ) ] diff --git a/topologie/migrations/0065_auto_20180927_1836.py b/topologie/migrations/0065_auto_20180927_1836.py index 80f3eb2d..2a5b9ed0 100644 --- a/topologie/migrations/0065_auto_20180927_1836.py +++ b/topologie/migrations/0065_auto_20180927_1836.py @@ -7,14 +7,25 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0064_switch_automatic_provision'), - ] + dependencies = [("topologie", "0064_switch_automatic_provision")] operations = [ migrations.AlterField( - model_name='portprofile', - name='profil_default', - field=models.CharField(blank=True, choices=[('room', 'room'), ('access_point', 'access_point'), ('uplink', 'uplink'), ('asso_machine', 'asso_machine'), ('nothing', 'nothing')], max_length=32, null=True, unique=True, verbose_name='Default profile'), - ), + model_name="portprofile", + name="profil_default", + field=models.CharField( + blank=True, + choices=[ + ("room", "room"), + ("access_point", "access_point"), + ("uplink", "uplink"), + ("asso_machine", "asso_machine"), + ("nothing", "nothing"), + ], + max_length=32, + null=True, + unique=True, + verbose_name="Default profile", + ), + ) ] diff --git a/topologie/migrations/0066_modelswitch_commercial_name.py b/topologie/migrations/0066_modelswitch_commercial_name.py index 9a01a4f0..2646c62b 100644 --- a/topologie/migrations/0066_modelswitch_commercial_name.py +++ b/topologie/migrations/0066_modelswitch_commercial_name.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0065_auto_20180927_1836'), - ] + dependencies = [("topologie", "0065_auto_20180927_1836")] operations = [ migrations.AddField( - model_name='modelswitch', - name='commercial_name', + model_name="modelswitch", + name="commercial_name", field=models.CharField(blank=True, max_length=255, null=True), - ), + ) ] diff --git a/topologie/migrations/0067_auto_20181230_1819.py b/topologie/migrations/0067_auto_20181230_1819.py index 57f268ea..f9f56f09 100644 --- a/topologie/migrations/0067_auto_20181230_1819.py +++ b/topologie/migrations/0067_auto_20181230_1819.py @@ -9,58 +9,103 @@ import re2o.mixins class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0066_modelswitch_commercial_name'), - ] + dependencies = [("topologie", "0066_modelswitch_commercial_name")] operations = [ migrations.CreateModel( - name='ModuleOnSwitch', + name="ModuleOnSwitch", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('slot', models.CharField(help_text='Slot on switch', max_length=15, verbose_name='Slot')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "slot", + models.CharField( + help_text="Slot on switch", max_length=15, verbose_name="Slot" + ), + ), ], options={ - 'verbose_name': 'link between switchs and modules', - 'permissions': (('view_moduleonswitch', 'Can view a moduleonswitch object'),), + "verbose_name": "link between switchs and modules", + "permissions": ( + ("view_moduleonswitch", "Can view a moduleonswitch object"), + ), }, bases=(re2o.mixins.AclMixin, re2o.mixins.RevMixin, models.Model), ), migrations.CreateModel( - name='ModuleSwitch', + name="ModuleSwitch", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('reference', models.CharField(help_text='Reference of a module', max_length=255, verbose_name='Module reference')), - ('comment', models.CharField(blank=True, help_text='Comment', max_length=255, null=True, verbose_name='Comment')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "reference", + models.CharField( + help_text="Reference of a module", + max_length=255, + verbose_name="Module reference", + ), + ), + ( + "comment", + models.CharField( + blank=True, + help_text="Comment", + max_length=255, + null=True, + verbose_name="Comment", + ), + ), ], options={ - 'verbose_name': 'Module of a switch', - 'permissions': (('view_moduleswitch', 'Can view a module object'),), + "verbose_name": "Module of a switch", + "permissions": (("view_moduleswitch", "Can view a module object"),), }, bases=(re2o.mixins.AclMixin, re2o.mixins.RevMixin, models.Model), ), migrations.AddField( - model_name='modelswitch', - name='is_itself_module', - field=models.BooleanField(default=False, help_text='Does the switch, itself, considered as a module'), + model_name="modelswitch", + name="is_itself_module", + field=models.BooleanField( + default=False, + help_text="Does the switch, itself, considered as a module", + ), ), migrations.AddField( - model_name='modelswitch', - name='is_modular', - field=models.BooleanField(default=False, help_text='Is this switch model modular'), + model_name="modelswitch", + name="is_modular", + field=models.BooleanField( + default=False, help_text="Is this switch model modular" + ), ), migrations.AddField( - model_name='moduleonswitch', - name='module', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='topologie.ModuleSwitch'), + model_name="moduleonswitch", + name="module", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="topologie.ModuleSwitch" + ), ), migrations.AddField( - model_name='moduleonswitch', - name='switch', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='topologie.Switch'), + model_name="moduleonswitch", + name="switch", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="topologie.Switch" + ), ), migrations.AlterUniqueTogether( - name='moduleonswitch', - unique_together=set([('slot', 'switch')]), + name="moduleonswitch", unique_together=set([("slot", "switch")]) ), ] diff --git a/topologie/migrations/0068_auto_20190102_1758.py b/topologie/migrations/0068_auto_20190102_1758.py index b03e7ae5..41342c90 100644 --- a/topologie/migrations/0068_auto_20190102_1758.py +++ b/topologie/migrations/0068_auto_20190102_1758.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0067_auto_20181230_1819'), - ] + dependencies = [("topologie", "0067_auto_20181230_1819")] operations = [ migrations.AlterField( - model_name='modelswitch', - name='is_itself_module', - field=models.BooleanField(default=False, help_text='Is the switch, itself, considered as a module'), - ), + model_name="modelswitch", + name="is_itself_module", + field=models.BooleanField( + default=False, help_text="Is the switch, itself, considered as a module" + ), + ) ] diff --git a/topologie/migrations/0069_auto_20190108_1439.py b/topologie/migrations/0069_auto_20190108_1439.py index ba13942b..9a26746e 100644 --- a/topologie/migrations/0069_auto_20190108_1439.py +++ b/topologie/migrations/0069_auto_20190108_1439.py @@ -8,52 +8,105 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0068_auto_20190102_1758'), - ] + dependencies = [("topologie", "0068_auto_20190102_1758")] operations = [ migrations.AlterModelOptions( - name='moduleonswitch', - options={'permissions': (('view_moduleonswitch', 'Can view a link between switch and module object'),), 'verbose_name': 'link between switch and module', 'verbose_name_plural': 'links between switch and module'}, + name="moduleonswitch", + options={ + "permissions": ( + ( + "view_moduleonswitch", + "Can view a link between switch and module object", + ), + ), + "verbose_name": "link between switch and module", + "verbose_name_plural": "links between switch and module", + }, ), migrations.AlterModelOptions( - name='moduleswitch', - options={'permissions': (('view_moduleswitch', 'Can view a switch module object'),), 'verbose_name': 'switch module', 'verbose_name_plural': 'switch modules'}, + name="moduleswitch", + options={ + "permissions": ( + ("view_moduleswitch", "Can view a switch module object"), + ), + "verbose_name": "switch module", + "verbose_name_plural": "switch modules", + }, ), migrations.AlterField( - model_name='modelswitch', - name='is_itself_module', - field=models.BooleanField(default=False, help_text='The switch is considered as a module.'), + model_name="modelswitch", + name="is_itself_module", + field=models.BooleanField( + default=False, help_text="The switch is considered as a module." + ), ), migrations.AlterField( - model_name='modelswitch', - name='is_modular', - field=models.BooleanField(default=False, help_text='The switch model is modular.'), + model_name="modelswitch", + name="is_modular", + field=models.BooleanField( + default=False, help_text="The switch model is modular." + ), ), migrations.AlterField( - model_name='portprofile', - name='profil_default', - field=models.CharField(blank=True, choices=[('room', 'Room'), ('access_point', 'Access point'), ('uplink', 'Uplink'), ('asso_machine', 'Organisation machine'), ('nothing', 'Nothing')], max_length=32, null=True, unique=True, verbose_name='Default profile'), + model_name="portprofile", + name="profil_default", + field=models.CharField( + blank=True, + choices=[ + ("room", "Room"), + ("access_point", "Access point"), + ("uplink", "Uplink"), + ("asso_machine", "Organisation machine"), + ("nothing", "Nothing"), + ], + max_length=32, + null=True, + unique=True, + verbose_name="Default profile", + ), ), migrations.AlterField( - model_name='portprofile', - name='radius_type', - field=models.CharField(choices=[('NO', 'NO'), ('802.1X', '802.1X'), ('MAC-radius', 'MAC-RADIUS')], help_text='Type of RADIUS authentication : inactive, MAC-address or 802.1X', max_length=32, verbose_name='RADIUS type'), + model_name="portprofile", + name="radius_type", + field=models.CharField( + choices=[ + ("NO", "NO"), + ("802.1X", "802.1X"), + ("MAC-radius", "MAC-RADIUS"), + ], + help_text="Type of RADIUS authentication : inactive, MAC-address or 802.1X", + max_length=32, + verbose_name="RADIUS type", + ), ), migrations.AlterField( - model_name='switch', - name='automatic_provision', - field=models.BooleanField(default=False, help_text='Automatic provision for the switch'), + model_name="switch", + name="automatic_provision", + field=models.BooleanField( + default=False, help_text="Automatic provision for the switch" + ), ), migrations.AlterField( - model_name='switch', - name='management_creds', - field=models.ForeignKey(blank=True, help_text='Management credentials for the switch', null=True, on_delete=django.db.models.deletion.PROTECT, to='preferences.SwitchManagementCred'), + model_name="switch", + name="management_creds", + field=models.ForeignKey( + blank=True, + help_text="Management credentials for the switch", + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="preferences.SwitchManagementCred", + ), ), migrations.AlterField( - model_name='switch', - name='radius_key', - field=models.ForeignKey(blank=True, help_text='RADIUS key of the switch', null=True, on_delete=django.db.models.deletion.PROTECT, to='preferences.RadiusKey'), + model_name="switch", + name="radius_key", + field=models.ForeignKey( + blank=True, + help_text="RADIUS key of the switch", + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="preferences.RadiusKey", + ), ), ] diff --git a/topologie/migrations/0070_auto_20190218_1743.py b/topologie/migrations/0070_auto_20190218_1743.py index bb0c6f5c..df16dfca 100644 --- a/topologie/migrations/0070_auto_20190218_1743.py +++ b/topologie/migrations/0070_auto_20190218_1743.py @@ -9,9 +9,7 @@ import re2o.mixins class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0069_auto_20190108_1439'), - ] + dependencies = [("topologie", "0069_auto_20190108_1439")] def create_dormitory(apps, schema_editor): db_alias = schema_editor.connection.alias @@ -25,23 +23,36 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='Dormitory', + name="Dormitory", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), ], options={ - 'verbose_name': 'dormitory', - 'permissions': (('view_dormitory', 'Can view a dormitory object'),), - 'verbose_name_plural': 'dormitories', + "verbose_name": "dormitory", + "permissions": (("view_dormitory", "Can view a dormitory object"),), + "verbose_name_plural": "dormitories", }, bases=(re2o.mixins.AclMixin, re2o.mixins.RevMixin, models.Model), ), migrations.AddField( - model_name='building', - name='dormitory', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='topologie.Dormitory'), + model_name="building", + name="dormitory", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="topologie.Dormitory", + ), preserve_default=False, ), - migrations.RunPython(create_dormitory, delete_dormitory) + migrations.RunPython(create_dormitory, delete_dormitory), ] diff --git a/topologie/migrations/0071_auto_20190218_1936.py b/topologie/migrations/0071_auto_20190218_1936.py index 8c5e3c8d..39db3e31 100644 --- a/topologie/migrations/0071_auto_20190218_1936.py +++ b/topologie/migrations/0071_auto_20190218_1936.py @@ -8,9 +8,7 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0070_auto_20190218_1743'), - ] + dependencies = [("topologie", "0070_auto_20190218_1743")] def transfer_room(apps, schema_editor): db_alias = schema_editor.connection.alias @@ -19,7 +17,9 @@ class Migration(migrations.Migration): dorm_obj = apps.get_model("topologie", "Dormitory") dorm = dorm_obj.objects.using(db_alias).first() for room in room_obj.objects.using(db_alias).all(): - building, created = building_obj.objects.using(db_alias).get_or_create(name=room.name[0].upper(), dormitory=dorm) + building, created = building_obj.objects.using(db_alias).get_or_create( + name=room.name[0].upper(), dormitory=dorm + ) room.building = building room.name = room.name[1:] room.save() @@ -29,28 +29,34 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name='room', - name='name', - field=models.CharField(max_length=255), + model_name="room", name="name", field=models.CharField(max_length=255) ), migrations.AddField( - model_name='room', - name='building', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='topologie.Building'), + model_name="room", + name="building", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="topologie.Building", + ), ), migrations.AlterUniqueTogether( - name='room', - unique_together=set([('name', 'building')]), + name="room", unique_together=set([("name", "building")]) ), migrations.AlterField( - model_name='building', - name='dormitory', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='topologie.Dormitory'), + model_name="building", + name="dormitory", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="topologie.Dormitory" + ), ), migrations.RunPython(transfer_room, untransfer_room), migrations.AlterField( - model_name='room', - name='building', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='topologie.Building'), - ) + model_name="room", + name="building", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="topologie.Building" + ), + ), ] diff --git a/topologie/migrations/0072_auto_20190720_2318.py b/topologie/migrations/0072_auto_20190720_2318.py index 3c403bfa..7e276c3e 100644 --- a/topologie/migrations/0072_auto_20190720_2318.py +++ b/topologie/migrations/0072_auto_20190720_2318.py @@ -8,27 +8,49 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('topologie', '0071_auto_20190218_1936'), - ] + dependencies = [("topologie", "0071_auto_20190218_1936")] operations = [ migrations.AlterModelOptions( - name='room', - options={'ordering': ['building__name'], 'permissions': (('view_room', 'Can view a room object'),), 'verbose_name': 'room', 'verbose_name_plural': 'rooms'}, + name="room", + options={ + "ordering": ["building__name"], + "permissions": (("view_room", "Can view a room object"),), + "verbose_name": "room", + "verbose_name_plural": "rooms", + }, ), migrations.AddField( - model_name='portprofile', - name='on_dormitory', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='dormitory_ofprofil', to='topologie.Dormitory', verbose_name='Profil on dormitory'), + model_name="portprofile", + name="on_dormitory", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="dormitory_ofprofil", + to="topologie.Dormitory", + verbose_name="Profil on dormitory", + ), ), migrations.AlterField( - model_name='portprofile', - name='profil_default', - field=models.CharField(blank=True, choices=[('room', 'Room'), ('access_point', 'Access point'), ('uplink', 'Uplink'), ('asso_machine', 'Organisation machine'), ('nothing', 'Nothing')], max_length=32, null=True, verbose_name='Default profile'), + model_name="portprofile", + name="profil_default", + field=models.CharField( + blank=True, + choices=[ + ("room", "Room"), + ("access_point", "Access point"), + ("uplink", "Uplink"), + ("asso_machine", "Organisation machine"), + ("nothing", "Nothing"), + ], + max_length=32, + null=True, + verbose_name="Default profile", + ), ), migrations.AlterUniqueTogether( - name='portprofile', - unique_together=set([('on_dormitory', 'profil_default')]), + name="portprofile", + unique_together=set([("on_dormitory", "profil_default")]), ), ] diff --git a/topologie/migrations/__init__.py b/topologie/migrations/__init__.py index b2b50566..b409e525 100644 --- a/topologie/migrations/__init__.py +++ b/topologie/migrations/__init__.py @@ -19,4 +19,3 @@ # 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. - diff --git a/topologie/models.py b/topologie/models.py index 093907df..93e7968c 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -50,18 +50,8 @@ from django.db import transaction from django.utils.translation import ugettext_lazy as _ from reversion import revisions as reversion -from preferences.models import ( - OptionalTopologie, - RadiusKey, - SwitchManagementCred -) -from machines.models import ( - Machine, - regen, - Role, - MachineType, - Ipv6List -) +from preferences.models import OptionalTopologie, RadiusKey, SwitchManagementCred +from machines.models import Machine, regen, Role, MachineType, Ipv6List from re2o.mixins import AclMixin, RevMixin @@ -77,9 +67,7 @@ class Stack(AclMixin, RevMixin, models.Model): member_id_max = models.PositiveIntegerField() class Meta: - permissions = ( - ("view_stack", _("Can view a stack object")), - ) + permissions = (("view_stack", _("Can view a stack object")),) verbose_name = _("switches stack") verbose_name_plural = _("switches stacks") @@ -96,8 +84,7 @@ class Stack(AclMixin, RevMixin, models.Model): """ Verification que l'id_max < id_min""" if self.member_id_max < self.member_id_min: raise ValidationError( - {'member_id_max': _("The maximum ID is less than the" - " minimum ID.")} + {"member_id_max": _("The maximum ID is less than the" " minimum ID.")} ) @@ -111,36 +98,28 @@ class AccessPoint(AclMixin, Machine): max_length=255, help_text=_("Details about the AP's location"), blank=True, - null=True + null=True, ) class Meta: - permissions = ( - ("view_accesspoint", _("Can view an access point object")), - ) + permissions = (("view_accesspoint", _("Can view an access point object")),) verbose_name = _("access point") verbose_name_plural = _("access points") def port(self): """Return the queryset of ports for this device""" - return Port.objects.filter( - machine_interface__machine=self - ) + return Port.objects.filter(machine_interface__machine=self) def switch(self): """Return the switch where this is plugged""" - return Switch.objects.filter( - ports__machine_interface__machine=self - ) + return Switch.objects.filter(ports__machine_interface__machine=self) def building(self): """ Return the building of the AP/Server (building of the switchs connected to...) """ - return Building.objects.filter( - switchbay__switch=self.switch() - ) + return Building.objects.filter(switchbay__switch=self.switch()) @cached_property def short_name(self): @@ -167,24 +146,18 @@ class Server(Machine): def port(self): """Return the queryset of ports for this device""" - return Port.objects.filter( - machine_interface__machine=self - ) + return Port.objects.filter(machine_interface__machine=self) def switch(self): """Return the switch where this is plugged""" - return Switch.objects.filter( - ports__machine_interface__machine=self - ) + return Switch.objects.filter(ports__machine_interface__machine=self) def building(self): """ Return the building of the AP/Server (building of the switchs connected to...) """ - return Building.objects.filter( - switchbay__switch=self.switch() - ) + return Building.objects.filter(switchbay__switch=self.switch()) @cached_property def short_name(self): @@ -214,57 +187,42 @@ class Switch(AclMixin, Machine): Validation au save que l'id du stack est bien dans le range id_min id_max de la stack parente""" - number = models.PositiveIntegerField( - help_text=_("Number of ports") - ) + number = models.PositiveIntegerField(help_text=_("Number of ports")) stack = models.ForeignKey( - 'topologie.Stack', - blank=True, - null=True, - on_delete=models.SET_NULL - ) - stack_member_id = models.PositiveIntegerField( - blank=True, - null=True + "topologie.Stack", blank=True, null=True, on_delete=models.SET_NULL ) + stack_member_id = models.PositiveIntegerField(blank=True, null=True) model = models.ForeignKey( - 'topologie.ModelSwitch', + "topologie.ModelSwitch", blank=True, null=True, on_delete=models.SET_NULL, - help_text=_("Switch model") + help_text=_("Switch model"), ) switchbay = models.ForeignKey( - 'topologie.SwitchBay', - blank=True, - null=True, - on_delete=models.SET_NULL, + "topologie.SwitchBay", blank=True, null=True, on_delete=models.SET_NULL ) radius_key = models.ForeignKey( - 'preferences.RadiusKey', + "preferences.RadiusKey", blank=True, null=True, on_delete=models.PROTECT, - help_text=_("RADIUS key of the switch") + help_text=_("RADIUS key of the switch"), ) management_creds = models.ForeignKey( - 'preferences.SwitchManagementCred', + "preferences.SwitchManagementCred", blank=True, null=True, on_delete=models.PROTECT, - help_text=_("Management credentials for the switch") + help_text=_("Management credentials for the switch"), ) automatic_provision = models.BooleanField( - default=False, - help_text=_("Automatic provision for the switch") + default=False, help_text=_("Automatic provision for the switch") ) - class Meta: - unique_together = ('stack', 'stack_member_id') - permissions = ( - ("view_switch", _("Can view a switch object")), - ) + unique_together = ("stack", "stack_member_id") + permissions = (("view_switch", _("Can view a switch object")),) verbose_name = _("switch") verbose_name_plural = _("switches") @@ -274,45 +232,58 @@ class Switch(AclMixin, Machine): super(Switch, self).clean() if self.stack is not None: if self.stack_member_id is not None: - if (self.stack_member_id > self.stack.member_id_max) or\ - (self.stack_member_id < self.stack.member_id_min): + if (self.stack_member_id > self.stack.member_id_max) or ( + self.stack_member_id < self.stack.member_id_min + ): raise ValidationError( - {'stack_member_id': _("The switch ID exceeds the" - " limits allowed by the stack.")} - ) + { + "stack_member_id": _( + "The switch ID exceeds the" + " limits allowed by the stack." + ) + } + ) else: raise ValidationError( - {'stack_member_id': _("The stack member ID can't be" - " void.")} + {"stack_member_id": _("The stack member ID can't be" " void.")} ) def create_ports(self, begin, end): """ Crée les ports de begin à end si les valeurs données sont cohérentes. """ if end < begin: - raise ValidationError(_("The end port is less than the start" - " port.")) + raise ValidationError(_("The end port is less than the start" " port.")) ports_to_create = range(begin, end + 1) - existing_ports = Port.objects.filter(switch=self.switch).values_list('port', flat=True) + existing_ports = Port.objects.filter(switch=self.switch).values_list( + "port", flat=True + ) non_existing_ports = list(set(ports_to_create) - set(existing_ports)) if len(non_existing_ports) + existing_ports.count() > self.number: raise ValidationError(_("This switch can't have that many ports.")) with transaction.atomic(), reversion.create_revision(): reversion.set_comment(_("Creation")) - Port.objects.bulk_create([Port(switch=self.switch, port=port_id) for port_id in non_existing_ports]) + Port.objects.bulk_create( + [ + Port(switch=self.switch, port=port_id) + for port_id in non_existing_ports + ] + ) def main_interface(self): """ Returns the 'main' interface of the switch It must the the management interface for that device""" - switch_iptype = OptionalTopologie.get_cached_value('switchs_ip_type') + switch_iptype = OptionalTopologie.get_cached_value("switchs_ip_type") if switch_iptype: - return self.interface_set.filter(machine_type__ip_type=switch_iptype).first() or self.interface_set.first() + return ( + self.interface_set.filter(machine_type__ip_type=switch_iptype).first() + or self.interface_set.first() + ) return self.interface_set.first() @cached_property def get_name(self): - return self.name or getattr(self.main_interface(), 'domain', 'Unknown') + return self.name or getattr(self.main_interface(), "domain", "Unknown") @cached_property def get_radius_key(self): @@ -329,35 +300,56 @@ class Switch(AclMixin, Machine): @cached_property def get_radius_servers_objects(self): - return Role.all_interfaces_for_roletype("radius-server").filter(machine_type__in=MachineType.objects.filter(interface__in=self.interface_set.all())) + return Role.all_interfaces_for_roletype("radius-server").filter( + machine_type__in=MachineType.objects.filter( + interface__in=self.interface_set.all() + ) + ) @cached_property def get_radius_servers(self): def return_ips_dict(interfaces): - return {'ipv4' : [str(interface.ipv4) for interface in interfaces], 'ipv6' : Ipv6List.objects.filter(interface__in=interfaces).values_list('ipv6', flat=True)} + return { + "ipv4": [str(interface.ipv4) for interface in interfaces], + "ipv6": Ipv6List.objects.filter(interface__in=interfaces).values_list( + "ipv6", flat=True + ), + } + return return_ips_dict(self.get_radius_servers_objects) @cached_property def get_management_cred(self): """Retourne l'objet des creds de managament de ce switch""" - return self.management_creds or SwitchManagementCred.objects.filter(default_switch=True).first() + return ( + self.management_creds + or SwitchManagementCred.objects.filter(default_switch=True).first() + ) @cached_property def get_management_cred_value(self): """Retourne un dict des creds de management du switch""" if self.get_management_cred: - return {'id': self.get_management_cred.management_id, 'pass': self.get_management_cred.management_pass} + return { + "id": self.get_management_cred.management_id, + "pass": self.get_management_cred.management_pass, + } else: return None @cached_property def rest_enabled(self): - return OptionalTopologie.get_cached_value('switchs_rest_management') or self.automatic_provision + return ( + OptionalTopologie.get_cached_value("switchs_rest_management") + or self.automatic_provision + ) @cached_property def web_management_enabled(self): - sw_management = OptionalTopologie.get_cached_value('switchs_web_management') - sw_management_ssl = OptionalTopologie.get_cached_value('switchs_web_management_ssl') + sw_management = OptionalTopologie.get_cached_value("switchs_web_management") + sw_management_ssl = OptionalTopologie.get_cached_value( + "switchs_web_management_ssl" + ) if sw_management_ssl: return "ssl" elif sw_management: @@ -378,18 +370,31 @@ class Switch(AclMixin, Machine): @cached_property def interfaces_subnet(self): """Return dict ip:subnet for all ip of the switch""" - return dict((str(interface.ipv4), interface.machine_type.ip_type.ip_net_full_info or interface.machine_type.ip_type.ip_set_full_info[0]) for interface in self.interface_set.all()) + return dict( + ( + str(interface.ipv4), + interface.machine_type.ip_type.ip_net_full_info + or interface.machine_type.ip_type.ip_set_full_info[0], + ) + for interface in self.interface_set.all() + ) @cached_property def interfaces6_subnet(self): """Return dict ip6:subnet for all ipv6 of the switch""" - return dict((str(interface.ipv6().first()), interface.machine_type.ip_type.ip6_set_full_info) for interface in self.interface_set.all()) + return dict( + ( + str(interface.ipv6().first()), + interface.machine_type.ip_type.ip6_set_full_info, + ) + for interface in self.interface_set.all() + ) @cached_property def list_modules(self): """Return modules of that switch, list of dict (rank, reference)""" modules = [] - if getattr(self.model, 'is_modular', None): + if getattr(self.model, "is_modular", None): if self.model.is_itself_module: modules.append((1, self.model.reference)) for module_of_self in self.moduleonswitch_set.all(): @@ -408,9 +413,7 @@ class Switch(AclMixin, Machine): def nothing_profile(cls): """Return default nothing port profile""" nothing_profile, _created = PortProfile.objects.get_or_create( - profil_default='nothing', - name='nothing', - radius_type='NO' + profil_default="nothing", name="nothing", radius_type="NO" ) return nothing_profile @@ -423,7 +426,10 @@ class Switch(AclMixin, Machine): Otherwise, returns the nothing profile""" profile_queryset = PortProfile.objects.filter(profil_default=profile_type) if self.get_dormitory: - port_profile = profile_queryset.filter(on_dormitory=self.get_dormitory).first() or profile_queryset.first() + port_profile = ( + profile_queryset.filter(on_dormitory=self.get_dormitory).first() + or profile_queryset.first() + ) else: port_profile = profile_queryset.first() return port_profile or Switch.nothing_profile() @@ -431,22 +437,22 @@ class Switch(AclMixin, Machine): @cached_property def default_uplink_profile(self): """Default uplink profile for that switch -- in cache""" - return self.profile_type_or_nothing('uplink') + return self.profile_type_or_nothing("uplink") @cached_property def default_access_point_profile(self): """Default ap profile for that switch -- in cache""" - return self.profile_type_or_nothing('access_point') + return self.profile_type_or_nothing("access_point") @cached_property def default_room_profile(self): """Default room profile for that switch -- in cache""" - return self.profile_type_or_nothing('room') + return self.profile_type_or_nothing("room") @cached_property def default_asso_machine_profile(self): """Default asso machine profile for that switch -- in cache""" - return self.profile_type_or_nothing('asso_machine') + return self.profile_type_or_nothing("asso_machine") def __str__(self): return str(self.get_name) @@ -456,88 +462,74 @@ class ModelSwitch(AclMixin, RevMixin, models.Model): """Un modèle (au sens constructeur) de switch""" reference = models.CharField(max_length=255) - commercial_name = models.CharField( - max_length=255, - null=True, - blank=True - ) + commercial_name = models.CharField(max_length=255, null=True, blank=True) constructor = models.ForeignKey( - 'topologie.ConstructorSwitch', - on_delete=models.PROTECT - ) - firmware = models.CharField( - max_length=255, - null=True, - blank=True + "topologie.ConstructorSwitch", on_delete=models.PROTECT ) + firmware = models.CharField(max_length=255, null=True, blank=True) is_modular = models.BooleanField( - default=False, - help_text=_("The switch model is modular."), + default=False, help_text=_("The switch model is modular.") ) is_itself_module = models.BooleanField( - default=False, - help_text=_("The switch is considered as a module."), + default=False, help_text=_("The switch is considered as a module.") ) class Meta: - permissions = ( - ("view_modelswitch", _("Can view a switch model object")), - ) + permissions = (("view_modelswitch", _("Can view a switch model object")),) verbose_name = _("switch model") verbose_name_plural = _("switch models") def __str__(self): if self.commercial_name: - return str(self.constructor) + ' ' + str(self.commercial_name) + return str(self.constructor) + " " + str(self.commercial_name) else: - return str(self.constructor) + ' ' + self.reference + return str(self.constructor) + " " + self.reference class ModuleSwitch(AclMixin, RevMixin, models.Model): """A module of a switch""" + reference = models.CharField( max_length=255, help_text=_("Reference of a module"), - verbose_name=_("Module reference") + verbose_name=_("Module reference"), ) comment = models.CharField( max_length=255, null=True, blank=True, help_text=_("Comment"), - verbose_name=_("Comment") + verbose_name=_("Comment"), ) class Meta: - permissions = ( - ("view_moduleswitch", _("Can view a switch module object")), - ) + permissions = (("view_moduleswitch", _("Can view a switch module object")),) verbose_name = _("switch module") verbose_name_plural = _("switch modules") - def __str__(self): return str(self.reference) class ModuleOnSwitch(AclMixin, RevMixin, models.Model): """Link beetween module and switch""" - module = models.ForeignKey('ModuleSwitch', on_delete=models.CASCADE) - switch = models.ForeignKey('Switch', on_delete=models.CASCADE) + + module = models.ForeignKey("ModuleSwitch", on_delete=models.CASCADE) + switch = models.ForeignKey("Switch", on_delete=models.CASCADE) slot = models.CharField( - max_length=15, - help_text=_("Slot on switch"), - verbose_name=_("Slot") + max_length=15, help_text=_("Slot on switch"), verbose_name=_("Slot") ) class Meta: permissions = ( - ("view_moduleonswitch", _("Can view a link between switch and" - " module object")), + ( + "view_moduleonswitch", + _("Can view a link between switch and" " module object"), + ), ) verbose_name = _("link between switch and module") verbose_name_plural = _("links between switch and module") - unique_together = ['slot', 'switch'] + unique_together = ["slot", "switch"] def __str__(self): return _("On slot ") + str(self.slot) + _(" of ") + str(self.switch) @@ -550,11 +542,10 @@ class ConstructorSwitch(AclMixin, RevMixin, models.Model): class Meta: permissions = ( - ("view_constructorswitch", _("Can view a switch constructor" - " object")), + ("view_constructorswitch", _("Can view a switch constructor" " object")), ) verbose_name = _("switch constructor") - verbose_name_plural = ("switch constructors") + verbose_name_plural = "switch constructors" def __str__(self): return self.name @@ -564,20 +555,11 @@ class SwitchBay(AclMixin, RevMixin, models.Model): """Une baie de brassage""" name = models.CharField(max_length=255) - building = models.ForeignKey( - 'Building', - on_delete=models.PROTECT - ) - info = models.CharField( - max_length=255, - blank=True, - null=True - ) + building = models.ForeignKey("Building", on_delete=models.PROTECT) + info = models.CharField(max_length=255, blank=True, null=True) class Meta: - permissions = ( - ("view_switchbay", _("Can view a switch bay object")), - ) + permissions = (("view_switchbay", _("Can view a switch bay object")),) verbose_name = _("switch bay") verbose_name_plural = _("switch bays") @@ -591,11 +573,8 @@ class Dormitory(AclMixin, RevMixin, models.Model): name = models.CharField(max_length=255) - class Meta: - permissions = ( - ("view_dormitory", _("Can view a dormitory object")), - ) + permissions = (("view_dormitory", _("Can view a dormitory object")),) verbose_name = _("dormitory") verbose_name_plural = _("dormitories") @@ -605,11 +584,11 @@ class Dormitory(AclMixin, RevMixin, models.Model): @classmethod def is_multiple_dorms(cls): - multiple_dorms = cache.get('multiple_dorms') + multiple_dorms = cache.get("multiple_dorms") if multiple_dorms: return multiple_dorms else: - return cache.get_or_set('multiple_dorms', cls.objects.count() > 1) + return cache.get_or_set("multiple_dorms", cls.objects.count() > 1) def __str__(self): return self.name @@ -620,15 +599,10 @@ class Building(AclMixin, RevMixin, models.Model): Un batiment""" name = models.CharField(max_length=255) - dormitory = models.ForeignKey( - 'Dormitory', - on_delete=models.PROTECT, - ) + dormitory = models.ForeignKey("Dormitory", on_delete=models.PROTECT) class Meta: - permissions = ( - ("view_building", _("Can view a building object")), - ) + permissions = (("view_building", _("Can view a building object")),) verbose_name = _("building") verbose_name_plural = _("buildings") @@ -667,48 +641,28 @@ class Port(AclMixin, RevMixin, models.Model): de forcer un port sur un vlan particulier. S'additionne à la politique RADIUS""" - switch = models.ForeignKey( - 'Switch', - related_name="ports", - on_delete=models.CASCADE - ) + switch = models.ForeignKey("Switch", related_name="ports", on_delete=models.CASCADE) port = models.PositiveIntegerField() - room = models.ForeignKey( - 'Room', - on_delete=models.PROTECT, - blank=True, - null=True - ) + room = models.ForeignKey("Room", on_delete=models.PROTECT, blank=True, null=True) machine_interface = models.ForeignKey( - 'machines.Interface', - on_delete=models.SET_NULL, - blank=True, - null=True + "machines.Interface", on_delete=models.SET_NULL, blank=True, null=True ) related = models.OneToOneField( - 'self', - null=True, - blank=True, - related_name='related_port' + "self", null=True, blank=True, related_name="related_port" ) custom_profile = models.ForeignKey( - 'PortProfile', - on_delete=models.PROTECT, - blank=True, - null=True + "PortProfile", on_delete=models.PROTECT, blank=True, null=True ) state = models.BooleanField( default=True, help_text=_("Port state Active"), - verbose_name=_("Port state Active") + verbose_name=_("Port state Active"), ) details = models.CharField(max_length=255, blank=True) class Meta: - unique_together = ('switch', 'port') - permissions = ( - ("view_port", _("Can view a port object")), - ) + unique_together = ("switch", "port") + permissions = (("view_port", _("Can view a port object")),) verbose_name = _("port") verbose_name_plural = _("ports") @@ -739,7 +693,7 @@ class Port(AclMixin, RevMixin, models.Model): elif self.related: return self.switch.default_uplink_profile elif self.machine_interface: - if hasattr(self.machine_interface.machine, 'accesspoint'): + if hasattr(self.machine_interface.machine, "accesspoint"): return self.switch.default_access_point_profile else: return self.switch.default_asso_machine_profile @@ -750,13 +704,14 @@ class Port(AclMixin, RevMixin, models.Model): @classmethod def get_instance(cls, portid, *_args, **kwargs): - return (cls.objects - .select_related('machine_interface__domain__extension') - .select_related('machine_interface__machine__switch') - .select_related('room') - .select_related('related') - .prefetch_related('switch__interface_set__domain__extension') - .get(pk=portid)) + return ( + cls.objects.select_related("machine_interface__domain__extension") + .select_related("machine_interface__machine__switch") + .select_related("room") + .select_related("related") + .prefetch_related("switch__interface_set__domain__extension") + .get(pk=portid) + ) def make_port_related(self): """ Synchronise le port distant sur self""" @@ -779,14 +734,19 @@ class Port(AclMixin, RevMixin, models.Model): A priori pas d'autre solution que de faire ça à la main. A priori tout cela est dans un bloc transaction, donc pas de problème de cohérence""" - if hasattr(self, 'switch'): + if hasattr(self, "switch"): if self.port > self.switch.number: raise ValidationError( _("The port can't exist, its number is too great.") ) - if (self.room and self.machine_interface or - self.room and self.related or - self.machine_interface and self.related): + if ( + self.room + and self.machine_interface + or self.room + and self.related + or self.machine_interface + and self.related + ): raise ValidationError( _("Room, interface and related port are mutually exclusive.") ) @@ -795,12 +755,14 @@ class Port(AclMixin, RevMixin, models.Model): if self.related and not self.related.related: if self.related.machine_interface or self.related.room: raise ValidationError( - _("The related port is already used, please clear it" - " before creating the relation.") + _( + "The related port is already used, please clear it" + " before creating the relation." + ) ) else: self.make_port_related() - elif hasattr(self, 'related_port'): + elif hasattr(self, "related_port"): self.clean_port_related() def __str__(self): @@ -812,51 +774,40 @@ class Room(AclMixin, RevMixin, models.Model): name = models.CharField(max_length=255) details = models.CharField(max_length=255, blank=True) - building = models.ForeignKey( - 'Building', - on_delete=models.PROTECT, - ) + building = models.ForeignKey("Building", on_delete=models.PROTECT) class Meta: - ordering = ['building__name'] - permissions = ( - ("view_room", _("Can view a room object")), - ) + ordering = ["building__name"] + permissions = (("view_room", _("Can view a room object")),) verbose_name = _("room") verbose_name_plural = _("rooms") - unique_together = ('name', 'building') + unique_together = ("name", "building") def __str__(self): - return self.building.cached_name + ' ' + self.name + return self.building.cached_name + " " + self.name class PortProfile(AclMixin, RevMixin, models.Model): """Contains the information of the ports' configuration for a switch""" - TYPES = ( - ('NO', 'NO'), - ('802.1X', '802.1X'), - ('MAC-radius', _("MAC-RADIUS")), - ) - MODES = ( - ('STRICT', 'STRICT'), - ('COMMON', 'COMMON'), - ) + + TYPES = (("NO", "NO"), ("802.1X", "802.1X"), ("MAC-radius", _("MAC-RADIUS"))) + MODES = (("STRICT", "STRICT"), ("COMMON", "COMMON")) SPEED = ( - ('10-half', '10-half'), - ('100-half', '100-half'), - ('10-full', '10-full'), - ('100-full', '100-full'), - ('1000-full', '1000-full'), - ('auto', 'auto'), - ('auto-10', 'auto-10'), - ('auto-100', 'auto-100'), + ("10-half", "10-half"), + ("100-half", "100-half"), + ("10-full", "10-full"), + ("100-full", "100-full"), + ("1000-full", "1000-full"), + ("auto", "auto"), + ("auto-10", "auto-10"), + ("auto-100", "auto-100"), ) PROFIL_DEFAULT = ( - ('room', _("Room")), - ('access_point', _("Access point")), - ('uplink', _("Uplink")), - ('asso_machine', _("Organisation machine")), - ('nothing', _("Nothing")), + ("room", _("Room")), + ("access_point", _("Access point")), + ("uplink", _("Uplink")), + ("asso_machine", _("Organisation machine")), + ("nothing", _("Nothing")), ) name = models.CharField(max_length=255, verbose_name=_("Name")) profil_default = models.CharField( @@ -864,102 +815,96 @@ class PortProfile(AclMixin, RevMixin, models.Model): choices=PROFIL_DEFAULT, blank=True, null=True, - verbose_name=_("Default profile") + verbose_name=_("Default profile"), ) on_dormitory = models.ForeignKey( - 'topologie.Dormitory', - related_name='dormitory_ofprofil', + "topologie.Dormitory", + related_name="dormitory_ofprofil", on_delete=models.SET_NULL, blank=True, null=True, - verbose_name=_("Profil on dormitory") + verbose_name=_("Profil on dormitory"), ) vlan_untagged = models.ForeignKey( - 'machines.Vlan', - related_name='vlan_untagged', + "machines.Vlan", + related_name="vlan_untagged", on_delete=models.SET_NULL, blank=True, null=True, - verbose_name=_("VLAN untagged") + verbose_name=_("VLAN untagged"), ) vlan_tagged = models.ManyToManyField( - 'machines.Vlan', - related_name='vlan_tagged', + "machines.Vlan", + related_name="vlan_tagged", blank=True, - verbose_name=_("VLAN(s) tagged") + verbose_name=_("VLAN(s) tagged"), ) radius_type = models.CharField( max_length=32, choices=TYPES, - help_text=_("Type of RADIUS authentication : inactive, MAC-address or" - " 802.1X"), - verbose_name=_("RADIUS type") + help_text=_( + "Type of RADIUS authentication : inactive, MAC-address or" " 802.1X" + ), + verbose_name=_("RADIUS type"), ) radius_mode = models.CharField( max_length=32, choices=MODES, - default='COMMON', - help_text=_("In case of MAC-authentication : mode COMMON or STRICT on" - " this port"), - verbose_name=_("RADIUS mode") + default="COMMON", + help_text=_( + "In case of MAC-authentication : mode COMMON or STRICT on" " this port" + ), + verbose_name=_("RADIUS mode"), ) speed = models.CharField( - max_length=32, - choices=SPEED, - default='auto', - help_text=_("Port speed limit"), + max_length=32, choices=SPEED, default="auto", help_text=_("Port speed limit") ) mac_limit = models.IntegerField( null=True, blank=True, help_text=_("Limit of MAC-address on this port"), - verbose_name=_("MAC limit") - ) - flow_control = models.BooleanField( - default=False, - help_text=_("Flow control"), + verbose_name=_("MAC limit"), ) + flow_control = models.BooleanField(default=False, help_text=_("Flow control")) dhcp_snooping = models.BooleanField( default=False, help_text=_("Protect against rogue DHCP"), - verbose_name=_("DHCP snooping") + verbose_name=_("DHCP snooping"), ) dhcpv6_snooping = models.BooleanField( default=False, help_text=_("Protect against rogue DHCPv6"), - verbose_name=_("DHCPv6 snooping") + verbose_name=_("DHCPv6 snooping"), ) arp_protect = models.BooleanField( default=False, help_text=_("Check if IP adress is DHCP assigned"), - verbose_name=_("ARP protection") + verbose_name=_("ARP protection"), ) ra_guard = models.BooleanField( default=False, help_text=_("Protect against rogue RA"), - verbose_name=_("RA guard") + verbose_name=_("RA guard"), ) loop_protect = models.BooleanField( default=False, help_text=_("Protect against loop"), - verbose_name=_("Loop protection") + verbose_name=_("Loop protection"), ) class Meta: - permissions = ( - ("view_port_profile", _("Can view a port profile object")), - ) + permissions = (("view_port_profile", _("Can view a port profile object")),) verbose_name = _("port profile") verbose_name_plural = _("port profiles") - unique_together = ['on_dormitory', 'profil_default'] + unique_together = ["on_dormitory", "profil_default"] security_parameters_fields = [ - 'loop_protect', - 'ra_guard', - 'arp_protect', - 'dhcpv6_snooping', - 'dhcp_snooping', - 'flow_control' + "loop_protect", + "ra_guard", + "arp_protect", + "dhcpv6_snooping", + "dhcp_snooping", + "flow_control", ] @cached_property @@ -972,14 +917,25 @@ class PortProfile(AclMixin, RevMixin, models.Model): @cached_property def security_parameters_as_str(self): - return ','.join(self.security_parameters_enabled) + return ",".join(self.security_parameters_enabled) def clean(self): """ Check that there is only one generic profil default""" super(PortProfile, self).clean() - if self.profil_default and not self.on_dormitory and PortProfile.objects.exclude(id=self.id).filter(profil_default=self.profil_default).exclude(on_dormitory__isnull=False).exists(): + if ( + self.profil_default + and not self.on_dormitory + and PortProfile.objects.exclude(id=self.id) + .filter(profil_default=self.profil_default) + .exclude(on_dormitory__isnull=False) + .exists() + ): raise ValidationError( - {'profil_default': _("A default profile for all dormitory of that type already exists.")} + { + "profil_default": _( + "A default profile for all dormitory of that type already exists." + ) + } ) def __str__(self): @@ -989,14 +945,14 @@ class PortProfile(AclMixin, RevMixin, models.Model): @receiver(post_save, sender=AccessPoint) def ap_post_save(**_kwargs): """Regeneration des noms des bornes vers le controleur""" - regen('unifi-ap-names') + regen("unifi-ap-names") regen("graph_topo") @receiver(post_delete, sender=AccessPoint) def ap_post_delete(**_kwargs): """Regeneration des noms des bornes vers le controleur""" - regen('unifi-ap-names') + regen("unifi-ap-names") regen("graph_topo") @@ -1044,4 +1000,3 @@ def switch_post_save(**_kwargs): @receiver(post_delete, sender=Switch) def switch_post_delete(**_kwargs): regen("graph_topo") - diff --git a/topologie/urls.py b/topologie/urls.py index ee26cb2e..c204cb39 100644 --- a/topologie/urls.py +++ b/topologie/urls.py @@ -33,114 +33,128 @@ from django.conf.urls import url from . import views urlpatterns = [ - url(r'^$', views.index, name='index'), - url(r'^index_ap/$', views.index_ap, name='index-ap'), - url(r'^new_ap/$', views.new_ap, name='new-ap'), - url(r'^edit_ap/(?P[0-9]+)$', - views.edit_ap, - name='edit-ap'), - url(r'^create_ports/(?P[0-9]+)$', - views.create_ports, - name='create-ports'), - url(r'^index_room/$', views.index_room, name='index-room'), - url(r'^new_room/$', views.new_room, name='new-room'), - url(r'^edit_room/(?P[0-9]+)$', views.edit_room, name='edit-room'), - url(r'^del_room/(?P[0-9]+)$', views.del_room, name='del-room'), - url(r'^new_switch/$', views.new_switch, name='new-switch'), - url(r'^switch/(?P[0-9]+)$', - views.index_port, - name='index-port'), - url(r'^edit_port/(?P[0-9]+)$', views.edit_port, name='edit-port'), - url(r'^new_port/(?P[0-9]+)$', views.new_port, name='new-port'), - url(r'^del_port/(?P[0-9]+)$', views.del_port, name='del-port'), - url(r'^edit_switch/(?P[0-9]+)$', - views.edit_switch, - name='edit-switch'), - url(r'^new_stack/$', views.new_stack, name='new-stack'), - url(r'^index_physical_grouping/$', + url(r"^$", views.index, name="index"), + url(r"^index_ap/$", views.index_ap, name="index-ap"), + url(r"^new_ap/$", views.new_ap, name="new-ap"), + url(r"^edit_ap/(?P[0-9]+)$", views.edit_ap, name="edit-ap"), + url( + r"^create_ports/(?P[0-9]+)$", views.create_ports, name="create-ports" + ), + url(r"^index_room/$", views.index_room, name="index-room"), + url(r"^new_room/$", views.new_room, name="new-room"), + url(r"^edit_room/(?P[0-9]+)$", views.edit_room, name="edit-room"), + url(r"^del_room/(?P[0-9]+)$", views.del_room, name="del-room"), + url(r"^new_switch/$", views.new_switch, name="new-switch"), + url(r"^switch/(?P[0-9]+)$", views.index_port, name="index-port"), + url(r"^edit_port/(?P[0-9]+)$", views.edit_port, name="edit-port"), + url(r"^new_port/(?P[0-9]+)$", views.new_port, name="new-port"), + url(r"^del_port/(?P[0-9]+)$", views.del_port, name="del-port"), + url(r"^edit_switch/(?P[0-9]+)$", views.edit_switch, name="edit-switch"), + url(r"^new_stack/$", views.new_stack, name="new-stack"), + url( + r"^index_physical_grouping/$", views.index_physical_grouping, - name='index-physical-grouping'), - url(r'^edit_stack/(?P[0-9]+)$', - views.edit_stack, - name='edit-stack'), - url(r'^del_stack/(?P[0-9]+)$', - views.del_stack, - name='del-stack'), - url(r'^index_model_switch/$', - views.index_model_switch, - name='index-model-switch'), - url(r'^index_model_switch/$', - views.index_model_switch, - name='index-model-switch'), - url(r'^new_model_switch/$', - views.new_model_switch, - name='new-model-switch'), - url(r'^edit_model_switch/(?P[0-9]+)$', + name="index-physical-grouping", + ), + url(r"^edit_stack/(?P[0-9]+)$", views.edit_stack, name="edit-stack"), + url(r"^del_stack/(?P[0-9]+)$", views.del_stack, name="del-stack"), + url(r"^index_model_switch/$", views.index_model_switch, name="index-model-switch"), + url(r"^index_model_switch/$", views.index_model_switch, name="index-model-switch"), + url(r"^new_model_switch/$", views.new_model_switch, name="new-model-switch"), + url( + r"^edit_model_switch/(?P[0-9]+)$", views.edit_model_switch, - name='edit-model-switch'), - url(r'^del_model_switch/(?P[0-9]+)$', + name="edit-model-switch", + ), + url( + r"^del_model_switch/(?P[0-9]+)$", views.del_model_switch, - name='del-model-switch'), - url(r'^new_constructor_switch/$', + name="del-model-switch", + ), + url( + r"^new_constructor_switch/$", views.new_constructor_switch, - name='new-constructor-switch'), - url(r'^edit_constructor_switch/(?P[0-9]+)$', + name="new-constructor-switch", + ), + url( + r"^edit_constructor_switch/(?P[0-9]+)$", views.edit_constructor_switch, - name='edit-constructor-switch'), - url(r'^del_constructor_switch/(?P[0-9]+)$', + name="edit-constructor-switch", + ), + url( + r"^del_constructor_switch/(?P[0-9]+)$", views.del_constructor_switch, - name='del-constructor-switch'), - url(r'^new_switch_bay/$', - views.new_switch_bay, - name='new-switch-bay'), - url(r'^edit_switch_bay/(?P[0-9]+)$', + name="del-constructor-switch", + ), + url(r"^new_switch_bay/$", views.new_switch_bay, name="new-switch-bay"), + url( + r"^edit_switch_bay/(?P[0-9]+)$", views.edit_switch_bay, - name='edit-switch-bay'), - url(r'^del_switch_bay/(?P[0-9]+)$', + name="edit-switch-bay", + ), + url( + r"^del_switch_bay/(?P[0-9]+)$", views.del_switch_bay, - name='del-switch-bay'), - url(r'^new_building/$', - views.new_building, - name='new-building'), - url(r'^edit_building/(?P[0-9]+)$', + name="del-switch-bay", + ), + url(r"^new_building/$", views.new_building, name="new-building"), + url( + r"^edit_building/(?P[0-9]+)$", views.edit_building, - name='edit-building'), - url(r'^del_building/(?P[0-9]+)$', + name="edit-building", + ), + url( + r"^del_building/(?P[0-9]+)$", views.del_building, - name='del-building'), - url(r'^new_dormitory/$', - views.new_dormitory, - name='new-dormitory'), - url(r'^edit_dormitory/(?P[0-9]+)$', + name="del-building", + ), + url(r"^new_dormitory/$", views.new_dormitory, name="new-dormitory"), + url( + r"^edit_dormitory/(?P[0-9]+)$", views.edit_dormitory, - name='edit-dormitory'), - url(r'^del_dormitory/(?P[0-9]+)$', + name="edit-dormitory", + ), + url( + r"^del_dormitory/(?P[0-9]+)$", views.del_dormitory, - name='del-dormitory'), - url(r'^index_port_profile/$', - views.index_port_profile, - name='index-port-profile'), - url(r'^new_port_profile/$', - views.new_port_profile, - name='new-port-profile'), - url(r'^edit_port_profile/(?P[0-9]+)$', + name="del-dormitory", + ), + url(r"^index_port_profile/$", views.index_port_profile, name="index-port-profile"), + url(r"^new_port_profile/$", views.new_port_profile, name="new-port-profile"), + url( + r"^edit_port_profile/(?P[0-9]+)$", views.edit_port_profile, - name='edit-port-profile'), - url(r'^del_port_profile/(?P[0-9]+)$', + name="edit-port-profile", + ), + url( + r"^del_port_profile/(?P[0-9]+)$", views.del_port_profile, - name='del-port-profile'), - url(r'^edit_vlanoptions/(?P[0-9]+)$', + name="del-port-profile", + ), + url( + r"^edit_vlanoptions/(?P[0-9]+)$", views.edit_vlanoptions, - name='edit-vlanoptions'), - url(r'^add_module/$', views.add_module, name='add-module'), - url(r'^edit_module/(?P[0-9]+)$', + name="edit-vlanoptions", + ), + url(r"^add_module/$", views.add_module, name="add-module"), + url( + r"^edit_module/(?P[0-9]+)$", views.edit_module, - name='edit-module'), - url(r'^del_module/(?P[0-9]+)$', views.del_module, name='del-module'), - url(r'^index_module/$', views.index_module, name='index-module'), - url(r'^add_module_on/$', views.add_module_on, name='add-module-on'), - url(r'^edit_module_on/(?P[0-9]+)$', + name="edit-module", + ), + url( + r"^del_module/(?P[0-9]+)$", views.del_module, name="del-module" + ), + url(r"^index_module/$", views.index_module, name="index-module"), + url(r"^add_module_on/$", views.add_module_on, name="add-module-on"), + url( + r"^edit_module_on/(?P[0-9]+)$", views.edit_module_on, - name='edit-module-on'), - url(r'^del_module_on/(?P[0-9]+)$', views.del_module_on, name='del-module-on'), + name="edit-module-on", + ), + url( + r"^del_module_on/(?P[0-9]+)$", + views.del_module_on, + name="del-module-on", + ), ] diff --git a/topologie/views.py b/topologie/views.py index 60ebc272..84b0345a 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -48,30 +48,17 @@ from django.utils.translation import ugettext as _ import tempfile from users.views import form -from re2o.base import ( - re2o_paginator, - SortTable, -) -from re2o.acl import ( - can_create, - can_edit, - can_delete, - can_view, - can_view_all, -) +from re2o.base import re2o_paginator, SortTable +from re2o.acl import can_create, can_edit, can_delete, can_view, can_view_all from re2o.settings import MEDIA_ROOT from machines.forms import ( DomainForm, EditInterfaceForm, AddInterfaceForm, - EditOptionVlanForm + EditOptionVlanForm, ) from machines.views import generate_ipv4_mbf_param -from machines.models import ( - Interface, - Service_link, - Vlan -) +from machines.models import Interface, Service_link, Vlan from preferences.models import AssoOption, GeneralOption from .models import ( @@ -110,10 +97,7 @@ from .forms import ( EditSwitchModuleForm, ) -from subprocess import ( - Popen, - PIPE -) +from subprocess import Popen, PIPE from os.path import isfile @@ -122,60 +106,64 @@ from os.path import isfile @can_view_all(Switch) def index(request): """ Vue d'affichage de tous les swicthes""" - switch_list = (Switch.objects - .prefetch_related(Prefetch( - 'interface_set', - queryset=(Interface.objects - .select_related('ipv4__ip_type__extension') - .select_related('domain__extension')) - )) - .select_related('stack') - .select_related('switchbay__building__dormitory') - .select_related('model__constructor')) + switch_list = ( + Switch.objects.prefetch_related( + Prefetch( + "interface_set", + queryset=( + Interface.objects.select_related( + "ipv4__ip_type__extension" + ).select_related("domain__extension") + ), + ) + ) + .select_related("stack") + .select_related("switchbay__building__dormitory") + .select_related("model__constructor") + ) switch_list = SortTable.sort( switch_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX, ) - pagination_number = GeneralOption.get_cached_value('pagination_number') + pagination_number = GeneralOption.get_cached_value("pagination_number") switch_list = re2o_paginator(request, switch_list, pagination_number) if any( service_link.need_regen for service_link in Service_link.objects.filter( - service__service_type='graph_topo') + service__service_type="graph_topo" + ) ): make_machine_graph() for service_link in Service_link.objects.filter( - service__service_type='graph_topo'): + service__service_type="graph_topo" + ): service_link.done_regen() if not isfile("/var/www/re2o/media/images/switchs.png"): make_machine_graph() - return render( - request, - 'topologie/index.html', - {'switch_list': switch_list} - ) + return render(request, "topologie/index.html", {"switch_list": switch_list}) @login_required @can_view_all(PortProfile) def index_port_profile(request): - pagination_number = GeneralOption.get_cached_value('pagination_number') - port_profile_list = PortProfile.objects.all()\ - .select_related('vlan_untagged')\ - .select_related('on_dormitory')\ - .prefetch_related('vlan_tagged') - port_profile_list = re2o_paginator( - request, port_profile_list, pagination_number) - vlan_list = Vlan.objects.all().order_by('vlan_id') + pagination_number = GeneralOption.get_cached_value("pagination_number") + port_profile_list = ( + PortProfile.objects.all() + .select_related("vlan_untagged") + .select_related("on_dormitory") + .prefetch_related("vlan_tagged") + ) + port_profile_list = re2o_paginator(request, port_profile_list, pagination_number) + vlan_list = Vlan.objects.all().order_by("vlan_id") return render( request, - 'topologie/index_portprofile.html', - {'port_profile_list': port_profile_list, 'vlan_list': vlan_list} + "topologie/index_portprofile.html", + {"port_profile_list": port_profile_list, "vlan_list": vlan_list}, ) @@ -184,34 +172,32 @@ def index_port_profile(request): @can_view(Switch) def index_port(request, switch, switchid): """ Affichage de l'ensemble des ports reliés à un switch particulier""" - port_list = (Port.objects - .filter(switch=switch) - .select_related('room__building__dormitory') - .select_related('machine_interface__domain__extension') - .select_related('machine_interface__machine__user') - .select_related('machine_interface__machine__accesspoint') - .select_related('related__switch__switchbay__building__dormitory') - .prefetch_related(Prefetch( - 'related__switch__interface_set', - queryset=(Interface.objects - .select_related('domain__extension')) - )) - .select_related('switch__switchbay__building__dormitory') - .select_related('switch__model__constructor')) + port_list = ( + Port.objects.filter(switch=switch) + .select_related("room__building__dormitory") + .select_related("machine_interface__domain__extension") + .select_related("machine_interface__machine__user") + .select_related("machine_interface__machine__accesspoint") + .select_related("related__switch__switchbay__building__dormitory") + .prefetch_related( + Prefetch( + "related__switch__interface_set", + queryset=(Interface.objects.select_related("domain__extension")), + ) + ) + .select_related("switch__switchbay__building__dormitory") + .select_related("switch__model__constructor") + ) port_list = SortTable.sort( port_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_PORT + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_PORT, ) return render( request, - 'topologie/index_p.html', - { - 'port_list': port_list, - 'id_switch': switchid, - 'switch': switch - } + "topologie/index_p.html", + {"port_list": port_list, "id_switch": switchid, "switch": switch}, ) @@ -219,92 +205,88 @@ def index_port(request, switch, switchid): @can_view_all(Room) def index_room(request): """ Affichage de l'ensemble des chambres""" - room_list = Room.objects.select_related('building__dormitory') + room_list = Room.objects.select_related("building__dormitory") room_list = SortTable.sort( room_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_ROOM + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_ROOM, ) - pagination_number = GeneralOption.get_cached_value('pagination_number') + pagination_number = GeneralOption.get_cached_value("pagination_number") room_list = re2o_paginator(request, room_list, pagination_number) - return render( - request, - 'topologie/index_room.html', - {'room_list': room_list} - ) + return render(request, "topologie/index_room.html", {"room_list": room_list}) @login_required @can_view_all(AccessPoint) def index_ap(request): """ Affichage de l'ensemble des bornes""" - ap_list = (AccessPoint.objects - .prefetch_related(Prefetch( - 'interface_set', - queryset=(Interface.objects - .select_related('ipv4__ip_type__extension') - .select_related('domain__extension')) - )).distinct()) + ap_list = AccessPoint.objects.prefetch_related( + Prefetch( + "interface_set", + queryset=( + Interface.objects.select_related( + "ipv4__ip_type__extension" + ).select_related("domain__extension") + ), + ) + ).distinct() ap_list = SortTable.sort( ap_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_BORNE + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_BORNE, ) - pagination_number = GeneralOption.get_cached_value('pagination_number') + pagination_number = GeneralOption.get_cached_value("pagination_number") ap_list = re2o_paginator(request, ap_list, pagination_number) - return render( - request, - 'topologie/index_ap.html', - {'ap_list': ap_list} - ) + return render(request, "topologie/index_ap.html", {"ap_list": ap_list}) @login_required @can_view_all(Stack, Building, Dormitory, SwitchBay) def index_physical_grouping(request): """Affichage de la liste des stacks (affiche l'ensemble des switches)""" - stack_list = (Stack.objects - .prefetch_related( - 'switch_set__interface_set__domain__extension' - )) - building_list = Building.objects.all().select_related('dormitory') - dormitory_list = Dormitory.objects.all().prefetch_related('building_set') - switch_bay_list = SwitchBay.objects.select_related('building__dormitory').prefetch_related('switch_set__interface_set__domain') + stack_list = Stack.objects.prefetch_related( + "switch_set__interface_set__domain__extension" + ) + building_list = Building.objects.all().select_related("dormitory") + dormitory_list = Dormitory.objects.all().prefetch_related("building_set") + switch_bay_list = SwitchBay.objects.select_related( + "building__dormitory" + ).prefetch_related("switch_set__interface_set__domain") stack_list = SortTable.sort( stack_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_STACK + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_STACK, ) building_list = SortTable.sort( building_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_BUILDING + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_BUILDING, ) dormitory_list = SortTable.sort( dormitory_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_DORMITORY + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_DORMITORY, ) switch_bay_list = SortTable.sort( switch_bay_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_SWITCH_BAY + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_SWITCH_BAY, ) return render( request, - 'topologie/index_physical_grouping.html', + "topologie/index_physical_grouping.html", { - 'stack_list': stack_list, - 'switch_bay_list': switch_bay_list, - 'building_list': building_list, - 'dormitory_list': dormitory_list, - } + "stack_list": stack_list, + "switch_bay_list": switch_bay_list, + "building_list": building_list, + "dormitory_list": dormitory_list, + }, ) @@ -312,27 +294,29 @@ def index_physical_grouping(request): @can_view_all(ModelSwitch, ConstructorSwitch) def index_model_switch(request): """ Affichage de l'ensemble des modèles de switches""" - model_switch_list = ModelSwitch.objects.select_related('constructor').prefetch_related('switch_set__interface_set__domain') + model_switch_list = ModelSwitch.objects.select_related( + "constructor" + ).prefetch_related("switch_set__interface_set__domain") constructor_switch_list = ConstructorSwitch.objects model_switch_list = SortTable.sort( model_switch_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_MODEL_SWITCH + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_MODEL_SWITCH, ) constructor_switch_list = SortTable.sort( constructor_switch_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.TOPOLOGIE_INDEX_CONSTRUCTOR_SWITCH + request.GET.get("col"), + request.GET.get("order"), + SortTable.TOPOLOGIE_INDEX_CONSTRUCTOR_SWITCH, ) return render( request, - 'topologie/index_model_switch.html', + "topologie/index_model_switch.html", { - 'model_switch_list': model_switch_list, - 'constructor_switch_list': constructor_switch_list, - } + "model_switch_list": model_switch_list, + "constructor_switch_list": constructor_switch_list, + }, ) @@ -341,15 +325,17 @@ def index_model_switch(request): def index_module(request): """Display all modules of switchs""" module_list = ModuleSwitch.objects.all() - modular_switchs = Switch.objects.filter(model__is_modular=True)\ - .select_related('model').prefetch_related('moduleonswitch_set__module') - pagination_number = GeneralOption.get_cached_value('pagination_number') + modular_switchs = ( + Switch.objects.filter(model__is_modular=True) + .select_related("model") + .prefetch_related("moduleonswitch_set__module") + ) + pagination_number = GeneralOption.get_cached_value("pagination_number") module_list = re2o_paginator(request, module_list, pagination_number) return render( request, - 'topologie/index_module.html', - {'module_list': module_list, - 'modular_switchs': modular_switchs} + "topologie/index_module.html", + {"module_list": module_list, "modular_switchs": modular_switchs}, ) @@ -362,11 +348,9 @@ def edit_vlanoptions(request, vlan_instance, **_kwargs): if vlan.changed_data: vlan.save() messages.success(request, _("The VLAN was edited.")) - return redirect(reverse('topologie:index-port-profile')) + return redirect(reverse("topologie:index-port-profile")) return form( - {'vlanform': vlan, 'action_name': _("Edit")}, - 'machines/machine.html', - request + {"vlanform": vlan, "action_name": _("Edit")}, "machines/machine.html", request ) @@ -378,7 +362,7 @@ def new_port(request, switchid): switch = Switch.objects.get(pk=switchid) except Switch.DoesNotExist: messages.error(request, _("Nonexistent switch.")) - return redirect(reverse('topologie:index')) + return redirect(reverse("topologie:index")) port = AddPortForm(request.POST or None) if port.is_valid(): port = port.save(commit=False) @@ -388,14 +372,12 @@ def new_port(request, switchid): messages.success(request, _("The port was added.")) except IntegrityError: messages.error(request, _("The port already exists.")) - return redirect(reverse( - 'topologie:index-port', - kwargs={'switchid': switchid} - )) + return redirect(reverse("topologie:index-port", kwargs={"switchid": switchid})) return form( - {'id_switch': switchid, 'topoform': port, 'action_name': _("Add")}, - 'topologie/topo.html', - request) + {"id_switch": switchid, "topoform": port, "action_name": _("Add")}, + "topologie/topo.html", + request, + ) @login_required @@ -409,18 +391,19 @@ def edit_port(request, port_object, **_kwargs): if port.changed_data: port.save() messages.success(request, _("The port was edited.")) - return redirect(reverse( - 'topologie:index-port', - kwargs={'switchid': str(port_object.switch.id)} - )) + return redirect( + reverse( + "topologie:index-port", kwargs={"switchid": str(port_object.switch.id)} + ) + ) return form( { - 'id_switch': str(port_object.switch.id), - 'topoform': port, - 'action_name': _("Edit") + "id_switch": str(port_object.switch.id), + "topoform": port, + "action_name": _("Edit"), }, - 'topologie/topo.html', - request + "topologie/topo.html", + request, ) @@ -435,14 +418,18 @@ def del_port(request, port, **_kwargs): except ProtectedError: messages.error( request, - (_("The port %s is used by another object, impossible to" - " delete it.") % port) + ( + _( + "The port %s is used by another object, impossible to" + " delete it." + ) + % port + ), ) - return redirect(reverse( - 'topologie:index-port', - kwargs={'switchid': str(port.switch.id)} - )) - return form({'objet': port}, 'topologie/delete.html', request) + return redirect( + reverse("topologie:index-port", kwargs={"switchid": str(port.switch.id)}) + ) + return form({"objet": port}, "topologie/delete.html", request) @login_required @@ -453,11 +440,9 @@ def new_stack(request): if stack.is_valid(): stack.save() messages.success(request, _("The stack was created.")) - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'topoform': stack, 'action_name': _("Create")}, - 'topologie/topo.html', - request + {"topoform": stack, "action_name": _("Create")}, "topologie/topo.html", request ) @@ -469,11 +454,9 @@ def edit_stack(request, stack, **_kwargs): if stack.is_valid(): if stack.changed_data: stack.save() - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'topoform': stack, 'action_name': _("Edit")}, - 'topologie/topo.html', - request + {"topoform": stack, "action_name": _("Edit")}, "topologie/topo.html", request ) @@ -488,11 +471,16 @@ def del_stack(request, stack, **_kwargs): except ProtectedError: messages.error( request, - (_("The stack %s is used by another object, impossible to" - " deleted it.") % stack) + ( + _( + "The stack %s is used by another object, impossible to" + " deleted it." + ) + % stack + ), ) - return redirect(reverse('topologie:index-physical-grouping')) - return form({'objet': stack}, 'topologie/delete.html', request) + return redirect(reverse("topologie:index-physical-grouping")) + return form({"objet": stack}, "topologie/delete.html", request) @login_required @@ -503,9 +491,9 @@ def edit_switchs_stack(request, stack, **_kwargs): if request.method == "POST": pass else: - context = {'stack': stack} - context['switchs_stack'] = stack.switchs_set.all() - context['switchs_autres'] = Switch.object.filter(stack=None) + context = {"stack": stack} + context["switchs_stack"] = stack.switchs_set.all() + context["switchs_autres"] = Switch.object.filter(stack=None) @login_required @@ -514,27 +502,22 @@ def new_switch(request): """ Creation d'un switch. Cree en meme temps l'interface et la machine associée. Vue complexe. Appelle successivement les 4 models forms adaptés : machine, interface, domain et switch""" - switch = NewSwitchForm( - request.POST or None, - user=request.user - ) - interface = AddInterfaceForm( - request.POST or None, - user=request.user - ) - domain = DomainForm( - request.POST or None, - user=request.user - ) + switch = NewSwitchForm(request.POST or None, user=request.user) + interface = AddInterfaceForm(request.POST or None, user=request.user) + domain = DomainForm(request.POST or None, user=request.user) if switch.is_valid() and interface.is_valid(): - user = AssoOption.get_cached_value('utilisateur_asso') + user = AssoOption.get_cached_value("utilisateur_asso") if not user: messages.error( request, - (_("The organisation's user doesn't exist yet, please create" - " or link it in the preferences.")) + ( + _( + "The organisation's user doesn't exist yet, please create" + " or link it in the preferences." + ) + ), ) - return redirect(reverse('topologie:index')) + return redirect(reverse("topologie:index")) new_switch_obj = switch.save(commit=False) new_switch_obj.user = user new_interface_obj = interface.save(commit=False) @@ -547,18 +530,18 @@ def new_switch(request): new_domain_obj.interface_parent = new_interface_obj new_domain_obj.save() messages.success(request, _("The switch was created.")) - return redirect(reverse('topologie:index')) + return redirect(reverse("topologie:index")) i_mbf_param = generate_ipv4_mbf_param(interface, False) return form( { - 'topoform': interface, - 'machineform': switch, - 'domainform': domain, - 'i_mbf_param': i_mbf_param, - 'device': 'switch', + "topoform": interface, + "machineform": switch, + "domainform": domain, + "i_mbf_param": i_mbf_param, + "device": "switch", }, - 'topologie/topo_more.html', - request + "topologie/topo_more.html", + request, ) @@ -570,30 +553,24 @@ def create_ports(request, switchid): switch = Switch.objects.get(pk=switchid) except Switch.DoesNotExist: messages.error(request, _("Nonexistent switch.")) - return redirect(reverse('topologie:index')) + return redirect(reverse("topologie:index")) - first_port = getattr(switch.ports.order_by('port').first(), 'port', 1) + first_port = getattr(switch.ports.order_by("port").first(), "port", 1) last_port = switch.number + first_port - 1 port_form = CreatePortsForm( - request.POST or None, - initial={'begin': first_port, 'end': last_port} + request.POST or None, initial={"begin": first_port, "end": last_port} ) if port_form.is_valid(): - begin = port_form.cleaned_data['begin'] - end = port_form.cleaned_data['end'] + begin = port_form.cleaned_data["begin"] + end = port_form.cleaned_data["end"] try: switch.create_ports(begin, end) messages.success(request, _("The ports were created.")) except ValidationError as e: - messages.error(request, ''.join(e)) - return redirect(reverse( - 'topologie:index-port', - kwargs={'switchid': switchid} - )) + messages.error(request, "".join(e)) + return redirect(reverse("topologie:index-port", kwargs={"switchid": switchid})) return form( - {'id_switch': switchid, 'topoform': port_form}, - 'topologie/switch.html', - request + {"id_switch": switchid, "topoform": port_form}, "topologie/switch.html", request ) @@ -604,19 +581,15 @@ def edit_switch(request, switch, switchid): place dans le stack, interface et machine associée""" switch_form = EditSwitchForm( - request.POST or None, - instance=switch, - user=request.user + request.POST or None, instance=switch, user=request.user ) interface_form = EditInterfaceForm( - request.POST or None, - instance=switch.interface_set.first(), - user=request.user + request.POST or None, instance=switch.interface_set.first(), user=request.user ) domain_form = DomainForm( request.POST or None, instance=switch.interface_set.first().domain, - user=request.user + user=request.user, ) if switch_form.is_valid() and interface_form.is_valid(): new_switch_obj = switch_form.save(commit=False) @@ -629,19 +602,19 @@ def edit_switch(request, switch, switchid): if domain_form.changed_data: new_domain_obj.save() messages.success(request, _("The switch was edited.")) - return redirect(reverse('topologie:index')) + return redirect(reverse("topologie:index")) i_mbf_param = generate_ipv4_mbf_param(interface_form, False) return form( { - 'id_switch': switchid, - 'topoform': interface_form, - 'machineform': switch_form, - 'domainform': domain_form, - 'i_mbf_param': i_mbf_param, - 'device': 'switch', + "id_switch": switchid, + "topoform": interface_form, + "machineform": switch_form, + "domainform": domain_form, + "i_mbf_param": i_mbf_param, + "device": "switch", }, - 'topologie/topo_more.html', - request + "topologie/topo_more.html", + request, ) @@ -651,27 +624,22 @@ def new_ap(request): """ Creation d'une ap. Cree en meme temps l'interface et la machine associée. Vue complexe. Appelle successivement les 3 models forms adaptés : machine, interface, domain et switch""" - ap = AddAccessPointForm( - request.POST or None, - user=request.user - ) - interface = AddInterfaceForm( - request.POST or None, - user=request.user - ) - domain = DomainForm( - request.POST or None, - user=request.user - ) + ap = AddAccessPointForm(request.POST or None, user=request.user) + interface = AddInterfaceForm(request.POST or None, user=request.user) + domain = DomainForm(request.POST or None, user=request.user) if ap.is_valid() and interface.is_valid(): - user = AssoOption.get_cached_value('utilisateur_asso') + user = AssoOption.get_cached_value("utilisateur_asso") if not user: messages.error( request, - (_("The organisation's user doesn't exist yet, please create" - " or link it in the preferences.")) + ( + _( + "The organisation's user doesn't exist yet, please create" + " or link it in the preferences." + ) + ), ) - return redirect(reverse('topologie:index')) + return redirect(reverse("topologie:index")) new_ap_obj = ap.save(commit=False) new_ap_obj.user = user new_interface_obj = interface.save(commit=False) @@ -684,18 +652,18 @@ def new_ap(request): new_domain_obj.interface_parent = new_interface_obj new_domain_obj.save() messages.success(request, _("The access point was created.")) - return redirect(reverse('topologie:index-ap')) + return redirect(reverse("topologie:index-ap")) i_mbf_param = generate_ipv4_mbf_param(interface, False) return form( { - 'topoform': interface, - 'machineform': ap, - 'domainform': domain, - 'i_mbf_param': i_mbf_param, - 'device': 'wifi ap', + "topoform": interface, + "machineform": ap, + "domainform": domain, + "i_mbf_param": i_mbf_param, + "device": "wifi ap", }, - 'topologie/topo_more.html', - request + "topologie/topo_more.html", + request, ) @@ -705,29 +673,27 @@ def edit_ap(request, ap, **_kwargs): """ Edition d'un switch. Permet de chambre nombre de ports, place dans le stack, interface et machine associée""" interface_form = EditInterfaceForm( - request.POST or None, - user=request.user, - instance=ap.interface_set.first() - ) - ap_form = EditAccessPointForm( - request.POST or None, - user=request.user, - instance=ap + request.POST or None, user=request.user, instance=ap.interface_set.first() ) + ap_form = EditAccessPointForm(request.POST or None, user=request.user, instance=ap) domain_form = DomainForm( request.POST or None, instance=ap.interface_set.first().domain, - user=request.user + user=request.user, ) if ap_form.is_valid() and interface_form.is_valid(): - user = AssoOption.get_cached_value('utilisateur_asso') + user = AssoOption.get_cached_value("utilisateur_asso") if not user: messages.error( request, - (_("The organisation's user doesn't exist yet, please create" - " or link it in the preferences.")) + ( + _( + "The organisation's user doesn't exist yet, please create" + " or link it in the preferences." + ) + ), ) - return redirect(reverse('topologie:index-ap')) + return redirect(reverse("topologie:index-ap")) new_ap_obj = ap_form.save(commit=False) new_interface_obj = interface_form.save(commit=False) new_domain_obj = domain_form.save(commit=False) @@ -738,18 +704,18 @@ def edit_ap(request, ap, **_kwargs): if domain_form.changed_data: new_domain_obj.save() messages.success(request, _("The access point was edited.")) - return redirect(reverse('topologie:index-ap')) + return redirect(reverse("topologie:index-ap")) i_mbf_param = generate_ipv4_mbf_param(interface_form, False) return form( { - 'topoform': interface_form, - 'machineform': ap_form, - 'domainform': domain_form, - 'i_mbf_param': i_mbf_param, - 'device': 'wifi ap', + "topoform": interface_form, + "machineform": ap_form, + "domainform": domain_form, + "i_mbf_param": i_mbf_param, + "device": "wifi ap", }, - 'topologie/topo_more.html', - request + "topologie/topo_more.html", + request, ) @@ -761,11 +727,9 @@ def new_room(request): if room.is_valid(): room.save() messages.success(request, _("The room was created.")) - return redirect(reverse('topologie:index-room')) + return redirect(reverse("topologie:index-room")) return form( - {'topoform': room, 'action_name': _("Create")}, - 'topologie/topo.html', - request + {"topoform": room, "action_name": _("Create")}, "topologie/topo.html", request ) @@ -778,11 +742,9 @@ def edit_room(request, room, **_kwargs): if room.changed_data: room.save() messages.success(request, _("The room was edited.")) - return redirect(reverse('topologie:index-room')) + return redirect(reverse("topologie:index-room")) return form( - {'topoform': room, 'action_name': _("Edit")}, - 'topologie/topo.html', - request + {"topoform": room, "action_name": _("Edit")}, "topologie/topo.html", request ) @@ -797,14 +759,17 @@ def del_room(request, room, **_kwargs): except ProtectedError: messages.error( request, - (_("The room %s is used by another object, impossible to" - " deleted it.") % room) + ( + _( + "The room %s is used by another object, impossible to" + " deleted it." + ) + % room + ), ) - return redirect(reverse('topologie:index-room')) + return redirect(reverse("topologie:index-room")) return form( - {'objet': room, 'objet_name': _("Room")}, - 'topologie/delete.html', - request + {"objet": room, "objet_name": _("Room")}, "topologie/delete.html", request ) @@ -816,11 +781,11 @@ def new_model_switch(request): if model_switch.is_valid(): model_switch.save() messages.success(request, _("The switch model was created.")) - return redirect(reverse('topologie:index-model-switch')) + return redirect(reverse("topologie:index-model-switch")) return form( - {'topoform': model_switch, 'action_name': _("Create")}, - 'topologie/topo.html', - request + {"topoform": model_switch, "action_name": _("Create")}, + "topologie/topo.html", + request, ) @@ -829,19 +794,16 @@ def new_model_switch(request): def edit_model_switch(request, model_switch, **_kwargs): """ Edition d'un modèle de switch""" - model_switch = EditModelSwitchForm( - request.POST or None, - instance=model_switch - ) + model_switch = EditModelSwitchForm(request.POST or None, instance=model_switch) if model_switch.is_valid(): if model_switch.changed_data: model_switch.save() messages.success(request, _("The switch model was edited.")) - return redirect(reverse('topologie:index-model-switch')) + return redirect(reverse("topologie:index-model-switch")) return form( - {'topoform': model_switch, 'action_name': _("Edit")}, - 'topologie/topo.html', - request + {"topoform": model_switch, "action_name": _("Edit")}, + "topologie/topo.html", + request, ) @@ -856,14 +818,19 @@ def del_model_switch(request, model_switch, **_kwargs): except ProtectedError: messages.error( request, - (_("The switch model %s is used by another object," - " impossible to delete it.") % model_switch) + ( + _( + "The switch model %s is used by another object," + " impossible to delete it." + ) + % model_switch + ), ) - return redirect(reverse('topologie:index-model-switch')) + return redirect(reverse("topologie:index-model-switch")) return form( - {'objet': model_switch, 'objet_name': _("Switch model")}, - 'topologie/delete.html', - request + {"objet": model_switch, "objet_name": _("Switch model")}, + "topologie/delete.html", + request, ) @@ -875,11 +842,11 @@ def new_switch_bay(request): if switch_bay.is_valid(): switch_bay.save() messages.success(request, _("The switch bay was created.")) - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'topoform': switch_bay, 'action_name': _("Create")}, - 'topologie/topo.html', - request + {"topoform": switch_bay, "action_name": _("Create")}, + "topologie/topo.html", + request, ) @@ -892,11 +859,11 @@ def edit_switch_bay(request, switch_bay, **_kwargs): if switch_bay.changed_data: switch_bay.save() messages.success(request, _("The switch bay was edited.")) - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'topoform': switch_bay, 'action_name': _("Edit")}, - 'topologie/topo.html', - request + {"topoform": switch_bay, "action_name": _("Edit")}, + "topologie/topo.html", + request, ) @@ -911,14 +878,19 @@ def del_switch_bay(request, switch_bay, **_kwargs): except ProtectedError: messages.error( request, - (_("The switch bay %s is used by another object," - " impossible to delete it.") % switch_bay) + ( + _( + "The switch bay %s is used by another object," + " impossible to delete it." + ) + % switch_bay + ), ) - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'objet': switch_bay, 'objet_name': _("Switch bay")}, - 'topologie/delete.html', - request + {"objet": switch_bay, "objet_name": _("Switch bay")}, + "topologie/delete.html", + request, ) @@ -931,11 +903,11 @@ def new_building(request): if building.is_valid(): building.save() messages.success(request, _("The building was created.")) - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'topoform': building, 'action_name': _("Create")}, - 'topologie/topo.html', - request + {"topoform": building, "action_name": _("Create")}, + "topologie/topo.html", + request, ) @@ -949,11 +921,9 @@ def edit_building(request, building, **_kwargs): if building.changed_data: building.save() messages.success(request, _("The building was edited.")) - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'topoform': building, 'action_name': _("Edit")}, - 'topologie/topo.html', - request + {"topoform": building, "action_name": _("Edit")}, "topologie/topo.html", request ) @@ -969,14 +939,19 @@ def del_building(request, building, **_kwargs): except ProtectedError: messages.error( request, - (_("The building %s is used by another object, impossible" - " to delete it.") % building) + ( + _( + "The building %s is used by another object, impossible" + " to delete it." + ) + % building + ), ) - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'objet': building, 'objet_name': _("Building")}, - 'topologie/delete.html', - request + {"objet": building, "objet_name": _("Building")}, + "topologie/delete.html", + request, ) @@ -989,11 +964,11 @@ def new_dormitory(request): if dormitory.is_valid(): dormitory.save() messages.success(request, _("The dormitory was created.")) - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'topoform': dormitory, 'action_name': _("Create")}, - 'topologie/topo.html', - request + {"topoform": dormitory, "action_name": _("Create")}, + "topologie/topo.html", + request, ) @@ -1007,11 +982,11 @@ def edit_dormitory(request, dormitory, **_kwargs): if dormitory.changed_data: dormitory.save() messages.success(request, _("The dormitory was edited.")) - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'topoform': dormitory, 'action_name': _("Edit")}, - 'topologie/topo.html', - request + {"topoform": dormitory, "action_name": _("Edit")}, + "topologie/topo.html", + request, ) @@ -1027,14 +1002,19 @@ def del_dormitory(request, dormitory, **_kwargs): except ProtectedError: messages.error( request, - (_("The dormitory %s is used by another object, impossible" - " to delete it.") % dormitory) + ( + _( + "The dormitory %s is used by another object, impossible" + " to delete it." + ) + % dormitory + ), ) - return redirect(reverse('topologie:index-physical-grouping')) + return redirect(reverse("topologie:index-physical-grouping")) return form( - {'objet': dormitory, 'objet_name': _("Dormitory")}, - 'topologie/delete.html', - request + {"objet": dormitory, "objet_name": _("Dormitory")}, + "topologie/delete.html", + request, ) @@ -1046,11 +1026,11 @@ def new_constructor_switch(request): if constructor_switch.is_valid(): constructor_switch.save() messages.success(request, _("The switch constructor was created.")) - return redirect(reverse('topologie:index-model-switch')) + return redirect(reverse("topologie:index-model-switch")) return form( - {'topoform': constructor_switch, 'action_name': _("Create")}, - 'topologie/topo.html', - request + {"topoform": constructor_switch, "action_name": _("Create")}, + "topologie/topo.html", + request, ) @@ -1060,18 +1040,17 @@ def edit_constructor_switch(request, constructor_switch, **_kwargs): """ Edition d'un constructeur de switch""" constructor_switch = EditConstructorSwitchForm( - request.POST or None, - instance=constructor_switch + request.POST or None, instance=constructor_switch ) if constructor_switch.is_valid(): if constructor_switch.changed_data: constructor_switch.save() messages.success(request, _("The switch constructor was edited.")) - return redirect(reverse('topologie:index-model-switch')) + return redirect(reverse("topologie:index-model-switch")) return form( - {'topoform': constructor_switch, 'action_name': _("Edit")}, - 'topologie/topo.html', - request + {"topoform": constructor_switch, "action_name": _("Edit")}, + "topologie/topo.html", + request, ) @@ -1086,14 +1065,20 @@ def del_constructor_switch(request, constructor_switch, **_kwargs): except ProtectedError: messages.error( request, - (_("The switch constructor %s is used by another object," - " impossible to delete it.") % constructor_switch) + ( + _( + "The switch constructor %s is used by another object," + " impossible to delete it." + ) + % constructor_switch + ), ) - return redirect(reverse('topologie:index-model-switch')) - return form({ - 'objet': constructor_switch, - 'objet_name': _("Switch constructor") - }, 'topologie/delete.html', request) + return redirect(reverse("topologie:index-model-switch")) + return form( + {"objet": constructor_switch, "objet_name": _("Switch constructor")}, + "topologie/delete.html", + request, + ) @login_required @@ -1104,11 +1089,11 @@ def new_port_profile(request): if port_profile.is_valid(): port_profile.save() messages.success(request, _("The port profile was created.")) - return redirect(reverse('topologie:index-port-profile')) + return redirect(reverse("topologie:index-port-profile")) return form( - {'topoform': port_profile, 'action_name': _("Create")}, - 'topologie/topo.html', - request + {"topoform": port_profile, "action_name": _("Create")}, + "topologie/topo.html", + request, ) @@ -1116,17 +1101,16 @@ def new_port_profile(request): @can_edit(PortProfile) def edit_port_profile(request, port_profile, **_kwargs): """Edit a port profile""" - port_profile = EditPortProfileForm( - request.POST or None, instance=port_profile) + port_profile = EditPortProfileForm(request.POST or None, instance=port_profile) if port_profile.is_valid(): if port_profile.changed_data: port_profile.save() messages.success(request, _("The port profile was edited.")) - return redirect(reverse('topologie:index-port-profile')) + return redirect(reverse("topologie:index-port-profile")) return form( - {'topoform': port_profile, 'action_name': _("Edit")}, - 'topologie/topo.html', - request + {"topoform": port_profile, "action_name": _("Edit")}, + "topologie/topo.html", + request, ) @@ -1134,19 +1118,17 @@ def edit_port_profile(request, port_profile, **_kwargs): @can_delete(PortProfile) def del_port_profile(request, port_profile, **_kwargs): """Delete a port profile""" - if request.method == 'POST': + if request.method == "POST": try: port_profile.delete() - messages.success(request, - _("The port profile was deleted.")) + messages.success(request, _("The port profile was deleted.")) except ProtectedError: - messages.success(request, - _("Impossible to delete the port profile.")) - return redirect(reverse('topologie:index-port-profile')) + messages.success(request, _("Impossible to delete the port profile.")) + return redirect(reverse("topologie:index-port-profile")) return form( - {'objet': port_profile, 'objet_name': _("Port profile")}, - 'topologie/delete.html', - request + {"objet": port_profile, "objet_name": _("Port profile")}, + "topologie/delete.html", + request, ) @@ -1158,11 +1140,9 @@ def add_module(request): if module.is_valid(): module.save() messages.success(request, _("The module was created.")) - return redirect(reverse('topologie:index-module')) + return redirect(reverse("topologie:index-module")) return form( - {'topoform': module, 'action_name': _("Create")}, - 'topologie/topo.html', - request + {"topoform": module, "action_name": _("Create")}, "topologie/topo.html", request ) @@ -1175,11 +1155,9 @@ def edit_module(request, module_instance, **_kwargs): if module.changed_data: module.save() messages.success(request, _("The module was edited.")) - return redirect(reverse('topologie:index-module')) + return redirect(reverse("topologie:index-module")) return form( - {'topoform': module, 'action_name': _("Edit")}, - 'topologie/topo.html', - request + {"topoform": module, "action_name": _("Edit")}, "topologie/topo.html", request ) @@ -1194,16 +1172,20 @@ def del_module(request, module, **_kwargs): except ProtectedError: messages.error( request, - (_("The module %s is used by another object, impossible to" - " deleted it.") % module) + ( + _( + "The module %s is used by another object, impossible to" + " deleted it." + ) + % module + ), ) - return redirect(reverse('topologie:index-module')) + return redirect(reverse("topologie:index-module")) return form( - {'objet': module, 'objet_name': _("Module")}, - 'topologie/delete.html', - request + {"objet": module, "objet_name": _("Module")}, "topologie/delete.html", request ) + @login_required @can_create(ModuleOnSwitch) def add_module_on(request): @@ -1212,11 +1194,11 @@ def add_module_on(request): if module_switch.is_valid(): module_switch.save() messages.success(request, _("The module was added.")) - return redirect(reverse('topologie:index-module')) + return redirect(reverse("topologie:index-module")) return form( - {'topoform': module_switch, 'action_name': _("Add")}, - 'topologie/topo.html', - request + {"topoform": module_switch, "action_name": _("Add")}, + "topologie/topo.html", + request, ) @@ -1229,11 +1211,9 @@ def edit_module_on(request, module_instance, **_kwargs): if module.changed_data: module.save() messages.success(request, _("The module was edited.")) - return redirect(reverse('topologie:index-module')) + return redirect(reverse("topologie:index-module")) return form( - {'topoform': module, 'action_name': _("Edit")}, - 'topologie/topo.html', - request + {"topoform": module, "action_name": _("Edit")}, "topologie/topo.html", request ) @@ -1248,14 +1228,17 @@ def del_module_on(request, module, **_kwargs): except ProtectedError: messages.error( request, - (_("The module %s is used by another object, impossible to" - " deleted it.") % module) + ( + _( + "The module %s is used by another object, impossible to" + " deleted it." + ) + % module + ), ) - return redirect(reverse('topologie:index-module')) + return redirect(reverse("topologie:index-module")) return form( - {'objet': module, 'objet_name': _("Module")}, - 'topologie/delete.html', - request + {"objet": module, "objet_name": _("Module")}, "topologie/delete.html", request ) @@ -1264,101 +1247,123 @@ def make_machine_graph(): Create the graph of switchs, machines and access points. """ dico = { - 'subs': [], - 'links': [], - 'alone': [], - 'colors': { - 'head': "#7f0505", # Color parameters for the graph - 'back': "#b5adad", - 'texte': "#563d01", - 'border_bornes': "#02078e", - 'head_bornes': "#25771c", - 'head_server': "#1c3777" - } + "subs": [], + "links": [], + "alone": [], + "colors": { + "head": "#7f0505", # Color parameters for the graph + "back": "#b5adad", + "texte": "#563d01", + "border_bornes": "#02078e", + "head_bornes": "#25771c", + "head_server": "#1c3777", + }, } - missing = list(Switch.objects.prefetch_related(Prefetch( - 'interface_set', - queryset=( - Interface.objects - .select_related('ipv4__ip_type__extension') - .select_related('domain__extension') + missing = list( + Switch.objects.prefetch_related( + Prefetch( + "interface_set", + queryset=( + Interface.objects.select_related( + "ipv4__ip_type__extension" + ).select_related("domain__extension") + ), + ) ) - ))) + ) detected = [] for building in Building.objects.all(): # Visit all buildings - dico['subs'].append( + dico["subs"].append( { - 'bat_id': building.id, - 'bat_name': building, - 'switchs': [], - 'bornes': [], - 'machines': [] + "bat_id": building.id, + "bat_name": building, + "switchs": [], + "bornes": [], + "machines": [], } ) # Visit all switchs in this building - for switch in Switch.objects.filter(switchbay__building=building).prefetch_related( - Prefetch( - 'interface_set', - queryset=( - Interface.objects - .select_related('ipv4__ip_type__extension') - .select_related('domain__extension') - ))).select_related('switchbay__building').select_related('switchbay__building__dormitory').select_related('model__constructor'): - dico['subs'][-1]['switchs'].append({ - 'name': switch.get_name, - 'nombre': switch.number, - 'model': switch.model, - 'id': switch.id, - 'batiment': building, - 'ports': [] - }) + for switch in ( + Switch.objects.filter(switchbay__building=building) + .prefetch_related( + Prefetch( + "interface_set", + queryset=( + Interface.objects.select_related( + "ipv4__ip_type__extension" + ).select_related("domain__extension") + ), + ) + ) + .select_related("switchbay__building") + .select_related("switchbay__building__dormitory") + .select_related("model__constructor") + ): + dico["subs"][-1]["switchs"].append( + { + "name": switch.get_name, + "nombre": switch.number, + "model": switch.model, + "id": switch.id, + "batiment": building, + "ports": [], + } + ) # visit all ports of this switch and add the switchs linked to it - for port in switch.ports.filter(related__isnull=False).select_related('related__switch'): - dico['subs'][-1]['switchs'][-1]['ports'].append({ - 'numero': port.port, - 'related': port.related.switch.get_name, - }) + for port in switch.ports.filter(related__isnull=False).select_related( + "related__switch" + ): + dico["subs"][-1]["switchs"][-1]["ports"].append( + {"numero": port.port, "related": port.related.switch.get_name} + ) - for ap in AccessPoint.all_ap_in(building).prefetch_related(Prefetch( - 'interface_set', - queryset=( - Interface.objects - .select_related('ipv4__ip_type__extension') - .select_related('domain__extension') - )) - ): + for ap in AccessPoint.all_ap_in(building).prefetch_related( + Prefetch( + "interface_set", + queryset=( + Interface.objects.select_related( + "ipv4__ip_type__extension" + ).select_related("domain__extension") + ), + ) + ): switch = ap.switch().first() - dico['subs'][-1]['bornes'].append({ - 'name': ap.short_name, - 'switch': switch.get_name, - 'port': switch.ports.filter( - machine_interface__machine=ap - ).first().port - }) - for server in Server.all_server_in(building).prefetch_related(Prefetch( - 'interface_set', - queryset=( - Interface.objects - .select_related('ipv4__ip_type__extension') - .select_related('domain__extension') - )) - ): - dico['subs'][-1]['machines'].append({ - 'name': server.short_name, - 'switch': server.switch().first().get_name, - 'port': Port.objects.filter( - machine_interface__machine=server - ).first().port - }) + dico["subs"][-1]["bornes"].append( + { + "name": ap.short_name, + "switch": switch.get_name, + "port": switch.ports.filter(machine_interface__machine=ap) + .first() + .port, + } + ) + for server in Server.all_server_in(building).prefetch_related( + Prefetch( + "interface_set", + queryset=( + Interface.objects.select_related( + "ipv4__ip_type__extension" + ).select_related("domain__extension") + ), + ) + ): + dico["subs"][-1]["machines"].append( + { + "name": server.short_name, + "switch": server.switch().first().get_name, + "port": Port.objects.filter(machine_interface__machine=server) + .first() + .port, + } + ) # While the list of forgotten ones is not empty while missing: if missing[0].ports.count(): # The switch is not empty - links, new_detected = recursive_switchs( - missing[0], None, [missing[0]]) + links, new_detected = recursive_switchs(missing[0], None, [missing[0]]) for link in links: - dico['links'].append(link) + dico["links"].append(link) # Update the lists of missings and already detected switchs missing = [i for i in missing if i not in new_detected] detected += new_detected @@ -1366,28 +1371,25 @@ def make_machine_graph(): else: del missing[0] # Switchs that are not connected or not in a building - for switch in Switch.objects.filter( - switchbay__isnull=True).exclude(ports__related__isnull=False): - dico['alone'].append({ - 'id': switch.id, - 'name': switch.get_name, - }) + for switch in Switch.objects.filter(switchbay__isnull=True).exclude( + ports__related__isnull=False + ): + dico["alone"].append({"id": switch.id, "name": switch.get_name}) # generate the dot file - dot_data = generate_dot(dico, 'topologie/graph_switch.dot') + dot_data = generate_dot(dico, "topologie/graph_switch.dot") # Create a temporary file to store the dot data - f = tempfile.NamedTemporaryFile(mode='w+', encoding='utf-8', delete=False) + f = tempfile.NamedTemporaryFile(mode="w+", encoding="utf-8", delete=False) with f: f.write(dot_data) unflatten = Popen( # unflatten the graph to make it look better - ["unflatten", "-l", "3", f.name], - stdout=PIPE + ["unflatten", "-l", "3", f.name], stdout=PIPE ) Popen( # pipe the result of the first command into the second ["dot", "-Tpng", "-o", MEDIA_ROOT + "/images/switchs.png"], stdin=unflatten.stdout, - stdout=PIPE + stdout=PIPE, ) @@ -1397,13 +1399,18 @@ def generate_dot(data, template): :param template: path to the dot template :return: all the lines of the dot file""" t = loader.get_template(template) - if not isinstance(t, Template) and \ - not (hasattr(t, 'template') and isinstance(t.template, Template)): - raise Exception(_("The default Django template isn't used. This can" - " lead to rendering errors. Check the parameters.")) + if not isinstance(t, Template) and not ( + hasattr(t, "template") and isinstance(t.template, Template) + ): + raise Exception( + _( + "The default Django template isn't used. This can" + " lead to rendering errors. Check the parameters." + ) + ) c = Context(data).flatten() dot = t.render(c) - return(dot) + return dot def recursive_switchs(switch_start, switch_before, detected): @@ -1421,12 +1428,14 @@ def recursive_switchs(switch_start, switch_before, detected): # create links to every switchs below for port in switch_start.ports.filter(related__isnull=False): # Not the switch that we come from, not the current switch - if port.related.switch != switch_before \ - and port.related.switch != port.switch \ - and port.related.switch not in detected: + if ( + port.related.switch != switch_before + and port.related.switch != port.switch + and port.related.switch not in detected + ): links = { # Dictionary of a link - 'depart': switch_start.id, - 'arrive': port.related.switch.id + "depart": switch_start.id, + "arrive": port.related.switch.id, } links_return.append(links) # Add current and below levels links @@ -1436,10 +1445,10 @@ def recursive_switchs(switch_start, switch_before, detected): if port.related.switch not in detected: # explore it and get the results links_down, detected = recursive_switchs( - port.related.switch, switch_start, detected) + port.related.switch, switch_start, detected + ) # Add the non empty links to the current list for link in links_down: if link: links_return.append(link) return (links_return, detected) - diff --git a/users/acl.py b/users/acl.py index 81d52026..993870a7 100644 --- a/users/acl.py +++ b/users/acl.py @@ -27,6 +27,7 @@ Here are defined some functions to check acl on the application. """ from django.utils.translation import ugettext as _ + def can_view(user): """Check if an user can view the application. @@ -37,11 +38,9 @@ def can_view(user): A couple (allowed, msg) where allowed is a boolean which is True if viewing is granted and msg is a message (can be None). """ - can = user.has_module_perms('users') + can = user.has_module_perms("users") return ( can, - None if can else _("You don't have the right to view this" - " application."), - ('users',) + None if can else _("You don't have the right to view this" " application."), + ("users",), ) - diff --git a/users/admin.py b/users/admin.py index f2fdc0c5..f3ec04f4 100644 --- a/users/admin.py +++ b/users/admin.py @@ -47,80 +47,92 @@ from .models import ( LdapUser, LdapServiceUser, LdapServiceUserGroup, - LdapUserGroup + LdapUserGroup, ) from .forms import ( UserChangeForm, UserCreationForm, ServiceUserChangeForm, - ServiceUserCreationForm + ServiceUserCreationForm, ) class LdapUserAdmin(admin.ModelAdmin): """Administration du ldapuser""" - list_display = ('name', 'uidNumber', 'login_shell') - exclude = ('user_password', 'sambat_nt_password') - search_fields = ('name',) + + list_display = ("name", "uidNumber", "login_shell") + exclude = ("user_password", "sambat_nt_password") + search_fields = ("name",) class LdapServiceUserAdmin(admin.ModelAdmin): """Administration du ldapserviceuser""" - list_display = ('name',) - exclude = ('user_password',) - search_fields = ('name',) + + list_display = ("name",) + exclude = ("user_password",) + search_fields = ("name",) class LdapUserGroupAdmin(admin.ModelAdmin): """Administration du ldapusergroupe""" - list_display = ('name', 'members', 'gid') - search_fields = ('name',) + + list_display = ("name", "members", "gid") + search_fields = ("name",) class LdapServiceUserGroupAdmin(admin.ModelAdmin): """Administration du ldap serviceusergroup""" - list_display = ('name',) - search_fields = ('name',) + + list_display = ("name",) + search_fields = ("name",) class SchoolAdmin(VersionAdmin): """Administration, gestion des écoles""" + pass class ListRightAdmin(VersionAdmin): """Gestion de la liste des droits existants Ne permet pas l'edition du gid (primarykey pour ldap)""" - list_display = ('unix_name',) + + list_display = ("unix_name",) class ListShellAdmin(VersionAdmin): """Gestion de la liste des shells coté admin""" + pass class RequestAdmin(admin.ModelAdmin): """Gestion des request objet, ticket pour lien de reinit mot de passe""" - list_display = ('user', 'type', 'created_at', 'expires_at') + + list_display = ("user", "type", "created_at", "expires_at") class BanAdmin(VersionAdmin): """Gestion des bannissements""" + pass class EMailAddressAdmin(VersionAdmin): """Gestion des alias mail""" + pass class WhitelistAdmin(VersionAdmin): """Gestion des whitelist""" + pass class UserAdmin(VersionAdmin, BaseUserAdmin): """Gestion d'un user : modification des champs perso, mot de passe, etc""" + # The forms to add and change user instances form = UserChangeForm add_form = UserCreationForm @@ -129,28 +141,25 @@ class UserAdmin(VersionAdmin, BaseUserAdmin): # These override the definitions on the base UserAdmin # that reference specific fields on auth.User. list_display = ( - 'pseudo', - 'surname', - 'email', - 'local_email_redirect', - 'local_email_enabled', - 'school', - 'is_admin', - 'shell' + "pseudo", + "surname", + "email", + "local_email_redirect", + "local_email_enabled", + "school", + "is_admin", + "shell", ) # Need to reset the settings from BaseUserAdmin # They are using fields we don't use like 'is_staff' list_filter = () fieldsets = ( - (None, {'fields': ('pseudo', 'password')}), + (None, {"fields": ("pseudo", "password")}), ( - 'Personal info', - { - 'fields': - ('surname', 'email', 'school', 'shell', 'uid_number') - } + "Personal info", + {"fields": ("surname", "email", "school", "shell", "uid_number")}, ), - ('Permissions', {'fields': ('is_admin', )}), + ("Permissions", {"fields": ("is_admin",)}), ) # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin # overrides get_fieldsets to use this attribute when creating a user. @@ -158,27 +167,28 @@ class UserAdmin(VersionAdmin, BaseUserAdmin): ( None, { - 'classes': ('wide',), - 'fields': ( - 'pseudo', - 'surname', - 'email', - 'school', - 'is_admin', - 'password1', - 'password2' - ) - } + "classes": ("wide",), + "fields": ( + "pseudo", + "surname", + "email", + "school", + "is_admin", + "password1", + "password2", + ), + }, ), ) - search_fields = ('pseudo', 'surname') - ordering = ('pseudo',) + search_fields = ("pseudo", "surname") + ordering = ("pseudo",) filter_horizontal = () class ServiceUserAdmin(VersionAdmin, BaseUserAdmin): """Gestion d'un service user admin : champs personnels, mot de passe; etc""" + # The forms to add and change user instances form = ServiceUserChangeForm add_form = ServiceUserCreationForm @@ -186,24 +196,16 @@ class ServiceUserAdmin(VersionAdmin, BaseUserAdmin): # The fields to be used in displaying the User model. # These override the definitions on the base UserAdmin # that reference specific fields on auth.User. - list_display = ('pseudo', 'access_group') + list_display = ("pseudo", "access_group") list_filter = () - fieldsets = ( - (None, {'fields': ('pseudo', 'password', 'access_group')}), - ) + fieldsets = ((None, {"fields": ("pseudo", "password", "access_group")}),) # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin # overrides get_fieldsets to use this attribute when creating a user. add_fieldsets = ( - ( - None, - { - 'classes': ('wide',), - 'fields': ('pseudo', 'password1', 'password2') - } - ), + (None, {"classes": ("wide",), "fields": ("pseudo", "password1", "password2")}), ) - search_fields = ('pseudo',) - ordering = ('pseudo',) + search_fields = ("pseudo",) + ordering = ("pseudo",) filter_horizontal = () diff --git a/users/forms.py b/users/forms.py index 66ab7e74..782e5aa1 100644 --- a/users/forms.py +++ b/users/forms.py @@ -65,7 +65,7 @@ from .models import ( ListShell, Ban, Adherent, - Club + Club, ) @@ -73,22 +73,21 @@ class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm): """Formulaire de changement de mot de passe. Verifie que les 2 nouveaux mots de passe renseignés sont identiques et respectent une norme""" + selfpasswd = forms.CharField( - label=_("Current password"), - max_length=255, - widget=forms.PasswordInput + label=_("Current password"), max_length=255, widget=forms.PasswordInput ) passwd1 = forms.CharField( label=_("New password"), max_length=255, validators=[MinLengthValidator(8)], - widget=forms.PasswordInput + widget=forms.PasswordInput, ) passwd2 = forms.CharField( label=_("New password confirmation"), max_length=255, validators=[MinLengthValidator(8)], - widget=forms.PasswordInput + widget=forms.PasswordInput, ) class Meta: @@ -101,16 +100,12 @@ class PassForm(FormRevMixin, FieldPermissionFormMixin, forms.ModelForm): password1 = self.cleaned_data.get("passwd1") password2 = self.cleaned_data.get("passwd2") if password1 and password2 and password1 != password2: - raise forms.ValidationError( - _("The new passwords don't match.") - ) + raise forms.ValidationError(_("The new passwords don't match.")) return password2 def clean_selfpasswd(self): """Verifie si il y a lieu que le mdp self est correct""" - if not self.instance.check_password( - self.cleaned_data.get("selfpasswd") - ): + if not self.instance.check_password(self.cleaned_data.get("selfpasswd")): raise forms.ValidationError(_("The current password is incorrect.")) return @@ -129,34 +124,38 @@ class UserCreationForm(FormRevMixin, forms.ModelForm): Formulaire pour la création d'un user. N'est utilisé que pour l'admin, lors de la creation d'un user par admin. Inclu tous les champs obligatoires""" + password1 = forms.CharField( label=_("Password"), widget=forms.PasswordInput, validators=[MinLengthValidator(8)], - max_length=255 + max_length=255, ) password2 = forms.CharField( label=_("Password confirmation"), widget=forms.PasswordInput, validators=[MinLengthValidator(8)], - max_length=255 + max_length=255, ) is_admin = forms.BooleanField(label=_("Is admin")) def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(UserCreationForm, self).__init__(*args, prefix=prefix, **kwargs) def clean_email(self): - if not OptionalUser.objects.first().local_email_domain in self.cleaned_data.get('email'): - return self.cleaned_data.get('email').lower() + if not OptionalUser.objects.first().local_email_domain in self.cleaned_data.get( + "email" + ): + return self.cleaned_data.get("email").lower() else: - raise forms.ValidationError(_("You can't use an internal address" - " as your external address.")) + raise forms.ValidationError( + _("You can't use an internal address" " as your external address.") + ) class Meta: model = Adherent - fields = ('pseudo', 'surname', 'email') + fields = ("pseudo", "surname", "email") def clean_password2(self): """Verifie que password1 et 2 sont identiques""" @@ -182,30 +181,24 @@ class ServiceUserCreationForm(FormRevMixin, forms.ModelForm): Formulaire pour la creation de nouveaux serviceusers. Requiert seulement un mot de passe; et un pseudo""" + password1 = forms.CharField( - label=_("Password"), - widget=forms.PasswordInput, - min_length=8, - max_length=255 + label=_("Password"), widget=forms.PasswordInput, min_length=8, max_length=255 ) password2 = forms.CharField( label=_("Password confirmation"), widget=forms.PasswordInput, min_length=8, - max_length=255 + max_length=255, ) def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(ServiceUserCreationForm, self).__init__( - *args, - prefix=prefix, - **kwargs - ) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(ServiceUserCreationForm, self).__init__(*args, prefix=prefix, **kwargs) class Meta: model = ServiceUser - fields = ('pseudo',) + fields = ("pseudo",) def clean_password2(self): """Verifie que password1 et 2 sont indentiques""" @@ -231,18 +224,19 @@ class UserChangeForm(FormRevMixin, forms.ModelForm): Formulaire pour la modification d'un user coté admin """ + password = ReadOnlyPasswordHashField() is_admin = forms.BooleanField(label=_("Is admin"), required=False) class Meta: model = Adherent - fields = ('pseudo', 'password', 'surname', 'email') + fields = ("pseudo", "password", "surname", "email") def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(UserChangeForm, self).__init__(*args, prefix=prefix, **kwargs) - print(_("User is admin: %s") % kwargs['instance'].is_admin) - self.initial['is_admin'] = kwargs['instance'].is_admin + print(_("User is admin: %s") % kwargs["instance"].is_admin) + self.initial["is_admin"] = kwargs["instance"].is_admin def clean_password(self): """Dummy fun""" @@ -267,19 +261,16 @@ class ServiceUserChangeForm(FormRevMixin, forms.ModelForm): Formulaire pour l'edition des service users coté admin """ + password = ReadOnlyPasswordHashField() def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(ServiceUserChangeForm, self).__init__( - *args, - prefix=prefix, - **kwargs - ) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(ServiceUserChangeForm, self).__init__(*args, prefix=prefix, **kwargs) class Meta: model = ServiceUser - fields = ('pseudo',) + fields = ("pseudo",) def clean_password(self): """Dummy fun""" @@ -289,6 +280,7 @@ class ServiceUserChangeForm(FormRevMixin, forms.ModelForm): class ResetPasswordForm(forms.Form): """Formulaire de demande de reinitialisation de mot de passe, mdp oublié""" + pseudo = forms.CharField(label=_("Username"), max_length=255) email = forms.EmailField(max_length=255) @@ -297,11 +289,14 @@ class MassArchiveForm(forms.Form): """Formulaire d'archivage des users inactif. Prend en argument du formulaire la date de depart avant laquelle archiver les users""" - date = forms.DateTimeField(help_text='%d/%m/%y') + + date = forms.DateTimeField(help_text="%d/%m/%y") full_archive = forms.BooleanField( - label=_("Make a full archive operation ? (WARNING : CRITICAL OPERATION IF TRUE)"), + label=_( + "Make a full archive operation ? (WARNING : CRITICAL OPERATION IF TRUE)" + ), initial=False, - required=False + required=False, ) def clean(self): @@ -309,70 +304,75 @@ class MassArchiveForm(forms.Form): date = cleaned_data.get("date") if date: if date > timezone.now(): - raise forms.ValidationError(_("Impossible to archive users" - " whose end access date is in" - " the future.")) + raise forms.ValidationError( + _( + "Impossible to archive users" + " whose end access date is in" + " the future." + ) + ) class AdherentForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Formulaire de base d'edition d'un user. Formulaire de base, utilisé pour l'edition de self par self ou un cableur. On formate les champs avec des label plus jolis""" + def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(AdherentForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['name'].label = _("First name") - self.fields['surname'].label = _("Surname") - self.fields['email'].label = _("Email address") - self.fields['school'].label = _("School") - self.fields['comment'].label = _("Comment") - if 'room' in self.fields: - self.fields['room'].label = _("Room") - self.fields['room'].empty_label = _("No room") - self.fields['school'].empty_label = _("Select a school") + self.fields["name"].label = _("First name") + self.fields["surname"].label = _("Surname") + self.fields["email"].label = _("Email address") + self.fields["school"].label = _("School") + self.fields["comment"].label = _("Comment") + if "room" in self.fields: + self.fields["room"].label = _("Room") + self.fields["room"].empty_label = _("No room") + self.fields["school"].empty_label = _("Select a school") class Meta: model = Adherent fields = [ - 'name', - 'surname', - 'pseudo', - 'email', - 'school', - 'comment', - 'telephone', - 'room', + "name", + "surname", + "pseudo", + "email", + "school", + "comment", + "telephone", + "room", ] force = forms.BooleanField( - label=_("Force the move?"), - initial=False, - required=False + label=_("Force the move?"), initial=False, required=False ) def clean_email(self): - if not OptionalUser.objects.first().local_email_domain in self.cleaned_data.get('email'): - return self.cleaned_data.get('email').lower() + if not OptionalUser.objects.first().local_email_domain in self.cleaned_data.get( + "email" + ): + return self.cleaned_data.get("email").lower() else: raise forms.ValidationError( - _("You can't use a {} address.").format( - OptionalUser.objects.first().local_email_domain)) + _("You can't use a {} address.").format( + OptionalUser.objects.first().local_email_domain + ) + ) def clean_telephone(self): """Verifie que le tel est présent si 'option est validée dans preferences""" - telephone = self.cleaned_data['telephone'] - if not telephone and OptionalUser.get_cached_value('is_tel_mandatory'): - raise forms.ValidationError( - _("A valid telephone number is required.") - ) + telephone = self.cleaned_data["telephone"] + if not telephone and OptionalUser.get_cached_value("is_tel_mandatory"): + raise forms.ValidationError(_("A valid telephone number is required.")) return telephone def clean_force(self): """On supprime l'ancien user de la chambre si et seulement si la case est cochée""" - room = self.cleaned_data.get('room') - if self.cleaned_data.get('force', False) and room: + room = self.cleaned_data.get("room") + if self.cleaned_data.get("force", False) and room: remove_user_room(room) return @@ -383,11 +383,15 @@ class AdherentCreationForm(AdherentForm): doublons d'utilisateurs""" # Champ permettant d'éviter au maxium les doublons d'utilisateurs - former_user_check_info = _("If you already have an account, please use it. "\ - + "If your lost access to it, please consider "\ - + "using the forgotten password button on the "\ - + "login page or contacting support.") - former_user_check = forms.BooleanField(required=True, help_text=former_user_check_info) + former_user_check_info = _( + "If you already have an account, please use it. " + + "If your lost access to it, please consider " + + "using the forgotten password button on the " + + "login page or contacting support." + ) + former_user_check = forms.BooleanField( + required=True, help_text=former_user_check_info + ) former_user_check.label = _("I certify that I have not had an account before") # Checkbox for GTU @@ -396,149 +400,151 @@ class AdherentCreationForm(AdherentForm): class Meta: model = Adherent fields = [ - 'name', - 'surname', - 'pseudo', - 'email', - 'school', - 'comment', - 'telephone', - 'room', - 'state', + "name", + "surname", + "pseudo", + "email", + "school", + "comment", + "telephone", + "room", + "state", ] def __init__(self, *args, **kwargs): super(AdherentCreationForm, self).__init__(*args, **kwargs) - gtu_file = GeneralOption.get_cached_value('GTU') - self.fields['gtu_check'].label = mark_safe( - "%s %s." % ( + gtu_file = GeneralOption.get_cached_value("GTU") + self.fields["gtu_check"].label = mark_safe( + "%s %s." + % ( _("I commit to accept the"), gtu_file.url if gtu_file else "#", - _("General Terms of Use") + _("General Terms of Use"), ) ) - class AdherentEditForm(AdherentForm): """Formulaire d'édition d'un user. AdherentForm incluant la modification des champs gpg et shell""" + def __init__(self, *args, **kwargs): - super(AdherentEditForm, self).__init__(*args, **kwargs) - self.fields['gpg_fingerprint'].widget.attrs['placeholder'] = _("Leave empty if you don't have any GPG key.") - if 'shell' in self.fields: - self.fields['shell'].empty_label = _("Default shell") + super(AdherentEditForm, self).__init__(*args, **kwargs) + self.fields["gpg_fingerprint"].widget.attrs["placeholder"] = _( + "Leave empty if you don't have any GPG key." + ) + if "shell" in self.fields: + self.fields["shell"].empty_label = _("Default shell") class Meta: model = Adherent fields = [ - 'name', - 'surname', - 'pseudo', - 'email', - 'school', - 'comment', - 'telephone', - 'room', - 'shell', - 'gpg_fingerprint', - 'shortcuts_enabled', + "name", + "surname", + "pseudo", + "email", + "school", + "comment", + "telephone", + "room", + "shell", + "gpg_fingerprint", + "shortcuts_enabled", ] + class ClubForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Formulaire de base d'edition d'un user. Formulaire de base, utilisé pour l'edition de self par self ou un cableur. On formate les champs avec des label plus jolis""" + def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(ClubForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['surname'].label = _("Name") - self.fields['school'].label = _("School") - self.fields['comment'].label = _("Comment") - self.fields['email'].label = _("Email address") - if 'room' in self.fields: - self.fields['room'].label = _("Room") - self.fields['room'].empty_label = _("No room") - self.fields['school'].empty_label = _("Select a school") - self.fields['mailing'].label = _("Use a mailing list") + self.fields["surname"].label = _("Name") + self.fields["school"].label = _("School") + self.fields["comment"].label = _("Comment") + self.fields["email"].label = _("Email address") + if "room" in self.fields: + self.fields["room"].label = _("Room") + self.fields["room"].empty_label = _("No room") + self.fields["school"].empty_label = _("Select a school") + self.fields["mailing"].label = _("Use a mailing list") class Meta: model = Club fields = [ - 'surname', - 'pseudo', - 'school', - 'comment', - 'room', - 'email', - 'telephone', - 'email', - 'shell', - 'mailing' + "surname", + "pseudo", + "school", + "comment", + "room", + "email", + "telephone", + "email", + "shell", + "mailing", ] def clean_telephone(self): """Verifie que le tel est présent si 'option est validée dans preferences""" - telephone = self.cleaned_data['telephone'] - if not telephone and OptionalUser.get_cached_value('is_tel_mandatory'): - raise forms.ValidationError( - _("A valid telephone number is required.") - ) + telephone = self.cleaned_data["telephone"] + if not telephone and OptionalUser.get_cached_value("is_tel_mandatory"): + raise forms.ValidationError(_("A valid telephone number is required.")) return telephone class ClubAdminandMembersForm(FormRevMixin, ModelForm): """Permet d'éditer la liste des membres et des administrateurs d'un club""" + class Meta: model = Club - fields = ['administrators', 'members'] + fields = ["administrators", "members"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) - super(ClubAdminandMembersForm, self).__init__( - *args, - prefix=prefix, - **kwargs - ) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) + super(ClubAdminandMembersForm, self).__init__(*args, prefix=prefix, **kwargs) class PasswordForm(FormRevMixin, ModelForm): """ Formulaire de changement brut de mot de passe. Ne pas utiliser sans traitement""" + class Meta: model = User - fields = ['password', 'pwd_ntlm'] + fields = ["password", "pwd_ntlm"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(PasswordForm, self).__init__(*args, prefix=prefix, **kwargs) class ServiceUserForm(FormRevMixin, ModelForm): """Service user creation force initial password set""" + password = forms.CharField( label=_("New password"), max_length=255, validators=[MinLengthValidator(8)], widget=forms.PasswordInput, - required=True + required=True, ) class Meta: model = ServiceUser - fields = ('pseudo', 'access_group','comment') + fields = ("pseudo", "access_group", "comment") def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(ServiceUserForm, self).__init__(*args, prefix=prefix, **kwargs) def save(self, commit=True): """Password change""" user = super(ServiceUserForm, self).save(commit=False) - if self.cleaned_data['password']: + if self.cleaned_data["password"]: user.set_password(self.cleaned_data.get("password")) user.save() @@ -546,209 +552,225 @@ class ServiceUserForm(FormRevMixin, ModelForm): class EditServiceUserForm(ServiceUserForm): """Formulaire d'edition de base d'un service user. Ne permet d'editer que son group d'acl et son commentaire""" + password = forms.CharField( label=_("New password"), max_length=255, validators=[MinLengthValidator(8)], widget=forms.PasswordInput, - required=False + required=False, ) class Meta(ServiceUserForm.Meta): - fields = ['access_group', 'comment'] + fields = ["access_group", "comment"] class StateForm(FormRevMixin, ModelForm): """ Changement de l'état d'un user""" + class Meta: model = User - fields = ['state'] + fields = ["state"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(StateForm, self).__init__(*args, prefix=prefix, **kwargs) def save(self, commit=True): user = super(StateForm, self).save(commit=False) - if self.cleaned_data['state']: - user.state=self.cleaned_data.get('state') + if self.cleaned_data["state"]: + user.state = self.cleaned_data.get("state") user.state_sync() user.save() + class GroupForm(FieldPermissionFormMixin, FormRevMixin, ModelForm): """ Gestion des groupes d'un user""" + groups = forms.ModelMultipleChoiceField( - Group.objects.all(), - widget=forms.CheckboxSelectMultiple, - required=False + Group.objects.all(), widget=forms.CheckboxSelectMultiple, required=False ) class Meta: model = User - fields = ['is_superuser', 'groups'] + fields = ["is_superuser", "groups"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(GroupForm, self).__init__(*args, prefix=prefix, **kwargs) - if 'is_superuser' in self.fields: - self.fields['is_superuser'].label = _("Superuser") + if "is_superuser" in self.fields: + self.fields["is_superuser"].label = _("Superuser") class SchoolForm(FormRevMixin, ModelForm): """Edition, creation d'un école""" + class Meta: model = School - fields = ['name'] + fields = ["name"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(SchoolForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['name'].label = _("School") + self.fields["name"].label = _("School") class ShellForm(FormRevMixin, ModelForm): """Edition, creation d'un école""" + class Meta: model = ListShell - fields = ['shell'] + fields = ["shell"] def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(ShellForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['shell'].label = _("Shell name") + self.fields["shell"].label = _("Shell name") class ListRightForm(FormRevMixin, ModelForm): """Edition, d'un groupe , équivalent à un droit Ne permet pas d'editer le gid, car il sert de primary key""" + permissions = forms.ModelMultipleChoiceField( - Permission.objects.all().select_related('content_type'), + Permission.objects.all().select_related("content_type"), widget=forms.CheckboxSelectMultiple, - required=False + required=False, ) class Meta: model = ListRight - fields = ('name', 'unix_name', 'critical', 'permissions', 'details') + fields = ("name", "unix_name", "critical", "permissions", "details") def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(ListRightForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['unix_name'].label = _("Name of the group of rights") + self.fields["unix_name"].label = _("Name of the group of rights") class NewListRightForm(ListRightForm): """Ajout d'un groupe/list de droit """ + class Meta(ListRightForm.Meta): - fields = ('name', 'unix_name', 'gid', 'critical', 'permissions', - 'details') + fields = ("name", "unix_name", "gid", "critical", "permissions", "details") def __init__(self, *args, **kwargs): super(NewListRightForm, self).__init__(*args, **kwargs) - self.fields['gid'].label = _("GID. Warning: this field must not be" - " edited after creation.") + self.fields["gid"].label = _( + "GID. Warning: this field must not be" " edited after creation." + ) class DelListRightForm(Form): """Suppression d'un ou plusieurs groupes""" + listrights = forms.ModelMultipleChoiceField( queryset=ListRight.objects.none(), label=_("Current groups of rights"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelListRightForm, self).__init__(*args, **kwargs) if instances: - self.fields['listrights'].queryset = instances + self.fields["listrights"].queryset = instances else: - self.fields['listrights'].queryset = ListRight.objects.all() + self.fields["listrights"].queryset = ListRight.objects.all() class DelSchoolForm(Form): """Suppression d'une ou plusieurs écoles""" + schools = forms.ModelMultipleChoiceField( queryset=School.objects.none(), label=_("Current schools"), - widget=forms.CheckboxSelectMultiple + widget=forms.CheckboxSelectMultiple, ) def __init__(self, *args, **kwargs): - instances = kwargs.pop('instances', None) + instances = kwargs.pop("instances", None) super(DelSchoolForm, self).__init__(*args, **kwargs) if instances: - self.fields['schools'].queryset = instances + self.fields["schools"].queryset = instances else: - self.fields['schools'].queryset = School.objects.all() + self.fields["schools"].queryset = School.objects.all() class BanForm(FormRevMixin, ModelForm): """Creation, edition d'un objet bannissement""" + def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(BanForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['date_end'].label = _("End date") - self.fields['date_end'].localize = False + self.fields["date_end"].label = _("End date") + self.fields["date_end"].localize = False class Meta: model = Ban - exclude = ['user'] - widgets = {'date_end':DateTimePicker} + exclude = ["user"] + widgets = {"date_end": DateTimePicker} class WhitelistForm(FormRevMixin, ModelForm): """Creation, edition d'un objet whitelist""" + def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(WhitelistForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['date_end'].label = _("End date") - self.fields['date_end'].localize = False + self.fields["date_end"].label = _("End date") + self.fields["date_end"].localize = False class Meta: model = Whitelist - exclude = ['user'] - widgets = {'date_end':DateTimePicker} + exclude = ["user"] + widgets = {"date_end": DateTimePicker} class EMailAddressForm(FormRevMixin, ModelForm): """Create and edit a local email address""" + def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EMailAddressForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['local_part'].label = _("Local part of the email address") - self.fields['local_part'].help_text = _("Can't contain @") + self.fields["local_part"].label = _("Local part of the email address") + self.fields["local_part"].help_text = _("Can't contain @") def clean_local_part(self): - return self.cleaned_data.get('local_part').lower() + return self.cleaned_data.get("local_part").lower() class Meta: model = EMailAddress - exclude = ['user'] + exclude = ["user"] class EmailSettingsForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): """Edit email-related settings""" + def __init__(self, *args, **kwargs): - prefix = kwargs.pop('prefix', self.Meta.model.__name__) + prefix = kwargs.pop("prefix", self.Meta.model.__name__) super(EmailSettingsForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['email'].label = _("Main email address") - if 'local_email_redirect' in self.fields: - self.fields['local_email_redirect'].label = _("Redirect local emails") - if 'local_email_enabled' in self.fields: - self.fields['local_email_enabled'].label = _("Use local emails") + self.fields["email"].label = _("Main email address") + if "local_email_redirect" in self.fields: + self.fields["local_email_redirect"].label = _("Redirect local emails") + if "local_email_enabled" in self.fields: + self.fields["local_email_enabled"].label = _("Use local emails") def clean_email(self): - if not OptionalUser.objects.first().local_email_domain in self.cleaned_data.get('email'): - return self.cleaned_data.get('email').lower() + if not OptionalUser.objects.first().local_email_domain in self.cleaned_data.get( + "email" + ): + return self.cleaned_data.get("email").lower() else: raise forms.ValidationError( - _("You can't use a {} address.").format( - OptionalUser.objects.first().local_email_domain)) + _("You can't use a {} address.").format( + OptionalUser.objects.first().local_email_domain + ) + ) class Meta: model = User - fields = ['email','local_email_enabled', 'local_email_redirect'] + fields = ["email", "local_email_enabled", "local_email_redirect"] class InitialRegisterForm(forms.Form): @@ -756,16 +778,22 @@ class InitialRegisterForm(forms.Form): register_machine = forms.BooleanField(required=False) def __init__(self, *args, **kwargs): - switch_ip = kwargs.pop('switch_ip') - switch_port = kwargs.pop('switch_port') - client_mac = kwargs.pop('client_mac') - self.user = kwargs.pop('user') + switch_ip = kwargs.pop("switch_ip") + switch_port = kwargs.pop("switch_port") + client_mac = kwargs.pop("client_mac") + self.user = kwargs.pop("user") if switch_ip and switch_port: # Looking for a port - port = Port.objects.filter(switch__interface__ipv4__ipv4=switch_ip, port=switch_port).first() + port = Port.objects.filter( + switch__interface__ipv4__ipv4=switch_ip, port=switch_port + ).first() # If a port exists, checking there is a room AND radius if port: - if port.get_port_profile.radius_type != 'NO' and port.get_port_profile.radius_mode == 'STRICT' and hasattr(port, 'room'): + if ( + port.get_port_profile.radius_type != "NO" + and port.get_port_profile.radius_mode == "STRICT" + and hasattr(port, "room") + ): # Requesting user is not in this room ? if self.user.room != port.room: self.new_room = port.room @@ -773,19 +801,23 @@ class InitialRegisterForm(forms.Form): # If this interface doesn't already exists if not Interface.objects.filter(mac_address=client_mac): self.mac_address = client_mac - self.nas_type = Nas.objects.filter(nas_type__interface__ipv4__ipv4=switch_ip).first() + self.nas_type = Nas.objects.filter( + nas_type__interface__ipv4__ipv4=switch_ip + ).first() super(InitialRegisterForm, self).__init__(*args, **kwargs) - if hasattr(self, 'new_room'): - self.fields['register_room'].label = _("This room is my room") + if hasattr(self, "new_room"): + self.fields["register_room"].label = _("This room is my room") else: - self.fields.pop('register_room') - if hasattr(self, 'mac_address'): - self.fields['register_machine'].label = _("This new connected device is mine") + self.fields.pop("register_room") + if hasattr(self, "mac_address"): + self.fields["register_machine"].label = _( + "This new connected device is mine" + ) else: - self.fields.pop('register_machine') + self.fields.pop("register_machine") def clean_register_room(self): - if self.cleaned_data['register_room']: + if self.cleaned_data["register_room"]: if self.user.is_class_adherent: remove_user_room(self.new_room) user = self.user.adherent @@ -797,6 +829,6 @@ class InitialRegisterForm(forms.Form): user.save() def clean_register_machine(self): - if self.cleaned_data['register_machine']: + if self.cleaned_data["register_machine"]: if self.mac_address and self.nas_type: self.user.autoregister_machine(self.mac_address, self.nas_type) diff --git a/users/management/commands/anonymize.py b/users/management/commands/anonymize.py index a6bce971..7f54de42 100644 --- a/users/management/commands/anonymize.py +++ b/users/management/commands/anonymize.py @@ -11,88 +11,107 @@ from re2o.login import hashNT, makeSecret import os, random, string from random import randint + class Command(BaseCommand): - help="Anonymize the data in the database in order to use them on critical servers (dev, personnal...). Every information will be overwritten using non-personnal informations. This script must follow any modification of the database.\nOptionnal argument: {id|id|id|...} to exclude users from anonymisation" + help = "Anonymize the data in the database in order to use them on critical servers (dev, personnal...). Every information will be overwritten using non-personnal informations. This script must follow any modification of the database.\nOptionnal argument: {id|id|id|...} to exclude users from anonymisation" def add_arguments(self, parser): - parser.add_argument('user_id', nargs='+', type=int, help='User ID') + parser.add_argument("user_id", nargs="+", type=int, help="User ID") def handle(self, *args, **kwargs): - users_ids = kwargs['user_id'] + users_ids = kwargs["user_id"] for user_id in users_ids: - self.stdout.write("User: {} will not be anonymised".format(User.objects.filter(id=user_id).get().name)) - - self.stdout.write(self.style.WARNING('\nDISCLAIMER\nThis function will make your database unusable for production. Are you sure you want to run this ?(doit): ')) - if(input()=="doit"): + self.stdout.write( + "User: {} will not be anonymised".format( + User.objects.filter(id=user_id).get().name + ) + ) + + self.stdout.write( + self.style.WARNING( + "\nDISCLAIMER\nThis function will make your database unusable for production. Are you sure you want to run this ?(doit): " + ) + ) + if input() == "doit": total = Adherent.objects.count() self.stdout.write("Starting anonymizing the {} users data.".format(total)) - + u = User.objects.filter(~Q(id__in=users_ids)) a = Adherent.objects.filter(~Q(id__in=users_ids)) c = Club.objects.filter(~Q(id__in=users_ids)) d = Domain.objects.all() m = Machine.objects.filter(~Q(user_id__in=users_ids)) - self.stdout.write('Supression de l\'école...') + self.stdout.write("Supression de l'école...") # Create a fake School to put everyone in it. ecole = School(name="Ecole des Ninja") ecole.save() u.update(school=ecole) - self.stdout.write(self.style.SUCCESS('done ...')) + self.stdout.write(self.style.SUCCESS("done ...")) - self.stdout.write('Supression des chambres...') + self.stdout.write("Supression des chambres...") a.update(room=None) c.update(room=None) - self.stdout.write(self.style.SUCCESS('done ...')) + self.stdout.write(self.style.SUCCESS("done ...")) - self.stdout.write('Supression des mails...') - u.update(email='example@example.org', - local_email_redirect = False, - local_email_enabled=False) - self.stdout.write(self.style.SUCCESS('done ...')) + self.stdout.write("Supression des mails...") + u.update( + email="example@example.org", + local_email_redirect=False, + local_email_enabled=False, + ) + self.stdout.write(self.style.SUCCESS("done ...")) - self.stdout.write('Supression des noms, prenoms, pseudo, telephone, commentaire...') - a.update(name=Concat(Value('name of '), 'id')) - self.stdout.write(self.style.SUCCESS('done name')) + self.stdout.write( + "Supression des noms, prenoms, pseudo, telephone, commentaire..." + ) + a.update(name=Concat(Value("name of "), "id")) + self.stdout.write(self.style.SUCCESS("done name")) - a.update(surname=Concat(Value('surname of '), 'id')) - self.stdout.write(self.style.SUCCESS('done surname')) + a.update(surname=Concat(Value("surname of "), "id")) + self.stdout.write(self.style.SUCCESS("done surname")) - u.update(pseudo=F('id')) - self.stdout.write(self.style.SUCCESS('done pseudo')) + u.update(pseudo=F("id")) + self.stdout.write(self.style.SUCCESS("done pseudo")) - a.update(telephone=Concat(Value('phone of '), 'id')) - self.stdout.write(self.style.SUCCESS('done phone')) + a.update(telephone=Concat(Value("phone of "), "id")) + self.stdout.write(self.style.SUCCESS("done phone")) - a.update(comment=Concat(Value('commentaire of '), 'id')) - self.stdout.write(self.style.SUCCESS('done ...')) - - self.stdout.write('Renommage des machines...') - m.update(name=Concat(Value('Machine '),F('id'),Value(' of '),F('user_id'))) - d.update(name=Concat(Value('Domaine id '),F('id'))) - self.stdout.write(self.style.SUCCESS('done ...')) + a.update(comment=Concat(Value("commentaire of "), "id")) + self.stdout.write(self.style.SUCCESS("done ...")) - self.stdout.write('Unification du mot de passe...') + self.stdout.write("Renommage des machines...") + m.update( + name=Concat(Value("Machine "), F("id"), Value(" of "), F("user_id")) + ) + d.update(name=Concat(Value("Domaine id "), F("id"))) + self.stdout.write(self.style.SUCCESS("done ...")) + + self.stdout.write("Unification du mot de passe...") # Define the password - chars = string.ascii_letters + string.digits + '!@#$%^&*()' + chars = string.ascii_letters + string.digits + "!@#$%^&*()" taille = 20 - random.seed = (os.urandom(1024)) + random.seed = os.urandom(1024) password = "" for i in range(taille): - password+=random.choice(chars) + password += random.choice(chars) - self.stdout.write(self.style.HTTP_NOT_MODIFIED('The password will be: {}'.format(password))) + self.stdout.write( + self.style.HTTP_NOT_MODIFIED( + "The password will be: {}".format(password) + ) + ) - u.update(pwd_ntlm = hashNT(password)) - u.update(password = makeSecret(password)) - self.stdout.write(self.style.SUCCESS('done...')) + u.update(pwd_ntlm=hashNT(password)) + u.update(password=makeSecret(password)) + self.stdout.write(self.style.SUCCESS("done...")) - self.stdout.write('Suppression de l\'historique (This may take some time)') + self.stdout.write("Suppression de l'historique (This may take some time)") Revision.objects.all().delete() - self.stdout.write(self.style.SUCCESS('done...')) + self.stdout.write(self.style.SUCCESS("done...")) self.stdout.write("Data anonymized!") else: - self.stdout.write("Anonymisation aborted") + self.stdout.write("Anonymisation aborted") diff --git a/users/management/commands/archive.py b/users/management/commands/archive.py index c2ff7801..8d054eae 100644 --- a/users/management/commands/archive.py +++ b/users/management/commands/archive.py @@ -28,6 +28,7 @@ from django.utils.timezone import make_aware from re2o.utils import all_has_access from users.models import User + def valid_date(s): try: return make_aware(datetime.datetime.strptime(s, "%d/%m/%Y")) @@ -35,33 +36,34 @@ def valid_date(s): msg = "Not a valid date: '{0}'.".format(s) raise argparse.ArgumentTypeError(msg) + class Command(BaseCommand): help = "Allow unactive users archiving by unassigning their IP addresses." def add_arguments(self, parser): parser.add_argument( - '--full', - '-f', - action='store_true', - help="Full archive users, i.e. delete their email address, machines and remove them from the LDAP." + "--full", + "-f", + action="store_true", + help="Full archive users, i.e. delete their email address, machines and remove them from the LDAP.", ) parser.add_argument( - '--date', - '-d', - default=datetime.date.today().strftime('%d/%m/%Y'), + "--date", + "-d", + default=datetime.date.today().strftime("%d/%m/%Y"), type=valid_date, help="Users which membership ends sooner than this date will be archived.", ) parser.add_argument( - '--show', - '-s', - action='store_true', - help="Only show a list of users, without doing anything." + "--show", + "-s", + action="store_true", + help="Only show a list of users, without doing anything.", ) parser.add_argument( - '-y', - action='store_true', - help='Do not ask for confirmation befor full archiving.' + "-y", + action="store_true", + help="Do not ask for confirmation befor full archiving.", ) def handle(self, *args, **kwargs): @@ -70,30 +72,40 @@ class Command(BaseCommand): force = kwargs["y"] show = kwargs["show"] - to_archive_list = User.objects.exclude(id__in=all_has_access()).exclude(id__in=all_has_access(search_time=date)).exclude(state=User.STATE_NOT_YET_ACTIVE).exclude(state=User.STATE_FULL_ARCHIVE) + to_archive_list = ( + User.objects.exclude(id__in=all_has_access()) + .exclude(id__in=all_has_access(search_time=date)) + .exclude(state=User.STATE_NOT_YET_ACTIVE) + .exclude(state=User.STATE_FULL_ARCHIVE) + ) if show: - self.stdout.write( - "%s users found : " % to_archive_list.count() - ) - self.stdout.write('\n'.join(map(str, to_archive_list.all()))) + self.stdout.write("%s users found : " % to_archive_list.count()) + self.stdout.write("\n".join(map(str, to_archive_list.all()))) return if full_archive and not force: self.stdout.write( self.style.WARNING( - "Please confirm full archiving (it is a critical operation !) [Y/n]" + "Please confirm full archiving (it is a critical operation !) [Y/n]" ) ) - if input() != 'Y': + if input() != "Y": self.stdout.write("Leaving without archiving.") return if full_archive: - self.stdout.write("Full archiving users with a membership ending prior to %s" % date.strftime("%d/%m/%Y")) + self.stdout.write( + "Full archiving users with a membership ending prior to %s" + % date.strftime("%d/%m/%Y") + ) User.mass_full_archive(to_archive_list) else: - self.stdout.write("Archiving users with a membership ending prior to %s" % date.strftime("%d/%m/%Y")) + self.stdout.write( + "Archiving users with a membership ending prior to %s" + % date.strftime("%d/%m/%Y") + ) to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE) User.mass_archive(to_archive_list) - self.stdout.write(self.style.SUCCESS("%s users were archived." % to_archive_list.count())) - + self.stdout.write( + self.style.SUCCESS("%s users were archived." % to_archive_list.count()) + ) diff --git a/users/management/commands/chgpass.py b/users/management/commands/chgpass.py index 9763ae4c..a88eeecb 100644 --- a/users/management/commands/chgpass.py +++ b/users/management/commands/chgpass.py @@ -31,7 +31,7 @@ class Command(BaseCommand): help = "Changer le mot de passe d'un utilisateur" def add_arguments(self, parser): - parser.add_argument('target_username', nargs='?') + parser.add_argument("target_username", nargs="?") def handle(self, *args, **kwargs): @@ -44,13 +44,8 @@ class Command(BaseCommand): if not ok: raise CommandError(msg) - self.stdout.write( - "Changement du mot de passe de %s" % target_user.pseudo - ) + self.stdout.write("Changement du mot de passe de %s" % target_user.pseudo) form_cli( - PassForm, - current_user, - "Changement du mot de passe", - instance=target_user + PassForm, current_user, "Changement du mot de passe", instance=target_user ) diff --git a/users/management/commands/chsh.py b/users/management/commands/chsh.py index 6921ad79..574bd0f1 100644 --- a/users/management/commands/chsh.py +++ b/users/management/commands/chsh.py @@ -32,10 +32,10 @@ from re2o.script_utils import get_user, get_system_user class Command(BaseCommand): - help = 'Change the default shell of a user' + help = "Change the default shell of a user" def add_arguments(self, parser): - parser.add_argument('target_username', nargs='?') + parser.add_argument("target_username", nargs="?") def handle(self, *args, **options): @@ -60,11 +60,9 @@ class Command(BaseCommand): "%s) :" % (target_user.pseudo, current_shell) ) for shell in shells: - self.stdout.write("%d - %s (%s)" % ( - shell.id, - shell.get_pretty_name(), - shell.shell - )) + self.stdout.write( + "%d - %s (%s)" % (shell.id, shell.get_pretty_name(), shell.shell) + ) shell_id = input("Entrez un nombre : ") try: @@ -82,7 +80,9 @@ class Command(BaseCommand): reversion.set_user(current_user) reversion.set_comment("Shell modifié") - self.stdout.write(self.style.SUCCESS( - "Shell modifié. La modification peut prendre quelques minutes " - "pour s'appliquer." - )) + self.stdout.write( + self.style.SUCCESS( + "Shell modifié. La modification peut prendre quelques minutes " + "pour s'appliquer." + ) + ) diff --git a/users/management/commands/clean_notyetactive.py b/users/management/commands/clean_notyetactive.py index 247fc668..b6056230 100644 --- a/users/management/commands/clean_notyetactive.py +++ b/users/management/commands/clean_notyetactive.py @@ -25,13 +25,19 @@ from datetime import timedelta from django.utils import timezone + class Command(BaseCommand): help = "Delete non members users (not yet active)" def handle(self, *args, **options): """First deleting invalid invoices, and then deleting the users""" - days = OptionalUser.get_cached_value('delete_notyetactive') - users_to_delete = User.objects.filter(state=User.STATE_NOT_YET_ACTIVE).filter(registered__lte=timezone.now() - timedelta(days=days)).exclude(facture__valid=True).distinct() + days = OptionalUser.get_cached_value("delete_notyetactive") + users_to_delete = ( + User.objects.filter(state=User.STATE_NOT_YET_ACTIVE) + .filter(registered__lte=timezone.now() - timedelta(days=days)) + .exclude(facture__valid=True) + .distinct() + ) print("Deleting " + str(users_to_delete.count()) + " users") Facture.objects.filter(user__in=users_to_delete).delete() users_to_delete.delete() diff --git a/users/management/commands/derniere_connexion.py b/users/management/commands/derniere_connexion.py index d936fda8..9d52ecf0 100644 --- a/users/management/commands/derniere_connexion.py +++ b/users/management/commands/derniere_connexion.py @@ -33,28 +33,35 @@ from users.models import User # Elles doivent contenir un groupe 'date' et un groupe 'user'. # Pour le CAS on prend comme entrée # cat ~/cas.log | grep -B 2 -A 2 "ACTION: AUTHENTICATION_SUCCESS"| grep 'WHEN\|WHO'|sed 'N;s/\n/ /' -COMPILED_REGEX = map(re.compile, [ - r'^(?P\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}).*(?:'r'dovecot.*Login: user=<|'r'sshd.*Accepted.*for 'r')(?P[^ >]+).*$', - r'^(?P.*) LOGIN INFO User logged in : (?P.*)', - r'WHO: \[username: (?P.*)\] WHEN: (?P.* CET .*)', - r'WHO: \[username: (?P.*)\] WHEN: (?P.* CEST .*)' -]) +COMPILED_REGEX = map( + re.compile, + [ + r"^(?P\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}).*(?:" + r"dovecot.*Login: user=<|" + r"sshd.*Accepted.*for " + r")(?P[^ >]+).*$", + r"^(?P.*) LOGIN INFO User logged in : (?P.*)", + r"WHO: \[username: (?P.*)\] WHEN: (?P.* CET .*)", + r"WHO: \[username: (?P.*)\] WHEN: (?P.* CEST .*)", + ], +) # Les formats de date en strftime associés aux expressions ci-dessus. DATE_FORMATS = [ "%Y-%m-%dT%H:%M:%S", "%d/%b/%Y:%H:%M:%S", "%a %b %d CET %H:%M:%S%Y", - "%a %b %d CEST %H:%M:%S%Y" + "%a %b %d CEST %H:%M:%S%Y", ] class Command(BaseCommand): - help = ('Update the time of the latest connection for users by matching ' - 'stdin against a set of regular expressions') + help = ( + "Update the time of the latest connection for users by matching " + "stdin against a set of regular expressions" + ) def handle(self, *args, **options): - def parse_logs(logfile): """ Parse les logs sur l'entrée standard et rempli un dictionnaire @@ -67,8 +74,8 @@ class Command(BaseCommand): for i, regex in enumerate(COMPILED_REGEX): m = regex.match(line) if m: - parsed_log[m.group('user')] = make_aware( - datetime.strptime(m.group('date'), DATE_FORMATS[i]) + parsed_log[m.group("user")] = make_aware( + datetime.strptime(m.group("date"), DATE_FORMATS[i]) ) return parsed_log diff --git a/users/management/commands/ldap_rebuild.py b/users/management/commands/ldap_rebuild.py index 9deecbd3..82bb0f0e 100644 --- a/users/management/commands/ldap_rebuild.py +++ b/users/management/commands/ldap_rebuild.py @@ -29,9 +29,9 @@ def split_lines(lines): following system lines begins with a space. """ ret = [] - for line in lines.split(b'\n'): - if line.startswith(b' ') and len(ret) > 1: - ret[-1] += line[len(b' '):] + for line in lines.split(b"\n"): + if line.startswith(b" ") and len(ret) > 1: + ret[-1] += line[len(b" ") :] else: ret.append(line) return ret @@ -61,28 +61,28 @@ def flush_ldap(binddn, bindpass, server, usersdn, groupsdn): for lookup in (usersdn, groupsdn): search_cmd = [ - 'ldapsearch', - '-LLL', - '-s', 'one', - '-D', binddn, - '-w', bindpass, - '-H', server, - '-b', lookup, - 'dn' + "ldapsearch", + "-LLL", + "-s", + "one", + "-D", + binddn, + "-w", + bindpass, + "-H", + server, + "-b", + lookup, + "dn", ] for line in split_lines(subprocess.check_output(search_cmd)): - if line.startswith(b'dn: '): - to_remove.append(line[len(b'dn: '):]) - elif line.startswith(b'dn:: '): + if line.startswith(b"dn: "): + to_remove.append(line[len(b"dn: ") :]) + elif line.startswith(b"dn:: "): # Non ASCII value ares are base64-encoded - to_remove.append(decodebytes(line[len(b'dn:: '):])) + to_remove.append(decodebytes(line[len(b"dn:: ") :])) - delete_cmd = [ - 'ldapdelete', - '-D', binddn, - '-w', bindpass, - '-H', server - ] + to_remove + delete_cmd = ["ldapdelete", "-D", binddn, "-w", bindpass, "-H", server] + to_remove subprocess.check_call(delete_cmd) @@ -95,16 +95,18 @@ def sync_ldap(): class Command(BaseCommand): - help = ('Destroy the current LDAP data and rebuild it from the DB data. ' - 'Use with caution.') + help = ( + "Destroy the current LDAP data and rebuild it from the DB data. " + "Use with caution." + ) def handle(self, *args, **options): - usersdn = settings.LDAP['base_user_dn'] - groupsdn = settings.LDAP['base_usergroup_dn'] - binddn = settings.DATABASES['ldap']['USER'] - bindpass = settings.DATABASES['ldap']['PASSWORD'] - server = settings.DATABASES['ldap']['NAME'] + usersdn = settings.LDAP["base_user_dn"] + groupsdn = settings.LDAP["base_usergroup_dn"] + binddn = settings.DATABASES["ldap"]["USER"] + bindpass = settings.DATABASES["ldap"]["PASSWORD"] + server = settings.DATABASES["ldap"]["NAME"] flush_ldap(binddn, bindpass, server, usersdn, groupsdn) self.stdout.write("LDAP emptied") diff --git a/users/management/commands/ldap_sync.py b/users/management/commands/ldap_sync.py index d6ac8469..5495fa30 100644 --- a/users/management/commands/ldap_sync.py +++ b/users/management/commands/ldap_sync.py @@ -22,19 +22,19 @@ from users.models import User class Command(BaseCommand): - help = 'Synchronise le ldap à partir du sql. A utiliser dans un cron' + help = "Synchronise le ldap à partir du sql. A utiliser dans un cron" def add_arguments(self, parser): # Named (optional) arguments parser.add_argument( - '--full', - action='store_true', - dest='full', + "--full", + action="store_true", + dest="full", default=False, - help='Régénération complète du ldap (y compris des machines)', + help="Régénération complète du ldap (y compris des machines)", ) def handle(self, *args, **options): for usr in User.objects.all(): - usr.ldap_sync(mac_refresh=options['full']) + usr.ldap_sync(mac_refresh=options["full"]) diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py index 8fd3d2ff..b10f2bd3 100644 --- a/users/migrations/0001_initial.py +++ b/users/migrations/0001_initial.py @@ -29,30 +29,61 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='School', + name="School", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('name', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ("name", models.CharField(max_length=255)), ], ), migrations.CreateModel( - name='User', + name="User", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)), - ('name', models.CharField(max_length=255)), - ('surname', models.CharField(max_length=255)), - ('pseudo', models.CharField(max_length=255)), - ('email', models.EmailField(max_length=254)), - ('promo', models.CharField(max_length=255)), - ('pwd_ssha', models.CharField(max_length=255)), - ('pwd_ntlm', models.CharField(max_length=255)), - ('state', models.CharField(default=0, max_length=30, choices=[(0, 'STATE_ACTIVE'), (1, 'STATE_DEACTIVATED'), (2, 'STATE_ARCHIVED')])), - ('school', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='users.School')), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + verbose_name="ID", + auto_created=True, + ), + ), + ("name", models.CharField(max_length=255)), + ("surname", models.CharField(max_length=255)), + ("pseudo", models.CharField(max_length=255)), + ("email", models.EmailField(max_length=254)), + ("promo", models.CharField(max_length=255)), + ("pwd_ssha", models.CharField(max_length=255)), + ("pwd_ntlm", models.CharField(max_length=255)), + ( + "state", + models.CharField( + default=0, + max_length=30, + choices=[ + (0, "STATE_ACTIVE"), + (1, "STATE_DEACTIVATED"), + (2, "STATE_ARCHIVED"), + ], + ), + ), + ( + "school", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="users.School" + ), + ), ], ), ] diff --git a/users/migrations/0002_auto_20160630_2301.py b/users/migrations/0002_auto_20160630_2301.py index a5964850..7994825e 100644 --- a/users/migrations/0002_auto_20160630_2301.py +++ b/users/migrations/0002_auto_20160630_2301.py @@ -28,19 +28,24 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0001_initial'), - ] + dependencies = [("users", "0001_initial")] operations = [ migrations.AlterField( - model_name='user', - name='pseudo', + model_name="user", + name="pseudo", field=models.CharField(unique=True, max_length=255), ), migrations.AlterField( - model_name='user', - name='state', - field=models.IntegerField(default=0, choices=[(0, 'STATE_ACTIVE'), (1, 'STATE_DEACTIVATED'), (2, 'STATE_ARCHIVED')]), + model_name="user", + name="state", + field=models.IntegerField( + default=0, + choices=[ + (0, "STATE_ACTIVE"), + (1, "STATE_DEACTIVATED"), + (2, "STATE_ARCHIVED"), + ], + ), ), ] diff --git a/users/migrations/0003_listrights_rights.py b/users/migrations/0003_listrights_rights.py index cc74369f..a67a0f4d 100644 --- a/users/migrations/0003_listrights_rights.py +++ b/users/migrations/0003_listrights_rights.py @@ -29,24 +29,49 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0002_auto_20160630_2301'), - ] + dependencies = [("users", "0002_auto_20160630_2301")] operations = [ migrations.CreateModel( - name='ListRights', + name="ListRights", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), - ('listright', models.CharField(max_length=255)), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + auto_created=True, + verbose_name="ID", + ), + ), + ("listright", models.CharField(max_length=255)), ], ), migrations.CreateModel( - name='Rights', + name="Rights", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), - ('right', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='users.ListRights')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='users.User')), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + auto_created=True, + verbose_name="ID", + ), + ), + ( + "right", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="users.ListRights", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="users.User" + ), + ), ], ), ] diff --git a/users/migrations/0004_auto_20160701_2312.py b/users/migrations/0004_auto_20160701_2312.py index c9739719..e925c6df 100644 --- a/users/migrations/0004_auto_20160701_2312.py +++ b/users/migrations/0004_auto_20160701_2312.py @@ -28,17 +28,9 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0003_listrights_rights'), - ] + dependencies = [("users", "0003_listrights_rights")] operations = [ - migrations.RenameModel( - old_name='ListRights', - new_name='ListRight', - ), - migrations.RenameModel( - old_name='Rights', - new_name='Right', - ), + migrations.RenameModel(old_name="ListRights", new_name="ListRight"), + migrations.RenameModel(old_name="Rights", new_name="Right"), ] diff --git a/users/migrations/0005_auto_20160702_0006.py b/users/migrations/0005_auto_20160702_0006.py index 8962cf41..e45cc6cf 100644 --- a/users/migrations/0005_auto_20160702_0006.py +++ b/users/migrations/0005_auto_20160702_0006.py @@ -28,13 +28,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0004_auto_20160701_2312'), - ] + dependencies = [("users", "0004_auto_20160701_2312")] operations = [ migrations.AlterUniqueTogether( - name='right', - unique_together=set([('user', 'right')]), - ), + name="right", unique_together=set([("user", "right")]) + ) ] diff --git a/users/migrations/0006_ban.py b/users/migrations/0006_ban.py index 69e04e5a..d47c33c0 100644 --- a/users/migrations/0006_ban.py +++ b/users/migrations/0006_ban.py @@ -29,19 +29,30 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0005_auto_20160702_0006'), - ] + dependencies = [("users", "0005_auto_20160702_0006")] operations = [ migrations.CreateModel( - name='Ban', + name="Ban", fields=[ - ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)), - ('raison', models.CharField(max_length=255)), - ('date_start', models.DateTimeField(help_text='%m/%d/%y %H:%M:%S')), - ('date_end', models.DateTimeField(help_text='%m/%d/%y %H:%M:%S')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='users.User')), + ( + "id", + models.AutoField( + serialize=False, + auto_created=True, + verbose_name="ID", + primary_key=True, + ), + ), + ("raison", models.CharField(max_length=255)), + ("date_start", models.DateTimeField(help_text="%m/%d/%y %H:%M:%S")), + ("date_end", models.DateTimeField(help_text="%m/%d/%y %H:%M:%S")), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="users.User" + ), + ), ], - ), + ) ] diff --git a/users/migrations/0007_auto_20160702_2322.py b/users/migrations/0007_auto_20160702_2322.py index ab288eca..45e1901e 100644 --- a/users/migrations/0007_auto_20160702_2322.py +++ b/users/migrations/0007_auto_20160702_2322.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0006_ban'), - ] + dependencies = [("users", "0006_ban")] operations = [ migrations.AlterField( - model_name='ban', - name='date_start', + model_name="ban", + name="date_start", field=models.DateTimeField(auto_now_add=True), - ), + ) ] diff --git a/users/migrations/0008_user_registered.py b/users/migrations/0008_user_registered.py index ab992540..36bd4b6b 100644 --- a/users/migrations/0008_user_registered.py +++ b/users/migrations/0008_user_registered.py @@ -30,15 +30,16 @@ import datetime class Migration(migrations.Migration): - dependencies = [ - ('users', '0007_auto_20160702_2322'), - ] + dependencies = [("users", "0007_auto_20160702_2322")] operations = [ migrations.AddField( - model_name='user', - name='registered', - field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2016, 7, 2, 23, 25, 21, 698883, tzinfo=utc)), + model_name="user", + name="registered", + field=models.DateTimeField( + auto_now_add=True, + default=datetime.datetime(2016, 7, 2, 23, 25, 21, 698883, tzinfo=utc), + ), preserve_default=False, - ), + ) ] diff --git a/users/migrations/0009_user_room.py b/users/migrations/0009_user_room.py index ac3e6094..e03c3119 100644 --- a/users/migrations/0009_user_room.py +++ b/users/migrations/0009_user_room.py @@ -30,15 +30,19 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('topologie', '0009_auto_20160703_1200'), - ('users', '0008_user_registered'), + ("topologie", "0009_auto_20160703_1200"), + ("users", "0008_user_registered"), ] operations = [ migrations.AddField( - model_name='user', - name='room', - field=models.ForeignKey(to='topologie.Room', on_delete=django.db.models.deletion.PROTECT, default=1), + model_name="user", + name="room", + field=models.ForeignKey( + to="topologie.Room", + on_delete=django.db.models.deletion.PROTECT, + default=1, + ), preserve_default=False, - ), + ) ] diff --git a/users/migrations/0010_auto_20160703_1226.py b/users/migrations/0010_auto_20160703_1226.py index db5b8758..80b0153a 100644 --- a/users/migrations/0010_auto_20160703_1226.py +++ b/users/migrations/0010_auto_20160703_1226.py @@ -29,14 +29,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0009_user_room'), - ] + dependencies = [("users", "0009_user_room")] operations = [ migrations.AlterField( - model_name='user', - name='room', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, blank=True, to='topologie.Room', null=True), - ), + model_name="user", + name="room", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + blank=True, + to="topologie.Room", + null=True, + ), + ) ] diff --git a/users/migrations/0011_auto_20160703_1227.py b/users/migrations/0011_auto_20160703_1227.py index d9f2e120..a064dfe7 100644 --- a/users/migrations/0011_auto_20160703_1227.py +++ b/users/migrations/0011_auto_20160703_1227.py @@ -29,14 +29,18 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0010_auto_20160703_1226'), - ] + dependencies = [("users", "0010_auto_20160703_1226")] operations = [ migrations.AlterField( - model_name='user', - name='room', - field=models.ForeignKey(null=True, blank=True, unique=True, on_delete=django.db.models.deletion.PROTECT, to='topologie.Room'), - ), + model_name="user", + name="room", + field=models.ForeignKey( + null=True, + blank=True, + unique=True, + on_delete=django.db.models.deletion.PROTECT, + to="topologie.Room", + ), + ) ] diff --git a/users/migrations/0012_auto_20160703_1230.py b/users/migrations/0012_auto_20160703_1230.py index 8e82895e..9a9cdcf6 100644 --- a/users/migrations/0012_auto_20160703_1230.py +++ b/users/migrations/0012_auto_20160703_1230.py @@ -29,14 +29,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0011_auto_20160703_1227'), - ] + dependencies = [("users", "0011_auto_20160703_1227")] operations = [ migrations.AlterField( - model_name='user', - name='room', - field=models.OneToOneField(blank=True, on_delete=django.db.models.deletion.PROTECT, to='topologie.Room', null=True), - ), + model_name="user", + name="room", + field=models.OneToOneField( + blank=True, + on_delete=django.db.models.deletion.PROTECT, + to="topologie.Room", + null=True, + ), + ) ] diff --git a/users/migrations/0013_auto_20160704_1547.py b/users/migrations/0013_auto_20160704_1547.py index b765cb09..adfbf928 100644 --- a/users/migrations/0013_auto_20160704_1547.py +++ b/users/migrations/0013_auto_20160704_1547.py @@ -28,19 +28,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0012_auto_20160703_1230'), - ] + dependencies = [("users", "0012_auto_20160703_1230")] operations = [ migrations.AddField( - model_name='user', - name='comment', - field=models.CharField(max_length=255, help_text="Infos sur l'etablissement (optionnel)", blank=True), + model_name="user", + name="comment", + field=models.CharField( + max_length=255, + help_text="Infos sur l'etablissement (optionnel)", + blank=True, + ), ), migrations.AlterField( - model_name='user', - name='promo', + model_name="user", + name="promo", field=models.CharField(max_length=255, blank=True), ), ] diff --git a/users/migrations/0014_auto_20160704_1548.py b/users/migrations/0014_auto_20160704_1548.py index a825a9b2..72dd09ef 100644 --- a/users/migrations/0014_auto_20160704_1548.py +++ b/users/migrations/0014_auto_20160704_1548.py @@ -28,18 +28,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0013_auto_20160704_1547'), - ] + dependencies = [("users", "0013_auto_20160704_1547")] operations = [ - migrations.RemoveField( - model_name='user', - name='promo', - ), + migrations.RemoveField(model_name="user", name="promo"), migrations.AlterField( - model_name='user', - name='comment', - field=models.CharField(blank=True, help_text='Commentaire, promo', max_length=255), + model_name="user", + name="comment", + field=models.CharField( + blank=True, help_text="Commentaire, promo", max_length=255 + ), ), ] diff --git a/users/migrations/0015_whitelist.py b/users/migrations/0015_whitelist.py index 6762ab21..6d582050 100644 --- a/users/migrations/0015_whitelist.py +++ b/users/migrations/0015_whitelist.py @@ -29,19 +29,30 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0014_auto_20160704_1548'), - ] + dependencies = [("users", "0014_auto_20160704_1548")] operations = [ migrations.CreateModel( - name='Whitelist', + name="Whitelist", fields=[ - ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)), - ('raison', models.CharField(max_length=255)), - ('date_start', models.DateTimeField(auto_now_add=True)), - ('date_end', models.DateTimeField(help_text='%m/%d/%y %H:%M:%S')), - ('user', models.ForeignKey(to='users.User', on_delete=django.db.models.deletion.PROTECT)), + ( + "id", + models.AutoField( + serialize=False, + verbose_name="ID", + auto_created=True, + primary_key=True, + ), + ), + ("raison", models.CharField(max_length=255)), + ("date_start", models.DateTimeField(auto_now_add=True)), + ("date_end", models.DateTimeField(help_text="%m/%d/%y %H:%M:%S")), + ( + "user", + models.ForeignKey( + to="users.User", on_delete=django.db.models.deletion.PROTECT + ), + ), ], - ), + ) ] diff --git a/users/migrations/0016_auto_20160706_1220.py b/users/migrations/0016_auto_20160706_1220.py index d9e7092c..c3596986 100644 --- a/users/migrations/0016_auto_20160706_1220.py +++ b/users/migrations/0016_auto_20160706_1220.py @@ -29,24 +29,27 @@ import users.models class Migration(migrations.Migration): - dependencies = [ - ('users', '0015_whitelist'), - ] + dependencies = [("users", "0015_whitelist")] operations = [ migrations.AlterField( - model_name='ban', - name='date_end', - field=models.DateTimeField(help_text='%d/%m/%y %H:%M:%S'), + model_name="ban", + name="date_end", + field=models.DateTimeField(help_text="%d/%m/%y %H:%M:%S"), ), migrations.AlterField( - model_name='user', - name='pseudo', - field=models.CharField(unique=True, validators=[users.models.linux_user_validator], max_length=32, help_text='Doit contenir uniquement des lettres, chiffres, ou tirets'), + model_name="user", + name="pseudo", + field=models.CharField( + unique=True, + validators=[users.models.linux_user_validator], + max_length=32, + help_text="Doit contenir uniquement des lettres, chiffres, ou tirets", + ), ), migrations.AlterField( - model_name='whitelist', - name='date_end', - field=models.DateTimeField(help_text='%d/%m/%y %H:%M:%S'), + model_name="whitelist", + name="date_end", + field=models.DateTimeField(help_text="%d/%m/%y %H:%M:%S"), ), ] diff --git a/users/migrations/0017_auto_20160707_0105.py b/users/migrations/0017_auto_20160707_0105.py index 45fa4826..2ce1d48e 100644 --- a/users/migrations/0017_auto_20160707_0105.py +++ b/users/migrations/0017_auto_20160707_0105.py @@ -27,7 +27,7 @@ from django.db import models, migrations def move_passwords(apps, schema_editor): - User = apps.get_model('users', 'User') + User = apps.get_model("users", "User") for row in User.objects.all(): row.password = row.pwd_ssha row.save() @@ -35,23 +35,23 @@ def move_passwords(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('users', '0016_auto_20160706_1220'), - ] + dependencies = [("users", "0016_auto_20160706_1220")] operations = [ migrations.AddField( - model_name='user', - name='last_login', - field=models.DateTimeField(null=True, blank=True, verbose_name='last login'), + model_name="user", + name="last_login", + field=models.DateTimeField( + null=True, blank=True, verbose_name="last login" + ), ), migrations.AddField( - model_name='user', - name='password', - field=models.CharField(verbose_name='password', default='!', max_length=128), + model_name="user", + name="password", + field=models.CharField( + verbose_name="password", default="!", max_length=128 + ), preserve_default=False, ), - migrations.RunPython( - move_passwords, - reverse_code=migrations.RunPython.noop), + migrations.RunPython(move_passwords, reverse_code=migrations.RunPython.noop), ] diff --git a/users/migrations/0018_auto_20160707_0115.py b/users/migrations/0018_auto_20160707_0115.py index 4bccb938..39e72a2c 100644 --- a/users/migrations/0018_auto_20160707_0115.py +++ b/users/migrations/0018_auto_20160707_0115.py @@ -28,13 +28,6 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ('users', '0017_auto_20160707_0105'), - ] + dependencies = [("users", "0017_auto_20160707_0105")] - operations = [ - migrations.RemoveField( - model_name='user', - name='pwd_ssha', - ), - ] + operations = [migrations.RemoveField(model_name="user", name="pwd_ssha")] diff --git a/users/migrations/0019_auto_20160708_1633.py b/users/migrations/0019_auto_20160708_1633.py index 980bf112..e4cbdbd8 100644 --- a/users/migrations/0019_auto_20160708_1633.py +++ b/users/migrations/0019_auto_20160708_1633.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0018_auto_20160707_0115'), - ] + dependencies = [("users", "0018_auto_20160707_0115")] operations = [ migrations.AlterField( - model_name='listright', - name='listright', + model_name="listright", + name="listright", field=models.CharField(unique=True, max_length=255), - ), + ) ] diff --git a/users/migrations/0020_request.py b/users/migrations/0020_request.py index 379f5f3c..6d059c6a 100644 --- a/users/migrations/0020_request.py +++ b/users/migrations/0020_request.py @@ -30,20 +30,37 @@ from django.conf import settings class Migration(migrations.Migration): - dependencies = [ - ('users', '0019_auto_20160708_1633'), - ] + dependencies = [("users", "0019_auto_20160708_1633")] operations = [ migrations.CreateModel( - name='Request', + name="Request", fields=[ - ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)), - ('type', models.CharField(choices=[('PW', 'Mot de passe'), ('EM', 'Email')], max_length=2)), - ('token', models.CharField(max_length=32)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('expires_at', models.DateTimeField()), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.PROTECT)), + ( + "id", + models.AutoField( + auto_created=True, + verbose_name="ID", + primary_key=True, + serialize=False, + ), + ), + ( + "type", + models.CharField( + choices=[("PW", "Mot de passe"), ("EM", "Email")], max_length=2 + ), + ), + ("token", models.CharField(max_length=32)), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("expires_at", models.DateTimeField()), + ( + "user", + models.ForeignKey( + to=settings.AUTH_USER_MODEL, + on_delete=django.db.models.deletion.PROTECT, + ), + ), ], - ), + ) ] diff --git a/users/migrations/0021_ldapuser.py b/users/migrations/0021_ldapuser.py index 712842cd..1d475027 100644 --- a/users/migrations/0021_ldapuser.py +++ b/users/migrations/0021_ldapuser.py @@ -29,29 +29,69 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0020_request'), - ] + dependencies = [("users", "0020_request")] operations = [ migrations.CreateModel( - name='LdapUser', + name="LdapUser", fields=[ - ('dn', models.CharField(max_length=200)), - ('gid', ldapdb.models.fields.IntegerField(db_column='gidNumber')), - ('name', ldapdb.models.fields.CharField(primary_key=True, max_length=200, db_column='cn', serialize=False)), - ('uid', ldapdb.models.fields.CharField(max_length=200, db_column='uid')), - ('uidNumber', ldapdb.models.fields.IntegerField(unique=True, db_column='uidNumber')), - ('sn', ldapdb.models.fields.CharField(max_length=200, db_column='sn')), - ('loginShell', ldapdb.models.fields.CharField(default='/bin/zsh', max_length=200, db_column='loginShell')), - ('mail', ldapdb.models.fields.CharField(max_length=200, db_column='mail')), - ('given_name', ldapdb.models.fields.CharField(max_length=200, db_column='givenName')), - ('home_directory', ldapdb.models.fields.CharField(max_length=200, db_column='homeDirectory')), - ('dialupAccess', ldapdb.models.fields.CharField(max_length=200, db_column='dialupAccess')), - ('mac_list', ldapdb.models.fields.CharField(max_length=200, db_column='radiusCallingStationId')), + ("dn", models.CharField(max_length=200)), + ("gid", ldapdb.models.fields.IntegerField(db_column="gidNumber")), + ( + "name", + ldapdb.models.fields.CharField( + primary_key=True, + max_length=200, + db_column="cn", + serialize=False, + ), + ), + ( + "uid", + ldapdb.models.fields.CharField(max_length=200, db_column="uid"), + ), + ( + "uidNumber", + ldapdb.models.fields.IntegerField( + unique=True, db_column="uidNumber" + ), + ), + ("sn", ldapdb.models.fields.CharField(max_length=200, db_column="sn")), + ( + "loginShell", + ldapdb.models.fields.CharField( + default="/bin/zsh", max_length=200, db_column="loginShell" + ), + ), + ( + "mail", + ldapdb.models.fields.CharField(max_length=200, db_column="mail"), + ), + ( + "given_name", + ldapdb.models.fields.CharField( + max_length=200, db_column="givenName" + ), + ), + ( + "home_directory", + ldapdb.models.fields.CharField( + max_length=200, db_column="homeDirectory" + ), + ), + ( + "dialupAccess", + ldapdb.models.fields.CharField( + max_length=200, db_column="dialupAccess" + ), + ), + ( + "mac_list", + ldapdb.models.fields.CharField( + max_length=200, db_column="radiusCallingStationId" + ), + ), ], - options={ - 'abstract': False, - }, - ), + options={"abstract": False}, + ) ] diff --git a/users/migrations/0022_ldapuser_sambasid.py b/users/migrations/0022_ldapuser_sambasid.py index 61e9c935..18d214bd 100644 --- a/users/migrations/0022_ldapuser_sambasid.py +++ b/users/migrations/0022_ldapuser_sambasid.py @@ -29,22 +29,24 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0021_ldapuser'), - ] + dependencies = [("users", "0021_ldapuser")] operations = [ migrations.SeparateDatabaseAndState( state_operations=[ migrations.AddField( - model_name='ldapuser', - name='sambaSID', - field=ldapdb.models.fields.IntegerField(db_column='sambaSID', unique=True, null=True), + model_name="ldapuser", + name="sambaSID", + field=ldapdb.models.fields.IntegerField( + db_column="sambaSID", unique=True, null=True + ), preserve_default=False, - ), + ) ], database_operations=[ - migrations.RunSQL('ALTER TABLE "users_ldapuser" ADD COLUMN "sambaSID" integer NULL UNIQUE;'), + migrations.RunSQL( + 'ALTER TABLE "users_ldapuser" ADD COLUMN "sambaSID" integer NULL UNIQUE;' + ) ], ) ] diff --git a/users/migrations/0023_auto_20160724_1908.py b/users/migrations/0023_auto_20160724_1908.py index 9bced0fc..3e9baf2c 100644 --- a/users/migrations/0023_auto_20160724_1908.py +++ b/users/migrations/0023_auto_20160724_1908.py @@ -29,14 +29,12 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0022_ldapuser_sambasid'), - ] + dependencies = [("users", "0022_ldapuser_sambasid")] operations = [ migrations.AlterField( - model_name='ldapuser', - name='sambaSID', - field=ldapdb.models.fields.IntegerField(db_column='sambaSID', unique=True), - ), + model_name="ldapuser", + name="sambaSID", + field=ldapdb.models.fields.IntegerField(db_column="sambaSID", unique=True), + ) ] diff --git a/users/migrations/0024_remove_ldapuser_mac_list.py b/users/migrations/0024_remove_ldapuser_mac_list.py index d4e4e458..72f3b11a 100644 --- a/users/migrations/0024_remove_ldapuser_mac_list.py +++ b/users/migrations/0024_remove_ldapuser_mac_list.py @@ -28,13 +28,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0023_auto_20160724_1908'), - ] + dependencies = [("users", "0023_auto_20160724_1908")] - operations = [ - migrations.RemoveField( - model_name='ldapuser', - name='mac_list', - ), - ] + operations = [migrations.RemoveField(model_name="ldapuser", name="mac_list")] diff --git a/users/migrations/0025_listshell.py b/users/migrations/0025_listshell.py index 8f63776d..e3a8f7bd 100644 --- a/users/migrations/0025_listshell.py +++ b/users/migrations/0025_listshell.py @@ -28,16 +28,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0024_remove_ldapuser_mac_list'), - ] + dependencies = [("users", "0024_remove_ldapuser_mac_list")] operations = [ migrations.CreateModel( - name='ListShell', + name="ListShell", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), - ('shell', models.CharField(unique=True, max_length=255)), + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + primary_key=True, + verbose_name="ID", + ), + ), + ("shell", models.CharField(unique=True, max_length=255)), ], - ), + ) ] diff --git a/users/migrations/0026_user_shell.py b/users/migrations/0026_user_shell.py index 081d9498..c7f14040 100644 --- a/users/migrations/0026_user_shell.py +++ b/users/migrations/0026_user_shell.py @@ -29,15 +29,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0025_listshell'), - ] + dependencies = [("users", "0025_listshell")] operations = [ migrations.AddField( - model_name='user', - name='shell', - field=models.ForeignKey(to='users.ListShell', default=1, on_delete=django.db.models.deletion.PROTECT), + model_name="user", + name="shell", + field=models.ForeignKey( + to="users.ListShell", + default=1, + on_delete=django.db.models.deletion.PROTECT, + ), preserve_default=False, - ), + ) ] diff --git a/users/migrations/0027_auto_20160726_0216.py b/users/migrations/0027_auto_20160726_0216.py index 9324c815..0d09063b 100644 --- a/users/migrations/0027_auto_20160726_0216.py +++ b/users/migrations/0027_auto_20160726_0216.py @@ -30,21 +30,28 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0026_user_shell'), - ] + dependencies = [("users", "0026_user_shell")] operations = [ migrations.CreateModel( - name='LdapUserGroup', + name="LdapUserGroup", fields=[ - ('dn', models.CharField(max_length=200)), - ('gid', ldapdb.models.fields.IntegerField(db_column='gidNumber')), - ('members', ldapdb.models.fields.ListField(db_column='memberUid', blank=True)), - ('name', ldapdb.models.fields.CharField(db_column='cn', primary_key=True, serialize=False, max_length=200)), + ("dn", models.CharField(max_length=200)), + ("gid", ldapdb.models.fields.IntegerField(db_column="gidNumber")), + ( + "members", + ldapdb.models.fields.ListField(db_column="memberUid", blank=True), + ), + ( + "name", + ldapdb.models.fields.CharField( + db_column="cn", + primary_key=True, + serialize=False, + max_length=200, + ), + ), ], - options={ - 'abstract': False, - }, - ), + options={"abstract": False}, + ) ] diff --git a/users/migrations/0028_auto_20160726_0227.py b/users/migrations/0028_auto_20160726_0227.py index c541bc14..5191e228 100644 --- a/users/migrations/0028_auto_20160726_0227.py +++ b/users/migrations/0028_auto_20160726_0227.py @@ -30,48 +30,70 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0027_auto_20160726_0216'), - ] + dependencies = [("users", "0027_auto_20160726_0216")] operations = [ migrations.SeparateDatabaseAndState( state_operations=[ migrations.AddField( - model_name='ldapuser', - name='display_name', - field=ldapdb.models.fields.CharField(null=True, blank=True, max_length=200, db_column='displayName'), + model_name="ldapuser", + name="display_name", + field=ldapdb.models.fields.CharField( + null=True, blank=True, max_length=200, db_column="displayName" + ), ), migrations.AddField( - model_name='ldapuser', - name='sambat_nt_password', - field=ldapdb.models.fields.CharField(null=True, blank=True, max_length=200, db_column='sambaNTPassword'), + model_name="ldapuser", + name="sambat_nt_password", + field=ldapdb.models.fields.CharField( + null=True, + blank=True, + max_length=200, + db_column="sambaNTPassword", + ), ), migrations.AddField( - model_name='ldapuser', - name='user_password', - field=ldapdb.models.fields.CharField(null=True, blank=True, max_length=200, db_column='userPassword'), + model_name="ldapuser", + name="user_password", + field=ldapdb.models.fields.CharField( + null=True, blank=True, max_length=200, db_column="userPassword" + ), ), ], database_operations=[ - migrations.RunSQL('ALTER TABLE users_ldapuser ADD COLUMN "displayName" varchar(200) NULL;'), - migrations.RunSQL('ALTER TABLE users_ldapuser ADD COLUMN "sambaNTPassword" varchar(200) NULL;'), - migrations.RunSQL('ALTER TABLE users_ldapuser ADD COLUMN "userPassword" varchar(200) NULL;'), - ] + migrations.RunSQL( + 'ALTER TABLE users_ldapuser ADD COLUMN "displayName" varchar(200) NULL;' + ), + migrations.RunSQL( + 'ALTER TABLE users_ldapuser ADD COLUMN "sambaNTPassword" varchar(200) NULL;' + ), + migrations.RunSQL( + 'ALTER TABLE users_ldapuser ADD COLUMN "userPassword" varchar(200) NULL;' + ), + ], ), migrations.AddField( - model_name='ldapuser', - name='macs', - field=ldapdb.models.fields.ListField(null=True, blank=True, max_length=200, db_column='radiusCallingStationId'), + model_name="ldapuser", + name="macs", + field=ldapdb.models.fields.ListField( + null=True, + blank=True, + max_length=200, + db_column="radiusCallingStationId", + ), ), migrations.AddField( - model_name='listright', - name='gid', + model_name="listright", + name="gid", field=models.IntegerField(null=True, unique=True), ), migrations.AlterField( - model_name='user', - name='shell', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, default=1, to='users.ListShell'), + model_name="user", + name="shell", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + default=1, + to="users.ListShell", + ), ), ] diff --git a/users/migrations/0029_auto_20160726_0229.py b/users/migrations/0029_auto_20160726_0229.py index 6b5d16d9..1abd06b2 100644 --- a/users/migrations/0029_auto_20160726_0229.py +++ b/users/migrations/0029_auto_20160726_0229.py @@ -29,14 +29,14 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0028_auto_20160726_0227'), - ] + dependencies = [("users", "0028_auto_20160726_0227")] operations = [ migrations.AlterField( - model_name='ldapuser', - name='display_name', - field=ldapdb.models.fields.CharField(db_column='displayName', max_length=200), - ), + model_name="ldapuser", + name="display_name", + field=ldapdb.models.fields.CharField( + db_column="displayName", max_length=200 + ), + ) ] diff --git a/users/migrations/0030_auto_20160726_0357.py b/users/migrations/0030_auto_20160726_0357.py index a4c3d727..9ccca318 100644 --- a/users/migrations/0030_auto_20160726_0357.py +++ b/users/migrations/0030_auto_20160726_0357.py @@ -30,14 +30,14 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0029_auto_20160726_0229'), - ] + dependencies = [("users", "0029_auto_20160726_0229")] operations = [ migrations.AlterField( - model_name='ldapuser', - name='display_name', - field=ldapdb.models.fields.CharField(null=True, max_length=200, db_column='displayName', blank=True), - ), + model_name="ldapuser", + name="display_name", + field=ldapdb.models.fields.CharField( + null=True, max_length=200, db_column="displayName", blank=True + ), + ) ] diff --git a/users/migrations/0031_auto_20160726_0359.py b/users/migrations/0031_auto_20160726_0359.py index 7f327e79..5cf65e41 100644 --- a/users/migrations/0031_auto_20160726_0359.py +++ b/users/migrations/0031_auto_20160726_0359.py @@ -30,14 +30,17 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0030_auto_20160726_0357'), - ] + dependencies = [("users", "0030_auto_20160726_0357")] operations = [ migrations.AlterField( - model_name='user', - name='shell', - field=models.ForeignKey(to='users.ListShell', on_delete=django.db.models.deletion.PROTECT, null=True, blank=True), - ), + model_name="user", + name="shell", + field=models.ForeignKey( + to="users.ListShell", + on_delete=django.db.models.deletion.PROTECT, + null=True, + blank=True, + ), + ) ] diff --git a/users/migrations/0032_auto_20160727_2122.py b/users/migrations/0032_auto_20160727_2122.py index b583b5db..1dc27579 100644 --- a/users/migrations/0032_auto_20160727_2122.py +++ b/users/migrations/0032_auto_20160727_2122.py @@ -30,32 +30,60 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0031_auto_20160726_0359'), - ] + dependencies = [("users", "0031_auto_20160726_0359")] operations = [ migrations.CreateModel( - name='LdapServiceUser', + name="LdapServiceUser", fields=[ - ('dn', models.CharField(max_length=200)), - ('name', ldapdb.models.fields.CharField(db_column='cn', max_length=200, serialize=False, primary_key=True)), - ('user_password', ldapdb.models.fields.CharField(db_column='userPassword', blank=True, max_length=200, null=True)), + ("dn", models.CharField(max_length=200)), + ( + "name", + ldapdb.models.fields.CharField( + db_column="cn", + max_length=200, + serialize=False, + primary_key=True, + ), + ), + ( + "user_password", + ldapdb.models.fields.CharField( + db_column="userPassword", blank=True, max_length=200, null=True + ), + ), ], - options={ - 'abstract': False, - }, + options={"abstract": False}, ), migrations.CreateModel( - name='ServiceUser', + name="ServiceUser", fields=[ - ('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, verbose_name='last login', null=True)), - ('pseudo', models.CharField(max_length=32, help_text='Doit contenir uniquement des lettres, chiffres, ou tirets', unique=True, validators=[users.models.linux_user_validator])), + ( + "id", + models.AutoField( + verbose_name="ID", + auto_created=True, + primary_key=True, + serialize=False, + ), + ), + ("password", models.CharField(max_length=128, verbose_name="password")), + ( + "last_login", + models.DateTimeField( + blank=True, verbose_name="last login", null=True + ), + ), + ( + "pseudo", + models.CharField( + max_length=32, + help_text="Doit contenir uniquement des lettres, chiffres, ou tirets", + unique=True, + validators=[users.models.linux_user_validator], + ), + ), ], - options={ - 'abstract': False, - }, + options={"abstract": False}, ), ] diff --git a/users/migrations/0033_remove_ldapuser_loginshell.py b/users/migrations/0033_remove_ldapuser_loginshell.py index e8a4c616..70be687d 100644 --- a/users/migrations/0033_remove_ldapuser_loginshell.py +++ b/users/migrations/0033_remove_ldapuser_loginshell.py @@ -28,13 +28,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0032_auto_20160727_2122'), - ] + dependencies = [("users", "0032_auto_20160727_2122")] - operations = [ - migrations.RemoveField( - model_name='ldapuser', - name='loginShell', - ), - ] + operations = [migrations.RemoveField(model_name="ldapuser", name="loginShell")] diff --git a/users/migrations/0034_auto_20161018_0037.py b/users/migrations/0034_auto_20161018_0037.py index 911357a2..ed0fbab0 100644 --- a/users/migrations/0034_auto_20161018_0037.py +++ b/users/migrations/0034_auto_20161018_0037.py @@ -31,36 +31,41 @@ import users.models class Migration(migrations.Migration): - dependencies = [ - ('users', '0033_remove_ldapuser_loginshell'), - ] + dependencies = [("users", "0033_remove_ldapuser_loginshell")] operations = [ migrations.SeparateDatabaseAndState( state_operations=[ migrations.AddField( - model_name='ldapuser', - name='login_shell', - field=ldapdb.models.fields.CharField(blank=True, db_column='loginShell', max_length=200, null=True), - ), + model_name="ldapuser", + name="login_shell", + field=ldapdb.models.fields.CharField( + blank=True, db_column="loginShell", max_length=200, null=True + ), + ) ], database_operations=[ - migrations.RunSQL('ALTER TABLE users_ldapuser ADD COLUMN "loginShell" varchar(200) NULL;') + migrations.RunSQL( + 'ALTER TABLE users_ldapuser ADD COLUMN "loginShell" varchar(200) NULL;' + ) ], ), migrations.AddField( - model_name='user', - name='rezo_rez_uid', + model_name="user", + name="rezo_rez_uid", field=models.IntegerField(blank=True, unique=True, null=True), ), migrations.AddField( - model_name='user', - name='uid_number', - field=models.IntegerField(unique=True), + model_name="user", name="uid_number", field=models.IntegerField(unique=True) ), migrations.AlterField( - model_name='user', - name='school', - field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.PROTECT, to='users.School', null=True), + model_name="user", + name="school", + field=models.ForeignKey( + blank=True, + on_delete=django.db.models.deletion.PROTECT, + to="users.School", + null=True, + ), ), ] diff --git a/users/migrations/0035_auto_20161018_0046.py b/users/migrations/0035_auto_20161018_0046.py index f026737b..ab27d7e2 100644 --- a/users/migrations/0035_auto_20161018_0046.py +++ b/users/migrations/0035_auto_20161018_0046.py @@ -29,14 +29,14 @@ import users.models class Migration(migrations.Migration): - dependencies = [ - ('users', '0034_auto_20161018_0037'), - ] + dependencies = [("users", "0034_auto_20161018_0037")] operations = [ migrations.AlterField( - model_name='user', - name='uid_number', - field=models.IntegerField(unique=True, default=users.models.get_fresh_user_uid), - ), + model_name="user", + name="uid_number", + field=models.IntegerField( + unique=True, default=users.models.get_fresh_user_uid + ), + ) ] diff --git a/users/migrations/0036_auto_20161022_2146.py b/users/migrations/0036_auto_20161022_2146.py index 3619cc31..7d7a4521 100644 --- a/users/migrations/0036_auto_20161022_2146.py +++ b/users/migrations/0036_auto_20161022_2146.py @@ -28,14 +28,19 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0035_auto_20161018_0046'), - ] + dependencies = [("users", "0035_auto_20161018_0046")] operations = [ migrations.AlterField( - model_name='user', - name='state', - field=models.IntegerField(default=0, choices=[(0, 'STATE_ACTIVE'), (1, 'STATE_DISABLED'), (2, 'STATE_ARCHIVE')]), - ), + model_name="user", + name="state", + field=models.IntegerField( + default=0, + choices=[ + (0, "STATE_ACTIVE"), + (1, "STATE_DISABLED"), + (2, "STATE_ARCHIVE"), + ], + ), + ) ] diff --git a/users/migrations/0037_auto_20161028_1906.py b/users/migrations/0037_auto_20161028_1906.py index ee4d5d5f..3e2c3887 100644 --- a/users/migrations/0037_auto_20161028_1906.py +++ b/users/migrations/0037_auto_20161028_1906.py @@ -28,24 +28,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0036_auto_20161022_2146'), - ] + dependencies = [("users", "0036_auto_20161022_2146")] operations = [ migrations.AlterField( - model_name='ldapserviceuser', - name='dn', + model_name="ldapserviceuser", + name="dn", field=models.CharField(serialize=False, primary_key=True, max_length=200), ), migrations.AlterField( - model_name='ldapuser', - name='dn', + model_name="ldapuser", + name="dn", field=models.CharField(serialize=False, primary_key=True, max_length=200), ), migrations.AlterField( - model_name='ldapusergroup', - name='dn', + model_name="ldapusergroup", + name="dn", field=models.CharField(serialize=False, primary_key=True, max_length=200), ), ] diff --git a/users/migrations/0038_auto_20161031_0258.py b/users/migrations/0038_auto_20161031_0258.py index 342d302b..bb3f9f86 100644 --- a/users/migrations/0038_auto_20161031_0258.py +++ b/users/migrations/0038_auto_20161031_0258.py @@ -28,24 +28,20 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0037_auto_20161028_1906'), - ] + dependencies = [("users", "0037_auto_20161028_1906")] operations = [ migrations.AlterField( - model_name='ldapserviceuser', - name='dn', + model_name="ldapserviceuser", + name="dn", field=models.CharField(max_length=200), ), migrations.AlterField( - model_name='ldapuser', - name='dn', - field=models.CharField(max_length=200), + model_name="ldapuser", name="dn", field=models.CharField(max_length=200) ), migrations.AlterField( - model_name='ldapusergroup', - name='dn', + model_name="ldapusergroup", + name="dn", field=models.CharField(max_length=200), ), ] diff --git a/users/migrations/0039_auto_20161119_0033.py b/users/migrations/0039_auto_20161119_0033.py index a5118b89..9c08ca33 100644 --- a/users/migrations/0039_auto_20161119_0033.py +++ b/users/migrations/0039_auto_20161119_0033.py @@ -28,24 +28,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0038_auto_20161031_0258'), - ] + dependencies = [("users", "0038_auto_20161031_0258")] operations = [ migrations.AlterField( - model_name='ldapserviceuser', - name='dn', + model_name="ldapserviceuser", + name="dn", field=models.CharField(serialize=False, max_length=200, primary_key=True), ), migrations.AlterField( - model_name='ldapuser', - name='dn', + model_name="ldapuser", + name="dn", field=models.CharField(serialize=False, max_length=200, primary_key=True), ), migrations.AlterField( - model_name='ldapusergroup', - name='dn', + model_name="ldapusergroup", + name="dn", field=models.CharField(serialize=False, max_length=200, primary_key=True), ), ] diff --git a/users/migrations/0040_auto_20161119_1709.py b/users/migrations/0040_auto_20161119_1709.py index bc2c3de2..d1bd88ab 100644 --- a/users/migrations/0040_auto_20161119_1709.py +++ b/users/migrations/0040_auto_20161119_1709.py @@ -28,24 +28,20 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0039_auto_20161119_0033'), - ] + dependencies = [("users", "0039_auto_20161119_0033")] operations = [ migrations.AlterField( - model_name='ldapserviceuser', - name='dn', + model_name="ldapserviceuser", + name="dn", field=models.CharField(max_length=200), ), migrations.AlterField( - model_name='ldapuser', - name='dn', - field=models.CharField(max_length=200), + model_name="ldapuser", name="dn", field=models.CharField(max_length=200) ), migrations.AlterField( - model_name='ldapusergroup', - name='dn', + model_name="ldapusergroup", + name="dn", field=models.CharField(max_length=200), ), ] diff --git a/users/migrations/0041_listright_details.py b/users/migrations/0041_listright_details.py index 1e44fe2b..a28b246c 100644 --- a/users/migrations/0041_listright_details.py +++ b/users/migrations/0041_listright_details.py @@ -28,14 +28,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0040_auto_20161119_1709'), - ] + dependencies = [("users", "0040_auto_20161119_1709")] operations = [ migrations.AddField( - model_name='listright', - name='details', - field=models.CharField(help_text='Description', max_length=255, blank=True), - ), + model_name="listright", + name="details", + field=models.CharField(help_text="Description", max_length=255, blank=True), + ) ] diff --git a/users/migrations/0042_auto_20161126_2028.py b/users/migrations/0042_auto_20161126_2028.py index 04a301c7..491ecec3 100644 --- a/users/migrations/0042_auto_20161126_2028.py +++ b/users/migrations/0042_auto_20161126_2028.py @@ -28,24 +28,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0041_listright_details'), - ] + dependencies = [("users", "0041_listright_details")] operations = [ migrations.AlterField( - model_name='ldapserviceuser', - name='dn', + model_name="ldapserviceuser", + name="dn", field=models.CharField(serialize=False, primary_key=True, max_length=200), ), migrations.AlterField( - model_name='ldapuser', - name='dn', + model_name="ldapuser", + name="dn", field=models.CharField(serialize=False, primary_key=True, max_length=200), ), migrations.AlterField( - model_name='ldapusergroup', - name='dn', + model_name="ldapusergroup", + name="dn", field=models.CharField(serialize=False, primary_key=True, max_length=200), ), ] diff --git a/users/migrations/0043_auto_20161224_1156.py b/users/migrations/0043_auto_20161224_1156.py index 18aa1e35..0502ea7b 100644 --- a/users/migrations/0043_auto_20161224_1156.py +++ b/users/migrations/0043_auto_20161224_1156.py @@ -6,24 +6,20 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0042_auto_20161126_2028'), - ] + dependencies = [("users", "0042_auto_20161126_2028")] operations = [ migrations.AlterField( - model_name='ldapserviceuser', - name='dn', + model_name="ldapserviceuser", + name="dn", field=models.CharField(max_length=200), ), migrations.AlterField( - model_name='ldapuser', - name='dn', - field=models.CharField(max_length=200), + model_name="ldapuser", name="dn", field=models.CharField(max_length=200) ), migrations.AlterField( - model_name='ldapusergroup', - name='dn', + model_name="ldapusergroup", + name="dn", field=models.CharField(max_length=200), ), ] diff --git a/users/migrations/0043_ban_state.py b/users/migrations/0043_ban_state.py index 897415e4..266bdfe5 100644 --- a/users/migrations/0043_ban_state.py +++ b/users/migrations/0043_ban_state.py @@ -6,14 +6,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0042_auto_20161126_2028'), - ] + dependencies = [("users", "0042_auto_20161126_2028")] operations = [ migrations.AddField( - model_name='ban', - name='state', - field=models.IntegerField(choices=[(0, 'STATE_HARD'), (1, 'STATE_SOFT'), (2, 'STATE_BRIDAGE')], default=0), - ), + model_name="ban", + name="state", + field=models.IntegerField( + choices=[(0, "STATE_HARD"), (1, "STATE_SOFT"), (2, "STATE_BRIDAGE")], + default=0, + ), + ) ] diff --git a/users/migrations/0044_user_ssh_public_key.py b/users/migrations/0044_user_ssh_public_key.py index e25194d2..7554ee6f 100644 --- a/users/migrations/0044_user_ssh_public_key.py +++ b/users/migrations/0044_user_ssh_public_key.py @@ -6,14 +6,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0043_auto_20161224_1156'), - ] + dependencies = [("users", "0043_auto_20161224_1156")] operations = [ migrations.AddField( - model_name='user', - name='ssh_public_key', + model_name="user", + name="ssh_public_key", field=models.CharField(max_length=2047, null=True, blank=True), - ), + ) ] diff --git a/users/migrations/0045_merge.py b/users/migrations/0045_merge.py index fa8b8712..90761425 100644 --- a/users/migrations/0045_merge.py +++ b/users/migrations/0045_merge.py @@ -6,10 +6,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0043_ban_state'), - ('users', '0044_user_ssh_public_key'), - ] + dependencies = [("users", "0043_ban_state"), ("users", "0044_user_ssh_public_key")] - operations = [ - ] + operations = [] diff --git a/users/migrations/0046_auto_20170617_1433.py b/users/migrations/0046_auto_20170617_1433.py index 7b846abf..ddb7eb87 100644 --- a/users/migrations/0046_auto_20170617_1433.py +++ b/users/migrations/0046_auto_20170617_1433.py @@ -7,33 +7,35 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0045_merge'), - ] + dependencies = [("users", "0045_merge")] operations = [ - migrations.RemoveField( - model_name='user', - name='ssh_public_key', + migrations.RemoveField(model_name="user", name="ssh_public_key"), + migrations.AlterField( + model_name="ban", + name="state", + field=models.IntegerField( + choices=[ + (0, "HARD (aucun accès)"), + (1, "SOFT (accès local seulement)"), + (2, "BRIDAGE (bridage du débit)"), + ], + default=0, + ), ), migrations.AlterField( - model_name='ban', - name='state', - field=models.IntegerField(choices=[(0, 'HARD (aucun accès)'), (1, 'SOFT (accès local seulement)'), (2, 'BRIDAGE (bridage du débit)')], default=0), - ), - migrations.AlterField( - model_name='ldapserviceuser', - name='dn', + model_name="ldapserviceuser", + name="dn", field=models.CharField(max_length=200, primary_key=True, serialize=False), ), migrations.AlterField( - model_name='ldapuser', - name='dn', + model_name="ldapuser", + name="dn", field=models.CharField(max_length=200, primary_key=True, serialize=False), ), migrations.AlterField( - model_name='ldapusergroup', - name='dn', + model_name="ldapusergroup", + name="dn", field=models.CharField(max_length=200, primary_key=True, serialize=False), ), ] diff --git a/users/migrations/0047_auto_20170618_0156.py b/users/migrations/0047_auto_20170618_0156.py index dc19b38a..6175a378 100644 --- a/users/migrations/0047_auto_20170618_0156.py +++ b/users/migrations/0047_auto_20170618_0156.py @@ -8,25 +8,34 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0046_auto_20170617_1433'), - ] + dependencies = [("users", "0046_auto_20170617_1433")] operations = [ migrations.CreateModel( - name='LdapServiceUserGroup', + name="LdapServiceUserGroup", fields=[ - ('dn', models.CharField(max_length=200, primary_key=True, serialize=False)), - ('name', ldapdb.models.fields.CharField(db_column='cn', max_length=200, serialize=False)), - ('members', ldapdb.models.fields.ListField(blank=True, db_column='member')), + ( + "dn", + models.CharField(max_length=200, primary_key=True, serialize=False), + ), + ( + "name", + ldapdb.models.fields.CharField( + db_column="cn", max_length=200, serialize=False + ), + ), + ( + "members", + ldapdb.models.fields.ListField(blank=True, db_column="member"), + ), ], - options={ - 'abstract': False, - }, + options={"abstract": False}, ), migrations.AddField( - model_name='serviceuser', - name='access_group', - field=models.IntegerField(choices=[(0, 'auth'), (1, 'readonly'), (2, 'usermgmt')], default=1), + model_name="serviceuser", + name="access_group", + field=models.IntegerField( + choices=[(0, "auth"), (1, "readonly"), (2, "usermgmt")], default=1 + ), ), ] diff --git a/users/migrations/0048_auto_20170618_0210.py b/users/migrations/0048_auto_20170618_0210.py index 7ef8c397..8d7ff90d 100644 --- a/users/migrations/0048_auto_20170618_0210.py +++ b/users/migrations/0048_auto_20170618_0210.py @@ -8,14 +8,14 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0047_auto_20170618_0156'), - ] + dependencies = [("users", "0047_auto_20170618_0156")] operations = [ migrations.AlterField( - model_name='ldapserviceusergroup', - name='name', - field=ldapdb.models.fields.CharField(db_column='cn', max_length=200, primary_key=True, serialize=False), - ), + model_name="ldapserviceusergroup", + name="name", + field=ldapdb.models.fields.CharField( + db_column="cn", max_length=200, primary_key=True, serialize=False + ), + ) ] diff --git a/users/migrations/0049_auto_20170618_1424.py b/users/migrations/0049_auto_20170618_1424.py index 773544a0..f73aa4b4 100644 --- a/users/migrations/0049_auto_20170618_1424.py +++ b/users/migrations/0049_auto_20170618_1424.py @@ -7,14 +7,20 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0048_auto_20170618_0210'), - ] + dependencies = [("users", "0048_auto_20170618_0210")] operations = [ migrations.AlterField( - model_name='serviceuser', - name='access_group', - field=models.CharField(choices=[('auth', 'auth'), ('readonly', 'readonly'), ('usermgmt', 'usermgmt')], default='readonly', max_length=32), - ), + model_name="serviceuser", + name="access_group", + field=models.CharField( + choices=[ + ("auth", "auth"), + ("readonly", "readonly"), + ("usermgmt", "usermgmt"), + ], + default="readonly", + max_length=32, + ), + ) ] diff --git a/users/migrations/0050_serviceuser_comment.py b/users/migrations/0050_serviceuser_comment.py index 37bfd5cf..f2503573 100644 --- a/users/migrations/0050_serviceuser_comment.py +++ b/users/migrations/0050_serviceuser_comment.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0049_auto_20170618_1424'), - ] + dependencies = [("users", "0049_auto_20170618_1424")] operations = [ migrations.AddField( - model_name='serviceuser', - name='comment', - field=models.CharField(blank=True, help_text='Commentaire', max_length=255), - ), + model_name="serviceuser", + name="comment", + field=models.CharField(blank=True, help_text="Commentaire", max_length=255), + ) ] diff --git a/users/migrations/0051_user_telephone.py b/users/migrations/0051_user_telephone.py index 32aedebc..ce5a4764 100644 --- a/users/migrations/0051_user_telephone.py +++ b/users/migrations/0051_user_telephone.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0050_serviceuser_comment'), - ] + dependencies = [("users", "0050_serviceuser_comment")] operations = [ migrations.AddField( - model_name='user', - name='telephone', + model_name="user", + name="telephone", field=models.CharField(blank=True, max_length=15, null=True), - ), + ) ] diff --git a/users/migrations/0052_ldapuser_shadowexpire.py b/users/migrations/0052_ldapuser_shadowexpire.py index 3948d2c9..2737d76d 100644 --- a/users/migrations/0052_ldapuser_shadowexpire.py +++ b/users/migrations/0052_ldapuser_shadowexpire.py @@ -8,21 +8,23 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0051_user_telephone'), - ] + dependencies = [("users", "0051_user_telephone")] operations = [ migrations.SeparateDatabaseAndState( state_operations=[ migrations.AddField( - model_name='ldapuser', - name='shadowexpire', - field=ldapdb.models.fields.CharField(blank=True, db_column='shadowExpire', max_length=200, null=True), - ), + model_name="ldapuser", + name="shadowexpire", + field=ldapdb.models.fields.CharField( + blank=True, db_column="shadowExpire", max_length=200, null=True + ), + ) ], database_operations=[ - migrations.RunSQL('ALTER TABLE users_ldapuser ADD COLUMN "shadowExpire" varchar(200) NULL;'), - ] - ), + migrations.RunSQL( + 'ALTER TABLE users_ldapuser ADD COLUMN "shadowExpire" varchar(200) NULL;' + ) + ], + ) ] diff --git a/users/migrations/0053_auto_20170626_2105.py b/users/migrations/0053_auto_20170626_2105.py index 03a23f12..482ba175 100644 --- a/users/migrations/0053_auto_20170626_2105.py +++ b/users/migrations/0053_auto_20170626_2105.py @@ -8,14 +8,14 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0052_ldapuser_shadowexpire'), - ] + dependencies = [("users", "0052_ldapuser_shadowexpire")] operations = [ migrations.AlterField( - model_name='ldapuser', - name='shadowexpire', - field=ldapdb.models.fields.IntegerField(blank=True, db_column='shadowExpire', null=True), - ), + model_name="ldapuser", + name="shadowexpire", + field=ldapdb.models.fields.IntegerField( + blank=True, db_column="shadowExpire", null=True + ), + ) ] diff --git a/users/migrations/0054_auto_20170626_2219.py b/users/migrations/0054_auto_20170626_2219.py index b22d1e1f..4b3710a5 100644 --- a/users/migrations/0054_auto_20170626_2219.py +++ b/users/migrations/0054_auto_20170626_2219.py @@ -8,14 +8,14 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0053_auto_20170626_2105'), - ] + dependencies = [("users", "0053_auto_20170626_2105")] operations = [ migrations.AlterField( - model_name='ldapuser', - name='shadowexpire', - field=ldapdb.models.fields.CharField(blank=True, db_column='shadowExpire', max_length=200, null=True), - ), + model_name="ldapuser", + name="shadowexpire", + field=ldapdb.models.fields.CharField( + blank=True, db_column="shadowExpire", max_length=200, null=True + ), + ) ] diff --git a/users/migrations/0055_auto_20171003_0556.py b/users/migrations/0055_auto_20171003_0556.py index 84d901c8..f14f2c68 100644 --- a/users/migrations/0055_auto_20171003_0556.py +++ b/users/migrations/0055_auto_20171003_0556.py @@ -8,14 +8,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0054_auto_20170626_2219'), - ] + dependencies = [("users", "0054_auto_20170626_2219")] operations = [ 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')]), - ), + 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", + ) + ], + ), + ) ] diff --git a/users/migrations/0056_auto_20171015_2033.py b/users/migrations/0056_auto_20171015_2033.py index 90423340..d319b302 100644 --- a/users/migrations/0056_auto_20171015_2033.py +++ b/users/migrations/0056_auto_20171015_2033.py @@ -9,29 +9,38 @@ import users.models class Migration(migrations.Migration): - dependencies = [ - ('users', '0055_auto_20171003_0556'), - ] + dependencies = [("users", "0055_auto_20171003_0556")] operations = [ migrations.AlterField( - model_name='listright', - name='gid', + 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')]), + 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', + 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.get_fresh_user_uid, unique=True), + model_name="user", + name="uid_number", + field=models.PositiveIntegerField( + default=users.models.get_fresh_user_uid, unique=True + ), ), ] diff --git a/users/migrations/0057_auto_20171023_0301.py b/users/migrations/0057_auto_20171023_0301.py index d8a02c54..f174ff0e 100644 --- a/users/migrations/0057_auto_20171023_0301.py +++ b/users/migrations/0057_auto_20171023_0301.py @@ -9,40 +9,52 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0056_auto_20171015_2033'), - ] + dependencies = [("users", "0056_auto_20171015_2033")] operations = [ migrations.CreateModel( - name='Adherent', + name="Adherent", fields=[ - ('user_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)), - ('usname', models.CharField(max_length=255)), + ( + "user_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to=settings.AUTH_USER_MODEL, + ), + ), + ("usname", models.CharField(max_length=255)), ], - options={ - 'abstract': False, - }, - bases=('users.user',), + options={"abstract": False}, + bases=("users.user",), ), migrations.CreateModel( - name='Club', + name="Club", fields=[ - ('user_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)), + ( + "user_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to=settings.AUTH_USER_MODEL, + ), + ) ], - options={ - 'abstract': False, - }, - bases=('users.user',), + options={"abstract": False}, + bases=("users.user",), ), - migrations.RunSQL("insert into users_adherent (user_ptr_id, usname) select id, name from users_user", reverse_sql="insert into users_user (name) select usname from users_adherent"), - migrations.RemoveField( - model_name='user', - name='name', + migrations.RunSQL( + "insert into users_adherent (user_ptr_id, usname) select id, name from users_user", + reverse_sql="insert into users_user (name) select usname from users_adherent", ), + migrations.RemoveField(model_name="user", name="name"), migrations.RenameField( - model_name='adherent', - old_name='usname', - new_name='name', + model_name="adherent", old_name="usname", new_name="name" ), -] + ] diff --git a/users/migrations/0058_auto_20171025_0154.py b/users/migrations/0058_auto_20171025_0154.py index 01e64fbc..9ddd97c0 100644 --- a/users/migrations/0058_auto_20171025_0154.py +++ b/users/migrations/0058_auto_20171025_0154.py @@ -5,10 +5,11 @@ from __future__ import unicode_literals from django.db import migrations, models import django.db.models.deletion + def create_move_room(apps, schema_editor): - User = apps.get_model('users', 'User') - Adherent = apps.get_model('users', 'Adherent') - Club = apps.get_model('users', 'Club') + User = apps.get_model("users", "User") + Adherent = apps.get_model("users", "Adherent") + Club = apps.get_model("users", "Club") db_alias = schema_editor.connection.alias users = Adherent.objects.using(db_alias).all() clubs = Club.objects.using(db_alias).all() @@ -21,9 +22,9 @@ def create_move_room(apps, schema_editor): def delete_move_room(apps, schema_editor): - User = apps.get_model('users', 'User') - Adherent = apps.get_model('users', 'Adherent') - Club = apps.get_model('users', 'Club') + User = apps.get_model("users", "User") + Adherent = apps.get_model("users", "Adherent") + Club = apps.get_model("users", "Club") db_alias = schema_editor.connection.alias users = Adherent.objects.using(db_alias).all() clubs = Club.objects.using(db_alias).all() @@ -38,24 +39,31 @@ def delete_move_room(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('topologie', '0031_auto_20171015_2033'), - ('users', '0057_auto_20171023_0301'), + ("topologie", "0031_auto_20171015_2033"), + ("users", "0057_auto_20171023_0301"), ] operations = [ migrations.AddField( - model_name='adherent', - name='room_adherent', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='topologie.Room'), + model_name="adherent", + name="room_adherent", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="topologie.Room", + ), ), migrations.AddField( - model_name='club', - name='room_club', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='topologie.Room'), + model_name="club", + name="room_club", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="topologie.Room", + ), ), migrations.RunPython(create_move_room, delete_move_room), - migrations.RemoveField( - model_name='user', - name='room', - ), + migrations.RemoveField(model_name="user", name="room"), ] diff --git a/users/migrations/0059_auto_20171025_1854.py b/users/migrations/0059_auto_20171025_1854.py index 0ab2f9c4..ef3dc6be 100644 --- a/users/migrations/0059_auto_20171025_1854.py +++ b/users/migrations/0059_auto_20171025_1854.py @@ -7,19 +7,13 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('users', '0058_auto_20171025_0154'), - ] + dependencies = [("users", "0058_auto_20171025_0154")] operations = [ migrations.RenameField( - model_name='adherent', - old_name='room_adherent', - new_name='room', + model_name="adherent", old_name="room_adherent", new_name="room" ), migrations.RenameField( - model_name='club', - old_name='room_club', - new_name='room', + model_name="club", old_name="room_club", new_name="room" ), ] diff --git a/users/migrations/0060_auto_20171120_0317.py b/users/migrations/0060_auto_20171120_0317.py index a77b24db..ac001931 100644 --- a/users/migrations/0060_auto_20171120_0317.py +++ b/users/migrations/0060_auto_20171120_0317.py @@ -7,19 +7,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0059_auto_20171025_1854'), - ] + dependencies = [("users", "0059_auto_20171025_1854")] operations = [ migrations.AddField( - model_name='club', - name='administrators', - field=models.ManyToManyField(blank=True, related_name='club_administrator', to='users.Adherent'), + model_name="club", + name="administrators", + field=models.ManyToManyField( + blank=True, related_name="club_administrator", to="users.Adherent" + ), ), migrations.AddField( - model_name='club', - name='members', - field=models.ManyToManyField(blank=True, related_name='club_members', to='users.Adherent'), + model_name="club", + name="members", + field=models.ManyToManyField( + blank=True, related_name="club_members", to="users.Adherent" + ), ), ] diff --git a/users/migrations/0061_auto_20171230_2033.py b/users/migrations/0061_auto_20171230_2033.py index f2751fe2..198c5718 100644 --- a/users/migrations/0061_auto_20171230_2033.py +++ b/users/migrations/0061_auto_20171230_2033.py @@ -8,24 +8,42 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('auth', '0008_alter_user_username_max_length'), - ('users', '0060_auto_20171120_0317'), + ("auth", "0008_alter_user_username_max_length"), + ("users", "0060_auto_20171120_0317"), ] operations = [ migrations.AddField( - model_name='user', - name='groups', - field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups'), + model_name="user", + name="groups", + field=models.ManyToManyField( + blank=True, + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + related_name="user_set", + related_query_name="user", + to="auth.Group", + verbose_name="groups", + ), ), migrations.AddField( - model_name='user', - name='is_superuser', - field=models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status'), + model_name="user", + name="is_superuser", + field=models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), ), migrations.AddField( - model_name='user', - name='user_permissions', - field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'), + model_name="user", + name="user_permissions", + field=models.ManyToManyField( + blank=True, + help_text="Specific permissions for this user.", + related_name="user_set", + related_query_name="user", + to="auth.Permission", + verbose_name="user permissions", + ), ), ] diff --git a/users/migrations/0062_auto_20171231_0056.py b/users/migrations/0062_auto_20171231_0056.py index 2eaedb50..1815efd3 100644 --- a/users/migrations/0062_auto_20171231_0056.py +++ b/users/migrations/0062_auto_20171231_0056.py @@ -9,8 +9,8 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('auth', '0008_alter_user_username_max_length'), - ('users', '0061_auto_20171230_2033'), + ("auth", "0008_alter_user_username_max_length"), + ("users", "0061_auto_20171230_2033"), ] def create_groups(apps, schema_editor): @@ -19,26 +19,31 @@ class Migration(migrations.Migration): db_alias = schema_editor.connection.alias for gr in listrights.objects.using(db_alias).all(): grp = group() - grp.name=gr.unix_name + grp.name = gr.unix_name grp.save() - gr.group_ptr=grp + gr.group_ptr = grp gr.save() def delete_groups(apps, schema_editor): group = apps.get_model("auth", "Group") - db_alias = schema_editor.connection.alias + db_alias = schema_editor.connection.alias group.objects.using(db_alias).all().delete() operations = [ migrations.RenameField( - model_name='listright', - old_name='listright', - new_name='unix_name', + model_name="listright", old_name="listright", new_name="unix_name" ), migrations.AddField( - model_name='listright', - name='group_ptr', - field=models.OneToOneField(blank=True, null=True, auto_created=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='auth.Group'), + model_name="listright", + name="group_ptr", + field=models.OneToOneField( + blank=True, + null=True, + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + serialize=False, + to="auth.Group", + ), preserve_default=False, ), migrations.RunPython(create_groups, delete_groups), diff --git a/users/migrations/0063_auto_20171231_0140.py b/users/migrations/0063_auto_20171231_0140.py index 56762014..66d78a4a 100644 --- a/users/migrations/0063_auto_20171231_0140.py +++ b/users/migrations/0063_auto_20171231_0140.py @@ -8,22 +8,18 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0062_auto_20171231_0056'), - ] + dependencies = [("users", "0062_auto_20171231_0056")] def transfer_right(apps, schema_editor): rights = apps.get_model("users", "Right") db_alias = schema_editor.connection.alias for rg in rights.objects.using(db_alias).all(): group = rg.right - u=rg.user + u = rg.user u.groups.add(group.group_ptr) u.save() def untransfer_right(apps, schema_editor): return - operations = [ - migrations.RunPython(transfer_right, untransfer_right), - ] + operations = [migrations.RunPython(transfer_right, untransfer_right)] diff --git a/users/migrations/0064_auto_20171231_0150.py b/users/migrations/0064_auto_20171231_0150.py index a08561eb..daf0ecc0 100644 --- a/users/migrations/0064_auto_20171231_0150.py +++ b/users/migrations/0064_auto_20171231_0150.py @@ -8,34 +8,24 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0063_auto_20171231_0140'), - ] + dependencies = [("users", "0063_auto_20171231_0140")] operations = [ - migrations.AlterUniqueTogether( - name='right', - unique_together=set([]), - ), - migrations.RemoveField( - model_name='right', - name='right', - ), - migrations.RemoveField( - model_name='right', - name='user', - ), - migrations.DeleteModel( - name='Right', - ), - migrations.RemoveField( - model_name='listright', - name='id', - ), + migrations.AlterUniqueTogether(name="right", unique_together=set([])), + migrations.RemoveField(model_name="right", name="right"), + migrations.RemoveField(model_name="right", name="user"), + migrations.DeleteModel(name="Right"), + migrations.RemoveField(model_name="listright", name="id"), migrations.AlterField( - model_name='listright', - name='group_ptr', - field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='auth.Group'), + model_name="listright", + name="group_ptr", + field=models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="auth.Group", + ), ), - ] diff --git a/users/migrations/0065_auto_20171231_2053.py b/users/migrations/0065_auto_20171231_2053.py index 7f2d135b..4df4dcae 100644 --- a/users/migrations/0065_auto_20171231_2053.py +++ b/users/migrations/0065_auto_20171231_2053.py @@ -7,33 +7,53 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('users', '0064_auto_20171231_0150'), - ] + dependencies = [("users", "0064_auto_20171231_0150")] operations = [ migrations.AlterModelOptions( - name='ban', - options={'permissions': (('view_ban', "Peut voir un objet ban quelqu'il soit"),)}, + name="ban", + options={ + "permissions": (("view_ban", "Peut voir un objet ban quelqu'il soit"),) + }, ), migrations.AlterModelOptions( - name='listright', - options={'permissions': (('view_listright', 'Peut voir un objet Group/ListRight'),)}, + name="listright", + options={ + "permissions": ( + ("view_listright", "Peut voir un objet Group/ListRight"), + ) + }, ), migrations.AlterModelOptions( - name='school', - options={'permissions': (('view_school', 'Peut voir un objet school'),)}, + name="school", + options={"permissions": (("view_school", "Peut voir un objet school"),)}, ), migrations.AlterModelOptions( - name='serviceuser', - options={'permissions': (('view_serviceuser', 'Peut voir un objet serviceuser'),)}, + name="serviceuser", + options={ + "permissions": (("view_serviceuser", "Peut voir un objet serviceuser"),) + }, ), migrations.AlterModelOptions( - name='user', - options={'permissions': (('change_user_password', "Peut changer le mot de passe d'un user"), ('change_user_state', "Peut éditer l'etat d'un user"), ('change_user_force', 'Peut forcer un déménagement'), ('change_user_shell', "Peut éditer le shell d'un user"), ('change_user_groups', "Peut éditer les groupes d'un user ! Permission critique"), ('view_user', 'Peut voir un objet user quelquonque'))}, + name="user", + options={ + "permissions": ( + ("change_user_password", "Peut changer le mot de passe d'un user"), + ("change_user_state", "Peut éditer l'etat d'un user"), + ("change_user_force", "Peut forcer un déménagement"), + ("change_user_shell", "Peut éditer le shell d'un user"), + ( + "change_user_groups", + "Peut éditer les groupes d'un user ! Permission critique", + ), + ("view_user", "Peut voir un objet user quelquonque"), + ) + }, ), migrations.AlterModelOptions( - name='whitelist', - options={'permissions': (('view_whitelist', 'Peut voir un objet whitelist'),)}, + name="whitelist", + options={ + "permissions": (("view_whitelist", "Peut voir un objet whitelist"),) + }, ), ] diff --git a/users/migrations/0066_grouppermissions.py b/users/migrations/0066_grouppermissions.py index 090bb82c..c0e86b16 100644 --- a/users/migrations/0066_grouppermissions.py +++ b/users/migrations/0066_grouppermissions.py @@ -8,333 +8,347 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('users', '0065_auto_20171231_2053'), - ('cotisations', '0028_auto_20171231_0007'), - ('machines', '0071_auto_20171231_2100'), - ('preferences', '0025_auto_20171231_2142'), - ('topologie', '0033_auto_20171231_1743'), + ("users", "0065_auto_20171231_2053"), + ("cotisations", "0028_auto_20171231_0007"), + ("machines", "0071_auto_20171231_2100"), + ("preferences", "0025_auto_20171231_2142"), + ("topologie", "0033_auto_20171231_1743"), ] - def transfer_permissions(apps, schema_editor): - permission_groups = {'bofh': ['add_ban', - 'change_ban', - 'delete_ban', - 'view_ban', - 'add_club', - 'change_club', - 'delete_club', - 'add_user', - 'change_user', - 'change_user_force', - 'change_user_password', - 'change_user_shell', - 'view_user', - 'add_whitelist', - 'change_whitelist', - 'delete_whitelist', - 'view_whitelist'], - 'bureau': ['add_logentry', - 'change_logentry', - 'delete_logentry', - 'add_group', - 'change_group', - 'delete_group', - 'add_permission', - 'change_permission', - 'delete_permission', - 'add_adherent', - 'change_adherent', - 'delete_adherent', - 'add_ban', - 'change_ban', - 'delete_ban', - 'view_ban', - 'add_club', - 'change_club', - 'delete_club', - 'add_listright', - 'change_listright', - 'delete_listright', - 'view_listright', - 'add_school', - 'change_school', - 'delete_school', - 'view_school', - 'add_user', - 'change_user', - 'change_user_force', - 'change_user_groups', - 'change_user_password', - 'change_user_shell', - 'change_user_state', - 'delete_user', - 'view_user', - 'add_whitelist', - 'change_whitelist', - 'delete_whitelist', - 'view_whitelist'], - 'cableur': ['add_logentry', - 'view_article', - 'add_banque', - 'change_banque', - 'delete_banque', - 'view_banque', - 'add_cotisation', - 'change_cotisation', - 'delete_cotisation', - 'view_cotisation', - 'add_facture', - 'can_create', - 'can_delete', - 'can_edit', - 'can_view', - 'can_view_all', - 'change_facture', - 'delete_facture', - 'view_facture', - 'view_paiement', - 'add_vente', - 'change_vente', - 'delete_vente', - 'view_vente', - 'add_domain', - 'change_domain', - 'delete_domain', - 'view_domain', - 'use_all_extension', - 'view_extension', - 'add_interface', - 'change_interface', - 'delete_interface', - 'view_interface', - 'view_iplist', - 'view_iptype', - 'add_machine', - 'change_machine', - 'view_machine', - 'view_machinetype', - 'view_mx', - 'view_nas', - 'view_ns', - 'view_ouvertureportlist', - 'view_service', - 'view_soa', - 'view_soa', - 'view_txt', - 'view_vlan', - 'view_assooption', - 'view_generaloption', - 'view_mailmessageoption', - 'view_optionalmachine', - 'view_optionaltopologie', - 'view_optionaluser', - 'view_service', - 'view_constructorswitch', - 'view_modelswitch', - 'view_port', - 'view_room', - 'view_stack', - 'view_switch', - 'add_adherent', - 'change_adherent', - 'view_ban', - 'add_club', - 'change_club', - 'view_listright', - 'add_school', - 'change_school', - 'delete_school', - 'view_school', - 'view_serviceuser', - 'add_user', - 'change_user', - 'change_user_force', - 'change_user_password', - 'view_user', - 'add_whitelist', - 'change_whitelist', - 'delete_whitelist', - 'view_whitelist'], - 'tresorier': ['add_article', - 'change_article', - 'delete_article', - 'view_article', - 'add_banque', - 'change_banque', - 'delete_banque', - 'view_banque', - 'add_cotisation', - 'change_all_cotisation', - 'change_cotisation', - 'delete_cotisation', - 'view_cotisation', - 'add_facture', - 'can_change_control', - 'can_change_pdf', - 'can_create', - 'can_delete', - 'can_edit', - 'can_view', - 'can_view_all', - 'change_all_facture', - 'change_facture', - 'change_facture_control', - 'change_facture_pdf', - 'delete_facture', - 'view_facture', - 'add_paiement', - 'change_paiement', - 'delete_paiement', - 'view_paiement', - 'add_vente', - 'change_all_vente', - 'change_vente', - 'delete_vente', - 'view_vente'], - 'admin': ['add_logentry', - 'change_logentry', - 'delete_logentry', - 'add_assooption', - 'change_assooption', - 'delete_assooption', - 'view_assooption', - 'add_generaloption', - 'change_generaloption', - 'delete_generaloption', - 'view_generaloption', - 'add_mailmessageoption', - 'change_mailmessageoption', - 'delete_mailmessageoption', - 'view_mailmessageoption', - 'add_optionalmachine', - 'change_optionalmachine', - 'delete_optionalmachine', - 'view_optionalmachine', - 'add_optionaltopologie', - 'change_optionaltopologie', - 'delete_optionaltopologie', - 'view_optionaltopologie', - 'add_optionaluser', - 'change_optionaluser', - 'delete_optionaluser', - 'view_optionaluser', - 'add_service', - 'add_services', - 'change_service', - 'change_services', - 'delete_service', - 'delete_services', - 'view_service'], - 'infra': ['add_domain', - 'change_domain', - 'delete_domain', - 'view_domain', - 'add_extension', - 'change_extension', - 'delete_extension', - 'use_all_extension', - 'view_extension', - 'add_interface', - 'change_interface', - 'delete_interface', - 'view_interface', - 'add_iplist', - 'change_iplist', - 'delete_iplist', - 'view_iplist', - 'add_iptype', - 'change_iptype', - 'delete_iptype', - 'use_all_iptype', - 'view_iptype', - 'add_machine', - 'change_machine', - 'change_machine_user', - 'delete_machine', - 'view_machine', - 'add_machinetype', - 'change_machinetype', - 'delete_machinetype', - 'use_all_machinetype', - 'view_machinetype', - 'add_mx', - 'change_mx', - 'delete_mx', - 'view_mx', - 'add_nas', - 'change_nas', - 'delete_nas', - 'view_nas', - 'add_ns', - 'change_ns', - 'delete_ns', - 'view_ns', - 'add_ouvertureport', - 'change_ouvertureport', - 'delete_ouvertureport', - 'add_ouvertureportlist', - 'change_ouvertureportlist', - 'delete_ouvertureportlist', - 'view_ouvertureportlist', - 'add_service', - 'change_service', - 'delete_service', - 'view_service', - 'add_service_link', - 'change_service_link', - 'delete_service_link', - 'add_soa', - 'change_soa', - 'delete_soa', - 'view_soa', - 'add_srv', - 'change_srv', - 'delete_srv', - 'view_soa', - 'add_text', - 'add_txt', - 'change_text', - 'change_txt', - 'delete_text', - 'delete_txt', - 'view_txt', - 'add_vlan', - 'change_vlan', - 'delete_vlan', - 'view_vlan', - 'add_constructorswitch', - 'change_constructorswitch', - 'delete_constructorswitch', - 'view_constructorswitch', - 'add_modelswitch', - 'change_modelswitch', - 'delete_modelswitch', - 'view_modelswitch', - 'add_port', - 'change_port', - 'delete_port', - 'view_port', - 'add_room', - 'change_room', - 'delete_room', - 'view_room', - 'add_stack', - 'change_stack', - 'delete_stack', - 'view_stack', - 'add_switch', - 'change_switch', - 'delete_switch', - 'view_switch', - 'add_listshell', - 'change_listshell', - 'delete_listshell', - 'add_serviceuser', - 'change_serviceuser', - 'delete_serviceuser', - 'view_serviceuser', - 'change_user', - 'view_user']} + def transfer_permissions(apps, schema_editor): + permission_groups = { + "bofh": [ + "add_ban", + "change_ban", + "delete_ban", + "view_ban", + "add_club", + "change_club", + "delete_club", + "add_user", + "change_user", + "change_user_force", + "change_user_password", + "change_user_shell", + "view_user", + "add_whitelist", + "change_whitelist", + "delete_whitelist", + "view_whitelist", + ], + "bureau": [ + "add_logentry", + "change_logentry", + "delete_logentry", + "add_group", + "change_group", + "delete_group", + "add_permission", + "change_permission", + "delete_permission", + "add_adherent", + "change_adherent", + "delete_adherent", + "add_ban", + "change_ban", + "delete_ban", + "view_ban", + "add_club", + "change_club", + "delete_club", + "add_listright", + "change_listright", + "delete_listright", + "view_listright", + "add_school", + "change_school", + "delete_school", + "view_school", + "add_user", + "change_user", + "change_user_force", + "change_user_groups", + "change_user_password", + "change_user_shell", + "change_user_state", + "delete_user", + "view_user", + "add_whitelist", + "change_whitelist", + "delete_whitelist", + "view_whitelist", + ], + "cableur": [ + "add_logentry", + "view_article", + "add_banque", + "change_banque", + "delete_banque", + "view_banque", + "add_cotisation", + "change_cotisation", + "delete_cotisation", + "view_cotisation", + "add_facture", + "can_create", + "can_delete", + "can_edit", + "can_view", + "can_view_all", + "change_facture", + "delete_facture", + "view_facture", + "view_paiement", + "add_vente", + "change_vente", + "delete_vente", + "view_vente", + "add_domain", + "change_domain", + "delete_domain", + "view_domain", + "use_all_extension", + "view_extension", + "add_interface", + "change_interface", + "delete_interface", + "view_interface", + "view_iplist", + "view_iptype", + "add_machine", + "change_machine", + "view_machine", + "view_machinetype", + "view_mx", + "view_nas", + "view_ns", + "view_ouvertureportlist", + "view_service", + "view_soa", + "view_soa", + "view_txt", + "view_vlan", + "view_assooption", + "view_generaloption", + "view_mailmessageoption", + "view_optionalmachine", + "view_optionaltopologie", + "view_optionaluser", + "view_service", + "view_constructorswitch", + "view_modelswitch", + "view_port", + "view_room", + "view_stack", + "view_switch", + "add_adherent", + "change_adherent", + "view_ban", + "add_club", + "change_club", + "view_listright", + "add_school", + "change_school", + "delete_school", + "view_school", + "view_serviceuser", + "add_user", + "change_user", + "change_user_force", + "change_user_password", + "view_user", + "add_whitelist", + "change_whitelist", + "delete_whitelist", + "view_whitelist", + ], + "tresorier": [ + "add_article", + "change_article", + "delete_article", + "view_article", + "add_banque", + "change_banque", + "delete_banque", + "view_banque", + "add_cotisation", + "change_all_cotisation", + "change_cotisation", + "delete_cotisation", + "view_cotisation", + "add_facture", + "can_change_control", + "can_change_pdf", + "can_create", + "can_delete", + "can_edit", + "can_view", + "can_view_all", + "change_all_facture", + "change_facture", + "change_facture_control", + "change_facture_pdf", + "delete_facture", + "view_facture", + "add_paiement", + "change_paiement", + "delete_paiement", + "view_paiement", + "add_vente", + "change_all_vente", + "change_vente", + "delete_vente", + "view_vente", + ], + "admin": [ + "add_logentry", + "change_logentry", + "delete_logentry", + "add_assooption", + "change_assooption", + "delete_assooption", + "view_assooption", + "add_generaloption", + "change_generaloption", + "delete_generaloption", + "view_generaloption", + "add_mailmessageoption", + "change_mailmessageoption", + "delete_mailmessageoption", + "view_mailmessageoption", + "add_optionalmachine", + "change_optionalmachine", + "delete_optionalmachine", + "view_optionalmachine", + "add_optionaltopologie", + "change_optionaltopologie", + "delete_optionaltopologie", + "view_optionaltopologie", + "add_optionaluser", + "change_optionaluser", + "delete_optionaluser", + "view_optionaluser", + "add_service", + "add_services", + "change_service", + "change_services", + "delete_service", + "delete_services", + "view_service", + ], + "infra": [ + "add_domain", + "change_domain", + "delete_domain", + "view_domain", + "add_extension", + "change_extension", + "delete_extension", + "use_all_extension", + "view_extension", + "add_interface", + "change_interface", + "delete_interface", + "view_interface", + "add_iplist", + "change_iplist", + "delete_iplist", + "view_iplist", + "add_iptype", + "change_iptype", + "delete_iptype", + "use_all_iptype", + "view_iptype", + "add_machine", + "change_machine", + "change_machine_user", + "delete_machine", + "view_machine", + "add_machinetype", + "change_machinetype", + "delete_machinetype", + "use_all_machinetype", + "view_machinetype", + "add_mx", + "change_mx", + "delete_mx", + "view_mx", + "add_nas", + "change_nas", + "delete_nas", + "view_nas", + "add_ns", + "change_ns", + "delete_ns", + "view_ns", + "add_ouvertureport", + "change_ouvertureport", + "delete_ouvertureport", + "add_ouvertureportlist", + "change_ouvertureportlist", + "delete_ouvertureportlist", + "view_ouvertureportlist", + "add_service", + "change_service", + "delete_service", + "view_service", + "add_service_link", + "change_service_link", + "delete_service_link", + "add_soa", + "change_soa", + "delete_soa", + "view_soa", + "add_srv", + "change_srv", + "delete_srv", + "view_soa", + "add_text", + "add_txt", + "change_text", + "change_txt", + "delete_text", + "delete_txt", + "view_txt", + "add_vlan", + "change_vlan", + "delete_vlan", + "view_vlan", + "add_constructorswitch", + "change_constructorswitch", + "delete_constructorswitch", + "view_constructorswitch", + "add_modelswitch", + "change_modelswitch", + "delete_modelswitch", + "view_modelswitch", + "add_port", + "change_port", + "delete_port", + "view_port", + "add_room", + "change_room", + "delete_room", + "view_room", + "add_stack", + "change_stack", + "delete_stack", + "view_stack", + "add_switch", + "change_switch", + "delete_switch", + "view_switch", + "add_listshell", + "change_listshell", + "delete_listshell", + "add_serviceuser", + "change_serviceuser", + "delete_serviceuser", + "view_serviceuser", + "change_user", + "view_user", + ], + } rights = apps.get_model("users", "ListRight") permissions = apps.get_model("auth", "Permission") @@ -343,16 +357,22 @@ class Migration(migrations.Migration): for group in permission_groups: lr_object = rights.objects.using(db_alias).filter(unix_name=group).first() if not lr_object: - last = rights.objects.using(db_alias).all().order_by('gid').last() + last = rights.objects.using(db_alias).all().order_by("gid").last() if last: gid = last.gid + 1 else: gid = 501 group_object = groups.objects.using(db_alias).create(name=group) - lr_object = rights.objects.using(db_alias).create(unix_name=group, gid=gid, group_ptr=group_object) + lr_object = rights.objects.using(db_alias).create( + unix_name=group, gid=gid, group_ptr=group_object + ) lr_object = lr_object.group_ptr for permission in permission_groups[group]: - perm = permissions.objects.using(db_alias).filter(codename=permission).first() + perm = ( + permissions.objects.using(db_alias) + .filter(codename=permission) + .first() + ) if perm: lr_object.permissions.add(perm) lr_object.save() @@ -360,6 +380,4 @@ class Migration(migrations.Migration): def untransfer_permissions(apps, schema_editor): return - operations = [ - migrations.RunPython(transfer_permissions, untransfer_permissions), - ] + operations = [migrations.RunPython(transfer_permissions, untransfer_permissions)] diff --git a/users/migrations/0067_serveurpermission.py b/users/migrations/0067_serveurpermission.py index a5ea8387..d1c73347 100644 --- a/users/migrations/0067_serveurpermission.py +++ b/users/migrations/0067_serveurpermission.py @@ -7,30 +7,32 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('users', '0066_grouppermissions'), - ] + dependencies = [("users", "0066_grouppermissions")] def transfer_permissions(apps, schema_editor): db_alias = schema_editor.connection.alias - contenttype = apps.get_model("contenttypes", "ContentType") + contenttype = apps.get_model("contenttypes", "ContentType") rights = apps.get_model("users", "ListRight") permissions = apps.get_model("auth", "Permission") groups = apps.get_model("auth", "Group") machine = apps.get_model("machines", "Machine") - perm = permissions.objects.using(db_alias).filter(codename='serveur').first() + perm = permissions.objects.using(db_alias).filter(codename="serveur").first() if not perm: perm = permissions.objects.using(db_alias).create( - codename='serveur', - name='Serveur', - content_type=contenttype.objects.get_for_model(machine) + codename="serveur", + name="Serveur", + content_type=contenttype.objects.get_for_model(machine), ) - group_object = rights.objects.using(db_alias).filter(unix_name='serveur').first() + group_object = ( + rights.objects.using(db_alias).filter(unix_name="serveur").first() + ) if not group_object: - last_gid = rights.objects.using(db_alias).all().order_by('gid').last().gid + last_gid = rights.objects.using(db_alias).all().order_by("gid").last().gid gid = last_gid + 1 - abstract_group = groups.objects.using(db_alias).create(name='serveur') - group_object = rights.objects.using(db_alias).create(group_ptr=abstract_group, unix_name='serveur', gid=gid) + abstract_group = groups.objects.using(db_alias).create(name="serveur") + group_object = rights.objects.using(db_alias).create( + group_ptr=abstract_group, unix_name="serveur", gid=gid + ) group_object = group_object.group_ptr group_object.permissions.add(perm) group_object.save() @@ -38,6 +40,4 @@ class Migration(migrations.Migration): def untransfer_permissions(apps, schema_editor): return - operations = [ - migrations.RunPython(transfer_permissions, untransfer_permissions), - ] + operations = [migrations.RunPython(transfer_permissions, untransfer_permissions)] diff --git a/users/migrations/0068_auto_20180107_2245.py b/users/migrations/0068_auto_20180107_2245.py index 27c4f446..a1dcee4f 100644 --- a/users/migrations/0068_auto_20180107_2245.py +++ b/users/migrations/0068_auto_20180107_2245.py @@ -7,18 +7,24 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0067_serveurpermission'), - ] + dependencies = [("users", "0067_serveurpermission")] def transfer_permissions(apps, schema_editor): - critical_rights = ['adm', 'admin', 'bureau', 'infra', 'tresorier', 'serveur', 'bofh'] + critical_rights = [ + "adm", + "admin", + "bureau", + "infra", + "tresorier", + "serveur", + "bofh", + ] db_alias = schema_editor.connection.alias rights = apps.get_model("users", "ListRight") for right in critical_rights: rg = rights.objects.using(db_alias).filter(unix_name=right).first() if rg: - rg.critical=True + rg.critical = True rg.save() def untransfer_permissions(apps, schema_editor): @@ -26,12 +32,28 @@ class Migration(migrations.Migration): operations = [ migrations.AlterModelOptions( - name='user', - options={'permissions': (('change_user_password', "Peut changer le mot de passe d'un user"), ('change_user_state', "Peut éditer l'etat d'un user"), ('change_user_force', 'Peut forcer un déménagement'), ('change_user_shell', "Peut éditer le shell d'un user"), ('change_user_groups', "Peut éditer les groupes d'un user ! Permission critique"), ('change_all_users', 'Peut éditer tous les users, y compris ceux dotés de droits. Superdroit'), ('view_user', 'Peut voir un objet user quelquonque'))}, + name="user", + options={ + "permissions": ( + ("change_user_password", "Peut changer le mot de passe d'un user"), + ("change_user_state", "Peut éditer l'etat d'un user"), + ("change_user_force", "Peut forcer un déménagement"), + ("change_user_shell", "Peut éditer le shell d'un user"), + ( + "change_user_groups", + "Peut éditer les groupes d'un user ! Permission critique", + ), + ( + "change_all_users", + "Peut éditer tous les users, y compris ceux dotés de droits. Superdroit", + ), + ("view_user", "Peut voir un objet user quelquonque"), + ) + }, ), migrations.AddField( - model_name='listright', - name='critical', + model_name="listright", + name="critical", field=models.BooleanField(default=False), ), migrations.RunPython(transfer_permissions, untransfer_permissions), diff --git a/users/migrations/0069_club_mailing.py b/users/migrations/0069_club_mailing.py index 17970494..4d72df8d 100644 --- a/users/migrations/0069_club_mailing.py +++ b/users/migrations/0069_club_mailing.py @@ -7,14 +7,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0068_auto_20180107_2245'), - ] + dependencies = [("users", "0068_auto_20180107_2245")] operations = [ migrations.AddField( - model_name='club', - name='mailing', - field=models.BooleanField(default=False), - ), + model_name="club", name="mailing", field=models.BooleanField(default=False) + ) ] diff --git a/users/migrations/0070_auto_20180324_1906.py b/users/migrations/0070_auto_20180324_1906.py index fe6ae790..dc44344e 100644 --- a/users/migrations/0070_auto_20180324_1906.py +++ b/users/migrations/0070_auto_20180324_1906.py @@ -7,13 +7,15 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('users', '0069_club_mailing'), - ] + dependencies = [("users", "0069_club_mailing")] operations = [ migrations.AlterModelOptions( - name='listshell', - options={'permissions': (('view_listshell', "Peut voir un objet shell quelqu'il soit"),)}, - ), + name="listshell", + options={ + "permissions": ( + ("view_listshell", "Peut voir un objet shell quelqu'il soit"), + ) + }, + ) ] diff --git a/users/migrations/0071_auto_20180415_1252.py b/users/migrations/0071_auto_20180415_1252.py index faf56a5b..ddaf1a65 100644 --- a/users/migrations/0071_auto_20180415_1252.py +++ b/users/migrations/0071_auto_20180415_1252.py @@ -8,14 +8,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0070_auto_20180324_1906'), - ] + dependencies = [("users", "0070_auto_20180324_1906")] operations = [ migrations.AlterField( - model_name='listright', - name='unix_name', - 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')]), - ), + model_name="listright", + name="unix_name", + 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", + ) + ], + ), + ) ] diff --git a/users/migrations/0072_auto_20180426_2021.py b/users/migrations/0072_auto_20180426_2021.py index f60103e0..be4c8aab 100644 --- a/users/migrations/0072_auto_20180426_2021.py +++ b/users/migrations/0072_auto_20180426_2021.py @@ -7,19 +7,13 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0071_auto_20180415_1252'), - ] + dependencies = [("users", "0071_auto_20180415_1252")] operations = [ migrations.AlterField( - model_name='ban', - name='date_end', - field=models.DateTimeField(), + model_name="ban", name="date_end", field=models.DateTimeField() ), migrations.AlterField( - model_name='whitelist', - name='date_end', - field=models.DateTimeField(), + model_name="whitelist", name="date_end", field=models.DateTimeField() ), ] diff --git a/users/migrations/0073_auto_20180629_1614.py b/users/migrations/0073_auto_20180629_1614.py index 72ebffe6..ebcc1bd0 100644 --- a/users/migrations/0073_auto_20180629_1614.py +++ b/users/migrations/0073_auto_20180629_1614.py @@ -9,7 +9,6 @@ import re2o.mixins class Migration(migrations.Migration): - def create_initial_email_address(apps, schema_editor): db_alias = schema_editor.connection.alias User = apps.get_model("users", "User") @@ -17,8 +16,7 @@ class Migration(migrations.Migration): users = User.objects.using(db_alias).all() for user in users: EMailAddress.objects.using(db_alias).create( - local_part=user.pseudo, - user=user + local_part=user.pseudo, user=user ) def delete_all_email_address(apps, schema_editor): @@ -26,32 +24,62 @@ class Migration(migrations.Migration): EMailAddress = apps.get_model("users", "EMailAddress") EMailAddress.objects.using(db_alias).delete() - dependencies = [ - ('users', '0072_auto_20180426_2021'), - ] + dependencies = [("users", "0072_auto_20180426_2021")] operations = [ migrations.CreateModel( - name='EMailAddress', + name="EMailAddress", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('local_part', models.CharField(help_text="Local part of the email address", max_length=128, unique=True)), - ('user', models.ForeignKey(help_text='User of the local email', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "local_part", + models.CharField( + help_text="Local part of the email address", + max_length=128, + unique=True, + ), + ), + ( + "user", + models.ForeignKey( + help_text="User of the local email", + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), ], bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), - options={'permissions': (('view_emailaddress', 'Can see a local email account object'),), 'verbose_name': 'Local email account', 'verbose_name_plural': 'Local email accounts'}, + options={ + "permissions": ( + ("view_emailaddress", "Can see a local email account object"), + ), + "verbose_name": "Local email account", + "verbose_name_plural": "Local email accounts", + }, ), migrations.AddField( - model_name='user', - name='local_email_enabled', - field=models.BooleanField(default=False, help_text="Wether or not to enable the local email account."), + model_name="user", + name="local_email_enabled", + field=models.BooleanField( + default=False, + help_text="Wether or not to enable the local email account.", + ), ), migrations.AddField( - model_name='user', - name='local_email_redirect', - field=models.BooleanField(default=False, help_text='Whether or not to redirect the local email messages to the main email.'), + model_name="user", + name="local_email_redirect", + field=models.BooleanField( + default=False, + help_text="Whether or not to redirect the local email messages to the main email.", + ), ), - migrations.RunPython(create_initial_email_address, - delete_all_email_address), + migrations.RunPython(create_initial_email_address, delete_all_email_address), ] - diff --git a/users/migrations/0074_auto_20180810_2104.py b/users/migrations/0074_auto_20180810_2104.py index bc32a266..35fdc0cd 100644 --- a/users/migrations/0074_auto_20180810_2104.py +++ b/users/migrations/0074_auto_20180810_2104.py @@ -9,14 +9,22 @@ import users.models class Migration(migrations.Migration): - dependencies = [ - ('users', '0073_auto_20180629_1614'), - ] + dependencies = [("users", "0073_auto_20180629_1614")] operations = [ migrations.AddField( - model_name='adherent', - name='gpg_fingerprint', - field=models.CharField(blank=True, max_length=40, null=True, validators=[django.core.validators.RegexValidator('^[0-9A-F]{40}$', message='Une fingerprint GPG doit contenir 40 caractères hexadécimaux')]), - ), + model_name="adherent", + name="gpg_fingerprint", + field=models.CharField( + blank=True, + max_length=40, + null=True, + validators=[ + django.core.validators.RegexValidator( + "^[0-9A-F]{40}$", + message="Une fingerprint GPG doit contenir 40 caractères hexadécimaux", + ) + ], + ), + ) ] diff --git a/users/migrations/0074_auto_20180814_1059.py b/users/migrations/0074_auto_20180814_1059.py index e3e8527f..4bac3095 100644 --- a/users/migrations/0074_auto_20180814_1059.py +++ b/users/migrations/0074_auto_20180814_1059.py @@ -7,24 +7,32 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0073_auto_20180629_1614'), - ] + dependencies = [("users", "0073_auto_20180629_1614")] operations = [ migrations.AlterField( - model_name='user', - name='email', - field=models.EmailField(blank=True, null=True, help_text='External email address allowing us to contact you.', max_length=254), + model_name="user", + name="email", + field=models.EmailField( + blank=True, + null=True, + help_text="External email address allowing us to contact you.", + max_length=254, + ), ), migrations.AlterField( - model_name='user', - name='local_email_enabled', - field=models.BooleanField(default=False, help_text='Enable the local email account.'), + model_name="user", + name="local_email_enabled", + field=models.BooleanField( + default=False, help_text="Enable the local email account." + ), ), migrations.AlterField( - model_name='user', - name='local_email_redirect', - field=models.BooleanField(default=False, help_text='Enable redirection of the local email messages to the main email.'), + model_name="user", + name="local_email_redirect", + field=models.BooleanField( + default=False, + help_text="Enable redirection of the local email messages to the main email.", + ), ), ] diff --git a/users/migrations/0075_merge_20180815_2202.py b/users/migrations/0075_merge_20180815_2202.py index c24ebf4e..6d22d0c9 100644 --- a/users/migrations/0075_merge_20180815_2202.py +++ b/users/migrations/0075_merge_20180815_2202.py @@ -8,9 +8,8 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('users', '0074_auto_20180814_1059'), - ('users', '0074_auto_20180810_2104'), + ("users", "0074_auto_20180814_1059"), + ("users", "0074_auto_20180810_2104"), ] - operations = [ - ] + operations = [] diff --git a/users/migrations/0076_auto_20180818_1321.py b/users/migrations/0076_auto_20180818_1321.py index 95af1422..f310f715 100644 --- a/users/migrations/0076_auto_20180818_1321.py +++ b/users/migrations/0076_auto_20180818_1321.py @@ -11,99 +11,196 @@ import users.models class Migration(migrations.Migration): - dependencies = [ - ('users', '0075_merge_20180815_2202'), - ] + dependencies = [("users", "0075_merge_20180815_2202")] operations = [ migrations.AlterModelOptions( - name='adherent', - options={'verbose_name': 'member', 'verbose_name_plural': 'members'}, + name="adherent", + options={"verbose_name": "member", "verbose_name_plural": "members"}, ), migrations.AlterModelOptions( - name='ban', - options={'permissions': (('view_ban', 'Can view a ban object'),), 'verbose_name': 'ban', 'verbose_name_plural': 'bans'}, + name="ban", + options={ + "permissions": (("view_ban", "Can view a ban object"),), + "verbose_name": "ban", + "verbose_name_plural": "bans", + }, ), migrations.AlterModelOptions( - name='club', - options={'verbose_name': 'club', 'verbose_name_plural': 'clubs'}, + name="club", + options={"verbose_name": "club", "verbose_name_plural": "clubs"}, ), migrations.AlterModelOptions( - name='emailaddress', - options={'permissions': (('view_emailaddress', 'Can view a local email account object'),), 'verbose_name': 'local email account', 'verbose_name_plural': 'local email accounts'}, + name="emailaddress", + options={ + "permissions": ( + ("view_emailaddress", "Can view a local email account object"), + ), + "verbose_name": "local email account", + "verbose_name_plural": "local email accounts", + }, ), migrations.AlterModelOptions( - name='listright', - options={'permissions': (('view_listright', 'Can view a group of rights object'),), 'verbose_name': 'group of rights', 'verbose_name_plural': 'groups of rights'}, + name="listright", + options={ + "permissions": ( + ("view_listright", "Can view a group of rights object"), + ), + "verbose_name": "group of rights", + "verbose_name_plural": "groups of rights", + }, ), migrations.AlterModelOptions( - name='listshell', - options={'permissions': (('view_listshell', 'Can view a shell object'),), 'verbose_name': 'shell', 'verbose_name_plural': 'shells'}, + name="listshell", + options={ + "permissions": (("view_listshell", "Can view a shell object"),), + "verbose_name": "shell", + "verbose_name_plural": "shells", + }, ), migrations.AlterModelOptions( - name='school', - options={'permissions': (('view_school', 'Can view a school object'),), 'verbose_name': 'school', 'verbose_name_plural': 'schools'}, + name="school", + options={ + "permissions": (("view_school", "Can view a school object"),), + "verbose_name": "school", + "verbose_name_plural": "schools", + }, ), migrations.AlterModelOptions( - name='serviceuser', - options={'permissions': (('view_serviceuser', 'Can view a service user object'),), 'verbose_name': 'service user', 'verbose_name_plural': 'service users'}, + name="serviceuser", + options={ + "permissions": ( + ("view_serviceuser", "Can view a service user object"), + ), + "verbose_name": "service user", + "verbose_name_plural": "service users", + }, ), migrations.AlterModelOptions( - name='user', - options={'permissions': (('change_user_password', 'Can change the password of a user'), ('change_user_state', 'Can edit the state of a user'), ('change_user_force', 'Can force the move'), ('change_user_shell', 'Can edit the shell of a user'), ('change_user_groups', 'Can edit the groups of rights of a user (critical permission)'), ('change_all_users', 'Can edit all users, including those with rights.'), ('view_user', 'Can view a user object')), 'verbose_name': 'user (member or club)', 'verbose_name_plural': 'users (members or clubs)'}, + name="user", + options={ + "permissions": ( + ("change_user_password", "Can change the password of a user"), + ("change_user_state", "Can edit the state of a user"), + ("change_user_force", "Can force the move"), + ("change_user_shell", "Can edit the shell of a user"), + ( + "change_user_groups", + "Can edit the groups of rights of a user (critical permission)", + ), + ( + "change_all_users", + "Can edit all users, including those with rights.", + ), + ("view_user", "Can view a user object"), + ), + "verbose_name": "user (member or club)", + "verbose_name_plural": "users (members or clubs)", + }, ), migrations.AlterModelOptions( - name='whitelist', - options={'permissions': (('view_whitelist', 'Can view a whitelist object'),), 'verbose_name': 'whitelist (free of charge access)', 'verbose_name_plural': 'whitelists (free of charge access)'}, + name="whitelist", + options={ + "permissions": (("view_whitelist", "Can view a whitelist object"),), + "verbose_name": "whitelist (free of charge access)", + "verbose_name_plural": "whitelists (free of charge access)", + }, ), migrations.AlterField( - model_name='adherent', - name='gpg_fingerprint', - field=models.CharField(blank=True, max_length=40, null=True, validators=[django.core.validators.RegexValidator('^[0-9A-F]{40}$', message='A GPG fingerprint must contain 40 hexadecimal characters.')]), + model_name="adherent", + name="gpg_fingerprint", + field=models.CharField( + blank=True, + max_length=40, + null=True, + validators=[ + django.core.validators.RegexValidator( + "^[0-9A-F]{40}$", + message="A GPG fingerprint must contain 40 hexadecimal characters.", + ) + ], + ), ), migrations.AlterField( - model_name='ban', - name='state', - field=models.IntegerField(choices=[(0, 'HARD (no access)'), (1, 'SOFT (local access only)'), (2, 'RESTRICTED (speed limitation)')], default=0), + model_name="ban", + name="state", + field=models.IntegerField( + choices=[ + (0, "HARD (no access)"), + (1, "SOFT (local access only)"), + (2, "RESTRICTED (speed limitation)"), + ], + default=0, + ), ), migrations.AlterField( - model_name='emailaddress', - name='user', - field=models.ForeignKey(help_text='User of the local email account', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + model_name="emailaddress", + name="user", + field=models.ForeignKey( + help_text="User of the local email account", + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), ), migrations.AlterField( - model_name='listright', - name='unix_name', - field=models.CharField(max_length=255, unique=True, validators=[django.core.validators.RegexValidator('^[a-z]+$', message='UNIX groups can only contain lower case letters.')]), + model_name="listright", + name="unix_name", + field=models.CharField( + max_length=255, + unique=True, + validators=[ + django.core.validators.RegexValidator( + "^[a-z]+$", + message="UNIX groups can only contain lower case letters.", + ) + ], + ), ), migrations.AlterField( - model_name='request', - name='type', - field=models.CharField(choices=[('PW', 'Password'), ('EM', 'Email address')], max_length=2), + model_name="request", + name="type", + field=models.CharField( + choices=[("PW", "Password"), ("EM", "Email address")], max_length=2 + ), ), migrations.AlterField( - model_name='serviceuser', - name='comment', - field=models.CharField(blank=True, help_text='Comment', max_length=255), + model_name="serviceuser", + name="comment", + field=models.CharField(blank=True, help_text="Comment", max_length=255), ), migrations.AlterField( - model_name='serviceuser', - name='pseudo', - field=models.CharField(help_text='Must only contain letters, numerals or dashes.', max_length=32, unique=True, validators=[users.models.linux_user_validator]), + model_name="serviceuser", + name="pseudo", + field=models.CharField( + help_text="Must only contain letters, numerals or dashes.", + max_length=32, + unique=True, + validators=[users.models.linux_user_validator], + ), ), migrations.AlterField( - model_name='user', - name='comment', - field=models.CharField(blank=True, help_text='Comment, school year', max_length=255), + model_name="user", + name="comment", + field=models.CharField( + blank=True, help_text="Comment, school year", max_length=255 + ), ), migrations.AlterField( - model_name='user', - name='local_email_redirect', - field=models.BooleanField(default=False, help_text='Enable redirection of the local email messages to the main email address.'), + model_name="user", + name="local_email_redirect", + field=models.BooleanField( + default=False, + help_text="Enable redirection of the local email messages to the main email address.", + ), ), migrations.AlterField( - model_name='user', - name='pseudo', - field=models.CharField(help_text='Must only contain letters, numerals or dashes.', max_length=32, unique=True, validators=[users.models.linux_user_validator]), + model_name="user", + name="pseudo", + field=models.CharField( + help_text="Must only contain letters, numerals or dashes.", + max_length=32, + unique=True, + validators=[users.models.linux_user_validator], + ), ), ] diff --git a/users/migrations/0077_auto_20180824_1750.py b/users/migrations/0077_auto_20180824_1750.py index b9510257..194bc247 100644 --- a/users/migrations/0077_auto_20180824_1750.py +++ b/users/migrations/0077_auto_20180824_1750.py @@ -7,14 +7,20 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0076_auto_20180818_1321'), - ] + dependencies = [("users", "0076_auto_20180818_1321")] operations = [ migrations.AlterField( - model_name='user', - name='state', - field=models.IntegerField(choices=[(0, 'STATE_ACTIVE'), (1, 'STATE_DISABLED'), (2, 'STATE_ARCHIVE'), (3, 'STATE_NOT_YET_ACTIVE')], default=3), - ), + model_name="user", + name="state", + field=models.IntegerField( + choices=[ + (0, "STATE_ACTIVE"), + (1, "STATE_DISABLED"), + (2, "STATE_ARCHIVE"), + (3, "STATE_NOT_YET_ACTIVE"), + ], + default=3, + ), + ) ] diff --git a/users/migrations/0078_auto_20181011_1405.py b/users/migrations/0078_auto_20181011_1405.py index 6046d2e4..cde58630 100644 --- a/users/migrations/0078_auto_20181011_1405.py +++ b/users/migrations/0078_auto_20181011_1405.py @@ -9,14 +9,14 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('users', '0077_auto_20180824_1750'), - ] + dependencies = [("users", "0077_auto_20180824_1750")] operations = [ migrations.AlterField( - model_name='request', - name='user', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), + model_name="request", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + ), + ) ] diff --git a/users/migrations/0079_auto_20181228_2039.py b/users/migrations/0079_auto_20181228_2039.py index 79ab56d9..c8335b6e 100644 --- a/users/migrations/0079_auto_20181228_2039.py +++ b/users/migrations/0079_auto_20181228_2039.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0078_auto_20181011_1405'), - ] + dependencies = [("users", "0078_auto_20181011_1405")] operations = [ migrations.AlterField( - model_name='adherent', - name='gpg_fingerprint', + model_name="adherent", + name="gpg_fingerprint", field=models.CharField(blank=True, max_length=49, null=True), - ), + ) ] diff --git a/users/migrations/0080_auto_20190108_1726.py b/users/migrations/0080_auto_20190108_1726.py index f3f872bc..f7831be8 100644 --- a/users/migrations/0080_auto_20190108_1726.py +++ b/users/migrations/0080_auto_20190108_1726.py @@ -7,14 +7,20 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0079_auto_20181228_2039'), - ] + dependencies = [("users", "0079_auto_20181228_2039")] operations = [ migrations.AlterField( - model_name='user', - name='state', - field=models.IntegerField(choices=[(0, 'Active'), (1, 'Disabled'), (2, 'Archived'), (3, 'Not yet active')], default=3), - ), + model_name="user", + name="state", + field=models.IntegerField( + choices=[ + (0, "Active"), + (1, "Disabled"), + (2, "Archived"), + (3, "Not yet active"), + ], + default=3, + ), + ) ] diff --git a/users/migrations/0081_auto_20190317_0302.py b/users/migrations/0081_auto_20190317_0302.py index d17085be..2e511bb8 100644 --- a/users/migrations/0081_auto_20190317_0302.py +++ b/users/migrations/0081_auto_20190317_0302.py @@ -7,14 +7,21 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0080_auto_20190108_1726'), - ] + dependencies = [("users", "0080_auto_20190108_1726")] operations = [ migrations.AlterField( - model_name='user', - name='state', - field=models.IntegerField(choices=[(0, 'Active'), (1, 'Disabled'), (2, 'Archived'), (3, 'Not yet active'), (4, 'Full Archived')], default=3), - ), + model_name="user", + name="state", + field=models.IntegerField( + choices=[ + (0, "Active"), + (1, "Disabled"), + (2, "Archived"), + (3, "Not yet active"), + (4, "Full Archived"), + ], + default=3, + ), + ) ] diff --git a/users/migrations/0082_auto_20190908_1338.py b/users/migrations/0082_auto_20190908_1338.py index fbc85d60..ecaf8c77 100644 --- a/users/migrations/0082_auto_20190908_1338.py +++ b/users/migrations/0082_auto_20190908_1338.py @@ -8,32 +8,38 @@ import ldapdb.models.fields class Migration(migrations.Migration): - dependencies = [ - ('users', '0081_auto_20190317_0302'), - ] + dependencies = [("users", "0081_auto_20190317_0302")] operations = [ migrations.SeparateDatabaseAndState( state_operations=[ migrations.AlterField( - model_name='ldapserviceuser', - name='dn', - field=ldapdb.models.fields.CharField(max_length=200, primary_key=True, serialize=False), + model_name="ldapserviceuser", + name="dn", + field=ldapdb.models.fields.CharField( + max_length=200, primary_key=True, serialize=False + ), ), migrations.AlterField( - model_name='ldapserviceusergroup', - name='dn', - field=ldapdb.models.fields.CharField(max_length=200, primary_key=True, serialize=False), + model_name="ldapserviceusergroup", + name="dn", + field=ldapdb.models.fields.CharField( + max_length=200, primary_key=True, serialize=False + ), ), migrations.AlterField( - model_name='ldapuser', - name='dn', - field=ldapdb.models.fields.CharField(max_length=200, primary_key=True, serialize=False), + model_name="ldapuser", + name="dn", + field=ldapdb.models.fields.CharField( + max_length=200, primary_key=True, serialize=False + ), ), migrations.AlterField( - model_name='ldapusergroup', - name='dn', - field=ldapdb.models.fields.CharField(max_length=200, primary_key=True, serialize=False), + model_name="ldapusergroup", + name="dn", + field=ldapdb.models.fields.CharField( + max_length=200, primary_key=True, serialize=False + ), ), ] ) diff --git a/users/migrations/0083_user_shortcuts_enabled.py b/users/migrations/0083_user_shortcuts_enabled.py index 8ba2252d..cb225f59 100644 --- a/users/migrations/0083_user_shortcuts_enabled.py +++ b/users/migrations/0083_user_shortcuts_enabled.py @@ -7,14 +7,14 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('users', '0082_auto_20190908_1338'), - ] + dependencies = [("users", "0082_auto_20190908_1338")] operations = [ migrations.AddField( - model_name='user', - name='shortcuts_enabled', - field=models.BooleanField(default=True, verbose_name='Enable shortcuts on Re2o website'), - ), + model_name="user", + name="shortcuts_enabled", + field=models.BooleanField( + default=True, verbose_name="Enable shortcuts on Re2o website" + ), + ) ] diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py index b2b50566..b409e525 100644 --- a/users/migrations/__init__.py +++ b/users/migrations/__init__.py @@ -19,4 +19,3 @@ # 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. - diff --git a/users/models.py b/users/models.py index a168eb51..225c4a9f 100755 --- a/users/models.py +++ b/users/models.py @@ -66,7 +66,7 @@ from django.contrib.auth.models import ( AbstractBaseUser, BaseUserManager, PermissionsMixin, - Group + Group, ) from django.core.validators import RegexValidator import traceback @@ -103,18 +103,15 @@ def linux_user_validator(login): if not linux_user_check(login): raise forms.ValidationError( _("The username '%(label)s' contains forbidden characters."), - params={'label': login}, + params={"label": login}, ) def get_fresh_user_uid(): """ Renvoie le plus petit uid non pris. Fonction très paresseuse """ - uids = list(range( - int(min(UID_RANGES['users'])), - int(max(UID_RANGES['users'])) - )) + uids = list(range(int(min(UID_RANGES["users"])), int(max(UID_RANGES["users"])))) try: - used_uids = list(User.objects.values_list('uid_number', flat=True)) + used_uids = list(User.objects.values_list("uid_number", flat=True)) except: used_uids = [] free_uids = [id for id in uids if id not in used_uids] @@ -123,11 +120,8 @@ def get_fresh_user_uid(): def get_fresh_gid(): """ Renvoie le plus petit gid libre """ - gids = list(range( - int(min(GID_RANGES['posix'])), - int(max(GID_RANGES['posix'])) - )) - used_gids = list(ListRight.objects.values_list('gid', flat=True)) + gids = list(range(int(min(GID_RANGES["posix"])), int(max(GID_RANGES["posix"])))) + used_gids = list(ListRight.objects.values_list("gid", flat=True)) free_gids = [id for id in gids if id not in used_gids] return min(free_gids) @@ -135,14 +129,7 @@ def get_fresh_gid(): class UserManager(BaseUserManager): """User manager basique de django""" - def _create_user( - self, - pseudo, - surname, - email, - password=None, - su=False - ): + def _create_user(self, pseudo, surname, email, password=None, su=False): if not pseudo: raise ValueError(_("Users must have an username.")) @@ -177,8 +164,9 @@ class UserManager(BaseUserManager): return self._create_user(pseudo, surname, email, password, True) -class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, - PermissionsMixin, AclMixin): +class User( + RevMixin, FieldPermissionModelMixin, AbstractBaseUser, PermissionsMixin, AclMixin +): """ Definition de l'utilisateur de base. Champs principaux : name, surnname, pseudo, email, room, password Herite du django BaseUser et du système d'auth django""" @@ -201,76 +189,59 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, max_length=32, unique=True, help_text=_("Must only contain letters, numerals or dashes."), - validators=[linux_user_validator] + validators=[linux_user_validator], ) email = models.EmailField( blank=True, null=True, - help_text=_("External email address allowing us to contact you.") + help_text=_("External email address allowing us to contact you."), ) local_email_redirect = models.BooleanField( default=False, - help_text=_("Enable redirection of the local email messages to the" - " main email address.") + help_text=_( + "Enable redirection of the local email messages to the" + " main email address." + ), ) local_email_enabled = models.BooleanField( - default=False, - help_text=_("Enable the local email account.") + default=False, help_text=_("Enable the local email account.") ) school = models.ForeignKey( - 'School', - on_delete=models.PROTECT, - null=True, - blank=True + "School", on_delete=models.PROTECT, null=True, blank=True ) shell = models.ForeignKey( - 'ListShell', - on_delete=models.PROTECT, - null=True, - blank=True + "ListShell", on_delete=models.PROTECT, null=True, blank=True ) comment = models.CharField( - help_text=_("Comment, school year"), - max_length=255, - blank=True + help_text=_("Comment, school year"), max_length=255, blank=True ) pwd_ntlm = models.CharField(max_length=255) state = models.IntegerField(choices=STATES, default=STATE_NOT_YET_ACTIVE) registered = models.DateTimeField(auto_now_add=True) telephone = models.CharField(max_length=15, blank=True, null=True) - uid_number = models.PositiveIntegerField( - default=get_fresh_user_uid, - unique=True - ) - rezo_rez_uid = models.PositiveIntegerField( - unique=True, - blank=True, - null=True - ) + uid_number = models.PositiveIntegerField(default=get_fresh_user_uid, unique=True) + rezo_rez_uid = models.PositiveIntegerField(unique=True, blank=True, null=True) shortcuts_enabled = models.BooleanField( - verbose_name=_("Enable shortcuts on Re2o website"), - default=True + verbose_name=_("Enable shortcuts on Re2o website"), default=True ) - USERNAME_FIELD = 'pseudo' - REQUIRED_FIELDS = ['surname', 'email'] + USERNAME_FIELD = "pseudo" + REQUIRED_FIELDS = ["surname", "email"] objects = UserManager() class Meta: permissions = ( - ("change_user_password", - _("Can change the password of a user")), + ("change_user_password", _("Can change the password of a user")), ("change_user_state", _("Can edit the state of a user")), ("change_user_force", _("Can force the move")), ("change_user_shell", _("Can edit the shell of a user")), - ("change_user_groups", - _("Can edit the groups of rights of a user (critical" - " permission)")), - ("change_all_users", - _("Can edit all users, including those with rights.")), - ("view_user", - _("Can view a user object")), + ( + "change_user_groups", + _("Can edit the groups of rights of a user (critical" " permission)"), + ), + ("change_all_users", _("Can edit all users, including those with rights.")), + ("view_user", _("Can view a user object")), ) verbose_name = _("user (member or club)") verbose_name_plural = _("users (members or clubs)") @@ -281,7 +252,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, if self.is_class_adherent: return self.adherent.name else: - return '' + return "" @cached_property def room(self): @@ -302,7 +273,11 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, @cached_property def get_mail(self): """Return the mail address choosen by the user""" - if not OptionalUser.get_cached_value('local_email_accounts_enabled') or not self.local_email_enabled or self.local_email_redirect: + if ( + not OptionalUser.get_cached_value("local_email_accounts_enabled") + or not self.local_email_enabled + or self.local_email_redirect + ): return str(self.email) else: return str(self.emailaddress_set.get(local_part=self.pseudo.lower())) @@ -310,9 +285,9 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, @cached_property def class_name(self): """Renvoie si il s'agit d'un adhérent ou d'un club""" - if hasattr(self, 'adherent'): + if hasattr(self, "adherent"): return _("Member") - elif hasattr(self, 'club'): + elif hasattr(self, "club"): return _("Club") else: raise NotImplementedError(_("Unknown type.")) @@ -320,32 +295,41 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, @cached_property def gid_number(self): """renvoie le gid par défaut des users""" - return int(LDAP['user_gid']) + return int(LDAP["user_gid"]) @cached_property def is_class_club(self): """ Returns True if the object is a Club (subclassing User) """ # TODO : change to isinstance (cleaner) - return hasattr(self, 'club') + return hasattr(self, "club") @cached_property def is_class_adherent(self): """ Returns True if the object is a Adherent (subclassing User) """ # TODO : change to isinstance (cleaner) - return hasattr(self, 'adherent') + return hasattr(self, "adherent") @property def is_active(self): """ Renvoie si l'user est à l'état actif""" - allow_archived = OptionalUser.get_cached_value('allow_archived_connexion') - return self.state == self.STATE_ACTIVE or self.state == self.STATE_NOT_YET_ACTIVE or (allow_archived and self.state in (self.STATE_ARCHIVE, self.STATE_FULL_ARCHIVE)) + allow_archived = OptionalUser.get_cached_value("allow_archived_connexion") + return ( + self.state == self.STATE_ACTIVE + or self.state == self.STATE_NOT_YET_ACTIVE + or ( + allow_archived + and self.state in (self.STATE_ARCHIVE, self.STATE_FULL_ARCHIVE) + ) + ) def set_active(self): """Enable this user if he subscribed successfully one time before Reenable it if it was archived Do nothing if disabed""" if self.state == self.STATE_NOT_YET_ACTIVE: - if self.facture_set.filter(valid=True).filter(Q(vente__type_cotisation='All') | Q(vente__type_cotisation='Adhesion')).exists() or OptionalUser.get_cached_value('all_users_active'): + if self.facture_set.filter(valid=True).filter( + Q(vente__type_cotisation="All") | Q(vente__type_cotisation="Adhesion") + ).exists() or OptionalUser.get_cached_value("all_users_active"): self.state = self.STATE_ACTIVE self.save() if self.state == self.STATE_ARCHIVE or self.state == self.STATE_FULL_ARCHIVE: @@ -379,17 +363,17 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, @cached_property def gid(self): """return the default gid of user""" - return LDAP['user_gid'] + return LDAP["user_gid"] @property def get_shell(self): """ A utiliser de préférence, prend le shell par défaut si il n'est pas défini""" - return self.shell or OptionalUser.get_cached_value('shell_default') + return self.shell or OptionalUser.get_cached_value("shell_default") @cached_property def home_directory(self): - return '/home/' + self.pseudo + return "/home/" + self.pseudo @cached_property def get_shadow_expire(self): @@ -402,29 +386,29 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def end_adhesion(self): """ Renvoie la date de fin d'adhésion d'un user. Examine les objets cotisation""" - date_max = Cotisation.objects.filter( - vente__in=Vente.objects.filter( - facture__in=Facture.objects.filter( - user=self - ).exclude(valid=False) + date_max = ( + Cotisation.objects.filter( + vente__in=Vente.objects.filter( + facture__in=Facture.objects.filter(user=self).exclude(valid=False) + ) ) - ).filter( - Q(type_cotisation='All') | Q(type_cotisation='Adhesion') - ).aggregate(models.Max('date_end'))['date_end__max'] + .filter(Q(type_cotisation="All") | Q(type_cotisation="Adhesion")) + .aggregate(models.Max("date_end"))["date_end__max"] + ) return date_max def end_connexion(self): """ Renvoie la date de fin de connexion d'un user. Examine les objets cotisation""" - date_max = Cotisation.objects.filter( - vente__in=Vente.objects.filter( - facture__in=Facture.objects.filter( - user=self - ).exclude(valid=False) + date_max = ( + Cotisation.objects.filter( + vente__in=Vente.objects.filter( + facture__in=Facture.objects.filter(user=self).exclude(valid=False) + ) ) - ).filter( - Q(type_cotisation='All') | Q(type_cotisation='Connexion') - ).aggregate(models.Max('date_end'))['date_end__max'] + .filter(Q(type_cotisation="All") | Q(type_cotisation="Connexion")) + .aggregate(models.Max("date_end"))["date_end__max"] + ) return date_max def is_adherent(self): @@ -451,16 +435,16 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def end_ban(self): """ Renvoie la date de fin de ban d'un user, False sinon """ - date_max = Ban.objects.filter( - user=self - ).aggregate(models.Max('date_end'))['date_end__max'] + date_max = Ban.objects.filter(user=self).aggregate(models.Max("date_end"))[ + "date_end__max" + ] return date_max def end_whitelist(self): """ Renvoie la date de fin de whitelist d'un user, False sinon """ - date_max = Whitelist.objects.filter( - user=self - ).aggregate(models.Max('date_end'))['date_end__max'] + date_max = Whitelist.objects.filter(user=self).aggregate( + models.Max("date_end") + )["date_end__max"] return date_max def is_ban(self): @@ -485,10 +469,11 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def has_access(self): """ Renvoie si un utilisateur a accès à internet """ - return (self.state == User.STATE_ACTIVE and - not self.is_ban() and - (self.is_connected() or self.is_whitelisted())) \ - or self == AssoOption.get_cached_value('utilisateur_asso') + return ( + self.state == User.STATE_ACTIVE + and not self.is_ban() + and (self.is_connected() or self.is_whitelisted()) + ) or self == AssoOption.get_cached_value("utilisateur_asso") def end_access(self): """ Renvoie la date de fin normale d'accès (adhésion ou whiteliste)""" @@ -508,27 +493,34 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, """ Renvoie le solde d'un user. Somme les crédits de solde et retire les débit payés par solde""" solde_objects = Paiement.objects.filter(is_balance=True) - somme_debit = Vente.objects.filter( - facture__in=Facture.objects.filter( - user=self, - paiement__in=solde_objects, - valid=True - ) - ).aggregate( - total=models.Sum( - models.F('prix')*models.F('number'), - output_field=models.DecimalField() - ) - )['total'] or 0 - somme_credit = Vente.objects.filter( - facture__in=Facture.objects.filter(user=self, valid=True), - name='solde' - ).aggregate( - total=models.Sum( - models.F('prix')*models.F('number'), - output_field=models.DecimalField() - ) - )['total'] or 0 + somme_debit = ( + Vente.objects.filter( + facture__in=Facture.objects.filter( + user=self, paiement__in=solde_objects, valid=True + ) + ).aggregate( + total=models.Sum( + models.F("prix") * models.F("number"), + output_field=models.DecimalField(), + ) + )[ + "total" + ] + or 0 + ) + somme_credit = ( + Vente.objects.filter( + facture__in=Facture.objects.filter(user=self, valid=True), name="solde" + ).aggregate( + total=models.Sum( + models.F("prix") * models.F("number"), + output_field=models.DecimalField(), + ) + )[ + "total" + ] + or 0 + ) return somme_credit - somme_debit @classmethod @@ -538,16 +530,18 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, if all_interfaces: return Interface.objects.filter( machine__in=Machine.objects.filter(user__in=users) - ).select_related('domain__extension') + ).select_related("domain__extension") else: return Interface.objects.filter( machine__in=Machine.objects.filter(user__in=users, active=active) - ).select_related('domain__extension') + ).select_related("domain__extension") def user_interfaces(self, active=True, all_interfaces=False): """ Renvoie toutes les interfaces dont les machines appartiennent à self. Par defaut ne prend que les interfaces actives""" - return self.users_interfaces([self], active=active, all_interfaces=all_interfaces) + return self.users_interfaces( + [self], active=active, all_interfaces=all_interfaces + ) def assign_ips(self): """ Assign une ipv4 aux machines d'un user """ @@ -585,8 +579,8 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def disable_email(self): """Disable email account and redirection""" - self.local_email_enabled=False - self.local_email_redirect=False + self.local_email_enabled = False + self.local_email_redirect = False def delete_data(self): """This user will be completely archived, so only keep mandatory data""" @@ -597,7 +591,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def mass_archive(cls, users_list): """Mass Archive several users, take a queryset Copy Queryset to avoid eval problem with queryset update""" - #Force eval of queryset + # Force eval of queryset bool(users_list) users_list = users_list.all() cls.mass_unassign_ips(users_list) @@ -607,7 +601,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def mass_full_archive(cls, users_list): """Mass Archive several users, take a queryset Copy Queryset to avoid eval problem with queryset update""" - #Force eval of queryset + # Force eval of queryset bool(users_list) users_list = users_list.all() cls.mass_unassign_ips(users_list) @@ -631,15 +625,25 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def state_sync(self): """Archive, or unarchive, if the user was not active/or archived before""" - if self.__original_state != self.STATE_ACTIVE and self.state == self.STATE_ACTIVE: + if ( + self.__original_state != self.STATE_ACTIVE + and self.state == self.STATE_ACTIVE + ): self.unarchive() - elif self.__original_state != self.STATE_ARCHIVE and self.state == self.STATE_ARCHIVE: + elif ( + self.__original_state != self.STATE_ARCHIVE + and self.state == self.STATE_ARCHIVE + ): self.archive() - elif self.__original_state != self.STATE_FULL_ARCHIVE and self.state == self.STATE_FULL_ARCHIVE: + elif ( + self.__original_state != self.STATE_FULL_ARCHIVE + and self.state == self.STATE_FULL_ARCHIVE + ): self.full_archive() - def ldap_sync(self, base=True, access_refresh=True, mac_refresh=True, - group_refresh=False): + def ldap_sync( + self, base=True, access_refresh=True, mac_refresh=True, group_refresh=False + ): """ Synchronisation du ldap. Synchronise dans le ldap les attributs de self Options : base : synchronise tous les attributs de base - nom, prenom, @@ -649,7 +653,11 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, mac_refresh : synchronise les machines de l'user group_refresh : synchronise les group de l'user Si l'instance n'existe pas, on crée le ldapuser correspondant""" - if sys.version_info[0] >= 3 and (self.state == self.STATE_ACTIVE or self.state == self.STATE_ARCHIVE or self.state == self.STATE_DISABLED): + if sys.version_info[0] >= 3 and ( + self.state == self.STATE_ACTIVE + or self.state == self.STATE_ARCHIVE + or self.state == self.STATE_DISABLED + ): self.refresh_from_db() try: user_ldap = LdapUser.objects.get(uidNumber=self.uid_number) @@ -664,20 +672,19 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, user_ldap.dialupAccess = str(self.has_access()) user_ldap.home_directory = self.home_directory user_ldap.mail = self.get_mail - user_ldap.given_name = self.surname.lower() + '_'\ - + self.name.lower()[:3] - user_ldap.gid = LDAP['user_gid'] - if '{SSHA}' in self.password or '{SMD5}' in self.password: + user_ldap.given_name = ( + self.surname.lower() + "_" + self.name.lower()[:3] + ) + user_ldap.gid = LDAP["user_gid"] + if "{SSHA}" in self.password or "{SMD5}" in self.password: # We remove the extra $ added at import from ldap - user_ldap.user_password = self.password[:6] + \ - self.password[7:] - elif '{crypt}' in self.password: + user_ldap.user_password = self.password[:6] + self.password[7:] + elif "{crypt}" in self.password: # depending on the length, we need to remove or not a $ if len(self.password) == 41: user_ldap.user_password = self.password else: - user_ldap.user_password = self.password[:7] + \ - self.password[8:] + user_ldap.user_password = self.password[:7] + self.password[8:] user_ldap.sambat_nt_password = self.pwd_ntlm.upper() if self.get_shell: @@ -686,15 +693,18 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, if access_refresh: user_ldap.dialupAccess = str(self.has_access()) if mac_refresh: - user_ldap.macs = [str(mac) for mac in Interface.objects.filter( - machine__user=self - ).values_list('mac_address', flat=True).distinct()] + user_ldap.macs = [ + str(mac) + for mac in Interface.objects.filter(machine__user=self) + .values_list("mac_address", flat=True) + .distinct() + ] if group_refresh: # Need to refresh all groups because we don't know which groups # were updated during edition of groups and the user may no longer # be part of the updated group (case of group removal) for group in Group.objects.all(): - if hasattr(group, 'listright'): + if hasattr(group, "listright"): group.listright.ldap_sync() user_ldap.save() @@ -709,29 +719,29 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, @classmethod def ldap_delete_users(cls, queryset_users): """Delete multiple users in ldap""" - LdapUser.objects.filter(name__in=list(queryset_users.values_list('pseudo', flat=True))) + LdapUser.objects.filter( + name__in=list(queryset_users.values_list("pseudo", flat=True)) + ) def notif_inscription(self): """ Prend en argument un objet user, envoie un mail de bienvenue """ - template = loader.get_template('users/email_welcome') - mailmessageoptions, _created = MailMessageOption\ - .objects.get_or_create() + template = loader.get_template("users/email_welcome") + mailmessageoptions, _created = MailMessageOption.objects.get_or_create() context = { - 'nom': self.get_full_name(), - 'asso_name': AssoOption.get_cached_value('name'), - 'asso_email': AssoOption.get_cached_value('contact'), - 'welcome_mail_fr': mailmessageoptions.welcome_mail_fr, - 'welcome_mail_en': mailmessageoptions.welcome_mail_en, - 'pseudo': self.pseudo, + "nom": self.get_full_name(), + "asso_name": AssoOption.get_cached_value("name"), + "asso_email": AssoOption.get_cached_value("contact"), + "welcome_mail_fr": mailmessageoptions.welcome_mail_fr, + "welcome_mail_en": mailmessageoptions.welcome_mail_en, + "pseudo": self.pseudo, } send_mail( - 'Bienvenue au %(name)s / Welcome to %(name)s' % { - 'name': AssoOption.get_cached_value('name') - }, - '', - GeneralOption.get_cached_value('email_from'), + "Bienvenue au %(name)s / Welcome to %(name)s" + % {"name": AssoOption.get_cached_value("name")}, + "", + GeneralOption.get_cached_value("email_from"), [self.email], - html_message=template.render(context) + html_message=template.render(context), ) return @@ -742,26 +752,25 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, req.type = Request.PASSWD req.user = self req.save() - template = loader.get_template('users/email_passwd_request') + template = loader.get_template("users/email_passwd_request") context = { - 'name': req.user.get_full_name(), - 'asso': AssoOption.get_cached_value('name'), - 'asso_mail': AssoOption.get_cached_value('contact'), - 'site_name': GeneralOption.get_cached_value('site_name'), - 'url': request.build_absolute_uri( - reverse('users:process', kwargs={'token': req.token}) + "name": req.user.get_full_name(), + "asso": AssoOption.get_cached_value("name"), + "asso_mail": AssoOption.get_cached_value("contact"), + "site_name": GeneralOption.get_cached_value("site_name"), + "url": request.build_absolute_uri( + reverse("users:process", kwargs={"token": req.token}) ), - 'expire_in': str( - GeneralOption.get_cached_value('req_expire_hrs') - ) + ' hours', + "expire_in": str(GeneralOption.get_cached_value("req_expire_hrs")) + + " hours", } send_mail( - 'Changement de mot de passe du %(name)s / Password renewal for ' - '%(name)s' % {'name': AssoOption.get_cached_value('name')}, + "Changement de mot de passe du %(name)s / Password renewal for " + "%(name)s" % {"name": AssoOption.get_cached_value("name")}, template.render(context), - GeneralOption.get_cached_value('email_from'), + GeneralOption.get_cached_value("email_from"), [req.user.email], - fail_silently=False + fail_silently=False, ) return @@ -794,27 +803,27 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, domain.save() self.notif_auto_newmachine(interface_cible) except Exception as error: - return False, traceback.format_exc() + return False, traceback.format_exc() return interface_cible, _("OK") def notif_auto_newmachine(self, interface): """Notification mail lorsque une machine est automatiquement ajoutée par le radius""" - template = loader.get_template('users/email_auto_newmachine') + template = loader.get_template("users/email_auto_newmachine") context = { - 'nom': self.get_full_name(), - 'mac_address': interface.mac_address, - 'asso_name': AssoOption.get_cached_value('name'), - 'interface_name': interface.domain, - 'asso_email': AssoOption.get_cached_value('contact'), - 'pseudo': self.pseudo, + "nom": self.get_full_name(), + "mac_address": interface.mac_address, + "asso_name": AssoOption.get_cached_value("name"), + "interface_name": interface.domain, + "asso_email": AssoOption.get_cached_value("contact"), + "pseudo": self.pseudo, } send_mail( "Ajout automatique d'une machine / New machine autoregistered", - '', - GeneralOption.get_cached_value('email_from'), + "", + GeneralOption.get_cached_value("email_from"), [self.email], - html_message=template.render(context) + html_message=template.render(context), ) return @@ -822,14 +831,17 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, """ A utiliser de préférence, set le password en hash courrant et dans la version ntlm""" from re2o.login import hashNT + super().set_password(password) self.pwd_ntlm = hashNT(password) return @cached_property def email_address(self): - if (OptionalUser.get_cached_value('local_email_accounts_enabled') - and self.local_email_enabled): + if ( + OptionalUser.get_cached_value("local_email_accounts_enabled") + and self.local_email_enabled + ): return self.emailaddress_set.all() return EMailAddress.objects.none() @@ -843,7 +855,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, def simple_pseudo(): """Renvoie le pseudo sans underscore (compat dns)""" - return self.pseudo.replace('_', '-').lower() + return self.pseudo.replace("_", "-").lower() def composed_pseudo(name): """Renvoie le resultat de simplepseudo et rajoute le nom""" @@ -869,40 +881,48 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, warning_message = None if self.is_class_club and user_request.is_class_adherent: - if (self == user_request or - user_request.has_perm('users.change_user') or - user_request.adherent in self.club.administrators.all()): + if ( + self == user_request + or user_request.has_perm("users.change_user") + or user_request.adherent in self.club.administrators.all() + ): return True, warning_message, None else: - return False, _("You don't have the right to edit this club."), ('users.change_user',) + return ( + False, + _("You don't have the right to edit this club."), + ("users.change_user",), + ) else: if self == user_request: return True, warning_message, None - elif user_request.has_perm('users.change_all_users'): + elif user_request.has_perm("users.change_all_users"): return True, warning_message, None - elif user_request.has_perm('users.change_user'): + elif user_request.has_perm("users.change_user"): if self.groups.filter(listright__critical=True): return ( False, _("User with critical rights, can't be edited. "), - ('users.change_all_users',) + ("users.change_all_users",), ) - elif self == AssoOption.get_cached_value('utilisateur_asso'): + elif self == AssoOption.get_cached_value("utilisateur_asso"): return ( False, - _("Impossible to edit the organisation's" - " user without the 'change_all_users' right."), - ('users.change_all_users', ) + _( + "Impossible to edit the organisation's" + " user without the 'change_all_users' right." + ), + ("users.change_all_users",), ) else: return True, warning_message, None - elif user_request.has_perm('users.change_all_users'): + elif user_request.has_perm("users.change_all_users"): return True, warning_message, None else: return ( False, _("You don't have the right to edit another user."), - ('users.change_user', 'users.change_all_users') + ("users.change_user", "users.change_all_users"), ) def can_change_password(self, user_request, *_args, **_kwargs): @@ -915,30 +935,32 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, or if user_request has the right to change other's password """ if self.is_class_club and user_request.is_class_adherent: - if (self == user_request or - user_request.has_perm('users.change_user_password') or - user_request.adherent in self.club.administrators.all()): + if ( + self == user_request + or user_request.has_perm("users.change_user_password") + or user_request.adherent in self.club.administrators.all() + ): return True, None, None else: return ( False, _("You don't have the right to edit this club."), - ('users.change_user_password',) + ("users.change_user_password",), ) else: - if (self == user_request or - user_request.has_perm('users.change_user_groups')): + if self == user_request or user_request.has_perm( + "users.change_user_groups" + ): # Peut éditer les groupes d'un user, # c'est un privilège élevé, True return True, None, None - elif (user_request.has_perm('users.change_user') and - not self.groups.all()): + elif user_request.has_perm("users.change_user") and not self.groups.all(): return True, None, None else: return ( False, _("You don't have the right to edit another user."), - ('users.change_user_groups', 'users.change_user') + ("users.change_user_groups", "users.change_user"), ) def check_selfpasswd(self, user_request, *_args, **_kwargs): @@ -954,12 +976,17 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, :returns: a message and a boolean which is True if the user has the right to change a state """ - if not ((self.pk == user_request.pk and OptionalUser.get_cached_value('self_change_room')) - or user_request.has_perm('users.change_user')): + if not ( + ( + self.pk == user_request.pk + and OptionalUser.get_cached_value("self_change_room") + ) + or user_request.has_perm("users.change_user") + ): return ( False, _("Permission required to change the room."), - ('users.change_user',) + ("users.change_user",), ) else: return True, None, None @@ -972,11 +999,11 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, :returns: a message and a boolean which is True if the user has the right to change a state """ - can = user_request.has_perm('users.change_user_state') + can = user_request.has_perm("users.change_user_state") return ( can, _("Permission required to change the state.") if not can else None, - ('users.change_user_state',) + ("users.change_user_state",), ) def can_change_shell(self, user_request, *_args, **_kwargs): @@ -986,12 +1013,17 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, :returns: a message and a boolean which is True if the user has the right to change a shell """ - if not ((self.pk == user_request.pk and OptionalUser.get_cached_value('self_change_shell')) - or user_request.has_perm('users.change_user_shell')): + if not ( + ( + self.pk == user_request.pk + and OptionalUser.get_cached_value("self_change_shell") + ) + or user_request.has_perm("users.change_user_shell") + ): return ( False, _("Permission required to change the shell."), - ('users.change_user_shell',) + ("users.change_user_shell",), ) else: return True, None, None @@ -1004,11 +1036,11 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, :returns: a message and a boolean which is True if the user has the right to change a redirection """ - can = OptionalUser.get_cached_value('local_email_accounts_enabled') + can = OptionalUser.get_cached_value("local_email_accounts_enabled") return ( can, _("Local email accounts must be enabled.") if not can else None, - None + None, ) @staticmethod @@ -1019,11 +1051,11 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, :returns: a message and a boolean which is True if the user has the right to change internal address """ - can = OptionalUser.get_cached_value('local_email_accounts_enabled') + can = OptionalUser.get_cached_value("local_email_accounts_enabled") return ( can, _("Local email accounts must be enabled.") if not can else None, - None + None, ) @staticmethod @@ -1034,11 +1066,11 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, :returns: a message and a boolean which is True if the user has the right to change a force """ - can = user_request.has_perm('users.change_user_force') + can = user_request.has_perm("users.change_user_force") return ( can, _("Permission required to force the move.") if not can else None, - ('users.change_user_force',) + ("users.change_user_force",), ) @staticmethod @@ -1049,11 +1081,13 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, :returns: a message and a boolean which is True if the user has the right to change a group """ - can = user_request.has_perm('users.change_user_grou') + can = user_request.has_perm("users.change_user_grou") return ( can, - _("Permission required to edit the user's groups of rights.") if not can else None, - ('users.change_user_groups') + _("Permission required to edit the user's groups of rights.") + if not can + else None, + ("users.change_user_groups"), ) @staticmethod @@ -1066,8 +1100,10 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, can = user_request.is_superuser return ( can, - _("'superuser' right required to edit the superuser flag.") if not can else None, - [] + _("'superuser' right required to edit the superuser flag.") + if not can + else None, + [], ) def can_view(self, user_request, *_args, **_kwargs): @@ -1079,26 +1115,27 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, text """ if self.is_class_club and user_request.is_class_adherent: - if (self == user_request or - user_request.has_perm('users.view_user') or - user_request.adherent in self.club.administrators.all() or - user_request.adherent in self.club.members.all()): + if ( + self == user_request + or user_request.has_perm("users.view_user") + or user_request.adherent in self.club.administrators.all() + or user_request.adherent in self.club.members.all() + ): return True, None, None else: return ( False, _("You don't have the right to view this club."), - ('users.view_user',) + ("users.view_user",), ) else: - if (self == user_request or - user_request.has_perm('users.view_user')): + if self == user_request or user_request.has_perm("users.view_user"): return True, None, None else: return ( False, _("You don't have the right to view another user."), - ('users.view_user',) + ("users.view_user",), ) @staticmethod @@ -1109,11 +1146,13 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, :return: True if the user can view the list and an explanation message. """ - can = user_request.has_perm('users.view_user') + can = user_request.has_perm("users.view_user") return ( can, - _("You don't have the right to view the list of users.") if not can else None, - ('users.view_user',) + _("You don't have the right to view the list of users.") + if not can + else None, + ("users.view_user",), ) def can_delete(self, user_request, *_args, **_kwargs): @@ -1124,39 +1163,49 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, :return: True if user_request has the right 'bureau', and a message. """ - can = user_request.has_perm('users.delete_user') + can = user_request.has_perm("users.delete_user") return ( can, _("You don't have the right to delete this user.") if not can else None, - ('users.delete_user',) + ("users.delete_user",), ) def __init__(self, *args, **kwargs): super(User, self).__init__(*args, **kwargs) self.field_permissions = { - 'shell': self.can_change_shell, - 'force': self.can_change_force, - 'selfpasswd': self.check_selfpasswd, - 'local_email_redirect': self.can_change_local_email_redirect, - 'local_email_enabled': self.can_change_local_email_enabled, - 'room': self.can_change_room, + "shell": self.can_change_shell, + "force": self.can_change_force, + "selfpasswd": self.check_selfpasswd, + "local_email_redirect": self.can_change_local_email_redirect, + "local_email_enabled": self.can_change_local_email_enabled, + "room": self.can_change_room, } self.__original_state = self.state def clean(self, *args, **kwargs): """Check if this pseudo is already used by any mailalias. Better than raising an error in post-save and catching it""" - if (EMailAddress.objects - .filter(local_part=self.pseudo.lower()).exclude(user_id=self.id) - ): + if EMailAddress.objects.filter(local_part=self.pseudo.lower()).exclude( + user_id=self.id + ): raise ValidationError(_("This username is already used.")) - if not self.local_email_enabled and not self.email and not (self.state == self.STATE_FULL_ARCHIVE): - raise ValidationError(_("There is neither a local email address nor an external" - " email address for this user.") + if ( + not self.local_email_enabled + and not self.email + and not (self.state == self.STATE_FULL_ARCHIVE) + ): + raise ValidationError( + _( + "There is neither a local email address nor an external" + " email address for this user." + ) ) if self.local_email_redirect and not self.email: - raise ValidationError(_("You can't redirect your local emails if no external email" - " address has been set.") + raise ValidationError( + _( + "You can't redirect your local emails if no external email" + " address has been set." + ) ) def __str__(self): @@ -1169,16 +1218,9 @@ class Adherent(User): name = models.CharField(max_length=255) room = models.OneToOneField( - 'topologie.Room', - on_delete=models.PROTECT, - blank=True, - null=True - ) - gpg_fingerprint = models.CharField( - max_length=49, - blank=True, - null=True, + "topologie.Room", on_delete=models.PROTECT, blank=True, null=True ) + gpg_fingerprint = models.CharField(max_length=49, blank=True, null=True) class Meta(User.Meta): verbose_name = _("member") @@ -1186,14 +1228,21 @@ class Adherent(User): def format_gpgfp(self): """Format gpg finger print as AAAA BBBB... from a string AAAABBBB....""" - self.gpg_fingerprint = ' '.join([self.gpg_fingerprint[i:i + 4] for i in range(0, len(self.gpg_fingerprint), 4)]) + self.gpg_fingerprint = " ".join( + [ + self.gpg_fingerprint[i : i + 4] + for i in range(0, len(self.gpg_fingerprint), 4) + ] + ) def validate_gpgfp(self): """Validate from raw entry if is it a valid gpg fp""" if self.gpg_fingerprint: - gpg_fingerprint = self.gpg_fingerprint.replace(' ', '').upper() + gpg_fingerprint = self.gpg_fingerprint.replace(" ", "").upper() if not re.match("^[0-9A-F]{40}$", gpg_fingerprint): - raise ValidationError(_("A GPG fingerprint must contain 40 hexadecimal characters")) + raise ValidationError( + _("A GPG fingerprint must contain 40 hexadecimal characters") + ) self.gpg_fingerprint = gpg_fingerprint @classmethod @@ -1213,19 +1262,23 @@ class Adherent(User): :return: a message and a boolean which is True if the user can create a user or if the `options.all_can_create` is set. """ - if (not user_request.is_authenticated and - not OptionalUser.get_cached_value('self_adhesion')): + if not user_request.is_authenticated and not OptionalUser.get_cached_value( + "self_adhesion" + ): return False, _("Self adhesion is disabled."), None else: - if (OptionalUser.get_cached_value('all_can_create_adherent') or - OptionalUser.get_cached_value('self_adhesion')): + if OptionalUser.get_cached_value( + "all_can_create_adherent" + ) or OptionalUser.get_cached_value("self_adhesion"): return True, None, None else: - can = user_request.has_perm('users.add_user') + can = user_request.has_perm("users.add_user") return ( can, - _("You don't have the right to create a user.") if not can else None, - ('users.add_user',) + _("You don't have the right to create a user.") + if not can + else None, + ("users.add_user",), ) def clean(self, *args, **kwargs): @@ -1241,24 +1294,15 @@ class Club(User): with special informations) """ room = models.ForeignKey( - 'topologie.Room', - on_delete=models.PROTECT, - blank=True, - null=True + "topologie.Room", on_delete=models.PROTECT, blank=True, null=True ) administrators = models.ManyToManyField( - blank=True, - to='users.Adherent', - related_name='club_administrator' + blank=True, to="users.Adherent", related_name="club_administrator" ) members = models.ManyToManyField( - blank=True, - to='users.Adherent', - related_name='club_members' - ) - mailing = models.BooleanField( - default=False + blank=True, to="users.Adherent", related_name="club_members" ) + mailing = models.BooleanField(default=False) class Meta(User.Meta): verbose_name = _("club") @@ -1275,14 +1319,16 @@ class Club(User): if not user_request.is_authenticated: return False, _("You must be authenticated."), None else: - if OptionalUser.get_cached_value('all_can_create_club'): + if OptionalUser.get_cached_value("all_can_create_club"): return True, None, None else: - can = user_request.has_perm('users.add_user') + can = user_request.has_perm("users.add_user") return ( can, - _("You don't have the right to create a club.") if not can else None, - ('users.add_user',) + _("You don't have the right to create a club.") + if not can + else None, + ("users.add_user",), ) @staticmethod @@ -1293,17 +1339,21 @@ class Club(User): :return: True if the user can view the list and an explanation message. """ - if user_request.has_perm('users.view_user'): + if user_request.has_perm("users.view_user"): return True, None, None - if (hasattr(user_request, 'is_class_adherent') and - user_request.is_class_adherent): - if (user_request.adherent.club_administrator.all() or - user_request.adherent.club_members.all()): + if ( + hasattr(user_request, "is_class_adherent") + and user_request.is_class_adherent + ): + if ( + user_request.adherent.club_administrator.all() + or user_request.adherent.club_members.all() + ): return True, None, None return ( False, _("You don't have the right to view the list of users."), - ('users.view_user',) + ("users.view_user",), ) @classmethod @@ -1323,31 +1373,26 @@ def user_post_save(**kwargs): """ Synchronisation post_save : envoie le mail de bienvenue si creation Synchronise le pseudo, en créant un alias mail correspondant Synchronise le ldap""" - is_created = kwargs['created'] - user = kwargs['instance'] - EMailAddress.objects.get_or_create( - local_part=user.pseudo.lower(), user=user) + is_created = kwargs["created"] + user = kwargs["instance"] + EMailAddress.objects.get_or_create(local_part=user.pseudo.lower(), user=user) if is_created: user.notif_inscription() user.state_sync() user.ldap_sync( - base=True, - access_refresh=True, - mac_refresh=False, - group_refresh=True + base=True, access_refresh=True, mac_refresh=False, group_refresh=True ) - regen('mailing') + regen("mailing") @receiver(m2m_changed, sender=User.groups.through) def user_group_relation_changed(**kwargs): - action = kwargs['action'] - if action in ('post_add', 'post_remove', 'post_clear'): - user = kwargs['instance'] - user.ldap_sync(base=False, - access_refresh=False, - mac_refresh=False, - group_refresh=True) + action = kwargs["action"] + if action in ("post_add", "post_remove", "post_clear"): + user = kwargs["instance"] + user.ldap_sync( + base=False, access_refresh=False, mac_refresh=False, group_refresh=True + ) @receiver(post_delete, sender=Adherent) @@ -1355,44 +1400,31 @@ def user_group_relation_changed(**kwargs): @receiver(post_delete, sender=User) def user_post_delete(**kwargs): """Post delete d'un user, on supprime son instance ldap""" - user = kwargs['instance'] + user = kwargs["instance"] user.ldap_del() - regen('mailing') + regen("mailing") class ServiceUser(RevMixin, AclMixin, AbstractBaseUser): """ Classe des users daemons, règle leurs accès au ldap""" - readonly = 'readonly' - ACCESS = ( - ('auth', 'auth'), - ('readonly', 'readonly'), - ('usermgmt', 'usermgmt'), - ) + + readonly = "readonly" + ACCESS = (("auth", "auth"), ("readonly", "readonly"), ("usermgmt", "usermgmt")) pseudo = models.CharField( max_length=32, unique=True, help_text=_("Must only contain letters, numerals or dashes."), - validators=[linux_user_validator] - ) - access_group = models.CharField( - choices=ACCESS, - default=readonly, - max_length=32 - ) - comment = models.CharField( - help_text=_("Comment"), - max_length=255, - blank=True + validators=[linux_user_validator], ) + access_group = models.CharField(choices=ACCESS, default=readonly, max_length=32) + comment = models.CharField(help_text=_("Comment"), max_length=255, blank=True) - USERNAME_FIELD = 'pseudo' + USERNAME_FIELD = "pseudo" objects = UserManager() class Meta: - permissions = ( - ("view_serviceuser", _("Can view a service user object")), - ) + permissions = (("view_serviceuser", _("Can view a service user object")),) verbose_name = _("service user") verbose_name_plural = _("service users") @@ -1429,10 +1461,16 @@ class ServiceUser(RevMixin, AclMixin, AbstractBaseUser): group = LdapServiceUserGroup.objects.get(name=self.access_group) except: group = LdapServiceUserGroup(name=self.access_group) - group.members = list(LdapServiceUser.objects.filter( - name__in=[user.pseudo for user in ServiceUser.objects.filter( - access_group=self.access_group - )]).values_list('dn', flat=True)) + group.members = list( + LdapServiceUser.objects.filter( + name__in=[ + user.pseudo + for user in ServiceUser.objects.filter( + access_group=self.access_group + ) + ] + ).values_list("dn", flat=True) + ) group.save() def __str__(self): @@ -1442,14 +1480,14 @@ class ServiceUser(RevMixin, AclMixin, AbstractBaseUser): @receiver(post_save, sender=ServiceUser) def service_user_post_save(**kwargs): """ Synchronise un service user ldap après modification django""" - service_user = kwargs['instance'] + service_user = kwargs["instance"] service_user.ldap_sync() @receiver(post_delete, sender=ServiceUser) def service_user_post_delete(**kwargs): """ Supprime un service user ldap après suppression django""" - service_user = kwargs['instance'] + service_user = kwargs["instance"] service_user.ldap_del() @@ -1459,9 +1497,7 @@ class School(RevMixin, AclMixin, models.Model): name = models.CharField(max_length=255) class Meta: - permissions = ( - ("view_school", _("Can view a school object")), - ) + permissions = (("view_school", _("Can view a school object")),) verbose_name = _("school") verbose_name_plural = _("schools") @@ -1479,23 +1515,19 @@ class ListRight(RevMixin, AclMixin, Group): unix_name = models.CharField( max_length=255, unique=True, - validators=[RegexValidator( - '^[a-z]+$', - message=(_("UNIX groups can only contain lower case letters.")) - )] + validators=[ + RegexValidator( + "^[a-z]+$", + message=(_("UNIX groups can only contain lower case letters.")), + ) + ], ) gid = models.PositiveIntegerField(unique=True, null=True) critical = models.BooleanField(default=False) - details = models.CharField( - help_text=_("Description"), - max_length=255, - blank=True - ) + details = models.CharField(help_text=_("Description"), max_length=255, blank=True) class Meta: - permissions = ( - ("view_listright", _("Can view a group of rights object")), - ) + permissions = (("view_listright", _("Can view a group of rights object")),) verbose_name = _("group of rights") verbose_name_plural = _("groups of rights") @@ -1509,8 +1541,7 @@ class ListRight(RevMixin, AclMixin, Group): except LdapUserGroup.DoesNotExist: group_ldap = LdapUserGroup(gid=self.gid) group_ldap.name = self.unix_name - group_ldap.members = [user.pseudo for user - in self.user_set.all()] + group_ldap.members = [user.pseudo for user in self.user_set.all()] group_ldap.save() def ldap_del(self): @@ -1525,14 +1556,14 @@ class ListRight(RevMixin, AclMixin, Group): @receiver(post_save, sender=ListRight) def listright_post_save(**kwargs): """ Synchronise le droit ldap quand il est modifié""" - right = kwargs['instance'] + right = kwargs["instance"] right.ldap_sync() @receiver(post_delete, sender=ListRight) def listright_post_delete(**kwargs): """Suppression d'un groupe ldap après suppression coté django""" - right = kwargs['instance'] + right = kwargs["instance"] right.ldap_del() @@ -1543,13 +1574,10 @@ class ListShell(RevMixin, AclMixin, models.Model): shell = models.CharField(max_length=255, unique=True) class Meta: - permissions = ( - ("view_listshell", _("Can view a shell object")), - ) + permissions = (("view_listshell", _("Can view a shell object")),) verbose_name = _("shell") verbose_name_plural = _("shells") - def get_pretty_name(self): """Return the canonical name of the shell""" return self.shell.split("/")[-1] @@ -1571,34 +1599,32 @@ class Ban(RevMixin, AclMixin, models.Model): (2, _("RESTRICTED (speed limitation)")), ) - user = models.ForeignKey('User', on_delete=models.PROTECT) + user = models.ForeignKey("User", on_delete=models.PROTECT) raison = models.CharField(max_length=255) date_start = models.DateTimeField(auto_now_add=True) date_end = models.DateTimeField() state = models.IntegerField(choices=STATES, default=STATE_HARD) class Meta: - permissions = ( - ("view_ban", _("Can view a ban object")), - ) + permissions = (("view_ban", _("Can view a ban object")),) verbose_name = _("ban") verbose_name_plural = _("bans") def notif_ban(self): """ Prend en argument un objet ban, envoie un mail de notification """ - template = loader.get_template('users/email_ban_notif') + template = loader.get_template("users/email_ban_notif") context = { - 'name': self.user.get_full_name(), - 'raison': self.raison, - 'date_end': self.date_end, - 'asso_name': AssoOption.get_cached_value('name'), + "name": self.user.get_full_name(), + "raison": self.raison, + "date_end": self.date_end, + "asso_name": AssoOption.get_cached_value("name"), } send_mail( - 'Déconnexion disciplinaire / Disciplinary disconnection', + "Déconnexion disciplinaire / Disciplinary disconnection", template.render(context), - GeneralOption.get_cached_value('email_from'), + GeneralOption.get_cached_value("email_from"), [self.user.email], - fail_silently=False + fail_silently=False, ) return @@ -1614,45 +1640,44 @@ class Ban(RevMixin, AclMixin, models.Model): :return: A boolean telling if the acces is granted and an explanation text """ - if (not user_request.has_perm('users.view_ban') and - self.user != user_request): + if not user_request.has_perm("users.view_ban") and self.user != user_request: return ( False, _("You don't have the right to view bans other than yours."), - ('users.view_ban',) + ("users.view_ban",), ) else: return True, None, None def __str__(self): - return str(self.user) + ' ' + str(self.raison) + return str(self.user) + " " + str(self.raison) @receiver(post_save, sender=Ban) def ban_post_save(**kwargs): """ Regeneration de tous les services après modification d'un ban""" - ban = kwargs['instance'] - is_created = kwargs['created'] + ban = kwargs["instance"] + is_created = kwargs["created"] user = ban.user user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) - regen('mailing') + regen("mailing") if is_created: ban.notif_ban() - regen('dhcp') - regen('mac_ip_list') + regen("dhcp") + regen("mac_ip_list") if user.has_access(): - regen('dhcp') - regen('mac_ip_list') + regen("dhcp") + regen("mac_ip_list") @receiver(post_delete, sender=Ban) def ban_post_delete(**kwargs): """ Regen de tous les services après suppression d'un ban""" - user = kwargs['instance'].user + user = kwargs["instance"].user user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) - regen('mailing') - regen('dhcp') - regen('mac_ip_list') + regen("mailing") + regen("dhcp") + regen("mac_ip_list") class Whitelist(RevMixin, AclMixin, models.Model): @@ -1660,15 +1685,13 @@ class Whitelist(RevMixin, AclMixin, models.Model): accorder un accès internet pour une durée défini. Moins fort qu'un ban quel qu'il soit""" - user = models.ForeignKey('User', on_delete=models.PROTECT) + user = models.ForeignKey("User", on_delete=models.PROTECT) raison = models.CharField(max_length=255) date_start = models.DateTimeField(auto_now_add=True) date_end = models.DateTimeField() class Meta: - permissions = ( - ("view_whitelist", _("Can view a whitelist object")), - ) + permissions = (("view_whitelist", _("Can view a whitelist object")),) verbose_name = _("whitelist (free of charge access)") verbose_name_plural = _("whitelists (free of charge access)") @@ -1684,74 +1707,71 @@ class Whitelist(RevMixin, AclMixin, models.Model): :return: A boolean telling if the acces is granted and an explanation text """ - if (not user_request.has_perm('users.view_whitelist') and - self.user != user_request): + if ( + not user_request.has_perm("users.view_whitelist") + and self.user != user_request + ): return ( False, _("You don't have the right to view whitelists other than yours."), - ('users.view_whitelist',) + ("users.view_whitelist",), ) else: return True, None, None def __str__(self): - return str(self.user) + ' ' + str(self.raison) + return str(self.user) + " " + str(self.raison) @receiver(post_save, sender=Whitelist) def whitelist_post_save(**kwargs): """Après modification d'une whitelist, on synchronise les services et on lui permet d'avoir internet""" - whitelist = kwargs['instance'] + whitelist = kwargs["instance"] user = whitelist.user user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) - is_created = kwargs['created'] - regen('mailing') + is_created = kwargs["created"] + regen("mailing") if is_created: - regen('dhcp') - regen('mac_ip_list') + regen("dhcp") + regen("mac_ip_list") if user.has_access(): - regen('dhcp') - regen('mac_ip_list') + regen("dhcp") + regen("mac_ip_list") @receiver(post_delete, sender=Whitelist) def whitelist_post_delete(**kwargs): """Après suppression d'une whitelist, on supprime l'accès internet en forçant la régénration""" - user = kwargs['instance'].user + user = kwargs["instance"].user user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) - regen('mailing') - regen('dhcp') - regen('mac_ip_list') + regen("mailing") + regen("dhcp") + regen("mac_ip_list") class Request(models.Model): """ Objet request, générant une url unique de validation. Utilisé par exemple pour la generation du mot de passe et sa réinitialisation""" - PASSWD = 'PW' - EMAIL = 'EM' - TYPE_CHOICES = ( - (PASSWD, _("Password")), - (EMAIL, _("Email address")), - ) + + PASSWD = "PW" + EMAIL = "EM" + TYPE_CHOICES = ((PASSWD, _("Password")), (EMAIL, _("Email address"))) type = models.CharField(max_length=2, choices=TYPE_CHOICES) token = models.CharField(max_length=32) - user = models.ForeignKey('User', on_delete=models.CASCADE) + user = models.ForeignKey("User", on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True, editable=False) expires_at = models.DateTimeField() def save(self): if not self.expires_at: - self.expires_at = (timezone.now() + - datetime.timedelta( - hours=GeneralOption.get_cached_value( - 'req_expire_hrs' - ) - )) + self.expires_at = timezone.now() + datetime.timedelta( + hours=GeneralOption.get_cached_value("req_expire_hrs") + ) if not self.token: - self.token = str(uuid.uuid4()).replace('-', '') # remove hyphens + self.token = str(uuid.uuid4()).replace("-", "") # remove hyphens super(Request, self).save() @@ -1759,73 +1779,50 @@ class LdapUser(ldapdb.models.Model): """ Class for representing an LDAP user entry. """ + # LDAP meta-data - base_dn = LDAP['base_user_dn'] - object_classes = ['inetOrgPerson', 'top', 'posixAccount', - 'sambaSamAccount', 'radiusprofile', - 'shadowAccount'] + base_dn = LDAP["base_user_dn"] + object_classes = [ + "inetOrgPerson", + "top", + "posixAccount", + "sambaSamAccount", + "radiusprofile", + "shadowAccount", + ] # attributes - gid = ldapdb.models.fields.IntegerField(db_column='gidNumber') + gid = ldapdb.models.fields.IntegerField(db_column="gidNumber") name = ldapdb.models.fields.CharField( - db_column='cn', - max_length=200, - primary_key=True + db_column="cn", max_length=200, primary_key=True ) - uid = ldapdb.models.fields.CharField(db_column='uid', max_length=200) - uidNumber = ldapdb.models.fields.IntegerField( - db_column='uidNumber', - unique=True - ) - sn = ldapdb.models.fields.CharField(db_column='sn', max_length=200) + uid = ldapdb.models.fields.CharField(db_column="uid", max_length=200) + uidNumber = ldapdb.models.fields.IntegerField(db_column="uidNumber", unique=True) + sn = ldapdb.models.fields.CharField(db_column="sn", max_length=200) login_shell = ldapdb.models.fields.CharField( - db_column='loginShell', - max_length=200, - blank=True, - null=True - ) - mail = ldapdb.models.fields.CharField(db_column='mail', max_length=200) - given_name = ldapdb.models.fields.CharField( - db_column='givenName', - max_length=200 + db_column="loginShell", max_length=200, blank=True, null=True ) + mail = ldapdb.models.fields.CharField(db_column="mail", max_length=200) + given_name = ldapdb.models.fields.CharField(db_column="givenName", max_length=200) home_directory = ldapdb.models.fields.CharField( - db_column='homeDirectory', - max_length=200 + db_column="homeDirectory", max_length=200 ) display_name = ldapdb.models.fields.CharField( - db_column='displayName', - max_length=200, - blank=True, - null=True - ) - dialupAccess = ldapdb.models.fields.CharField(db_column='dialupAccess') - sambaSID = ldapdb.models.fields.IntegerField( - db_column='sambaSID', - unique=True + db_column="displayName", max_length=200, blank=True, null=True ) + dialupAccess = ldapdb.models.fields.CharField(db_column="dialupAccess") + sambaSID = ldapdb.models.fields.IntegerField(db_column="sambaSID", unique=True) user_password = ldapdb.models.fields.CharField( - db_column='userPassword', - max_length=200, - blank=True, - null=True + db_column="userPassword", max_length=200, blank=True, null=True ) sambat_nt_password = ldapdb.models.fields.CharField( - db_column='sambaNTPassword', - max_length=200, - blank=True, - null=True + db_column="sambaNTPassword", max_length=200, blank=True, null=True ) macs = ldapdb.models.fields.ListField( - db_column='radiusCallingStationId', - max_length=200, - blank=True, - null=True + db_column="radiusCallingStationId", max_length=200, blank=True, null=True ) shadowexpire = ldapdb.models.fields.CharField( - db_column='shadowExpire', - blank=True, - null=True + db_column="shadowExpire", blank=True, null=True ) def __str__(self): @@ -1847,20 +1844,16 @@ class LdapUserGroup(ldapdb.models.Model): Un groupe ldap """ + # LDAP meta-data - base_dn = LDAP['base_usergroup_dn'] - object_classes = ['posixGroup'] + base_dn = LDAP["base_usergroup_dn"] + object_classes = ["posixGroup"] # attributes - gid = ldapdb.models.fields.IntegerField(db_column='gidNumber') - members = ldapdb.models.fields.ListField( - db_column='memberUid', - blank=True - ) + gid = ldapdb.models.fields.IntegerField(db_column="gidNumber") + members = ldapdb.models.fields.ListField(db_column="memberUid", blank=True) name = ldapdb.models.fields.CharField( - db_column='cn', - max_length=200, - primary_key=True + db_column="cn", max_length=200, primary_key=True ) def __str__(self): @@ -1873,21 +1866,17 @@ class LdapServiceUser(ldapdb.models.Model): Un user de service coté ldap """ + # LDAP meta-data - base_dn = LDAP['base_userservice_dn'] - object_classes = ['applicationProcess', 'simpleSecurityObject'] + base_dn = LDAP["base_userservice_dn"] + object_classes = ["applicationProcess", "simpleSecurityObject"] # attributes name = ldapdb.models.fields.CharField( - db_column='cn', - max_length=200, - primary_key=True + db_column="cn", max_length=200, primary_key=True ) user_password = ldapdb.models.fields.CharField( - db_column='userPassword', - max_length=200, - blank=True, - null=True + db_column="userPassword", max_length=200, blank=True, null=True ) def __str__(self): @@ -1901,20 +1890,16 @@ class LdapServiceUserGroup(ldapdb.models.Model): Un group user de service coté ldap. Dans userservicegroupdn (voir dans settings_local.py) """ + # LDAP meta-data - base_dn = LDAP['base_userservicegroup_dn'] - object_classes = ['groupOfNames'] + base_dn = LDAP["base_userservicegroup_dn"] + object_classes = ["groupOfNames"] # attributes name = ldapdb.models.fields.CharField( - db_column='cn', - max_length=200, - primary_key=True - ) - members = ldapdb.models.fields.ListField( - db_column='member', - blank=True + db_column="cn", max_length=200, primary_key=True ) + members = ldapdb.models.fields.ListField(db_column="member", blank=True) def __str__(self): return self.name @@ -1923,15 +1908,12 @@ class LdapServiceUserGroup(ldapdb.models.Model): class EMailAddress(RevMixin, AclMixin, models.Model): """Defines a local email account for a user """ + user = models.ForeignKey( - User, - on_delete=models.CASCADE, - help_text=_("User of the local email account") + User, on_delete=models.CASCADE, help_text=_("User of the local email account") ) local_part = models.CharField( - unique=True, - max_length=128, - help_text=_("Local part of the email address") + unique=True, max_length=128, help_text=_("Local part of the email address") ) class Meta: @@ -1942,11 +1924,15 @@ class EMailAddress(RevMixin, AclMixin, models.Model): verbose_name_plural = _("local email accounts") def __str__(self): - return str(self.local_part) + OptionalUser.get_cached_value('local_email_domain') + return str(self.local_part) + OptionalUser.get_cached_value( + "local_email_domain" + ) @cached_property def complete_email_address(self): - return str(self.local_part) + OptionalUser.get_cached_value('local_email_domain') + return str(self.local_part) + OptionalUser.get_cached_value( + "local_email_domain" + ) @staticmethod def can_create(user_request, userid, *_args, **_kwargs): @@ -1960,28 +1946,28 @@ class EMailAddress(RevMixin, AclMixin, models.Model): a message and a boolean which is True if the user can create a local email account. """ - if user_request.has_perm('users.add_emailaddress'): + if user_request.has_perm("users.add_emailaddress"): return True, None, None - if not OptionalUser.get_cached_value('local_email_accounts_enabled'): - return ( - False, - _("The local email accounts are not enabled."), - None - ) + if not OptionalUser.get_cached_value("local_email_accounts_enabled"): + return (False, _("The local email accounts are not enabled."), None) if int(user_request.id) != int(userid): return ( False, - _("You don't have the right to add a local email" - " account to another user."), - ('users.add_emailaddress',) + _( + "You don't have the right to add a local email" + " account to another user." + ), + ("users.add_emailaddress",), ) - elif user_request.email_address.count() >= OptionalUser.get_cached_value('max_email_address'): + elif user_request.email_address.count() >= OptionalUser.get_cached_value( + "max_email_address" + ): return ( False, _("You reached the limit of {} local email accounts.").format( - OptionalUser.get_cached_value('max_email_address') + OptionalUser.get_cached_value("max_email_address") ), - None + None, ) return True, None, None @@ -1995,21 +1981,19 @@ class EMailAddress(RevMixin, AclMixin, models.Model): a message and a boolean which is True if the user can see the local email account. """ - if user_request.has_perm('users.view_emailaddress'): + if user_request.has_perm("users.view_emailaddress"): return True, None, None - if not OptionalUser.get_cached_value('local_email_accounts_enabled'): - return ( - False, - _("The local email accounts are not enabled."), - None - ) + if not OptionalUser.get_cached_value("local_email_accounts_enabled"): + return (False, _("The local email accounts are not enabled."), None) if user_request == self.user: return True, None, None return ( False, - _("You don't have the right to edit another user's local" - " email account."), - ('users.view_emailaddress',) + _( + "You don't have the right to edit another user's local" + " email account." + ), + ("users.view_emailaddress",), ) def can_delete(self, user_request, *_args, **_kwargs): @@ -2025,21 +2009,25 @@ class EMailAddress(RevMixin, AclMixin, models.Model): if self.local_part == self.user.pseudo.lower(): return ( False, - _("You can't delete a local email account whose" - " local part is the same as the username."), - None + _( + "You can't delete a local email account whose" + " local part is the same as the username." + ), + None, ) - if user_request.has_perm('users.delete_emailaddress'): + if user_request.has_perm("users.delete_emailaddress"): return True, None, None - if not OptionalUser.get_cached_value('local_email_accounts_enabled'): + if not OptionalUser.get_cached_value("local_email_accounts_enabled"): return False, _("The local email accounts are not enabled."), None if user_request == self.user: return True, None, None return ( False, - _("You don't have the right to delete another user's" - " local email account"), - ('users.delete_emailaddress',) + _( + "You don't have the right to delete another user's" + " local email account" + ), + ("users.delete_emailaddress",), ) def can_edit(self, user_request, *_args, **_kwargs): @@ -2055,21 +2043,25 @@ class EMailAddress(RevMixin, AclMixin, models.Model): if self.local_part == self.user.pseudo.lower(): return ( False, - _("You can't edit a local email account whose local" - " part is the same as the username."), - None + _( + "You can't edit a local email account whose local" + " part is the same as the username." + ), + None, ) - if user_request.has_perm('users.change_emailaddress'): + if user_request.has_perm("users.change_emailaddress"): return True, None, None - if not OptionalUser.get_cached_value('local_email_accounts_enabled'): + if not OptionalUser.get_cached_value("local_email_accounts_enabled"): return False, _("The local email accounts are not enabled."), None if user_request == self.user: return True, None, None return ( False, - _("You don't have the right to edit another user's local" - " email account."), - ('users.change_emailaddress',) + _( + "You don't have the right to edit another user's local" + " email account." + ), + ("users.change_emailaddress",), ) def clean(self, *args, **kwargs): diff --git a/users/serializers.py b/users/serializers.py index 893b6c3a..65ac7ef1 100644 --- a/users/serializers.py +++ b/users/serializers.py @@ -33,11 +33,11 @@ from users.models import Club, Adherent class MailingSerializer(serializers.ModelSerializer): """ Serializer to build Mailing objects """ - name = serializers.CharField(source='pseudo') + name = serializers.CharField(source="pseudo") class Meta: model = Club - fields = ('name',) + fields = ("name",) class MailingMemberSerializer(serializers.ModelSerializer): @@ -46,4 +46,4 @@ class MailingMemberSerializer(serializers.ModelSerializer): class Meta: model = Adherent - fields = ('email',) + fields = ("email",) diff --git a/users/test_models.py b/users/test_models.py index e9cb7d7b..bb69cb79 100644 --- a/users/test_models.py +++ b/users/test_models.py @@ -6,25 +6,18 @@ from django.utils import timezone from users.models import User from cotisations.models import Vente, Facture, Paiement + class UserModelTests(TestCase): def setUp(self): - self.user = User.objects.create( - pseudo="testUser" - ) + self.user = User.objects.create(pseudo="testUser") def tearDown(self): self.user.facture_set.all().delete() self.user.delete() def test_multiple_cotisations_are_taken_into_account(self): - paiement = Paiement.objects.create( - moyen="test payment" - ) - invoice = Facture.objects.create( - user=self.user, - paiement=paiement, - valid=True - ) + paiement = Paiement.objects.create(moyen="test payment") + invoice = Facture.objects.create(user=self.user, paiement=paiement, valid=True) date = timezone.now() purchase1 = Vente.objects.create( facture=invoice, @@ -47,5 +40,5 @@ class UserModelTests(TestCase): self.assertAlmostEqual( self.user.end_connexion() - date, datetime.timedelta(days=2), - delta=datetime.timedelta(seconds=1) + delta=datetime.timedelta(seconds=1), ) diff --git a/users/tests.py b/users/tests.py index 2706c5af..f0ae8d09 100644 --- a/users/tests.py +++ b/users/tests.py @@ -62,26 +62,23 @@ class LdapUserTestCase(TestCase): user_password="{SSHA}aBcDeFgHiJkLmNoPqRsTuVwXyZ012345", sambat_nt_password="0123456789ABCDEF0123456789ABCDEF", macs=[], - shadowexpire="0" + shadowexpire="0", ) - self.assertEqual(g.name, 'users_test_ldapuser') + self.assertEqual(g.name, "users_test_ldapuser") class LdapUserGroupTestCase(TestCase): def test_create_ldap_user_group(self): g = models.LdapUserGroup.objects.create( - gid="501", - members=[], - name="users_test_ldapusergroup" + gid="501", members=[], name="users_test_ldapusergroup" ) - self.assertEqual(g.name, 'users_test_ldapusergroup') + self.assertEqual(g.name, "users_test_ldapusergroup") class LdapServiceUserTestCase(TestCase): def test_create_ldap_service_user(self): g = models.LdapServiceUser.objects.create( name="users_test_ldapserviceuser", - user_password="{SSHA}AbCdEfGhIjKlMnOpQrStUvWxYz987654" + user_password="{SSHA}AbCdEfGhIjKlMnOpQrStUvWxYz987654", ) - self.assertEqual(g.name, 'users_test_ldapserviceuser') - + self.assertEqual(g.name, "users_test_ldapserviceuser") diff --git a/users/urls.py b/users/urls.py index b31f374b..1cd303e6 100644 --- a/users/urls.py +++ b/users/urls.py @@ -31,98 +31,114 @@ from django.conf.urls import url from . import views urlpatterns = [ - url(r'^new_user/$', views.new_user, name='new-user'), - url(r'^new_club/$', views.new_club, name='new-club'), - url(r'^edit_info/(?P[0-9]+)$', views.edit_info, name='edit-info'), - url(r'^edit_club_admin_members/(?P[0-9]+)$', + url(r"^new_user/$", views.new_user, name="new-user"), + url(r"^new_club/$", views.new_club, name="new-club"), + url(r"^edit_info/(?P[0-9]+)$", views.edit_info, name="edit-info"), + url( + r"^edit_club_admin_members/(?P[0-9]+)$", views.edit_club_admin_members, - name='edit-club-admin-members'), - url(r'^state/(?P[0-9]+)$', views.state, name='state'), - url(r'^groups/(?P[0-9]+)$', views.groups, name='groups'), - url(r'^password/(?P[0-9]+)$', views.password, name='password'), - url(r'^del_group/(?P[0-9]+)/(?P[0-9]+)$', + name="edit-club-admin-members", + ), + url(r"^state/(?P[0-9]+)$", views.state, name="state"), + url(r"^groups/(?P[0-9]+)$", views.groups, name="groups"), + url(r"^password/(?P[0-9]+)$", views.password, name="password"), + url( + r"^del_group/(?P[0-9]+)/(?P[0-9]+)$", views.del_group, - name='del-group'), - url(r'^del_superuser/(?P[0-9]+)$', - views.del_superuser, - name='del-superuser'), - url(r'^new_serviceuser/$', views.new_serviceuser, name='new-serviceuser'), - url(r'^edit_serviceuser/(?P[0-9]+)$', + name="del-group", + ), + url( + r"^del_superuser/(?P[0-9]+)$", views.del_superuser, name="del-superuser" + ), + url(r"^new_serviceuser/$", views.new_serviceuser, name="new-serviceuser"), + url( + r"^edit_serviceuser/(?P[0-9]+)$", views.edit_serviceuser, - name='edit-serviceuser'), - url(r'^del_serviceuser/(?P[0-9]+)$', + name="edit-serviceuser", + ), + url( + r"^del_serviceuser/(?P[0-9]+)$", views.del_serviceuser, - name='del-serviceuser'), - url(r'^add_ban/(?P[0-9]+)$', views.add_ban, name='add-ban'), - url(r'^edit_ban/(?P[0-9]+)$', views.edit_ban, name='edit-ban'), - url(r'^del-ban/(?P[0-9]+)$', views.del_ban, name='del-ban'), - url(r'^add_whitelist/(?P[0-9]+)$', - views.add_whitelist, - name='add-whitelist'), - url(r'^edit_whitelist/(?P[0-9]+)$', + name="del-serviceuser", + ), + url(r"^add_ban/(?P[0-9]+)$", views.add_ban, name="add-ban"), + url(r"^edit_ban/(?P[0-9]+)$", views.edit_ban, name="edit-ban"), + url(r"^del-ban/(?P[0-9]+)$", views.del_ban, name="del-ban"), + url( + r"^add_whitelist/(?P[0-9]+)$", views.add_whitelist, name="add-whitelist" + ), + url( + r"^edit_whitelist/(?P[0-9]+)$", views.edit_whitelist, - name='edit-whitelist'), - url(r'^del_whitelist/(?P[0-9]+)$', + name="edit-whitelist", + ), + url( + r"^del_whitelist/(?P[0-9]+)$", views.del_whitelist, - name='del-whitelist'), - url(r'^add_emailaddress/(?P[0-9]+)$', + name="del-whitelist", + ), + url( + r"^add_emailaddress/(?P[0-9]+)$", views.add_emailaddress, - name='add-emailaddress'), - url(r'^edit_emailaddress/(?P[0-9]+)$', + name="add-emailaddress", + ), + url( + r"^edit_emailaddress/(?P[0-9]+)$", views.edit_emailaddress, - name='edit-emailaddress'), - url(r'^del_emailaddress/(?P[0-9]+)$', + name="edit-emailaddress", + ), + url( + r"^del_emailaddress/(?P[0-9]+)$", views.del_emailaddress, - name='del-emailaddress'), - url(r'^edit_email_settings/(?P[0-9]+)$', + name="del-emailaddress", + ), + url( + r"^edit_email_settings/(?P[0-9]+)$", views.edit_email_settings, - name='edit-email-settings'), - url(r'^add_school/$', views.add_school, name='add-school'), - url(r'^edit_school/(?P[0-9]+)$', - views.edit_school, - name='edit-school'), - url(r'^del_school/$', views.del_school, name='del-school'), - url(r'^add_listright/$', views.add_listright, name='add-listright'), - url(r'^edit_listright/(?P[0-9]+)$', + name="edit-email-settings", + ), + url(r"^add_school/$", views.add_school, name="add-school"), + url(r"^edit_school/(?P[0-9]+)$", views.edit_school, name="edit-school"), + url(r"^del_school/$", views.del_school, name="del-school"), + url(r"^add_listright/$", views.add_listright, name="add-listright"), + url( + r"^edit_listright/(?P[0-9]+)$", views.edit_listright, - name='edit-listright'), - url(r'^del_listright/$', views.del_listright, name='del-listright'), - url(r'^add_shell/$', views.add_shell, name='add-shell'), - url(r'^edit_shell/(?P[0-9]+)$', - views.edit_shell, - name='edit-shell'), - url(r'^del_shell/(?P[0-9]+)$', - views.del_shell, - name='del-shell'), - url(r'^profil/(?P[0-9]+)$', views.profil, name='profil'), - url(r'^index_ban/$', views.index_ban, name='index-ban'), - url(r'^index_white/$', views.index_white, name='index-white'), - url(r'^index_school/$', views.index_school, name='index-school'), - url(r'^index_shell/$', views.index_shell, name='index-shell'), - url(r'^index_listright/$', views.index_listright, name='index-listright'), - url(r'^index_serviceusers/$', - views.index_serviceusers, - name='index-serviceusers'), - url(r'^mon_profil/$', views.mon_profil, name='mon-profil'), - url(r'^process/(?P[a-z0-9]{32})/$', views.process, name='process'), - url(r'^reset_password/$', views.reset_password, name='reset-password'), - url(r'^mass_archive/$', views.mass_archive, name='mass-archive'), - url(r'^$', views.index, name='index'), - url(r'^index_clubs/$', views.index_clubs, name='index-clubs'), - url(r'^initial_register/$', views.initial_register, name='initial-register'), - url(r'^rest/ml/std/$', - views.ml_std_list, - name='ml-std-list'), - url(r'^rest/ml/std/member/(?P\w+)/$', + name="edit-listright", + ), + url(r"^del_listright/$", views.del_listright, name="del-listright"), + url(r"^add_shell/$", views.add_shell, name="add-shell"), + url(r"^edit_shell/(?P[0-9]+)$", views.edit_shell, name="edit-shell"), + url(r"^del_shell/(?P[0-9]+)$", views.del_shell, name="del-shell"), + url(r"^profil/(?P[0-9]+)$", views.profil, name="profil"), + url(r"^index_ban/$", views.index_ban, name="index-ban"), + url(r"^index_white/$", views.index_white, name="index-white"), + url(r"^index_school/$", views.index_school, name="index-school"), + url(r"^index_shell/$", views.index_shell, name="index-shell"), + url(r"^index_listright/$", views.index_listright, name="index-listright"), + url(r"^index_serviceusers/$", views.index_serviceusers, name="index-serviceusers"), + url(r"^mon_profil/$", views.mon_profil, name="mon-profil"), + url(r"^process/(?P[a-z0-9]{32})/$", views.process, name="process"), + url(r"^reset_password/$", views.reset_password, name="reset-password"), + url(r"^mass_archive/$", views.mass_archive, name="mass-archive"), + url(r"^$", views.index, name="index"), + url(r"^index_clubs/$", views.index_clubs, name="index-clubs"), + url(r"^initial_register/$", views.initial_register, name="initial-register"), + url(r"^rest/ml/std/$", views.ml_std_list, name="ml-std-list"), + url( + r"^rest/ml/std/member/(?P\w+)/$", views.ml_std_members, - name='ml-std-members'), - url(r'^rest/ml/club/$', - views.ml_club_list, - name='ml-club-list'), - url(r'^rest/ml/club/admin/(?P\w+)/$', + name="ml-std-members", + ), + url(r"^rest/ml/club/$", views.ml_club_list, name="ml-club-list"), + url( + r"^rest/ml/club/admin/(?P\w+)/$", views.ml_club_admins, - name='ml-club-admins'), - url(r'^rest/ml/club/member/(?P\w+)/$', + name="ml-club-admins", + ), + url( + r"^rest/ml/club/member/(?P\w+)/$", views.ml_club_members, - name='ml-club-members'), + name="ml-club-members", + ), ] diff --git a/users/views.py b/users/views.py index 9764fbe0..abc7025e 100644 --- a/users/views.py +++ b/users/views.py @@ -59,13 +59,8 @@ from preferences.models import OptionalUser, GeneralOption, AssoOption from importlib import import_module from re2o.settings_local import OPTIONNAL_APPS_RE2O from re2o.views import form -from re2o.utils import ( - all_has_access, -) -from re2o.base import ( - re2o_paginator, - SortTable -) +from re2o.utils import all_has_access +from re2o.base import re2o_paginator, SortTable from re2o.acl import ( can_create, can_edit, @@ -73,7 +68,7 @@ from re2o.acl import ( can_delete, can_view, can_view_all, - can_change + can_change, ) from cotisations.utils import find_payment_method from topologie.models import Port @@ -113,7 +108,7 @@ from .forms import ( ResetPasswordForm, ClubAdminandMembersForm, GroupForm, - InitialRegisterForm + InitialRegisterForm, ) @@ -122,27 +117,27 @@ def new_user(request): """ Vue de création d'un nouvel utilisateur, envoie un mail pour le mot de passe""" user = AdherentCreationForm(request.POST or None, user=request.user) - GTU_sum_up = GeneralOption.get_cached_value('GTU_sum_up') - GTU = GeneralOption.get_cached_value('GTU') + GTU_sum_up = GeneralOption.get_cached_value("GTU_sum_up") + GTU = GeneralOption.get_cached_value("GTU") if user.is_valid(): user = user.save() user.reset_passwd_mail(request) - messages.success(request, _("The user %s was created, an email to set" - " the password was sent.") % user.pseudo) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(user.id)} - )) + messages.success( + request, + _("The user %s was created, an email to set" " the password was sent.") + % user.pseudo, + ) + return redirect(reverse("users:profil", kwargs={"userid": str(user.id)})) return form( { - 'userform': user, - 'GTU_sum_up': GTU_sum_up, - 'GTU': GTU, - 'showCGU': True, - 'action_name': _("Commit") + "userform": user, + "GTU_sum_up": GTU_sum_up, + "GTU": GTU, + "showCGU": True, + "action_name": _("Commit"), }, - 'users/user.html', - request + "users/user.html", + request, ) @@ -156,16 +151,16 @@ def new_club(request): club = club.save(commit=False) club.save() club.reset_passwd_mail(request) - messages.success(request, _("The club %s was created, an email to set" - " the password was sent.") % club.pseudo) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(club.id)} - )) + messages.success( + request, + _("The club %s was created, an email to set" " the password was sent.") + % club.pseudo, + ) + return redirect(reverse("users:profil", kwargs={"userid": str(club.id)})) return form( - {'userform': club, 'showCGU': False, 'action_name': _("Create a club")}, - 'users/user.html', - request + {"userform": club, "showCGU": False, "action_name": _("Create a club")}, + "users/user.html", + request, ) @@ -174,26 +169,22 @@ def new_club(request): def edit_club_admin_members(request, club_instance, **_kwargs): """Vue d'edition de la liste des users administrateurs et membres d'un club""" - club = ClubAdminandMembersForm( - request.POST or None, - instance=club_instance - ) + club = ClubAdminandMembersForm(request.POST or None, instance=club_instance) if club.is_valid(): if club.changed_data: club.save() messages.success(request, _("The club was edited.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(club_instance.id)} - )) + return redirect( + reverse("users:profil", kwargs={"userid": str(club_instance.id)}) + ) return form( { - 'userform': club, - 'showCGU': False, - 'action_name': _("Edit the admins and members") + "userform": club, + "showCGU": False, + "action_name": _("Edit the admins and members"), }, - 'users/user.html', - request + "users/user.html", + request, ) @@ -205,33 +196,26 @@ def edit_info(request, user, userid): possession du droit cableur """ if user.is_class_adherent: user_form = AdherentEditForm( - request.POST or None, - instance=user.adherent, - user=request.user + request.POST or None, instance=user.adherent, user=request.user ) else: user_form = ClubForm( - request.POST or None, - instance=user.club, - user=request.user + request.POST or None, instance=user.club, user=request.user ) if user_form.is_valid(): if user_form.changed_data: user_form.save() messages.success(request, _("The user was edited.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(userid)} - )) + return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) return form( - {'userform': user_form, 'action_name': _("Edit the user")}, - 'users/user.html', - request + {"userform": user_form, "action_name": _("Edit the user")}, + "users/user.html", + request, ) @login_required -@can_edit(User, 'state') +@can_edit(User, "state") def state(request, user, userid): """ Change the state (active/unactive/archived) of a user""" state_form = StateForm(request.POST or None, instance=user) @@ -239,40 +223,33 @@ def state(request, user, userid): if state_form.changed_data: state_form.save() messages.success(request, _("The state was edited.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(userid)} - )) + return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) return form( - {'userform': state_form, 'action_name': _("Edit the state")}, - 'users/user.html', - request + {"userform": state_form, "action_name": _("Edit the state")}, + "users/user.html", + request, ) @login_required -@can_edit(User, 'groups') +@can_edit(User, "groups") def groups(request, user, userid): """ View to edit the groups of a user """ - group_form = GroupForm(request.POST or None, - instance=user, user=request.user) + group_form = GroupForm(request.POST or None, instance=user, user=request.user) if group_form.is_valid(): if group_form.changed_data: group_form.save() messages.success(request, _("The groups were edited.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(userid)} - )) + return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) return form( - {'userform': group_form, 'action_name': _("Edit the groups")}, - 'users/user.html', - request + {"userform": group_form, "action_name": _("Edit the groups")}, + "users/user.html", + request, ) @login_required -@can_edit(User, 'password') +@can_edit(User, "password") def password(request, user, userid): """ Reinitialisation d'un mot de passe à partir de l'userid, pour self par défaut, pour tous sans droit si droit cableur, @@ -282,35 +259,32 @@ def password(request, user, userid): if u_form.changed_data: u_form.save() messages.success(request, _("The password was changed.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(userid)} - )) + return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) return form( - {'userform': u_form, 'action_name': _("Change the password")}, - 'users/user.html', - request + {"userform": u_form, "action_name": _("Change the password")}, + "users/user.html", + request, ) @login_required -@can_edit(User, 'groups') +@can_edit(User, "groups") def del_group(request, user, listrightid, **_kwargs): """ View used to delete a group """ user.groups.remove(ListRight.objects.get(id=listrightid)) user.save() messages.success(request, _("%s was removed from the group.") % user) - return HttpResponseRedirect(request.META.get('HTTP_REFERER')) + return HttpResponseRedirect(request.META.get("HTTP_REFERER")) @login_required -@can_edit(User, 'is_superuser') +@can_edit(User, "is_superuser") def del_superuser(request, user, **_kwargs): """Remove the superuser right of an user.""" user.is_superuser = False user.save() messages.success(request, _("%s is no longer superuser.") % user) - return HttpResponseRedirect(request.META.get('HTTP_REFERER')) + return HttpResponseRedirect(request.META.get("HTTP_REFERER")) @login_required @@ -320,15 +294,12 @@ def new_serviceuser(request): user = ServiceUserForm(request.POST or None) if user.is_valid(): user.save() - messages.success( - request, - _("The service user was created.") - ) - return redirect(reverse('users:index-serviceusers')) + messages.success(request, _("The service user was created.")) + return redirect(reverse("users:index-serviceusers")) return form( - {'userform': user, 'action_name': _("Create a service user")}, - 'users/user.html', - request + {"userform": user, "action_name": _("Create a service user")}, + "users/user.html", + request, ) @@ -336,19 +307,16 @@ def new_serviceuser(request): @can_edit(ServiceUser) def edit_serviceuser(request, serviceuser, **_kwargs): """ Edit a ServiceUser """ - serviceuser = EditServiceUserForm( - request.POST or None, - instance=serviceuser - ) + serviceuser = EditServiceUserForm(request.POST or None, instance=serviceuser) if serviceuser.is_valid(): if serviceuser.changed_data: serviceuser.save() messages.success(request, _("The service user was edited.")) - return redirect(reverse('users:index-serviceusers')) + return redirect(reverse("users:index-serviceusers")) return form( - {'userform': serviceuser, 'action_name': _("Edit a service user")}, - 'users/user.html', - request + {"userform": serviceuser, "action_name": _("Edit a service user")}, + "users/user.html", + request, ) @@ -359,11 +327,11 @@ def del_serviceuser(request, serviceuser, **_kwargs): if request.method == "POST": serviceuser.delete() messages.success(request, _("The service user was deleted.")) - return redirect(reverse('users:index-serviceusers')) + return redirect(reverse("users:index-serviceusers")) return form( - {'objet': serviceuser, 'objet_name': 'service user'}, - 'users/delete.html', - request + {"objet": serviceuser, "objet_name": "service user"}, + "users/delete.html", + request, ) @@ -379,19 +347,11 @@ def add_ban(request, user, userid): if ban.is_valid(): ban.save() messages.success(request, _("The ban was added.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(userid)} - )) + return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) if user.is_ban(): - messages.error( - request, - _("Warning: this user already has an active ban.") - ) + messages.error(request, _("Warning: this user already has an active ban.")) return form( - {'userform': ban, 'action_name': _("Add a ban")}, - 'users/user.html', - request + {"userform": ban, "action_name": _("Add a ban")}, "users/user.html", request ) @@ -406,11 +366,9 @@ def edit_ban(request, ban_instance, **_kwargs): if ban.changed_data: ban.save() messages.success(request, _("The ban was edited.")) - return redirect(reverse('users:index')) + return redirect(reverse("users:index")) return form( - {'userform': ban, 'action_name': _("Edit a ban")}, - 'users/user.html', - request + {"userform": ban, "action_name": _("Edit a ban")}, "users/user.html", request ) @@ -421,15 +379,8 @@ def del_ban(request, ban, **_kwargs): if request.method == "POST": ban.delete() messages.success(request, _("The ban was deleted.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(ban.user.id)} - )) - return form( - {'objet': ban, 'objet_name': 'ban'}, - 'users/delete.html', - request - ) + return redirect(reverse("users:profil", kwargs={"userid": str(ban.user.id)})) + return form({"objet": ban, "objet_name": "ban"}, "users/delete.html", request) @login_required @@ -441,26 +392,19 @@ def add_whitelist(request, user, userid): Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement, raison obligatoire""" whitelist_instance = Whitelist(user=user) - whitelist = WhitelistForm( - request.POST or None, - instance=whitelist_instance - ) + whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance) if whitelist.is_valid(): whitelist.save() messages.success(request, _("The whitelist was added.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(userid)} - )) + return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) if user.is_whitelisted(): messages.error( - request, - _("Warning: this user already has an active whitelist.") + request, _("Warning: this user already has an active whitelist.") ) return form( - {'userform': whitelist, 'action_name': _("Add a whitelist")}, - 'users/user.html', - request + {"userform": whitelist, "action_name": _("Add a whitelist")}, + "users/user.html", + request, ) @@ -471,19 +415,16 @@ def edit_whitelist(request, whitelist_instance, **_kwargs): Need droit cableur Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement, raison obligatoire""" - whitelist = WhitelistForm( - request.POST or None, - instance=whitelist_instance - ) + whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance) if whitelist.is_valid(): if whitelist.changed_data: whitelist.save() messages.success(request, _("The whitelist was edited.")) - return redirect(reverse('users:index')) + return redirect(reverse("users:index")) return form( - {'userform': whitelist, 'action_name': _("Edit a whitelist")}, - 'users/user.html', - request + {"userform": whitelist, "action_name": _("Edit a whitelist")}, + "users/user.html", + request, ) @@ -494,14 +435,11 @@ def del_whitelist(request, whitelist, **_kwargs): if request.method == "POST": whitelist.delete() messages.success(request, _("The whitelist was deleted.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(whitelist.user.id)} - )) + return redirect( + reverse("users:profil", kwargs={"userid": str(whitelist.user.id)}) + ) return form( - {'objet': whitelist, 'objet_name': 'whitelist'}, - 'users/delete.html', - request + {"objet": whitelist, "objet_name": "whitelist"}, "users/delete.html", request ) @@ -512,22 +450,20 @@ def add_emailaddress(request, user, userid): """ Create a new local email account""" emailaddress_instance = EMailAddress(user=user) emailaddress = EMailAddressForm( - request.POST or None, - instance=emailaddress_instance + request.POST or None, instance=emailaddress_instance ) if emailaddress.is_valid(): emailaddress.save() messages.success(request, _("The local email account was created.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(userid)} - )) + return redirect(reverse("users:profil", kwargs={"userid": str(userid)})) return form( - {'userform': emailaddress, - 'showCGU': False, - 'action_name': _("Add a local email account")}, - 'users/user.html', - request + { + "userform": emailaddress, + "showCGU": False, + "action_name": _("Add a local email account"), + }, + "users/user.html", + request, ) @@ -536,23 +472,25 @@ def add_emailaddress(request, user, userid): def edit_emailaddress(request, emailaddress_instance, **_kwargs): """ Edit a local email account""" emailaddress = EMailAddressForm( - request.POST or None, - instance=emailaddress_instance + request.POST or None, instance=emailaddress_instance ) if emailaddress.is_valid(): if emailaddress.changed_data: emailaddress.save() messages.success(request, _("The local email account was edited.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(emailaddress_instance.user.id)} - )) + return redirect( + reverse( + "users:profil", kwargs={"userid": str(emailaddress_instance.user.id)} + ) + ) return form( - {'userform': emailaddress, - 'showCGU': False, - 'action_name': _("Edit a local email account")}, - 'users/user.html', - request + { + "userform": emailaddress, + "showCGU": False, + "action_name": _("Edit a local email account"), + }, + "users/user.html", + request, ) @@ -563,14 +501,13 @@ def del_emailaddress(request, emailaddress, **_kwargs): if request.method == "POST": emailaddress.delete() messages.success(request, _("The local email account was deleted.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(emailaddress.user.id)} - )) + return redirect( + reverse("users:profil", kwargs={"userid": str(emailaddress.user.id)}) + ) return form( - {'objet': emailaddress, 'objet_name': 'emailaddress'}, - 'users/delete.html', - request + {"objet": emailaddress, "objet_name": "emailaddress"}, + "users/delete.html", + request, ) @@ -579,25 +516,24 @@ def del_emailaddress(request, emailaddress, **_kwargs): def edit_email_settings(request, user_instance, **_kwargs): """Edit the email settings of a user""" email_settings = EmailSettingsForm( - request.POST or None, - instance=user_instance, - user=request.user + request.POST or None, instance=user_instance, user=request.user ) if email_settings.is_valid(): if email_settings.changed_data: email_settings.save() messages.success(request, _("The email settings were edited.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(user_instance.id)} - )) + return redirect( + reverse("users:profil", kwargs={"userid": str(user_instance.id)}) + ) return form( - {'userform': email_settings, - 'showCGU': False, - 'load_js_file': '/static/js/email_address.js', - 'action_name': _("Edit the email settings")}, - 'users/user.html', - request + { + "userform": email_settings, + "showCGU": False, + "load_js_file": "/static/js/email_address.js", + "action_name": _("Edit the email settings"), + }, + "users/user.html", + request, ) @@ -610,11 +546,11 @@ def add_school(request): if school.is_valid(): school.save() messages.success(request, _("The school was added.")) - return redirect(reverse('users:index-school')) + return redirect(reverse("users:index-school")) return form( - {'userform': school, 'action_name': _("Add a school")}, - 'users/user.html', - request + {"userform": school, "action_name": _("Add a school")}, + "users/user.html", + request, ) @@ -628,11 +564,11 @@ def edit_school(request, school_instance, **_kwargs): if school.changed_data: school.save() messages.success(request, _("The school was edited.")) - return redirect(reverse('users:index-school')) + return redirect(reverse("users:index-school")) return form( - {'userform': school, 'action_name': _("Edit a school")}, - 'users/user.html', - request + {"userform": school, "action_name": _("Edit a school")}, + "users/user.html", + request, ) @@ -645,7 +581,7 @@ def del_school(request, instances): l'établissement """ school = DelSchoolForm(request.POST or None, instances=instances) if school.is_valid(): - school_dels = school.cleaned_data['schools'] + school_dels = school.cleaned_data["schools"] for school_del in school_dels: try: school_del.delete() @@ -653,13 +589,15 @@ def del_school(request, instances): except ProtectedError: messages.error( request, - _("The school %s is assigned to at least one user," - " impossible to delete it.") % school_del) - return redirect(reverse('users:index-school')) + _( + "The school %s is assigned to at least one user," + " impossible to delete it." + ) + % school_del, + ) + return redirect(reverse("users:index-school")) return form( - {'userform': school, 'action_name': _("Delete")}, - 'users/user.html', - request + {"userform": school, "action_name": _("Delete")}, "users/user.html", request ) @@ -671,11 +609,9 @@ def add_shell(request): if shell.is_valid(): shell.save() messages.success(request, _("The shell was added.")) - return redirect(reverse('users:index-shell')) + return redirect(reverse("users:index-shell")) return form( - {'userform': shell, 'action_name': _("Add a shell")}, - 'users/user.html', - request + {"userform": shell, "action_name": _("Add a shell")}, "users/user.html", request ) @@ -688,11 +624,11 @@ def edit_shell(request, shell_instance, **_kwargs): if shell.changed_data: shell.save() messages.success(request, _("The shell was edited.")) - return redirect(reverse('users:index-shell')) + return redirect(reverse("users:index-shell")) return form( - {'userform': shell, 'action_name': _("Edit a shell")}, - 'users/user.html', - request + {"userform": shell, "action_name": _("Edit a shell")}, + "users/user.html", + request, ) @@ -703,12 +639,8 @@ def del_shell(request, shell, **_kwargs): if request.method == "POST": shell.delete() messages.success(request, _("The shell was deleted.")) - return redirect(reverse('users:index-shell')) - return form( - {'objet': shell, 'objet_name': 'shell'}, - 'users/delete.html', - request - ) + return redirect(reverse("users:index-shell")) + return form({"objet": shell, "objet_name": "shell"}, "users/delete.html", request) @login_required @@ -720,11 +652,11 @@ def add_listright(request): if listright.is_valid(): listright.save() messages.success(request, _("The group of rights was added.")) - return redirect(reverse('users:index-listright')) + return redirect(reverse("users:index-listright")) return form( - {'userform': listright, 'action_name': _("Add a group of rights")}, - 'users/user.html', - request + {"userform": listright, "action_name": _("Add a group of rights")}, + "users/user.html", + request, ) @@ -733,19 +665,16 @@ def add_listright(request): def edit_listright(request, listright_instance, **_kwargs): """ Editer un groupe/droit, necessite droit bureau, à partir du listright id """ - listright = ListRightForm( - request.POST or None, - instance=listright_instance - ) + listright = ListRightForm(request.POST or None, instance=listright_instance) if listright.is_valid(): if listright.changed_data: listright.save() messages.success(request, _("The group of rights was edited.")) - return redirect(reverse('users:index-listright')) + return redirect(reverse("users:index-listright")) return form( - {'userform': listright, 'action_name': _("Edit a group of rights")}, - 'users/user.html', - request + {"userform": listright, "action_name": _("Edit a group of rights")}, + "users/user.html", + request, ) @@ -756,37 +685,43 @@ def del_listright(request, instances): bureau """ listright = DelListRightForm(request.POST or None, instances=instances) if listright.is_valid(): - listright_dels = listright.cleaned_data['listrights'] + listright_dels = listright.cleaned_data["listrights"] for listright_del in listright_dels: try: listright_del.delete() - messages.success(request, _("The group of rights was" - " deleted.")) + messages.success(request, _("The group of rights was" " deleted.")) except ProtectedError: messages.error( request, - _("The group of rights %s is assigned to at least one" - " user, impossible to delete it.") % listright_del) - return redirect(reverse('users:index-listright')) + _( + "The group of rights %s is assigned to at least one" + " user, impossible to delete it." + ) + % listright_del, + ) + return redirect(reverse("users:index-listright")) return form( - {'userform': listright, 'action_name': _("Delete")}, - 'users/user.html', - request + {"userform": listright, "action_name": _("Delete")}, "users/user.html", request ) @login_required @can_view_all(User) -@can_change(User, 'state') +@can_change(User, "state") def mass_archive(request): """ Permet l'archivage massif""" - pagination_number = GeneralOption.get_cached_value('pagination_number') + pagination_number = GeneralOption.get_cached_value("pagination_number") to_archive_form = MassArchiveForm(request.POST or None) to_archive_list = [] if to_archive_form.is_valid(): - date = to_archive_form.cleaned_data['date'] - full_archive = to_archive_form.cleaned_data['full_archive'] - to_archive_list = User.objects.exclude(id__in=all_has_access()).exclude(id__in=all_has_access(search_time=date)).exclude(state=User.STATE_NOT_YET_ACTIVE).exclude(state=User.STATE_FULL_ARCHIVE) + date = to_archive_form.cleaned_data["date"] + full_archive = to_archive_form.cleaned_data["full_archive"] + to_archive_list = ( + User.objects.exclude(id__in=all_has_access()) + .exclude(id__in=all_has_access(search_time=date)) + .exclude(state=User.STATE_NOT_YET_ACTIVE) + .exclude(state=User.STATE_FULL_ARCHIVE) + ) if not full_archive: to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE) if "valider" in request.POST: @@ -794,15 +729,15 @@ def mass_archive(request): User.mass_full_archive(to_archive_list) else: User.mass_archive(to_archive_list) - messages.success(request, _("%s users were archived.") % - to_archive_list.count() + messages.success( + request, _("%s users were archived.") % to_archive_list.count() ) - return redirect(reverse('users:index')) + return redirect(reverse("users:index")) to_archive_list = re2o_paginator(request, to_archive_list, pagination_number) return form( - {'userform': to_archive_form, 'to_archive_list': to_archive_list}, - 'users/mass_archive.html', - request + {"userform": to_archive_form, "to_archive_list": to_archive_list}, + "users/mass_archive.html", + request, ) @@ -810,104 +745,88 @@ def mass_archive(request): @can_view_all(Adherent) def index(request): """ Affiche l'ensemble des adherents, need droit cableur """ - pagination_number = GeneralOption.get_cached_value('pagination_number') - users_list = Adherent.objects.select_related('room') + pagination_number = GeneralOption.get_cached_value("pagination_number") + users_list = Adherent.objects.select_related("room") users_list = SortTable.sort( users_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.USERS_INDEX + request.GET.get("col"), + request.GET.get("order"), + SortTable.USERS_INDEX, ) users_list = re2o_paginator(request, users_list, pagination_number) - return render(request, 'users/index.html', {'users_list': users_list}) + return render(request, "users/index.html", {"users_list": users_list}) @login_required @can_view_all(Club) def index_clubs(request): """ Affiche l'ensemble des clubs, need droit cableur """ - pagination_number = GeneralOption.get_cached_value('pagination_number') - clubs_list = Club.objects.select_related('room') + pagination_number = GeneralOption.get_cached_value("pagination_number") + clubs_list = Club.objects.select_related("room") clubs_list = SortTable.sort( clubs_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.USERS_INDEX + request.GET.get("col"), + request.GET.get("order"), + SortTable.USERS_INDEX, ) clubs_list = re2o_paginator(request, clubs_list, pagination_number) - return render( - request, - 'users/index_clubs.html', - {'clubs_list': clubs_list} - ) + return render(request, "users/index_clubs.html", {"clubs_list": clubs_list}) @login_required @can_view_all(Ban) def index_ban(request): """ Affiche l'ensemble des ban, need droit cableur """ - pagination_number = GeneralOption.get_cached_value('pagination_number') - ban_list = Ban.objects.select_related('user') + pagination_number = GeneralOption.get_cached_value("pagination_number") + ban_list = Ban.objects.select_related("user") ban_list = SortTable.sort( ban_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.USERS_INDEX_BAN + request.GET.get("col"), + request.GET.get("order"), + SortTable.USERS_INDEX_BAN, ) ban_list = re2o_paginator(request, ban_list, pagination_number) - return render(request, 'users/index_ban.html', {'ban_list': ban_list}) + return render(request, "users/index_ban.html", {"ban_list": ban_list}) @login_required @can_view_all(Whitelist) def index_white(request): """ Affiche l'ensemble des whitelist, need droit cableur """ - pagination_number = GeneralOption.get_cached_value('pagination_number') - white_list = Whitelist.objects.select_related('user') + pagination_number = GeneralOption.get_cached_value("pagination_number") + white_list = Whitelist.objects.select_related("user") white_list = SortTable.sort( white_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.USERS_INDEX_BAN + request.GET.get("col"), + request.GET.get("order"), + SortTable.USERS_INDEX_BAN, ) white_list = re2o_paginator(request, white_list, pagination_number) - return render( - request, - 'users/index_whitelist.html', - {'white_list': white_list} - ) + return render(request, "users/index_whitelist.html", {"white_list": white_list}) @login_required @can_view_all(School) def index_school(request): """ Affiche l'ensemble des établissement""" - school_list = School.objects.order_by('name') - pagination_number = GeneralOption.get_cached_value('pagination_number') + school_list = School.objects.order_by("name") + pagination_number = GeneralOption.get_cached_value("pagination_number") school_list = SortTable.sort( school_list, - request.GET.get('col'), - request.GET.get('order'), - SortTable.USERS_INDEX_SCHOOL + request.GET.get("col"), + request.GET.get("order"), + SortTable.USERS_INDEX_SCHOOL, ) school_list = re2o_paginator(request, school_list, pagination_number) - return render( - request, - 'users/index_schools.html', - {'school_list': school_list} - ) + return render(request, "users/index_schools.html", {"school_list": school_list}) @login_required @can_view_all(ListShell) def index_shell(request): """ Affiche l'ensemble des shells""" - shell_list = ListShell.objects.order_by('shell') - return render( - request, - 'users/index_shell.html', - {'shell_list': shell_list} - ) + shell_list = ListShell.objects.order_by("shell") + return render(request, "users/index_shell.html", {"shell_list": shell_list}) @login_required @@ -915,27 +834,21 @@ def index_shell(request): def index_listright(request): """ Affiche l'ensemble des droits""" rights = {} - for right in (ListRight.objects - .order_by('name') - .prefetch_related('permissions') - .prefetch_related('user_set') - ): - rights[right] = (right.user_set - .annotate(action_number=Count('revision'), - last_seen=Max('revision__date_created')) - ) - superusers = (User.objects - .filter(is_superuser=True) - .annotate(action_number=Count('revision'), - last_seen=Max('revision__date_created')) - ) + for right in ( + ListRight.objects.order_by("name") + .prefetch_related("permissions") + .prefetch_related("user_set") + ): + rights[right] = right.user_set.annotate( + action_number=Count("revision"), last_seen=Max("revision__date_created") + ) + superusers = User.objects.filter(is_superuser=True).annotate( + action_number=Count("revision"), last_seen=Max("revision__date_created") + ) return render( request, - 'users/index_listright.html', - { - 'rights': rights, - 'superusers' : superusers, - } + "users/index_listright.html", + {"rights": rights, "superusers": superusers}, ) @@ -943,96 +856,95 @@ def index_listright(request): @can_view_all(ServiceUser) def index_serviceusers(request): """ Affiche les users de services (pour les accès ldap)""" - serviceusers_list = ServiceUser.objects.order_by('pseudo') + serviceusers_list = ServiceUser.objects.order_by("pseudo") return render( request, - 'users/index_serviceusers.html', - {'serviceusers_list': serviceusers_list} + "users/index_serviceusers.html", + {"serviceusers_list": serviceusers_list}, ) @login_required def mon_profil(request): """ Lien vers profil, renvoie request.id à la fonction """ - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(request.user.id)} - )) + return redirect(reverse("users:profil", kwargs={"userid": str(request.user.id)})) @login_required @can_view(User) def profil(request, users, **_kwargs): """ Affiche un profil, self or cableur, prend un userid en argument """ - machines = Machine.objects.filter(user=users).select_related('user')\ - .prefetch_related('interface_set__domain__extension')\ - .prefetch_related('interface_set__ipv4__ip_type__extension')\ - .prefetch_related('interface_set__machine_type')\ - .prefetch_related('interface_set__domain__related_domain__extension') + machines = ( + Machine.objects.filter(user=users) + .select_related("user") + .prefetch_related("interface_set__domain__extension") + .prefetch_related("interface_set__ipv4__ip_type__extension") + .prefetch_related("interface_set__machine_type") + .prefetch_related("interface_set__domain__related_domain__extension") + ) machines = SortTable.sort( machines, - request.GET.get('col'), - request.GET.get('order'), - SortTable.MACHINES_INDEX + request.GET.get("col"), + request.GET.get("order"), + SortTable.MACHINES_INDEX, ) optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] - optionnal_templates_list = [app.views.profil(request,users) for app in optionnal_apps if hasattr(app.views, 'profil')] + optionnal_templates_list = [ + app.views.profil(request, users) + for app in optionnal_apps + if hasattr(app.views, "profil") + ] - pagination_large_number = GeneralOption.get_cached_value( - 'pagination_large_number' - ) + pagination_large_number = GeneralOption.get_cached_value("pagination_large_number") nb_machines = machines.count() machines = re2o_paginator(request, machines, pagination_large_number) factures = Facture.objects.filter(user=users) factures = SortTable.sort( factures, - request.GET.get('col'), - request.GET.get('order'), - SortTable.COTISATIONS_INDEX + request.GET.get("col"), + request.GET.get("order"), + SortTable.COTISATIONS_INDEX, ) bans = Ban.objects.filter(user=users) bans = SortTable.sort( bans, - request.GET.get('col'), - request.GET.get('order'), - SortTable.USERS_INDEX_BAN + request.GET.get("col"), + request.GET.get("order"), + SortTable.USERS_INDEX_BAN, ) whitelists = Whitelist.objects.filter(user=users) whitelists = SortTable.sort( whitelists, - request.GET.get('col'), - request.GET.get('order'), - SortTable.USERS_INDEX_WHITE + request.GET.get("col"), + request.GET.get("order"), + SortTable.USERS_INDEX_WHITE, ) try: balance = find_payment_method(Paiement.objects.get(is_balance=True)) except Paiement.DoesNotExist: user_solde = False else: - user_solde = ( - balance is not None - and balance.can_credit_balance(request.user) - ) + user_solde = balance is not None and balance.can_credit_balance(request.user) return render( request, - 'users/profil.html', + "users/profil.html", { - 'users': users, - 'machines_list': machines, - 'nb_machines': nb_machines, - 'optionnal_templates_list': optionnal_templates_list, - 'facture_list': factures, - 'ban_list': bans, - 'white_list': whitelists, - 'user_solde': user_solde, - 'solde_activated': Paiement.objects.filter(is_balance=True).exists(), - 'asso_name': AssoOption.objects.first().name, - 'emailaddress_list': users.email_address, - 'local_email_accounts_enabled': ( + "users": users, + "machines_list": machines, + "nb_machines": nb_machines, + "optionnal_templates_list": optionnal_templates_list, + "facture_list": factures, + "ban_list": bans, + "white_list": whitelists, + "user_solde": user_solde, + "solde_activated": Paiement.objects.filter(is_balance=True).exists(), + "asso_name": AssoOption.objects.first().name, + "emailaddress_list": users.email_address, + "local_email_accounts_enabled": ( OptionalUser.objects.first().local_email_accounts_enabled - ) - } + ), + }, ) @@ -1042,24 +954,22 @@ def reset_password(request): if userform.is_valid(): try: user = User.objects.get( - pseudo=userform.cleaned_data['pseudo'], - email=userform.cleaned_data['email'], + pseudo=userform.cleaned_data["pseudo"], + email=userform.cleaned_data["email"], state__in=[User.STATE_ACTIVE, User.STATE_NOT_YET_ACTIVE], ) except User.DoesNotExist: messages.error(request, _("The user doesn't exist.")) return form( - {'userform': userform, 'action_name': _("Reset")}, - 'users/user.html', - request + {"userform": userform, "action_name": _("Reset")}, + "users/user.html", + request, ) user.reset_passwd_mail(request) messages.success(request, _("An email to reset the password was sent.")) - redirect(reverse('index')) + redirect(reverse("index")) return form( - {'userform': userform, 'action_name': _("Reset")}, - 'users/user.html', - request + {"userform": userform, "action_name": _("Reset")}, "users/user.html", request ) @@ -1072,7 +982,7 @@ def process(request, token): return process_passwd(request, req) else: messages.error(request, _("Error: please contact an admin.")) - redirect(reverse('index')) + redirect(reverse("index")) def process_passwd(request, req): @@ -1086,40 +996,49 @@ def process_passwd(request, req): reversion.set_comment(_("Password reset")) req.delete() messages.success(request, _("The password was changed.")) - return redirect(reverse('index')) + return redirect(reverse("index")) return form( - {'userform': u_form, 'action_name': _("Change the password")}, - 'users/user.html', - request + {"userform": u_form, "action_name": _("Change the password")}, + "users/user.html", + request, ) + @login_required def initial_register(request): - switch_ip = request.GET.get('switch_ip', None) - switch_port = request.GET.get('switch_port', None) - client_mac = request.GET.get('client_mac', None) - u_form = InitialRegisterForm(request.POST or None, user=request.user, switch_ip=switch_ip, switch_port=switch_port, client_mac=client_mac) + switch_ip = request.GET.get("switch_ip", None) + switch_port = request.GET.get("switch_port", None) + client_mac = request.GET.get("client_mac", None) + u_form = InitialRegisterForm( + request.POST or None, + user=request.user, + switch_ip=switch_ip, + switch_port=switch_port, + client_mac=client_mac, + ) if not u_form.fields: messages.error(request, _("Incorrect URL, or already registered device.")) - return redirect(reverse( - 'users:profil', - kwargs={'userid': str(request.user.id)} - )) - if switch_ip and switch_port: - port = Port.objects.filter(switch__interface__ipv4__ipv4=switch_ip, port=switch_port).first() - if u_form.is_valid(): - messages.success(request, _("Successful registration! Please" - " disconnect and reconnect your Ethernet" - " cable to get Internet access.")) - return form( - {}, - 'users/plugin_out.html', - request + return redirect( + reverse("users:profil", kwargs={"userid": str(request.user.id)}) ) + if switch_ip and switch_port: + port = Port.objects.filter( + switch__interface__ipv4__ipv4=switch_ip, port=switch_port + ).first() + if u_form.is_valid(): + messages.success( + request, + _( + "Successful registration! Please" + " disconnect and reconnect your Ethernet" + " cable to get Internet access." + ), + ) + return form({}, "users/plugin_out.html", request) return form( - {'userform': u_form, 'port': port, 'mac': client_mac}, - 'users/user_autocapture.html', - request + {"userform": u_form, "port": port, "mac": client_mac}, + "users/user_autocapture.html", + request, ) @@ -1128,75 +1047,72 @@ class JSONResponse(HttpResponse): def __init__(self, data, **kwargs): content = JSONRenderer().render(data) - kwargs['content_type'] = 'application/json' + kwargs["content_type"] = "application/json" super(JSONResponse, self).__init__(content, **kwargs) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def ml_std_list(_request): """ API view sending all the available standard mailings""" - return JSONResponse([ - {'name': 'adherents'} - ]) + return JSONResponse([{"name": "adherents"}]) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def ml_std_members(request, ml_name): """ API view sending all the members for a standard mailing""" # All with active connextion - if ml_name == 'adherents': - members = all_has_access().values('email').distinct() + if ml_name == "adherents": + members = all_has_access().values("email").distinct() # Unknown mailing else: messages.error(request, _("The mailing list doesn't exist.")) - return redirect(reverse('index')) + return redirect(reverse("index")) seria = MailingMemberSerializer(members, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def ml_club_list(_request): """ API view sending all the available club mailings""" - clubs = Club.objects.filter(mailing=True).values('pseudo') + clubs = Club.objects.filter(mailing=True).values("pseudo") seria = MailingSerializer(clubs, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def ml_club_admins(request, ml_name): """ API view sending all the administrators for a specific club mailing""" try: club = Club.objects.get(mailing=True, pseudo=ml_name) except Club.DoesNotExist: messages.error(request, _("The mailing list doesn't exist.")) - return redirect(reverse('index')) - members = club.administrators.all().values('email').distinct() + return redirect(reverse("index")) + members = club.administrators.all().values("email").distinct() seria = MailingMemberSerializer(members, many=True) return JSONResponse(seria.data) @csrf_exempt @login_required -@permission_required('machines.serveur') +@permission_required("machines.serveur") def ml_club_members(request, ml_name): """ API view sending all the members for a specific club mailing""" try: club = Club.objects.get(mailing=True, pseudo=ml_name) except Club.DoesNotExist: messages.error(request, _("The mailing list doesn't exist.")) - return redirect(reverse('index')) + return redirect(reverse("index")) members = ( - club.administrators.all().values('email').distinct() | - club.members.all().values('email').distinct() + club.administrators.all().values("email").distinct() + | club.members.all().values("email").distinct() ) seria = MailingMemberSerializer(members, many=True) return JSONResponse(seria.data) - diff --git a/users/widgets.py b/users/widgets.py index bfacb7d5..81cced82 100644 --- a/users/widgets.py +++ b/users/widgets.py @@ -1,19 +1,20 @@ -from django.forms.widgets import Input -from django.forms.utils import flatatt -from django.utils.safestring import mark_safe -from django.template import Template -from django.template.loader import get_template -from django.conf import settings -from django.utils.translation import ugettext_lazy as _, get_language_bidi -from django.utils.dates import ( - WEEKDAYS, - WEEKDAYS_ABBR, - MONTHS, - MONTHS_3, - MONTHS_AP, - MONTHS_ALT +from django.forms.widgets import Input +from django.forms.utils import flatatt +from django.utils.safestring import mark_safe +from django.template import Template +from django.template.loader import get_template +from django.conf import settings +from django.utils.translation import ugettext_lazy as _, get_language_bidi +from django.utils.dates import ( + WEEKDAYS, + WEEKDAYS_ABBR, + MONTHS, + MONTHS_3, + MONTHS_AP, + MONTHS_ALT, ) + def list2str(str_iterable): """ Utility function to return a string representing a list of string @@ -22,29 +23,42 @@ def list2str(str_iterable): :returns: A representation of the iterable as a list (e.g '["a", "b"]') """ return '["' + '", "'.join(str_iterable) + '"]' - + + class DateTimePicker(Input): is_localized = False - def render(self, name, value, attrs=None): - super().render(name, value, attrs) + + def render(self, name, value, attrs=None): + super().render(name, value, attrs) flat_attrs = flatatt(attrs) context = { - 'name': name, - 'attrs': flat_attrs, - 'id': attrs['id'], - 'closeText': _("Close"), - 'currentText': _("Today"), - 'dayNames': mark_safe(list2str((str(item[1]) for item in WEEKDAYS.items()))), - 'dayNamesMin': mark_safe(list2str((str(item[1]) for item in WEEKDAYS_ABBR.items()))), - 'dayNamesShort': mark_safe(list2str((str(item[1]) for item in WEEKDAYS_ABBR.items()))), - 'firstDay': mark_safe('"' + str(WEEKDAYS[settings.FIRST_DAY_OF_WEEK]) + '"'), - 'isRTL': str(get_language_bidi()).lower(), - 'monthNames': mark_safe(list2str((str(item[1]) for item in MONTHS.items()))), - 'monthNamesShort': mark_safe(list2str((str(item[1]) for item in MONTHS_3.items()))), - 'nextText': mark_safe('"' + str(_('Next')) + '"'), - 'prevText': mark_safe('"' + str(_('Previous')) + '"'), - 'weekHeader': mark_safe('"' + str(_('Wk')) + '"' ), - } - template = get_template('users/datetimepicker.html') - return template.render(context) - + "name": name, + "attrs": flat_attrs, + "id": attrs["id"], + "closeText": _("Close"), + "currentText": _("Today"), + "dayNames": mark_safe( + list2str((str(item[1]) for item in WEEKDAYS.items())) + ), + "dayNamesMin": mark_safe( + list2str((str(item[1]) for item in WEEKDAYS_ABBR.items())) + ), + "dayNamesShort": mark_safe( + list2str((str(item[1]) for item in WEEKDAYS_ABBR.items())) + ), + "firstDay": mark_safe( + '"' + str(WEEKDAYS[settings.FIRST_DAY_OF_WEEK]) + '"' + ), + "isRTL": str(get_language_bidi()).lower(), + "monthNames": mark_safe( + list2str((str(item[1]) for item in MONTHS.items())) + ), + "monthNamesShort": mark_safe( + list2str((str(item[1]) for item in MONTHS_3.items())) + ), + "nextText": mark_safe('"' + str(_("Next")) + '"'), + "prevText": mark_safe('"' + str(_("Previous")) + '"'), + "weekHeader": mark_safe('"' + str(_("Wk")) + '"'), + } + template = get_template("users/datetimepicker.html") + return template.render(context) From 35ba5b6e4937668e24e8a14fdc21f52e62ebc000 Mon Sep 17 00:00:00 2001 From: nanoy Date: Sat, 16 Nov 2019 19:22:03 +0100 Subject: [PATCH 188/228] Add spaces where needed. --- .../templates/preferences/display_preferences.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index fcc9064f..aae99d74 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -210,7 +210,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    @@ -387,7 +387,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    @@ -414,7 +414,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    @@ -465,7 +465,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,

    - {% trans "Social networks" %} + {% trans "Social networks" %}

    From 09da1b4d43bbef0fbf223b801bed918e7bbf3459 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Sun, 17 Nov 2019 11:58:23 +0000 Subject: [PATCH 189/228] Fix klafy horrors --- cotisations/tex.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cotisations/tex.py b/cotisations/tex.py index 45ded1aa..6872ac6a 100644 --- a/cotisations/tex.py +++ b/cotisations/tex.py @@ -110,13 +110,12 @@ def create_pdf(template, ctx={}): with tempfile.TemporaryDirectory() as tempdir: for _ in range(2): - with open("/var/www/re2o/out.log", "w") as f: - process = Popen( - ["pdflatex", "-output-directory", tempdir], - stdin=PIPE, - stdout=f, # PIPE, - ) - process.communicate(rendered_tpl) + process = Popen( + ["pdflatex", "-output-directory", tempdir], + stdin=PIPE, + stdout=PIPE, + ) + process.communicate(rendered_tpl) with open(os.path.join(tempdir, "texput.pdf"), "rb") as f: pdf = f.read() From 755e95e6441b0706646e779cd2082b7a0e0762d6 Mon Sep 17 00:00:00 2001 From: Jean-Roman Garnier Date: Sun, 24 Nov 2019 22:10:55 +0000 Subject: [PATCH 190/228] Fix massive fields sending incorrect data in POST request --- re2o/templatetags/massive_bootstrap_form.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/re2o/templatetags/massive_bootstrap_form.py b/re2o/templatetags/massive_bootstrap_form.py index 20d468a1..d4460de7 100644 --- a/re2o/templatetags/massive_bootstrap_form.py +++ b/re2o/templatetags/massive_bootstrap_form.py @@ -520,6 +520,14 @@ class MBFField: "}} );" ) + # Make sure the visible element doesn't have the same name as the hidden elements + # Otherwise, in the POST request, they collide and an incoherent value is sent + self.js_script += ( + '$( "#{input_id}" ).ready( function() {{' + ' $( "#{input_id}" ).attr("name", "mbf_{f_name}");' + "}} );" + ) + def fill_js(self): """ Fill the template with the correct values """ self.js_script = self.js_script.format( From 3743a46bc522b7789b462baa2c6f66d7603fed47 Mon Sep 17 00:00:00 2001 From: Laouen Fernet Date: Sat, 16 Nov 2019 14:01:07 +0000 Subject: [PATCH 191/228] Mark strings for translation in api --- api/acl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/acl.py b/api/acl.py index c2db9862..490b88c7 100644 --- a/api/acl.py +++ b/api/acl.py @@ -74,6 +74,6 @@ def can_view(user): can = user.has_perm(permission) return ( can, - None if can else _("You don't have the right to see this" " application."), + None if can else _("You don't have the right to view this application."), (permission,), ) From 2454de2032d60493e6da4dc1ea31dc68436b5b80 Mon Sep 17 00:00:00 2001 From: Laouen Fernet Date: Sat, 16 Nov 2019 14:02:32 +0000 Subject: [PATCH 192/228] Mark strings for translation in cotisations --- cotisations/forms.py | 10 +-- cotisations/models.py | 64 +++++++++---------- cotisations/payment_methods/balance/models.py | 11 ++-- cotisations/payment_methods/cheque/models.py | 2 +- cotisations/payment_methods/comnpay/models.py | 7 +- cotisations/payment_methods/forms.py | 8 +-- cotisations/payment_methods/free/models.py | 2 +- .../payment_methods/note_kfet/forms.py | 2 +- .../templates/cotisations/aff_paiement.html | 2 +- .../templates/cotisations/control.html | 12 ++-- cotisations/templates/cotisations/delete.html | 2 +- .../templates/cotisations/email_invoice | 14 ++-- .../cotisations/email_subscription_accepted | 7 +- .../templates/cotisations/index_article.html | 6 +- .../templates/cotisations/index_banque.html | 2 +- .../templates/cotisations/index_paiement.html | 2 +- .../templates/cotisations/sidebar.html | 2 +- cotisations/tex.py | 1 - cotisations/views.py | 52 +++++++++++---- 19 files changed, 117 insertions(+), 91 deletions(-) diff --git a/cotisations/forms.py b/cotisations/forms.py index 6f4a9a45..76db358c 100644 --- a/cotisations/forms.py +++ b/cotisations/forms.py @@ -116,7 +116,7 @@ class DiscountForm(Form): """ is_relative = forms.BooleanField( - label=_("Discount is on percentage."), required=False + label=_("Discount is in percentage."), required=False ) discount = forms.DecimalField( label=_("Discount"), @@ -136,7 +136,7 @@ class DiscountForm(Form): else: amount = discount if amount: - name = _("{}% discount") if is_relative else _("{}€ discount") + name = _("{}% discount") if is_relative else _("{} € discount") name = name.format(discount) Vente.objects.create(facture=invoice, name=name, prix=-amount, number=1) @@ -184,7 +184,7 @@ class DelArticleForm(FormRevMixin, Form): articles = forms.ModelMultipleChoiceField( queryset=Article.objects.none(), - label=_("Available articles"), + label=_("Current articles"), widget=forms.CheckboxSelectMultiple, ) @@ -226,7 +226,7 @@ class DelPaiementForm(FormRevMixin, Form): # TODO : change paiement to payment paiements = forms.ModelMultipleChoiceField( queryset=Paiement.objects.none(), - label=_("Available payment methods"), + label=_("Current payment methods"), widget=forms.CheckboxSelectMultiple, ) @@ -266,7 +266,7 @@ class DelBanqueForm(FormRevMixin, Form): # TODO : change banque to bank banques = forms.ModelMultipleChoiceField( queryset=Banque.objects.none(), - label=_("Available banks"), + label=_("Current banks"), widget=forms.CheckboxSelectMultiple, ) diff --git a/cotisations/models.py b/cotisations/models.py index 5cab9212..c2d23171 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -56,7 +56,7 @@ from cotisations.validators import check_no_balance class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): - date = models.DateTimeField(auto_now_add=True, verbose_name=_("Date")) + date = models.DateTimeField(auto_now_add=True, verbose_name=_("date")) # TODO : change prix to price def prix(self): @@ -138,7 +138,7 @@ class Facture(BaseInvoice): abstract = False permissions = ( # TODO : change facture to invoice - ("change_facture_control", _('Can edit the "controlled" state')), + ("change_facture_control", _("Can edit the \"controlled\" state")), ("view_facture", _("Can view an invoice object")), ("change_all_facture", _("Can edit all the previous invoices")), ) @@ -174,8 +174,8 @@ class Facture(BaseInvoice): return ( False, _( - "You don't have the right to edit an invoice " - "already controlled or invalidated." + "You don't have the right to edit an invoice" + " already controlled or invalidated." ), ("cotisations.change_all_facture",), ) @@ -206,8 +206,8 @@ class Facture(BaseInvoice): return ( False, _( - "You don't have the right to delete an invoice " - "already controlled or invalidated." + "You don't have the right to delete an invoice" + " already controlled or invalidated." ), ("cotisations.change_all_facture",), ) @@ -220,8 +220,8 @@ class Facture(BaseInvoice): return ( False, _( - "You don't have the right to view someone else's " - "invoices history." + "You don't have the right to view someone else's" + " invoices history." ), ("cotisations.view_facture",), ) @@ -243,7 +243,7 @@ class Facture(BaseInvoice): can = user_request.has_perm("cotisations.change_facture_control") return ( can, - _('You don\'t have the right to edit the "controlled" state.') + _("You don't have the right to edit the \"controlled\" state.") if not can else None, ("cotisations.change_facture_control",), @@ -262,13 +262,13 @@ class Facture(BaseInvoice): if len(Paiement.find_allowed_payments(user_request)) <= 0: return ( False, - _("There are no payment method which you can use."), + _("There are no payment methods that you can use."), ("cotisations.add_facture",), ) if len(Article.find_allowed_articles(user_request, user_request)) <= 0: return ( False, - _("There are no article that you can buy."), + _("There are no articles that you can buy."), ("cotisations.add_facture",), ) return True, None, None @@ -346,11 +346,11 @@ class CustomInvoice(BaseInvoice): class Meta: permissions = (("view_custominvoice", _("Can view a custom invoice object")),) - recipient = models.CharField(max_length=255, verbose_name=_("Recipient")) - payment = models.CharField(max_length=255, verbose_name=_("Payment type")) - address = models.CharField(max_length=255, verbose_name=_("Address")) - paid = models.BooleanField(verbose_name=_("Paid"), default=False) - remark = models.TextField(verbose_name=_("Remark"), blank=True, null=True) + recipient = models.CharField(max_length=255, verbose_name=_("recipient")) + payment = models.CharField(max_length=255, verbose_name=_("payment type")) + address = models.CharField(max_length=255, verbose_name=_("address")) + paid = models.BooleanField(verbose_name=_("paid"), default=False) + remark = models.TextField(verbose_name=_("remark"), blank=True, null=True) class CostEstimate(CustomInvoice): @@ -358,7 +358,7 @@ class CostEstimate(CustomInvoice): permissions = (("view_costestimate", _("Can view a cost estimate object")),) validity = models.DurationField( - verbose_name=_("Period of validity"), help_text="DD HH:MM:SS" + verbose_name=_("period of validity"), help_text="DD HH:MM:SS" ) final_invoice = models.ForeignKey( CustomInvoice, @@ -547,7 +547,7 @@ class Vente(RevMixin, AclMixin, models.Model): if not user_request.has_perm("cotisations.change_vente"): return ( False, - _("You don't have the right to edit the purchases."), + _("You don't have the right to edit a purchase."), ("cotisations.change_vente",), ) elif not (user_request.has_perm("cotisations.change_all_facture") or user_can): @@ -562,8 +562,8 @@ class Vente(RevMixin, AclMixin, models.Model): return ( False, _( - "You don't have the right to edit a purchase " - "already controlled or invalidated." + "You don't have the right to edit a purchase" + " already controlled or invalidated." ), ("cotisations.change_all_vente",), ) @@ -590,8 +590,8 @@ class Vente(RevMixin, AclMixin, models.Model): return ( False, _( - "You don't have the right to delete a purchase " - "already controlled or invalidated." + "You don't have the right to delete a purchase" + " already controlled or invalidated." ), None, ) @@ -606,8 +606,8 @@ class Vente(RevMixin, AclMixin, models.Model): return ( False, _( - "You don't have the right to view someone " - "else's purchase history." + "You don't have the right to view someone" + " else's purchase history." ), ("cotisations.view_vente",), ) @@ -731,7 +731,7 @@ class Article(RevMixin, AclMixin, models.Model): def clean(self): if self.name.lower() == "solde": - raise ValidationError(_("Balance is a reserved article name.")) + raise ValidationError(_("Solde is a reserved article name.")) if self.type_cotisation and not (self.duration or self.duration_days): raise ValidationError(_("Duration must be specified for a subscription.")) @@ -921,7 +921,7 @@ class Paiement(RevMixin, AclMixin, models.Model): p = find_payment_method(self) if p is not None: return p._meta.verbose_name - return _("No custom payment method.") + return _("No custom payment methods.") class Cotisation(RevMixin, AclMixin, models.Model): @@ -976,8 +976,8 @@ class Cotisation(RevMixin, AclMixin, models.Model): return ( False, _( - "You don't have the right to edit a subscription " - "already controlled or invalidated." + "You don't have the right to edit a subscription" + " already controlled or invalidated." ), ("cotisations.change_all_cotisation",), ) @@ -995,8 +995,8 @@ class Cotisation(RevMixin, AclMixin, models.Model): return ( False, _( - "You don't have the right to delete a subscription " - "already controlled or invalidated." + "You don't have the right to delete a subscription" + " already controlled or invalidated." ), None, ) @@ -1011,8 +1011,8 @@ class Cotisation(RevMixin, AclMixin, models.Model): return ( False, _( - "You don't have the right to view someone else's " - "subscription history." + "You don't have the right to view someone else's" + " subscription history." ), ("cotisations.view_cotisation",), ) diff --git a/cotisations/payment_methods/balance/models.py b/cotisations/payment_methods/balance/models.py index a252affb..afa43c48 100644 --- a/cotisations/payment_methods/balance/models.py +++ b/cotisations/payment_methods/balance/models.py @@ -44,18 +44,17 @@ class BalancePayment(PaymentMethodMixin, models.Model): editable=False, ) minimum_balance = models.DecimalField( - verbose_name=_("Minimum balance"), + verbose_name=_("minimum balance"), help_text=_( - "The minimal amount of money allowed for the balance" - " at the end of a payment. You can specify negative " - "amount." + "The minimal amount of money allowed for the balance at the end" + " of a payment. You can specify a negative amount." ), max_digits=5, decimal_places=2, default=0, ) maximum_balance = models.DecimalField( - verbose_name=_("Maximum balance"), + verbose_name=_("maximum balance"), help_text=_("The maximal amount of money allowed for the balance."), max_digits=5, decimal_places=2, @@ -64,7 +63,7 @@ class BalancePayment(PaymentMethodMixin, models.Model): null=True, ) credit_balance_allowed = models.BooleanField( - verbose_name=_("Allow user to credit their balance"), default=False + verbose_name=_("allow user to credit their balance"), default=False ) def end_payment(self, invoice, request): diff --git a/cotisations/payment_methods/cheque/models.py b/cotisations/payment_methods/cheque/models.py index 53acef6a..62479f22 100644 --- a/cotisations/payment_methods/cheque/models.py +++ b/cotisations/payment_methods/cheque/models.py @@ -33,7 +33,7 @@ class ChequePayment(PaymentMethodMixin, models.Model): """ class Meta: - verbose_name = _("Cheque") + verbose_name = _("cheque") payment = models.OneToOneField( Paiement, diff --git a/cotisations/payment_methods/comnpay/models.py b/cotisations/payment_methods/comnpay/models.py index ff35650c..2c46f685 100644 --- a/cotisations/payment_methods/comnpay/models.py +++ b/cotisations/payment_methods/comnpay/models.py @@ -51,9 +51,10 @@ class ComnpayPayment(PaymentMethodMixin, models.Model): max_length=255, null=True, blank=True, verbose_name=_("ComNpay secret key") ) minimum_payment = models.DecimalField( - verbose_name=_("Minimum payment"), + verbose_name=_("minimum payment"), help_text=_( - "The minimal amount of money you have to use when paying" " with ComNpay" + "The minimal amount of money you have to use when paying with" + " ComNpay." ), max_digits=5, decimal_places=2, @@ -62,7 +63,7 @@ class ComnpayPayment(PaymentMethodMixin, models.Model): production = models.BooleanField( default=True, verbose_name=_( - "Production mode enabled (production URL, instead of homologation)" + "production mode enabled (production URL, instead of homologation)" ), ) diff --git a/cotisations/payment_methods/forms.py b/cotisations/payment_methods/forms.py index fdcd50b8..a6bac3ed 100644 --- a/cotisations/payment_methods/forms.py +++ b/cotisations/payment_methods/forms.py @@ -58,9 +58,9 @@ class PaymentMethodForm(forms.Form): payment_method = forms.ChoiceField( label=_("Special payment method"), help_text=_( - "Warning: you will not be able to change the payment " - "method later. But you will be allowed to edit the other " - "options." + "Warning: you will not be able to change the payment" + " method later. But you will be allowed to edit the other" + " options." ), required=False, ) @@ -71,7 +71,7 @@ class PaymentMethodForm(forms.Form): self.fields["payment_method"].choices = [ (i, p.NAME) for (i, p) in enumerate(PAYMENT_METHODS) ] - self.fields["payment_method"].choices.insert(0, ("", _("no"))) + self.fields["payment_method"].choices.insert(0, ("", _("No"))) self.fields["payment_method"].widget.attrs = {"id": "paymentMethodSelect"} self.templates = [ forms.modelform_factory(p.PaymentMethod, fields="__all__")(prefix=prefix) diff --git a/cotisations/payment_methods/free/models.py b/cotisations/payment_methods/free/models.py index b64744fe..39a3aa80 100644 --- a/cotisations/payment_methods/free/models.py +++ b/cotisations/payment_methods/free/models.py @@ -51,4 +51,4 @@ class FreePayment(PaymentMethodMixin, models.Model): """Checks that the price meets the requirement to be paid with user balance. """ - return (price == 0, _("You cannot validate this invoice for free.")) + return (price == 0, _("You can't pay this invoice for free.")) diff --git a/cotisations/payment_methods/note_kfet/forms.py b/cotisations/payment_methods/note_kfet/forms.py index 098315b7..7d82b93f 100644 --- a/cotisations/payment_methods/note_kfet/forms.py +++ b/cotisations/payment_methods/note_kfet/forms.py @@ -30,5 +30,5 @@ class NoteCredentialForm(forms.Form): object. """ - login = forms.CharField(label=_("pseudo note")) + login = forms.CharField(label=_("Username")) password = forms.CharField(label=_("Password"), widget=forms.PasswordInput) diff --git a/cotisations/templates/cotisations/aff_paiement.html b/cotisations/templates/cotisations/aff_paiement.html index edd485f1..6043da67 100644 --- a/cotisations/templates/cotisations/aff_paiement.html +++ b/cotisations/templates/cotisations/aff_paiement.html @@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Payment type" %} - {% trans "Is available for everyone" %} + {% trans "Available for everyone" %} {% trans "Custom payment method" %} diff --git a/cotisations/templates/cotisations/control.html b/cotisations/templates/cotisations/control.html index b199ba2d..497de6f4 100644 --- a/cotisations/templates/cotisations/control.html +++ b/cotisations/templates/cotisations/control.html @@ -45,12 +45,12 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Profile" %} - {% trans "Last name" as tr_last_name %} - {% include 'buttons/sort.html' with prefix='control' col='name' text=tr_last_name %} + {% trans "First name" as tr_first_name %} + {% include 'buttons/sort.html' with prefix='control' col='name' text=tr_first_name %} - {% trans "First name" as tr_first_name %} - {% include 'buttons/sort.html' with prefix='control' col='surname' text=tr_first_name %} + {% trans "Surname" as tr_surname %} + {% include 'buttons/sort.html' with prefix='control' col='surname' text=tr_surname %} {% trans "Invoice ID" as tr_invoice_id %} @@ -104,8 +104,8 @@ with this program; if not, write to the Free Software Foundation, Inc., {% endfor %} - {% trans "Edit" as tr_edit %} - {% bootstrap_button tr_edit button_type='submit' icon='ok' button_class='btn-success' %} + {% trans "Confirm" as tr_confirm %} + {% bootstrap_button tr_confirm button_type='submit' icon='ok' button_class='btn-success' %} {% endblock %} diff --git a/cotisations/templates/cotisations/delete.html b/cotisations/templates/cotisations/delete.html index 483dd218..e6f1b362 100644 --- a/cotisations/templates/cotisations/delete.html +++ b/cotisations/templates/cotisations/delete.html @@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    {% csrf_token %}

    - {% blocktrans %}Warning: are you sure you really want to delete this {{ object_name }} object ( {{ objet }} )?{% endblocktrans %} + {% blocktrans %}Warning: are you sure you really want to delete this {{ objet_name }} object ( {{ objet }} )?{% endblocktrans %}

    {% trans "Confirm" as tr_confirm %} {% bootstrap_button tr_confirm button_type='submit' icon='trash' button_class='btn-danger' %} diff --git a/cotisations/templates/cotisations/email_invoice b/cotisations/templates/cotisations/email_invoice index 8d6b2cc2..01f80225 100644 --- a/cotisations/templates/cotisations/email_invoice +++ b/cotisations/templates/cotisations/email_invoice @@ -6,17 +6,17 @@ Nous vous remercions pour votre achat auprès de {{asso_name}} et nous vous en j En cas de question, n’hésitez pas à nous contacter par mail à {{contact_mail}}. -Cordialement, -L’équipe de {{asso_name}} +Respectueusement, +L’équipe de {{asso_name}}. === English version === -Dear {{name}}, +Hello {{name}}, -Thank you for your purchase. Here is your invoice. +Thank you for your purchase at {{asso_name}}. Here is your invoice. -Should you need extra information, you can email us at {{contact_mail}}. +Should you need extra information, do not hesitate to email us at {{contact_mail}}. -Best regards, - {{ asso_name }}'s team +Regards, +The {{ asso_name }} team. diff --git a/cotisations/templates/cotisations/email_subscription_accepted b/cotisations/templates/cotisations/email_subscription_accepted index bd1c7628..cb0eb760 100644 --- a/cotisations/templates/cotisations/email_subscription_accepted +++ b/cotisations/templates/cotisations/email_subscription_accepted @@ -6,17 +6,18 @@ Vous trouverez en pièce jointe un reçu. Pour nous faire part de toute remarque, suggestion ou problème vous pouvez nous envoyer un mail à {{asso_email}}. -À bientôt, +Respectueusement, L'équipe de {{asso_name}}. --- +Hello {{name}}! + Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}} until {{ date_end|date:"d/m/Y" }}. You will find with this email a subscription voucher. -For any information, suggestion or problem, you can contact us via email at -{{asso_email}}. +To express any comment, suggestion or problem, you can send us an email to {{asso_email}}. Regards, The {{asso_name}} team. diff --git a/cotisations/templates/cotisations/index_article.html b/cotisations/templates/cotisations/index_article.html index 8adc7639..1a4c3c8d 100644 --- a/cotisations/templates/cotisations/index_article.html +++ b/cotisations/templates/cotisations/index_article.html @@ -30,14 +30,14 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block title %}{% trans "Articles" %}{% endblock %} {% block content %} -

    {% trans "List of article types" %}

    +

    {% trans "List of articles" %}

    {% can_create Article %} - {% trans "Add an article type" %} + {% trans "Add an article" %} {% acl_end %} - {% trans "Delete one or several article types" %} + {% trans "Delete one or several articles" %} {% include 'cotisations/aff_article.html' with article_list=article_list %} {% endblock %} diff --git a/cotisations/templates/cotisations/index_banque.html b/cotisations/templates/cotisations/index_banque.html index a497198f..c653acfd 100644 --- a/cotisations/templates/cotisations/index_banque.html +++ b/cotisations/templates/cotisations/index_banque.html @@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,

    {% trans "List of banks" %}

    {% can_create Banque %} - {% trans "Add a bank" %} + {% trans "Add a bank" %} {% acl_end %} diff --git a/cotisations/templates/cotisations/index_paiement.html b/cotisations/templates/cotisations/index_paiement.html index b76dec65..1411add0 100644 --- a/cotisations/templates/cotisations/index_paiement.html +++ b/cotisations/templates/cotisations/index_paiement.html @@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,

    {% trans "List of payment methods" %}

    {% can_create Paiement %}
    - {% trans "Add a payment method" %} + {% trans "Add a payment method" %} {% acl_end %} diff --git a/cotisations/templates/cotisations/sidebar.html b/cotisations/templates/cotisations/sidebar.html index 96a674f9..8e69a8c9 100644 --- a/cotisations/templates/cotisations/sidebar.html +++ b/cotisations/templates/cotisations/sidebar.html @@ -52,7 +52,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% acl_end %} {% can_view_all Article %} - {% trans "Available articles" %} + {% trans "Articles" %} {% acl_end %} {% can_view_all Banque %} diff --git a/cotisations/tex.py b/cotisations/tex.py index 6872ac6a..2930fffe 100644 --- a/cotisations/tex.py +++ b/cotisations/tex.py @@ -36,7 +36,6 @@ from django.template.loader import get_template from django.http import HttpResponse from django.conf import settings from django.utils.text import slugify -from django.utils.translation import ugettext_lazy as _ from re2o.mixins import AclMixin, RevMixin from preferences.models import CotisationsOption diff --git a/cotisations/views.py b/cotisations/views.py index 4510aff9..562326e3 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -166,6 +166,7 @@ def new_facture(request, user, userid): "articlelist": article_list, "balance": balance, "action_name": _("Confirm"), + "title": _("New invoice"), }, "cotisations/facture.html", request, @@ -222,7 +223,7 @@ def new_cost_estimate(request): "articlesformset": articles_formset, "articlelist": articles, "discount_form": discount_form, - "title": _("Cost estimate"), + "title": _("New cost estimate"), }, "cotisations/facture.html", request, @@ -278,6 +279,7 @@ def new_custom_invoice(request): "articlesformset": articles_formset, "articlelist": articles, "discount_form": discount_form, + "title": _("New custom invoice"), }, "cotisations/facture.html", request, @@ -373,7 +375,7 @@ def del_facture(request, facture, **_kwargs): messages.success(request, _("The invoice was deleted.")) return redirect(reverse("cotisations:index")) return form( - {"objet": facture, "objet_name": _("Invoice")}, + {"objet": facture, "objet_name": _("invoice")}, "cotisations/delete.html", request, ) @@ -437,7 +439,11 @@ def edit_custom_invoice(request, invoice, **kwargs): return redirect(reverse("cotisations:index-custom-invoice")) return form( - {"factureform": invoice_form, "venteform": purchase_form}, + { + "factureform": invoice_form, + "venteform": purchase_form, + "title": _("Edit custom invoice"), + }, "cotisations/edit_facture.html", request, ) @@ -501,7 +507,7 @@ def del_cost_estimate(request, estimate, **_kwargs): messages.success(request, _("The cost estimate was deleted.")) return redirect(reverse("cotisations:index-cost-estimate")) return form( - {"objet": estimate, "objet_name": _("Cost estimate")}, + {"objet": estimate, "objet_name": _("cost estimate")}, "cotisations/delete.html", request, ) @@ -564,7 +570,7 @@ def del_custom_invoice(request, invoice, **_kwargs): messages.success(request, _("The invoice was deleted.")) return redirect(reverse("cotisations:index-custom-invoice")) return form( - {"objet": invoice, "objet_name": _("Invoice")}, + {"objet": invoice, "objet_name": _("invoice")}, "cotisations/delete.html", request, ) @@ -588,7 +594,11 @@ def add_article(request): messages.success(request, _("The article was created.")) return redirect(reverse("cotisations:index-article")) return form( - {"factureform": article, "action_name": _("Add"), "title": _("New article")}, + { + "factureform": article, + "action_name": _("Add"), + "title": _("New article"), + }, "cotisations/facture.html", request, ) @@ -607,7 +617,11 @@ def edit_article(request, article_instance, **_kwargs): messages.success(request, _("The article was edited.")) return redirect(reverse("cotisations:index-article")) return form( - {"factureform": article, "action_name": _("Edit"), "title": _("Edit article")}, + { + "factureform": article, + "action_name": _("Edit"), + "title": _("Edit article"), + }, "cotisations/facture.html", request, ) @@ -718,8 +732,8 @@ def del_paiement(request, instances): messages.error( request, _( - "The payment method %(method_name)s can't be deleted \ - because there are invoices using it." + "The payment method %(method_name)s can't be deleted" + " because there are invoices using it." ) % {"method_name": payment_del}, ) @@ -748,7 +762,11 @@ def add_banque(request): messages.success(request, _("The bank was created.")) return redirect(reverse("cotisations:index-banque")) return form( - {"factureform": bank, "action_name": _("Add"), "title": _("New bank")}, + { + "factureform": bank, + "action_name": _("Add"), + "title": _("New bank"), + }, "cotisations/facture.html", request, ) @@ -768,7 +786,11 @@ def edit_banque(request, banque_instance, **_kwargs): messages.success(request, _("The bank was edited.")) return redirect(reverse("cotisations:index-banque")) return form( - {"factureform": bank, "action_name": _("Edit"), "title": _("Edit bank")}, + { + "factureform": bank, + "action_name": _("Edit"), + "title": _("Edit bank"), + }, "cotisations/facture.html", request, ) @@ -802,7 +824,11 @@ def del_banque(request, instances): ) return redirect(reverse("cotisations:index-banque")) return form( - {"factureform": bank, "action_name": _("Delete"), "title": _("Delete bank")}, + { + "factureform": bank, + "action_name": _("Delete"), + "title": _("Delete bank"), + }, "cotisations/facture.html", request, ) @@ -833,7 +859,7 @@ def control(request): ) if control_invoices_form.is_valid(): control_invoices_form.save() - reversion.set_comment("Controle") + reversion.set_comment("Control") messages.success( request, _("Your changes have been properly taken into account.") ) From 07ce7bd8a77d76a4fab23d095f4722cc854c3396 Mon Sep 17 00:00:00 2001 From: Laouen Fernet Date: Sat, 16 Nov 2019 14:03:08 +0000 Subject: [PATCH 193/228] Mark strings for translation in logs --- logs/acl.py | 3 ++- logs/templates/logs/aff_summary.html | 2 +- logs/views.py | 38 ++++++++++++++-------------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/logs/acl.py b/logs/acl.py index f6be8183..42000ea8 100644 --- a/logs/acl.py +++ b/logs/acl.py @@ -41,6 +41,7 @@ def can_view(user): can = user.has_module_perms("admin") return ( can, - None if can else _("You don't have the right to view this" " application."), + None if can else _("You don't have the right to view this" + " application."), "admin", ) diff --git a/logs/templates/logs/aff_summary.html b/logs/templates/logs/aff_summary.html index 7205bc6a..31834a2d 100644 --- a/logs/templates/logs/aff_summary.html +++ b/logs/templates/logs/aff_summary.html @@ -113,7 +113,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% blocktrans with username=v.username number=v.version.object.number name=v.version.object.name %}{{ username }} has sold {{ number }}x {{ name }}{% endblocktrans %} {% with invoice=v.version.object.facture %} {% if invoice|is_facture %} - {% trans " to" %} + {% trans "to" %} {{ v.version.object.facture.facture.user.get_username }} {% if v.version.object.iscotisation %} ({% blocktrans with duration=v.version.object.duration %}+{{ duration }} months{% endblocktrans %}) diff --git a/logs/views.py b/logs/views.py index be71f7cc..7c509134 100644 --- a/logs/views.py +++ b/logs/views.py @@ -241,7 +241,7 @@ def stats_general(request): Club.objects.filter(state=Club.STATE_ARCHIVE).count(), ], "full_archive_users": [ - _("Full Archived users"), + _("Fully archived users"), User.objects.filter(state=User.STATE_FULL_ARCHIVE).count(), ( Adherent.objects.filter( @@ -321,7 +321,7 @@ def stats_general(request): _("Total number of IP addresses"), _("Number of assigned IP addresses"), _("Number of IP address assigned to an activated machine"), - _("Number of nonassigned IP addresses"), + _("Number of unassigned IP addresses"), ], ip_dict, # Data already prepared ], @@ -336,7 +336,7 @@ def stats_models(request): nombre d'users, d'écoles, de droits, de bannissements, de factures, de ventes, de banque, de machines, etc""" stats = { - _("Users"): { + _("Users (members and clubs)"): { "users": [User._meta.verbose_name, User.objects.count()], "adherents": [Adherent._meta.verbose_name, Adherent.objects.count()], "clubs": [Club._meta.verbose_name, Club.objects.count()], @@ -350,14 +350,14 @@ def stats_models(request): "ban": [Ban._meta.verbose_name, Ban.objects.count()], "whitelist": [Whitelist._meta.verbose_name, Whitelist.objects.count()], }, - _("Subscriptions"): { + Cotisation._meta.verbose_name_plural.title(): { "factures": [Facture._meta.verbose_name, Facture.objects.count()], "vente": [Vente._meta.verbose_name, Vente.objects.count()], "cotisation": [Cotisation._meta.verbose_name, Cotisation.objects.count()], "article": [Article._meta.verbose_name, Article.objects.count()], "banque": [Banque._meta.verbose_name, Banque.objects.count()], }, - _("Machines"): { + Machine._meta.verbose_name_plural.title(): { "machine": [Machine._meta.verbose_name, Machine.objects.count()], "typemachine": [ MachineType._meta.verbose_name, @@ -412,31 +412,31 @@ def stats_users(request): de moyens de paiements par user, de banque par user, de bannissement par user, etc""" stats = { - _("User"): { - _("Machines"): User.objects.annotate(num=Count("machine")).order_by("-num")[ + User._meta.verbose_name: { + Machine._meta.verbose_name_plural: User.objects.annotate(num=Count("machine")).order_by("-num")[ :10 ], - _("Invoice"): User.objects.annotate(num=Count("facture")).order_by("-num")[ + Facture._meta.verbose_name_plural: User.objects.annotate(num=Count("facture")).order_by("-num")[ :10 ], - _("Ban"): User.objects.annotate(num=Count("ban")).order_by("-num")[:10], - _("Whitelist"): User.objects.annotate(num=Count("whitelist")).order_by( + Ban._meta.verbose_name_plural: User.objects.annotate(num=Count("ban")).order_by("-num")[:10], + Whitelist._meta.verbose_name_plural: User.objects.annotate(num=Count("whitelist")).order_by( "-num" )[:10], - _("Rights"): User.objects.annotate(num=Count("groups")).order_by("-num")[ + _("rights"): User.objects.annotate(num=Count("groups")).order_by("-num")[ :10 ], }, - _("School"): { - _("User"): School.objects.annotate(num=Count("user")).order_by("-num")[:10] + School._meta.verbose_name: { + User._meta.verbose_name_plural: School.objects.annotate(num=Count("user")).order_by("-num")[:10] }, - _("Payment method"): { - _("User"): Paiement.objects.annotate(num=Count("facture")).order_by("-num")[ + Paiement._meta.verbose_name: { + User._meta.verbose_name_plural: Paiement.objects.annotate(num=Count("facture")).order_by("-num")[ :10 ] }, - _("Bank"): { - _("User"): Banque.objects.annotate(num=Count("facture")).order_by("-num")[ + Banque._meta.verbose_name: { + User._meta.verbose_name_plural: Banque.objects.annotate(num=Count("facture")).order_by("-num")[ :10 ] }, @@ -451,8 +451,8 @@ def stats_actions(request): utilisateurs. Affiche le nombre de modifications aggrégées par utilisateurs""" stats = { - _("User"): { - _("Action"): User.objects.annotate(num=Count("revision")).order_by("-num")[ + User._meta.verbose_name: { + _("actions"): User.objects.annotate(num=Count("revision")).order_by("-num")[ :40 ] } From ac5d8e2080f08b74bcfdc902f75af81bed7b1ab9 Mon Sep 17 00:00:00 2001 From: Laouen Fernet Date: Sat, 16 Nov 2019 14:07:15 +0000 Subject: [PATCH 194/228] Mark strings for translation in machines --- machines/acl.py | 3 +- machines/models.py | 108 ++++++++++-------- .../templates/machines/aff_extension.html | 2 +- machines/templates/machines/aff_iptype.html | 2 +- machines/templates/machines/aff_machines.html | 10 +- machines/templates/machines/aff_servers.html | 4 +- .../templates/machines/edit_portlist.html | 7 +- machines/templates/machines/index_alias.html | 4 +- .../templates/machines/index_extension.html | 29 +++-- machines/templates/machines/index_iptype.html | 4 +- machines/templates/machines/index_ipv6.html | 2 +- .../templates/machines/index_machinetype.html | 4 +- machines/templates/machines/index_nas.html | 4 +- .../templates/machines/index_portlist.html | 2 +- machines/templates/machines/index_role.html | 4 +- .../templates/machines/index_service.html | 4 +- machines/templates/machines/index_sshfp.html | 2 +- machines/templates/machines/index_vlan.html | 4 +- machines/templates/machines/sidebar.html | 2 +- machines/views.py | 50 ++++---- 20 files changed, 129 insertions(+), 122 deletions(-) diff --git a/machines/acl.py b/machines/acl.py index 55b48145..1989a788 100644 --- a/machines/acl.py +++ b/machines/acl.py @@ -41,6 +41,7 @@ def can_view(user): can = user.has_module_perms("machines") return ( can, - None if can else _("You don't have the right to view this" " application."), + None if can else _("You don't have the right to view this" + " application."), ("machines",), ) diff --git a/machines/models.py b/machines/models.py index 8b83e256..7b548cfb 100644 --- a/machines/models.py +++ b/machines/models.py @@ -68,7 +68,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): user = models.ForeignKey("users.User", on_delete=models.CASCADE) name = models.CharField( - max_length=255, help_text=_("Optional"), blank=True, null=True + max_length=255, help_text=_("Optional."), blank=True, null=True ) active = models.BooleanField(default=True) @@ -157,7 +157,8 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): if user != user_request: return ( False, - _("You don't have the right to add a machine" " to another user."), + _("You don't have the right to add a machine to another" + " user."), ("machines.add_machine",), ) if user.user_interfaces().count() >= max_lambdauser_interfaces: @@ -185,7 +186,8 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): if not (user_request.has_perm("machines.change_interface") and can_user): return ( False, - _("You don't have the right to edit a machine" " of another user."), + _("You don't have the right to edit a machine of another" + " user."), ("machines.change_interface",) + permissions, ) return True, None, None @@ -223,7 +225,8 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): ): return ( False, - _("You don't have the right to view other machines" " than yours."), + _("You don't have the right to view other machines than" + " yours."), ("machines.view_machine",), ) return True, None, None @@ -358,22 +361,22 @@ class IpType(RevMixin, AclMixin, models.Model): protocol="IPv4", null=True, blank=True, - help_text=_("Network containing the domain's IPv4 range (optional)"), + help_text=_("Network containing the domain's IPv4 range (optional)."), ) domaine_ip_netmask = models.IntegerField( default=24, validators=[MaxValueValidator(31), MinValueValidator(8)], - help_text=_("Netmask for the domain's IPv4 range"), + help_text=_("Netmask for the domain's IPv4 range."), ) reverse_v4 = models.BooleanField( - default=False, help_text=_("Enable reverse DNS for IPv4") + default=False, help_text=_("Enable reverse DNS for IPv4.") ) prefix_v6 = models.GenericIPAddressField(protocol="IPv6", null=True, blank=True) prefix_v6_length = models.IntegerField( default=64, validators=[MaxValueValidator(128), MinValueValidator(0)] ) reverse_v6 = models.BooleanField( - default=False, help_text=_("Enable reverse DNS for IPv6") + default=False, help_text=_("Enable reverse DNS for IPv6.") ) vlan = models.ForeignKey("Vlan", on_delete=models.PROTECT, blank=True, null=True) ouverture_ports = models.ForeignKey("OuverturePortList", blank=True, null=True) @@ -553,7 +556,8 @@ class IpType(RevMixin, AclMixin, models.Model): for element in IpType.objects.all().exclude(pk=self.pk): if not self.ip_set.isdisjoint(element.ip_set): raise ValidationError( - _("The specified range is not disjoint" " from existing ranges.") + _("The specified range is not disjoint from existing" + " ranges.") ) # On formate le prefix v6 if self.prefix_v6: @@ -604,8 +608,8 @@ class Vlan(RevMixin, AclMixin, models.Model): arp_protect = models.BooleanField(default=False) dhcp_snooping = models.BooleanField(default=False) dhcpv6_snooping = models.BooleanField(default=False) - igmp = models.BooleanField(default=False, help_text=_("v4 multicast management")) - mld = models.BooleanField(default=False, help_text=_("v6 multicast management")) + igmp = models.BooleanField(default=False, help_text=_("v4 multicast management.")) + mld = models.BooleanField(default=False, help_text=_("v6 multicast management.")) class Meta: permissions = (("view_vlan", _("Can view a VLAN object")),) @@ -653,30 +657,30 @@ class SOA(RevMixin, AclMixin, models.Model): """ name = models.CharField(max_length=255) - mail = models.EmailField(help_text=_("Contact email address for the zone")) + mail = models.EmailField(help_text=_("Contact email address for the zone.")) refresh = models.PositiveIntegerField( default=86400, # 24 hours help_text=_( "Seconds before the secondary DNS have to ask the primary" - " DNS serial to detect a modification" + " DNS serial to detect a modification." ), ) retry = models.PositiveIntegerField( default=7200, # 2 hours help_text=_( "Seconds before the secondary DNS ask the serial again in" - " case of a primary DNS timeout" + " case of a primary DNS timeout." ), ) expire = models.PositiveIntegerField( default=3600000, # 1000 hours help_text=_( "Seconds before the secondary DNS stop answering requests" - " in case of primary DNS timeout" + " in case of primary DNS timeout." ), ) ttl = models.PositiveIntegerField( - default=172800, help_text=_("Time to Live") # 2 days + default=172800, help_text=_("Time To Live.") # 2 days ) class Meta: @@ -732,7 +736,7 @@ class Extension(RevMixin, AclMixin, models.Model): name = models.CharField( max_length=255, unique=True, - help_text=_("Zone name, must begin with a dot (.example.org)"), + help_text=_("Zone name, must begin with a dot (.example.org)."), ) need_infra = models.BooleanField(default=False) origin = models.ForeignKey( @@ -740,17 +744,17 @@ class Extension(RevMixin, AclMixin, models.Model): on_delete=models.PROTECT, blank=True, null=True, - help_text=_("A record associated with the zone"), + help_text=_("A record associated with the zone."), ) origin_v6 = models.GenericIPAddressField( protocol="IPv6", null=True, blank=True, - help_text=_("AAAA record associated with the zone"), + help_text=_("AAAA record associated with the zone."), ) soa = models.ForeignKey("SOA", on_delete=models.CASCADE) dnssec = models.BooleanField( - default=False, help_text=_("Should the zone be signed with DNSSEC") + default=False, help_text=_("Should the zone be signed with DNSSEC.") ) class Meta: @@ -819,7 +823,7 @@ class Extension(RevMixin, AclMixin, models.Model): can = user_request.has_perm("machines.use_all_extension") return ( can, - _("You cannot use all extensions.") if not can else None, + _("You don't have the right to use all extensions.") if not can else None, ("machines.use_all_extension",), ) @@ -943,7 +947,7 @@ class Srv(RevMixin, AclMixin, models.Model): ) extension = models.ForeignKey("Extension", on_delete=models.PROTECT) ttl = models.PositiveIntegerField( - default=172800, help_text=_("Time to Live") # 2 days + default=172800, help_text=_("Time To Live.") # 2 days ) priority = models.PositiveIntegerField( default=0, @@ -951,7 +955,7 @@ class Srv(RevMixin, AclMixin, models.Model): help_text=_( "Priority of the target server (positive integer value," " the lower it is, the more the server will be used if" - " available)" + " available)." ), ) weight = models.PositiveIntegerField( @@ -959,14 +963,14 @@ class Srv(RevMixin, AclMixin, models.Model): validators=[MaxValueValidator(65535)], help_text=_( "Relative weight for records with the same priority" - " (integer value between 0 and 65535)" + " (integer value between 0 and 65535)." ), ) port = models.PositiveIntegerField( - validators=[MaxValueValidator(65535)], help_text=_("TCP/UDP port") + validators=[MaxValueValidator(65535)], help_text=_("TCP/UDP port.") ) target = models.ForeignKey( - "Domain", on_delete=models.PROTECT, help_text=_("Target server") + "Domain", on_delete=models.PROTECT, help_text=_("Target server.") ) class Meta: @@ -1023,10 +1027,10 @@ class SshFp(RevMixin, AclMixin, models.Model): ) machine = models.ForeignKey("Machine", on_delete=models.CASCADE) - pub_key_entry = models.TextField(help_text=_("SSH public key"), max_length=2048) + pub_key_entry = models.TextField(help_text=_("SSH public key."), max_length=2048) algo = models.CharField(choices=ALGO, max_length=32) comment = models.CharField( - help_text=_("Comment"), max_length=255, null=True, blank=True + help_text=_("Comment."), max_length=255, null=True, blank=True ) @cached_property @@ -1128,7 +1132,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): oui = mac.oui vendor = oui.registration().org except NotRegisteredError: - vendor = "Unknown vendor" + vendor = _("Unknown vendor.") return vendor def sync_ipv6_dhcpv6(self): @@ -1201,7 +1205,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): self.ipv4 = free_ips[0] else: raise ValidationError( - _("There is no IP address available in the" " slash.") + _("There are no IP addresses available in the slash.") ) return @@ -1214,7 +1218,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): """Unassign ipv4 to multiple interfaces""" with transaction.atomic(), reversion.create_revision(): interface_list.update(ipv4=None) - reversion.set_comment(_("IPv4 unassigning")) + reversion.set_comment("IPv4 unassignment") @classmethod def mass_assign_ipv4(cls, interface_list): @@ -1222,7 +1226,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): with transaction.atomic(), reversion.create_revision(): interface.assign_ipv4() interface.save() - reversion.set_comment(_("IPv4 assigning")) + reversion.set_comment("IPv4 assignment") def update_type(self): """ Lorsque le machinetype est changé de type d'ip, on réassigne""" @@ -1267,7 +1271,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ) if interfaces_similar and interfaces_similar.first() != self: raise ValidationError( - _("Mac address already registered in this Machine Type/Subnet") + _("MAC address already registered in this machine type/subnet.") ) def save(self, *args, **kwargs): @@ -1276,7 +1280,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): if self.ipv4: if self.machine_type.ip_type != self.ipv4.ip_type: raise ValidationError( - _("The IPv4 address and the machine type" " don't match.") + _("The IPv4 address and the machine type don't match.") ) self.validate_unique() super(Interface, self).save(*args, **kwargs) @@ -1296,7 +1300,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): if not ( preferences.models.OptionalMachine.get_cached_value("create_machine") ): - return False, _("You can't add a machine."), ("machines.add_interface",) + return False, _("You don't have the right to add a machine."), ("machines.add_interface",) max_lambdauser_interfaces = preferences.models.OptionalMachine.get_cached_value( "max_lambdauser_interfaces" ) @@ -1328,7 +1332,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): can = user_request.has_perm("machines.change_interface_machine") return ( can, - _("Permission required to edit the machine.") if not can else None, + _("You don't have the right to edit the machine.") if not can else None, ("machines.change_interface_machine",), ) @@ -1345,7 +1349,8 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): if not (user_request.has_perm("machines.change_interface") and can_user): return ( False, - _("You don't have the right to edit a machine of" " another user."), + _("You don't have the right to edit a machine of another" + " user."), ("machines.change_interface",) + permissions, ) return True, None, None @@ -1363,7 +1368,8 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): if not (user_request.has_perm("machines.change_interface") and can_user): return ( False, - _("You don't have the right to edit a machine of" " another user."), + _("You don't have the right to edit a machine of another" + " user."), ("machines.change_interface",) + permissions, ) return True, None, None @@ -1411,7 +1417,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ("view_ipv6list", _("Can view an IPv6 addresses list object")), ( "change_ipv6list_slaac_ip", - _("Can change the SLAAC value of an" " IPv6 addresses list"), + _("Can change the SLAAC value of an IPv6 addresses list"), ), ) verbose_name = _("IPv6 addresses list") @@ -1446,7 +1452,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): can = user_request.has_perm("machines.change_ipv6list_slaac_ip") return ( can, - _("Permission required to change the SLAAC value of an IPv6" " address") + _("You don't have the right to change the SLAAC value of an IPv6 address.") if not can else None, ("machines.change_ipv6list_slaac_ip",), @@ -1465,7 +1471,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): if not (user_request.has_perm("machines.change_ipv6list") and can_user): return ( False, - _("You don't have the right to edit a machine of" " another user."), + _("You don't have the right to edit a machine of another user."), ("machines.change_ipv6list",), ) return True, None, None @@ -1483,7 +1489,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): if not (user_request.has_perm("machines.change_ipv6list") and can_user): return ( False, - _("You don't have the right to edit a machine of" " another user."), + _("You don't have the right to edit a machine of another user."), ("machines.change_ipv6list",) + permissions, ) return True, None, None @@ -1587,7 +1593,7 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): unique_together = (("name", "extension"),) permissions = ( ("view_domain", _("Can view a domain object")), - ("change_ttl", _("Can change TTL of a domain object")), + ("change_ttl", _("Can change the TTL of a domain object")), ) verbose_name = _("domain") verbose_name_plural = _("domains") @@ -1612,20 +1618,20 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): if self.get_extension(): self.extension = self.get_extension() if self.interface_parent and self.cname: - raise ValidationError(_("You can't create a both A and CNAME" " record.")) + raise ValidationError(_("You can't create a both A and CNAME record.")) if self.cname == self: raise ValidationError( - _("You can't create a CNAME record pointing" " to itself.") + _("You can't create a CNAME record pointing to itself.") ) HOSTNAME_LABEL_PATTERN = re.compile(r"(?!-)[A-Z\d-]+(? 63: raise ValidationError( - _("The domain name %s is too long (over 63" " characters).") % dns + _("The domain name %s is too long (over 63 characters).") % dns ) if not HOSTNAME_LABEL_PATTERN.match(dns): raise ValidationError( - _("The domain name %s contains forbidden" " characters.") % dns + _("The domain name %s contains forbidden characters.") % dns ) self.validate_unique() super(Domain, self).clean() @@ -1753,7 +1759,8 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): ): return ( False, - _("You don't have the right to view machines other than yours."), + _("You don't have the right to view other machines than" + " yours."), ("machines.view_domain",), ) return True, None, None @@ -1794,7 +1801,7 @@ class IpList(RevMixin, AclMixin, models.Model): """ Erreur si l'ip_type est incorrect""" if not str(self.ipv4) in self.ip_type.ip_set_as_str: raise ValidationError( - _("The IPv4 address and the range of the IP" " type don't match.") + _("The IPv4 address and the range of the IP type don't match.") ) return @@ -1970,7 +1977,8 @@ class OuverturePortList(RevMixin, AclMixin, models.Model): class Meta: permissions = ( - ("view_ouvertureportlist", _("Can view a ports opening list" " object")), + ("view_ouvertureportlist", _("Can view a ports opening list" + " object")), ) verbose_name = _("ports opening list") verbose_name_plural = _("ports opening lists") diff --git a/machines/templates/machines/aff_extension.html b/machines/templates/machines/aff_extension.html index 809ef4ba..358fc33e 100644 --- a/machines/templates/machines/aff_extension.html +++ b/machines/templates/machines/aff_extension.html @@ -32,7 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Extension" %} - {% trans "'infra' right required" %} + {% blocktrans %}"infra" right required{% endblocktrans %} {% trans "SOA record" %} {% trans "A record origin" %} {% if ipv6_enabled %} diff --git a/machines/templates/machines/aff_iptype.html b/machines/templates/machines/aff_iptype.html index 2675b87a..7cf710c2 100644 --- a/machines/templates/machines/aff_iptype.html +++ b/machines/templates/machines/aff_iptype.html @@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "IP type" %} {% trans "Extension" %} - {% trans "'infra' right required" %} + {% blocktrans %}"infra" right required{% endblocktrans %} {% trans "IPv4 range" %} {% trans "v6 prefix" %} {% trans "DNSSEC reverse v4/v6" %} diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html index e59cfde6..77b65546 100644 --- a/machines/templates/machines/aff_machines.html +++ b/machines/templates/machines/aff_machines.html @@ -123,7 +123,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
  • - {% trans " Edit" %} + {% trans "Edit" %}
  • {% acl_end %} @@ -131,7 +131,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
  • - {% trans " Manage the aliases" %} + {% trans "Manage the aliases" %}
  • {% acl_end %} @@ -139,7 +139,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
  • - {% trans " Manage the IPv6 addresses" %} + {% trans "Manage the IPv6 addresses" %}
  • {% acl_end %} @@ -147,7 +147,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
  • - {% trans " Manage the SSH fingerprints" %} + {% trans "Manage the SSH fingerprints" %}
  • {% acl_end %} @@ -155,7 +155,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
  • - {% trans " Manage the ports configuration" %} + {% trans "Manage the ports configuration" %}
  • {% acl_end %} diff --git a/machines/templates/machines/aff_servers.html b/machines/templates/machines/aff_servers.html index 36c4bca0..3829c6c1 100644 --- a/machines/templates/machines/aff_servers.html +++ b/machines/templates/machines/aff_servers.html @@ -31,8 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Service name" %} {% trans "Server" %} {% trans "Last regeneration" %} - {% trans "Regeneration required" %} - {% trans "Regeneration activated" %} + {% trans "Regeneration asked" %} + {% trans "Regeneration needed" %} {% for server in servers_list %} diff --git a/machines/templates/machines/edit_portlist.html b/machines/templates/machines/edit_portlist.html index 387723bb..a2aded23 100644 --- a/machines/templates/machines/edit_portlist.html +++ b/machines/templates/machines/edit_portlist.html @@ -47,11 +47,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,

    - {% trans "Add a port" as value %} - +

    - {% trans "Create or edit" as tr_create_or_edit %} - {% bootstrap_button tr_create_or_edit icon='ok' button_class='btn-success' %} + {% trans "Confirm" as tr_confirm %} + {% bootstrap_button tr_confirm icon='ok' button_class='btn-success' %}