未知(继上次中断)
This commit is contained in:
@@ -3,7 +3,7 @@ import uuid
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.deps import get_current_user, get_db_session, require_study_member, require_study_roles, require_study_not_locked
|
||||
from app.core.deps import get_cra_site_scope, get_current_user, get_db_session, require_study_member
|
||||
from app.crud import audit as audit_crud
|
||||
from app.crud import site as site_crud
|
||||
from app.crud import startup as startup_crud
|
||||
@@ -53,7 +53,7 @@ async def _ensure_site_active(db: AsyncSession, site_id: uuid.UUID | None):
|
||||
"/feasibility",
|
||||
response_model=StartupFeasibilityRead,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def create_feasibility(
|
||||
study_id: uuid.UUID,
|
||||
@@ -62,6 +62,9 @@ async def create_feasibility(
|
||||
current_user=Depends(get_current_user),
|
||||
) -> StartupFeasibilityRead:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
if cra_scope and record_in.site_id not in cra_scope[0]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
await _ensure_site_active(db, record_in.site_id)
|
||||
record = await startup_crud.create_feasibility(db, study_id, record_in, created_by=current_user.id)
|
||||
await audit_crud.log_action(
|
||||
@@ -87,9 +90,12 @@ async def list_feasibilities(
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
current_user=Depends(get_current_user),
|
||||
) -> list[StartupFeasibilityRead]:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
items = await startup_crud.list_feasibilities(db, study_id, skip=skip, limit=limit)
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
site_ids = cra_scope[0] if cra_scope else None
|
||||
items = await startup_crud.list_feasibilities(db, study_id, skip=skip, limit=limit, site_ids=site_ids)
|
||||
return [StartupFeasibilityRead.model_validate(item) for item in items]
|
||||
|
||||
|
||||
@@ -102,18 +108,22 @@ async def get_feasibility(
|
||||
study_id: uuid.UUID,
|
||||
record_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
current_user=Depends(get_current_user),
|
||||
) -> StartupFeasibilityRead:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
record = await startup_crud.get_feasibility(db, record_id)
|
||||
if not record or record.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="立项记录不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
if cra_scope and record.site_id not in cra_scope[0]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
return StartupFeasibilityRead.model_validate(record)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/feasibility/{record_id}",
|
||||
response_model=StartupFeasibilityRead,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def update_feasibility(
|
||||
study_id: uuid.UUID,
|
||||
@@ -126,6 +136,9 @@ async def update_feasibility(
|
||||
record = await startup_crud.get_feasibility(db, record_id)
|
||||
if not record or record.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="立项记录不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
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 = await startup_crud.update_feasibility(db, record, record_in)
|
||||
await audit_crud.log_action(
|
||||
@@ -144,7 +157,7 @@ async def update_feasibility(
|
||||
@router.delete(
|
||||
"/feasibility/{record_id}",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def delete_feasibility(
|
||||
study_id: uuid.UUID,
|
||||
@@ -156,6 +169,9 @@ async def delete_feasibility(
|
||||
record = await startup_crud.get_feasibility(db, record_id)
|
||||
if not record or record.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="立项记录不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
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)
|
||||
await startup_crud.delete_feasibility(db, record)
|
||||
await audit_crud.log_action(
|
||||
@@ -174,7 +190,7 @@ async def delete_feasibility(
|
||||
"/ethics",
|
||||
response_model=StartupEthicsRead,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def create_ethics(
|
||||
study_id: uuid.UUID,
|
||||
@@ -183,6 +199,9 @@ async def create_ethics(
|
||||
current_user=Depends(get_current_user),
|
||||
) -> StartupEthicsRead:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
if cra_scope and record_in.site_id not in cra_scope[0]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
await _ensure_site_active(db, record_in.site_id)
|
||||
record = await startup_crud.create_ethics(db, study_id, record_in, created_by=current_user.id)
|
||||
await audit_crud.log_action(
|
||||
@@ -208,9 +227,12 @@ async def list_ethics(
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
current_user=Depends(get_current_user),
|
||||
) -> list[StartupEthicsRead]:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
items = await startup_crud.list_ethics(db, study_id, skip=skip, limit=limit)
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
site_ids = cra_scope[0] if cra_scope else None
|
||||
items = await startup_crud.list_ethics(db, study_id, skip=skip, limit=limit, site_ids=site_ids)
|
||||
return [StartupEthicsRead.model_validate(item) for item in items]
|
||||
|
||||
|
||||
@@ -223,18 +245,22 @@ async def get_ethics(
|
||||
study_id: uuid.UUID,
|
||||
record_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
current_user=Depends(get_current_user),
|
||||
) -> StartupEthicsRead:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
record = await startup_crud.get_ethics(db, record_id)
|
||||
if not record or record.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="伦理记录不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
if cra_scope and record.site_id not in cra_scope[0]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
return StartupEthicsRead.model_validate(record)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/ethics/{record_id}",
|
||||
response_model=StartupEthicsRead,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def update_ethics(
|
||||
study_id: uuid.UUID,
|
||||
@@ -247,6 +273,9 @@ async def update_ethics(
|
||||
record = await startup_crud.get_ethics(db, record_id)
|
||||
if not record or record.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="伦理记录不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
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 = await startup_crud.update_ethics(db, record, record_in)
|
||||
await audit_crud.log_action(
|
||||
@@ -265,7 +294,7 @@ async def update_ethics(
|
||||
@router.delete(
|
||||
"/ethics/{record_id}",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def delete_ethics(
|
||||
study_id: uuid.UUID,
|
||||
@@ -277,6 +306,9 @@ async def delete_ethics(
|
||||
record = await startup_crud.get_ethics(db, record_id)
|
||||
if not record or record.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="伦理记录不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
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)
|
||||
await startup_crud.delete_ethics(db, record)
|
||||
await audit_crud.log_action(
|
||||
@@ -295,7 +327,7 @@ async def delete_ethics(
|
||||
"/kickoff",
|
||||
response_model=KickoffMeetingRead,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def create_kickoff(
|
||||
study_id: uuid.UUID,
|
||||
@@ -304,6 +336,9 @@ async def create_kickoff(
|
||||
current_user=Depends(get_current_user),
|
||||
) -> KickoffMeetingRead:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
if cra_scope and meeting_in.site_id not in cra_scope[0]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
await _ensure_site_active(db, meeting_in.site_id)
|
||||
meeting = await startup_crud.create_kickoff(db, study_id, meeting_in, created_by=current_user.id)
|
||||
await audit_crud.log_action(
|
||||
@@ -329,9 +364,12 @@ async def list_kickoffs(
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
current_user=Depends(get_current_user),
|
||||
) -> list[KickoffMeetingRead]:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
items = await startup_crud.list_kickoffs(db, study_id, skip=skip, limit=limit)
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
site_ids = cra_scope[0] if cra_scope else None
|
||||
items = await startup_crud.list_kickoffs(db, study_id, skip=skip, limit=limit, site_ids=site_ids)
|
||||
return [KickoffMeetingRead.model_validate(item) for item in items]
|
||||
|
||||
|
||||
@@ -344,18 +382,22 @@ async def get_kickoff(
|
||||
study_id: uuid.UUID,
|
||||
meeting_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
current_user=Depends(get_current_user),
|
||||
) -> KickoffMeetingRead:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
meeting = await startup_crud.get_kickoff(db, meeting_id)
|
||||
if not meeting or meeting.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="启动会记录不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
if cra_scope and meeting.site_id not in cra_scope[0]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
return KickoffMeetingRead.model_validate(meeting)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/kickoff/{meeting_id}",
|
||||
response_model=KickoffMeetingRead,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def update_kickoff(
|
||||
study_id: uuid.UUID,
|
||||
@@ -368,6 +410,9 @@ async def update_kickoff(
|
||||
meeting = await startup_crud.get_kickoff(db, meeting_id)
|
||||
if not meeting or meeting.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="启动会记录不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
if cra_scope and meeting.site_id not in cra_scope[0]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
await _ensure_site_active(db, meeting.site_id)
|
||||
meeting = await startup_crud.update_kickoff(db, meeting, meeting_in)
|
||||
await audit_crud.log_action(
|
||||
@@ -387,7 +432,7 @@ async def update_kickoff(
|
||||
"/training-authorizations",
|
||||
response_model=TrainingAuthorizationRead,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def create_training_authorization(
|
||||
study_id: uuid.UUID,
|
||||
@@ -396,6 +441,9 @@ async def create_training_authorization(
|
||||
current_user=Depends(get_current_user),
|
||||
) -> TrainingAuthorizationRead:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
if cra_scope and record_in.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_in.site_name)
|
||||
record = await startup_crud.create_training_authorization(db, study_id, record_in, created_by=current_user.id)
|
||||
await audit_crud.log_action(
|
||||
@@ -421,9 +469,12 @@ async def list_training_authorizations(
|
||||
skip: int = 0,
|
||||
limit: int = 200,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
current_user=Depends(get_current_user),
|
||||
) -> list[TrainingAuthorizationRead]:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
items = await startup_crud.list_training_authorizations(db, study_id, skip=skip, limit=limit)
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
site_names = cra_scope[1] if cra_scope else None
|
||||
items = await startup_crud.list_training_authorizations(db, study_id, skip=skip, limit=limit, site_names=site_names)
|
||||
return [TrainingAuthorizationRead.model_validate(item) for item in items]
|
||||
|
||||
|
||||
@@ -436,18 +487,22 @@ async def get_training_authorization(
|
||||
study_id: uuid.UUID,
|
||||
record_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
current_user=Depends(get_current_user),
|
||||
) -> TrainingAuthorizationRead:
|
||||
await _ensure_study_exists(db, study_id)
|
||||
record = await startup_crud.get_training_authorization(db, record_id)
|
||||
if not record or record.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="培训授权人员不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
if cra_scope and record.site_name not in cra_scope[1]:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足")
|
||||
return TrainingAuthorizationRead.model_validate(record)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/training-authorizations/{record_id}",
|
||||
response_model=TrainingAuthorizationRead,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def update_training_authorization(
|
||||
study_id: uuid.UUID,
|
||||
@@ -460,6 +515,9 @@ async def update_training_authorization(
|
||||
record = await startup_crud.get_training_authorization(db, record_id)
|
||||
if not record or record.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="培训授权人员不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
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 = await startup_crud.update_training_authorization(db, record, record_in)
|
||||
await audit_crud.log_action(
|
||||
@@ -478,7 +536,7 @@ async def update_training_authorization(
|
||||
@router.delete(
|
||||
"/training-authorizations/{record_id}",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
dependencies=[Depends(require_study_roles(["PM", "CRA"]))],
|
||||
dependencies=[Depends(require_study_member())],
|
||||
)
|
||||
async def delete_training_authorization(
|
||||
study_id: uuid.UUID,
|
||||
@@ -490,6 +548,9 @@ async def delete_training_authorization(
|
||||
record = await startup_crud.get_training_authorization(db, record_id)
|
||||
if not record or record.study_id != study_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="培训授权人员不存在")
|
||||
cra_scope = await get_cra_site_scope(db, study_id, current_user)
|
||||
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)
|
||||
await startup_crud.delete_training_authorization(db, record)
|
||||
await audit_crud.log_action(
|
||||
|
||||
Reference in New Issue
Block a user