From 4bd5180b879be63abb021abb7d8d04debe17116b Mon Sep 17 00:00:00 2001 From: Kobe Date: Sat, 31 May 2025 13:00:06 +0200 Subject: [PATCH] storage cards on dash --- routes/__pycache__/main.cpython-313.pyc | Bin 48498 -> 52214 bytes routes/main.py | 41 ++++++++++- .../components/conversation_storage.html | 69 ++++++++++++++++++ templates/components/storage_usage.html | 2 +- templates/components/trash.html | 2 +- templates/dashboard/dashboard.html | 2 + uploads/Screenshot_2025-05-27_103137.png | Bin 0 -> 133693 bytes uploads/test.png | Bin 0 -> 20029 bytes 8 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 templates/components/conversation_storage.html create mode 100644 uploads/Screenshot_2025-05-27_103137.png create mode 100644 uploads/test.png diff --git a/routes/__pycache__/main.cpython-313.pyc b/routes/__pycache__/main.cpython-313.pyc index b122c38b41e93a2af811d3313faa781328727711..7f90ded612d0d0f405f2206ea865a7355315d362 100644 GIT binary patch delta 9529 zcmdT}4OH9Lb^rhMM_)*Q009CdBq1yi-(SY&%hDI4goBPr^PO>`g++|LDlDNc;o49k@r61YSGyau#)cxz$%Q;)yZ0Sm3uU@ls*}YE) z1R-hDbGDsw?BD;s_wIY|zWeUG_r9lh-j)6Gw2*l#BO{%IzpOXfMk@dORHlJHd8&LU z+LK4}dh$trPXQ^ga8Ayd)@$e~B!!HY_ZE>Ns8jS7_ZW$h)hT;TJtd^1$4tyU7GmkK z5-Y1$^_KROlF}XDp-``IY6i;s_t6HEK5bxC{{ZDHi?nsTQ`;&aZ~p;o$r-3$&Et|djx;zkia63p zpWr{mr_(aorgBN!9SR=xldv}u2n8kOHh(zm9rjDv^TdWo#5*)HK66M$6@2;3yQ&;M zyAFq{29VN5LgRj^kY+!gM;p^^71(ktz0T(ij|_&q#5V-xg}+Roa^e528;vvfrC;Lt zeY8&dm9))#Ux+qn%`{_IE^RHn=)m>o21_w7K+;?depi&sDT-;W)R2UMn<$ z7TiVjNS2Wvyf?2<=~UIplIu+AT}!PQxiYn!ZnqWyqaJ7A8|fu$Ip0jhdLymBM@9eQ zuwLeFrkdV6M#FL9NwBy3L|g&hIegEA-T|OGT^dva@tSrF+?EnvUe?Amym8 zn4UkJt97?6RCdsp`b~Tr)67j>1~$|8bs7-=uRdj5Pztup&p!?#y&%KCSp zzUhQ5oqjvp2;HEPzMtJn%?dRwY%dAcFTL@QTW1U>Zor(G6>OAQAkkM7TP2>Gsbx_-AFbm%Mq@|;nh2Bd+WE6=Bu zJ2L6bTr=IUJC~L3D_7Dl8F5R~WxxvuNzo1x0J)<vvJ&vzCl*W+H7Y-Wcs4>STy+LY>pa7O2=o1Mm_ zWjReX&@owRmbn*BlCvZ^w$t1y>-RH#*H@}#?sfG3r%G@m=FK|Uc%qOsF1MojW=&~w zyww7I_Q9eQqf*ZsRsV2u65K*T$F`XKYh~_Zi@SF$b@w#K z77Tq!20$_RWUeZvF?${@9n;hI?4|sDc!UIPza29m+E*_B?VNt2tE6In7Oxf}K}r87 zl9Mie!O_S+5E`@vpW`?UXW?9$VAgUc^m}q9Az&=G?vIEGOU*2Cu(Fn%;zVTlNJHr> zQqqU2&=yx_Q?C?0>OPbm8WQeANsTqeCGPY8IHD}oPEx3cs#O0UF=i!Ue#eM&w*L1& z;;f_&G(*)A>owCaL3;Yi0~&cAIJ{;s&{o0hKFPio_XGINur5F8A4oSISdwm}#6)wA5=?`4&iD^2^JNTk)dE{ikPt= zc!SdUvJ2_m2yhqX2wwfjUW9!JnDCPw^wL^O5ne8(9MJtZ zY$!Dtyxg%`;|I?~!) zO#Db6LKsFEK?neZ%jg$dOX>5iav7e<@v*-ft5 znq4u&ZfH82aVBHdzD6{xjT^c|Ls#6;EgHIS7)#Ffoau=ht3_k=#ewHM7d$az=S`FK z%+B*e)$!66v9u*-T65E6JG1Nj#-}!)+kElFbI}V?v20z;)OAalR#5aR9+^BHJr#`?REY&uv4WadX6g#vAsErw*Sx9JjZK_LdjOi&K}TUOay3`1S6c@$S81 z_ukl=eKET`ZXXowgE6}=ZV$|k1ZJaJ+YMV?+_qY@t&ZE)iMDlDPsF=+iCw$mU2d_< z9qZa3vmJ=re4@=a>pv8;4aaSxqHQ#08~?u60((?io0Pasw6zg`_P z?~a=fh~@*=J)?0?SoDPBo+;5Yb(`Z(@LObe@Y5TWz0JO|S$oAvT>~R$|kT9KOiKsu+I^ctehZ6`7|4Nn$;X6+~f#B7J-wy^a29lhn03D zN;`16NuFt_Y$rCA?ZXy8nA}? zRJP2?k$79d)wItk8L8qNO>=5SrX#6gq?W5%Gnc{0Osvgfq>iiYoXcip4p+H)E|-yd zuDW$DkCFLY{RV!nfYAo%7o96)bP-qAHCN0?BXXMhQO~1466?n(~w0nv_{P_Ws4#$*a zp|F%T;f;)tdn9oMO>NQb8>C2fYxi3ZV{yq!)e+Sd?r9@g;58 zAMqpwn~&Ioq0pG5-gNJfe*%9;AkW}n^o@c3VvJGbRV=D;D(DE}&0ysV^q&2z`D*&f z{gwQhndkOjm1~-@9)CoD7;|)}lK)G3Zm5v2qc0ELt82pQREBO}3xAOw^OXR@8J|-Z zU(WEJ&tCi$c*6|qpyecYTgBA#NJ7LrC@F?QV<8eI_!9uxhSds|sD#NB79dCPLB8f8xLuNLjgRdY?h0f|UD)R? zgb9E*--kca57Y%2`B(TzstL$~80UE?zMBt$u$*xq` zCPz>pC;=dYBEwuLj7u%Uotblg5$mf07_?zo(7t3Jyy{WGi?Lsn-DZ&7N& z?84vUsqRSC%-X|ToC!3XBD9lBU33K`6i|Qr9OntUIief;r9f98#hsc+ptCTSm8lQk1*aKGwa8|sB zWZ?pI$f!%UB@NY~CGVo3?;-pe;lB~yN8qprctHxRywfS#1x z0g%$zHQ-xVPF+b9%D?4Oej9W84vx?Eiy7)N!%`;fwF2c)Grb(5S02hO#Wl=VFrUoK z4ecAO4gbL6e*RF8(utew6xb#Q9^RrZ#f3QpNmg4g@c~Ia;=dQ}kmwTe_F}P|gnqF< z+sDt)+S8qU6&*WmgrB5g4EWC-gvLisZ{aV|ADylNx2<_}(u_WoR6(nQCpH|Lmjp6A z$oNr+vyX1!FVmkrS`9}(?~K5!5(1DKYI&?cQH{OpY3F18{7dvtAG@on8Ap;6oRVxn zSc`zK2&5GtjGoeR&~g&x{Pkn^fUn>Bc)g+yhxsXe;PEeN7UVfrL0@^oGSmCS79pb@ zx`H_}{f^Qn&l)pizp-G&dMGw(UZ=c=7ej-eWq(PCAf9uzS zU^|~&%b%Zl_{r^ZSoDv-tW@kv_&b!6Ijx@|^(Mli$7F(cVclH-lF-;Z!lDalW5uR= zAK3{Ms2PWV59|6C?Yww2nt|(6k)J?AigR9^im@_Zjhy7)kq?<2>J-oS(N3OCVO!ZJ z!GW0ft^a`(3tYI(>;|0@jPzK?g4PkF!U!xtZAWSh0izW8PXw0pECeV?IpT*KK1A-s zCL+g!2ntwGlqEw6uf1^a7gy%UNYVPD!ZAciDtH6%pvOo&4n!EuWR$dtca-_`fWrkYBsr*sz23mvikwkwaN?nNE}I~p=Y4e@ zUpuq&s~7mF0moSCN+kuzI5g#BE>%*Edq@4g00}#?;f2QwFF}J7qy~GfMtBn8I>HYS zeu(g6gf|fICv2ieC_q?+unmE2#37y&I1;1LD@8`syQB#O0}&4iO-B4-G7fy`%EPbG z%U8T5cc;m>@V5j`VM5R&SmzY1_VzB-Oyk$?kuf*oXrh1g@=+Umm|A?>ku-@>YrT_@ z|0WhqbyxMfa0W1)BV*pNp%MT1G<&fk#VEWH!GyqaGBa{2!GjM&76)%y(_vx-5hXe9 zMwnQzSw0zo7cyd{$F8>R`8({&tR0tN!q&qKdaRW z%qu77_#EFOefOWa|NQgMKmTJ!x_&^s@&`la)r<_g0MGO17Ytrx`!fqkY=2E(+#~n| zpRqfyE1%|b+SFY@3!u;3UD#Dbi+G=MEtBU1hY4_glN&U2f{`@=(vz z*m7D9V@=%^w1U4YX(haE-Lt!@XcgzNcUO1S&>D}hsoeX3z7JuCO*vR}-#I2(!2*&*@~8<^sD&DvDoMsO{HKpT7+#R6?)&yy#Kg*6%O zPaHPvGn3hgCfh7xu0s}?t+X#Eb?kF?Da#2Rx$t{+qbvwt5ZHx$H;a7TmN;+!G%-Ca z2tCE@!R*qf9WM4*)-K~(4ceDoO{{6VgS~zx*XXl!5O%UE55E48E&Y_u=n;B6Fk&I8 z0KR6?=CiXi+2vC$2XDFA#ekE&lkX~W`c0XFFT-!n6k3g`6@Y}vVFD%D+M7n*xL$5DrV0v%rRv~ENMZG3Rok5 zK)pk=N=O@fut{?EOm}O`FBU(fW?mcs{c6m}5eP^I z?^4_@cBIPAuIEayTIghrt`3sLE<3B(UYAGA?&)MFUFGi1lp=m>N@-u_f(?S8JOkE7 ztF?+bVAL(HQnsElV`B&8eCtA(-f#CVKz(hZub{yi$@Dwe;|pEvjr{o;g*|Eg zve=fqe8UVIemtc*sCgy_R^5$K97U;h^vq$TZECkjZz*hEv}&pe?DKrZZHA--Ur9X> zsn$G0&x0w+J}D*4SK49l`uGH8sXmxse(Uk>=MTg-tr!~y$64|hDJLSni7E(ilVd#b_4_7qnqUEBl% zk`a;iIPV5_vN)IYaL;_N%EnIB=CVEetZZ#bF4@4!H+QufpV?Q@L2xr7 z`M2UMNOM+lPRN*%f*Wm-oYp)umNu|MrA77W*aGjq`SBO@q-BE^>_TZXtZ*vs9Ulf) zYcr&rDP{ST2X(epn?Gh>%Xli}PQzAbI7mP4FxyyM%3eF;GWuqNqoA)9LxlgvBZKD^ zm1Cxy^0S!+ZRfr*#2%?E1qMia2A_?^D`e4>-itf(v-5RX>~j@mX%pWewcb%uD&bCr z@&}P{Z?Dho(lAEj`%`cg82ZjB_y;@%-*p3$({_v1An;Gi%}zs4IK9E)R8&Cq!Qkf` z>`3=UpbF(e>b9rq5?fMJ!bCZbw6h|)tzb)PeERKoddpJh1QwS~cc=wjsalX8oud3@ zbEZfI4ha4-FHL<(zac-FZmJ&{8BYm)IO8Oe3XD`T zNR^X&@~XIGVPo~^zISE6u?98X%aCNAvanT+(g$0fZg04hN@Mlb53+FGO`$)#oW0fZ z;Vfr&GYq^P2%ZehXl| zKO3;Yp99$Fp9R?DcL6s0^8j1?g@CR8BEWfm5wNW%pS`kOk^-ci%oa3*2Yw^Y{uCwk z3-Wx%7B^Xs6WubZsgzw`{8O?h@z#>dq*W$63xkR_*c(-7uyLAd7>o^v<%POA932=? zscsBK`lB=xRz$1WL!I;EtB`~gDA3IaE&$yY3k|DUOc@@bcy6WH2ssE@2o8h-0A18Z zhjpVC+NtX1{!lokQo0EH&03!lR$#VAqoIgyq0#7YAQaRcqa)#{5>$hM-W_x)N?B2h z?52tVSrF&UHIXPATWp&C1A#8VS-u_7}@aNfA4^tSMfDOja#M`%zO`f=%;i ztS=JXMkQ=mhSlL-m1?@EM0V(6C=#Hvpr3Z&M{z)n(T`zM1d!d-i?k169YO%XkFXx$ zA%xWcdKOjt)JQDQp!CH;TSKuOx=jg(1F&*cqYIE@78rL}iN!$m6c1g-hL_h?;t7$$ zbyJ`lkZ5Q@5gwhyos-4}B15%2suT zen*h;#zp8(O^pRc6iwR}r9mFOy0JGJ4ePf1xA&fl2pXn_J;F6BxX)R4+qtav zv(|Q6#~SGN>?UNLIp{mIojk>UMa$qXGfvHy{ll9XqFQyy{`X03K9|*U*4hG6U(kl$ zKWJ{Oz2w0A26djxT6WgDjMgO{i~Ye8$0gH709}kJy}G$C8jezp;z@?$O-whdTOqPF z-Ok^E*p3lZhddNiVrqaYkpWdV%nv5h2W%o_QaoDHB?tomm)?Vit^w+}f&Ls`x^+aQ zU{B!u0tE4|A6sdzLgop!XjgT{2_WT$skFhk&jH32G>T@!N*i};}ofmc0l zKb{D_hkbl8r;+-50NI!nQG~WkTJQTnX+{7KJP;#4`fR)9zX|mHBVprXF19aTkZAd< zZ;Fop!y!|)x%l}du#lR)jfw!Qup8-8eAA-tL3gev*Um6QC3JGG(0BLFBV~zq_FlBz zpu+jTuBpYzp=!sJSg4OO7@%kLMTbYAcn09$0GW#fC;=X7U`+=LyWhbT{2Jjm2$Kkx z5w0LyMYx9WTZHQfzXQ;nC@U~Jf>9NuBFZx{cCZdC@XEp7TW%$~u5R6`ghM!pP8&gY z&eV_o3g^H?MqfZUi4Z~fJA?!RrcinbKsWM3!*{Sfb0KkP-{VT|#c58Ve7++JQa8De zCFzwIcDjw5rN0d_u$}?u0&enTE>7lV{+;J$?qlfG;9~fIoB0oQk(R`fLpyBb5-UE6 zhlPblH7mqHM%fQB$&?jXB90B3L6dKV@F*t^)GNBdlQG;J$Gl==0qbtcicK>tr zkes#WM%|bdAydOhLOm#e=pr5H<@`9U<=9H{413^M9R~X`k<_ATWs!Pdh)(+8*fty; zg^Vgfx5u-G%J8O@_;EEGKT*k=p0l%w=RM>gd-wTeb8B!S6W55&1Dei7n1fIUpkZu# zHhcDf9Ht&$Lk_SPk2fX%*8em1_VF*9lj@f{O4qLM8%FzXL$&mO&LR4N$HX?B_d5k$M*a{R?g+ z4S=`US2<&bz0;;X&mJ5ru0(ZoXDk|1!hvM@Pg;-Lk(&$tu`!nKkZ}s^)JxdowmeIc z_qD{EV?$W#=D&PWBwu2e{vjN{v2MtgWFg@j!590ND8wEb2`IrJRW&$n@R|pOI})R2 zaNC`;d~nwZMFu?Zc_bRq)CC^7aE96OAA0gj^^O zCeuO@$m@|lm7Zo-zhAM6>o~2FZVPGA9;U@@xM6jSgd(9> zfJR4Sa9Y|7gNty$>&*SSA`ObB#aBhaT#DdAD4#TA=e2c~#Ft-RW8f)AZemy7*c#Uz zNg)l&D4d$77p`Y+Q|Zu7b#$O%GzLeOZ3!#kzCm?(2fsSgLYS4})U+6Zhl>Q1 zZh>qMN4f#HT<_4R3lxOA1l%YzevH#iNugx|yZ)n&mN6WwAmB=7p0-hxb{~x9MX)yo* diff --git a/routes/main.py b/routes/main.py index 328db53..02fe663 100644 --- a/routes/main.py +++ b/routes/main.py @@ -1,6 +1,6 @@ from flask import render_template, Blueprint, redirect, url_for, request, flash, Response, jsonify, session from flask_login import current_user, login_required -from models import User, db, Room, RoomFile, RoomMemberPermission, SiteSettings, Event +from models import User, db, Room, RoomFile, RoomMemberPermission, SiteSettings, Event, Conversation, Message, MessageAttachment from routes.auth import require_password_change import os from werkzeug.utils import secure_filename @@ -49,7 +49,20 @@ def init_routes(main_bp): if current_user.is_admin: recent_events = Event.query.order_by(Event.timestamp.desc()).limit(7).all() else: - recent_events = Event.query.filter_by(user_id=current_user.id).order_by(Event.timestamp.desc()).limit(7).all() + # Get events where user is the actor OR events from conversations they are a member of + recent_events = Event.query.filter( + db.or_( + 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_( + db.session.query(Conversation.id) + .join(Conversation.members) + .filter(User.id == current_user.id) + ) + ) + ) + ).order_by(Event.timestamp.desc()).limit(7).all() # Room count and size logic if current_user.is_admin: @@ -253,6 +266,21 @@ def init_routes(main_bp): RoomFile.deleted==True ).group_by('extension').all() + # Get conversation statistics + if current_user.is_admin: + conversation_count = Conversation.query.count() + message_count = Message.query.count() + attachment_count = MessageAttachment.query.count() + conversation_total_size = db.session.query(db.func.sum(MessageAttachment.size)).scalar() or 0 + recent_conversations = Conversation.query.order_by(Conversation.created_at.desc()).limit(5).all() + else: + # For regular users, only show their conversations + conversation_count = Conversation.query.filter(Conversation.members.any(id=current_user.id)).count() + message_count = Message.query.join(Conversation).filter(Conversation.members.any(id=current_user.id)).count() + attachment_count = MessageAttachment.query.join(Message).join(Conversation).filter(Conversation.members.any(id=current_user.id)).count() + conversation_total_size = db.session.query(db.func.sum(MessageAttachment.size)).join(Message).join(Conversation).filter(Conversation.members.any(id=current_user.id)).scalar() or 0 + recent_conversations = Conversation.query.filter(Conversation.members.any(id=current_user.id)).order_by(Conversation.created_at.desc()).limit(5).all() + return render_template('dashboard/dashboard.html', recent_contacts=recent_contacts, active_count=active_count, @@ -260,7 +288,7 @@ def init_routes(main_bp): room_count=room_count, file_count=file_count, folder_count=folder_count, - total_size=total_size, + total_size=total_size, # Room storage size storage_by_type=storage_by_type, trash_count=trash_count, starred_count=starred_count, @@ -269,7 +297,12 @@ def init_routes(main_bp): pending_deletion=pending_deletion, trash_by_type=trash_by_type, recent_events=recent_events, - is_admin=current_user.is_admin) + is_admin=current_user.is_admin, + conversation_count=conversation_count, + message_count=message_count, + attachment_count=attachment_count, + conversation_total_size=conversation_total_size, # Conversation storage size + recent_conversations=recent_conversations) UPLOAD_FOLDER = os.path.join(os.getcwd(), 'uploads', 'profile_pics') if not os.path.exists(UPLOAD_FOLDER): diff --git a/templates/components/conversation_storage.html b/templates/components/conversation_storage.html new file mode 100644 index 0000000..aa2290d --- /dev/null +++ b/templates/components/conversation_storage.html @@ -0,0 +1,69 @@ +{% from 'common/macros.html' import format_size %} + +{% macro conversation_storage(conversation_count, message_count, attachment_count, total_size, recent_conversations) %} +
+
+
+
+
Conversation Storage
+ Browse +
+
+
+
+ + Conversations: +
+
{{ conversation_count }}
+
+
+
+ + Messages: +
+
{{ message_count }}
+
+
+
+ + Attachments: +
+
{{ attachment_count }}
+
+
+
+ + Total Size: +
+
{{ format_size(total_size) }}
+
+
+ + {% if recent_conversations %} +
+
+
Recent Activity
+
+ + {% endif %} +
+
+
+{% endmacro %} \ No newline at end of file diff --git a/templates/components/storage_usage.html b/templates/components/storage_usage.html index a90899a..a4e6211 100644 --- a/templates/components/storage_usage.html +++ b/templates/components/storage_usage.html @@ -5,7 +5,7 @@
-
Storage Usage
+
Room Storage
View Details
{% if storage_by_type %} diff --git a/templates/components/trash.html b/templates/components/trash.html index 77943da..0b95a0c 100644 --- a/templates/components/trash.html +++ b/templates/components/trash.html @@ -5,7 +5,7 @@
-
Trash Storage Overview
+
Trash Storage
View All
diff --git a/templates/dashboard/dashboard.html b/templates/dashboard/dashboard.html index d8ee6e7..4f79bb4 100644 --- a/templates/dashboard/dashboard.html +++ b/templates/dashboard/dashboard.html @@ -24,6 +24,7 @@ {% from 'components/trash.html' import trash %} {% from 'components/trash_type.html' import trash_type %} {% from 'components/recent_activity.html' import recent_activity %} +{% from 'components/conversation_storage.html' import conversation_storage %}