mirror of
https://github.com/open-webui/open-webui
synced 2024-11-24 13:07:25 +00:00
enh: user chat edit permission
This commit is contained in:
parent
dfa5041b6f
commit
cbadf39d7d
@ -808,10 +808,24 @@ USER_PERMISSIONS_CHAT_DELETION = (
|
||||
os.environ.get("USER_PERMISSIONS_CHAT_DELETION", "True").lower() == "true"
|
||||
)
|
||||
|
||||
USER_PERMISSIONS_CHAT_EDITING = (
|
||||
os.environ.get("USER_PERMISSIONS_CHAT_EDITING", "True").lower() == "true"
|
||||
)
|
||||
|
||||
USER_PERMISSIONS_CHAT_TEMPORARY = (
|
||||
os.environ.get("USER_PERMISSIONS_CHAT_TEMPORARY", "True").lower() == "true"
|
||||
)
|
||||
|
||||
USER_PERMISSIONS = PersistentConfig(
|
||||
"USER_PERMISSIONS",
|
||||
"ui.user_permissions",
|
||||
{"chat": {"deletion": USER_PERMISSIONS_CHAT_DELETION}},
|
||||
{
|
||||
"chat": {
|
||||
"deletion": USER_PERMISSIONS_CHAT_DELETION,
|
||||
"editing": USER_PERMISSIONS_CHAT_EDITING,
|
||||
"temporary": USER_PERMISSIONS_CHAT_TEMPORARY,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
ENABLE_MODEL_FILTER = PersistentConfig(
|
||||
|
@ -68,6 +68,7 @@ from utils.utils import (
|
||||
get_http_authorization_cred,
|
||||
get_password_hash,
|
||||
create_token,
|
||||
decode_token,
|
||||
)
|
||||
from utils.task import (
|
||||
title_generation_template,
|
||||
@ -1957,41 +1958,61 @@ async def update_pipeline_valves(
|
||||
|
||||
|
||||
@app.get("/api/config")
|
||||
async def get_app_config():
|
||||
async def get_app_config(request: Request):
|
||||
user = None
|
||||
if "token" in request.cookies:
|
||||
token = request.cookies.get("token")
|
||||
data = decode_token(token)
|
||||
if data is not None and "id" in data:
|
||||
user = Users.get_user_by_id(data["id"])
|
||||
|
||||
return {
|
||||
"status": True,
|
||||
"name": WEBUI_NAME,
|
||||
"version": VERSION,
|
||||
"default_locale": str(DEFAULT_LOCALE),
|
||||
"default_models": webui_app.state.config.DEFAULT_MODELS,
|
||||
"default_prompt_suggestions": webui_app.state.config.DEFAULT_PROMPT_SUGGESTIONS,
|
||||
"features": {
|
||||
"auth": WEBUI_AUTH,
|
||||
"auth_trusted_header": bool(webui_app.state.AUTH_TRUSTED_EMAIL_HEADER),
|
||||
"enable_signup": webui_app.state.config.ENABLE_SIGNUP,
|
||||
"enable_login_form": webui_app.state.config.ENABLE_LOGIN_FORM,
|
||||
"enable_web_search": rag_app.state.config.ENABLE_RAG_WEB_SEARCH,
|
||||
"enable_image_generation": images_app.state.config.ENABLED,
|
||||
"enable_community_sharing": webui_app.state.config.ENABLE_COMMUNITY_SHARING,
|
||||
"enable_message_rating": webui_app.state.config.ENABLE_MESSAGE_RATING,
|
||||
"enable_admin_export": ENABLE_ADMIN_EXPORT,
|
||||
"enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS,
|
||||
},
|
||||
"audio": {
|
||||
"tts": {
|
||||
"engine": audio_app.state.config.TTS_ENGINE,
|
||||
"voice": audio_app.state.config.TTS_VOICE,
|
||||
},
|
||||
"stt": {
|
||||
"engine": audio_app.state.config.STT_ENGINE,
|
||||
},
|
||||
},
|
||||
"oauth": {
|
||||
"providers": {
|
||||
name: config.get("name", name)
|
||||
for name, config in OAUTH_PROVIDERS.items()
|
||||
}
|
||||
},
|
||||
"features": {
|
||||
"auth": WEBUI_AUTH,
|
||||
"auth_trusted_header": bool(webui_app.state.AUTH_TRUSTED_EMAIL_HEADER),
|
||||
"enable_signup": webui_app.state.config.ENABLE_SIGNUP,
|
||||
"enable_login_form": webui_app.state.config.ENABLE_LOGIN_FORM,
|
||||
**(
|
||||
{
|
||||
"enable_web_search": rag_app.state.config.ENABLE_RAG_WEB_SEARCH,
|
||||
"enable_image_generation": images_app.state.config.ENABLED,
|
||||
"enable_community_sharing": webui_app.state.config.ENABLE_COMMUNITY_SHARING,
|
||||
"enable_message_rating": webui_app.state.config.ENABLE_MESSAGE_RATING,
|
||||
"enable_admin_export": ENABLE_ADMIN_EXPORT,
|
||||
"enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS,
|
||||
}
|
||||
if user is not None
|
||||
else {}
|
||||
),
|
||||
},
|
||||
**(
|
||||
{
|
||||
"default_models": webui_app.state.config.DEFAULT_MODELS,
|
||||
"default_prompt_suggestions": webui_app.state.config.DEFAULT_PROMPT_SUGGESTIONS,
|
||||
"audio": {
|
||||
"tts": {
|
||||
"engine": audio_app.state.config.TTS_ENGINE,
|
||||
"voice": audio_app.state.config.TTS_VOICE,
|
||||
},
|
||||
"stt": {
|
||||
"engine": audio_app.state.config.STT_ENGINE,
|
||||
},
|
||||
},
|
||||
"permissions": {**webui_app.state.config.USER_PERMISSIONS},
|
||||
}
|
||||
if user is not None
|
||||
else {}
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
@ -665,6 +665,7 @@ export const getBackendConfig = async () => {
|
||||
|
||||
const res = await fetch(`${WEBUI_BASE_URL}/api/config`, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
@ -18,7 +18,9 @@
|
||||
let whitelistModels = [''];
|
||||
let permissions = {
|
||||
chat: {
|
||||
deletion: true
|
||||
deletion: true,
|
||||
edit: true,
|
||||
temporary: true
|
||||
}
|
||||
};
|
||||
|
||||
@ -92,6 +94,88 @@
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class=" flex w-full justify-between">
|
||||
<div class=" self-center text-xs font-medium">{$i18n.t('Allow Chat Editing')}</div>
|
||||
|
||||
<button
|
||||
class="p-1 px-3 text-xs flex rounded transition"
|
||||
on:click={() => {
|
||||
permissions.chat.editing = !(permissions?.chat?.editing ?? true);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{#if permissions?.chat?.editing ?? true}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="ml-2 self-center">{$i18n.t('Allow')}</span>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7A1.5 1.5 0 0 0 3 8.5v5A1.5 1.5 0 0 0 4.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 11.5 7V4.5A3.5 3.5 0 0 0 8 1Zm2 6V4.5a2 2 0 1 0-4 0V7h4Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span class="ml-2 self-center">{$i18n.t("Don't Allow")}</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class=" flex w-full justify-between">
|
||||
<div class=" self-center text-xs font-medium">{$i18n.t('Allow Temporary Chat')}</div>
|
||||
|
||||
<button
|
||||
class="p-1 px-3 text-xs flex rounded transition"
|
||||
on:click={() => {
|
||||
permissions.chat.temporary = !(permissions?.chat?.temporary ?? true);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{#if permissions?.chat?.temporary ?? true}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="ml-2 self-center">{$i18n.t('Allow')}</span>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7A1.5 1.5 0 0 0 3 8.5v5A1.5 1.5 0 0 0 4.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 11.5 7V4.5A3.5 3.5 0 0 0 8 1Zm2 6V4.5a2 2 0 1 0-4 0V7h4Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span class="ml-2 self-center">{$i18n.t("Don't Allow")}</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class=" dark:border-gray-850 my-2" />
|
||||
|
@ -150,7 +150,7 @@
|
||||
}`
|
||||
: `border-gray-50 dark:border-gray-850 border-dashed ${
|
||||
$mobile ? 'min-w-full' : 'min-w-80'
|
||||
}`} transition-[width] transform duration-300 p-5 rounded-2xl"
|
||||
}`} transition-all p-5 rounded-2xl"
|
||||
on:click={() => {
|
||||
if (currentMessageId != message.id) {
|
||||
currentMessageId = message.id;
|
||||
|
@ -458,31 +458,33 @@
|
||||
|
||||
{#if message.done}
|
||||
{#if !readOnly}
|
||||
<Tooltip content={$i18n.t('Edit')} placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
editMessageHandler();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
{#if $user.role === 'user' ? ($config?.permissions?.chat?.editing ?? true) : true}
|
||||
<Tooltip content={$i18n.t('Edit')} placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
editMessageHandler();
|
||||
}}
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<Tooltip content={$i18n.t('Copy')} placement="bottom">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { models, showSettings, settings, user, mobile } from '$lib/stores';
|
||||
import { models, showSettings, settings, user, mobile, config } from '$lib/stores';
|
||||
import { onMount, tick, getContext } from 'svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import Selector from './ModelSelector/Selector.svelte';
|
||||
@ -46,7 +46,9 @@
|
||||
label: model.name,
|
||||
model: model
|
||||
}))}
|
||||
showTemporaryChatControl={true}
|
||||
showTemporaryChatControl={$user.role === 'user'
|
||||
? ($config?.permissions?.chat?.temporary ?? true)
|
||||
: true}
|
||||
bind:value={selectedModel}
|
||||
/>
|
||||
</div>
|
||||
|
@ -160,6 +160,7 @@
|
||||
if (sessionUser) {
|
||||
// Save Session User to Store
|
||||
await user.set(sessionUser);
|
||||
await config.set(await getBackendConfig());
|
||||
} else {
|
||||
// Redirect Invalid Session User to /auth Page
|
||||
localStorage.removeItem('token');
|
||||
|
Loading…
Reference in New Issue
Block a user