完全移除模块级权限系统,迁移至接口级权限
后端: - 删除 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,230 @@
|
||||
"""权限模板服务单元测试"""
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
|
||||
from app.models.permission_template import PermissionTemplate, TemplateType
|
||||
from app.schemas.permission_template import PermissionTemplateCreate, PermissionTemplateUpdate
|
||||
from app.services.permission_template_service import PermissionTemplateService
|
||||
|
||||
|
||||
SAMPLE_PERMISSIONS = {
|
||||
"PM": {
|
||||
"subjects:create": True,
|
||||
"subjects:read": True,
|
||||
"subjects:update": True,
|
||||
"subjects:delete": False,
|
||||
},
|
||||
"CRA": {
|
||||
"subjects:create": False,
|
||||
"subjects:read": True,
|
||||
"subjects:update": False,
|
||||
"subjects:delete": False,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def user_id() -> uuid.UUID:
|
||||
return uuid.uuid4()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 创建模板
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_template_success(db_session, user_id):
|
||||
payload = PermissionTemplateCreate(
|
||||
name="测试模板",
|
||||
description="用于测试",
|
||||
template_type=TemplateType.CUSTOM,
|
||||
permissions=SAMPLE_PERMISSIONS,
|
||||
)
|
||||
template = await PermissionTemplateService.create_template(db_session, payload, user_id)
|
||||
|
||||
assert template.id is not None
|
||||
assert template.name == "测试模板"
|
||||
assert template.is_system is False
|
||||
assert template.template_type == TemplateType.CUSTOM
|
||||
assert template.permissions == SAMPLE_PERMISSIONS
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_template_creates_version_1(db_session, user_id):
|
||||
payload = PermissionTemplateCreate(
|
||||
name="版本测试",
|
||||
template_type=TemplateType.CUSTOM,
|
||||
permissions=SAMPLE_PERMISSIONS,
|
||||
)
|
||||
template = await PermissionTemplateService.create_template(db_session, payload, user_id)
|
||||
|
||||
await db_session.refresh(template, ["versions"])
|
||||
assert len(template.versions) == 1
|
||||
assert template.versions[0].version == 1
|
||||
assert template.versions[0].change_log == "初始版本"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_template_invalid_endpoint_key(db_session, user_id):
|
||||
payload = PermissionTemplateCreate(
|
||||
name="无效模板",
|
||||
template_type=TemplateType.CUSTOM,
|
||||
permissions={"PM": {"nonexistent:action": True}},
|
||||
)
|
||||
with pytest.raises(ValueError, match="权限操作 nonexistent:action 不存在"):
|
||||
await PermissionTemplateService.create_template(db_session, payload, user_id)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_template_invalid_permission_value(db_session, user_id):
|
||||
payload = PermissionTemplateCreate(
|
||||
name="无效值模板",
|
||||
template_type=TemplateType.CUSTOM,
|
||||
permissions={"PM": {"subjects:read": "yes"}}, # type: ignore
|
||||
)
|
||||
with pytest.raises(ValueError, match="必须是布尔类型"):
|
||||
await PermissionTemplateService.create_template(db_session, payload, user_id)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 获取模板
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_template_exists(db_session, user_id):
|
||||
payload = PermissionTemplateCreate(
|
||||
name="获取测试",
|
||||
template_type=TemplateType.ROLE,
|
||||
permissions=SAMPLE_PERMISSIONS,
|
||||
)
|
||||
created = await PermissionTemplateService.create_template(db_session, payload, user_id)
|
||||
fetched = await PermissionTemplateService.get_template(db_session, created.id)
|
||||
|
||||
assert fetched is not None
|
||||
assert fetched.id == created.id
|
||||
assert fetched.name == "获取测试"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_template_not_found(db_session):
|
||||
result = await PermissionTemplateService.get_template(db_session, uuid.uuid4())
|
||||
assert result is None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 列表模板
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_templates_filter_by_type(db_session, user_id):
|
||||
await PermissionTemplateService.create_template(
|
||||
db_session,
|
||||
PermissionTemplateCreate(name="角色模板", template_type=TemplateType.ROLE, permissions=SAMPLE_PERMISSIONS),
|
||||
user_id,
|
||||
)
|
||||
await PermissionTemplateService.create_template(
|
||||
db_session,
|
||||
PermissionTemplateCreate(name="场景模板", template_type=TemplateType.SCENARIO, permissions=SAMPLE_PERMISSIONS),
|
||||
user_id,
|
||||
)
|
||||
|
||||
role_templates = await PermissionTemplateService.list_templates(db_session, template_type=TemplateType.ROLE)
|
||||
assert all(t.template_type == TemplateType.ROLE for t in role_templates)
|
||||
assert len(role_templates) >= 1
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 更新模板
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_template_name(db_session, user_id):
|
||||
created = await PermissionTemplateService.create_template(
|
||||
db_session,
|
||||
PermissionTemplateCreate(name="旧名称", template_type=TemplateType.CUSTOM, permissions=SAMPLE_PERMISSIONS),
|
||||
user_id,
|
||||
)
|
||||
|
||||
updated = await PermissionTemplateService.update_template(
|
||||
db_session, created.id, PermissionTemplateUpdate(name="新名称")
|
||||
)
|
||||
assert updated.name == "新名称"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_template_permissions_creates_new_version(db_session, user_id):
|
||||
created = await PermissionTemplateService.create_template(
|
||||
db_session,
|
||||
PermissionTemplateCreate(name="版本测试2", template_type=TemplateType.CUSTOM, permissions=SAMPLE_PERMISSIONS),
|
||||
user_id,
|
||||
)
|
||||
|
||||
new_perms = {"PM": {"subjects:read": True}}
|
||||
await PermissionTemplateService.update_template(
|
||||
db_session, created.id, PermissionTemplateUpdate(permissions=new_perms)
|
||||
)
|
||||
|
||||
updated = await PermissionTemplateService.get_template(db_session, created.id)
|
||||
await db_session.refresh(updated, ["versions"])
|
||||
assert len(updated.versions) == 2
|
||||
assert updated.versions[-1].version == 2
|
||||
assert updated.permissions == new_perms
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_system_template_raises(db_session):
|
||||
system_template = PermissionTemplate(
|
||||
name="系统模板",
|
||||
template_type=TemplateType.ROLE,
|
||||
is_system=True,
|
||||
permissions=SAMPLE_PERMISSIONS,
|
||||
)
|
||||
db_session.add(system_template)
|
||||
await db_session.commit()
|
||||
await db_session.refresh(system_template)
|
||||
|
||||
with pytest.raises(ValueError, match="不允许修改系统预设模板"):
|
||||
await PermissionTemplateService.update_template(
|
||||
db_session, system_template.id, PermissionTemplateUpdate(name="改名")
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 删除模板
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_delete_template_success(db_session, user_id):
|
||||
created = await PermissionTemplateService.create_template(
|
||||
db_session,
|
||||
PermissionTemplateCreate(name="待删除", template_type=TemplateType.CUSTOM, permissions=SAMPLE_PERMISSIONS),
|
||||
user_id,
|
||||
)
|
||||
|
||||
await PermissionTemplateService.delete_template(db_session, created.id)
|
||||
assert await PermissionTemplateService.get_template(db_session, created.id) is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_delete_system_template_raises(db_session):
|
||||
system_template = PermissionTemplate(
|
||||
name="系统模板2",
|
||||
template_type=TemplateType.ROLE,
|
||||
is_system=True,
|
||||
permissions=SAMPLE_PERMISSIONS,
|
||||
)
|
||||
db_session.add(system_template)
|
||||
await db_session.commit()
|
||||
await db_session.refresh(system_template)
|
||||
|
||||
with pytest.raises(ValueError, match="不允许删除系统预设模板"):
|
||||
await PermissionTemplateService.delete_template(db_session, system_template.id)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_delete_nonexistent_template_raises(db_session):
|
||||
with pytest.raises(ValueError, match="不存在"):
|
||||
await PermissionTemplateService.delete_template(db_session, uuid.uuid4())
|
||||
Reference in New Issue
Block a user