mirror of
https://github.com/open-webui/open-webui.git
synced 2026-09-27 17:56:26 -04:00
refac
This commit is contained in:
@@ -625,6 +625,7 @@ class KnowledgeTable:
|
||||
db=db,
|
||||
),
|
||||
breadcrumbs=await self.get_directory_breadcrumbs(
|
||||
knowledge_id,
|
||||
filter.get('directory_id') if filter else None,
|
||||
db=db,
|
||||
),
|
||||
@@ -908,6 +909,7 @@ class KnowledgeTable:
|
||||
|
||||
async def get_directory_breadcrumbs(
|
||||
self,
|
||||
knowledge_id: str,
|
||||
directory_id: Optional[str],
|
||||
db: Optional[AsyncSession] = None,
|
||||
) -> list[KnowledgeDirectoryModel]:
|
||||
@@ -922,7 +924,10 @@ class KnowledgeTable:
|
||||
|
||||
while current_id and current_id not in seen:
|
||||
seen.add(current_id)
|
||||
result = await db.execute(select(KnowledgeDirectory).filter_by(id=current_id))
|
||||
# Scoped by knowledge base so a caller-supplied id cannot walk another one's tree.
|
||||
result = await db.execute(
|
||||
select(KnowledgeDirectory).filter_by(id=current_id, knowledge_id=knowledge_id)
|
||||
)
|
||||
directory = result.scalars().first()
|
||||
if not directory:
|
||||
break
|
||||
|
||||
@@ -224,6 +224,15 @@ async def process_uploaded_file(
|
||||
f'{knowledge_id}: user {user.id} lacks write access'
|
||||
)
|
||||
else:
|
||||
directory_id = file_metadata.get('directory_id') or None
|
||||
if directory_id:
|
||||
directory = await Knowledges.get_directory_by_id(directory_id, db=db_session)
|
||||
if not directory or directory.knowledge_id != knowledge_id:
|
||||
log.warning(
|
||||
'Ignoring directory %s: not a directory of knowledge %s', directory_id, knowledge_id
|
||||
)
|
||||
directory_id = None
|
||||
|
||||
# Keep the generic file status stream open until the
|
||||
# KB-specific vector write and durable link both finish.
|
||||
await Files.update_file_data_by_id(file_item.id, {'status': 'processing'}, db=db_session)
|
||||
@@ -237,7 +246,7 @@ async def process_uploaded_file(
|
||||
knowledge_id=knowledge_id,
|
||||
file_id=file_item.id,
|
||||
user_id=user.id,
|
||||
directory_id=file_metadata.get('directory_id'),
|
||||
directory_id=directory_id,
|
||||
db=db_session,
|
||||
)
|
||||
if not knowledge_file:
|
||||
|
||||
@@ -151,6 +151,24 @@ def external_knowledge_error():
|
||||
)
|
||||
|
||||
|
||||
async def _verify_directory_in_knowledge(
|
||||
id: str,
|
||||
directory_id: str | None,
|
||||
db: AsyncSession,
|
||||
detail: str = ERROR_MESSAGES.NOT_FOUND,
|
||||
):
|
||||
"""Verify a caller-supplied directory belongs to the knowledge base in the URL. Unset means the root level."""
|
||||
if not directory_id:
|
||||
return None
|
||||
|
||||
directory = await Knowledges.get_directory_by_id(directory_id, db=db)
|
||||
if not directory or directory.knowledge_id != id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=detail,
|
||||
)
|
||||
|
||||
|
||||
@router.get('/', response_model=KnowledgeAccessListResponse)
|
||||
async def get_knowledge_bases(
|
||||
page: int | None = 1,
|
||||
@@ -1437,6 +1455,8 @@ async def add_file_to_knowledge_by_id(
|
||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
)
|
||||
|
||||
await _verify_directory_in_knowledge(id, form_data.directory_id, db, detail='Target directory not found.')
|
||||
|
||||
file = await Files.get_file_by_id(form_data.file_id, db=db)
|
||||
if not file:
|
||||
raise HTTPException(
|
||||
@@ -2049,6 +2069,9 @@ async def add_files_to_knowledge_batch(
|
||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
)
|
||||
|
||||
for directory_id in {form.directory_id for form in form_data if form.directory_id}:
|
||||
await _verify_directory_in_knowledge(id, directory_id, db, detail='Target directory not found.')
|
||||
|
||||
# Batch-fetch all files to avoid N+1 queries
|
||||
log.info('files/batch/add - %s files', len(form_data))
|
||||
file_ids = [form.file_id for form in form_data]
|
||||
@@ -2237,6 +2260,8 @@ async def create_knowledge_directory(
|
||||
):
|
||||
await _verify_knowledge_write_access(id, user, db)
|
||||
|
||||
await _verify_directory_in_knowledge(id, form_data.parent_id, db, detail='Parent directory not found.')
|
||||
|
||||
directory = await Knowledges.create_directory(
|
||||
knowledge_id=id,
|
||||
name=form_data.name,
|
||||
@@ -2269,14 +2294,11 @@ async def update_knowledge_directory(
|
||||
db: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
await _verify_knowledge_write_access(id, user, db)
|
||||
await _verify_directory_in_knowledge(id, dir_id, db)
|
||||
|
||||
# Verify directory belongs to this knowledge base
|
||||
directory = await Knowledges.get_directory_by_id(dir_id, db=db)
|
||||
if not directory or directory.knowledge_id != id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=ERROR_MESSAGES.NOT_FOUND,
|
||||
)
|
||||
# '__unset__' leaves the parent alone, None moves the directory to the root
|
||||
if form_data.parent_id not in (None, '__unset__'):
|
||||
await _verify_directory_in_knowledge(id, form_data.parent_id, db, detail='Parent directory not found.')
|
||||
|
||||
result = await Knowledges.update_directory(
|
||||
directory_id=dir_id,
|
||||
@@ -2309,14 +2331,7 @@ async def delete_knowledge_directory(
|
||||
db: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
await _verify_knowledge_write_access(id, user, db)
|
||||
|
||||
# Verify directory belongs to this knowledge base
|
||||
directory = await Knowledges.get_directory_by_id(dir_id, db=db)
|
||||
if not directory or directory.knowledge_id != id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=ERROR_MESSAGES.NOT_FOUND,
|
||||
)
|
||||
await _verify_directory_in_knowledge(id, dir_id, db)
|
||||
|
||||
# Collect before delete_directory drops the KnowledgeFile rows
|
||||
files = [] if move_files else await Knowledges.get_files_by_id_and_directory_id(id, dir_id, db=db)
|
||||
@@ -2375,14 +2390,7 @@ async def move_file_in_knowledge(
|
||||
detail=ERROR_MESSAGES.NOT_FOUND,
|
||||
)
|
||||
|
||||
# If target directory is set, verify it belongs to this knowledge base
|
||||
if form_data.directory_id:
|
||||
directory = await Knowledges.get_directory_by_id(form_data.directory_id, db=db)
|
||||
if not directory or directory.knowledge_id != id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail='Target directory not found.',
|
||||
)
|
||||
await _verify_directory_in_knowledge(id, form_data.directory_id, db, detail='Target directory not found.')
|
||||
|
||||
success = await Knowledges.move_file_to_directory(
|
||||
knowledge_id=id,
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
import { createMessagesList } from '$lib/utils';
|
||||
import { getOutputText } from '$lib/components/chat/Messages/structuredOutput';
|
||||
import { config, user, chatId as currentChatId, tags } from '$lib/stores';
|
||||
import { refreshChatList } from '$lib/stores/chatList';
|
||||
import { refreshSidebar } from '$lib/stores/chatList';
|
||||
import Messages from '../chat/Messages.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import EditPencilIcon from './Sidebar/icons/EditPencil.svelte';
|
||||
@@ -65,10 +65,6 @@
|
||||
};
|
||||
let generating = false;
|
||||
|
||||
const refreshSidebar = async () => {
|
||||
await refreshChatList(localStorage.token, { refreshPinned: true });
|
||||
};
|
||||
|
||||
const cloneChatHandler = async (id) => {
|
||||
const chat = chatList?.find((c) => c.id === id);
|
||||
const res = await cloneChatById(
|
||||
@@ -83,7 +79,7 @@
|
||||
});
|
||||
|
||||
if (res) {
|
||||
await refreshSidebar();
|
||||
await refreshSidebar(localStorage.token);
|
||||
await searchHandler();
|
||||
}
|
||||
};
|
||||
@@ -95,7 +91,7 @@
|
||||
});
|
||||
|
||||
if (res) {
|
||||
await refreshSidebar();
|
||||
await refreshSidebar(localStorage.token);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -110,7 +106,7 @@
|
||||
currentChatId.set('');
|
||||
}
|
||||
|
||||
await refreshSidebar();
|
||||
await refreshSidebar(localStorage.token);
|
||||
toast.success(res?.archived ? $i18n.t('Chat archived.') : $i18n.t('Chat unarchived.'));
|
||||
} catch (error) {
|
||||
toast.error($i18n.t('Failed to archive chat.'));
|
||||
@@ -132,7 +128,7 @@
|
||||
currentChatId.set('');
|
||||
}
|
||||
|
||||
await refreshSidebar();
|
||||
await refreshSidebar(localStorage.token);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -147,7 +143,7 @@
|
||||
|
||||
if (res) {
|
||||
chatList = chatList?.filter((c) => c.id !== chatId) ?? null;
|
||||
await refreshSidebar();
|
||||
await refreshSidebar(localStorage.token);
|
||||
toast.success($i18n.t('Chat moved successfully'));
|
||||
}
|
||||
}
|
||||
@@ -182,7 +178,7 @@
|
||||
|
||||
editingChatId = null;
|
||||
editingChatTitle = '';
|
||||
await refreshSidebar();
|
||||
await refreshSidebar(localStorage.token);
|
||||
};
|
||||
|
||||
const cancelRename = () => {
|
||||
@@ -841,7 +837,7 @@
|
||||
}}
|
||||
onClose={() => {}}
|
||||
onPinChange={async () => {
|
||||
await refreshSidebar();
|
||||
await refreshSidebar(localStorage.token);
|
||||
await searchHandler();
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
settings,
|
||||
user
|
||||
} from '$lib/stores';
|
||||
import { refreshChatList } from '$lib/stores/chatList';
|
||||
import { refreshChatList, refreshSidebar } from '$lib/stores/chatList';
|
||||
|
||||
import ChatMenu from './ChatMenu.svelte';
|
||||
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||
@@ -241,7 +241,7 @@
|
||||
if (res) {
|
||||
goto(`/c/${res.id}`);
|
||||
|
||||
await refreshChatList(localStorage.token, { refreshPinned: true });
|
||||
await refreshSidebar(localStorage.token);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user