This commit is contained in:
Timothy Jaeryang Baek committed 2026-05-14 13:12:59 +09:00
1 parent 74ae177d79
commit 9c14740ffb
10 files changed
+619

No files matched your search

+89
View File
@@ -7,6 +7,7 @@ from fastapi import APIRouter, Depends, HTTPException, Request, status
from open_webui.config import CACHE_DIR
from open_webui.constants import ERROR_MESSAGES
from open_webui.internal.db import get_async_session
from open_webui.models.access_grants import AccessGrants
from open_webui.models.groups import (
GroupForm,
GroupInfoResponse,
@@ -15,6 +16,9 @@ from open_webui.models.groups import (
GroupUpdateForm,
UserIdsForm,
)
from open_webui.models.knowledge import Knowledges
from open_webui.models.models import Models
from open_webui.models.tools import Tools
from open_webui.models.users import UserInfoResponse, Users
from open_webui.utils.auth import get_admin_user, get_verified_user
from sqlalchemy.ext.asyncio import AsyncSession
@@ -273,3 +277,88 @@ async def delete_group_by_id(id: str, user=Depends(get_admin_user), db: AsyncSes
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
############################
# PreviewGroupAccess
############################
@router.get('/id/{id}/preview')
async def preview_group_access(
id: str,
user=Depends(get_admin_user),
db: AsyncSession = Depends(get_async_session),
):
"""Show what resources a group can access (preview audit)."""
group = await Groups.get_group_by_id(id, db=db)
if not group:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
group_ids = {group.id}
# Batch-check accessible resources using existing AccessGrants
all_models = await Models.get_all_models(db=db)
accessible_model_ids = await AccessGrants.get_accessible_resource_ids(
user_id='',
resource_type='model',
resource_ids=[m.id for m in all_models],
permission='read',
user_group_ids=group_ids,
db=db,
)
all_knowledge = await Knowledges.get_knowledge_bases(db=db)
accessible_knowledge_ids = await AccessGrants.get_accessible_resource_ids(
user_id='',
resource_type='knowledge',
resource_ids=[k.id for k in all_knowledge],
permission='read',
user_group_ids=group_ids,
db=db,
)
all_tools = await Tools.get_tools(defer_content=True, db=db)
accessible_tool_ids = await AccessGrants.get_accessible_resource_ids(
user_id='',
resource_type='tool',
resource_ids=[t.id for t in all_tools],
permission='read',
user_group_ids=group_ids,
db=db,
)
active_models = [m for m in all_models if m.is_active]
return {
'group': {'id': group.id, 'name': group.name},
'models': {
'items': [
{'id': m.id, 'name': m.name}
for m in active_models
if m.id in accessible_model_ids
],
'total': len(active_models),
},
'knowledge': {
'items': [
{'id': k.id, 'name': k.name}
for k in all_knowledge
if k.id in accessible_knowledge_ids
],
'total': len(all_knowledge),
},
'tools': {
'items': [
{'id': t.id, 'name': t.name}
for t in all_tools
if t.id in accessible_tool_ids
],
'total': len(all_tools),
},
'permissions': group.permissions or {},
}
+90
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
import base64
import io
import logging
import time
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Request, status
@@ -25,6 +26,10 @@ from open_webui.models.users import (
UserStatus,
UserUpdateForm,
)
from open_webui.models.access_grants import AccessGrants
from open_webui.models.knowledge import Knowledges
from open_webui.models.models import Models
from open_webui.models.tools import Tools
from open_webui.socket.main import disconnect_user_sessions
from open_webui.utils.access_control import get_permissions, has_permission
from open_webui.utils.auth import (
@@ -677,3 +682,88 @@ async def get_user_groups_by_id(
user_id: str, user=Depends(get_admin_user), db: AsyncSession = Depends(get_async_session)
):
return await Groups.get_groups_by_member_id(user_id, db=db)
############################
# GetUserPreview
############################
@router.get('/{user_id}/preview')
async def get_user_preview(
user_id: str,
user=Depends(get_admin_user),
db: AsyncSession = Depends(get_async_session),
):
"""Show what resources a specific user can access across all their groups."""
target_user = await Users.get_user_by_id(user_id, db=db)
if not target_user:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.USER_NOT_FOUND,
)
# Get all group IDs this user belongs to
user_groups = await Groups.get_groups_by_member_id(user_id, db=db)
user_group_ids = {g.id for g in user_groups}
all_models = await Models.get_all_models(db=db)
accessible_model_ids = await AccessGrants.get_accessible_resource_ids(
user_id=user_id,
resource_type='model',
resource_ids=[m.id for m in all_models],
permission='read',
user_group_ids=user_group_ids,
db=db,
)
all_knowledge = await Knowledges.get_knowledge_bases(db=db)
accessible_knowledge_ids = await AccessGrants.get_accessible_resource_ids(
user_id=user_id,
resource_type='knowledge',
resource_ids=[k.id for k in all_knowledge],
permission='read',
user_group_ids=user_group_ids,
db=db,
)
all_tools = await Tools.get_tools(defer_content=True, db=db)
accessible_tool_ids = await AccessGrants.get_accessible_resource_ids(
user_id=user_id,
resource_type='tool',
resource_ids=[t.id for t in all_tools],
permission='read',
user_group_ids=user_group_ids,
db=db,
)
active_models = [m for m in all_models if m.is_active]
return {
'user': {'id': target_user.id, 'name': target_user.name},
'groups': [{'id': g.id, 'name': g.name} for g in user_groups],
'models': {
'items': [
{'id': m.id, 'name': m.name}
for m in active_models
if m.id in accessible_model_ids
],
'total': len(active_models),
},
'knowledge': {
'items': [
{'id': k.id, 'name': k.name}
for k in all_knowledge
if k.id in accessible_knowledge_ids
],
'total': len(all_knowledge),
},
'tools': {
'items': [
{'id': t.id, 'name': t.name}
for t in all_tools
if t.id in accessible_tool_ids
],
'total': len(all_tools),
},
}