From 0970ecba5250136c2c639d3a74b68c26c8e7b726 Mon Sep 17 00:00:00 2001 From: emile Date: Wed, 29 May 2024 10:59:11 +0300 Subject: [PATCH] New --- osinaweb/db.sqlite3 | Bin 1355776 -> 1355776 bytes .../__pycache__/admin.cpython-310.pyc | Bin 1910 -> 1939 bytes .../__pycache__/models.cpython-310.pyc | Bin 13273 -> 14355 bytes .../__pycache__/views.cpython-310.pyc | Bin 20363 -> 20681 bytes osinaweb/osinacore/admin.py | 1 + .../edit/__pycache__/urls.cpython-310.pyc | Bin 2060 -> 2139 bytes .../edit/__pycache__/views.cpython-310.pyc | Bin 12116 -> 12444 bytes osinaweb/osinacore/edit/urls.py | 1 + osinaweb/osinacore/edit/views.py | 14 + .../migrations/0082_pinnedproject.py | 24 ++ .../0082_pinnedproject.cpython-310.pyc | Bin 0 -> 971 bytes osinaweb/osinacore/models.py | 31 +++ .../details_templates/project-details.html | 56 ++-- osinaweb/osinacore/templates/index.html | 248 ++++++------------ .../templates/listing_pages/projects.html | 2 +- osinaweb/osinacore/views.py | 13 + 16 files changed, 197 insertions(+), 193 deletions(-) create mode 100644 osinaweb/osinacore/migrations/0082_pinnedproject.py create mode 100644 osinaweb/osinacore/migrations/__pycache__/0082_pinnedproject.cpython-310.pyc diff --git a/osinaweb/db.sqlite3 b/osinaweb/db.sqlite3 index 37ca83ac6fdbf19023734bc2709de74a5c6c2bb8..9e91a1175d139f5004045589ca3fa44e06578384 100644 GIT binary patch delta 2589 zcmah~eNa@_6@T}>`@Y}ZU0CFEm1R*0>c+Rbd@YE{E=Hn^2#Av^ZI@;DVL-xCz!Yp} zbor1>KAIX5Z!#vSV){oYAGSN=i_`vrBx#Hj9qU9VsZ9qvjW}(rI-~7GOX*v8tDw@n zH)rm9=iJ}9=bn4c@9v$d**jJ9^Yp}Z0g3_@)V&AJ>|f=C>jJ;7e=if{4KmhdFd1pH zR*6;yWP}l20zw^4t^Po$UG=p!wYI9kw)Rl78tCkbOs%j0P(3)a@(egR_}MB2SRym4 zEe4ifH=l*7wznU+pV2czy) zY0v5&3qt`%iTC*?^~dwGTjp=IMzz-1n$~#IT|F5(BL4|*P;F5=A2^XHCZ>M~l^#RI zlNjH}=GZ|-VKKu4Fndp$4qNT^`h&rTqtlfS%-5Pmq=OOgeZths$DwgTo2Zw2BoHQj zH$gySZ-I2$nn`=0Q*q|ml>)oNIp_SG&OF6I{dr(2Bx_S4ywoJVK}(eJn(>dukM)9( zK{853kiJ5nqd%bEqhF@m>8*4Ty;xJi_$ts|9mYq2cDfJeW$ZEJQu{y=Wk@mr{15yE zp2TDLAnwN@T!){;HjLye@@Mj>{4@DS@-}&`oGpve4e7jeT>6EyPimGbr93H3yd!=k zo)CW}z9x2y4PvEOC|X5HxGh{3&IuF3QQ;loMWI{p3+siILLxuIf6brfHU2RF!X7@v ze~(|!J9rB(a96oA+&K3d*TvOwYq@MrVz0C3+2654Y!9olUUnG^nQ7+t%rNs3)52_K z3Kk;}L`X_V)T}m&7v+xT17>>c$;cnOfH$Xc~ z0RIA)K+Q=o4&DSWfL)*gRD&YpUyUb?WANcq1ZgG&GNI>g^))t8R4M|iA32Xy9>&QA zPrT?Fn_5(mLbi_J9Zn#GGL~i`eWKO4U zr66FxtBAXfqp{{YjO~EDKdK{N9@2fB8pYXcl(1kC8UFw;g48s*I!AZt2u=oIfI~V9_iHV~I1Fmi5OBapZ~)Lb6Xe53_BzOj+2(h2tf4{rv7;C%bR&CR`4XR!DHaCA`zFi$^yRRwea}>HPnnX5;X`xwlRcHa0WPJa1ok;P{S7VZ z0-hF7gXQGJ0XkKh6C=sGCKi&+S6~BqKUIE4>-)(3OBzx~$h&VRW|PX3=AYJv3wncG zN%TI`H5>o{ delta 2080 zcmZuyeQ*>-7Vqxq`JSHH>~1yzlDOFrlR&T;93i-0RRjD=!fCLC8(zD&y8buz_KXo-VV>l zBJO(0odW~iU54JC+J~8v*>R{dpm&CR&Ed9?6pJs)fUrJ#WAQuiT=cENQkWjQQTRTB z)zSA#N||ag66H%9V!_g{glK(ZRxDC}z$JWQSq0PDCo#4DJq>;seS34}Um9z9+cLMe zyrRrov1DoSlG3}DdSlyKjw3mKuG*rzOZ z5Apm6eh$FZGuf~O#F#lvOFeY=5*~v69wM+@)ME^#g zsy1|%Tt!F8n`j?-8AZ?rv;?KX8}Kqb2am%;a0qrnAGuSzOl0k}@|AY~VdVp@Prao1 z)Yr8N^_Z5bM%90*PpD1mYPFO+Lk#jDxm!7{yrev>JgT%RTaF#09@F zM_(jEym`H!d;nc`40BNR?9C=h1*U~NT4?tO>7SR5VF{|7vwfH0H@dr^jVfbg!Gfgq z$~kU^j9CSh_KlHr`rQcG!MZWL2hpl=c|H#X4~8{}J~=LDsE|(z%WtixQ!fw~&)tDx zmF0Ec5#pfn7YGMg+B8Z6VHbvrQPmtztb+z2NIF-jy6~h8l zgfM93{E5>WI}neuQ|WEDTrN3I+Z8ip{}+?-S>uwlR`Q zpa0UvA@Ci|8zb3bCWhsx(lU_LL*Uz!CkQTOLfmzekCXk-Jn$*m#tzpDi3h^`;R_`FP5zSoPng zv03nW%JgUZmt+^_qT-H-n)t;!REQ+JdOn= zC4xT^DGG*~x?9}&-hyI(WXG?FY?cKD1>$Y~=UNG=0JFgBouiWPEzA1VZe>ZPfnh-) zAky)D&V_WU*U8@=t;G>Pp5jPH%P-{|$b!X-#ZZT?xBH9Q^cFp# z^$YQ2qaC}Mm23v(ciEq^BDNPZckZsIDSPaxQAt;a?j5w7_YOMFR4kH_0{F+&L82?q za+Ix*XYhcyTTVxc^se+S=t+KwD(s0?H?E~U6OPMtYSOU)HHWF~GijL;dNkZ+SjAKC zH(KcitB`2z1tQU!ht#YTz1ib#()BiX-Tj;0bz9c0qw*QY3s%M zojT)?sAtCJNRG^RCLN2Q*?-n?ltJ(z`rILV4y`-yc!CcYzHrb}Ko1_W>$bkgK#)%> zFGu}7hQFyTL{CgOT!}8tUR$$qW%cHj1Ga(2ge5eXNwcro(*KX0r4M8%sFG2J#T)@} zAF6*Rro2P?9p1~v7(c4CLYINeN{{pGdTI74LI9Xj#QC+xCL@1xmlM0wlZp6}cDI(V zwQ9rKliF1+Q@f~bO{62#DkNqeYz-%}P)fCa)LS}?u+bI@7I}+Gy@~4+)0yAEI^EEH bYrC7nzUoeYQ#erkSU4ikt-a2%TbBL{Kg)sa diff --git a/osinaweb/osinacore/__pycache__/admin.cpython-310.pyc b/osinaweb/osinacore/__pycache__/admin.cpython-310.pyc index 91305e5cc1ffe0dc697d904363215b84016922d1..4843b16272b885b34663dc7bb213330fb62a1dc9 100644 GIT binary patch delta 100 zcmeyyH<_O|pO=@50SH8Hho$Y9$SccOv{74}QD7k>BSR`<7S{sqRH;geU?6LU;@TOiVQR#~AU4BqpA7w`+@RGvA!K=ezfw z`<-)7uP7>)O-WD0FO@C5Q zXY@ZNK2=ICuwHL}wN|QmHVBb&&8zv~9n$<-0N&x31-lTb0Cuo{sc#SIY8P>bfgjp- zc;>)kcmPbHlXQw1k`Xl0Bkr>G3NTY_Rz>;{cr8bYCOh?ZQ?*+~EwMyG*IIG|bT+!> zj#%8(sU_>HV}@z;i4@o5Q>hm%uh0ePLvBILXiM=WcEhKEk$A|O;(_(*{`1}!uL3Ly z9v*K742@(V+D?HMW+3uiVy}>Jpw(%EQM)GgkgP3ZYZ9LEX6+gKE~&RmSYpdcSvl*- zh#5(cJJ>SVb{}{%QU-15T^k4^H&X&Z zsKgo;HH_GD(4);v-f_DG;m!ZH8`IwrD&~*Ta0vX_(QD4iFuL)ve)X(u~I2IM0l&)Kz6rU#n!m3FEK` z-@=lRYFKuBS#C~X+s9OPMf?wv`Lg*e<&#uAg!e*{uF$m)AuJ;RU?){X5nZGV&`A^` z+C(A}`JXkxdhy=h1CK{XzDy{&)s8TMvP}K^^8jz=M?ah?w6& zuPQaGgm%L^mOLk(G;|F<7s4mhE{@Wd(RR=t0cy~)w}K?RXmdh4^wsV0w5D59dorCc z=^HrXC4_;x%`4(grt}2Y%4p-%FM(vp05V8XA+8DJkNZ%2Zjcur1-|j^6qN!+bQd!c%#`i{YM*Eo%t@|H z#dTBH=tpcz&`0*Ny}>4lAD!I|HU{yQ9mln?!zhqGx9lQLLU*&7Wu8K80yEJ&o~@l& zQDxT^-3BT{4~P_KB9yv~t^+qs12n6Jthdt3MmKn5jF@(_?(%>a{b%6eVkm-}cnDnw zi=QJ`nX7z?{3%j*vd7D-+&mv){O(2gfYpb?QXiNX+0Jr5>4RBecB$ML@iDrK08|mq zXrB+-(*y7con3H1!(aQ26rE^ z9|mv0W0U}(^dOL30r8#ukM8F&Z3CTis|M3;Q0+#at^Fi!qW&+ z_wzMsD_hAItgCVb;kpG61MN@b=MsZSSBQ_$!<;>}Y6-BnRV^K09|7jyL)jP~u#W)S z!={bc@5Cd+mDg9BbRP>fgiA2DSl96+%?ZHwm5;)(K-jEm4>`&wA1f?iM)j@fbO$)@ z+ymg!x6%}tPynC9t53XFxELBiEU~<5eu933q=N``2#5N6M%EH?l698`$PRXKR5dxp z?v9F!WrQsoeIP_%LDs7Psx4BGO2!f{Qt z&O_LOcTz?%6vBQUTLUM;x>Rcxl4Go^#y{#DvQ7Y~q9wOPp^Izu2OPsDIiLvZ4td%6 znmGB6%}|46Gh3vN^WrHZO0?aKt%{j14n68=@HDag>Ju`r+~bVY2HY3|@0%Vy_xqwre z08}aWFNP1ihNG_|Yyx1r$4@3p*tPNc6pSSo;P+_pT>OaEB>=0aDNUnhESZ=a)8krh z11|7o6gYelI4yV(7Z{3A!rL6SCbt8k#;QI!Aq$Gns(Y3k=QlmhzN(v)7wE6Lk?w1_ z7gvd*#ju}*uYlPxxNhzq`{1sCL|6E_t0rd26?S*x6hGel6mk_Xuy;AJd)?ry#gjDo z7%qF2otP9N*V!NSK6bz*skscHCxlReU?K2U!|RGC?HcAQcoRIUaf|#l$AHQRy$PFy zS*rf&&~0EqB{}AIbi`u`o&JPt)d959L+sc3$po)+edR3}Sv$B8_9-4MjyJ0{EZ%Tp z9ya@2!^W;k@y1Z>OB9<8#U4WO`sXy`*~2VQl#HSl6r-iLAaFn1*f^ZbX4@KTq=u5B K5}BQ74EzgXy_Zh_ delta 1719 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 QNhQl!8Yfd(V(Iw*0&_7>3jhEB delta 4097 zcmb7HdvKK172o^q?zhkEZj#Mz60;$R39t!yK!lJG6ChDQ1H{09GUztVF1jHv?k+mg zZ_8j%!Ah&1wmz!~6oj_6Ky0nHwID@{c6{_7?COY*I<>8pAj7nSwe9)cO^A=unP%qu z?YZZk$9YRxJF&E^4$nW=+$CCiG9;Rm};uPiOw+f;WU;dm`kpDK|JAfR(cL9|bpbFFj z4DW+@kRHqL6StGQV7+*l;sr}fUt@M6z+l&WX7(cjW}n$__LwbZ%fH{UcvTR78-M1`jil3bgX>m zaJD7VH7W9k-d5j0^d~9gLhDbCv)Gd?!oKf;G5IjZOrkA)Ae07Oyd2H95 z^vd)Qy*Ry5oK|sDGNWhuc1Wr-QkSAm`b%LnuEJ=XMW28*gi&BJe#gld$fxlck6f+} zz}4Oz@4K}tHZ&+da|)TrR33J~p^9`%CPtOZv&czrRusw+sk9T%(D=-tIEOIx>}9R6 zWra*Z`wglOH(VrU-%v|^gT-F@Ld=?3FB9=EhdVE#{SQ?dmREXQCs|wm9p27QXl<`t za}ljil$N8)m;3JI@o=hJEdO%r^3w_JtEyJ%nFOHn$}s(|%Bznn7t~!@##v~Y)iyc* zcIC`$DR}Zc1P)*gLeQab5sU4ab+L_WbY@n*S7Q~OPgi~)Y8oA?E27J)zpf*Js_K17Q$kkYiKaePiF+LCf~|E>^5!dj}L6d!)i;!dIkrg3HeRz ziG;NJ1WBrM=CE9&!LY80^ss!;GOyTUz4Q6&rE9Tah z!jYT?DTt<>Nv>^ukz~9-CQHFBquq16M2ybOom(=C89lHw`G@z@#$OwMiG_l4YA)TX z_nLbxh8ER!i4kkmJStL_r0q*QYtlZ&OX-H*>qt7ImSGXK?&4O18x3nzXI(otBU-O} zBx}^fEr^3@k6aBj95@R8cZqorXIr`brhOX9{dJO zQ76-0rkw$vH9Uqhl52Pw{cOP*>B-x)#?Vwd`P=5fV0es#jxfL*V=Q=-^Z#ER>{+QV+JNU_oCFI|DNdEcZtAf%3 zg{J^Mz|>=)(tA62PXpcq{1JecEN$tFCz29oGcWs(=-&DMt-rwdmw;aZo(23GpyDYf z6HhgWl!M^bf~o_|2K*Jg4*^)8GM?7^W9kVW2In^bm3PmBdI9iTKnzf6q7SEK(Y!{l zYX@>@F*Ds7bu~8I^z&|qoF{11mrKR%b~@a+RNPIUG|uxr&5~y=ENL-wJJyJF4Na!& zz0BsKVu=mKd(??@NnAi%nwFHPvr&7>RD`q*GPs=u*hn+I(^M8bfkk|wB3NY$yYN%Z zf*ae^5uoppUjv{dumf<@&Oz>jRCXt}1Sjsk8oX-NC)eDR?C;~2_$hjAL1?NxO?Hn{ z2i&U4Q(1G68I?P&HPIiq8#rJlPkMwe)=Rti^Mf&E;YSmZjv> zMSZ^OO}jS4l07#?u<^tP*s9LrZY>~uLblOmmw)0r!;CHVie*g|%S$STz^Us=txXGxV_|ZPXQ(@0S%r+yC!vj2apZO1%v>_06d~xxELA%En+s~LXd5M4nP-R6<{@BEnq$1 a20$fkE6AnOE7yukXh~;8)Y0ReW&Z)6hfEr{|=`7i8w?-x5M_ z;x|V#ZDwYap3Kjd%UZ++v}SS*+s4U8>=M#NJV4$p?$V;1g2a-N)S|rNl?+7!K(Qi$ V$qDQgj7F1hva3!0%g)F63;@GjH>&^u delta 155 zcmcaD&?BIo&&$ij00a?x0@G?Z7#JRdILJT}$Z-JTVz-Ujj*MLCqEV75`oRpE29sMD z-)>&bw3?YwYH~PR?&Onf8;#k33X9l51kfmkB2EwiGQNl#NZjHsEy^iKEGbDX$}3*U eP{a?C;Gevfy@JaC$mC(*VdP_-Y{;R>_#6Nq%^!3C diff --git a/osinaweb/osinacore/edit/__pycache__/views.cpython-310.pyc b/osinaweb/osinacore/edit/__pycache__/views.cpython-310.pyc index 63154f646298feab7b6daa2c705844ee5a8d4e96..87487f1bab853abe6e0c025e9311ca967fb00efc 100644 GIT binary patch delta 2192 zcmb`HUrbwd6vumROMyaxm6md$g<>J>Vu0XGNN^c08T&&N84za{84y}n0Rey9NkCZ1 zAi6j~wzILQ8-eL`>fB@%|FF&fQ#YAUK4D^fa#0_Q`s9)&{=T=m&Sp~{?8B$${(k3o ze&>76x%Zo0$J)~R>~@<;{#L$yxZ}#UgJ~XWUAViE96@`aB5==yX`FWY1M3=1+P#qp zD#_qlk3GCo`s*g0Mkqj&%BZ3%UFI&!h^Z@KLVBO-=PJ4K5*!-DQT2MNlJzy_VGmaob)PEw>tL9O)11^ z$0O1fV;okC<>s&6OkPsm)~B$z*NFI&>YyEbLse-%yK}te38^GQbxP+4a_asOX>)v} zYdNa*nOGz>*GZjRmaEbMWUYu%?#Mkslg2e3PiD%HOk9lPz*MBlQ$+MMw|d<){kQjw zca#pn+m;jzg!C4@t#gJe@?3N{vL$aF(NTUfeOmMeW_ zMyW-JyM6g7u@)ZXBR-u@v8|wj79#5l6bc_f8Z*H2zze{Oz%k%BFbDJjyCpQ|UzcIw zCBPV~mtma*e84L}Y}#MN<1BCr*af@>R2whS>oAQWyE%kfa&-RQz}77a@OT<{6F9@w zrP=KC`>dBSE`^+4P-ICni*vjs&&y-}OSMpSJ=s_4t8d#g5DeTRYaRhkNNDP+6!CL~ zwc*=oh?8I>n}pzao#oe{0QQ}9tk`?n2K1J;c0Ke&NFNes;A~X%EUdQx|4neZKY^Qz z9CVHQi;C$yuP^ZOV$s=f1TIDg--Z=yUaW7~t5S*6vA!+h@g3k@;631dAg&IZjAq6a zV)eaTLda+@tBXAfDcoFq7hQ;q6%Uaes#Z)w_E(N4TeYg@n7UXGbN(-Nd|Xo-f|Gmv(iIYp}GUB^yd=iFBT;%5IlKbdtWVxi3!WSXcXyym7qRL@?2z&&5415B7 z3Va4!0zL=60Af{&&A_TAJskJ)-f;-N#5JoZRcsLK|5YVKbX^9o0AB&i0H&jo?&rbM z%EYhbLY-E~i>1rkJFz(k3;`p+K43p^0GI-%fy2N8a1J;RTmY^D2rK+XOTI5lqYnP1 Ltc>iOQ(pBaDG2BA delta 1908 zcmb`{U2Kz87zgk^?dZC7E&FKKwQIMwjL~<4rh~*KLNG?qv5N*$E(Qi>w-%@jTu!^e zn5-cZkRUjH1R@lf<4XrR;RSSne8dE9RBqsc#VcdDAtWSlWxVkG-?|kW#9q*(zn%BI z=j%Do(`BM}*IM7RSW0#B({XjhI$PT(RyVCY*Bl{ZtR9JBUaoi{rhC?#@I^#Q3q@R)ocQ z#9?PobtygMK=o4U<;~T76y-mv7aOt8HidmPHeTfLP!F$m1dZC33EuBmOm6-~b_;&! z_-JMe>2yh)smM@f5PdvW;pWkr2eg$dLRFk`mOB>85l_nGh%!T|-byAi>C5$EkbiQH z$Wbv@Tjdt{QU)?Z{t+EufUmjc$d?aXO~y1jwrHyZKu6*hOHzXOQbqe(e)p4Z@r!N zsk`bI5DoKX@9UJ{zq|oUQm&-fvzO4rExsjmi2Hp(Eg7PV$9(nXYznaBFyHm1=rAwy zx6qh6=+{$vKl(ogp8^J-fdk+m_#A8iQHf&vXEStUfL3@%(fR^-!7<M6BaMV;^r5}Flp(DCR3f! z?o^^bks1)EF;TnCuh9A$%$kPlLo+zjSV{MJym1a);6cBKpEi!C&tiy{y>HOUB`%k< znu4Ol>|D;i#p5{m4x9t$LEb$q(Gr<=5ryYb#gf@P4h7u$C&Zb6pDwD`0|R71RFgU( zb1O@emo~k+CKp{Uhpv|u9skzkjO2y)yy)`MJoCkA7Am(jhs*P`tNllqXtq-c-)UY* zw^Z}ocPM=cp=!ze9<6NTX#D^tz-4d+Tm?UZYv4M#0dlvLtAT))3Bp3ndQ diff --git a/osinaweb/osinacore/edit/urls.py b/osinaweb/osinacore/edit/urls.py index aa4de05a..a622f9cf 100644 --- a/osinaweb/osinacore/edit/urls.py +++ b/osinaweb/osinacore/edit/urls.py @@ -9,6 +9,7 @@ urlpatterns = [ path('business//', views.edit_business, name='editbusiness'), path('staff//', views.edit_staff, name='editstaff'), path('project//', views.edit_project, name='editproject'), + path('project//toggle_pin/', views.toggle_pin_project, name='toggle_pin_project'), path('projectstatus//', views.edit_project_status_modal, name='editprojectstatusmodal'), path('task//', views.edit_task, name='edittask'), path('task-status//', views.edit_task_status_modal, name='edittaskstatusmodal'), diff --git a/osinaweb/osinacore/edit/views.py b/osinaweb/osinacore/edit/views.py index b36b7c4d..47fee5f8 100644 --- a/osinaweb/osinacore/edit/views.py +++ b/osinaweb/osinacore/edit/views.py @@ -232,6 +232,20 @@ def edit_project_status_modal(request, project_id): +@staff_login_required +def toggle_pin_project(request, project_id): + project = get_object_or_404(Project, id=project_id) + if PinnedProject.objects.filter(user=request.user, project=project): + PinnedProject.objects.filter(user=request.user, project=project).delete() + else: + PinnedProject.objects.create(user=request.user, project=project) + + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + + + + + @staff_login_required def edit_task(request, task_id): task = get_object_or_404(Task, task_id=task_id) diff --git a/osinaweb/osinacore/migrations/0082_pinnedproject.py b/osinaweb/osinacore/migrations/0082_pinnedproject.py new file mode 100644 index 00000000..4a51c897 --- /dev/null +++ b/osinaweb/osinacore/migrations/0082_pinnedproject.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.5 on 2024-05-29 06:37 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('osinacore', '0081_status_task'), + ] + + operations = [ + migrations.CreateModel( + name='PinnedProject', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osinacore.project')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/osinaweb/osinacore/migrations/__pycache__/0082_pinnedproject.cpython-310.pyc b/osinaweb/osinacore/migrations/__pycache__/0082_pinnedproject.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66b640a108e19e4d323b21970e24f61966073761 GIT binary patch literal 971 zcmY*XOK;Oa5caMe$99}PqzV-zBm}2i;=&1`3N>w7K=dWja`0v4WGB|Te&KZ}=@qX1 z4{+qi@CWwFiNAnEVQi-lR@&9fx3e?fe6v}%>u9*Pf4rY=>YDbma_%kzoh{t*1s+`E zB-Rq*6H?hUrit$BiQyZyug5Lle5G-Nx4vk+1$xx}tov=QkF=io3*T!!qAUqzDbi5( zsB#h!7C|YpR4OycIK=XBQpMd}Hac6lWq}81KH-{ALH}w%D>AO@SX5Sp<_(QNd646n!)78OjZ2WyU521SN3Q z$qSJL#hjhNT-g!|5yavGl=~5iaVCMKK?16sH;FD*Z;JL8P|YM|C>fNXXqhQvhG`Hs z>Zj&ZK+NS~Z&g{W&c>K>7(mk$d_-nqM6R literal 0 HcmV?d00001 diff --git a/osinaweb/osinacore/models.py b/osinaweb/osinacore/models.py index 571b2c94..76e3d041 100644 --- a/osinaweb/osinacore/models.py +++ b/osinaweb/osinacore/models.py @@ -160,6 +160,31 @@ class Project(models.Model): new_id = str(int(max_id[-4:]) + 1).zfill(4) if max_id else '0001' # If no existing records, start with '0001' self.project_id = 'P' + current_year + new_id # Add 'p' prefix super(Project, self).save(*args, **kwargs) + def is_pinned(self, user): + return PinnedProject.objects.filter(user=user, project=self).exists() + def total_time_worked(self, user): + total_time_seconds = 0 + tasks = self.task_set.all() if user.is_superuser else self.task_set.filter(assigned_to=user.staffprofile) + + for task in tasks: + total_time_hours, total_time_minutes, total_time_seconds_task = task.total_task_time() + total_time_seconds += (total_time_hours * 3600) + (total_time_minutes * 60) + total_time_seconds_task + + total_time_hours = total_time_seconds // 3600 + total_time_minutes = (total_time_seconds % 3600) // 60 + total_time_seconds = total_time_seconds % 60 + + return { + 'hours': total_time_hours, + 'minutes': total_time_minutes, + 'seconds': total_time_seconds + } + def open_tasks_count(self, user): + if user.is_superuser: + return Task.objects.filter(project=self).exclude(status='Closed').count() + else: + return Task.objects.filter(project=self, assigned_to=user.staffprofile).exclude(status='Closed').count() + class ProjectStatus(models.Model): @@ -175,6 +200,12 @@ class ProjectStatus(models.Model): +class PinnedProject(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + project = models.ForeignKey(Project, on_delete=models.CASCADE) + + + class Milestone(models.Model): title = models.CharField(max_length=150) description = models.TextField() diff --git a/osinaweb/osinacore/templates/details_templates/project-details.html b/osinaweb/osinacore/templates/details_templates/project-details.html index d7b3a3d1..a6a28636 100644 --- a/osinaweb/osinacore/templates/details_templates/project-details.html +++ b/osinaweb/osinacore/templates/details_templates/project-details.html @@ -21,32 +21,36 @@ {% endfor %} -
- - - - -
- - + + {% if not is_pinned %} +
+ + + + +
+ {% else %} +
+ + + + + + +
+ {% endif %} +
diff --git a/osinaweb/osinacore/templates/index.html b/osinaweb/osinacore/templates/index.html index 67ee885e..ff26f97f 100644 --- a/osinaweb/osinacore/templates/index.html +++ b/osinaweb/osinacore/templates/index.html @@ -5,191 +5,107 @@
-
-
-
-
-

