}P89ObUChx~PuYm8=313D_cCJE6Ddr4HH_U
zl2=l1MHFoD#jmz~nte0iDfK8T(c|GAJ&A_9)+a^E^R@#tA=7Jc;$&&@Eo6keSoL2_
z0dTM@ApYkYv;Fsn;GeDl{P(s%^rtNVANeBt&=;uSe8G;X1^(B@#F=I&xLw!$nVVO_
zhy+=fZ^9r90#FyN_0;ojkFC^rbx@7Dkk_S|U3YT}S|1-aCJdw!BHlRhh7%fiQ|XKv
zK1Yx+JN~Mad?0t4uwvjju?=~G8fs9pY~l;b6Z9#^F>=Krae<7WtMX-d{ggIR>}>4N
zG*#Bp%`jd+gCy|zDVjNhW&L?7f=k86bDk74aMI+x!3#0(
zEF|cu-16pO*vT1uc&Kc3g2^qr)IPh^0#tQnT_`cfn?RExed>t5)=0T@@2H|@g5Gq+
zYmtElQZ)cJCP7W!9paF{{k-T^;+0Cl-UkYhmhfAcjSbH@WizjbSruYeKPc&ccFv#a
ze)3$Ak9s<+vd(g>w}L$^_dV~G)&!_TMaXq8)4IYm`>dX({`ll)lVd{Z(HZ
z_qLMT3VkCqNe0q|c=)D+E?FVW^#Ku%7s!~GSz4~V4giaJsxP{ah!4(T5#yg~%F~$6
zxjc#(9PXKOoLcVdc)IyDRG{8fKmHl}o^VLQe22LMDL$5Wr9d)Tim70AA$cbEGX>Y3
zS~Zys;Ct$f3mUrh?F|>uJ(EpBxu8Z+TiDQ6Us%(F{=hV@u(7G}bu_Hz%Hq8iiu$v*
zlO~t&cVPVfO;G-KBhQs9A8zIE?MaLUwhuf~4sL-K2;s>$vc+O3zyFs)i^uyYNr7h
zM)}QGkTJMPdsO!*)hOoGG3PKad`#9FVaV@moqqL*_~c2pKIFPDzTo?_>WMB!UU>!u
z@cOby0?Vu$TGyQ}1*|%t^!pMQYil)%b!XW7*d^`5gmT!cTPx=6-KKRfSCVCndu`rw
z$_FB~U-?P-)71i?l=fEO
zNhS-`^#8hmWKJaFQ;~c`^5ovt5zU@FDozHsGQO9LeNqwJiyqd#SjzKUcGNgOe@CuK
zV(+%x;YE?Ev$IfH}MSrr7v
zQoX~{5u77*AUf>oSv6#4b+BQ*c$R^Kjn=u+IU~mJR-tVU?Uv4wnO{I|(_GW6PD)13
zSkQYj&g0%Q^G2RMjQ7hvsu!8I=voV;XXi$gTpQtvHZg*S9vFih=w`t<$=Vyhl<0M_
z`0gj4W>>;qTmLUqTy~G%7YdTp#OlPHWAoz}2^@qUiE{#?Oi3zy+F){uvz
zy34Q~#_cG{LX@q4kW!*fwE%MCp|_H3&izW_MEzJA8E@WL*QEGVF#$g!5#xf8y|CwM
zaL(g)=_(ILOIBHYygUtFJXE$gws`hxsbC7H`{LAs5aElW@OL(;=jtTEdJVvpTU*D2
zVn*`l&w8>JL`7!b-MCVVJBLpv)`-1lNM+4>n7w>o$l5=5kGml5%yrCpasW}+5m?f+w{q1L
zQRDr@{N}?3yl?s&5J0r#|75#Drfh-rpr4`GF=0;O9S31
z%pu;H(vF1QF7(i@0Jf$|mY1k2L$IC7s=3yA
ziS4QfyNp6j(u3a>nSj6*13QC;V>a{`<(=u`A^yjLn!#A>@upR$npr~gFKfCs_$>Xb
zP{$2dpT53vLLP@yZ)No4+^|WNs+581GvW%mbI%DGv#AuH_ZzJ;ODHCB{_q9{o}_yM
zg%PzS?iZ_0E{TUJ?q;OC*^;VmQP?ai;W>-}lpDFenNx5!o??~yr8@e^&|41ID{
z3u?vFUb!{lFZqxR?a_Xknf=C{iP`vACEZ?CH|L)6x-5(+2x)4yxVq_Ya(9?JY<@Z=
zqquuAXPQEy2_Rm74d(nhGc%EGubJ={bMVs}{MyR>@y1}^8(h{!SwRepgux(>_gaQnz0279bB9TaWF{p|X0wyM^02L8cRECKmlx2QzljCekc$5a@xIEK~OnO1-
z&soKVL&23-Q)=s+ql1GbJ`r$EKPHzs)_#X&o9Yow^u_7(fl6=F#l?w3hg8)A6d@N|
zcde_-pWdmH+S#2=w*FSZR0#x5UN|2pER;tJB7YoQQTsKTr8va6I6H1IqOuFs*10|#
zF>7_%#q`v@8ZSaNaYkM~A5g8ipVm!GDt6%@LRH%sZy8mQ>xcwJ{~Zo=FbHQ_^AWMvotoUf+dFUso2
z%cxN5dYpcJHdAG2tb$fKdK1e+=GfSH``ol%iw$=BB+H&oycT=u+BqA{hNXiPWu{2?
z?x|6
delta 5318
zcmbVQ3sh9q8g4|P4r+pk0Y1)E5MOW}bDjzqGt4OF0|$H%k&eT07@Y@qW-#!a$F;qL2
z50WvL+bJ1sSlMgsbFy~~;RhV}Y4@oMWM|&ioqe>;Z;o0$WRwG6bNREwOG!ucrB9mV
zN$*T)Z@BgSLh{I>`fZ74|2p%X3$e%Ru3ngDs>H;-#SSjkP+v
z_4HtC;*pMvLP=WP^fOHnl@}%&zdQa#Yua7skMg3<=Py)_{kp!NZt%k5jSp0D`ojGm
z@9)4dIW0FoQ#pcShUsa7?
zcVGP8#P1^>x!ksJlFN1dr5`){zP#d~%WQ_pCvEYOC&MzdJCgd}{XB1+w;m
zS3mf+qGdt5y!YDVPus_oH&(Qtej;zrsgE{H+F|L~wI~1c=k>!!
zn^Qkr_E}g&JwBoO{%yD3-P|-}eD(I-e}B7o+DcW~muD?c#x3sEf3<4);H#JQC#?DB
zFJ3y48S~&{Z#gTM)bQ@u8E2wKMDCiWi*LK}bM?5bn#kB$>e160TXQKYu8kM%yaWNVl?K)m~bolP*AuC$SqijR1qw`He
zty_-F8}sO1fQhMei>E#Sm?Zn^gaEPEnC&UenrL3D+BEyq6ty
zXxi>!No$Wx*I8fRDMuR%cS)tgnx4ID&S+aZFDmuVx3Vhsi@i$TxcbLK#N3vo@{d&q
zzF2;2V2Amms=nr<-|f$vbS?7h9pifC57>v#s(EupPK@=|oF#3SW8;RK#XD^eg^d?i
zH$4ENmWnN1)Vpqu6|#)
zv9!ZFs=2>TZ0UEj&mR^)b3J_L%Ck4w@+s=JzPoar=3m1u*%QWMlD)`F7tlhCf*~S7
z4T@xGG^_}DkFYu_Jt>jqX`GlMS0VtCpM<_MbLb=K@B*9yZH1U$Tf?S`1uLmgn$Sd)Z8c4btUvWkS12PXbywRCsSDr2LPCiN)wXhLmuVBV^^u8
zP)ZEdQ|^xRL9D@f_thzK2rJ4|lv7Gz1+Gh}7ayp8Dq-s#c6XNKGC3_JZU=+{-5Exk
zL})Y7Z(OF+Vzf@rgHWwTvkPaS0W&ljM_EA%$1!+{nr3jBCP@;&Lvn>gw%cg6m@@5V
ztAvvnk?As_b0Lx}!iA@kLQ@n*XpJS_qXY|KG}kTJ=HLRXK^7ph5{)YkK+otS=+`96HrUs*ox1p5>s}{o9@AER~duXpAlixzIBO7N^UtEjBt)VAG7=
zHVd)LwG_FFT?IT#;yj!)mgQue=6U5&tJSyw4+wE|2+^aoVH~~DIL9e(4E52&!P)Z9
zfz+aL-uWGXD2|DC<`3?#NTr2ny
zKqHPq!2VAN&I&+qipF6rx)+RT9+y+pJY>iNV@mixVNCJ&fHC5lpbXJI#`B)-I^8l=
zf*--=WvZDW5ez%oGxpy>aOf0-gfR_AI{?NUC6fwb5ORD7LTEyWL4DsFwGpb&JTGh&
z6#3>NxT*zFK@)78q%MlftI_VHDHA*KRy(+
zlqCp59M3Ra$og-&QR6{Yp2a4)W=KyM95$mpC$|e;Tp&xzEGGa>l74uR{Jr2Mh`=QQ
zED3soSQ7f7Sdv!0fC5>P4q(Z;Ew!rQK4{e)t5sbJnUVjI8-FJSA>kE3lDrJW2uv9Q
z0X?`y2_zT*0d-qX0SwXR6MCo>-j*5|w#RYvQ3)J3y+ekAM0<{;uj+$5+s5DulAy)n
ziYL$lP%8$qZ2)_vmFE=Tng>P!XN0cIJvrA6)gKh-Cg+N{!g6RN$LTQTO6~#zK4FPG
zsmu+^jAls-ui@~{_H;GM^~hh`KrNtheL_M4VUS#oQm09B!A(=KJ6$TW7*X9_pEp6)
zLVbd|3WHuxd@A6^=Vu75qZA^g;Fbb)3s)n`F(`G*+YUsGGU{bj&pMLGv$(BNnqH^Z
zLp%UWcY#O6ynOjloMPBis4Jp66;f45BN(t8*;TGaBgI8b-S9}0snOP#)Gfi%b
z!(LE#vraWw22rWoYO%u{kK?GU+s&gFIaBn8F+u4GpqR@@#S`Oy%pofFSJng|yQK?Dt+tR`q
z(gg;PEi{h-ogC+V&=`CqAUX0ujo#p!n)KO((6a!nqq8Q^B*n|5no?5?!?Dyjl1e7Y
z!0yTzZuiJg2bFsC>yl9vY-O;F6?wQe
zb`w%OiSDgIiz%9A;p7F$NQ&ZMM}lM=!!d9!gJmoOr6yQL^9&*g_(6s9dCiKP*v$w<
z@)Xm3F~>4|cbULYO!q8+jO(5Sfl+fo0n6Znzz9P3)Ceriz)3?tzk{Mc_b>vo9!5j~
zwzJ1tq31l2qUCNA;k#GtzMn`2AEiOgz`j#_x9C8|@Ilc54gi_zo@+Vya#r-ozUUy;
zDAsO9c(SK6Jl%auV6B=BFyeL^;nTs1Zil&+WfI_*FgP5*Oo$_Z1hVam9B@BIoe1b<
z!DnjSzP+juDolAzLll$cFlmb=(-K#y4JW8fJ*QFAIzh*AVwRA}FtniKd5uvH&c)O8k_TKmlO}x2Z<~VFH(rH~|Wm7D@pjlQ`xWw@^v}qYeQ%
zm-|Tp92qn@FGgu{b95jvGd3_UOl59obZ8(mHa9hwFiHU_fBLp97OnUYUl)r4dEPGi
zyiKusV??u|{fN|ZoTIzv_C624-j
zPBhxKE}-Q^e|c$>Od<_PHD1L_S(a!ie1ay?Eb=S@Ge+VO`sX8$MvX@5Y+^E`-Y3Q+
zSpdfduLd-3Q9oFpSUgg~BvvEMToRiwA+ZLj*9oc^EoI^)QZR>+noOC*q1>WhhgS@k
z!%(cjOJLnPClU-DX_k126yuIf2|Uk`Qda2FqdgSae;{jro2Bszn5P5)n
zfDwMhs_rH4}RuGBh-g%aX|nm|x<06AwO1A
zIpT+lZc}q?yVQ=*OXa(ua%l`;D|zrgby{(b-RczQmc
zt-E`oDhu#HmGCkBagk5Pr#sX0Ns)+jXMS3sPak~Bj!3h9x|d%*FUIGetD>Vte{u01
z;1t_E98U_cA9=pYYI?LhSuk^4E{phdH=h@=`N_kNBQgtaeYd
zqt*qXQu=E|7=&qyP_{&fw_KkLf2Fva5PMnfm7iY;kbvnh^({IBW@7QQ@zOA;m;x@D
zvW#__t6i6uwN=WtJl<{U@qLz&ZrX`;_`H60&DGH*)}0My0(H03=0PPISWr1G%Gbqz
z-yW^>Y1;baV)TSwi6tHgC9ksxt=8()LR?X&620oYqfK1HbDu)xN}m?9f6(^Wf$SK9
z+}0BIYd#=_lXBc=1YF}G1TM!|A%W4?*??&YObivA&eN4m5&(i%&3OaU*MBhJiv8u*^6n<+*
z^QvPtYFn$>y&}yBDZT0kXHPhkO8riKh5DWBRsS7LrkCNqIiTd#IRK}I&Y_1RW4U}2
z&8&)Yw}v5wfQ)_A75uPjeqgDm3uWQrWN;=7()i4i?xL6KSfJY0e**vA9abgaS{o2$
zdr87%t<_-}Ex4=dK+#tAX!{hR?`V%VaNesHe?=`envJQ|V53^B^-=tA^%F)TmB~Q`
zh))`N^$e2mG#Suv$YNf@Of{SCl`s?CkHd!q-cGL4>
zG!(-rVXrY76kTx~f5MfO24#I(x}({2n7w_C0pfJU)tTYCHNy`jcLZXEL#m)AHTMlF
zGHxkUB%+S=th2LRe4dp*93C7V
zBG}C!W&JGOD~o)wdWyJHI5=+z&8r%Q`Dbi#v^*`EYS~^@f5oc0I;v%OZf$+BOjpn8
z3TmbYNJZV@csAY77saFfe<6Bs46bE{b<=z=S^3vo_&rt|SC
zzdt@ZE6^hXIRt5GWMeitI{qb5tIV5YL@RaX043QfgA%jKy#5ccq0a2=y+~Y>**$of
z_*Ld82@U=H80Oz(ULFERn#_BYtQa^%$%=u!cd(!}Yw$={nI94CH<|sH2k;kHxjlyA
z>m0-6e|3%_@H)rfy2-uXc>$nab@1zJ_#JCW?85BRld|{|%OJSO%h?q0o}P}&)8)n4
zr1%1WPe-#wej0%f3&ZE-^gJ(@7n6L6d`M^KvuW`=R;09qGJxUfctW=p?{U*7Jy}jB
z#e(}n=_o%xFG_9<)#T`8!p)(ym`ui(^YNVfe?w_;G0Nwkxj~c`)0)iEv&jtYGeAzy
z%KVge%$=n4d^w)X(J?wXTX5fK{iLkG8Bx~7c)DccA-yb0K+$rZPeeez{J*msHD%TX6DjU16o3ts6VpLq@H)
zZmGsJ*ed1rW<}I1M%+-Whwf5S@LG^>cFA8u3CL{k*1EL~dImcWsehogwo@
zbSA3JOWW*TUYSx|3B;GWi}u)Ysl#s
zo|RFtj0Royl$!#+y6n!5+URe{r_)Vyb~&;bMEIWX0g%kqjQm;E{Y=kEF-p=qw&C
ztQL>j5!eQE&c@R<;%o;r+(55^#)&?lQOa(vCSJBzlUAnDQt~P9QoyEsQgw`5;mfeHbAAoe_b6ox;>y2
zGPMaxL0oZhn;vg~q#!pSDd;{(3fcW2DVPD021ptp>7gJgxD_PTJ0#mc5(YA!Yzs%y
z0gebuvI9mu`q7QILui9h?CS;~LK_=M#Pf4KP{h-8_rfBc!W+P70HXnn9tezhrnNyM
zo@(9NLs~A1W%&uyp)4-TfARcwPf2BjCY8l7&T7XHPVwl{20BUMH_?fQY}>xlX5TkL
zRoH|oDSM$xs(V6J`-Ig1RRdHFQ1y+Wsy-DMp-S4j1aqJ64p%(s>l`9FtN7Es48*N2
zSZUn>tJV3zCa~-FeiLA|4;xm1)jrwR0xTu(30O)EfHeTt09X$Oe^||NEdo}3K64wu
zV)XS@h((+-6=rGvGT(<-N_Kt$=Qlzv#Om+pt!vh~R|ep&oAe%4o@7Qd6PP)m8$i&}c~D0lqa
z`5ISiOW4ZHCTwM{7q+s#PiF1}TVa5$0k#I%dN9~Bat&L}f#_|13EVy;pMhFuj275?Ym#l0KIIs`Key~H*+oYx|Nrkpv-r|MBg7K`um27
zeh3o>C>x;c;h-$E!o;wBn8+XN?hR)~s0e3<|4UXzY&f%~56+zK9w-f0V#lrcxe3xj
zC!7rZ;bgdPI2nd;a)7h}(jE}f)*mt}vHh3K@t3@BhG{xmVOrMxZwma^siNbe@jvZu
z{P*Y;_3uq;JKY>=_p5H(#F?<9)fZ70R-wM?J4~i5E_mcr)6$3IcFqiaL0VoVH
zF$E
zAr}$V%8ghp%qS>&+eSC`phXc#t(u~Rn<7_9QcSPO2ZdHx6fwGJW|2Wu+Iyz+KW7>)
zgnyH824?>Je&;*iy&TTC$S0e19W_cE$5q3LfXpJFnyQ~Ts%937ub959)AY%H9O=uq
zp!X-caV1x@lM$}wjp1U~m?3@B5q|4@hMAIg*6~ZY#V-tZGR-XMTUYW^a>r9M2tR6SpHzD1Gb^m8T^=d9SQx$O8T
z#j1BotC^7eKEZs+Wn+91U&&>|y=-HF^npu!*0~vX63wd5M
zq&<~X*?6k=(I=k71tL}+m$>$1sI~E|?W9LMkM>Y+Au@{<8#6_+er
T0S*m0I5Ra33MC~)Peu(2WYKUR
delta 2794
zcmVgHSATS_rVrmTvJUlN{d2nSfPhx6QbZswAATu;CMrm?$
zbRaS|FfUAHZfA68ATc>PGm|mqAAhY_`)}hm68=~CTN5l2zDcQAEZ|4nEjF9Y#qMsm
zi=a?!*%7KpK1sgYqSycZK2i_Ahd!ID@Ov|~XT&B5ZD_#y10B~excL@TsdOl!2zPh+YL1u>8h1S3We
z&9J|bXv2^=5zaX=Sc*$c43^+vT8=j43H%PB#ygBWA@W_J5xPM9!cde?+}$Ap+=`)tVB%Z%8oae^>4D6tJ6$O9U=1NlV(a4it;Lzjk(?@JZbEy9bkF4Q3PAonQf<>w%O
zxSWRE;PMY-t(VujY4I4~E?KiK@|1LGhBxao*Sh^#tqWv)8z34Z2T2AmQ7-2o)d4U^
zYnL3bk8wH3x_^`=>UTh^r947j9C?j+uGb9rtm#8aFZ|H#!o5ljzZHK0e#?8|f1%6t
zD%^Jl1m8ac77-9ZJU~TafR%934EA+)H^__{QBt`USQ*Lc^C9s#d{Bd^5Ll!2V}a`*
zM=x>Yf#SIy_}%eq)dp_RfGKxV5)Nwv2g;Jr*nK#_dViKbnm$0}3;ppAH1CBa*n`D*
zx6us@#=~MzS~>Fz>)g{cE(ZuueYO2=43-F-%b+im_OyhXNK_0htqfd}d)SU3lSi&2
zpX)lK`o*WeK0V}Vmuk#m<%P1AbC+nCIpH*5?G+B;UZw%B52Y8n&5^Qyo?{Skj?Hy+
z!sX5hpMP*y#e0E?gP`e3SL@eZe+{U+nzTLRYW=!v-KAl>9yWLNzUSQ*`Ft8zU+C?4
zLTB;U>fXx?Hq~QZyq;W5CXAt;XGXrEqau!~Zd6-vP`sJ2kS%
zj`Q;z#w()g=V-kyaIliH#Kq*C4yN?Oa!Eh>|MB3A{uHg3V-(~MQB}gyvnBpk=eWSk
ztA8(WA93lNh+V=LHRGNLE(ILv{q{W-3l*&K3NPv2lTM(;;1>Gc;Q8$CK+Unip78Vr
zU^;HO;g+l0=mY-jhqK>)Bd1@6{Ez%de*gXaloQ~OZ#`i5J?T}3!wbRz0D+c-IkQ1l
zCLKLamdhAB;v$Dj8ue=A>2&rZ5gqYihJV{iLtKHQIszQs5jX!rY-otV=pC^wF}%7a
zK}SqU*!JJf;QlRfJwY64iI3oP3QWN16d2vXgSM)nBJGIpanEjv@%0tz#f}=`Y87lL
zM5}O1!F}15QZBJJ)Xm@>0(G~+=Nr@=TT2Y#_Vl5M|ARCLEutdN5Z>uLDdwA}Wq%rf
zMS!P^yo%;N@F6igZn9NWY@X6+13IMnD$n9ykdbHsFc8COlDe`M^Y9nYhfSKsh>;Lo
zM5|Sd2nN}@yLd=JaT=#-vM!SngrM=$A}Sxzl{C(puA<8{$NKJqOqWG8cYX}Q(A6eM
zOKglyme@tw?MP7vXWX)$l5FD^4}a-8E)a?~Wt1&|0i*xk!~gl8$1;t;WqmM1db4%c
zULHp>!@`3|=DroxY4129t&4o=?3HI3QhVvMKpU9oxY6wo!gJsJI-)%@Gwh}X7joSP
zEwAj@ebVZ3sSC8IueO2K9#-&ng0ML(0XtC478LW3fP#G7f?`#88WhXyAt>f=f^r+V
zRMH;7zh!dMncN(h-0Ya#9GKkfnB4A~eE)=$l~3IDheFeSDcn0!#}@FDwh8k8e>>IhR2?0Unp0H~|O>F*h(EFd$MOK0cR0IRPOEH90OfH6SrKmtiyk
zAh*Ci0f7RSH&6i$mrOwcAeUrN0V21JK>?Z$0XUcLUI8c!FgaZ>Q)zl-ATlsHmm*&Q
zL;^B5muO!BZhts8Mn*R?MME|MYURLWC&
zkXG0d_lJERsITwB)`AT6v@HYd=X#XNy|Nn
zGFAG}F+Q7IM~-LS4>daV`n(=K$@=36)Balbar2ijXx_WtzN_j@&pr0M2gT(7bHC5C
z=sd|$kKWh!h63rsNd~0%(!RSL%*@1B66TfP*MGZ>S<)}9KY1t%Ux|kL3x_XFS7%T|6s~b4xr|YbkZ{tXfRBc)IRU
z?&P^a%y^bl<>FbriF4w)(m}P8=Obr~XF3~QJQe$C7f(FORwqx8qsH@&dKb@{vm6r7
z 0:
+
+ user = getUser(uid=uid)
+
+ group = getGroup(gid)
+
+ if user is None:
+ return {"ERROR": "The user with id " + str(gid) + " does not exists !"}, 400
+
+ prenom = user["name"].split(" ", 1)
+ nom = user["name"].split(" ", 2)
+
+ group["name"]
+
+ annee1 = group["year"]
+ annee2 = int(group["year"]) + 1
+ promo = group["class_short"]
+
+ group["class_long"]
+ group["departement"]
+ group["resp_id"]
+ group["sec_id"]
+ group["ressources_dir"]
+
+ self.data = {
+ 'page1.nom_master': 'Renan',
+ 'page1.nom_complet_master': 'Husson',
+ 'page1.annee_1': 'Husson',
+ 'page1.annee_2': 'Jean Jaures',
+ 'page1.nom_prenom': 'Panda',
+ 'page1.email': 'Panda',
+ 'page1.telephone': 'Panda',
+ 'page1.entreprise': 'Panda',
+ 'page1.tuteur_pedagogique': 'Panda',
+ 'page1.tuteur_entreprise': 'Panda',
+ 'page2.type_contrat_apprentissage': True,
+ 'page2.type_contrat_professionnalisation': True,
+ 'page2.type_contrat_stage': True,
+ 'page2.debut_contrat': 'Panda',
+ 'page2.fin_contrat': 'Panda',
+ 'page2.telephone': 'Panda',
+ 'page2.email': 'Panda',
+ 'page2.compostant_formation': 'Panda',
+ 'page2.responsable_pedagogique_formation': 'Panda',
+ 'page2.tel_responsable_pedagogique_formation': 'Panda',
+ 'page2.mail_responsable_pedagogique_formation': 'Panda',
+ 'page2.tel_tuteur_pedagogique': 'Panda',
+ 'page2.mail_tuteur_pedagogique': 'Panda',
+ 'page2.tuteur_entreprise': 'Panda',
+ 'page2.entreprise': 'Panda',
+ 'page2.adresse_entreprise': 'Panda',
+ 'page2.tel_tuteur_entreprise': 'Panda',
+ 'page2.mail_tuteur_entreprise': 'Panda',
+ 'page4.poste_occupe': 'Panda',
+ 'page4.poste_occupe_2': 'Panda',
+ 'PEntreprise.n_periode': 'Panda',
+ 'PEntreprise.debut_periode': 'Panda',
+ 'PEntreprise.fin_periode': 'Panda',
+ 'PEntreprise.travaux_entreprise': 'Panda',
+ 'PEntreprise.remarque_tuteur': 'Panda',
+ 'pagePFormation.n_periode': 'Panda',
+ 'pagePFormation.bilan_periode': 'Panda',
+
+ }
+
+ pdf_fusion = ["/page1.pdf", "/page2.pdf"]
+ chemin_pdf = "/tmp"
+
+ nom_pdf = "Livret_Alternant_BOB_Armandeau.pdf"
+
+ fusion_fichiers(chemin_pdf, nom_pdf, pdf_fusion)
+
+ # Prenom NOM
+ # remplir_template()
diff --git a/backend/app/tools/LibPdf.py b/backend/app/tools/LibPdf.py
index da93aa5..985594a 100644
--- a/backend/app/tools/LibPdf.py
+++ b/backend/app/tools/LibPdf.py
@@ -55,15 +55,14 @@ def allowed_file(filename):
def upload_file(file_to_upload, upload_folder):
"""
- rep de l'etu avec id
- :param file:
+ televersement d'un fichier
+ :param file_to_upload:
:param upload_folder:
:return:
"""
file_to_upload.save(os.path.join(upload_folder, secure_filename(file_to_upload.filename)))
-
def delete_file(pdf_path):
if os.path.exists(pdf_path):
os.remove(pdf_path)
diff --git a/backend/tests/tools/libPdf/UploadPDF/testUploadPdf.py b/backend/tests/tools/libPdf/UploadPDF/testUploadPdf.py
index 45e1940..4604a9e 100644
--- a/backend/tests/tools/libPdf/UploadPDF/testUploadPdf.py
+++ b/backend/tests/tools/libPdf/UploadPDF/testUploadPdf.py
@@ -1,20 +1,25 @@
+import filecmp
import os
import unittest
+from pathlib import Path
from werkzeug.datastructures import FileStorage
-from app.tools.LibPdf import upload_file
+from app.tools.LibPdf import upload_file, allowed_file
class TestFusionTestCase(unittest.TestCase):
def setUp(self):
- self.datadir = os.path.join(os.path.dirname(__file__))
+ self.datadir = "upload/page1.pdf"
+ self.file_name = "page1.pdf"
def test_fusion(self):
- with open("page1.pdf", 'rb') as fp:
+ with open(self.file_name, 'rb') as fp:
file = FileStorage(fp)
upload_file(file, "upload")
- # self.assertTrue(Path(self.datadir + "/testFusion.pdf").is_file(), "Pdf fusionne inexistant")
- # self.assertTrue(len(get_pdf_from_directory(self.datadir)) > 0, "pdf non trouve")
- # os.remove(self.datadir + "/testFusion.pdf")
+ self.assertTrue(Path(self.datadir).is_file(), "Pdf upload inexistant")
+ self.assertTrue(filecmp.cmp(self.datadir, self.file_name), "fichiers non identique")
+ self.assertTrue(allowed_file(self.file_name), "format non conforme")
+
+ os.remove(self.datadir)
From cf95abbf17316296d52fb35cc26a884b9179bfbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20ARNAUDEAU?=
Date: Fri, 31 Mar 2017 12:35:29 +0200
Subject: [PATCH 3/7] =?UTF-8?q?TG-36=20:=20LivretAPI=20->=20cr=C3=A9ation?=
=?UTF-8?q?=20de=20livret=20+=20s=C3=A9curisation?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/OLA.mysql | 3 ++
backend/app/OLA_DATA.mysql | 18 -------
backend/app/api/GroupAPI.py | 26 +++++----
backend/app/api/LivretAPI.py | 98 ++++++++++++++++++----------------
backend/app/api/UserAPI.py | 24 ++++++---
backend/app/api/UserInfoAPI.py | 4 +-
backend/app/api/mailsModels.py | 19 ++++++-
7 files changed, 104 insertions(+), 88 deletions(-)
delete mode 100644 backend/app/OLA_DATA.mysql
diff --git a/backend/OLA.mysql b/backend/OLA.mysql
index 79529a8..80d8b2c 100644
--- a/backend/OLA.mysql
+++ b/backend/OLA.mysql
@@ -66,6 +66,7 @@ CREATE TABLE IF NOT EXISTS LIVRET
contract_type INT NOT NULL,
contract_start DATE NOT NULL,
contract_end DATE NOT NULL,
+ description TEXT NOT NULL,
ressources_dir VARCHAR(512),
opened TINYINT(1) NOT NULL,
expire DATE NOT NULL,
@@ -143,3 +144,5 @@ CREATE UNIQUE INDEX user_email
ON `USER` (`email`);
CREATE UNIQUE INDEX user_hash
ON `USER` (`hash`);
+CREATE UNIQUE INDEX tutorship_unique_bygroup
+ ON `TUTORSHIP` (`group_id`, `student_id`);
diff --git a/backend/app/OLA_DATA.mysql b/backend/app/OLA_DATA.mysql
deleted file mode 100644
index 1daf4d5..0000000
--- a/backend/app/OLA_DATA.mysql
+++ /dev/null
@@ -1,18 +0,0 @@
-USE OLA;
-INSERT INTO SETTINGS VALUES ('URL_BASE_DIRECTORY', '/OLA_RESSOURCES/', 'Répertoire base pour le dépot des fichiers');
-INSERT INTO SETTINGS VALUES ('OLA_URL', 'ola.univ-tlse2.fr/', 'URL de l application');
-
-INSERT INTO `USER` VALUES (1, 'sec', '1', 'sec@univ-tlse2.fr', '01.23.45.67.89');
-INSERT INTO `USER` VALUES (2, 'etu1', '4', 'etu1@univ-tlse2.fr', '01.23.45.67.89');
-INSERT INTO `USER` VALUES (3, 'etu2', '4', 'etu2@univ-tlse2.fr', '01.23.45.67.89');
-INSERT INTO `USER` VALUES (4, 'etu3', '4', 'etu3@univ-tlse2.fr', '01.23.45.67.89');
-INSERT INTO `USER` VALUES (5, 'resp', '2-3', 'resp@univ-tlse2.fr', '01.23.45.67.89');
-INSERT INTO `USER` VALUES (6, 'tut', '3', 'tut@univ-tlse2.fr', '01.23.45.67.89');
-
-INSERT INTO `GROUP` VALUES (1, 'M2_ICE_2016-2017_TEST', '2017', 'Master2 ICE', 'Master 2 Informatique Collaborative en Entreprise', 'Sciences du chômage proffessionnel', 5, 1, '/home/dan/PycharmProjects/OLA/backend/app/OLA_RESSOURCES/M2_ICE_2016-2017_TEST');
-INSERT INTO `GROUP` VALUES (2, 'M1_ICE_2016-2017_TEST', '2017', 'Master1 ICE', 'Master 1 Informatique Collaborative en Entreprise', 'Sciences du chômage proffessionnel', 5, 1, '/home/dan/PycharmProjects/OLA/backend/app/OLA_RESSOURCES/M1_ICE_2016-2017_TEST');
-
-INSERT INTO TUTORSHIP VALUES (DEFAULT, 1, 2, 5);
-INSERT INTO TUTORSHIP VALUES (DEFAULT, 2, 4, 5);
-INSERT INTO TUTORSHIP VALUES (DEFAULT, 1, 3, 6);
-
diff --git a/backend/app/api/GroupAPI.py b/backend/app/api/GroupAPI.py
index deaa810..781b566 100644
--- a/backend/app/api/GroupAPI.py
+++ b/backend/app/api/GroupAPI.py
@@ -12,6 +12,7 @@ class GroupAPI(Resource):
"""
Group Api Resource
"""
+
@login_required(roles=[Roles.resp_formation])
def post(self):
args = request.get_json(cache=False, force=True)
@@ -48,8 +49,8 @@ class GroupAPI(Resource):
"URL": getParam('OLA_URL')})
mails.append((user["email"], mail))
- if "2" not in user['role'].split('-'):
- role = user['role'] + "-2"
+ if str(Roles.resp_formation) not in user['role'].split('-'):
+ role = user['role'] + "-" + str(Roles.resp_formation)
query = USER.update().values(role=role).where(USER.c.id == resp_id)
query.execute()
@@ -69,8 +70,8 @@ class GroupAPI(Resource):
"URL": getParam('OLA_URL')})
mails.append((user["email"], mail))
- if "1" not in user['role'].split('-'):
- role = user['role'] + "-1"
+ if str(Roles.secretaire) not in user['role'].split('-'):
+ role = user['role'] + "-" + str(Roles.secretaire)
query = USER.update().values(role=role).where(USER.c.id == sec_id)
query.execute()
@@ -86,6 +87,7 @@ class GroupAPI(Resource):
return {"GID": res.lastrowid}, 201
+ @login_required(roles=Roles.resp_formation)
def put(self, gid):
args = request.get_json(cache=False, force=True)
if not checkParams(['name', 'year', 'class_short', 'class_long', 'department', 'resp_id', 'sec_id'], args):
@@ -125,8 +127,8 @@ class GroupAPI(Resource):
"URL": getParam('OLA_URL')})
mails.append((user["email"], mail))
- if "2" not in user['role'].split('-'):
- role = user['role'] + "-2"
+ if str(Roles.resp_formation) not in user['role'].split('-'):
+ role = user['role'] + "-" + str(Roles.resp_formation)
query = USER.update().values(role=role).where(USER.c.id == resp_id)
query.execute()
@@ -146,8 +148,8 @@ class GroupAPI(Resource):
"URL": getParam('OLA_URL')})
mails.append((user["email"], mail))
- if "1" not in user['role'].split('-'):
- role = user['role'] + "-1"
+ if str(Roles.secretaire) not in user['role'].split('-'):
+ role = user['role'] + "-" + str(Roles.secretaire)
query = USER.update().values(role=role).where(USER.c.id == sec_id)
query.execute()
@@ -166,12 +168,14 @@ class GroupAPI(Resource):
return {"GID": gid}, 200
+ @login_required()
def get(self, gid=0, name=""):
if gid > 0:
return {'GROUP': getGroup(gid=gid)}, 200
elif name != "":
return {'GROUP': getGroup(name=name)}, 200
+ @login_required(roles=Roles.resp_formation)
def options(self, gid):
args = request.get_json(cache=False, force=True)
if not checkParams(['pairs'], args):
@@ -188,16 +192,16 @@ class GroupAPI(Resource):
stud = getUser(uid=p[0])
if stud is None:
return {"ERROR": "The user with id " + str(p[0]) + " does not exists !"}, 400
- elif stud['role'] != "4":
+ elif stud['role'] != str(Roles.etudiant):
return {"ERROR": "A student must have the 'student' role !"}, 400
tutor = getUser(uid=p[1])
if tutor is None:
return {"ERROR": "The user with id " + str(p[1]) + " does not exists !"}, 400
- elif tutor['role'] == "4":
+ elif tutor['role'] == str(Roles.etudiant):
return {"ERROR": "A student can't be a tutor !"}, 400
elif "3" not in tutor['role'].split('-'):
- role = tutor['role'] + "-3"
+ role = tutor['role'] + "-" + str(Roles.tuteur_univ)
query = USER.update().values(role=role).where(USER.c.id == p[1])
query.execute()
except IndexError:
diff --git a/backend/app/api/LivretAPI.py b/backend/app/api/LivretAPI.py
index 0667f1c..596a054 100644
--- a/backend/app/api/LivretAPI.py
+++ b/backend/app/api/LivretAPI.py
@@ -1,80 +1,83 @@
import os
+from datetime import datetime
+from dateutil.relativedelta import relativedelta
+from flask import session
from flask_restful import Resource, request
+from sqlalchemy import and_
from app.api import mailsModels
-from app.model import Roles, getParam, getGroup, getUser, USER, GROUP, TUTORSHIP
-from app.utils import send_mail, checkParams
from app.api.LoginAPI import login_required
+from app.model import Roles, getParam, getGroup, getUser, USER, GROUP, TUTORSHIP, LIVRET
+from app.utils import send_mail, checkParams
+
class LivretAPI(Resource):
"""
Livret Api Resource
"""
+
@login_required(roles=[Roles.etudiant])
def post(self):
args = request.get_json(cache=False, force=True)
- if not checkParams(['name', 'year', 'class_short', 'class_long', 'department', 'resp_id', 'sec_id'], args):
+ if not checkParams(['student_id', 'group_id', 'etutor_id', 'company_name', 'company_address', 'contract_type',
+ 'contract_start', 'contract_end', 'description'], args):
return {"ERROR": "One or more parameters are missing !"}, 400
- name = args['name']
- year = args['year']
- class_short = args['class_short']
- class_long = args['class_long']
- department = args['department']
- resp_id = args['resp_id']
- sec_id = args['sec_id']
- res_dir = getParam('BASE_DIRECTORY') + name + "/"
+ user = session.get("user")
+ group_id = args['group_id']
+ etutor_id = args['etutor_id']
+ company_name = args['company_name']
+ company_address = args['company_address']
+ contract_type = int(args['contract_type'])
+ contract_start = datetime.strptime(args['contract_start'], "%d-%m-%Y")
+ contract_end = datetime.strptime(args['contract_end'], "%d-%m-%Y")
+ description = args['description']
mails = []
- group = getGroup(name=name)
- if group is not None:
- return {"GID": group["id"]}, 200
+ group = getGroup(gid=group_id)
+ if group is None:
+ return {"ERROR": "This group does not exists !"}, 405
- user = getUser(uid=resp_id)
+ query = TUTORSHIP.select(and_(TUTORSHIP.c.group_id == group_id, TUTORSHIP.c.student_id == user["id"]))
+ res = query.execute()
+ tutorship = res.first()
+
+ if tutorship is None:
+ return {"ERROR": "This student is not in this group !"}, 405
+
+ tutorship_id = tutorship.id
+
+ user = getUser(uid=etutor_id)
if user is None:
- return {"ERROR": "The user with id " + str(resp_id) + " does not exists !"}, 400
+ return {"ERROR": "The user with id " + str(etutor_id) + " does not exists !"}, 400
else:
query = USER.select(USER.c.id == user["id"])
rows = query.execute()
res = rows.first()
if res.hash is not None and len(res.hash) > 0:
- mail = mailsModels.getMailContent("NEW_RESP_OF_GROUP", {"GROUP": name,
- "URL": getParam('OLA_URL') + "registration/"
- + res.hash})
- else:
- mail = mailsModels.getMailContent("RESP_OF_GROUP", {"GROUP": name,
- "URL": getParam('OLA_URL')})
-
- mails.append((user["email"], mail))
- if "2" not in user['role'].split('-'):
- role = user['role'] + "-2"
- query = USER.update().values(role=role).where(USER.c.id == resp_id)
- query.execute()
-
- user = getUser(uid=sec_id)
- if user is None:
- return {"ERROR": "The user with id " + str(sec_id) + " does not exists !"}, 400
- else:
- query = USER.select(USER.c.id == user["id"])
- rows = query.execute()
- res = rows.first()
- if res.hash is not None and len(res.hash) > 0:
- mail = mailsModels.getMailContent("NEW_SEC_OF_GROUP", {"GROUP": name,
+ mail = mailsModels.getMailContent("NEW_ETUTOR_ADDED", {"GROUP": group["name"],
"URL": getParam('OLA_URL') + "registration/"
+ res.hash})
else:
- mail = mailsModels.getMailContent("SEC_OF_GROUP", {"GROUP": name,
+ mail = mailsModels.getMailContent("ETUTOR_ADDED", {"GROUP": group["name"],
"URL": getParam('OLA_URL')})
mails.append((user["email"], mail))
- if "1" not in user['role'].split('-'):
- role = user['role'] + "-1"
- query = USER.update().values(role=role).where(USER.c.id == sec_id)
- query.execute()
+ if str(Roles.tuteur_entreprise) not in user['role'].split('-'):
+ return {"ERROR": "The user with id " + str(etutor_id) +
+ " doesn't have the 'etutor' role (" + str(Roles.tuteur_entreprise) + ") !"}, 400
- query = GROUP.insert().values(name=name, year=year, class_short=class_short, class_long=class_long,
- department=department, resp_id=resp_id, sec_id=sec_id, ressources_dir=res_dir)
+ if contract_start > contract_end:
+ return {"ERROR": "The contract start can't be after its end !"}, 400
+
+ res_dir = group["ressources_dir"] + user['id'] + "/"
+ expire = datetime.now() + relativedelta(year=1)
+
+ query = LIVRET.insert().values(tutorship_id=tutorship_id, etutor_id=etutor_id, company_name=company_name,
+ company_address=company_address, contract_type=contract_type,
+ contract_start=contract_start, contract_end=contract_end,
+ description=description, ressources_dir=res_dir, opened='1', expire=expire)
res = query.execute()
os.mkdir(res_dir)
@@ -83,8 +86,9 @@ class LivretAPI(Resource):
mail = m[1]
send_mail(mail[0], addr, mail[1])
- return {"GID": res.lastrowid}, 201
+ return {"LID": res.lastrowid}, 201
+ @login_required(roles=[Roles.etudiant])
def put(self, gid):
args = request.get_json(cache=False, force=True)
if not checkParams(['name', 'year', 'class_short', 'class_long', 'department', 'resp_id', 'sec_id'], args):
@@ -165,12 +169,14 @@ class LivretAPI(Resource):
return {"GID": gid}, 200
+ @login_required()
def get(self, gid=0, name=""):
if gid > 0:
return {'GROUP': getGroup(gid=gid)}, 200
elif name != "":
return {'GROUP': getGroup(name=name)}, 200
+ @login_required(roles=Roles.etudiant)
def options(self, gid):
args = request.get_json(cache=False, force=True)
if not checkParams(['pairs'], args):
diff --git a/backend/app/api/UserAPI.py b/backend/app/api/UserAPI.py
index 5b61425..3c2194d 100644
--- a/backend/app/api/UserAPI.py
+++ b/backend/app/api/UserAPI.py
@@ -1,10 +1,11 @@
from hashlib import sha256
+from flask import session
from flask_restful import Resource, request
+from app.api.LoginAPI import login_required
from app.model import Roles, getUser, hashExists, USER
from app.utils import checkParams, get_random_string
-from app.api.LoginAPI import login_required
class UserAPI(Resource):
"""
@@ -52,9 +53,14 @@ class UserAPI(Resource):
password = sha256(psw.encode('utf-8')).hexdigest()
- if getUser(uid=uid) is None:
+ user = getUser(uid=uid)
+ if user is None:
return {"ERROR": "This user doesn't exists !"}, 405
+ # On n'autorise pas de modifcation anonyme d'un profil s'il est déjà activé (si il a un mdp)
+ if user["password"] is not None and user["password"] != "" and session.get("user", None) is None:
+ return {"msg": "UNAUTHORIZED"}, 401
+
if getUser(email=email) is not None:
return {"ERROR": "A user with this email already exists !"}, 405
@@ -64,9 +70,11 @@ class UserAPI(Resource):
return {"UID": uid}, 200
def get(self, uid=0, email="", hashcode=""):
- if uid > 0:
- return {'USER': getUser(uid=uid)}, 200
- elif email != "":
- return {'USER': getUser(email=email)}, 200
- elif hashcode != "":
- return {'USER': getUser(hashcode=hashcode)}, 200
+ if session.get('user', None) is not None:
+ if uid > 0:
+ return {'USER': getUser(uid=uid)}, 200
+ elif email != "":
+ return {'USER': getUser(email=email)}, 200
+
+ if hashcode != "":
+ return {'USER': getUser(hashcode=hashcode)}, 200
\ No newline at end of file
diff --git a/backend/app/api/UserInfoAPI.py b/backend/app/api/UserInfoAPI.py
index 5e2f6cc..eb46881 100644
--- a/backend/app/api/UserInfoAPI.py
+++ b/backend/app/api/UserInfoAPI.py
@@ -1,6 +1,6 @@
from flask import session
from flask_restful import Resource
-from app.api.LoginAPI import login_required
+
from app.model import LIVRET, TUTORSHIP, and_
@@ -9,7 +9,6 @@ class UserInfoAPI(Resource):
UserInfo Api Resource
"""
- @login_required()
def get(self):
user = session.get("user", None)
return {'USER': user}, 200
@@ -19,7 +18,6 @@ class UserGroupsAPI(Resource):
"""
UserGroups Api Resource
"""
- @login_required()
def get(self):
user = session.get("user", None)
if user is not None:
diff --git a/backend/app/api/mailsModels.py b/backend/app/api/mailsModels.py
index e928d94..b92ee26 100644
--- a/backend/app/api/mailsModels.py
+++ b/backend/app/api/mailsModels.py
@@ -11,7 +11,7 @@ _STUD_OF_GROUP = (
_NEW_RESP_OF_GROUP = ("Votre compte OLA a été créé !", "Bonjour,
Votre compte vient d'être créé dans l'Outil du "
"Livret de l'Alternant en tant que responsable du groupe #GROUPE. Vous pouvez dès "
- "maintenant l'activer, en vous rendant à l'adresse :
"
+ "maintenant l'activer en vous rendant à l'adresse :
"
"#URL
Bonne journée !
")
_RESP_OF_GROUP = (
@@ -22,7 +22,7 @@ _RESP_OF_GROUP = (
_NEW_SEC_OF_GROUP = ("Votre compte OLA a été créé !", "Bonjour,
Votre compte vient d'être créé dans l'Outil du "
"Livret de l'Alternant en tant que secrétaire du groupe #GROUPE. Vous pouvez dès "
- "maintenant l'activer, en vous rendant à l'adresse :
"
+ "maintenant l'activer en vous rendant à l'adresse :
"
"#URL
Bonne journée !
")
_SEC_OF_GROUP = (
@@ -31,6 +31,17 @@ _SEC_OF_GROUP = (
"maintenant y accéder en vous rendant à l'adresse :
"
"#URL
Bonne journée !
")
+_NEW_ETUTOR_ADDED = ("Votre compte OLA a été créé !", "Bonjour,
Votre compte vient d'être créé dans l'Outil du "
+ "Livret de l'Alternant de l'Université Toulouse Jean-Jaurès en tant que tuteur dans le groupe #GROUPE. Vous pouvez dès "
+ "maintenant l'activer en vous rendant à l'adresse :
"
+ "#URL
Bonne journée !
")
+
+_ETUTOR_ADDED = (
+ "Vous avez été déclaré comme tuteur dans OLA !", "Bonjour,
Votre compte vient d'être ajouté dans l'Outil du "
+ "Livret de l'Alternant de l'Université Toulouse Jean-Jaurès en tant que tuteur dans le groupe #GROUPE. Vous pouvez dès "
+ "maintenant accéder à votre compte en vous rendant à l'adresse :
"
+ "#URL
Bonne journée !
")
+
def getMailContent(mail_type, args):
if mail_type == "NEW_STUD_OF_GROUP":
@@ -45,6 +56,10 @@ def getMailContent(mail_type, args):
mail = _NEW_SEC_OF_GROUP
elif mail_type == "SEC_OF_GROUP":
mail = _SEC_OF_GROUP
+ elif mail_type == "NEW_ETUTOR_ADDED":
+ mail = _NEW_ETUTOR_ADDED
+ elif mail_type == "ETUTOR_ADDED":
+ mail = _ETUTOR_ADDED
else:
raise Exception("Unknown mail type !")
From 0891214b30a06a52744420c941e9d7bdfce697a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20ARNAUDEAU?=
Date: Sat, 6 May 2017 18:03:15 +0200
Subject: [PATCH 4/7] TG-40 : LivretAPI -> finalisation de l'API des livrets +
correctifs
---
API_Interfaces.txt | 3 +-
backend/OLA_DATA.mysql | 2 +-
backend/app/api/LivretAPI.py | 173 ++++++++++-----------------------
backend/app/api/LoginAPI.py | 7 +-
backend/app/api/UserAPI.py | 4 +-
backend/app/api/mailsModels.py | 6 +-
backend/app/model.py | 60 ++++++++++--
backend/app/urls.py | 3 +-
8 files changed, 117 insertions(+), 141 deletions(-)
diff --git a/API_Interfaces.txt b/API_Interfaces.txt
index 9a73149..745aba2 100644
--- a/API_Interfaces.txt
+++ b/API_Interfaces.txt
@@ -1,7 +1,7 @@
#######################
LoginAPI (api/login)
#######################
-GET -> Authentication method
+POST -> Authentication method
Out:
200 -> AUTH_RESULT = "OK" : Authentication sucessful
401 -> AUTH_RESULT = "AUTHENTICATION_FAILURE" : Wrong login/password
@@ -27,6 +27,7 @@ POST -> Create a user if it not already exists
In:
email = Email and login of the user (must be unique)
role = Role of the user (can be concatenated with -) 1=secrétaire, 2=resp_formation, 3=tuteur_univ, 4=étudiant, 5=tuteur_ent
+ name = Display name of the user
Out:
200 -> UID = : The user already exists with the id USER_ID
201 -> UID = : The user has been successfully created with the id USER_ID
diff --git a/backend/OLA_DATA.mysql b/backend/OLA_DATA.mysql
index 7c8db3a..ed16388 100644
--- a/backend/OLA_DATA.mysql
+++ b/backend/OLA_DATA.mysql
@@ -1,7 +1,7 @@
USE OLA;
INSERT INTO SETTINGS VALUES ('BASE_DIRECTORY', '/OLA_RESSOURCES/', 'Répertoire base pour le dépot des fichiers');
INSERT INTO SETTINGS VALUES ('TEMPLATES_DIRECTORY', '/OLA_TEMPLATES/', 'Répertoire base pour le dépot des fichiers');
-INSERT INTO SETTINGS VALUES ('OLA_URL', 'ola.univ-tlse2.fr/', 'URL de l application');
+INSERT INTO SETTINGS VALUES ('OLA_URL', 'http://ola.univ-tlse2.fr/', 'URL de l application');
INSERT INTO `USER` VALUES (1, '1', 'sec@univ-tlse2.fr', 'Secrétaire', DEFAULT, 'aZeRtYuIoP', '01.23.45.67.89');
INSERT INTO `USER` VALUES (2, '4', 'etu1@univ-tlse2.fr', 'Etudiant 1', DEFAULT, 'qSdFgHjKlM', '01.23.45.67.89');
diff --git a/backend/app/api/LivretAPI.py b/backend/app/api/LivretAPI.py
index 596a054..0898901 100644
--- a/backend/app/api/LivretAPI.py
+++ b/backend/app/api/LivretAPI.py
@@ -1,14 +1,12 @@
import os
-from datetime import datetime
+from datetime import datetime, timedelta
-from dateutil.relativedelta import relativedelta
from flask import session
from flask_restful import Resource, request
-from sqlalchemy import and_
from app.api import mailsModels
from app.api.LoginAPI import login_required
-from app.model import Roles, getParam, getGroup, getUser, USER, GROUP, TUTORSHIP, LIVRET
+from app.model import Roles, getParam, getGroup, getUser, USER, LIVRET, getLivret, getTutorship
from app.utils import send_mail, checkParams
@@ -20,7 +18,7 @@ class LivretAPI(Resource):
@login_required(roles=[Roles.etudiant])
def post(self):
args = request.get_json(cache=False, force=True)
- if not checkParams(['student_id', 'group_id', 'etutor_id', 'company_name', 'company_address', 'contract_type',
+ if not checkParams(['group_id', 'etutor_id', 'company_name', 'company_address', 'contract_type',
'contract_start', 'contract_end', 'description'], args):
return {"ERROR": "One or more parameters are missing !"}, 400
@@ -39,14 +37,16 @@ class LivretAPI(Resource):
if group is None:
return {"ERROR": "This group does not exists !"}, 405
- query = TUTORSHIP.select(and_(TUTORSHIP.c.group_id == group_id, TUTORSHIP.c.student_id == user["id"]))
- res = query.execute()
- tutorship = res.first()
+ tutorship = getTutorship(gid=group_id, student=user["id"])
if tutorship is None:
return {"ERROR": "This student is not in this group !"}, 405
- tutorship_id = tutorship.id
+ tutorship_id = tutorship["id"]
+
+ livret = getLivret(group_id=group_id, student_id=user["id"])
+ if livret is not None:
+ return {"ERROR": "This livret already exists !"}, 405
user = getUser(uid=etutor_id)
if user is None:
@@ -56,11 +56,11 @@ class LivretAPI(Resource):
rows = query.execute()
res = rows.first()
if res.hash is not None and len(res.hash) > 0:
- mail = mailsModels.getMailContent("NEW_ETUTOR_ADDED", {"GROUP": group["name"],
+ mail = mailsModels.getMailContent("NEW_ETUTOR_ADDED", {"GROUPE": group["name"],
"URL": getParam('OLA_URL') + "registration/"
+ res.hash})
else:
- mail = mailsModels.getMailContent("ETUTOR_ADDED", {"GROUP": group["name"],
+ mail = mailsModels.getMailContent("ETUTOR_ADDED", {"GROUPE": group["name"],
"URL": getParam('OLA_URL')})
mails.append((user["email"], mail))
@@ -71,8 +71,8 @@ class LivretAPI(Resource):
if contract_start > contract_end:
return {"ERROR": "The contract start can't be after its end !"}, 400
- res_dir = group["ressources_dir"] + user['id'] + "/"
- expire = datetime.now() + relativedelta(year=1)
+ res_dir = group["ressources_dir"] + "/" + str(user['id']) + "/"
+ expire = datetime.now() + timedelta(days=365)
query = LIVRET.insert().values(tutorship_id=tutorship_id, etutor_id=etutor_id, company_name=company_name,
company_address=company_address, contract_type=contract_type,
@@ -89,139 +89,66 @@ class LivretAPI(Resource):
return {"LID": res.lastrowid}, 201
@login_required(roles=[Roles.etudiant])
- def put(self, gid):
+ def put(self, lid):
args = request.get_json(cache=False, force=True)
- if not checkParams(['name', 'year', 'class_short', 'class_long', 'department', 'resp_id', 'sec_id'], args):
+ if not checkParams(['etutor_id', 'company_name', 'company_address', 'contract_type',
+ 'contract_start', 'contract_end', 'description'], args):
return {"ERROR": "One or more parameters are missing !"}, 400
- name = args['name'].replace(" ", "_").replace("/", "-")
- year = args['year']
- class_short = args['class_short']
- class_long = args['class_long']
- department = args['department']
- resp_id = args['resp_id']
- sec_id = args['sec_id']
- res_dir = getParam('BASE_DIRECTORY') + name + "/"
+ etutor_id = args['etutor_id']
+ company_name = args['company_name']
+ company_address = args['company_address']
+ contract_type = int(args['contract_type'])
+ contract_start = datetime.strptime(args['contract_start'], "%d-%m-%Y")
+ contract_end = datetime.strptime(args['contract_end'], "%d-%m-%Y")
+ description = args['description']
mails = []
- group = getGroup(gid=gid)
- if group is None:
- return {"ERROR": "This group does not exists !"}, 405
+ livret = getLivret(lid=lid)
+ if livret is None:
+ return {"ERROR": "This livret does not exists !"}, 405
- group2 = getGroup(name=name)
- if group2 is not None:
- return {"ERROR": "A group with this name already exists !"}, 405
-
- user = getUser(uid=resp_id)
+ user = getUser(uid=etutor_id)
if user is None:
- return {"ERROR": "The user with id " + str(resp_id) + " does not exists !"}, 400
+ return {"ERROR": "The user with id " + str(etutor_id) + " does not exists !"}, 400
else:
query = USER.select(USER.c.id == user["id"])
rows = query.execute()
res = rows.first()
if res.hash is not None and len(res.hash) > 0:
- mail = mailsModels.getMailContent("NEW_RESP_OF_GROUP", {"GROUP": group["name"],
- "URL": getParam('OLA_URL') + "registration/"
- + res.hash})
+ mail = mailsModels.getMailContent("NEW_ETUTOR_ADDED",
+ {"GROUPE": livret["tutorship_id"]["group_id"]["name"],
+ "URL": getParam('OLA_URL') + "registration/"
+ + res.hash})
else:
- mail = mailsModels.getMailContent("RESP_OF_GROUP", {"GROUP": group["name"],
- "URL": getParam('OLA_URL')})
-
- mails.append((user["email"], mail))
- if "2" not in user['role'].split('-'):
- role = user['role'] + "-2"
- query = USER.update().values(role=role).where(USER.c.id == resp_id)
- query.execute()
-
- user = getUser(uid=sec_id)
- if user is None:
- return {"ERROR": "The user with id " + str(sec_id) + " does not exists !"}, 400
- else:
- query = USER.select(USER.c.id == user["id"])
- rows = query.execute()
- res = rows.first()
- if res.hash is not None and len(res.hash) > 0:
- mail = mailsModels.getMailContent("NEW_SEC_OF_GROUP", {"GROUP": group["name"],
- "URL": getParam('OLA_URL') + "registration/"
- + res.hash})
- else:
- mail = mailsModels.getMailContent("SEC_OF_GROUP", {"GROUP": group["name"],
+ mail = mailsModels.getMailContent("ETUTOR_ADDED", {"GROUPE": livret["tutorship_id"]["group_id"]["name"],
"URL": getParam('OLA_URL')})
mails.append((user["email"], mail))
- if "1" not in user['role'].split('-'):
- role = user['role'] + "-1"
- query = USER.update().values(role=role).where(USER.c.id == sec_id)
- query.execute()
+ if str(Roles.tuteur_entreprise) not in user['role'].split('-'):
+ return {"ERROR": "The user with id " + str(etutor_id) +
+ " doesn't have the 'etutor' role (" + str(Roles.tuteur_entreprise) + ") !"}, 400
- query = GROUP.update().values(name=name, year=year, class_short=class_short, class_long=class_long,
- department=department, resp_id=resp_id, sec_id=sec_id, ressources_dir=res_dir) \
- .where(GROUP.c.id == gid)
+ if contract_start > contract_end:
+ return {"ERROR": "The contract start can't be after its end !"}, 400
+
+ query = LIVRET.update().values(etutor_id=etutor_id, company_name=company_name,
+ company_address=company_address, contract_type=contract_type,
+ contract_start=contract_start, contract_end=contract_end,
+ description=description) \
+ .where(LIVRET.c.id == lid)
query.execute()
- if group["ressources_dir"] != res_dir:
- os.rename(group["ressources_dir"], res_dir)
-
for m in mails:
addr = m[0]
mail = m[1]
send_mail(mail[0], addr, mail[1])
- return {"GID": gid}, 200
+ return {"LID": lid}, 200
@login_required()
- def get(self, gid=0, name=""):
- if gid > 0:
- return {'GROUP': getGroup(gid=gid)}, 200
- elif name != "":
- return {'GROUP': getGroup(name=name)}, 200
-
- @login_required(roles=Roles.etudiant)
- def options(self, gid):
- args = request.get_json(cache=False, force=True)
- if not checkParams(['pairs'], args):
- return {"ERROR": "One or more parameters are missing !"}, 400
-
- pairs = args["pairs"]
-
- group = getGroup(gid=gid)
- if group is None:
- return {"ERROR": "This group does not exists !"}, 405
-
- for p in pairs:
- try:
- stud = getUser(uid=p[0])
- if stud is None:
- return {"ERROR": "The user with id " + str(p[0]) + " does not exists !"}, 400
- elif stud['role'] != "4":
- return {"ERROR": "A student must have the 'student' role !"}, 400
-
- tutor = getUser(uid=p[1])
- if tutor is None:
- return {"ERROR": "The user with id " + str(p[1]) + " does not exists !"}, 400
- elif tutor['role'] == "4":
- return {"ERROR": "A student can't be a tutor !"}, 400
- elif "3" not in tutor['role'].split('-'):
- role = tutor['role'] + "-3"
- query = USER.update().values(role=role).where(USER.c.id == p[1])
- query.execute()
- except IndexError:
- return {"ERROR": "Pairs are incorrectly formed !"}, 409
-
- query = TUTORSHIP.insert().values(group_id=gid, student_id=p[0], ptutor_id=p[1])
- query.execute()
-
- query = USER.select(USER.c.id == stud["id"])
- rows = query.execute()
- res = rows.first()
- if res.hash is not None and len(res.hash) > 0:
- mail = mailsModels.getMailContent("NEW_STUD_OF_GROUP", {"GROUP": group["name"],
- "URL": getParam('OLA_URL') + "registration/"
- + res.hash})
- else:
- mail = mailsModels.getMailContent("STUD_OF_GROUP", {"GROUP": group["name"],
- "URL": getParam('OLA_URL')})
-
- send_mail(mail[0], stud["email"], mail[1])
-
- return {"RESULT": "Pairs added successfully"}, 200
+ def get(self, lid=0, group_id=0, student_id=0):
+ if lid > 0:
+ return {'LIVRET': getLivret(lid=lid)}, 200
+ elif group_id > 0 and student_id > 0:
+ return {'LIVRET': getLivret(group_id=group_id, student_id=student_id)}, 200
diff --git a/backend/app/api/LoginAPI.py b/backend/app/api/LoginAPI.py
index b388529..e99686a 100644
--- a/backend/app/api/LoginAPI.py
+++ b/backend/app/api/LoginAPI.py
@@ -50,14 +50,13 @@ class LoginAPI(Resource):
return {'AUTH_RESULT': 'OK'}, 200
-
def login_required(roles=[]):
def my_login_required(func):
- def wrapper(*args):
+ def wrapper(*args, **kvargs):
current_user = session.get('user', None)
if current_user is None or (len(roles) != 0 and not sum([1 for x in current_user['role'].split("-") if int(x) in roles]) > 0):
- return {"msg": "UNAUTHORIZED"}, 401
- return func(*args)
+ return {"ERROR": "UNAUTHORIZED"}, 401
+ return func(*args, **kvargs)
return wrapper
return my_login_required
diff --git a/backend/app/api/UserAPI.py b/backend/app/api/UserAPI.py
index 3c2194d..9b14a41 100644
--- a/backend/app/api/UserAPI.py
+++ b/backend/app/api/UserAPI.py
@@ -7,11 +7,13 @@ from app.api.LoginAPI import login_required
from app.model import Roles, getUser, hashExists, USER
from app.utils import checkParams, get_random_string
+
class UserAPI(Resource):
"""
User Api Resource
"""
- @login_required(roles=[Roles.resp_formation])
+
+ @login_required(roles=[Roles.resp_formation, Roles.etudiant])
def post(self):
args = request.get_json(cache=False, force=True)
if not checkParams(['role', 'email', 'name'], args):
diff --git a/backend/app/api/mailsModels.py b/backend/app/api/mailsModels.py
index b92ee26..c64d0dd 100644
--- a/backend/app/api/mailsModels.py
+++ b/backend/app/api/mailsModels.py
@@ -63,6 +63,8 @@ def getMailContent(mail_type, args):
else:
raise Exception("Unknown mail type !")
+ obj = mail[0]
+ content = str(mail[1])
for key, value in args.items():
- mail[1].replace("#" + key, value)
- return mail
+ content = content.replace("#" + key, value)
+ return (obj, content)
diff --git a/backend/app/model.py b/backend/app/model.py
index 6179978..5861f3b 100644
--- a/backend/app/model.py
+++ b/backend/app/model.py
@@ -75,15 +75,59 @@ def getGroup(gid=0, name=""):
return None
-def getTutorshipForStudent(gid, student):
- query = TUTORSHIP.select(and_(TUTORSHIP.c.group_id == gid, TUTORSHIP.c.student_id == student))
- rows = query.execute()
- res = rows.first()
- if res is not None:
- return {"id": res.id, "group_id": getGroup(gid=res.group_id), "student_id": getUser(uid=res.student_id),
- "ptutor_id": getUser(uid=res.ptutor_id)}
+def getTutorship(tid=0, gid=0, student=0):
+ if tid == 0 and gid == 0 and student == 0:
+ raise Exception("getGroup must be called with at least one argument !")
else:
- return None
+ if gid != 0:
+ query = TUTORSHIP.select(and_(TUTORSHIP.c.group_id == gid, TUTORSHIP.c.student_id == student))
+ rows = query.execute()
+ res = rows.first()
+ elif tid != 0:
+ query = TUTORSHIP.select(TUTORSHIP.c.id == tid)
+ rows = query.execute()
+ res = rows.first()
+ else:
+ raise Exception("getTutorship must be called with two parameter for group+student search !")
+
+ if res is not None:
+ return {"id": res.id, "group_id": getGroup(gid=res.group_id), "student_id": getUser(uid=res.student_id),
+ "ptutor_id": getUser(uid=res.ptutor_id)}
+ else:
+ return None
+
+
+def getLivret(lid=0, group_id=0, student_id=0):
+ res = None
+
+ if lid == 0 and student_id == "":
+ raise Exception("getLivret must be called with at least one argument !")
+ else:
+ if lid != 0:
+ query = LIVRET.select(LIVRET.c.id == lid)
+ rows = query.execute()
+ res = rows.first()
+
+ elif student_id != 0 and group_id != 0:
+ tutorship = getTutorship(gid=group_id, student=student_id)
+ if tutorship is None:
+ return None
+ query = LIVRET.select(LIVRET.c.tutorship_id == tutorship["id"])
+ rows = query.execute()
+ res = rows.first()
+ else:
+ raise Exception("getLivret must be called with two parameter for group+student search !")
+
+ if res is not None:
+ return {"id": res.id, "tutorship_id": getTutorship(tid=res.tutorship_id),
+ "etutor_id": getUser(uid=res.etutor_id), "company_name": res.company_name,
+ "company_address": res.company_address, "contract_type": res.contract_type,
+ "contract_start": res.contract_start.strftime('%d-%m-%Y'),
+ "contract_end": res.contract_end.strftime('%d-%m-%Y'),
+ "ressources_dir": res.ressources_dir, "opened": res.opened,
+ "expire": res.expire.strftime('%d-%m-%Y')}
+ else:
+ return None
def hashExists(test):
diff --git a/backend/app/urls.py b/backend/app/urls.py
index 5ccd60b..2a0027d 100644
--- a/backend/app/urls.py
+++ b/backend/app/urls.py
@@ -14,4 +14,5 @@ api.add_resource(UserGroupsAPI, '/api/userGroups')
api.add_resource(UserAPI, '/api/user', '/api/user/byuid/', '/api/user/byemail/',
'/api/user/byhash/')
api.add_resource(GroupAPI, '/api/group', '/api/group/bygid/', '/api/group/byname/')
-api.add_resource(LivretAPI, '/api/livret', '/api/livret/byuid/')
+api.add_resource(LivretAPI, '/api/livret', '/api/livret/bylid/',
+ '/api/livret/bytutorship//')
From 5641f8ebd98f4506699e44d37d1f899e6b211690 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20ARNAUDEAU?=
Date: Mon, 8 May 2017 15:48:12 +0200
Subject: [PATCH 5/7] TG-40 : LivretAPI -> MAJ de l'interface
---
API_Interfaces.txt | 48 ++++++++++++++++++++++++++++++++++++
backend/app/api/LivretAPI.py | 6 ++---
2 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/API_Interfaces.txt b/API_Interfaces.txt
index 745aba2..b1c2634 100644
--- a/API_Interfaces.txt
+++ b/API_Interfaces.txt
@@ -2,6 +2,9 @@
LoginAPI (api/login)
#######################
POST -> Authentication method
+ In:
+ email = Email and login of the user (must be unique)
+ password = Password of the user (secured by HTTPS)
Out:
200 -> AUTH_RESULT = "OK" : Authentication sucessful
401 -> AUTH_RESULT = "AUTHENTICATION_FAILURE" : Wrong login/password
@@ -99,3 +102,48 @@ OPTIONS -> Add pairs of users (student/tutor) to the group
400 -> ERROR = "A student can't be a tutor !" : The given USER_ID for tutor have the "student" role (4) and so can't be a tutor
405 -> ERROR = "This group doesn't exists !" : Bad GROUP_ID provided
409 -> ERROR = "Pairs are incorrectly formed !" : Bad syntax in pairs table
+
+########################
+LivretAPI (api/livret)
+########################
+POST -> Create a livret if it not already exists
+ In:
+ group_id = Id of the group where this livret should be inserted in (we must have only one livret per student in a single group)
+ etutor_id = UID of the company tutor
+ company_name = Name of the company
+ company_address = Mail address of the company
+ contract_type = Type of the internship contract (1 = contrat d'alternance, 2 = contrat de professionnalisation, 3 = stage)
+ contract_start = Date of the contract's beginning (format : dd-mm-yyyy)
+ contract_end = Date of the contract's end (format : dd-mm-yyyy)
+ description = Description of the internship missions and activities overview
+ Out:
+ 200 -> LID = : The livret already exists with the id LIVRET_ID
+ 201 -> LID = : The livret has been successfully created with the id LIVRET_ID
+ 400 -> ERROR = "One or more parameters are missing" : Bad request
+ 400 -> ERROR = "The user with id doesn't exists !" : The given USER_ID for etutor is not found
+ 400 -> ERROR = "An etutor must have the 'etutor' role !" : The given USER_ID for etutor doesn't have the "etutor" role (5)
+ 400 -> ERROR = "The contract start can't be after its end !" : The given contract's end date is anterior to it's beginning
+ 405 -> ERROR = "The group with id GROUP_ID doesn't exists !" : The given GROUP_ID is not found
+ 405 -> ERROR = "The The current student is not registered in the group !" : The currently logged student is not affected to the specified GROUP_ID
+
+PUT -> Modify an existing livret
+ In: (Suffix = /bylid/)
+ etutor_id = UID of the company tutor
+ company_name = Name of the company
+ company_address = Mail address of the company
+ contract_type = Type of the internship contract (1 = contrat d'alternance, 2 = contrat de professionnalisation, 3 = stage)
+ contract_start = Date of the contract's beginning (format : dd-mm-yyyy)
+ contract_end = Date of the contract's end (format : dd-mm-yyyy)
+ description = Description of the internship missions and activities overview
+ Out:
+ 200 -> LID = : The livret has been modified successfully with the id LIVRET_ID
+ 400 -> ERROR = "One or more parameters are missing !" : Bad request
+ 400 -> ERROR = "The user with id doesn't exists !" : The given USER_ID for etutor is not found
+ 400 -> ERROR = "An etutor must have the 'etutor' role !" : The given USER_ID for etutor doesn't have the "etutor" role (5)
+ 400 -> ERROR = "The contract start can't be after its end !" : The given contract's end date is anterior to it's beginning
+ 405 -> ERROR = "This group doesn't exists !" : Bad LIVRET_ID provided
+
+GET -> Getting specified livret infos
+ In: (Suffixes = /bylid/ | /bytutorship// )
+ Out:
+ 200 -> LIVRET = |null : Dictionary containing livret infos or null
\ No newline at end of file
diff --git a/backend/app/api/LivretAPI.py b/backend/app/api/LivretAPI.py
index 0898901..02f6f9d 100644
--- a/backend/app/api/LivretAPI.py
+++ b/backend/app/api/LivretAPI.py
@@ -35,18 +35,18 @@ class LivretAPI(Resource):
group = getGroup(gid=group_id)
if group is None:
- return {"ERROR": "This group does not exists !"}, 405
+ return {"ERROR": "This group with id " + str(group_id) + "does not exists !"}, 405
tutorship = getTutorship(gid=group_id, student=user["id"])
if tutorship is None:
- return {"ERROR": "This student is not in this group !"}, 405
+ return {"ERROR": "The current student is not registered in the group" + str(group_id) + " !"}, 405
tutorship_id = tutorship["id"]
livret = getLivret(group_id=group_id, student_id=user["id"])
if livret is not None:
- return {"ERROR": "This livret already exists !"}, 405
+ return {"LID": livret["id"]}, 200
user = getUser(uid=etutor_id)
if user is None:
From 335bd04803cb1890c966f69ca22e424b3ea6d75e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20ARNAUDEAU?=
Date: Mon, 8 May 2017 19:51:28 +0200
Subject: [PATCH 6/7] =?UTF-8?q?TG-40=20:=20PeriodAPI=20+=20S=C3=A9curisati?=
=?UTF-8?q?on?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/app/api/GetAllAPI.py | 31 +++++++++
backend/app/api/LivretAPI.py | 19 ++++--
backend/app/api/PeriodAPI.py | 116 +++++++++++++++++++++++++++++++++
backend/app/api/mailsModels.py | 27 +++++++-
backend/app/core.py | 6 ++
backend/app/model.py | 18 +++++
backend/app/urls.py | 4 ++
7 files changed, 215 insertions(+), 6 deletions(-)
create mode 100644 backend/app/api/GetAllAPI.py
create mode 100644 backend/app/api/PeriodAPI.py
diff --git a/backend/app/api/GetAllAPI.py b/backend/app/api/GetAllAPI.py
new file mode 100644
index 0000000..9811d6d
--- /dev/null
+++ b/backend/app/api/GetAllAPI.py
@@ -0,0 +1,31 @@
+from flask import session
+from flask_restful import Resource
+
+from app.api.LoginAPI import login_required
+from app.model import getLivret, PERIOD, getPeriod
+
+
+class GetAllAPI(Resource):
+ """
+ GetAll Api Resource
+ Renvoie toutes les occurences correspondant à un critère
+ """
+
+ @login_required()
+ def get(self, what, value):
+ user = session.get("user")
+ result = []
+
+ if what == "periodsOfLivret": # Toutes les périodes associées à un livret
+ if value > 0:
+ livret = getLivret(lid=value)
+ if livret is None:
+ return {"ERROR": "This livret doesn't exists !"}, 405
+ query = PERIOD.select(PERIOD.c.livret_id == value)
+ res = query.execute()
+ for row in res:
+ result.append(getPeriod(pid=row.id))
+ else:
+ return {'ERROR': 'Unkown parameter :' + str(what)}, 200
+
+ return {'RESULT': result}, 200
diff --git a/backend/app/api/LivretAPI.py b/backend/app/api/LivretAPI.py
index 02f6f9d..4ce7d3a 100644
--- a/backend/app/api/LivretAPI.py
+++ b/backend/app/api/LivretAPI.py
@@ -48,11 +48,15 @@ class LivretAPI(Resource):
if livret is not None:
return {"LID": livret["id"]}, 200
- user = getUser(uid=etutor_id)
- if user is None:
+ # On vérifie que l'utilisateur actuel a le droit de modifier ce livret
+ if user["id"] != livret["tutorship_id"]["student_id"]:
+ return {"ERROR": "UNAUTHORIZED"}, 401
+
+ user2 = getUser(uid=etutor_id)
+ if user2 is None:
return {"ERROR": "The user with id " + str(etutor_id) + " does not exists !"}, 400
else:
- query = USER.select(USER.c.id == user["id"])
+ query = USER.select(USER.c.id == user2["id"])
rows = query.execute()
res = rows.first()
if res.hash is not None and len(res.hash) > 0:
@@ -63,8 +67,8 @@ class LivretAPI(Resource):
mail = mailsModels.getMailContent("ETUTOR_ADDED", {"GROUPE": group["name"],
"URL": getParam('OLA_URL')})
- mails.append((user["email"], mail))
- if str(Roles.tuteur_entreprise) not in user['role'].split('-'):
+ mails.append((user2["email"], mail))
+ if str(Roles.tuteur_entreprise) not in user2['role'].split('-'):
return {"ERROR": "The user with id " + str(etutor_id) +
" doesn't have the 'etutor' role (" + str(Roles.tuteur_entreprise) + ") !"}, 400
@@ -108,6 +112,11 @@ class LivretAPI(Resource):
if livret is None:
return {"ERROR": "This livret does not exists !"}, 405
+ # On vérifie que l'utilisateur actuel a le droit de modifier ce livret
+ user = session.get("user")
+ if user["id"] != livret["tutorship_id"]["student_id"]:
+ return {"ERROR": "UNAUTHORIZED"}, 401
+
user = getUser(uid=etutor_id)
if user is None:
return {"ERROR": "The user with id " + str(etutor_id) + " does not exists !"}, 400
diff --git a/backend/app/api/PeriodAPI.py b/backend/app/api/PeriodAPI.py
new file mode 100644
index 0000000..1cd752d
--- /dev/null
+++ b/backend/app/api/PeriodAPI.py
@@ -0,0 +1,116 @@
+import os
+from datetime import datetime
+
+from flask import session
+from flask_restful import Resource, request
+from sqlalchemy import select, and_
+
+from app.api import mailsModels
+from app.api.LoginAPI import login_required
+from app.model import Roles, getParam, getGroup, getUser, LIVRET, getLivret, TUTORSHIP, PERIOD, getPeriod, \
+ TypesPeriode
+from app.utils import send_mail, checkParams, get_random_string
+
+
+class PeriodAPI(Resource):
+ """
+ Period Api Resource
+ """
+
+ @login_required(roles=[Roles.resp_formation])
+ def post(self):
+ args = request.get_json(cache=False, force=True)
+ if not checkParams(['group_id', 'period_type', 'start', 'end'], args):
+ return {"ERROR": "One or more parameters are missing !"}, 400
+
+ group_id = args['group_id']
+ period_type = args['period_type']
+ start = datetime.strptime(args['start'], "%d-%m-%Y")
+ end = datetime.strptime(args['end'], "%d-%m-%Y")
+
+ # On vérifie que le groupe existe
+ group = getGroup(gid=group_id)
+ if group is None:
+ return {"ERROR": "This group with id " + str(group_id) + "does not exists !"}, 405
+
+ if start > end:
+ return {"ERROR": "The period's start can't be after its end !"}, 400
+
+ # On vérifie que l'utilisateur actuel a le droit de modifier ce groupe
+ user = session.get("user")
+ if user["id"] != group["resp_id"]:
+ return {"ERROR": "UNAUTHORIZED"}, 401
+
+ # On récupère tous les livrets de ce groupe
+ query = select([LIVRET.c.id, TUTORSHIP.c.student_id]).where(
+ and_(TUTORSHIP.c.id == LIVRET.c.tutorship_id, TUTORSHIP.c.group_id == group_id))
+ res = query.execute()
+
+ # Pour chaque livret du groupe on ajoute la période et on prévient l'étudiant
+ for row in res:
+ # On crée un répertoire avec un nom aléatoire
+ res_dir = group["ressources_dir"] + "/" + str(row.student_id) + "/" + get_random_string() + "/"
+ while os.path.exists(res_dir):
+ res_dir = group["ressources_dir"] + "/" + str(row.student_id) + "/" + get_random_string() + "/"
+
+ # Enregistrement des infos en base
+ query = PERIOD.insert().values(livret_id=row.id, type=period_type, start=start, end=end,
+ ressources_dir=res_dir)
+ query.execute()
+ os.mkdir(res_dir)
+
+ # Envoi d'un mail
+ mail = mailsModels.getMailContent("NEW_PERIOD", {"GROUPE": group["name"],
+ "URL": getParam('OLA_URL') + "mon_livret"})
+ send_mail(mail[0], getUser(row.student_id)["email"], mail[1])
+
+ return {"RESULT": "OK"}, 201
+
+ @login_required(roles=[Roles.etudiant, Roles.tuteur_entreprise])
+ def put(self, pid):
+ args = request.get_json(cache=False, force=True)
+ if not checkParams(['text'], args):
+ return {"ERROR": "One or more parameters are missing !"}, 400
+
+ text = args['text']
+ user = session.get("user")
+ mails = []
+
+ # On vérifie que la période existe
+ period = getPeriod(pid)
+ if period is None:
+ return {"ERROR": "This period does not exists !"}, 405
+
+ # On vérifie que l'utilisateur actuel a le droit de modifier ce livret (étudiant ou tuteur)
+ livret = getLivret(lid=period["livret_id"])
+ if user["id"] != livret["etutor_id"]["id"] and user["id"] != livret["tutorship_id"]["student_id"]["id"]:
+ return {"ERROR": "UNAUTHORIZED"}, 401
+
+ # Si c'est le commentaire de l'étudiant, on prévient le tuteur
+ if user["role"] == str(Roles.etudiant):
+ mail = mailsModels.getMailContent("STUD_COMMENT_ADDED", {"ETUDIANT": user["name"],
+ "URL": getParam('OLA_URL')})
+ mails.append((user["email"], mail))
+ query = PERIOD.update().values(student_desc=text).where(PERIOD.c.id == pid)
+ else: # Sinon on vérifie que c'est une période d'entreprise
+ if period["type"] == TypesPeriode.universitaire:
+ return {"ERROR": "A tutor can't modify a university period !"}
+
+ mail = mailsModels.getMailContent("ETUTOR_COMMENT_ADDED", {"TUTEUR": user["name"],
+ "URL": getParam('OLA_URL')})
+ mails.append((user["email"], mail))
+ query = PERIOD.update().values(etutor_desc=text).where(PERIOD.c.id == pid)
+
+ query.execute()
+
+ for m in mails:
+ addr = m[0]
+ mail = m[1]
+ send_mail(mail[0], addr, mail[1])
+
+ return {"PID": pid}, 200
+
+ @login_required()
+ def get(self, pid):
+ if pid > 0:
+ return {'PERIOD': getPeriod(pid=pid)}, 200
diff --git a/backend/app/api/mailsModels.py b/backend/app/api/mailsModels.py
index c64d0dd..4fd4cb5 100644
--- a/backend/app/api/mailsModels.py
+++ b/backend/app/api/mailsModels.py
@@ -42,6 +42,25 @@ _ETUTOR_ADDED = (
"maintenant accéder à votre compte en vous rendant à l'adresse :
"
"#URL