处理孙子部门权限问题

This commit is contained in:
silk 2026-06-02 13:33:12 +08:00
parent 8f21add2d4
commit 2014daee67
3 changed files with 22 additions and 13 deletions

View File

@ -333,7 +333,7 @@ async def upload_file(
kb = await _check_kb_access(conn, kb_id, current_user) kb = await _check_kb_access(conn, kb_id, current_user)
# 检查上传权限allow_kb_upload 开关) # 检查上传权限allow_kb_upload 开关)
if not can_upload_to_kb(current_user, kb): if not await can_upload_to_kb(conn, current_user, kb):
raise BadRequestError("您的上传权限已被关闭,请联系部门领导或管理员") raise BadRequestError("您的上传权限已被关闭,请联系部门领导或管理员")
# 检查文件类型 # 检查文件类型
@ -489,7 +489,7 @@ async def upload_url(
): ):
"""上传 URL 到知识库并进行向量化处理""" """上传 URL 到知识库并进行向量化处理"""
kb = await _check_kb_access(conn, kb_id, current_user) kb = await _check_kb_access(conn, kb_id, current_user)
if not can_upload_to_kb(current_user, kb): if not await can_upload_to_kb(conn, current_user, kb):
raise BadRequestError("您的上传权限已被关闭,请联系部门领导或管理员") raise BadRequestError("您的上传权限已被关闭,请联系部门领导或管理员")
url = request.url.strip() url = request.url.strip()

View File

@ -87,13 +87,15 @@ async def is_subordinate(
# 知识库级权限(同步,无需数据库) # 知识库级权限(同步,无需数据库)
# ────────────────────────────────────────────── # ──────────────────────────────────────────────
def can_view_kb(user: User, kb: KnowledgeBase) -> bool: async def can_view_kb(conn: asyncpg.Connection, user: User, kb: KnowledgeBase) -> bool:
"""判断用户是否可查看该知识库。""" """判断用户是否可查看该知识库。leader 权限覆盖本部门及所有子孙部门。"""
if user.role == "admin": if user.role == "admin":
return True return True
if kb.creator_id is not None and user.id == kb.creator_id: if kb.creator_id is not None and user.id == kb.creator_id:
return True return True
if user.role == "leader" and user.department_id is not None and kb.department_id == user.department_id: if user.role == "leader" and user.department_id is not None and kb.department_id is not None:
managed = await get_managed_dept_ids(conn, user)
if kb.department_id in managed:
return True return True
vis = kb.visibility or "private" vis = kb.visibility or "private"
if vis == "private": if vis == "private":
@ -144,14 +146,14 @@ async def can_delete_file(
return False return False
def can_upload_to_kb(user: User, kb: KnowledgeBase) -> bool: async def can_upload_to_kb(conn: asyncpg.Connection, user: User, kb: KnowledgeBase) -> bool:
""" """
判断用户是否可向知识库上传文件 判断用户是否可向知识库上传文件
- 必须能 view KB - 必须能 view KB
- allow_kb_upload 未被关闭 - allow_kb_upload 未被关闭
- leader admin 也受 allow_kb_upload 约束管理员初始化时均为 True - leader admin 也受 allow_kb_upload 约束管理员初始化时均为 True
""" """
if not can_view_kb(user, kb): if not await can_view_kb(conn, user, kb):
return False return False
return bool(user.allow_kb_upload) return bool(user.allow_kb_upload)

View File

@ -4,7 +4,7 @@
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
import asyncpg import asyncpg
from core.permissions import can_manage_kb, can_view_kb from core.permissions import can_manage_kb, can_view_kb, get_managed_dept_ids
from models.knowledge_base import KnowledgeBase, KnowledgeBaseCreate, KnowledgeBaseUpdate from models.knowledge_base import KnowledgeBase, KnowledgeBaseCreate, KnowledgeBaseUpdate
from models.user import User from models.user import User
from logger.logging import get_logger from logger.logging import get_logger
@ -185,7 +185,7 @@ class KnowledgeBaseService:
kb = await KnowledgeBaseService.fetch_knowledge_base_by_id(conn, kb_id) kb = await KnowledgeBaseService.fetch_knowledge_base_by_id(conn, kb_id)
if kb is None: if kb is None:
return None return None
if not can_view_kb(user, kb): if not await can_view_kb(conn, user, kb):
return None return None
return kb return kb
@ -206,14 +206,19 @@ class KnowledgeBaseService:
dept_id = user.department_id dept_id = user.department_id
uid = user.id uid = user.id
# leader 需要获取本部门及所有子孙部门 ID用于列表过滤
managed_dept_ids: List[int] = []
if role == "leader" and dept_id is not None:
managed_dept_ids = await get_managed_dept_ids(conn, user)
where_sql = """ where_sql = """
kb.is_deleted = FALSE kb.is_deleted = FALSE
AND kb.enterprise_id = $1 AND kb.enterprise_id = $1
AND ( AND (
$2::text = 'admin' $2::text = 'admin'
OR kb.creator_id = $3 OR kb.creator_id = $3
OR ($2::text = 'leader' AND kb.department_id IS NOT NULL AND kb.department_id = $4) OR ($2::text = 'leader' AND kb.department_id IS NOT NULL AND kb.department_id = ANY($4::int[]))
OR (kb.visibility = 'department' AND kb.department_id IS NOT NULL AND kb.department_id = $4) OR (kb.visibility = 'department' AND kb.department_id IS NOT NULL AND kb.department_id = $5)
OR (kb.visibility = 'enterprise') OR (kb.visibility = 'enterprise')
) )
""" """
@ -226,6 +231,7 @@ class KnowledgeBaseService:
enterprise_id, enterprise_id,
role, role,
uid, uid,
managed_dept_ids,
dept_id, dept_id,
) )
@ -241,11 +247,12 @@ class KnowledgeBaseService:
LEFT JOIN department d ON d.id = kb.department_id LEFT JOIN department d ON d.id = kb.department_id
WHERE {where_sql} WHERE {where_sql}
ORDER BY kb.created_at DESC ORDER BY kb.created_at DESC
LIMIT $5 OFFSET $6 LIMIT $6 OFFSET $7
""", """,
enterprise_id, enterprise_id,
role, role,
uid, uid,
managed_dept_ids,
dept_id, dept_id,
page_size, page_size,
offset, offset,