diff --git a/backend/api/kb_file_router.py b/backend/api/kb_file_router.py index d18eaeb..614ede6 100644 --- a/backend/api/kb_file_router.py +++ b/backend/api/kb_file_router.py @@ -333,7 +333,7 @@ async def upload_file( kb = await _check_kb_access(conn, kb_id, current_user) # 检查上传权限(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("您的上传权限已被关闭,请联系部门领导或管理员") # 检查文件类型 @@ -489,7 +489,7 @@ async def upload_url( ): """上传 URL 到知识库并进行向量化处理""" 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("您的上传权限已被关闭,请联系部门领导或管理员") url = request.url.strip() diff --git a/backend/core/permissions.py b/backend/core/permissions.py index 6ce21ae..03a45d4 100644 --- a/backend/core/permissions.py +++ b/backend/core/permissions.py @@ -87,14 +87,16 @@ 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": return True if kb.creator_id is not None and user.id == kb.creator_id: return True - if user.role == "leader" and user.department_id is not None and kb.department_id == user.department_id: - return True + 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 vis = kb.visibility or "private" if vis == "private": return False @@ -144,14 +146,14 @@ async def can_delete_file( 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 - allow_kb_upload 未被关闭 - 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 bool(user.allow_kb_upload) diff --git a/backend/services/knowledge_base_service.py b/backend/services/knowledge_base_service.py index 0b5366e..a318996 100644 --- a/backend/services/knowledge_base_service.py +++ b/backend/services/knowledge_base_service.py @@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional, Tuple 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.user import User from logger.logging import get_logger @@ -185,7 +185,7 @@ class KnowledgeBaseService: kb = await KnowledgeBaseService.fetch_knowledge_base_by_id(conn, kb_id) if kb is None: return None - if not can_view_kb(user, kb): + if not await can_view_kb(conn, user, kb): return None return kb @@ -206,14 +206,19 @@ class KnowledgeBaseService: dept_id = user.department_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 = """ kb.is_deleted = FALSE AND kb.enterprise_id = $1 AND ( $2::text = 'admin' OR kb.creator_id = $3 - OR ($2::text = 'leader' 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 = $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 = $5) OR (kb.visibility = 'enterprise') ) """ @@ -226,6 +231,7 @@ class KnowledgeBaseService: enterprise_id, role, uid, + managed_dept_ids, dept_id, ) @@ -241,11 +247,12 @@ class KnowledgeBaseService: LEFT JOIN department d ON d.id = kb.department_id WHERE {where_sql} ORDER BY kb.created_at DESC - LIMIT $5 OFFSET $6 + LIMIT $6 OFFSET $7 """, enterprise_id, role, uid, + managed_dept_ids, dept_id, page_size, offset,