diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index c176c64dfd..28cb853656 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1231,6 +1231,30 @@ USER_PERMISSIONS_WORKSPACE_TOOLS_ACCESS = ( os.environ.get("USER_PERMISSIONS_WORKSPACE_TOOLS_ACCESS", "False").lower() == "true" ) +USER_PERMISSIONS_WORKSPACE_MODELS_IMPORT = ( + os.environ.get("USER_PERMISSIONS_WORKSPACE_MODELS_IMPORT", "False").lower() == "true" +) + +USER_PERMISSIONS_WORKSPACE_MODELS_EXPORT = ( + os.environ.get("USER_PERMISSIONS_WORKSPACE_MODELS_EXPORT", "False").lower() == "true" +) + +USER_PERMISSIONS_WORKSPACE_PROMPTS_IMPORT = ( + os.environ.get("USER_PERMISSIONS_WORKSPACE_PROMPTS_IMPORT", "False").lower() == "true" +) + +USER_PERMISSIONS_WORKSPACE_PROMPTS_EXPORT = ( + os.environ.get("USER_PERMISSIONS_WORKSPACE_PROMPTS_EXPORT", "False").lower() == "true" +) + +USER_PERMISSIONS_WORKSPACE_TOOLS_IMPORT = ( + os.environ.get("USER_PERMISSIONS_WORKSPACE_TOOLS_IMPORT", "False").lower() == "true" +) + +USER_PERMISSIONS_WORKSPACE_TOOLS_EXPORT = ( + os.environ.get("USER_PERMISSIONS_WORKSPACE_TOOLS_EXPORT", "False").lower() == "true" +) + USER_PERMISSIONS_WORKSPACE_MODELS_ALLOW_PUBLIC_SHARING = ( os.environ.get( "USER_PERMISSIONS_WORKSPACE_MODELS_ALLOW_PUBLIC_SHARING", "False" @@ -1374,6 +1398,12 @@ DEFAULT_USER_PERMISSIONS = { "knowledge": USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_ACCESS, "prompts": USER_PERMISSIONS_WORKSPACE_PROMPTS_ACCESS, "tools": USER_PERMISSIONS_WORKSPACE_TOOLS_ACCESS, + "models_import": USER_PERMISSIONS_WORKSPACE_MODELS_IMPORT, + "models_export": USER_PERMISSIONS_WORKSPACE_MODELS_EXPORT, + "prompts_import": USER_PERMISSIONS_WORKSPACE_PROMPTS_IMPORT, + "prompts_export": USER_PERMISSIONS_WORKSPACE_PROMPTS_EXPORT, + "tools_import": USER_PERMISSIONS_WORKSPACE_TOOLS_IMPORT, + "tools_export": USER_PERMISSIONS_WORKSPACE_TOOLS_EXPORT, }, "sharing": { "public_models": USER_PERMISSIONS_WORKSPACE_MODELS_ALLOW_PUBLIC_SHARING, diff --git a/backend/open_webui/routers/models.py b/backend/open_webui/routers/models.py index d69cd4ee42..33aa73429e 100644 --- a/backend/open_webui/routers/models.py +++ b/backend/open_webui/routers/models.py @@ -113,8 +113,19 @@ async def create_new_model( @router.get("/export", response_model=list[ModelModel]) -async def export_models(user=Depends(get_admin_user)): - return Models.get_models() +async def export_models(request: Request, user=Depends(get_verified_user)): + if user.role != "admin" and not has_permission( + user.id, "workspace.models_export", request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + + if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: + return Models.get_models() + else: + return Models.get_models_by_user_id(user.id) ############################ @@ -128,8 +139,17 @@ class ModelsImportForm(BaseModel): @router.post("/import", response_model=bool) async def import_models( - user: str = Depends(get_admin_user), form_data: ModelsImportForm = (...) + request: Request, + user=Depends(get_verified_user), + form_data: ModelsImportForm = (...), ): + if user.role != "admin" and not has_permission( + user.id, "workspace.models_import", request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) try: data = form_data.models if isinstance(data, list): diff --git a/backend/open_webui/routers/prompts.py b/backend/open_webui/routers/prompts.py index 5981f99f69..c056489e0a 100644 --- a/backend/open_webui/routers/prompts.py +++ b/backend/open_webui/routers/prompts.py @@ -48,8 +48,13 @@ async def get_prompt_list(user=Depends(get_verified_user)): async def create_new_prompt( request: Request, form_data: PromptForm, user=Depends(get_verified_user) ): - if user.role != "admin" and not has_permission( - user.id, "workspace.prompts", request.app.state.config.USER_PERMISSIONS + if user.role != "admin" and not ( + has_permission( + user.id, "workspace.prompts", request.app.state.config.USER_PERMISSIONS + ) + or has_permission( + user.id, "workspace.prompts_import", request.app.state.config.USER_PERMISSIONS + ) ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index 2fa3f6abf6..aa8d95943a 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -247,9 +247,19 @@ async def load_tool_from_url( @router.get("/export", response_model=list[ToolModel]) -async def export_tools(user=Depends(get_admin_user)): - tools = Tools.get_tools() - return tools +async def export_tools(request: Request, user=Depends(get_verified_user)): + if user.role != "admin" and not has_permission( + user.id, "workspace.tools_export", request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + + if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: + return Tools.get_tools() + else: + return Tools.get_tools_by_user_id(user.id, "read") ############################ @@ -263,8 +273,13 @@ async def create_new_tools( form_data: ToolForm, user=Depends(get_verified_user), ): - if user.role != "admin" and not has_permission( - user.id, "workspace.tools", request.app.state.config.USER_PERMISSIONS + if user.role != "admin" and not ( + has_permission( + user.id, "workspace.tools", request.app.state.config.USER_PERMISSIONS + ) + or has_permission( + user.id, "workspace.tools_import", request.app.state.config.USER_PERMISSIONS + ) ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py index 9ee3f9f88c..65a6a57dc8 100644 --- a/backend/open_webui/routers/users.py +++ b/backend/open_webui/routers/users.py @@ -150,6 +150,12 @@ class WorkspacePermissions(BaseModel): knowledge: bool = False prompts: bool = False tools: bool = False + models_import: bool = False + models_export: bool = False + prompts_import: bool = False + prompts_export: bool = False + tools_import: bool = False + tools_export: bool = False class SharingPermissions(BaseModel): diff --git a/src/lib/components/admin/Users/Groups/EditGroupModal.svelte b/src/lib/components/admin/Users/Groups/EditGroupModal.svelte index 1225a3dcf4..c81db86fd6 100644 --- a/src/lib/components/admin/Users/Groups/EditGroupModal.svelte +++ b/src/lib/components/admin/Users/Groups/EditGroupModal.svelte @@ -39,13 +39,20 @@ models: false, knowledge: false, prompts: false, - tools: false + tools: false, + models_import: false, + models_export: false, + prompts_import: false, + prompts_export: false, + tools_import: false, + tools_export: false }, sharing: { public_models: false, public_knowledge: false, public_prompts: false, - public_tools: false + public_tools: false, + public_notes: false }, chat: { controls: true, @@ -72,7 +79,8 @@ direct_tool_servers: false, web_search: true, image_generation: true, - code_interpreter: true + code_interpreter: true, + notes: true } }; export let userIds = []; diff --git a/src/lib/components/admin/Users/Groups/Permissions.svelte b/src/lib/components/admin/Users/Groups/Permissions.svelte index f9b6a75ae5..5b989b215d 100644 --- a/src/lib/components/admin/Users/Groups/Permissions.svelte +++ b/src/lib/components/admin/Users/Groups/Permissions.svelte @@ -11,7 +11,13 @@ models: false, knowledge: false, prompts: false, - tools: false + tools: false, + models_import: false, + models_export: false, + prompts_import: false, + prompts_export: false, + tools_import: false, + tools_export: false }, sharing: { public_models: false, @@ -97,6 +103,23 @@ {/if} + + {#if permissions.workspace.models} +
+
+
+ {$i18n.t('Import Models')} +
+ +
+
+
+ {$i18n.t('Export Models')} +
+ +
+
+ {/if}
@@ -129,6 +152,23 @@
{/if} + + {#if permissions.workspace.prompts} +
+
+
+ {$i18n.t('Import Prompts')} +
+ +
+
+
+ {$i18n.t('Export Prompts')} +
+ +
+
+ {/if}
@@ -151,6 +191,23 @@
{/if} + + {#if permissions.workspace.tools} +
+
+
+ {$i18n.t('Import Tools')} +
+ +
+
+
+ {$i18n.t('Export Tools')} +
+ +
+
+ {/if} diff --git a/src/lib/components/workspace/Models.svelte b/src/lib/components/workspace/Models.svelte index 2f9c5b5910..78567500e9 100644 --- a/src/lib/components/workspace/Models.svelte +++ b/src/lib/components/workspace/Models.svelte @@ -308,7 +308,7 @@
- {#if $user?.role === 'admin'} + {#if $user?.role === 'admin' || $user?.permissions?.workspace?.models_import}
+ {/if} - {#if models.length} - - {/if} + {#if models.length && ($user?.role === 'admin' || $user?.permissions?.workspace?.models_export)} + {/if} {$i18n.t('Copy Link')} - { - exportHandler(); - }} - > - + {#if $currentUser?.role === 'admin' || $currentUser?.permissions?.workspace?.models_export} + { + exportHandler(); + }} + > + -
{$i18n.t('Export')}
-
+
{$i18n.t('Export')}
+
+ {/if} {#if $config?.features.enable_community_sharing}
- {#if $user?.role === 'admin'} + {#if $user?.role === 'admin' || $user?.permissions?.workspace?.prompts_import}
+ {/if} - {#if prompts.length} - - {/if} + {#if prompts.length && ($user?.role === 'admin' || $user?.permissions?.workspace?.prompts_export)} + {/if}
{$i18n.t('Clone')} - { - exportHandler(); - }} - > - + {#if $user?.role === 'admin' || $user?.permissions?.workspace?.prompts_export} + { + exportHandler(); + }} + > + -
{$i18n.t('Export')}
-
+
{$i18n.t('Export')}
+
+ {/if}
diff --git a/src/lib/components/workspace/Tools.svelte b/src/lib/components/workspace/Tools.svelte index 5213f3ff1d..bf4ff1c285 100644 --- a/src/lib/components/workspace/Tools.svelte +++ b/src/lib/components/workspace/Tools.svelte @@ -232,7 +232,7 @@
- {#if $user?.role === 'admin'} + {#if $user?.role === 'admin' || $user?.permissions?.workspace?.tools_import}
+ {/if} - {#if tools.length} - - {/if} + saveAs(blob, `tools-export-${Date.now()}.json`); + } + }} + > +
+ {$i18n.t('Export')} +
+ {/if} {#if $user?.role === 'admin'} diff --git a/src/lib/components/workspace/Tools/ToolMenu.svelte b/src/lib/components/workspace/Tools/ToolMenu.svelte index f4a74cf3e7..fbc9fde7c9 100644 --- a/src/lib/components/workspace/Tools/ToolMenu.svelte +++ b/src/lib/components/workspace/Tools/ToolMenu.svelte @@ -12,7 +12,7 @@ import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte'; import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte'; import Download from '$lib/components/icons/Download.svelte'; - import { config } from '$lib/stores'; + import { config, user } from '$lib/stores'; const i18n = getContext('i18n'); @@ -93,16 +93,18 @@
{$i18n.t('Clone')}
- { - exportHandler(); - }} - > - + {#if $user?.role === 'admin' || $user?.permissions?.workspace?.tools_export} + { + exportHandler(); + }} + > + -
{$i18n.t('Export')}
-
+
{$i18n.t('Export')}
+
+ {/if}