diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py
index ec62c8ba01..54ca0218d7 100644
--- a/backend/open_webui/config.py
+++ b/backend/open_webui/config.py
@@ -1447,6 +1447,10 @@ USER_PERMISSIONS_FEATURES_CODE_INTERPRETER = (
== "true"
)
+USER_PERMISSIONS_FEATURES_FOLDERS = (
+ os.environ.get("USER_PERMISSIONS_FEATURES_FOLDERS", "True").lower() == "true"
+)
+
USER_PERMISSIONS_FEATURES_NOTES = (
os.environ.get("USER_PERMISSIONS_FEATURES_NOTES", "True").lower() == "true"
)
@@ -1503,12 +1507,15 @@ DEFAULT_USER_PERMISSIONS = {
"temporary_enforced": USER_PERMISSIONS_CHAT_TEMPORARY_ENFORCED,
},
"features": {
+ # General features
"api_keys": USER_PERMISSIONS_FEATURES_API_KEYS,
+ "folders": USER_PERMISSIONS_FEATURES_FOLDERS,
+ "notes": USER_PERMISSIONS_FEATURES_NOTES,
"direct_tool_servers": USER_PERMISSIONS_FEATURES_DIRECT_TOOL_SERVERS,
+ # Chat features
"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,
},
}
@@ -1518,6 +1525,12 @@ USER_PERMISSIONS = PersistentConfig(
DEFAULT_USER_PERMISSIONS,
)
+ENABLE_FOLDERS = PersistentConfig(
+ "ENABLE_FOLDERS",
+ "folders.enable",
+ os.environ.get("ENABLE_FOLDERS", "True").lower() == "true",
+)
+
ENABLE_CHANNELS = PersistentConfig(
"ENABLE_CHANNELS",
"channels.enable",
diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py
index af8e670a53..899a3e08e1 100644
--- a/backend/open_webui/main.py
+++ b/backend/open_webui/main.py
@@ -352,6 +352,7 @@ from open_webui.config import (
ENABLE_API_KEYS,
ENABLE_API_KEYS_ENDPOINT_RESTRICTIONS,
API_KEYS_ALLOWED_ENDPOINTS,
+ ENABLE_FOLDERS,
ENABLE_CHANNELS,
ENABLE_NOTES,
ENABLE_COMMUNITY_SHARING,
@@ -767,6 +768,7 @@ app.state.config.WEBHOOK_URL = WEBHOOK_URL
app.state.config.BANNERS = WEBUI_BANNERS
+app.state.config.ENABLE_FOLDERS = ENABLE_FOLDERS
app.state.config.ENABLE_CHANNELS = ENABLE_CHANNELS
app.state.config.ENABLE_NOTES = ENABLE_NOTES
app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING
@@ -1842,6 +1844,7 @@ async def get_app_config(request: Request):
**(
{
"enable_direct_connections": app.state.config.ENABLE_DIRECT_CONNECTIONS,
+ "enable_folders": app.state.config.ENABLE_FOLDERS,
"enable_channels": app.state.config.ENABLE_CHANNELS,
"enable_notes": app.state.config.ENABLE_NOTES,
"enable_web_search": app.state.config.ENABLE_WEB_SEARCH,
diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py
index 2a73496f3b..24cbd9a03f 100644
--- a/backend/open_webui/routers/auths.py
+++ b/backend/open_webui/routers/auths.py
@@ -900,6 +900,7 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)):
"JWT_EXPIRES_IN": request.app.state.config.JWT_EXPIRES_IN,
"ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING,
"ENABLE_MESSAGE_RATING": request.app.state.config.ENABLE_MESSAGE_RATING,
+ "ENABLE_FOLDERS": request.app.state.config.ENABLE_FOLDERS,
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
"ENABLE_NOTES": request.app.state.config.ENABLE_NOTES,
"ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
@@ -921,6 +922,7 @@ class AdminConfig(BaseModel):
JWT_EXPIRES_IN: str
ENABLE_COMMUNITY_SHARING: bool
ENABLE_MESSAGE_RATING: bool
+ ENABLE_FOLDERS: bool
ENABLE_CHANNELS: bool
ENABLE_NOTES: bool
ENABLE_USER_WEBHOOKS: bool
@@ -945,6 +947,7 @@ async def update_admin_config(
form_data.API_KEYS_ALLOWED_ENDPOINTS
)
+ request.app.state.config.ENABLE_FOLDERS = form_data.ENABLE_FOLDERS
request.app.state.config.ENABLE_CHANNELS = form_data.ENABLE_CHANNELS
request.app.state.config.ENABLE_NOTES = form_data.ENABLE_NOTES
@@ -987,6 +990,7 @@ async def update_admin_config(
"JWT_EXPIRES_IN": request.app.state.config.JWT_EXPIRES_IN,
"ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING,
"ENABLE_MESSAGE_RATING": request.app.state.config.ENABLE_MESSAGE_RATING,
+ "ENABLE_FOLDERS": request.app.state.config.ENABLE_FOLDERS,
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
"ENABLE_NOTES": request.app.state.config.ENABLE_NOTES,
"ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
diff --git a/backend/open_webui/routers/folders.py b/backend/open_webui/routers/folders.py
index 03212bdb7c..fe2bf367bf 100644
--- a/backend/open_webui/routers/folders.py
+++ b/backend/open_webui/routers/folders.py
@@ -46,7 +46,23 @@ router = APIRouter()
@router.get("/", response_model=list[FolderNameIdResponse])
-async def get_folders(user=Depends(get_verified_user)):
+async def get_folders(request: Request, user=Depends(get_verified_user)):
+ if request.app.state.config.ENABLE_FOLDERS is False:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
+ )
+
+ if user.role != "admin" and not has_permission(
+ user.id,
+ "features.folders",
+ request.app.state.config.USER_PERMISSIONS,
+ ):
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
+ )
+
folders = Folders.get_folders_by_user_id(user.id)
# Verify folder data integrity
diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py
index eddc56d77a..9b30ba8f20 100644
--- a/backend/open_webui/routers/users.py
+++ b/backend/open_webui/routers/users.py
@@ -219,11 +219,13 @@ class ChatPermissions(BaseModel):
class FeaturesPermissions(BaseModel):
api_keys: bool = False
+ folders: bool = True
+ notes: bool = True
direct_tool_servers: bool = False
+
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/Settings/General.svelte b/src/lib/components/admin/Settings/General.svelte
index a7b62857c0..d46f37a89f 100644
--- a/src/lib/components/admin/Settings/General.svelte
+++ b/src/lib/components/admin/Settings/General.svelte
@@ -676,6 +676,14 @@