diff --git a/backend/open_webui/routers/notes.py b/backend/open_webui/routers/notes.py index 321b06fcd..659d9459f 100644 --- a/backend/open_webui/routers/notes.py +++ b/backend/open_webui/routers/notes.py @@ -300,6 +300,58 @@ async def update_note_by_id( ) +############################ +# UpdateNoteAccessById +############################ + + +class NoteAccessGrantsForm(BaseModel): + access_grants: list[dict] + + +@router.post("/{id}/access/update", response_model=Optional[NoteModel]) +async def update_note_access_by_id( + request: Request, + id: str, + form_data: NoteAccessGrantsForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): + if user.role != "admin" and not has_permission( + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS, db=db + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + + note = Notes.get_note_by_id(id, db=db) + if not note: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND + ) + + if user.role != "admin" and ( + user.id != note.user_id + and not AccessGrants.has_access( + user_id=user.id, + resource_type="note", + resource_id=note.id, + permission="write", + db=db, + ) + ): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT() + ) + + AccessGrants.set_access_grants( + "note", id, form_data.access_grants, db=db + ) + + return Notes.get_note_by_id(id, db=db) + + ############################ # DeleteNoteById ############################ diff --git a/src/lib/apis/notes/index.ts b/src/lib/apis/notes/index.ts index 341ced57e..1780aa790 100644 --- a/src/lib/apis/notes/index.ts +++ b/src/lib/apis/notes/index.ts @@ -253,6 +253,39 @@ export const updateNoteById = async (token: string, id: string, note: NoteItem) return res; }; +export const updateNoteAccessGrants = async ( + token: string, + id: string, + accessGrants: any[] +) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/notes/${id}/access/update`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + }, + body: JSON.stringify({ access_grants: accessGrants }) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + export const deleteNoteById = async (token: string, id: string) => { let error = null; diff --git a/src/lib/components/notes/NoteEditor.svelte b/src/lib/components/notes/NoteEditor.svelte index 708e7e852..0d82bd176 100644 --- a/src/lib/components/notes/NoteEditor.svelte +++ b/src/lib/components/notes/NoteEditor.svelte @@ -60,7 +60,7 @@ // Assuming $i18n.languages is an array of language codes $: loadLocale($i18n.languages); - import { deleteNoteById, getNoteById, updateNoteById } from '$lib/apis/notes'; + import { deleteNoteById, getNoteById, updateNoteById, updateNoteAccessGrants } from '$lib/apis/notes'; import RichTextInput from '../common/RichTextInput.svelte'; import Spinner from '../common/Spinner.svelte'; @@ -71,6 +71,7 @@ import Calendar from '../icons/Calendar.svelte'; import Users from '../icons/Users.svelte'; + import LockClosed from '../icons/LockClosed.svelte'; import Image from '../common/Image.svelte'; import FileItem from '../common/FileItem.svelte'; @@ -865,8 +866,15 @@ Provide the enhanced notes in markdown format. Use markdown syntax for headings, bind:show={showAccessControlModal} bind:accessGrants={note.access_grants} accessRoles={['read', 'write']} - onChange={() => { - changeDebounceHandler(); + onChange={async () => { + if (id) { + try { + await updateNoteAccessGrants(localStorage.token, id, note.access_grants ?? []); + toast.success($i18n.t('Saved')); + } catch (error) { + toast.error(`${error}`); + } + } }} /> {/if} @@ -898,7 +906,7 @@ Provide the enhanced notes in markdown format. Use markdown syntax for headings, {:else}
-
+
{#if $mobile}
+
{#if note?.write_access} {#if editor}
@@ -1077,6 +1085,23 @@ Provide the enhanced notes in markdown format. Use markdown syntax for headings,
+ + {#if note?.write_access} + + {:else} +
+ {$i18n.t('Read-Only Access')} +
+ {/if}
@@ -1118,26 +1143,6 @@ Provide the enhanced notes in markdown format. Use markdown syntax for headings, {/if} - {#if note?.write_access} - - {:else} -
- {$i18n.t('Read-Only Access')} -
- {/if} - {#if editor}