enh: channel read/write perm
This commit is contained in:
parent
6d69ea3ac7
commit
ac879513e5
|
@ -57,6 +57,10 @@ class ChannelModel(BaseModel):
|
|||
####################
|
||||
|
||||
|
||||
class ChannelResponse(ChannelModel):
|
||||
write_access: bool = False
|
||||
|
||||
|
||||
class ChannelForm(BaseModel):
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
|
|
|
@ -10,7 +10,13 @@ from pydantic import BaseModel
|
|||
from open_webui.socket.main import sio, get_user_ids_from_room
|
||||
from open_webui.models.users import Users, UserNameResponse
|
||||
|
||||
from open_webui.models.channels import Channels, ChannelModel, ChannelForm
|
||||
from open_webui.models.groups import Groups
|
||||
from open_webui.models.channels import (
|
||||
Channels,
|
||||
ChannelModel,
|
||||
ChannelForm,
|
||||
ChannelResponse,
|
||||
)
|
||||
from open_webui.models.messages import (
|
||||
Messages,
|
||||
MessageModel,
|
||||
|
@ -80,7 +86,7 @@ async def create_new_channel(form_data: ChannelForm, user=Depends(get_admin_user
|
|||
############################
|
||||
|
||||
|
||||
@router.get("/{id}", response_model=Optional[ChannelModel])
|
||||
@router.get("/{id}", response_model=Optional[ChannelResponse])
|
||||
async def get_channel_by_id(id: str, user=Depends(get_verified_user)):
|
||||
channel = Channels.get_channel_by_id(id)
|
||||
if not channel:
|
||||
|
@ -95,7 +101,16 @@ async def get_channel_by_id(id: str, user=Depends(get_verified_user)):
|
|||
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
|
||||
)
|
||||
|
||||
return ChannelModel(**channel.model_dump())
|
||||
write_access = has_access(
|
||||
user.id, type="write", access_control=channel.access_control, strict=False
|
||||
)
|
||||
|
||||
return ChannelResponse(
|
||||
**{
|
||||
**channel.model_dump(),
|
||||
"write_access": write_access or user.role == "admin",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
############################
|
||||
|
@ -362,7 +377,7 @@ async def new_message_handler(
|
|||
)
|
||||
|
||||
if user.role != "admin" and not has_access(
|
||||
user.id, type="read", access_control=channel.access_control
|
||||
user.id, type="write", access_control=channel.access_control, strict=False
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
|
||||
|
@ -658,7 +673,7 @@ async def add_reaction_to_message(
|
|||
)
|
||||
|
||||
if user.role != "admin" and not has_access(
|
||||
user.id, type="read", access_control=channel.access_control
|
||||
user.id, type="write", access_control=channel.access_control, strict=False
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
|
||||
|
@ -724,7 +739,7 @@ async def remove_reaction_by_id_and_user_id_and_name(
|
|||
)
|
||||
|
||||
if user.role != "admin" and not has_access(
|
||||
user.id, type="read", access_control=channel.access_control
|
||||
user.id, type="write", access_control=channel.access_control, strict=False
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
|
||||
|
@ -806,7 +821,9 @@ async def delete_message_by_id(
|
|||
if (
|
||||
user.role != "admin"
|
||||
and message.user_id != user.id
|
||||
and not has_access(user.id, type="read", access_control=channel.access_control)
|
||||
and not has_access(
|
||||
user.id, type="write", access_control=channel.access_control, strict=False
|
||||
)
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
|
||||
|
|
|
@ -110,9 +110,13 @@ def has_access(
|
|||
type: str = "write",
|
||||
access_control: Optional[dict] = None,
|
||||
user_group_ids: Optional[Set[str]] = None,
|
||||
strict: bool = True,
|
||||
) -> bool:
|
||||
if access_control is None:
|
||||
if strict:
|
||||
return type == "read"
|
||||
else:
|
||||
return True
|
||||
|
||||
if user_group_ids is None:
|
||||
user_groups = Groups.get_groups_by_member_id(user_id)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
import Drawer from '../common/Drawer.svelte';
|
||||
import EllipsisVertical from '../icons/EllipsisVertical.svelte';
|
||||
import Thread from './Thread.svelte';
|
||||
import i18n from '$lib/i18n';
|
||||
|
||||
export let id = '';
|
||||
|
||||
|
@ -252,6 +253,10 @@
|
|||
{typingUsers}
|
||||
userSuggestions={true}
|
||||
channelSuggestions={true}
|
||||
disabled={!channel?.write_access}
|
||||
placeholder={!channel?.write_access
|
||||
? $i18n.t('You do not have permission to send messages in this channel.')
|
||||
: $i18n.t('Type here...')}
|
||||
{onChange}
|
||||
onSubmit={submitHandler}
|
||||
{scrollToBottom}
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
import MentionList from './MessageInput/MentionList.svelte';
|
||||
import Skeleton from '../chat/Messages/Skeleton.svelte';
|
||||
|
||||
export let placeholder = $i18n.t('Send a Message');
|
||||
export let placeholder = $i18n.t('Type here...');
|
||||
|
||||
export let id = null;
|
||||
export let chatInputElement;
|
||||
|
@ -53,6 +53,7 @@
|
|||
export let scrollEnd = true;
|
||||
export let scrollToBottom: Function = () => {};
|
||||
|
||||
export let disabled = false;
|
||||
export let acceptFiles = true;
|
||||
export let showFormattingToolbar = true;
|
||||
|
||||
|
@ -731,7 +732,9 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<div
|
||||
class="{disabled ? 'opacity-50 pointer-events-none cursor-not-allowed' : ''} relative z-20"
|
||||
>
|
||||
{#if recording}
|
||||
<VoiceRecording
|
||||
bind:recording
|
||||
|
@ -836,6 +839,8 @@
|
|||
bind:this={chatInputElement}
|
||||
json={true}
|
||||
messageInput={true}
|
||||
editable={!disabled}
|
||||
{placeholder}
|
||||
richText={$settings?.richTextInput ?? true}
|
||||
showFormattingToolbar={$settings?.showFormattingToolbar ?? false}
|
||||
shiftEnter={!($settings?.ctrlEnterToSend ?? false) &&
|
||||
|
|
|
@ -201,6 +201,10 @@
|
|||
<div class=" pb-[1rem] px-2.5 w-full">
|
||||
<MessageInput
|
||||
id={threadId}
|
||||
disabled={!channel?.write_access}
|
||||
placeholder={!channel?.write_access
|
||||
? $i18n.t('You do not have permission to send messages in this thread.')
|
||||
: $i18n.t('Reply to thread...')}
|
||||
typingUsersClassName="from-gray-50 dark:from-gray-850"
|
||||
{typingUsers}
|
||||
userSuggestions={true}
|
||||
|
|
|
@ -168,7 +168,7 @@
|
|||
export let documentId = '';
|
||||
|
||||
export let className = 'input-prose';
|
||||
export let placeholder = 'Type here...';
|
||||
export let placeholder = $i18n.t('Type here...');
|
||||
let _placeholder = placeholder;
|
||||
|
||||
$: if (placeholder !== _placeholder) {
|
||||
|
@ -689,7 +689,7 @@
|
|||
link: link
|
||||
}),
|
||||
...(dragHandle ? [ListItemDragHandle] : []),
|
||||
Placeholder.configure({ placeholder: () => _placeholder }),
|
||||
Placeholder.configure({ placeholder: () => _placeholder, showOnlyWhenEditable: false }),
|
||||
SelectionDecoration,
|
||||
|
||||
...(richText
|
||||
|
@ -1123,4 +1123,9 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<div bind:this={element} class="relative w-full min-w-full h-full min-h-fit {className}" />
|
||||
<div
|
||||
bind:this={element}
|
||||
class="relative w-full min-w-full h-full min-h-fit {className} {!editable
|
||||
? 'cursor-not-allowed'
|
||||
: ''}"
|
||||
/>
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
|
||||
<div class="my-2 -mx-2">
|
||||
<div class="px-4 py-3 bg-gray-50 dark:bg-gray-950 rounded-3xl">
|
||||
<AccessControl bind:accessControl />
|
||||
<AccessControl bind:accessControl accessRoles={['read', 'write']} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Reference in New Issue