From 45a1bc07c6eb43aa025a9092afb35e02737fc5ad Mon Sep 17 00:00:00 2001 From: Kobe Date: Sat, 31 May 2025 12:24:48 +0200 Subject: [PATCH] search inside folders --- routes/__pycache__/main.cpython-313.pyc | Bin 47659 -> 47659 bytes routes/__pycache__/room_files.cpython-313.pyc | Bin 47025 -> 47799 bytes routes/room_files.py | 27 ++++++++++++--- static/js/rooms/searchManager.js | 31 +++++++++++------- static/js/rooms/viewManager.js | 14 ++++++-- 5 files changed, 54 insertions(+), 18 deletions(-) diff --git a/routes/__pycache__/main.cpython-313.pyc b/routes/__pycache__/main.cpython-313.pyc index 48f270daa90031e3c66597f46a7cec08bb4f23c5..249de6acd5b5f8ced44d611a9be06ec297b034fe 100644 GIT binary patch delta 21 bcmZ4eg=zH{Ca%xCyj%=Gpn78?m*Oq}Rx<|o delta 21 bcmZ4eg=zH{Ca%xCyj%=Gu;}_mF2!8{SsVv* diff --git a/routes/__pycache__/room_files.cpython-313.pyc b/routes/__pycache__/room_files.cpython-313.pyc index d4ac50d493b9024b3ac817790911da602d5aa1c6..4e92dc21c60d3d5ae9800b46eaf738487e347dbb 100644 GIT binary patch delta 1227 zcmZ8hUrbw77(a)$x3s-2m3xcO7JDhsmdPK%Ie|fB8I+j-%jjwfWWx>$t?4fG76z0| z*rs9AA>eVL;scbBz?%jBpar4g%-JVvf26)^_)%pY1HgtTCMu({k&%J--$Xg#pmfm&r<_8v;qV^ct z`q<9MDgZBc%NWoMkHrAs6>bH(|1OK}Tv91a0PHhL2V4|hUWl=1_PktvT(eK)Jmo1) z@8TQ?^dCasj?4INTfH z`?3lE>^8wmFLgfQ9|DM#7;M_aj(z>uFC^7{e;*Ebvta)aI>e^@PyV(-Ej zfo=jJ3{K%^jBUaNvT>2XB?4~|cpF2B8Z}HAkYj<#zNaF-x`{90Jz}z;iq|dZc7LHh zLgeoga1oe7u>~{wYQ~}`oh3vG$T5_tkjZbA2`ohBSuX#Xu+J;>_`8LHfwSG|e1sfa zlv3OR;VrZ|Re=`#j)^A}&>CjiuCyiT0*NkIaU`u(lC^5RS+XAf!jr6TmFipX4omeX zw`q5h?vUt?ZMti+DW%g-Hvg{8z6^Iu%i_+sb2c=8ZtmQyKk8kAt5l4Nj!LZK7W|s} zjJmAa)#&G)bI$pexfay6t+6io;uF^=wksNbny@vb3W^i-bE!gmg62|L`kBZ~Bvou% z?TmFMi>syL>V)39!x*ELi?tutE{(4@CYc(EsY$W6wZe6HQ@x>1zR)P)=Rl*xHYQlx zPE*U>6W@1!)0yaaBM}@-Hie|7&{AkM5{o45M}Dv$NsNpq^hLWggVRRp!1D@AWy(>9 zUJY2dRK9J;WM8X{*IloZOfNq+Xw165fkvD4*aURUlY`<|pe~cj#bp%o(CyG~PnRn~ zKyAglr$}+nBCoRmm5=Grnl}rX*YiX^>`^H2z2I+38aT0VgOJ)Jw(rRGh<{8_H7YElz(_s>I^YmpzbL#J`d7I2N14 z7gv5&Wf@6e%eWQp!2>6SBE)_25auI&d<*_4{t`bg!=y``q(~bGR&-xJhPKEL{D|f%ZDmB|NZlN3=}r5gMOKDc zRJu2r{xPVuh`{L$hx9`u=vM?wYGMR^(XT*Ft-qZsbbdVV^StkK&UxQAzDZ55P`Y)k zHU*J$ZhKjPj!f&qXW`vbHC04|Z{H}`T4Gc&hJ(+xK?kQc(gi52@X|c0OCS_xnsT6X z)C95CEDeQFy#pbyqQM3}p2rNS2vFg-Kz}RGH8N#Q2>Cc-U;w)X_7HAl2|aQ}phz%| zWisZi+E=p)Cfj&u9%9H7M!x`4&(-k7&qAu7hw)OYiriFsnTC8wwDD=Gd}T3~yGJMs z)h{BXA@O7(oDZ02b!WN0Li zYk^nom25=T1F#TDx80ZNhzwh%sLW)is34Hb!s(y`HYSbmD9ERnNHck46&K8~5IkP> zgA?v~20cm6p5W|{cO)Iogu@xDO*r;0a;_v-p5V$CxyrukC7q$K_LDaCCSKAQqBX-c zQTMPLJRdZUB`}0`3nhEv!FX`A^Fhy8PtxXmZ*wlRKy}DwT+^$px<5#z)vqx~$8VUW z{*X(>rja(pba>PC{Xd=RZfEQy>y|PvzF;)V>bCAs=uC&ND*zvROYpFyz2suC1?DHx zB;U0Y7{{cS*BK@ITOOv43{xO&-tw!kRXPPl8eA_$#`BceBF#@UVdY(#n0hf39?OtQ zpL|y9E%N^l$$FOY&ZA;B$%E0|{9;@8r*naea0&9i;1ye-iVKWA(3RcTlJ7Z$A8 Yx=tg?AjAGu1(B;R7@EtF4$Ot|KmFj(UjP6A diff --git a/routes/room_files.py b/routes/room_files.py index a836d0b..72849b0 100644 --- a/routes/room_files.py +++ b/routes/room_files.py @@ -557,32 +557,49 @@ def download_zip(room_id): @login_required def search_room_files(room_id): """ - Search for files in a room by name. + Search for files in a room by name, including files in subfolders. Args: room_id (int): ID of the room to search in Returns: - JSON response containing matching files + JSON response containing matching files with their full paths """ room = Room.query.get_or_404(room_id) if not user_has_permission(room, 'can_view'): abort(403) query = request.args.get('query', '').strip().lower() + # Search RoomFile for this room - files = RoomFile.query.filter(RoomFile.room_id==room_id).all() + files = RoomFile.query.filter(RoomFile.room_id==room_id, RoomFile.deleted==False).all() matches = [] + for f in files: - if query in f.name.lower(): + # Create full path by combining folder path and filename + full_path = f"{f.path}/{f.name}" if f.path else f.name + + if query in f.name.lower() or query in full_path.lower(): + uploader_full_name = None + uploader_profile_pic = None + if f.uploader: + uploader_full_name = f.uploader.username + if getattr(f.uploader, 'last_name', None): + uploader_full_name += ' ' + f.uploader.last_name + uploader_profile_pic = f.uploader.profile_picture if getattr(f.uploader, 'profile_picture', None) else None + matches.append({ 'name': f.name, 'type': f.type, 'size': f.size if f.type == 'file' else '-', 'modified': f.modified, - 'uploaded_by': f.uploader.username if f.uploader else None, + 'uploaded_by': uploader_full_name, + 'uploader_profile_pic': uploader_profile_pic, 'uploaded_at': f.uploaded_at.isoformat() if f.uploaded_at else None, 'path': f.path, + 'full_path': full_path, # Add full path to the response + 'starred': current_user in f.starred_by }) + return jsonify(matches) @room_files_bp.route('//move', methods=['POST']) diff --git a/static/js/rooms/searchManager.js b/static/js/rooms/searchManager.js index 2da39b1..f72aa74 100644 --- a/static/js/rooms/searchManager.js +++ b/static/js/rooms/searchManager.js @@ -22,6 +22,7 @@ export class SearchManager { this.roomManager = roomManager; this.searchInput = document.getElementById('quickSearchInput'); this.clearSearchBtn = document.getElementById('clearSearchBtn'); + this.isSearching = false; } /** @@ -35,9 +36,11 @@ export class SearchManager { // Create debounced search function const debouncedSearch = this.debounce((searchTerm) => { if (searchTerm) { + this.isSearching = true; this.performSearch(searchTerm); this.clearSearchBtn.style.display = 'block'; } else { + this.isSearching = false; this.roomManager.fileManager.fetchFiles(); // Reset to show all files this.clearSearchBtn.style.display = 'none'; } @@ -53,6 +56,7 @@ export class SearchManager { if (this.clearSearchBtn) { this.clearSearchBtn.addEventListener('click', () => { this.searchInput.value = ''; + this.isSearching = false; this.roomManager.fileManager.fetchFiles(); // Reset to show all files this.clearSearchBtn.style.display = 'none'; }); @@ -60,20 +64,25 @@ export class SearchManager { } /** - * Performs the search operation on the current file list. - * Filters files based on name and type matching the search term. + * Performs the search operation using the server-side search endpoint. * @param {string} searchTerm - The term to search for */ performSearch(searchTerm) { - if (!this.roomManager.fileManager.currentFiles) return; - - const filteredFiles = this.roomManager.fileManager.currentFiles.filter(file => { - const searchLower = searchTerm.toLowerCase(); - return file.name.toLowerCase().includes(searchLower) || - (file.type && file.type.toLowerCase().includes(searchLower)); - }); - - this.roomManager.viewManager.renderFiles(filteredFiles); + // Fetch all files from the server for searching + fetch(`/api/rooms/${this.roomManager.roomId}/search?query=${encodeURIComponent(searchTerm)}`) + .then(response => response.json()) + .then(files => { + // Modify the file objects to show full paths in search results + const modifiedFiles = files.map(file => ({ + ...file, + displayName: this.isSearching ? file.full_path : file.name + })); + + this.roomManager.viewManager.renderFiles(modifiedFiles); + }) + .catch(error => { + console.error('Error performing search:', error); + }); } /** diff --git a/static/js/rooms/viewManager.js b/static/js/rooms/viewManager.js index 8253353..2b33d2e 100644 --- a/static/js/rooms/viewManager.js +++ b/static/js/rooms/viewManager.js @@ -255,6 +255,11 @@ export class ViewManager { const size = isFolder ? '-' : this.formatFileSize(file.size); const modified = new Date(file.modified).toLocaleString(); + // Create file name element + const name = document.createElement('span'); + name.className = 'file-name'; + name.textContent = file.displayName || file.name; + return ` - ${file.name} + ${name.outerHTML} ${size} ${modified} @@ -294,6 +299,11 @@ export class ViewManager { const size = isFolder ? '-' : this.formatFileSize(file.size); const modified = new Date(file.modified).toLocaleString(); + // Create file name element + const name = document.createElement('span'); + name.className = 'file-name'; + name.textContent = file.displayName || file.name; + return `
-
${file.name}
+
${name.outerHTML}
${modified}
${size}