完全移除模块级权限系统,迁移至接口级权限
后端: - 删除 StudyRolePermission 模型和 project_permissions API 文件 - 重写 project_permissions.py core,移除所有模块级权限函数 - 重写 permission_cache.py,移除模块级权限缓存逻辑 - 新增权限模板功能(PermissionTemplate 模型、API、服务层) - 新增 permission_templates 数据库迁移 - 迁移 8 个模块(attachments、audit_logs、dashboard、faqs、 faq_categories、fees_attachments、knowledge_notes、 material_equipments、overview、subject_histories、subject_pds) 至接口级权限检查 - 删除所有模块级权限相关测试文件,新增权限模板测试 前端: - 删除 ProjectPermissions.vue 和 ProjectPermissionsModule.vue - 重写 projectRoutePermissions.ts,改为基于接口级权限格式 - 更新 store/study.ts、router/index.ts、AuditLogs.vue、Projects.vue 中的权限 API 调用,从 fetchProjectRolePermissions 改为 fetchApiEndpointPermissions - 清理 types/api.ts 中的旧模块级权限类型定义 - 新增 PermissionTemplateSelector.vue 组件 - 更新权限管理页面,移除模块级权限 tab Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
"""权限模板管理API"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from typing import Annotated, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.responses import Response
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.deps import get_current_user, get_db_session, require_study_roles
|
||||
from app.models.permission_template import TemplateType
|
||||
from app.schemas.permission_template import (
|
||||
ApplyTemplateRequest,
|
||||
ApplyTemplateResponse,
|
||||
PermissionTemplateCreate,
|
||||
PermissionTemplateRead,
|
||||
PermissionTemplateUpdate,
|
||||
)
|
||||
from app.services.permission_template_service import PermissionTemplateService
|
||||
|
||||
# 模板管理路由(不需要 study_id)
|
||||
router = APIRouter(prefix="/permission-templates", tags=["permission-templates"])
|
||||
|
||||
# 项目级模板操作路由(需要 study_id,挂载到 /studies/{study_id})
|
||||
study_router = APIRouter(prefix="/permission-templates", tags=["permission-templates"])
|
||||
|
||||
|
||||
@router.get("", response_model=list[PermissionTemplateRead])
|
||||
async def list_templates(
|
||||
template_type: Optional[str] = None,
|
||||
category: Optional[str] = None,
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
db: Annotated[AsyncSession, Depends(get_db_session)] = None,
|
||||
) -> list[PermissionTemplateRead]:
|
||||
"""列表权限模板"""
|
||||
t_type = TemplateType(template_type) if template_type else None
|
||||
templates = await PermissionTemplateService.list_templates(
|
||||
db, template_type=t_type, category=category, skip=skip, limit=limit
|
||||
)
|
||||
return [PermissionTemplateRead.model_validate(t) for t in templates]
|
||||
|
||||
|
||||
@router.post(
|
||||
"",
|
||||
response_model=PermissionTemplateRead,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
)
|
||||
async def create_template(
|
||||
payload: PermissionTemplateCreate,
|
||||
db: Annotated[AsyncSession, Depends(get_db_session)] = None,
|
||||
current_user=Depends(get_current_user),
|
||||
) -> PermissionTemplateRead:
|
||||
"""创建权限模板"""
|
||||
try:
|
||||
template = await PermissionTemplateService.create_template(db, payload, current_user.id)
|
||||
return PermissionTemplateRead.model_validate(template)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/{template_id}", response_model=PermissionTemplateRead)
|
||||
async def get_template(
|
||||
template_id: uuid.UUID,
|
||||
db: Annotated[AsyncSession, Depends(get_db_session)] = None,
|
||||
) -> PermissionTemplateRead:
|
||||
"""获取权限模板"""
|
||||
template = await PermissionTemplateService.get_template(db, template_id)
|
||||
if not template:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="模板不存在")
|
||||
return PermissionTemplateRead.model_validate(template)
|
||||
|
||||
|
||||
@router.put("/{template_id}", response_model=PermissionTemplateRead)
|
||||
async def update_template(
|
||||
template_id: uuid.UUID,
|
||||
payload: PermissionTemplateUpdate,
|
||||
db: Annotated[AsyncSession, Depends(get_db_session)] = None,
|
||||
current_user=Depends(get_current_user),
|
||||
) -> PermissionTemplateRead:
|
||||
"""更新权限模板"""
|
||||
try:
|
||||
template = await PermissionTemplateService.update_template(db, template_id, payload)
|
||||
return PermissionTemplateRead.model_validate(template)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
|
||||
|
||||
|
||||
@router.delete("/{template_id}", status_code=status.HTTP_204_NO_CONTENT, response_class=Response)
|
||||
async def delete_template(
|
||||
template_id: uuid.UUID,
|
||||
db: Annotated[AsyncSession, Depends(get_db_session)] = None,
|
||||
current_user=Depends(get_current_user),
|
||||
):
|
||||
"""删除权限模板"""
|
||||
try:
|
||||
await PermissionTemplateService.delete_template(db, template_id)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
|
||||
|
||||
|
||||
@study_router.post(
|
||||
"/{template_id}/apply",
|
||||
response_model=ApplyTemplateResponse,
|
||||
)
|
||||
async def apply_template(
|
||||
study_id: uuid.UUID,
|
||||
template_id: uuid.UUID,
|
||||
payload: ApplyTemplateRequest,
|
||||
db: Annotated[AsyncSession, Depends(get_db_session)] = None,
|
||||
_=Depends(require_study_roles(["PM"])),
|
||||
) -> ApplyTemplateResponse:
|
||||
"""应用权限模板到项目"""
|
||||
try:
|
||||
result = await PermissionTemplateService.apply_template(
|
||||
db,
|
||||
study_id,
|
||||
payload.template_id,
|
||||
roles=payload.roles,
|
||||
override=payload.override,
|
||||
)
|
||||
return ApplyTemplateResponse(**result)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
|
||||
Reference in New Issue
Block a user