From caa2457c17e592587b804f21054cc000944af75c Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 14 Jul 2026 00:42:47 -0400 Subject: [PATCH] refac --- backend/open_webui/retrieval/utils.py | 27 ++++++++++++++++++- backend/open_webui/utils/middleware.py | 23 ++-------------- .../components/common/DropdownOptions.svelte | 2 +- src/lib/components/common/Select.svelte | 8 +++--- src/lib/components/playground/Chat.svelte | 7 +++-- src/routes/(app)/automations/+page.svelte | 7 +++-- 6 files changed, 39 insertions(+), 35 deletions(-) diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index 2788d4dd0c..6b21f9763c 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -37,6 +37,7 @@ from open_webui.env import ( from open_webui.models.access_grants import AccessGrants from open_webui.models.chats import Chats from open_webui.models.files import Files +from open_webui.models.folders import Folders from open_webui.models.knowledge import Knowledges from open_webui.models.notes import Notes from open_webui.models.config import Config @@ -48,6 +49,7 @@ from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT from open_webui.retrieval.vector.main import GetResult, SearchResult from open_webui.retrieval.web.utils import get_web_loader from open_webui.utils.access_control.files import has_access_to_file +from open_webui.utils.access_control.folders import has_folder_access from open_webui.utils.headers import include_user_info_headers from open_webui.utils.misc import get_message_list @@ -1323,6 +1325,25 @@ async def get_sources_from_items( bypass_embedding_and_retrieval = await Config.get('rag.bypass_embedding_and_retrieval') extracted_collections = [] query_results = [] + folder_items = set() + expanded_folders = set() + + items = list(items) + for item in items: + if item.get('type') != 'folder' or not user: + continue + folder_id = item.get('id') + if not folder_id or folder_id in expanded_folders: + continue + expanded_folders.add(folder_id) + + folder = await Folders.get_folder_by_id(folder_id) + if folder and (user.role == 'admin' or await has_folder_access(user.id, folder, 'read', db=None)): + files = (folder.data or {}).get('files', []) + folder_items.update( + (entry.get('type'), entry.get('id')) for entry in files if isinstance(entry, dict) + ) + items.extend(files) for item in items: query_result = None @@ -1429,6 +1450,7 @@ async def get_sources_from_items( user.role == 'admin' or file_object.user_id == user.id or await has_access_to_file(item.get('id'), 'read', user) + or ('file', item.get('id')) in folder_items ): query_result = { 'documents': [[file_object.data.get('content', '')]], @@ -1459,6 +1481,7 @@ async def get_sources_from_items( user.role == 'admin' or file_object.user_id == user.id or await has_access_to_file(file_id, 'read', user) + or ('file', file_id) in folder_items ): if item.get('legacy'): collection_names.append(f'{file_id}') @@ -1478,6 +1501,7 @@ async def get_sources_from_items( resource_id=knowledge_base.id, permission='read', ) + or ('collection', item.get('id')) in folder_items ): if (knowledge_base.meta or {}).get('source') == 'external': query_result = await retrieve_external_knowledge( @@ -1500,6 +1524,7 @@ async def get_sources_from_items( resource_id=knowledge_base.id, permission='read', ) + or ('collection', item.get('id')) in folder_items ): files = await Knowledges.get_files_by_id(knowledge_base.id) @@ -1570,7 +1595,7 @@ async def get_sources_from_items( continue # Filter out collections the user cannot read - if user: + if user and (item.get('type'), item.get('id')) not in folder_items: collection_names = await filter_accessible_collections(collection_names, user) if not collection_names: log.debug(f'access denied for all collections in item {item}') diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 8f26d5766f..4279d56402 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -74,7 +74,6 @@ from open_webui.socket.main import ( get_event_emitter, ) from open_webui.utils.access_control import has_connection_access, has_permission -from open_webui.utils.access_control.files import get_accessible_folder_files from open_webui.utils.access_control.folders import has_folder_access from open_webui.utils.chat import generate_chat_completion from open_webui.utils.code_interpreter import execute_code_jupyter @@ -2363,16 +2362,15 @@ async def process_chat_payload(request, form_data, user, metadata, model): if 'system_prompt' in folder.data: form_data = await apply_system_prompt_to_body(folder.data['system_prompt'], form_data, metadata, user) if 'files' in folder.data: - allowed_files = await get_accessible_folder_files(folder.data['files'], user) if metadata.get('params', {}).get('function_calling') == 'legacy': form_data['files'] = [ - *allowed_files, + {'type': 'folder', 'id': folder.id}, *form_data.get('files', []), ] else: # Native FC: skip RAG injection, builtin tools # will read folder knowledge from metadata. - metadata['folder_knowledge'] = allowed_files + metadata['folder_knowledge'] = folder.data['files'] # Model "Knowledge" handling user_message = get_last_user_message(form_data['messages']) @@ -2578,23 +2576,6 @@ async def process_chat_payload(request, form_data, user, metadata, model): # urls = extract_urls(prompt) if files: - if not files: - files = [] - - for file_item in files: - if file_item.get('type', 'file') == 'folder': - # Get folder files - folder_id = file_item.get('id', None) - if folder_id: - folder = await Folders.get_folder_by_id(folder_id) - if folder and user.role != 'admin' and not await has_folder_access( - user.id, folder, 'read', db=None - ): - folder = None - if folder and folder.data and 'files' in folder.data: - files = [f for f in files if f.get('id', None) != folder_id] - files = [*files, *await get_accessible_folder_files(folder.data['files'], user)] - # files = [*files, *[{"type": "url", "url": url, "name": url} for url in urls]] # Remove duplicate files based on their content files = list({json.dumps(f, sort_keys=True): f for f in files}.values()) diff --git a/src/lib/components/common/DropdownOptions.svelte b/src/lib/components/common/DropdownOptions.svelte index d6485f802f..a2e5053c6d 100644 --- a/src/lib/components/common/DropdownOptions.svelte +++ b/src/lib/components/common/DropdownOptions.svelte @@ -31,7 +31,7 @@ triggerClass={className ? className : 'flex shrink-0 items-center gap-2 bg-transparent px-0.5 text-sm placeholder-gray-400 outline-hidden focus:outline-hidden'} - itemClass="flex w-full gap-2 items-center px-3 py-1.5 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-xl" + itemClass="flex w-full h-[1.6875rem] gap-2 items-center rounded-xl px-2 text-[13px] cursor-pointer hover:bg-gray-50/60 dark:hover:bg-gray-800/60" onChange={(v) => { onChange(v); }} diff --git a/src/lib/components/common/Select.svelte b/src/lib/components/common/Select.svelte index 210ce03f52..1414014490 100644 --- a/src/lib/components/common/Select.svelte +++ b/src/lib/components/common/Select.svelte @@ -1,6 +1,7 @@