完善审计日志展示与导出权限
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import uuid
|
||||
import json
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
@@ -49,6 +50,41 @@ async def _ensure_site_active(db: AsyncSession, site_id: uuid.UUID | None):
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="中心已停用")
|
||||
|
||||
|
||||
async def _site_label(db: AsyncSession, site_id: uuid.UUID | None, fallback: str = "项目级") -> str:
|
||||
if not site_id:
|
||||
return fallback
|
||||
site = await site_crud.get_site(db, site_id)
|
||||
return site.name if site else fallback
|
||||
|
||||
|
||||
async def _feasibility_audit_detail(db: AsyncSession, action: str, record) -> str:
|
||||
site_name = await _site_label(db, record.site_id)
|
||||
project_no = str(record.project_no or "").strip()
|
||||
name = f"{site_name} / {project_no}" if project_no else site_name
|
||||
return json.dumps({"targetName": name, "description": f"{action}立项记录“{name}”"}, ensure_ascii=False)
|
||||
|
||||
|
||||
async def _ethics_audit_detail(db: AsyncSession, action: str, record) -> str:
|
||||
site_name = await _site_label(db, record.site_id)
|
||||
approval_no = str(record.approval_no or "").strip()
|
||||
name = f"{site_name} / {approval_no}" if approval_no else site_name
|
||||
return json.dumps({"targetName": name, "description": f"{action}伦理记录“{name}”"}, ensure_ascii=False)
|
||||
|
||||
|
||||
async def _kickoff_audit_detail(db: AsyncSession, action: str, meeting) -> str:
|
||||
site_name = await _site_label(db, meeting.site_id)
|
||||
date_text = meeting.kickoff_date.isoformat() if meeting.kickoff_date else ""
|
||||
name = f"{site_name} / {date_text}" if date_text else site_name
|
||||
return json.dumps({"targetName": name, "description": f"{action}启动会记录“{name}”"}, ensure_ascii=False)
|
||||
|
||||
|
||||
def _training_audit_detail(action: str, record) -> str:
|
||||
name = str(record.name or "").strip() or "培训授权人员"
|
||||
site_name = str(record.site_name or "").strip()
|
||||
target_name = f"{name} / {site_name}" if site_name else name
|
||||
return json.dumps({"targetName": target_name, "description": f"{action}培训授权人员“{target_name}”"}, ensure_ascii=False)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/feasibility",
|
||||
response_model=StartupFeasibilityRead,
|
||||
@@ -73,7 +109,7 @@ async def create_feasibility(
|
||||
entity_type="startup_feasibility",
|
||||
entity_id=record.id,
|
||||
action="CREATE_STARTUP_FEASIBILITY",
|
||||
detail="立项记录已创建",
|
||||
detail=await _feasibility_audit_detail(db, "创建", record),
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
@@ -147,7 +183,7 @@ async def update_feasibility(
|
||||
entity_type="startup_feasibility",
|
||||
entity_id=record_id,
|
||||
action="UPDATE_STARTUP_FEASIBILITY",
|
||||
detail="立项记录已更新",
|
||||
detail=await _feasibility_audit_detail(db, "更新", record),
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
@@ -173,6 +209,7 @@ async def delete_feasibility(
|
||||
if cra_scope and record.site_id not in cra_scope[0]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
await _ensure_site_active(db, record.site_id)
|
||||
record_detail = await _feasibility_audit_detail(db, "删除", record)
|
||||
await startup_crud.delete_feasibility(db, record)
|
||||
await audit_crud.log_action(
|
||||
db,
|
||||
@@ -180,7 +217,7 @@ async def delete_feasibility(
|
||||
entity_type="startup_feasibility",
|
||||
entity_id=record_id,
|
||||
action="DELETE_STARTUP_FEASIBILITY",
|
||||
detail="立项记录已删除",
|
||||
detail=record_detail,
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
@@ -210,7 +247,7 @@ async def create_ethics(
|
||||
entity_type="startup_ethics",
|
||||
entity_id=record.id,
|
||||
action="CREATE_STARTUP_ETHICS",
|
||||
detail="伦理记录已创建",
|
||||
detail=await _ethics_audit_detail(db, "创建", record),
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
@@ -284,7 +321,7 @@ async def update_ethics(
|
||||
entity_type="startup_ethics",
|
||||
entity_id=record_id,
|
||||
action="UPDATE_STARTUP_ETHICS",
|
||||
detail="伦理记录已更新",
|
||||
detail=await _ethics_audit_detail(db, "更新", record),
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
@@ -310,6 +347,7 @@ async def delete_ethics(
|
||||
if cra_scope and record.site_id not in cra_scope[0]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
await _ensure_site_active(db, record.site_id)
|
||||
record_detail = await _ethics_audit_detail(db, "删除", record)
|
||||
await startup_crud.delete_ethics(db, record)
|
||||
await audit_crud.log_action(
|
||||
db,
|
||||
@@ -317,7 +355,7 @@ async def delete_ethics(
|
||||
entity_type="startup_ethics",
|
||||
entity_id=record_id,
|
||||
action="DELETE_STARTUP_ETHICS",
|
||||
detail="伦理记录已删除",
|
||||
detail=record_detail,
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
@@ -347,7 +385,7 @@ async def create_kickoff(
|
||||
entity_type="startup_kickoff",
|
||||
entity_id=meeting.id,
|
||||
action="CREATE_KICKOFF_MEETING",
|
||||
detail="启动会记录已创建",
|
||||
detail=await _kickoff_audit_detail(db, "创建", meeting),
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
@@ -421,7 +459,7 @@ async def update_kickoff(
|
||||
entity_type="startup_kickoff",
|
||||
entity_id=meeting_id,
|
||||
action="UPDATE_KICKOFF_MEETING",
|
||||
detail="启动会记录已更新",
|
||||
detail=await _kickoff_audit_detail(db, "更新", meeting),
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
@@ -452,7 +490,7 @@ async def create_training_authorization(
|
||||
entity_type="training_authorization",
|
||||
entity_id=record.id,
|
||||
action="CREATE_TRAINING_AUTH",
|
||||
detail="培训授权人员已创建",
|
||||
detail=_training_audit_detail("创建", record),
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
@@ -527,7 +565,7 @@ async def update_training_authorization(
|
||||
entity_type="training_authorization",
|
||||
entity_id=record_id,
|
||||
action="UPDATE_TRAINING_AUTH",
|
||||
detail="培训授权人员已更新",
|
||||
detail=_training_audit_detail("更新", record),
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
@@ -553,6 +591,7 @@ async def delete_training_authorization(
|
||||
if cra_scope and record.site_name not in cra_scope[1]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
await _ensure_site_name_active(db, study_id, record.site_name)
|
||||
record_detail = _training_audit_detail("删除", record)
|
||||
await startup_crud.delete_training_authorization(db, record)
|
||||
await audit_crud.log_action(
|
||||
db,
|
||||
@@ -560,7 +599,7 @@ async def delete_training_authorization(
|
||||
entity_type="training_authorization",
|
||||
entity_id=record_id,
|
||||
action="DELETE_TRAINING_AUTH",
|
||||
detail="培训授权人员已删除",
|
||||
detail=record_detail,
|
||||
operator_id=current_user.id,
|
||||
operator_role=await get_operator_role_label(db, study_id, current_user),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user