From 2c9b302a69c67f6302307305c40200bcc9760fef Mon Sep 17 00:00:00 2001 From: Kobe Date: Sat, 31 May 2025 19:07:29 +0200 Subject: [PATCH] added events to event system --- routes/__pycache__/auth.cpython-313.pyc | Bin 8580 -> 9272 bytes routes/__pycache__/contacts.cpython-313.pyc | Bin 19496 -> 21152 bytes .../__pycache__/conversations.cpython-313.pyc | Bin 25226 -> 27181 bytes routes/__pycache__/main.cpython-313.pyc | Bin 58918 -> 59337 bytes .../__pycache__/room_members.cpython-313.pyc | Bin 8397 -> 9431 bytes routes/auth.py | 24 +- routes/contacts.py | 49 +++- routes/conversations.py | 51 ++++- routes/main.py | 18 +- routes/room_members.py | 35 ++- static/js/notifications.js | 211 ++++++++++-------- templates/notifications/notifications.html | 33 ++- 12 files changed, 309 insertions(+), 112 deletions(-) diff --git a/routes/__pycache__/auth.cpython-313.pyc b/routes/__pycache__/auth.cpython-313.pyc index c44381b80c67fc96fcc86d23225eead8584be5fa..608081d7c9e274d0ec635203b80e99af38eb7646 100644 GIT binary patch delta 1845 zcmZvc-%lJ>6vyZ8>`#_o`+HefW_I~erqHFd{E(kQK`>T`WvaE3upM>>*mT*UcVkt|$NSQ4}X3YXZgc~iIs*69|q zSLq8`ry=yjm}w*BuDbF#*LCn>x`XTnA`!VNVU??Ud6AnrUkZ^uG*>g^B7aneZC*O- zycG#r>GL#+d3+9^?59xyvhHjkvz~g?Lq6~fp6@-34|buV-N;FyDcnLQxCy`xHVPIy zT^o7siK9+Z?G2z&((DyB4i^-vlvGMHb4IdwMd`JXD{3~SEvcfRiDO#Ie8bG@YD~PU znOHnnD=sR!IH#&P@gPXl%~VR&^?5U!T}?>Vf@6u!lm!*DO~BU*E+a#ohO)GLm)|Iq zF)1XC)nyg;z(%1e1-GfI_+Tfv8$8YxbuKxt;U&phT=xy|MWI|*jpVYT>nj>g<8ts1 zgP&K@X*>c`FW>^;@SwOFme@@rmD5%Vu8gk1_7wwrVA&YJ*$F%@!lS!-1)`lfbtMV4 z&|x1U4B8lzz7F(Ve#0lAL2;+HZ6_>lySLm=g}EKE<+0fDQ0&-=Hf_&t%|3}qUkZ1G zN3nB{V*?Lk1CL@udoEjz_l3h%QTcb6eC9W4Z+Qa~Xda3z@h3|QRmGrSsl2#tR?DMv zvQw~2I4nxB9xezxEcaaw$G}lf9t2y^I(ZgcrpN#GW^p&r2sUI7xfiZ)lf5&ICD(Lw$vS!-Yc&a4%_;j57TMp+lW!xsEg%OIRw70w z`H&nY%Ml?_Q)-&hvyq#D{|6g#KPuDZH2lt(df5-? zEOp}!vRc<@XLlPWU(|K0h3b-clBq={x1gri+E^cz+{YTJ`2IvAS@1= zsI{9VSH$7y2(k@;(+?O%dsc8TxlTzz^0jD6?8I@Jg{8yqfK`+;wF=IGB`s}c)ggR? XT#PmQe&No(usTrvzIT{M#YF!C@d}!g delta 1282 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 diff --git a/routes/__pycache__/conversations.cpython-313.pyc b/routes/__pycache__/conversations.cpython-313.pyc index 5f57099a760ce2d1d78982b43fb1e483d3b70f6c..2950c626622fb324af0aec8626c58f691be21c89 100644 GIT binary patch delta 5668 zcmb7I3s4)^72VZJ0-+xuK0*j20WwI&!r&MijO~!rcEBG#Yh2rc2!R$`Hj?m@uoE|l zl1%G)J^=*lAtI{lzJ5^rF^s^g~01 ztC17U`*~6&=96l%z{Zgpu@KPRU)j4Ah3FdItEtUWxAXOyx-4}O<~&(SPQFEdBzNHaUW74ZYJ+2AQZytB;b?-Gk=co7-%7P0skCN?uH+ahTKhGEGy+t(09rzwMT$; z*g@CmZ93oHL}b(>kmGc%&1uKgYxRvzbrgGG66^%ZPXlhYAIsb}` zglNtx?PChv^o42*JyBC882SYIRCPH$z0RT)^L;sD0o_(JtSMZf5-s$@ItP8erqEin zjeHYyDaQU5jwTRJ&<|@4CM{PvUpRU&oRALJ?~08(_XZD2&LK&PIu&lnnTR>}#llhN z;#ZtiGGE2~)uWMfB2qja+#@M|atcEd+)5h*eRlfh8Platm@A962s%VuCnp}=??W-)N({6!2Y5)6-$ zBXr*FwSOLzddi6jew5f;E*y`I#7HEVAQ*qLhHdDoNW!y|lK}2TE{d{waE|n`$rbzrbvMqq zo2T5(bFO7GuI4FMbIQ5u{DB|aXIi?ZTDnrJyHk}ta~1B1z=MJ53g1k{>Zyv=(-p0+ z>$SzEH*|Vk-dlD~S2$a`{8CyWJyF|KI=jSsHgY<0DsaC2eCUbjL}Upy*BEHadW+V? ztq}Zm^pw?ZfFMh&?p;O?6xd2cJw%#;MOs68h7*mTVt?j!>Z{42m%a5u9z@xtbw!Lm zmJh3%AkxgVXX$1kA0iIo%w5>WiRu>BN~~b;)NmflN28AZdFifX`Bh%6L`Q%~k=Q{g zbl7us;HBBl5fY1B6Ln+~mPyAQ`96-ZSddcya$fp9h&l2@V5I~D zHpWX_yz$wb4+hD)x_ zr`u*W_fKu^PjwEY25wF{0<*O%&L&SMXFV%tJgrln);SE6)+u*us%FiF#vk|3tQDu$ zimA5ksj9v?m*=eG5y!NvX~xwyhR&`w;F! zUPVZ~OLYUhEg<0tQ3{d~?q*6`4oE^f0z(x{X+ zD=UW{?cxAZW)%xAjFrCd)41j%2uJ8ou5UE5vSMFkt}TkWP=X!mNcxr+bz$Gf*}PyP5ggtdfgU`Lw~HMav}E*Rdzt1Hpt~mL z+fVV}j(6Tzr{-^?=Qb@b#e(vl**)ZRhw7c~T~7B+t?sSlE_!8C2fJrk9Sg&Im!JT zcnw*wOt#NkXi&+c_zG)K--VH!3tl&Z{RR00PGpNJ$+{G{cyt`*F`96jN-VvDBQ1bO zmv%8^TrNjs_sAMuW@1ek+LK$z%XDXl(;5H)*?{eKy61_L4}f*Y9?eqFOGs3-FGNXmxMa8oVi)W>1@#Ts|SUk7>iR1Jfw5vTCaj}>VilsE( zy@PG2n!eV3eT6ZuYT)83uz?k9VDyU_={_T#s=z`|tt>JcyZ8o9ECJo6EvjSKLiaS& zsa}h^Pu;tNeJt<7?_j+(Q)m5tdY9Ki!HzVwF_&)Xb+I*<@%?nnWwQriF+biEd&Dw7 zUNn1p`%%#*TZ^how@9K~w2Q#=2QzYgn#@ubZii`yJ}#t>(Zq4%V8*e(_37aNL9a#7 z_YPriqF-3A0u8axBv!TvqQfV2tF~UJ7%MJB^-+`P^yNg&evEkbh^{`fSmn!JRt*@; z34c-Jh%#btjc}goZAvfyD!fKsLqPu|!}O2h$|OdE;{JETNY=1#XsD}iBA;dNmvDrB zFBe^v64Q=+xMG`h$eAXf_y3QL$IBtmaai#Ae4gBF3*t!kAX+6W$mX=7z!;GZhNVOF z!1n5Wi@Fk1W?uRH22E_ExOdjfupC4FfuxoP$N_*3Kb!2>_d}c3_~pF4dd`hMhb9<)fSVpQc91Z zbTId1lx-h+J0vCJu(7uhc{P9&Bb$v<%(ea4f&kR}%{ zH&Ycjydvg|m|s==zkE5();6C{ zTo6*VZO>Sq4s=d;45S8!r#pr(YEt3-Q?;XWwcbb9OxLcu;F_vkGgr6t(aqC!t3R%t zEYOt|zNIr6O|NS>OYK`rCgVHr;q|{==@6T(zw@++YbJHO!zw-NYrciXnxMD$ueB}o z9LJGqK!_kH|NLP-$Esc)GFb{B^!@&dIu>qkA(P!3dmArB=B2n6eiiFOC(%Aorgedx z^(s0z@Gjp(cinu<$(##xUF*>2_hHM zubkTko$UCiw2n0J9Q|&fR+#6OPtFFKdHA2DIasW1A#> i{)!g4SBB`GV5%a>^Ep=w^nd_zuWS_P_Ms*bQsqNH9FYBR3CVV>X-YO|l`o8@{_q zc}N4T%qX@ho-#hB)wbF?*y7aLQKy}DaGYWKN3q3Dt?jLk(rRlT3e_X5CQ>QASdA!(C9pmi(GZ87Pb$DO1u1D#zDPkl&jIS z8jFk^h$N#4mG7e|hvD_oC)pH4J3Wx{EM7rE-5iUiqx>+9j}xRwXpK%!tI3#diYL>& zh{WO)lW@k<$&Q1iY^{$Dp?i#dBBQC~tje`$I-W}Mr!vE3do9*OH0?fkv$CS`2$H85 zKZ-v=i}=w?7EUqF_&5|*EoR4{wW^Vwg#N04pElJC$JKNs#Ur=0-@=_J;8O%Cxz zk>c3mf{zgk@RO=Q&m%;hAkYZX2)Ze%jq+Jy#g)uR1n!^?~N+0)Qf(}t(sU*j(qrh1MPt~+j2Y@4JJIx|@}Vw~st zqv$Nbe}F329z-v@#%KvOF@i?tFQVetN%<`aE_eH%4F#C|x(QgpZSbCdW#+lsC9KvZ zNnr=-h)=OAaxMV_()Q2#SdUj^=MhY|p%xb`uJ3}cESZE*s}rs+Sq|;X9q>v0qAXtp z_pkTZ6-TQLlUs&FZ!N4{?}6fw172yUv$$5uiW`dCYGA0Yq%v5vji16@4P(7P)YAly z!_uX*ODk@0p-40q<3~^@Xfu5C3=A|btK=CJ>BTsRVLhX%JfbF|@hN@`o^NdSKS25w z+>Jj*s4lQSMapAMmbv3JI7uMnbyvg79gXl&(-3y z!{%nW%W$H5*=bWCTng)IJK*B7rOX9wbye2wANI*TWx{P+S|;FE%O_3tuodpS+Yi&r z%`n*7X0rF0pmsx<;LkKHaw-MrvcixYkiuSgslpErwA8rfqXKI+xvjy~Cn@HTd@EHe z{FX>T_y7A4dfRs2UUeh)aW#>`VsHef<~@kCUT6$ZO@f~G&6w!lYF|-Hj^jTf-SV4z zZ;p!Eyw`MVc8@RUIQ|N)pUrgPF_F88}kB;QZ8DO-Dy=Jyk%;N4Y~q9o#xMA;I>m&SCb5i+74 zYE&wr`i>AmTjwowv$W^mp!vc^#YBCN;QIvEh2Jck?W`Xp zL+RF-I;E!7Y_ps1F1jtDYFcz$)eEEPbaZqgf!Ef^snl(ZcB6ZY$=5d3_fThLX6?pr zQwzFqPm`G)g2Jus6?Es%iW)`&4Y8I$!|p&s*Q$nYegt-I-84tRrJJ?*K~*=+@F_Hn zXgfAEXd3r5nqq;5jUKCMJf=Icqf zKe|h0xz3*Nu@gJ)HoL>?a7=uPtIrJQTg%{d{{VBtsa^HZG_cm^)Z{ivlRZ+GSCW#> z@Rpo@pA%l{FN3*tc6esM<#KLkZTKo~wJXJhWFGPL^wRuJPe|Tgut1|sDOXSyrgy9O z`YgE}JW{`_-=UeZH&`J_GqNO2|Dn%8XE*mbdiKDZ^&Z#!c8d%nwD-A`ijYb1wwiXx z-M2`RLki$qHt9&Zl*(3H(jBHe5}#7l=T>}hVYjErIfj5WN2|2E?V@kdnT7YN9c zd<6V^ZVgl17=dyWDcv#_pHd@OUH?jQQDT2j6h(;c&iUJTx*C1TZm801j;&ha9}|3n z02lYv!_KhBdyFI>An1;1o)SAu$4B`f+!qeaeMp0UA@~~twmlKz;#g^t=9kl5*&K_` z(z9EHZ$8WDM#0uEoMob(PSWyodkN=LP3%rqHC{E3B85hon$ae73y&tT{0I|iJVHA6 z5|k7Cj(|+1nJx z_#x)_g{5YP)%(j(Xon;7d^9dQ!~@_3+T&^P#qO+15GlH^s6Rz`ivT@Va&WN&UPp1(QsmDWhIWIb#rmgSdZTef36@=H$eBXMHKb{vvG61;Ytmz*fFCEFsh! zY!2;V(K-J9`DgCT+`0G8H+O#j>?O^M$2F!gYMgrkbbe^V7&z#Yn#&kAw z4)w1_khO#1A-|jhC!V%K)Ktvoz)4eyT760ME7O2lv&Wqa<7IQ;{y9c4@3X?Asn4Or zoeT2d{xl1W=NO;?pARfBv0B)-(*lc1GFUx4P*-A|PbyCRx$EKdm|gTro0}26d`1U@ zv$lNrvfi%Ix|_#rbHI>3i;03K-Io{=*!_9hB9*%tR$1(03ugj$2T!GuT}lRnEtXWa z94(a#E%Pi;P-33c(^F|syBETy5*wQjFK5`*ILKEedEjvw;dG7#j%B1^!(c`pYlh8p z?T}l#h(?A1s|CKw(3_fLOX%#N1+p$N2MvR#^VcQ-sxR>-;`KNH8J z^$caUU0B&f;D>{&bBJMB4Gg2#@HOV@Y`K^%mWYVGvJME z18afJl?Ax$+g*0EyCo*pNl`{t!fNPn*q9%7hrdU~^%aW(K*t8z-mWB2TUp*4;v@gxQvv5NNccJyECuoOZ?8 zK@nk})Y!&m8sIY^u(9Af;H{k+@N|j%~FUxwpsOyL4T%=Cdk%4P{P~QoFaqaK1IMG-U#v z*_{ZbAbD$MR%5veV>&iwr>NCrVSh)#(uDfojRy^&EyP`+L_XSsF}Tx~i@vH7TQp^M zKK$1hns6t2s0nOE`50)8MVC)nroPkyEprPd?HFZuR#c}#L2>>!kbJSYKC$d65jELg z7n$c7*;i4NaL0EOg%{_M znCUJUVw0HV!loW`Rb4a&Co|A%F4xy(C!*k{nqt9N|4(!@B|OGlX^EKr)(C0Z6n`T% zWkE@8&37Fb33{5QeA>j3G8-PMufo*ht@;IQ58`}{!@ZZD@Q({7=L3|;;8~E_xj4qV zi6?eY@{735t*m~`mIs%cDXaOOwgz5lTA^F2zT$dJWoYw>geFFcbYvB{_h5(rBl&r& zv1EFWe6|<&>z2BqDPhl*?AmC4^B0V@ zMRQxYIJRf&Gy|`IyV@E|om4av^us%CF18jj7SBr6_IagXYqAZ zUQe)rz)#>N=pmqdig&@Tb_XU<``feGGI+GTym%8;dk8io$mVd+=a(X$2=_{Z+)MSn zkhG*+*GEMk)GevA4p4EBAV6>>!4?=@QpKv_$dXG~TJ-HD4rXaOk=^vG-lJDOcIB(t z%TH#nJdwRJYFhg4Omnlf)!(4~OH)>>e6&6)2iI$I`Qi^bZ!tyVNdKDrNcD4T69~4i7?$5b_}F27p}?yhX(SrHLLg` zcyZuyb|kuYu$_&{GlspAbXA!9Jbi=S(172!qjG(Cggau@jzO>F==J+Uj)``MG}71S zm!$rYU~qf2Q!VR<@Xd>nNy(&BBOAq?%oEu@?B`cu72k=lBfn!}9>>VA4{vThF%G;L zXzzZIgpLqAL=Yu-nBWnD`w^VU{8v=Ixa6ZGnWW5l1b%SkG34+|w+zmx;d*S5bwmEh zVA#il@Z^@f88ob{4ok9j*c%z-yWq^0y4)YrBtjEqQ_`zMPzjB}{EZ16E}*Dvmi!S< z%xt`vx~(NBAQ(fC4FM^P8-BJ(AL~@s*{6!@UUyU; zOgoVFR$2G!&N=rN{Jh{*XX8m{`w3_JtIkW$CTR+D&*}Bn%#YJm*4*gcVWYaqZB#vH zX|v$t`Lg9{_;{tkhIqo#N=>iMTv~;X-y4k^>omX5Xv^GKqd8s9@a1$((#AUY4c}y{ zCykXGIMhnz>_PBIIe4w!E^V7pM{Sb@Sfrl)66QtnQDAMPYsTs60*^;Z*%R<~1V@N| z5oy;X@yAgFF5i|j{|b_AC1^*GHFIkR`D%JyC|)nA@$ofSI?O~=;DdS|R`d7aj%|UZ zwB#P^Fgx2LdYq91PeF(a9G zN4m>992gt187W>Z_;-E>u-l6v*O(FQ8F^9-BfE^8zHTQeZK3-Ivx-e?YN z9&LiM(M)w`EpbiS%xcXQtV`9EUajj;uRH)pM$1RVn*NBRDhqp$N@8_W&CbtIL)`5A z19~O1^A8C=BKR}HVU4mO;@jx3PN@*{kX2^_s;jJ6mOUp0ri} z&Q^Us%amVpE>mT9-BdDeg%f*RqefMx?UtTfddBrCn`3|FPb&Aje&RaiC^=|8U_R-n zJK?B1Rakn^e!zaRu;D~u!#TaymOh@WnqB#^)l`srmc}|uqmJV&WvA?pvw3OR#`CJQ z8K!Ynn!)thIW;y)#H7F0x0NoNm%O8pg3mRfI%HmJjb8ixci8BCC?cD?L*5ajTOQcq z_q_+W2&a0I_y3AA&eX&{lZ|ABF!$8f)G7p?*mJ@?@etv0_e}H7VYQr0x}^7e0zR%L zv#Eu>c{P0UgB3alzDbY4k8W&*>wb7OQc2RaOPQOLHDerY5ak#Iy6h7`PheJ5K4t{ZxA)_=NTE!#A8iDJst-)xET)yX=a zKj@G6FSN?m8{61Y*n8tPobSsUKiBt*`D#%cSrhU0%DTRAFw7-R&fr8GvQB)$mH2k5 znMNK z^zoasbqaUDhc{>S3i8OH&SJL;Ru|fc>8G(ugycd5!vvoq$VtPP@JI?7rc$loG*Xlo z5*&m6TaGSwkY}vd1TP1nTjyfVeBjnf))jsER-FcI z{qMIGC+QSh!&g78&?%FF>%cvAb{q|ZD?a^Ut%zXRK&J78yhDEe1dV$X0S`kl?@ln> zRnG2(+Pl___ETdrK@x$EAV}~O0a1W3uR_Fh>hM{le|)~_ky=C|YYF1i&tIljq5g3y z{SLvYRffnBCKF~lh1HT4foKzhyXfwEb|AX`?$DZ)m#*?|ztdG7oR01uP)J8L>9ZAR~d$faEmuQh4B@(plU^LNx?) zNYYHbJrfx;Ur6=MaOR;(Tzz)5m-WNWXxR#KhHQ?FNj-QONm5?PpCx#XU>Cu!37#j& zC7_KVYa;=Skbk9jp~d=XT6`1t{+4WT~Nubj9n2y1GVY0ogF<-{w)MhHkkI$8PKgPj0~5>qk#E zu{BV6)NbB@W)MWV85>t0U55W&x#MUR=AFMeI#NK~#MhvNlkpN7o5>nJ&>JUK&#`6f zGB|Xsk~ZHl4NF!O;OpS6r?Pa_)Y}bTKGn&tfR3lzDm*k&5~nG7kf4uXGl365qOIlF z?AT3uKJoM_wi3+G)aXRg{6}be=1x;wpB=Md_p^?u>DgtPlz!}r(IJdF1e>4FUN~** zkymBoM1**}5hYtS(0WWtI6Fv%LV^%H{QMGILZvDBNlObVmhr+oHb1)Zg^na#^qs%e z>(&WR61z{LE0Gu`I7=wrN+N>3&roSK0VU;$>=4Z?m`5aue}*q#-8wptR+l`D(I-tL z<`7&-lDvR`=-+9WL_QZMSusWNg$V-QxY;mz@f0(0Xoy2voE+kS=%lrU2;!%N@?|G} zGRXQtOm69HQoKj9KO~^TL42B_Okz~UFThdGl<8J@pE`-t;WH}5Q_tAVV&aTFPmSV) z6lNn*l~NFJUnPFZHG`yNo497AzNTYWN3E}IQKQ?hIrX5%B;2m#NznBAno<504&u}+ ztS;OrtZ*yV%ErL3$LsT9ULs*6(vgFQC0??`cYyRR%<7Tj9N0V@4oUt-hckPUJB&C2 zPgq%`UkQ7)Q7evC}NWEc1Hh6 z#$-`W5+x;{+)GwSi77`nHm|Z($y}2%cBQk=AMpl)O2!T^pDxDB*}2pAvC*k4E9)@3 z?Yqh+*j7#+@^10_0$g%t;lzreL3qO>zzB;v+&3}|B$}| z=arM_qlY9iBTUaCXfR$xiz$YJcN?82s3=^#kCd#ZS3!e9z2t>MVc$s5-^>rdo_D)6 SZ>nnG)VoUztI}Ah5c^-$A6=PQuyk%}y6n4L_5;6|PS zPE?=*1v)rlj$@1Q+?g;q(+q2iOry(hAW6|Mgo+S%j>_`Pii4lg7CQV8$X0RoE4fdBT zQl+?@aHS-VIU#vUhUQTPX-)?`WL$q`RwbP!-I^nsDH0Bdh_U7r~ zVu2AZ*{x_4^!mv7*E5Cm@m@psk4zuQES~5)_ohA{8=)~Z3%*y8Ixeip)eTiTNXi)#R`C`WkJ`00L}>-jorqJq?t(jWEXFUH z@=UXgIY>mV)-=W~8_3nkX|qZxN=C(tQB@kscIPhsn{lfiRF-Vvkue4u@m;yd>6*A` zeqqjA*=7+>)%ndBpPTcS#4N#@ffdx?^D~&x%L*#KWJXt57d`w<>%atYiGS@{FuLEI z;;cWb2_?cpv3fvDofsVB9hqArS*^fs=c)VK^aA)UCHo zHh8Gig4$tB!ST|3cCVl=BlT5F3w)z2ncW9_%5oW1mRvYjW{vvb|3zIH^-UzS5@F_; z+A>m6MtR8g4ONqc-`4W1(VAnauKE(cy-{88SE)b~6dV)Ke|Z&}Ap8GVjncqdTm3f^ z5Tg}o!l9yGFM+EwDzGIP={A;5s1@bkK8<1l(Xw9Fp89!9GQH905| zF2$!Jb$-r0+QrIc+g&tR6E~*mi50+7*jt~a%5{m&slQMncW!;r&A3N&i*OG?&7+0? z>!K+mj+spRuPkT6F(*CI-Z^u{$?s(khVPjBN5&e%tLJg0wMo`uKiTEuvf3Y5ALI#G zuXriEJHO7@LZpen2L(-4Y$Z6G3UykK6!L8f!Gle;tPxH$<)-Kbp`~&{bX1*A1EGR9wgE-d`xQWpe?D6`fkUPXZQa4{m;~rSDuvFVYWGCFc zaC-K7BD)B>3H$^b5Trr`IJ?jezg?(SVmp0(;WVZVmn^a~L&MqhhPTq2&Zako*DU@Z z*;Hm}^cAZARGQZ4bHI|-x3K}(y}DAh5d~~*&kbK%{hkh+x7R)U;M{rx%Yol_l(1aL z>!_f}_hy6sakJWKcbT9iDGUCg^B7wKE#4}Y7vAc9l4UGGMZ~8~8+{RQ=2yl!3!rg* zfv&I(+t6uB_@c`JxldzL{*)2Y*W|DwIJ@4$iXpK*kCi}8J2sA8>Dgp{@zE(fk1G@b zy-OV(XJEB2ItU}x>+9(6 zlGPMcvSz)%$0tQXo%WWMK}lBkc|zU%9!Tt+p1DhiB#5L3QPe*2GFaQ2(-c#5lGDg0 z$ro}*_2esYnXK*z276@v!cCpNzK}l{;D_Ly-jz0rbN&)B=t(17gc=;B!DDc1U^=US zp+FT&f+K-NtTX&s;1#9nTxv%6`ke;loHg-^m(26c`1LO(w3M8 zLOwSqr^(7XFPR&Q&}}4U9zhd=teRTe&7Jf}Z&I>qTD6zAA$5QWFXPvH^rYk$K(oa^ zNN$o<{y>Q5BE@$S*a^}JuwNhXny6{y2p%Gk2t={#B`Sy@$Dum@0IDd86&ALTuUB#y z#D4rgi0uNwWx?wUc-?p$_+(4MRN6&0g@PeZk6RpA;#Y|CQv}I?U?2VP3NZl{cbBk# z47c6wWoXP3_Y@lAaomjmuP;|avSCIz_uhAvY&)=_r!fQ$53NjcCRZw#F{i?rQmI|8 zT)G1qww4Z(Dfs&YLcb4)5=xFYD*uosMvclpqDL|+zesS2;9~@|sxT1+_W^B$7F&?H zWHtAByqua_Su5fBeSDCAf=`Z2k!<`b(p;p?HKP7ffAH%hh0Mo)M?i|mdcPEmTnhY8 z3PqzrsKfu8=1FOXaWZf5-_!hm5|FF-X9N)s!J+$YXy8}wpR0Wre|wS6hfROi#L}&b zEXP~6$~SG5*DZ#e>T9Wrtg4+w!)EAupvn-Zu-d-U{+;$=4eWg&z44kxWlI^>DyEeG z&TPm{xJtZNY1J@FDS11~e$|$cZn&;UNHPv967@Ihk)frelWp+a4jb&>F%_?fcXqVnRx=*Doz;v#px9@{O%Djq zKWs~x`%LY@v;+ZpT$a*5ONMbVSB;uk%MZ=#V2 zSu89dQh6TDQfcIOB3%3eKao_XjO9-td~U_-CgcxvNmWszvO5I!@77Fl5Kkt#NW}Xv zKFXSY$%lG8kF=vQ+Uz~_tMtKG0-K4?L_rZ1$VE=4k~on=qKXQ|g{Bjdo$3YeB?uBw zCd(SC_EMxgi7QoHp>!smNAS;(^u3?ml1;ki5Kz)%666v+$uYQ{CWHo}_Qec#nWU9M z`tGTi*-Lhpv&G>}yR|BG%ix{@jW*&IcZ0J^<*q} zz|-sF&yw7KLclU9_N7v|rLc+I3XdPPvme24_N^TB5nCLAhCoX|{Re-JfYM%=K2j;k z&^(V$GP?8F=%v|wf|UfqV26o1Lm&?FDp9W^IMfjl8NztNV86g&NsVB~4>q>1{cwiv zTa<6FGq`VeS-AFzgDPV!Z9Za?OHa+kLpTmpd1jC~5=Mf9wwQ3Bub{WkQD~-&_)n-q z(Jz#F_CPIrCH(1ukM!eIcsE?qN}J;q6Y_-ooqQiIkmEapy?vg*W;edKV4ud^ypGhK zNsLL+xoD_5OuT?*iwKGdN?^&+VvB5|)$T}*@ba(GOg((-Xt|M!+LpY9oTDSzu}rvd zbT0l3T6C<$m4{5SDY^r#=Y_QHC9=s$f)@zxAvi_wB0(krC5)^N`7v@{rsqj?!mf>G zV)bz{U%x^u!k8k8CU{*J2_^@m9nZ-pt;F97f{{K_Sezmb{ZAi^f!mMYsyjz9;8cki z_{H&NJ-Y^3C+(Olb55?opHRMga*o4^hrCFk<51$uq7>r(K3Nm$@9Xh77{47SCH${g zhXQY$Y{nlI7r#(}jZFUw{kfv^pykL|NCKFw;$0nrpA^uaYG!kx^;9|K<0%y@B|AA( zybYJgtW(x{dV~Fekfg$4yL~9qFs-7=rSMG10y|F^!G#yitO-7Uaei4lZKM$zaX-?0 z9l;$09t4R}(7w(-gmR$k^lkX|di->Ctyf{urM8<-j1lW#UWM`1@hZ zMq&>;8Iw4976CCk^kd4^%?q^HqG0ku0^k3Ye$1sKZkP!dN$kSmq_((qB%)df#@{fJ z7q!t_Mb>p=ze+b<%%Km^D!N!ii%*F+sF=*Hj`)dI5LfYKS~ zJB2mAja$eDf1lgq^>UviVMNlkg%>Wq7>R2t#fcp|wg`5d?h6Ja-z>W$eT-WSbhMbY zMOPQGn~i1~2}ls`BKZSYn**Ib{wndC6j!87=4MvY&=`p8qi$JV~-&AP~u?#Wtn$F0UxRa$K)x zqtEN-lEW(NdOiMtyQ7a+67LLx#|eH(@D9N_g7XBQ5-3my9!Fp#NFuNh)DX-jXkdz5 z1z$>JKY?)dHlqF=B}i5T{3*#|!DL2KHu?kpkedhlL)iH|4BGe3+cq#w-F1~hn@x~P zFmqT-gTt$Kz5iNjmBu(a;TTrq<8Vj#x9`6Z`D3r67LI+ehn)oHg_ew4a9jKx1Aons zcpmMh=@0pPB%TkaF3fVgh9i;4f0)#pPLGi{ePWH9-5d1w_xR@W$Drs#r|Q=V8{GZj MLjC+iRxH^52T#cWqW}N^ diff --git a/routes/__pycache__/room_members.cpython-313.pyc b/routes/__pycache__/room_members.cpython-313.pyc index 84896b23c491759d8b3fca8f0c5f4503d8ddbc67..70dda33f21b47a265b977dbaf2a60abfd597a2a4 100644 GIT binary patch delta 2424 zcmaJ?O>7%Q6yEjz_}{VPzt~CYO`4?H)NMlZ0|`ylP^F~-0`=B~%8`s4Z`wt*9nEfn z8c=iN9?hZ9OK+e8f>0l@k(`s+1NXapJvM$2cfuTdhL(hXj9|z4p_WGskook^s{@mIDt$!v=!V0Hxn)Fs=CPE?#H^+B#nmpG! z>OyypBhk5NPNl#4qP=d-GstV+ao3!z`O@5|14oEP$v6IY5skHw??=^+1-wLHUu)^=EOc08h`#svr*X#`Gdz9D{;cg8)O+CJ+X zO#&<=h0sU;4D_xhu^R_COWFZXk`6RQhDD>gY*_kA&-vPta;dbeD;IRV zsyNoNV%3z7YDQH-SEbwL;issw?XKviS-Pk@$?&p3)lx;beQe@+ytQM9fs>TJ8V*M#irq-d0FcUiYe#%0rPVc{xzpuY!!QCP$;Zeng2BgsqFe6{wm?KRBWLXA{P772k}b+e-) zhtNj^Rg~)KV&f%KCu9)1rW-(EZNEZ>@MR0^sMvHOBnMVJS##F4emnFDpM4>7QrlKk z*$O8gweGt%xHkAWHMvo~W85+}3itTUZ9l)HZ9H4>ZMMig`XSP>ANiXn7&mk0K2W3;(y47}ES8E2SQd!!56B0Vc2E9itZ1 zLc8SE(kw63lpST6aMV#GdZo6kmsh%WYo~5j76@nt{grO=DoiG?0RWlDu@6;joMV)> zef0?_nWOk_62NY4%6WaIh7jn}=z&#o4t=K)u=1Q$)6Jwua}YsB!0Zu}fGsb6hu{6p{GQktxifxieBg%yZPO{7rFg1lG_jDP9wQLj~nt4 zSYl;}ejDytKbTOZxB_FsDk;i~uo^l_jrJ_uTW}Nc8Tx&DPZEoHfV_!t8sR_n2yZ#30$plUAXcPUdYrVdgJ#KK=lbvE*(gq`?9>}}C$J2> zhjH15u{0npSQ?H>$ zWQB-et_aS($r1E+vg$cnsg;*5>&Hk1YKCzjcyyv;QvI#vtx5c+Sb7h+*XfOfB+jI1qazw7%Q6yEXv*zv!;S+Cm~ntwl!KZ)e_{w>$6q z-kYDV|8y;U918gbHs1bw{=>UNd*LKm-kY#?vqF)a6)d?Jo%5hu5Fl2J<;UA|H(HA2 zohFuV-cwYpfs`=UadzLJo*L)x#RdA}cJYUUrvwJAP%kjt7l?7%DRB`i+KY?*Ph8@I zxT*e*$2aL`WSe;CQ!?6`_q-tzmEM&f&Ssd)k>B5hM$=Ks^}4-Xfh@DZD8gBUF$5K1 z2q8u9Ws<7Irlt%D_Hrbs)v7Q-zf-F6G&A^G8Sf+spavp)j(?Eohv$VG8yj|`VP*kY1FT8N(RyT3o51NggdoCm2qyhLq6eOpMBjCkjas$3*@Q6L<4E{> zmy|vXM72#XKO{WQcU8*Gawm1Z-f7qX=h?L3Wsq$Tm_lEKC0TMM4a>}mCvE)3DE)+f znmpfXMPDc4V<|*GiZ4z7awhj@$Q$!Ni3+jd`;ooKUs^y`o}`4JdhhyI%}1(n5Ey?X zjl&H4$Q^@{ltKTEYbS;C(9;@GpAuOpc=A~qPUv)0Q+=!+=K3+1P%LGN8R-{Vde!psO2Cx)uzc3QGnL?XR|3lK#9f(|z^>MA*?|4uDSEg_ zoBG7A<8QkvrS;qJB6GtP2CHVmts|O42ns>~0abOB&Szc1qHh3Uk#DHjTXxfim(hZ% z!V*Fjf%oTJPgQU=WLr;67G6c*a>{JR)r2WpOeXzrvh_RcX~gNr$#1!4Uk+`Onbto; zd09JY3#?t>4KYhMGLtD+)uG4L6m&mh=tvPH8Fb4Gn;mreICEvy#n15R{NOoL~P6i+{kA)KxrTb)LA5%mgg;<<9RP^oV1(?7Bq`35uGX+=iE9xqnw zim6j$tVBN_8(YCEkM{x~r+_>61zywbzVR(oYn7cX`zqXIF1&pjzcM%y2_c8Vg#+ON z!$aZHfpF 100 else ''), + 'has_attachments': len(attachments) > 0, + 'attachment_count': len(attachments), + 'timestamp': datetime.utcnow().isoformat() + } + ) + # Log message creation log_event( event_type='message_create', diff --git a/routes/main.py b/routes/main.py index 69d6d55..c945934 100644 --- a/routes/main.py +++ b/routes/main.py @@ -10,7 +10,7 @@ import logging import sys import time from forms import CompanySettingsForm -from utils import log_event +from utils import log_event, create_notification # Set up logging to show in console logging.basicConfig( @@ -55,7 +55,7 @@ def init_routes(main_bp): Event.user_id == current_user.id, # User's own actions db.and_( Event.event_type.in_(['conversation_create', 'message_create']), # Conversation-related events - Event.details['conversation_id'].astext.in_( + Event.details['conversation_id'].cast(db.Integer).in_( db.session.query(Conversation.id) .join(Conversation.members) .filter(User.id == current_user.id) @@ -370,6 +370,17 @@ def init_routes(main_bp): flash('Passwords do not match.', 'error') return render_template('profile/profile.html') current_user.set_password(new_password) + + # Create password change notification + create_notification( + notif_type='password_changed', + user_id=current_user.id, + details={ + 'message': 'Your password has been changed successfully.', + 'timestamp': datetime.utcnow().isoformat() + } + ) + flash('Password updated successfully.', 'success') elif confirm_password: flash('Please enter a new password.', 'error') @@ -522,7 +533,8 @@ def init_routes(main_bp): 'details': notif.details, 'sender': { 'id': notif.sender.id, - 'username': notif.sender.username + 'username': notif.sender.username, + 'last_name': notif.sender.last_name } if notif.sender else None } for notif in notifications.items], 'total_pages': total_pages, diff --git a/routes/room_members.py b/routes/room_members.py index 91eec30..7a10312 100644 --- a/routes/room_members.py +++ b/routes/room_members.py @@ -1,7 +1,8 @@ from flask import Blueprint, jsonify, request, abort from flask_login import login_required, current_user from models import db, Room, User, RoomMemberPermission -from utils import user_has_permission, log_event +from utils import user_has_permission, log_event, create_notification +from datetime import datetime room_members_bp = Blueprint('room_members', __name__) @@ -69,6 +70,21 @@ def add_room_member(room_id): permission.can_share = permissions.get('can_share', False) db.session.commit() + + # Create notification for the invited user + create_notification( + notif_type='room_invite', + user_id=user_id, + sender_id=current_user.id, + details={ + 'message': f'You have been invited to join room "{room.name}"', + 'room_id': room_id, + 'room_name': room.name, + 'invited_by': f"{current_user.username} {current_user.last_name}", + 'permissions': permissions, + 'timestamp': datetime.utcnow().isoformat() + } + ) log_event( event_type='room_member_add', @@ -77,8 +93,7 @@ def add_room_member(room_id): 'room_name': room.name, 'added_user_id': user_id, 'added_user_name': f"{user.username} {user.last_name}", - 'added_by': f"{current_user.username} {current_user.last_name}", - 'permissions': permissions + 'added_by': f"{current_user.username} {current_user.last_name}" }, user_id=current_user.id ) @@ -104,6 +119,20 @@ def remove_room_member(room_id, user_id): db.session.delete(permission) db.session.commit() + + # Create notification for the removed user + create_notification( + notif_type='room_invite_removed', + user_id=user_id, + sender_id=current_user.id, + details={ + 'message': f'You have been removed from room "{room.name}"', + 'room_id': room_id, + 'room_name': room.name, + 'removed_by': f"{current_user.username} {current_user.last_name}", + 'timestamp': datetime.utcnow().isoformat() + } + ) log_event( event_type='room_member_remove', diff --git a/static/js/notifications.js b/static/js/notifications.js index 1b65785..933eeee 100644 --- a/static/js/notifications.js +++ b/static/js/notifications.js @@ -21,6 +21,9 @@ document.addEventListener('DOMContentLoaded', function() { const notifDetailsModal = document.getElementById('notifDetailsModal'); const notifDetailsContent = document.getElementById('notifDetailsContent'); + // Get CSRF token from meta tag + const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); + // Function to update URL with current filters function updateURL() { const params = new URLSearchParams(window.location.search); @@ -31,7 +34,7 @@ document.addEventListener('DOMContentLoaded', function() { } // Function to fetch notifications - function fetchNotifications() { + async function fetchNotifications() { if (isFetching) return; isFetching = true; @@ -45,54 +48,26 @@ document.addEventListener('DOMContentLoaded', function() { ajax: 'true' }); - fetch(`${window.location.pathname}?${params.toString()}`, { - headers: { - 'X-Requested-With': 'XMLHttpRequest' - } - }) - .then(response => { + try { + const response = await fetch(`${window.location.pathname}?${params.toString()}`, { + headers: { + 'X-Requested-With': 'XMLHttpRequest' + } + }); + if (!response.ok) { throw new Error('Network response was not ok'); } - return response.text(); - }) - .then(html => { - const parser = new DOMParser(); - const doc = parser.parseFromString(html, 'text/html'); - const newTableBody = doc.getElementById('notifsTableBody'); - if (newTableBody) { - notifsTableBody.innerHTML = newTableBody.innerHTML; - - // Update pagination - const newCurrentPage = parseInt(doc.getElementById('currentPage').textContent); - const newTotalPages = parseInt(doc.getElementById('totalPages').textContent); - currentPage = newCurrentPage; - totalPages = newTotalPages; - currentPageSpan.textContent = currentPage; - totalPagesSpan.textContent = totalPages; - - // Update pagination buttons - prevPageBtn.disabled = currentPage === 1; - nextPageBtn.disabled = currentPage === totalPages; - - // Update URL - updateURL(); - - // Reattach event listeners - attachEventListeners(); - } else { - console.error('Could not find notifications table in response'); - notifsTableBody.innerHTML = 'Error loading notifications'; - } - }) - .catch(error => { + const data = await response.json(); + updateNotificationsTable(data.notifications); + updatePagination(data.total_pages, data.current_page); + } catch (error) { console.error('Error fetching notifications:', error); notifsTableBody.innerHTML = 'Error loading notifications'; - }) - .finally(() => { + } finally { isFetching = false; - }); + } } // Function to get notification type badge @@ -130,80 +105,123 @@ document.addEventListener('DOMContentLoaded', function() { } // Function to mark notification as read - function markAsRead(notifId) { - fetch(`/api/notifications/${notifId}/read`, { - method: 'POST', - headers: { - 'X-Requested-With': 'XMLHttpRequest', - 'Content-Type': 'application/json' - } - }) - .then(response => { + async function markAsRead(notifId) { + try { + const response = await fetch(`/api/notifications/${notifId}/read`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': csrfToken, + 'X-Requested-With': 'XMLHttpRequest' + } + }); + if (!response.ok) { throw new Error('Network response was not ok'); } - return response.json(); - }) - .then(data => { + + const data = await response.json(); if (data.success) { - fetchNotifications(); + // Update the UI to show the notification as read + const notifRow = document.querySelector(`tr[data-notif-id="${notifId}"]`); + if (notifRow) { + notifRow.classList.remove('table-warning'); + const statusCell = notifRow.querySelector('td:nth-last-child(2)'); + if (statusCell) { + statusCell.innerHTML = 'Read'; + } + const actionsCell = notifRow.querySelector('td:last-child'); + if (actionsCell) { + const markReadBtn = actionsCell.querySelector('.mark-read'); + if (markReadBtn) { + markReadBtn.remove(); + } + } + } } - }) - .catch(error => { + } catch (error) { console.error('Error marking notification as read:', error); - }); + } } // Function to delete notification - function deleteNotification(notifId) { - if (!confirm('Are you sure you want to delete this notification?')) { - return; - } - - fetch(`/api/notifications/${notifId}`, { - method: 'DELETE', - headers: { - 'X-Requested-With': 'XMLHttpRequest' - } - }) - .then(response => { + async function deleteNotification(notifId) { + try { + const response = await fetch(`/api/notifications/${notifId}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': csrfToken, + 'X-Requested-With': 'XMLHttpRequest' + } + }); + if (!response.ok) { throw new Error('Network response was not ok'); } - return response.json(); - }) - .then(data => { + + const data = await response.json(); if (data.success) { - fetchNotifications(); + // Remove the notification row from the table + const notifRow = document.querySelector(`tr[data-notif-id="${notifId}"]`); + if (notifRow) { + notifRow.remove(); + } } - }) - .catch(error => { + } catch (error) { console.error('Error deleting notification:', error); - }); + } } // Function to mark all notifications as read - function markAllAsRead() { - fetch('/api/notifications/mark-all-read', { - method: 'POST', - headers: { - 'X-Requested-With': 'XMLHttpRequest' - } - }) - .then(response => { + async function markAllAsRead() { + try { + const response = await fetch('/api/notifications/mark-all-read', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': csrfToken, + 'X-Requested-With': 'XMLHttpRequest' + } + }); + if (!response.ok) { throw new Error('Network response was not ok'); } - return response.json(); - }) - .then(data => { + + const data = await response.json(); if (data.success) { - fetchNotifications(); + // Update all notifications to show as read + document.querySelectorAll('tr[data-notif-id]').forEach(row => { + row.classList.remove('table-warning'); + const statusCell = row.querySelector('td:nth-last-child(2)'); + if (statusCell) { + statusCell.innerHTML = 'Read'; + } + const actionsCell = row.querySelector('td:last-child'); + if (actionsCell) { + const markReadBtn = actionsCell.querySelector('.mark-read'); + if (markReadBtn) { + markReadBtn.remove(); + } + } + }); } - }) - .catch(error => { + } catch (error) { console.error('Error marking all notifications as read:', error); - }); + } + } + + // Function to handle notification action clicks + function handleNotificationAction(notifId, actionType) { + // Mark the notification as read when an action is taken + markAsRead(notifId); + + // Additional handling for specific action types can be added here + if (actionType === 'view_room' || actionType === 'view_conversation') { + // The link will handle the navigation automatically + return true; + } } // Function to attach event listeners @@ -231,6 +249,15 @@ document.addEventListener('DOMContentLoaded', function() { loadNotifDetails(notifId); }); }); + + // Action buttons (View Room, View Conversation) + document.querySelectorAll('.btn-group a').forEach(btn => { + btn.addEventListener('click', (e) => { + const notifId = e.target.closest('tr').dataset.notifId; + const actionType = btn.classList.contains('fa-door-open') ? 'view_room' : 'view_conversation'; + handleNotificationAction(notifId, actionType); + }); + }); } // Add event listeners for filters with debounce diff --git a/templates/notifications/notifications.html b/templates/notifications/notifications.html index f2a3018..031ecf8 100644 --- a/templates/notifications/notifications.html +++ b/templates/notifications/notifications.html @@ -58,7 +58,7 @@ {% if notifications %} {% for notif in notifications %} - + {{ notif.timestamp.strftime('%Y-%m-%d %H:%M:%S') }} {% if notif.notif_type == 'account_created' %} @@ -83,7 +83,7 @@ {{ notif.notif_type }} {% endif %} - {{ notif.sender.username if notif.sender else 'System' }} + {{ notif.sender.username + ' ' + notif.sender.last_name if notif.sender else 'System' }} - {% endif %} - +
+ {% if notif.notif_type in ['room_invite', 'room_invite_removed'] and notif.details and notif.details.room_id %} + + View Room + + {% elif notif.notif_type in ['conversation_invite', 'conversation_invite_removed', 'conversation_message'] and notif.details and notif.details.conversation_id %} + + View Conversation + + {% endif %} + {% if not notif.read %} + + {% endif %} + +
{% endfor %}