hallo

- -
-

20-2-24

-

20-2-24

-
+ {% if pinned_projects_with_time %} +
-
- - - - - - -
-
+ {% for pinned in pinned_projects_with_time %} + +
+
+
+

{{pinned.project.name}}

+ +
+

{{ pinned.project.start_date|date:'d-m-Y' }}

+

{{ pinned.project.end_date|date:'d-m-Y' }}

+
- -
-
-
-
+
+ + + + + + +
-
-
+ {% endif %} diff --git a/osinaweb/osinacore/templates/listing_pages/projects.html b/osinaweb/osinacore/templates/listing_pages/projects.html index 4fd4aba5..a0039e76 100644 --- a/osinaweb/osinacore/templates/listing_pages/projects.html +++ b/osinaweb/osinacore/templates/listing_pages/projects.html @@ -153,7 +153,7 @@

{{project.open_user_tasks_count}} Open {% if project.open_user_tasks_count == 1 %} Ticket {% else %} Tickets {% endif %}

+ class="font-poppinsBold">{{project.ticket_set.all.count}} Open {% if project.ticket_set.all.count == 1 %} Ticket {% else %} Tickets {% endif %}

diff --git a/osinaweb/osinacore/views.py b/osinaweb/osinacore/views.py index 6e7d5c66..a5ccbdfe 100644 --- a/osinaweb/osinacore/views.py +++ b/osinaweb/osinacore/views.py @@ -181,10 +181,21 @@ def home(request, *args, **kwargs): else: # Non-superadmin user can only see their assigned tasks tasks = Task.objects.filter(Q(assigned_to=request.user.staffprofile) & (Q(status='Open') | Q(status='Working On'))).order_by('-status_date', '-id') + + + pinned_projects = PinnedProject.objects.filter(user=request.user).order_by('-id')[:3] + pinned_projects_with_time = [] + for pinned_project in pinned_projects: + project = pinned_project.project + total_time_worked = project.total_time_worked(request.user) + open_tasks = project.open_tasks_count(request.user) + pinned_projects_with_time.append({'project': project, 'total_time_worked': total_time_worked, 'open_tasks': open_tasks}) + context = { 'notes': notes, 'recent_note': recent_note, 'tasks': tasks, + 'pinned_projects_with_time': pinned_projects_with_time, } return render(request, 'index.html', context) @@ -648,6 +659,7 @@ def timeline_modal(request, task_id): @staff_login_required def projectdetails(request, project_id): project = get_object_or_404(Project, project_id=project_id) + is_pinned = project.is_pinned(request.user) epics = Epic.objects.filter(project=project).order_by('-id') project_notes = Note.objects.filter(project=project).order_by('-id') @@ -687,6 +699,7 @@ def projectdetails(request, project_id): 'members': members, 'statuses' : statuses, 'all_tickets_ordered': all_tickets_ordered, + 'is_pinned': is_pinned, } return render(request, 'details_templates/project-details.html', context)