from __future__ import annotations from .shared import * def _parse_due_date(value: Optional[str]) -> Optional[datetime]: if not value: return None try: return datetime.fromisoformat(value.replace("Z", "+00:00")).replace(tzinfo=None) except ValueError as exc: raise HTTPException(status_code=400, detail="Invalid due_date") from exc async def _ensure_project( svc: SSTCService, project_id: int, ): project = await svc.get_project(project_id) if not project: raise HTTPException(status_code=404, detail="Project not found") return project async def _ensure_charter( db: AsyncSession, *, tenant_id: int, project_id: int, charter_id: int, ) -> TruthNode: result = await db.execute( select(TruthNode).where( and_( TruthNode.id == charter_id, TruthNode.project_id == project_id, TruthNode.tenant_id == tenant_id, TruthNode.node_type == "charter", ) ) ) charter = result.scalar_one_or_none() if not charter: raise HTTPException(status_code=404, detail="Charter not found") return charter async def _ensure_task( db: AsyncSession, *, tenant_id: int, project_id: int, task_id: int, ) -> Task: result = await db.execute( select(Task).where( and_( Task.id == task_id, Task.project_id == project_id, Task.tenant_id == tenant_id, ) ) ) task = result.scalar_one_or_none() if not task: raise HTTPException(status_code=404, detail="Task not found") return task async def _ensure_release( db: AsyncSession, *, tenant_id: int, project_id: int, release_node_id: int, ) -> TruthNode: result = await db.execute( select(TruthNode).where( and_( TruthNode.id == release_node_id, TruthNode.project_id == project_id, TruthNode.tenant_id == tenant_id, TruthNode.node_type == "release", ) ) ) release_node = result.scalar_one_or_none() if not release_node: raise HTTPException(status_code=404, detail="Release plan not found") return release_node async def _ensure_review( db: AsyncSession, *, tenant_id: int, project_id: int, review_node_id: int, ) -> TruthNode: result = await db.execute( select(TruthNode).where( and_( TruthNode.id == review_node_id, TruthNode.project_id == project_id, TruthNode.tenant_id == tenant_id, TruthNode.node_type == "review", ) ) ) review_node = result.scalar_one_or_none() if not review_node: raise HTTPException(status_code=404, detail="Review not found") return review_node