116 lines
3.4 KiB
Python
116 lines
3.4 KiB
Python
"""Legacy 兼容路由 — 通过旧版 task_id (JJC-xxx) 操作任务。
|
||
|
||
旧版 kanban_update.py 使用自定义 ID (JJC-20260301-007),
|
||
Edict 使用 UUID。此路由通过 tags 或 meta.legacy_id 映射。from __future__ import annotations"""
|
||
|
||
import logging
|
||
from fastapi import APIRouter, Depends, HTTPException
|
||
from pydantic import BaseModel
|
||
from sqlalchemy import select
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from ..db import get_db
|
||
from ..models.task import Task, TaskState
|
||
from ..services.event_bus import get_event_bus
|
||
from ..services.task_service import TaskService
|
||
|
||
log = logging.getLogger("edict.api.legacy")
|
||
router = APIRouter()
|
||
|
||
|
||
async def _find_by_legacy_id(db: AsyncSession, legacy_id: str) -> Task | None:
|
||
"""通过旧版 ID 查找任务(在 tags 或 meta.legacy_id 中搜索)。"""
|
||
# 方式1: tags 包含 legacy_id
|
||
stmt = select(Task).where(Task.tags.contains([legacy_id]))
|
||
result = await db.execute(stmt)
|
||
task = result.scalars().first()
|
||
if task:
|
||
return task
|
||
|
||
# 方式2: meta->legacy_id
|
||
stmt2 = select(Task).where(Task.meta["legacy_id"].astext == legacy_id)
|
||
result2 = await db.execute(stmt2)
|
||
return result2.scalars().first()
|
||
|
||
|
||
class LegacyTransition(BaseModel):
|
||
new_state: str
|
||
agent: str = "system"
|
||
reason: str = ""
|
||
|
||
|
||
class LegacyProgress(BaseModel):
|
||
agent: str
|
||
content: str
|
||
|
||
|
||
class LegacyTodoUpdate(BaseModel):
|
||
todos: list[dict]
|
||
|
||
|
||
@router.post("/by-legacy/{legacy_id}/transition")
|
||
async def legacy_transition(
|
||
legacy_id: str,
|
||
body: LegacyTransition,
|
||
db: AsyncSession = Depends(get_db),
|
||
):
|
||
task = await _find_by_legacy_id(db, legacy_id)
|
||
if not task:
|
||
raise HTTPException(status_code=404, detail=f"Legacy task not found: {legacy_id}")
|
||
|
||
bus = await get_event_bus()
|
||
svc = TaskService(db, bus)
|
||
try:
|
||
new_state = TaskState(body.new_state)
|
||
except ValueError:
|
||
raise HTTPException(status_code=400, detail=f"Invalid state: {body.new_state}")
|
||
|
||
try:
|
||
t = await svc.transition_state(task.task_id, new_state, body.agent, body.reason)
|
||
return {"task_id": str(t.task_id), "state": t.state.value}
|
||
except ValueError as e:
|
||
raise HTTPException(status_code=400, detail=str(e))
|
||
|
||
|
||
@router.post("/by-legacy/{legacy_id}/progress")
|
||
async def legacy_progress(
|
||
legacy_id: str,
|
||
body: LegacyProgress,
|
||
db: AsyncSession = Depends(get_db),
|
||
):
|
||
task = await _find_by_legacy_id(db, legacy_id)
|
||
if not task:
|
||
raise HTTPException(status_code=404, detail=f"Legacy task not found: {legacy_id}")
|
||
|
||
bus = await get_event_bus()
|
||
svc = TaskService(db, bus)
|
||
await svc.add_progress(task.task_id, body.agent, body.content)
|
||
return {"message": "ok"}
|
||
|
||
|
||
@router.put("/by-legacy/{legacy_id}/todos")
|
||
async def legacy_todos(
|
||
legacy_id: str,
|
||
body: LegacyTodoUpdate,
|
||
db: AsyncSession = Depends(get_db),
|
||
):
|
||
task = await _find_by_legacy_id(db, legacy_id)
|
||
if not task:
|
||
raise HTTPException(status_code=404, detail=f"Legacy task not found: {legacy_id}")
|
||
|
||
bus = await get_event_bus()
|
||
svc = TaskService(db, bus)
|
||
await svc.update_todos(task.task_id, body.todos)
|
||
return {"message": "ok"}
|
||
|
||
|
||
@router.get("/by-legacy/{legacy_id}")
|
||
async def legacy_get(
|
||
legacy_id: str,
|
||
db: AsyncSession = Depends(get_db),
|
||
):
|
||
task = await _find_by_legacy_id(db, legacy_id)
|
||
if not task:
|
||
raise HTTPException(status_code=404, detail=f"Legacy task not found: {legacy_id}")
|
||
return task.to_dict()
|