Files
ctms/backend/tests/test_project_permissions.py
T
Cheng Zhou 89cecce6b5 权限管理:新增医学审核项目角色
新增 MEDICAL_REVIEW 项目角色,界面显示为医学审核,并通过 Alembic 迁移扩展 user_role 枚举。

为医学审核配置独立默认权限:项目总览、参与者、风险问题、监查稽查、FAQ、共享库按医学审核职责开放,不再复制 PV 默认权限。

同步前后端类型、项目成员角色下拉、权限矩阵展示、文件分发角色兜底和用户协议文案,并补充权限矩阵回归测试。
2026-05-13 09:25:37 +08:00

190 lines
7.2 KiB
Python

from app.core.project_permissions import PROJECT_PERMISSION_MODULES, normalize_permission_matrix
def test_normalize_permission_matrix_makes_admin_fixed_full_access():
matrix = normalize_permission_matrix({"ADMIN": {}})
for module in PROJECT_PERMISSION_MODULES:
assert matrix["ADMIN"][module["key"]] == {
"read": True,
"write": module.get("writable") is not False,
}
def test_normalize_permission_matrix_keeps_admin_fixed_even_when_disabled():
payload = {
"ADMIN": {
module["key"]: {"read": False, "write": False}
for module in PROJECT_PERMISSION_MODULES
}
}
matrix = normalize_permission_matrix(payload)
for module in PROJECT_PERMISSION_MODULES:
assert matrix["ADMIN"][module["key"]] == {
"read": True,
"write": module.get("writable") is not False,
}
def test_normalize_permission_matrix_write_implies_read():
matrix = normalize_permission_matrix({
"CRA": {
"subjects": {"read": False, "write": True},
}
})
assert matrix["CRA"]["subjects"] == {"read": True, "write": True}
def test_business_permission_modules_follow_project_menu():
module_labels = [module["label"] for module in PROJECT_PERMISSION_MODULES]
assert module_labels == [
"项目成员",
"中心管理",
"审计日志导出",
"项目总览",
"项目里程碑",
"合同费用管理",
"物资管理",
"文件版本管理",
"立项与伦理",
"启动与授权",
"参与者管理",
"风险问题",
"监查稽查",
"eTMF",
"FAQ",
"共享库",
]
def test_default_business_permissions_match_role_responsibilities():
matrix = normalize_permission_matrix()
assert matrix["PM"]["project_members"] == {"read": True, "write": True}
assert matrix["PM"]["sites"] == {"read": True, "write": True}
assert matrix["CRA"]["project_members"] == {"read": False, "write": False}
assert matrix["CRA"]["audit_export"] == {"read": False, "write": False}
assert matrix["PV"]["sites"] == {"read": False, "write": False}
assert matrix["IMP"]["audit_export"] == {"read": False, "write": False}
assert matrix["QA"]["audit_export"] == {"read": False, "write": False}
assert matrix["CRA"]["project_milestones"] == {"read": True, "write": True}
assert matrix["CRA"]["subjects"] == {"read": True, "write": True}
assert matrix["CRA"]["monitoring_audit"] == {"read": True, "write": True}
assert matrix["PV"]["risk_issues"] == {"read": True, "write": True}
assert matrix["MEDICAL_REVIEW"]["project_overview"] == {"read": True, "write": False}
assert matrix["MEDICAL_REVIEW"]["subjects"] == {"read": True, "write": False}
assert matrix["MEDICAL_REVIEW"]["risk_issues"] == {"read": True, "write": True}
assert matrix["MEDICAL_REVIEW"]["monitoring_audit"] == {"read": True, "write": False}
assert matrix["MEDICAL_REVIEW"]["faq"] == {"read": True, "write": True}
assert matrix["MEDICAL_REVIEW"]["shared_library"] == {"read": True, "write": True}
assert matrix["MEDICAL_REVIEW"]["fees"] == {"read": False, "write": False}
assert matrix["MEDICAL_REVIEW"]["materials"] == {"read": False, "write": False}
assert matrix["IMP"]["materials"] == {"read": True, "write": True}
assert matrix["PM"]["faq"] == {"read": True, "write": True}
assert matrix["CRA"]["faq"] == {"read": True, "write": True}
assert matrix["PM"]["project_overview"] == {"read": True, "write": False}
assert matrix["CRA"]["project_overview"] == {"read": True, "write": False}
assert matrix["PM"]["shared_library"] == {"read": True, "write": True}
assert matrix["CRA"]["shared_library"] == {"read": True, "write": True}
def test_project_overview_is_read_only_even_when_write_is_submitted():
matrix = normalize_permission_matrix({
"CRA": {
"project_overview": {"read": False, "write": True},
}
})
assert matrix["CRA"]["project_overview"] == {"read": True, "write": False}
def test_pm_can_be_granted_management_backend_permissions():
matrix = normalize_permission_matrix({
"PM": {
"project_members": {"read": True, "write": True},
"sites": {"read": True, "write": True},
"audit_export": {"read": True, "write": True},
}
})
assert matrix["PM"]["project_members"] == {"read": True, "write": True}
assert matrix["PM"]["sites"] == {"read": True, "write": True}
assert matrix["PM"]["audit_export"] == {"read": True, "write": True}
def test_non_pm_roles_cannot_be_granted_management_backend_permissions():
management_modules = ["project_members", "sites", "audit_export"]
matrix = normalize_permission_matrix({
role: {
module: {"read": True, "write": True}
for module in management_modules
}
for role in ["CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"]
})
for role in ["CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"]:
for module in management_modules:
assert matrix[role][module] == {"read": False, "write": False}
def test_each_non_admin_role_can_toggle_each_writable_module():
roles = ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"]
management_modules = {"project_members", "sites", "audit_export"}
writable_modules = [
module["key"]
for module in PROJECT_PERMISSION_MODULES
if module.get("writable") is not False and module["key"] not in management_modules
]
for role in roles:
enabled = normalize_permission_matrix({
role: {
module: {"read": False, "write": True}
for module in writable_modules
}
})
disabled = normalize_permission_matrix({
role: {
module["key"]: {"read": False, "write": False}
for module in PROJECT_PERMISSION_MODULES
}
})
for module in writable_modules:
assert enabled[role][module] == {"read": True, "write": True}
assert disabled[role][module] == {"read": False, "write": False}
def test_read_only_modules_never_accept_write_for_any_role():
read_only_modules = [
module["key"]
for module in PROJECT_PERMISSION_MODULES
if module.get("writable") is False
]
payload = {
role: {
module: {"read": False, "write": True}
for module in read_only_modules
}
for role in ["ADMIN", "PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"]
}
matrix = normalize_permission_matrix(payload)
for role in ["ADMIN", "PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"]:
for module in read_only_modules:
assert matrix[role][module] == {"read": True, "write": False}
def test_medical_review_default_permissions_are_independent_from_pv():
matrix = normalize_permission_matrix()
assert matrix["PV"]["monitoring_audit"] == {"read": True, "write": True}
assert matrix["MEDICAL_REVIEW"]["monitoring_audit"] == {"read": True, "write": False}
assert matrix["PV"]["fees"] == {"read": True, "write": False}
assert matrix["MEDICAL_REVIEW"]["fees"] == {"read": False, "write": False}