diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index d0b4ed8f3..a6cffeecd 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1137,6 +1137,10 @@ USER_PERMISSIONS_FEATURES_CODE_INTERPRETER = ( == "true" ) +USER_PERMISSIONS_FEATURES_NOTES = ( + os.environ.get("USER_PERMISSIONS_FEATURES_NOTES", "True").lower() == "true" +) + DEFAULT_USER_PERMISSIONS = { "workspace": { @@ -1170,6 +1174,7 @@ DEFAULT_USER_PERMISSIONS = { "web_search": USER_PERMISSIONS_FEATURES_WEB_SEARCH, "image_generation": USER_PERMISSIONS_FEATURES_IMAGE_GENERATION, "code_interpreter": USER_PERMISSIONS_FEATURES_CODE_INTERPRETER, + "notes": USER_PERMISSIONS_FEATURES_NOTES, }, } diff --git a/backend/open_webui/routers/notes.py b/backend/open_webui/routers/notes.py index a78953bb4..74156dea3 100644 --- a/backend/open_webui/routers/notes.py +++ b/backend/open_webui/routers/notes.py @@ -15,7 +15,7 @@ from open_webui.env import SRC_LOG_LEVELS from open_webui.utils.auth import get_admin_user, get_verified_user -from open_webui.utils.access_control import has_access +from open_webui.utils.access_control import has_permission log = logging.getLogger(__name__) log.setLevel(SRC_LOG_LEVELS["MODELS"]) @@ -28,7 +28,16 @@ router = APIRouter() @router.get("/", response_model=list[NoteUserResponse]) -async def get_notes(user=Depends(get_verified_user)): +async def get_notes(request: Request, user=Depends(get_verified_user)): + + if user.role != "admin" and not has_permission( + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + notes = [ NoteUserResponse( **{ @@ -43,7 +52,16 @@ async def get_notes(user=Depends(get_verified_user)): @router.get("/list", response_model=list[NoteUserResponse]) -async def get_note_list(user=Depends(get_verified_user)): +async def get_note_list(request: Request, user=Depends(get_verified_user)): + + if user.role != "admin" and not has_permission( + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + notes = [ NoteUserResponse( **{ @@ -63,7 +81,18 @@ async def get_note_list(user=Depends(get_verified_user)): @router.post("/create", response_model=Optional[NoteModel]) -async def create_new_note(form_data: NoteForm, user=Depends(get_admin_user)): +async def create_new_note( + request: Request, form_data: NoteForm, user=Depends(get_verified_user) +): + + if user.role != "admin" and not has_permission( + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + try: note = Notes.insert_new_note(form_data, user.id) return note @@ -80,7 +109,15 @@ async def create_new_note(form_data: NoteForm, user=Depends(get_admin_user)): @router.get("/{id}", response_model=Optional[NoteModel]) -async def get_note_by_id(id: str, user=Depends(get_verified_user)): +async def get_note_by_id(request: Request, id: str, user=Depends(get_verified_user)): + if user.role != "admin" and not has_permission( + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + note = Notes.get_note_by_id(id) if not note: raise HTTPException( @@ -104,8 +141,16 @@ async def get_note_by_id(id: str, user=Depends(get_verified_user)): @router.post("/{id}/update", response_model=Optional[NoteModel]) async def update_note_by_id( - id: str, form_data: NoteForm, user=Depends(get_verified_user) + request: Request, id: str, form_data: NoteForm, user=Depends(get_verified_user) ): + if user.role != "admin" and not has_permission( + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + note = Notes.get_note_by_id(id) if not note: raise HTTPException( @@ -135,7 +180,15 @@ async def update_note_by_id( @router.delete("/{id}/delete", response_model=bool) -async def delete_note_by_id(id: str, user=Depends(get_verified_user)): +async def delete_note_by_id(request: Request, id: str, user=Depends(get_verified_user)): + if user.role != "admin" and not has_permission( + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + note = Notes.get_note_by_id(id) if not note: raise HTTPException( diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py index 0c348f51e..50014a5f6 100644 --- a/backend/open_webui/routers/users.py +++ b/backend/open_webui/routers/users.py @@ -129,6 +129,7 @@ class FeaturesPermissions(BaseModel): web_search: bool = True image_generation: bool = True code_interpreter: bool = True + notes: bool = True class UserPermissions(BaseModel): diff --git a/src/lib/components/admin/Users/Groups.svelte b/src/lib/components/admin/Users/Groups.svelte index e89b463b0..5847ebbb1 100644 --- a/src/lib/components/admin/Users/Groups.svelte +++ b/src/lib/components/admin/Users/Groups.svelte @@ -81,7 +81,8 @@ direct_tool_servers: false, web_search: true, image_generation: true, - code_interpreter: true + code_interpreter: true, + notes: true } }; diff --git a/src/lib/components/admin/Users/Groups/Permissions.svelte b/src/lib/components/admin/Users/Groups/Permissions.svelte index 9edf20ca0..6af935813 100644 --- a/src/lib/components/admin/Users/Groups/Permissions.svelte +++ b/src/lib/components/admin/Users/Groups/Permissions.svelte @@ -37,7 +37,8 @@ direct_tool_servers: false, web_search: true, image_generation: true, - code_interpreter: true + code_interpreter: true, + notes: true } }; @@ -380,5 +381,13 @@ + +
+
+ {$i18n.t('Notes')} +
+ + +
diff --git a/src/lib/components/layout/Sidebar.svelte b/src/lib/components/layout/Sidebar.svelte index 02a2f2e08..e9158a396 100644 --- a/src/lib/components/layout/Sidebar.svelte +++ b/src/lib/components/layout/Sidebar.svelte @@ -570,7 +570,7 @@ {/if} --> - {#if $config?.features?.enable_notes ?? false} + {#if ($config?.features?.enable_notes ?? false) && ($user?.role === 'admin' || ($user?.permissions?.features?.notes ?? true))}
{ + if (!note) { + return; + } + + console.log('Saving note:', note); + const res = await updateNoteById(localStorage.token, id, { ...note, title: note.title === '' ? $i18n.t('Untitled') : note.title diff --git a/src/routes/(app)/notes/+layout.svelte b/src/routes/(app)/notes/+layout.svelte index 8b8792c94..84267b6ae 100644 --- a/src/routes/(app)/notes/+layout.svelte +++ b/src/routes/(app)/notes/+layout.svelte @@ -1,17 +1,27 @@ @@ -21,71 +31,73 @@ -
- + -
- +
+ +
-
+{/if}