From 412923dc915065fd264228ad18db7991db88b7dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20Pyykk=C3=B6nen?= Date: Thu, 23 Jan 2025 16:16:50 +0200 Subject: [PATCH 1/8] feat: separate cookie settings between session & auth cookies Introducing two new env config options to control cookies settings regarding authentication. These values are taken into use when setting 'token' and 'oauth_id_token'. To maintain backwards compatibility, the original session cookie values are used as fallback. Separation is done to prevent issues with the session cookie. When the config value was set as 'strict', the oauth flow was broken (since the session cookie was not provided after the callback). Providing a separate config for auth & session cookies allows us to keep the 'strict' settings for auth related cookies, while also allowing the session cookie to behave as intended (e.g., by configuring it as 'lax'). The original config was added in commit #af4f8aa. However a later commit #a2e889c reused this config option for other type of cookies, which was not the original intent. --- backend/open_webui/env.py | 17 +++++++++-------- backend/open_webui/routers/auths.py | 16 ++++++++-------- backend/open_webui/utils/oauth.py | 10 +++++----- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index 77e632ccc..b589e9490 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -356,15 +356,16 @@ WEBUI_SECRET_KEY = os.environ.get( ), # DEPRECATED: remove at next major version ) -WEBUI_SESSION_COOKIE_SAME_SITE = os.environ.get( - "WEBUI_SESSION_COOKIE_SAME_SITE", - os.environ.get("WEBUI_SESSION_COOKIE_SAME_SITE", "lax"), -) +WEBUI_SESSION_COOKIE_SAME_SITE = os.environ.get("WEBUI_SESSION_COOKIE_SAME_SITE", "lax") -WEBUI_SESSION_COOKIE_SECURE = os.environ.get( - "WEBUI_SESSION_COOKIE_SECURE", - os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false").lower() == "true", -) +WEBUI_SESSION_COOKIE_SECURE = os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false").lower() == "true" + +WEBUI_AUTH_COOKIE_SAME_SITE = os.environ.get("WEBUI_AUTH_COOKIE_SAME_SITE", WEBUI_SESSION_COOKIE_SAME_SITE) + +WEBUI_AUTH_COOKIE_SECURE = os.environ.get( + "WEBUI_AUTH_COOKIE_SECURE", + os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false") +).lower() == "true" if WEBUI_AUTH and WEBUI_SECRET_KEY == "": raise ValueError(ERROR_MESSAGES.ENV_VAR_NOT_FOUND) diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index 47baeb0ac..d7c4fa013 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -25,8 +25,8 @@ from open_webui.env import ( WEBUI_AUTH, WEBUI_AUTH_TRUSTED_EMAIL_HEADER, WEBUI_AUTH_TRUSTED_NAME_HEADER, - WEBUI_SESSION_COOKIE_SAME_SITE, - WEBUI_SESSION_COOKIE_SECURE, + WEBUI_AUTH_COOKIE_SAME_SITE, + WEBUI_AUTH_COOKIE_SECURE, SRC_LOG_LEVELS, ) from fastapi import APIRouter, Depends, HTTPException, Request, status @@ -95,8 +95,8 @@ async def get_session_user( value=token, expires=datetime_expires_at, httponly=True, # Ensures the cookie is not accessible via JavaScript - samesite=WEBUI_SESSION_COOKIE_SAME_SITE, - secure=WEBUI_SESSION_COOKIE_SECURE, + samesite=WEBUI_AUTH_COOKIE_SAME_SITE, + secure=WEBUI_AUTH_COOKIE_SECURE, ) user_permissions = get_permissions( @@ -378,8 +378,8 @@ async def signin(request: Request, response: Response, form_data: SigninForm): value=token, expires=datetime_expires_at, httponly=True, # Ensures the cookie is not accessible via JavaScript - samesite=WEBUI_SESSION_COOKIE_SAME_SITE, - secure=WEBUI_SESSION_COOKIE_SECURE, + samesite=WEBUI_AUTH_COOKIE_SAME_SITE, + secure=WEBUI_AUTH_COOKIE_SECURE, ) user_permissions = get_permissions( @@ -473,8 +473,8 @@ async def signup(request: Request, response: Response, form_data: SignupForm): value=token, expires=datetime_expires_at, httponly=True, # Ensures the cookie is not accessible via JavaScript - samesite=WEBUI_SESSION_COOKIE_SAME_SITE, - secure=WEBUI_SESSION_COOKIE_SECURE, + samesite=WEBUI_AUTH_COOKIE_SAME_SITE, + secure=WEBUI_AUTH_COOKIE_SECURE, ) if request.app.state.config.WEBHOOK_URL: diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index 1ae6d4aa7..b336f0631 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -35,7 +35,7 @@ from open_webui.config import ( AppConfig, ) from open_webui.constants import ERROR_MESSAGES, WEBHOOK_MESSAGES -from open_webui.env import WEBUI_SESSION_COOKIE_SAME_SITE, WEBUI_SESSION_COOKIE_SECURE +from open_webui.env import WEBUI_AUTH_COOKIE_SAME_SITE, WEBUI_AUTH_COOKIE_SECURE from open_webui.utils.misc import parse_duration from open_webui.utils.auth import get_password_hash, create_token from open_webui.utils.webhook import post_webhook @@ -323,8 +323,8 @@ class OAuthManager: key="token", value=jwt_token, httponly=True, # Ensures the cookie is not accessible via JavaScript - samesite=WEBUI_SESSION_COOKIE_SAME_SITE, - secure=WEBUI_SESSION_COOKIE_SECURE, + samesite=WEBUI_AUTH_COOKIE_SAME_SITE, + secure=WEBUI_AUTH_COOKIE_SECURE, ) if ENABLE_OAUTH_SIGNUP.value: @@ -333,8 +333,8 @@ class OAuthManager: key="oauth_id_token", value=oauth_id_token, httponly=True, - samesite=WEBUI_SESSION_COOKIE_SAME_SITE, - secure=WEBUI_SESSION_COOKIE_SECURE, + samesite=WEBUI_AUTH_COOKIE_SAME_SITE, + secure=WEBUI_AUTH_COOKIE_SECURE, ) # Redirect back to the frontend with the JWT token redirect_url = f"{request.base_url}auth#token={jwt_token}" From dda945f4ad0c1482fd3ac0e8e55f7817b50ffaf4 Mon Sep 17 00:00:00 2001 From: Sharon Fox Date: Sun, 26 Jan 2025 02:44:26 -0500 Subject: [PATCH 2/8] feat: Localized dates and times --- src/lib/components/admin/Users/UserList.svelte | 4 +++- .../components/admin/Users/UserList/EditUserModal.svelte | 4 +++- .../components/admin/Users/UserList/UserChatsModal.svelte | 4 +++- src/lib/components/channel/Messages/Message.svelte | 8 +++++--- .../components/chat/Messages/MultiResponseMessages.svelte | 4 +++- src/lib/components/chat/Messages/ResponseMessage.svelte | 2 +- src/lib/components/chat/Messages/UserMessage.svelte | 4 +++- .../chat/Settings/Personalization/ManageModal.svelte | 6 +++--- .../components/layout/Sidebar/ArchivedChatsModal.svelte | 5 ++++- src/lib/utils/index.ts | 8 +++++--- src/routes/s/[id]/+page.svelte | 4 +++- 11 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/lib/components/admin/Users/UserList.svelte b/src/lib/components/admin/Users/UserList.svelte index 2ee4297a4..ce730571f 100644 --- a/src/lib/components/admin/Users/UserList.svelte +++ b/src/lib/components/admin/Users/UserList.svelte @@ -6,7 +6,9 @@ import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; + import localizedFormat from 'dayjs/plugin/localizedFormat'; dayjs.extend(relativeTime); + dayjs.extend(localizedFormat); import { toast } from 'svelte-sonner'; @@ -364,7 +366,7 @@ - {dayjs(user.created_at * 1000).format($i18n.t('MMMM DD, YYYY'))} + {dayjs(user.created_at * 1000).format('LL')} {user.oauth_sub ?? ''} diff --git a/src/lib/components/admin/Users/UserList/EditUserModal.svelte b/src/lib/components/admin/Users/UserList/EditUserModal.svelte index 868951d57..9b2edb407 100644 --- a/src/lib/components/admin/Users/UserList/EditUserModal.svelte +++ b/src/lib/components/admin/Users/UserList/EditUserModal.svelte @@ -7,9 +7,11 @@ import { updateUserById } from '$lib/apis/users'; import Modal from '$lib/components/common/Modal.svelte'; + import localizedFormat from 'dayjs/plugin/localizedFormat'; const i18n = getContext('i18n'); const dispatch = createEventDispatcher(); + dayjs.extend(localizedFormat); export let show = false; export let selectedUser; @@ -87,7 +89,7 @@
{$i18n.t('Created at')} - {dayjs(selectedUser.created_at * 1000).format($i18n.t('MMMM DD, YYYY'))} + {dayjs(selectedUser.created_at * 1000).format('LL')}
diff --git a/src/lib/components/admin/Users/UserList/UserChatsModal.svelte b/src/lib/components/admin/Users/UserList/UserChatsModal.svelte index 92970b658..a95df8291 100644 --- a/src/lib/components/admin/Users/UserList/UserChatsModal.svelte +++ b/src/lib/components/admin/Users/UserList/UserChatsModal.svelte @@ -2,8 +2,10 @@ import { toast } from 'svelte-sonner'; import dayjs from 'dayjs'; import { getContext, createEventDispatcher } from 'svelte'; + import localizedFormat from 'dayjs/plugin/localizedFormat'; const dispatch = createEventDispatcher(); + dayjs.extend(localizedFormat); import { getChatListByUserId, deleteChatById, getArchivedChatList } from '$lib/apis/chats'; @@ -130,7 +132,7 @@
- {dayjs(chat.updated_at * 1000).format($i18n.t('MMMM DD, YYYY HH:mm'))} + {dayjs(chat.updated_at * 1000).format('LLL')}
diff --git a/src/lib/components/channel/Messages/Message.svelte b/src/lib/components/channel/Messages/Message.svelte index ef17feb7f..a84077823 100644 --- a/src/lib/components/channel/Messages/Message.svelte +++ b/src/lib/components/channel/Messages/Message.svelte @@ -3,10 +3,12 @@ import relativeTime from 'dayjs/plugin/relativeTime'; import isToday from 'dayjs/plugin/isToday'; import isYesterday from 'dayjs/plugin/isYesterday'; + import localizedFormat from 'dayjs/plugin/localizedFormat'; dayjs.extend(relativeTime); dayjs.extend(isToday); dayjs.extend(isYesterday); + dayjs.extend(localizedFormat); import { getContext, onMount } from 'svelte'; const i18n = getContext>('i18n'); @@ -154,9 +156,9 @@ class="mt-1.5 flex flex-shrink-0 items-center text-xs self-center invisible group-hover:visible text-gray-500 font-medium first-letter:capitalize" > - {dayjs(message.created_at / 1000000).format('HH:mm')} + {dayjs(message.created_at / 1000000).format('LT')} {/if} @@ -175,7 +177,7 @@ class=" self-center text-xs invisible group-hover:visible text-gray-400 font-medium first-letter:capitalize ml-0.5 translate-y-[1px]" > {formatDate(message.created_at / 1000000)} diff --git a/src/lib/components/chat/Messages/MultiResponseMessages.svelte b/src/lib/components/chat/Messages/MultiResponseMessages.svelte index e7874df63..ad42c0f26 100644 --- a/src/lib/components/chat/Messages/MultiResponseMessages.svelte +++ b/src/lib/components/chat/Messages/MultiResponseMessages.svelte @@ -16,7 +16,9 @@ import Markdown from './Markdown.svelte'; import Name from './Name.svelte'; import Skeleton from './Skeleton.svelte'; + import localizedFormat from 'dayjs/plugin/localizedFormat'; const i18n = getContext('i18n'); + dayjs.extend(localizedFormat); export let chatId; export let history; @@ -264,7 +266,7 @@ {/if} diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index 1768d584d..d6b31e6a0 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -500,7 +500,7 @@ diff --git a/src/lib/components/chat/Messages/UserMessage.svelte b/src/lib/components/chat/Messages/UserMessage.svelte index db1d31548..bf22e558a 100644 --- a/src/lib/components/chat/Messages/UserMessage.svelte +++ b/src/lib/components/chat/Messages/UserMessage.svelte @@ -13,8 +13,10 @@ import FileItem from '$lib/components/common/FileItem.svelte'; import Markdown from './Markdown.svelte'; import Image from '$lib/components/common/Image.svelte'; + import localizedFormat from 'dayjs/plugin/localizedFormat'; const i18n = getContext('i18n'); + dayjs.extend(localizedFormat); export let user; @@ -112,7 +114,7 @@ diff --git a/src/lib/components/chat/Settings/Personalization/ManageModal.svelte b/src/lib/components/chat/Settings/Personalization/ManageModal.svelte index e4613b5fe..a9f72ccbb 100644 --- a/src/lib/components/chat/Settings/Personalization/ManageModal.svelte +++ b/src/lib/components/chat/Settings/Personalization/ManageModal.svelte @@ -11,8 +11,10 @@ import Tooltip from '$lib/components/common/Tooltip.svelte'; import { error } from '@sveltejs/kit'; import EditMemoryModal from './EditMemoryModal.svelte'; + import localizedFormat from 'dayjs/plugin/localizedFormat'; const i18n = getContext('i18n'); + dayjs.extend(localizedFormat); export let show = false; @@ -84,9 +86,7 @@
- {dayjs(memory.updated_at * 1000).format( - $i18n.t('MMMM DD, YYYY hh:mm:ss A') - )} + {dayjs(memory.updated_at * 1000).format('LLL')}
diff --git a/src/lib/components/layout/Sidebar/ArchivedChatsModal.svelte b/src/lib/components/layout/Sidebar/ArchivedChatsModal.svelte index 6626cfed7..7af0c6ded 100644 --- a/src/lib/components/layout/Sidebar/ArchivedChatsModal.svelte +++ b/src/lib/components/layout/Sidebar/ArchivedChatsModal.svelte @@ -4,6 +4,9 @@ import { toast } from 'svelte-sonner'; import dayjs from 'dayjs'; import { getContext, createEventDispatcher } from 'svelte'; + import localizedFormat from 'dayjs/plugin/localizedFormat'; + + dayjs.extend(localizedFormat); const dispatch = createEventDispatcher(); @@ -159,7 +162,7 @@
- {dayjs(chat.created_at * 1000).format($i18n.t('MMMM DD, YYYY HH:mm'))} + {dayjs(chat.created_at * 1000).format('LLL')}
diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index 24d6f23b5..20f44f49b 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -5,10 +5,12 @@ import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import isToday from 'dayjs/plugin/isToday'; import isYesterday from 'dayjs/plugin/isYesterday'; +import localizedFormat from 'dayjs/plugin/localizedFormat'; dayjs.extend(relativeTime); dayjs.extend(isToday); dayjs.extend(isYesterday); +dayjs.extend(localizedFormat); import { WEBUI_BASE_URL } from '$lib/constants'; import { TTS_RESPONSE_SPLIT } from '$lib/types'; @@ -295,11 +297,11 @@ export const formatDate = (inputDate) => { const now = dayjs(); if (date.isToday()) { - return `Today at ${date.format('HH:mm')}`; + return `Today at ${date.format('LT')}`; } else if (date.isYesterday()) { - return `Yesterday at ${date.format('HH:mm')}`; + return `Yesterday at ${date.format('LT')}`; } else { - return `${date.format('DD/MM/YYYY')} at ${date.format('HH:mm')}`; + return `${date.format('L')} at ${date.format('LT')}`; } }; diff --git a/src/routes/s/[id]/+page.svelte b/src/routes/s/[id]/+page.svelte index dfef68513..36ea3541e 100644 --- a/src/routes/s/[id]/+page.svelte +++ b/src/routes/s/[id]/+page.svelte @@ -16,8 +16,10 @@ import { getUserById } from '$lib/apis/users'; import { getModels } from '$lib/apis'; import { toast } from 'svelte-sonner'; + import localizedFormat from 'dayjs/plugin/localizedFormat'; const i18n = getContext('i18n'); + dayjs.extend(localizedFormat); let loaded = false; @@ -138,7 +140,7 @@
- {dayjs(chat.chat.timestamp).format($i18n.t('MMMM DD, YYYY'))} + {dayjs(chat.chat.timestamp).format('LLL')}
From 2d562ed317f34f1ee3c7d79a6fc751715a590ca1 Mon Sep 17 00:00:00 2001 From: kokutaro Date: Sun, 26 Jan 2025 17:51:20 +0900 Subject: [PATCH 3/8] Fixed the type on translation.json Fixed the typo on Japanese translation file --- src/lib/i18n/locales/ja-JP/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/i18n/locales/ja-JP/translation.json b/src/lib/i18n/locales/ja-JP/translation.json index 6ddb781f1..492acce1b 100644 --- a/src/lib/i18n/locales/ja-JP/translation.json +++ b/src/lib/i18n/locales/ja-JP/translation.json @@ -766,7 +766,7 @@ "Reset": "", "Reset All Models": "", "Reset Upload Directory": "アップロードディレクトリをリセット", - "Reset Vector Storage/Knowledge": "ベクターストレージとナレッジべーうをリセット", + "Reset Vector Storage/Knowledge": "ベクターストレージとナレッジベースをリセット", "Reset view": "", "Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "", "Response splitting": "応答の分割", From 6f3c92f6d522d34e89252e2f227c3fde58b0a170 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 26 Jan 2025 23:17:58 -0800 Subject: [PATCH 4/8] enh: chat loading screen --- src/lib/components/chat/Chat.svelte | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 331806a96..24abe6110 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -82,10 +82,12 @@ import EventConfirmDialog from '../common/ConfirmDialog.svelte'; import Placeholder from './Placeholder.svelte'; import NotificationToast from '../NotificationToast.svelte'; + import Spinner from '../common/Spinner.svelte'; export let chatIdProp = ''; - let loaded = false; + let loading = false; + const eventTarget = new EventTarget(); let controlPane; let controlPaneComponent; @@ -133,6 +135,7 @@ $: if (chatIdProp) { (async () => { + loading = true; console.log(chatIdProp); prompt = ''; @@ -141,11 +144,9 @@ webSearchEnabled = false; imageGenerationEnabled = false; - loaded = false; - if (chatIdProp && (await loadChat())) { await tick(); - loaded = true; + loading = false; if (localStorage.getItem(`chat-input-${chatIdProp}`)) { try { @@ -1861,7 +1862,7 @@ : ' '} w-full max-w-full flex flex-col" id="chat-container" > - {#if !chatIdProp || (loaded && chatIdProp)} + {#if chatIdProp === '' || (!loading && chatIdProp)} {#if $settings?.backgroundImageUrl ?? null}
+
+ +
+
{/if} From 6eb51ab62e3c3bee3590b91cc596ed2d94ce28ca Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 26 Jan 2025 23:30:46 -0800 Subject: [PATCH 5/8] enh: file upload permission indicator --- .../chat/MessageInput/InputMenu.svelte | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/lib/components/chat/MessageInput/InputMenu.svelte b/src/lib/components/chat/MessageInput/InputMenu.svelte index 20b297eb3..3c8eaf008 100644 --- a/src/lib/components/chat/MessageInput/InputMenu.svelte +++ b/src/lib/components/chat/MessageInput/InputMenu.svelte @@ -48,6 +48,9 @@ init(); } + let fileUploadEnabled = true; + $: fileUploadEnabled = $user.role === 'admin' || $user?.permissions?.chat?.file_upload; + const init = async () => { if ($_tools === null) { await _tools.set(await getTools(localStorage.token)); @@ -166,26 +169,44 @@ {/if} {#if !$mobile} - { - screenCaptureHandler(); - }} + - -
{$i18n.t('Capture')}
-
+ { + if (fileUploadEnabled) { + screenCaptureHandler(); + } + }} + > + +
{$i18n.t('Capture')}
+
+ {/if} - { - uploadFilesHandler(); - }} + - -
{$i18n.t('Upload Files')}
-
+ { + if (fileUploadEnabled) { + uploadFilesHandler(); + } + }} + > + +
{$i18n.t('Upload Files')}
+
+ {#if $config?.features?.enable_google_drive_integration} Date: Mon, 27 Jan 2025 18:11:52 +0000 Subject: [PATCH 6/8] Adding more checks for write access. Adding accessRoles to Model & Knowledge creation --- backend/open_webui/routers/knowledge.py | 36 +++++++++++++++---- backend/open_webui/routers/models.py | 6 +++- backend/open_webui/routers/prompts.py | 6 +++- backend/open_webui/routers/tools.py | 6 +++- .../Knowledge/CreateKnowledgeBase.svelte | 5 ++- .../workspace/Models/ModelEditor.svelte | 5 ++- 6 files changed, 53 insertions(+), 11 deletions(-) diff --git a/backend/open_webui/routers/knowledge.py b/backend/open_webui/routers/knowledge.py index cce3d6311..a85ccd05e 100644 --- a/backend/open_webui/routers/knowledge.py +++ b/backend/open_webui/routers/knowledge.py @@ -264,7 +264,10 @@ def add_file_to_knowledge_by_id( detail=ERROR_MESSAGES.NOT_FOUND, ) - if knowledge.user_id != user.id and user.role != "admin": + if (knowledge.user_id != user.id + and not has_access(user.id, "write", knowledge.access_control) + and user.role != "admin" + ): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -342,7 +345,12 @@ def update_file_from_knowledge_by_id( detail=ERROR_MESSAGES.NOT_FOUND, ) - if knowledge.user_id != user.id and user.role != "admin": + if ( + knowledge.user_id != user.id + and not has_access(user.id, "write", knowledge.access_control) + and user.role != "admin" + ): + raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -406,7 +414,11 @@ def remove_file_from_knowledge_by_id( detail=ERROR_MESSAGES.NOT_FOUND, ) - if knowledge.user_id != user.id and user.role != "admin": + if ( + knowledge.user_id != user.id + and not has_access(user.id, "write", knowledge.access_control) + and user.role != "admin" + ): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -484,7 +496,11 @@ async def delete_knowledge_by_id(id: str, user=Depends(get_verified_user)): detail=ERROR_MESSAGES.NOT_FOUND, ) - if knowledge.user_id != user.id and user.role != "admin": + if ( + knowledge.user_id != user.id + and not has_access(user.id, "write", knowledge.access_control) + and user.role != "admin" + ): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -543,7 +559,11 @@ async def reset_knowledge_by_id(id: str, user=Depends(get_verified_user)): detail=ERROR_MESSAGES.NOT_FOUND, ) - if knowledge.user_id != user.id and user.role != "admin": + if ( + knowledge.user_id != user.id + and not has_access(user.id, "write", knowledge.access_control) + and user.role != "admin" + ): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -582,7 +602,11 @@ def add_files_to_knowledge_batch( detail=ERROR_MESSAGES.NOT_FOUND, ) - if knowledge.user_id != user.id and user.role != "admin": + if ( + knowledge.user_id != user.id + and not has_access(user.id, "write", knowledge.access_control) + and user.role != "admin" + ): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, diff --git a/backend/open_webui/routers/models.py b/backend/open_webui/routers/models.py index 6c8519b2c..a45814d32 100644 --- a/backend/open_webui/routers/models.py +++ b/backend/open_webui/routers/models.py @@ -183,7 +183,11 @@ async def delete_model_by_id(id: str, user=Depends(get_verified_user)): detail=ERROR_MESSAGES.NOT_FOUND, ) - if model.user_id != user.id and user.role != "admin": + if ( + user.role == "admin" + or model.user_id == user.id + or has_access(user.id, "write", model.access_control) + ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.UNAUTHORIZED, diff --git a/backend/open_webui/routers/prompts.py b/backend/open_webui/routers/prompts.py index 014e5652e..9fb946c6e 100644 --- a/backend/open_webui/routers/prompts.py +++ b/backend/open_webui/routers/prompts.py @@ -147,7 +147,11 @@ async def delete_prompt_by_command(command: str, user=Depends(get_verified_user) detail=ERROR_MESSAGES.NOT_FOUND, ) - if prompt.user_id != user.id and user.role != "admin": + if ( + prompt.user_id != user.id + and not has_access(user.id, "write", prompt.access_control) + and user.role != "admin" + ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index 7b9144b4c..d6a5c5532 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -227,7 +227,11 @@ async def delete_tools_by_id( detail=ERROR_MESSAGES.NOT_FOUND, ) - if tools.user_id != user.id and user.role != "admin": + if ( + tools.user_id != user.id + and not has_access(user.id, "write", tools.access_control) + and user.role != "admin" + ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.UNAUTHORIZED, diff --git a/src/lib/components/workspace/Knowledge/CreateKnowledgeBase.svelte b/src/lib/components/workspace/Knowledge/CreateKnowledgeBase.svelte index 5d1e79808..8253c1f68 100644 --- a/src/lib/components/workspace/Knowledge/CreateKnowledgeBase.svelte +++ b/src/lib/components/workspace/Knowledge/CreateKnowledgeBase.svelte @@ -112,7 +112,10 @@
- +
diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index 58628f0d1..ae10c6eba 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -531,7 +531,10 @@
- +
From 45e19fb9bd5a0fb4c0a882334af772883d58df7a Mon Sep 17 00:00:00 2001 From: Tiancong Li Date: Tue, 28 Jan 2025 05:08:19 +0800 Subject: [PATCH 7/8] i18n: update zh-TW --- src/lib/i18n/locales/zh-TW/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/i18n/locales/zh-TW/translation.json b/src/lib/i18n/locales/zh-TW/translation.json index 029fb9968..239cec25f 100644 --- a/src/lib/i18n/locales/zh-TW/translation.json +++ b/src/lib/i18n/locales/zh-TW/translation.json @@ -934,7 +934,7 @@ "This will delete all models including custom models and cannot be undone.": "這將刪除所有模型,包括自訂模型,且無法復原。", "This will reset the knowledge base and sync all files. Do you wish to continue?": "這將重設知識庫並同步所有檔案。您確定要繼續嗎?", "Thorough explanation": "詳細解釋", - "Thought for {{DURATION}}": "", + "Thought for {{DURATION}}": "{{DURATION}} 思考中", "Tika": "Tika", "Tika Server URL required.": "需要 Tika 伺服器 URL。", "Tiktoken": "Tiktoken", From 95f4d99e3b54c6cca308136b496900e391d813d6 Mon Sep 17 00:00:00 2001 From: Orion Date: Tue, 28 Jan 2025 09:53:22 +1000 Subject: [PATCH 8/8] Update misc.py Include empty delta object on openai_chat_chunk_message_template per OpenAI API documentation. https://platform.openai.com/docs/api-reference/chat/streaming#chat/streaming --- backend/open_webui/utils/misc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py index a83733d63..8792b1cfc 100644 --- a/backend/open_webui/utils/misc.py +++ b/backend/open_webui/utils/misc.py @@ -149,6 +149,7 @@ def openai_chat_chunk_message_template( template["choices"][0]["delta"] = {"content": message} else: template["choices"][0]["finish_reason"] = "stop" + template["choices"][0]["delta"] = {} if usage: template["usage"] = usage