From 7d4747dfd73d7629227b10ae63c6854cc7543bee Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 20 Aug 2026 13:13:51 -0700 Subject: [PATCH] refac --- backend/open_webui/config.py | 3 +- backend/open_webui/env.py | 1 + backend/open_webui/models/chats.py | 37 ++++++++++++++++++++++++ backend/open_webui/routers/chats.py | 44 +++++++++-------------------- 4 files changed, 52 insertions(+), 33 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 75b4b6d284..33d3840e28 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -19,6 +19,7 @@ from pydantic import BaseModel from open_webui.env import ( DATA_DIR, DATABASE_URL, + ENABLE_ADMIN_CHAT_ACCESS, ENABLE_DB_MIGRATIONS, ENV, FRONTEND_BUILD_DIR, @@ -2085,8 +2086,6 @@ BYPASS_ADMIN_ACCESS_CONTROL = ( == 'true' ) -ENABLE_ADMIN_CHAT_ACCESS = os.getenv('ENABLE_ADMIN_CHAT_ACCESS', 'True').lower() == 'true' - ENABLE_ADMIN_ANALYTICS = os.getenv('ENABLE_ADMIN_ANALYTICS', 'True').lower() == 'true' ENABLE_COMMUNITY_SHARING = os.getenv('ENABLE_COMMUNITY_SHARING', 'True').lower() == 'true' diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index 6cdc35ad57..3d3ab02c51 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -365,6 +365,7 @@ ENABLE_PUBLIC_ACTIVE_USERS_COUNT = os.getenv('ENABLE_PUBLIC_ACTIVE_USERS_COUNT', RESET_CONFIG_ON_START = os.getenv('RESET_CONFIG_ON_START', 'False').lower() == 'true' ENABLE_REALTIME_CHAT_SAVE = os.getenv('ENABLE_REALTIME_CHAT_SAVE', 'False').lower() == 'true' ENABLE_QUERIES_CACHE = os.getenv('ENABLE_QUERIES_CACHE', 'False').lower() == 'true' +ENABLE_ADMIN_CHAT_ACCESS = os.getenv('ENABLE_ADMIN_CHAT_ACCESS', 'True').lower() == 'true' RAG_SYSTEM_CONTEXT = os.getenv('RAG_SYSTEM_CONTEXT', 'False').lower() == 'true' #################################### diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index 9854af6d3a..f373b30580 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -8,7 +8,9 @@ import time import uuid # local imports +from open_webui.env import ENABLE_ADMIN_CHAT_ACCESS from open_webui.internal.db import Base, JSONField, get_async_db_context +from open_webui.models.access_grants import AccessGrants from open_webui.models.automations import AutomationRun from open_webui.models.chat_messages import ChatMessage, ChatMessages from open_webui.models.folders import Folders @@ -1634,6 +1636,41 @@ class ChatTable: except Exception: return None + async def get_chat_by_id_for_user( + self, + id: str, + user, + db: AsyncSession | None = None, + ) -> ChatModel | None: + chat = await self.get_chat_by_id_and_user_id(id, user.id, db=db) + if chat: + return chat + + chat = await self.get_chat_by_id(id, db=db) + if not chat: + return None + + if user.role == 'admin' and (ENABLE_ADMIN_CHAT_ACCESS or is_internal_chat(chat.meta)): + return chat + + if await AccessGrants.has_access( + user_id=user.id, + resource_type='shared_chat', + resource_id=id, + permission='read', + db=db, + ): + return chat + + if chat.folder_id: + from open_webui.utils.access_control.folders import has_folder_access + + folder = await Folders.get_folder_by_id(chat.folder_id, db=db) + if folder and await has_folder_access(user.id, folder, 'read', db): + return chat + + return None + async def is_chat_owner(self, id: str, user_id: str, db: AsyncSession | None = None) -> bool: """ Lightweight ownership check — uses EXISTS subquery instead of loading diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 549c26217b..c5e1ff3c43 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -27,7 +27,6 @@ from open_webui.models.chats import ( MessageStats, chat_search_content_query, chat_search_terms, - is_internal_chat, ) from open_webui.models.config import Config from open_webui.models.folders import Folders @@ -36,7 +35,7 @@ from open_webui.models.tags import TagModel, Tags from open_webui.socket.main import get_event_emitter from open_webui.tasks import get_response_streams_by_chat_id, has_active_tasks, stop_item_tasks from open_webui.utils.access_control import filter_allowed_access_grants, has_permission -from open_webui.utils.access_control.folders import has_folder_access, has_folder_write_access +from open_webui.utils.access_control.folders import has_folder_write_access from open_webui.utils.auth import bearer_security, get_admin_user, get_current_user, get_verified_user from open_webui.utils.chat_fork import build_fork_history from open_webui.utils.context_compaction import compact_chat_branch, get_chat_context_usage @@ -1329,33 +1328,11 @@ async def get_chat_by_id( user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session), ): - chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db) - - if not chat and user.role == 'admin': - candidate = await Chats.get_chat_by_id(id, db=db) - if ENABLE_ADMIN_CHAT_ACCESS or (candidate and is_internal_chat(candidate.meta)): - chat = candidate - - # Access explicitly granted to this user applies to admins too, so an admin - # does not lose a chat shared with them when ENABLE_ADMIN_CHAT_ACCESS is off. - if not chat: - has_grant = await AccessGrants.has_access( - user_id=user.id, - resource_type='shared_chat', - resource_id=id, - permission='read', - db=db, - ) - if has_grant: - chat = await Chats.get_chat_by_id(id, db=db) - - # Check folder-based access (shared folders) - if not chat: - candidate = await Chats.get_chat_by_id(id, db=db) - if candidate and candidate.folder_id: - folder = await Folders.get_folder_by_id(candidate.folder_id, db=db) - if folder and await has_folder_access(user.id, folder, 'read', db): - chat = candidate + chat = await Chats.get_chat_by_id_for_user( + id, + user, + db=db, + ) if chat: data = ChatResponse.model_validate(chat, from_attributes=True).model_dump() @@ -2177,10 +2154,15 @@ async def update_chat_folder_id_by_id( @router.get('/{id}/tags', response_model=list[TagModel]) async def get_chat_tags_by_id(id: str, user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)): - chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db) + chat = await Chats.get_chat_by_id_for_user( + id, + user, + db=db, + ) + if chat: tags = chat.meta.get('tags', []) - return await Tags.get_tags_by_ids_and_user_id(tags, user.id, db=db) + return await Tags.get_tags_by_ids_and_user_id(tags, chat.user_id, db=db) else: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND)