100 lines
3.2 KiB
Python
100 lines
3.2 KiB
Python
import uuid
|
|
from datetime import date, datetime, timezone
|
|
from typing import Sequence
|
|
|
|
from sqlalchemy import select, update as sa_update
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models.issue import Issue
|
|
from app.models.site import Site
|
|
from app.models.subject import Subject
|
|
from app.schemas.issue import IssueCreate, IssueUpdate
|
|
|
|
|
|
async def _validate_site_subject(db: AsyncSession, study_id: uuid.UUID, site_id: uuid.UUID | None, subject_id: uuid.UUID | None):
|
|
if site_id:
|
|
result = await db.execute(select(Site).where(Site.id == site_id))
|
|
site = result.scalar_one_or_none()
|
|
if not site or site.study_id != study_id:
|
|
raise ValueError("Site not found in study")
|
|
if subject_id:
|
|
result = await db.execute(select(Subject).where(Subject.id == subject_id))
|
|
subj = result.scalar_one_or_none()
|
|
if not subj or subj.study_id != study_id:
|
|
raise ValueError("Subject not found in study")
|
|
|
|
|
|
async def create_issue(
|
|
db: AsyncSession,
|
|
study_id: uuid.UUID,
|
|
issue_in: IssueCreate,
|
|
*,
|
|
created_by: uuid.UUID,
|
|
) -> Issue:
|
|
await _validate_site_subject(db, study_id, issue_in.site_id, issue_in.subject_id)
|
|
issue = Issue(
|
|
study_id=study_id,
|
|
site_id=issue_in.site_id,
|
|
subject_id=issue_in.subject_id,
|
|
title=issue_in.title,
|
|
description=issue_in.description,
|
|
category=issue_in.category,
|
|
level=issue_in.level,
|
|
owner_id=issue_in.owner_id,
|
|
due_date=issue_in.due_date,
|
|
status="OPEN",
|
|
capa=None,
|
|
closed_at=None,
|
|
created_by=created_by,
|
|
)
|
|
db.add(issue)
|
|
await db.commit()
|
|
await db.refresh(issue)
|
|
return issue
|
|
|
|
|
|
async def get_issue(db: AsyncSession, issue_id: uuid.UUID) -> Issue | None:
|
|
result = await db.execute(select(Issue).where(Issue.id == issue_id))
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
async def list_issues(
|
|
db: AsyncSession,
|
|
study_id: uuid.UUID,
|
|
status: str | None = None,
|
|
level: str | None = None,
|
|
category: str | None = None,
|
|
overdue: bool | None = None,
|
|
) -> Sequence[Issue]:
|
|
stmt = select(Issue).where(Issue.study_id == study_id)
|
|
if status:
|
|
stmt = stmt.where(Issue.status == status)
|
|
if level:
|
|
stmt = stmt.where(Issue.level == level)
|
|
if category:
|
|
stmt = stmt.where(Issue.category == category)
|
|
if overdue is True:
|
|
stmt = stmt.where(Issue.due_date < date.today(), Issue.status != "CLOSED")
|
|
if overdue is False:
|
|
stmt = stmt.where((Issue.due_date >= date.today()) | (Issue.due_date.is_(None)) | (Issue.status == "CLOSED"))
|
|
result = await db.execute(stmt)
|
|
return result.scalars().all()
|
|
|
|
|
|
async def update_issue(db: AsyncSession, issue: Issue, issue_in: IssueUpdate) -> Issue:
|
|
update_data = issue_in.model_dump(exclude_unset=True)
|
|
if "status" in update_data:
|
|
if update_data["status"] == "CLOSED":
|
|
update_data["closed_at"] = datetime.now(timezone.utc)
|
|
else:
|
|
update_data["closed_at"] = None
|
|
if update_data:
|
|
await db.execute(
|
|
sa_update(Issue)
|
|
.where(Issue.id == issue.id)
|
|
.values(**update_data)
|
|
)
|
|
await db.commit()
|
|
await db.refresh(issue)
|
|
return issue
|