完善审计日志展示与导出权限
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import uuid
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
|
||||
import pytest
|
||||
@@ -7,11 +8,11 @@ from sqlalchemy import text
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.v1.api_permissions import get_my_study_api_permissions, update_study_api_permissions
|
||||
from app.api.v1.members import update_member
|
||||
from app.api.v1.members import add_member, update_member
|
||||
from app.api.v1.permission_monitoring import resolve_monitoring_scope
|
||||
from app.api.v1.system_permissions import list_system_permissions
|
||||
from app.core.deps import require_admin_or_any_project_pm, require_system_permission
|
||||
from app.schemas.member import StudyMemberUpdate
|
||||
from app.schemas.member import StudyMemberCreate, StudyMemberUpdate
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -40,6 +41,26 @@ async def _seed_user(db: AsyncSession, user_id: uuid.UUID, *, is_admin: bool = F
|
||||
)
|
||||
|
||||
|
||||
async def _seed_named_user(db: AsyncSession, user_id: uuid.UUID, full_name: str, *, is_admin: bool = False) -> None:
|
||||
await db.execute(
|
||||
text(
|
||||
"""
|
||||
INSERT INTO users (id, email, password_hash, full_name, clinical_department, is_admin, status)
|
||||
VALUES (:id, :email, :password_hash, :full_name, :clinical_department, :is_admin, :status)
|
||||
"""
|
||||
),
|
||||
{
|
||||
"id": str(user_id),
|
||||
"email": f"{user_id.hex}@example.com",
|
||||
"password_hash": "hash",
|
||||
"full_name": full_name,
|
||||
"clinical_department": "Clinical",
|
||||
"is_admin": is_admin,
|
||||
"status": "ACTIVE",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def _seed_study(db: AsyncSession, study_id: uuid.UUID, code: str) -> None:
|
||||
await db.execute(
|
||||
text(
|
||||
@@ -289,3 +310,77 @@ async def test_project_pm_cannot_grant_peer_pm_role(db_session: AsyncSession):
|
||||
)
|
||||
|
||||
assert exc_info.value.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_project_member_add_audit_uses_member_display_name(db_session: AsyncSession):
|
||||
study_id = uuid.uuid4()
|
||||
admin_id = uuid.uuid4()
|
||||
target_user_id = uuid.uuid4()
|
||||
await _seed_study(db_session, study_id, "MEMBER-AUDIT-NAME")
|
||||
await _seed_user(db_session, admin_id, is_admin=True)
|
||||
await _seed_named_user(db_session, target_user_id, "张三")
|
||||
await db_session.commit()
|
||||
|
||||
await add_member(
|
||||
study_id=study_id,
|
||||
member_in=StudyMemberCreate(user_id=target_user_id, role_in_study="CRA"),
|
||||
current_user=UserStub(id=admin_id, is_admin=True),
|
||||
db=db_session,
|
||||
)
|
||||
|
||||
row = (
|
||||
await db_session.execute(
|
||||
text(
|
||||
"""
|
||||
SELECT detail
|
||||
FROM audit_logs
|
||||
WHERE study_id = :study_id AND action = 'PROJECT_MEMBER_ADDED'
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
"""
|
||||
),
|
||||
{"study_id": str(study_id)},
|
||||
)
|
||||
).one()
|
||||
detail = json.loads(row.detail)
|
||||
assert detail["targetName"] == "张三"
|
||||
assert str(target_user_id) not in detail["targetName"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_project_member_update_audit_uses_member_display_name(db_session: AsyncSession):
|
||||
study_id = uuid.uuid4()
|
||||
admin_id = uuid.uuid4()
|
||||
target_user_id = uuid.uuid4()
|
||||
await _seed_study(db_session, study_id, "MEMBER-UPDATE-AUDIT-NAME")
|
||||
await _seed_user(db_session, admin_id, is_admin=True)
|
||||
await _seed_named_user(db_session, target_user_id, "李四")
|
||||
member_id = await _seed_member_return_id(db_session, study_id, target_user_id, "CRA")
|
||||
await db_session.commit()
|
||||
|
||||
await update_member(
|
||||
study_id=study_id,
|
||||
member_id=member_id,
|
||||
member_in=StudyMemberUpdate(role_in_study="CTA"),
|
||||
current_user=UserStub(id=admin_id, is_admin=True),
|
||||
db=db_session,
|
||||
)
|
||||
|
||||
row = (
|
||||
await db_session.execute(
|
||||
text(
|
||||
"""
|
||||
SELECT detail
|
||||
FROM audit_logs
|
||||
WHERE study_id = :study_id AND action = 'PROJECT_MEMBER_UPDATED'
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
"""
|
||||
),
|
||||
{"study_id": str(study_id)},
|
||||
)
|
||||
).one()
|
||||
detail = json.loads(row.detail)
|
||||
assert detail["targetName"] == "李四"
|
||||
assert str(target_user_id) not in detail["targetName"]
|
||||
|
||||
Reference in New Issue
Block a user