feat: task key (TE-1) generated on backend, project includes chat_id
Some checks failed
Deploy Tracker / deploy (push) Failing after 0s
Some checks failed
Deploy Tracker / deploy (push) Failing after 0s
This commit is contained in:
parent
999b049a9d
commit
377817c62e
@ -7,7 +7,7 @@ from fastapi import APIRouter, Depends, HTTPException, Query
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from sqlalchemy import select, update
|
from sqlalchemy import select, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload, joinedload
|
||||||
|
|
||||||
from tracker.database import get_db
|
from tracker.database import get_db
|
||||||
from tracker.models import Task, Step, Project
|
from tracker.models import Task, Step, Project
|
||||||
@ -29,6 +29,7 @@ class TaskOut(BaseModel):
|
|||||||
project_id: str
|
project_id: str
|
||||||
parent_id: str | None = None
|
parent_id: str | None = None
|
||||||
number: int
|
number: int
|
||||||
|
key: str # e.g. "TE-1"
|
||||||
title: str
|
title: str
|
||||||
description: str | None = None
|
description: str | None = None
|
||||||
type: str
|
type: str
|
||||||
@ -79,12 +80,14 @@ class AssignRequest(BaseModel):
|
|||||||
|
|
||||||
# --- Helpers ---
|
# --- Helpers ---
|
||||||
|
|
||||||
def _task_out(t: Task) -> dict:
|
def _task_out(t: Task, project_slug: str = "") -> dict:
|
||||||
|
prefix = project_slug[:2].upper() if project_slug else "XX"
|
||||||
return {
|
return {
|
||||||
"id": str(t.id),
|
"id": str(t.id),
|
||||||
"project_id": str(t.project_id),
|
"project_id": str(t.project_id),
|
||||||
"parent_id": str(t.parent_id) if t.parent_id else None,
|
"parent_id": str(t.parent_id) if t.parent_id else None,
|
||||||
"number": t.number,
|
"number": t.number,
|
||||||
|
"key": f"{prefix}-{t.number}",
|
||||||
"title": t.title,
|
"title": t.title,
|
||||||
"description": t.description,
|
"description": t.description,
|
||||||
"type": t.type,
|
"type": t.type,
|
||||||
@ -106,7 +109,8 @@ def _task_out(t: Task) -> dict:
|
|||||||
|
|
||||||
async def _get_task(task_id: str, db: AsyncSession) -> Task:
|
async def _get_task(task_id: str, db: AsyncSession) -> Task:
|
||||||
result = await db.execute(
|
result = await db.execute(
|
||||||
select(Task).where(Task.id == uuid.UUID(task_id)).options(selectinload(Task.steps))
|
select(Task).where(Task.id == uuid.UUID(task_id))
|
||||||
|
.options(selectinload(Task.steps), joinedload(Task.project))
|
||||||
)
|
)
|
||||||
task = result.scalar_one_or_none()
|
task = result.scalar_one_or_none()
|
||||||
if not task:
|
if not task:
|
||||||
@ -124,7 +128,7 @@ async def list_tasks(
|
|||||||
label: Optional[str] = Query(None),
|
label: Optional[str] = Query(None),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
):
|
):
|
||||||
q = select(Task).options(selectinload(Task.steps))
|
q = select(Task).options(selectinload(Task.steps), joinedload(Task.project))
|
||||||
if project_id:
|
if project_id:
|
||||||
q = q.where(Task.project_id == uuid.UUID(project_id))
|
q = q.where(Task.project_id == uuid.UUID(project_id))
|
||||||
if status:
|
if status:
|
||||||
@ -135,13 +139,13 @@ async def list_tasks(
|
|||||||
q = q.where(Task.labels.contains([label]))
|
q = q.where(Task.labels.contains([label]))
|
||||||
q = q.order_by(Task.position, Task.created_at)
|
q = q.order_by(Task.position, Task.created_at)
|
||||||
result = await db.execute(q)
|
result = await db.execute(q)
|
||||||
return [_task_out(t) for t in result.scalars()]
|
return [_task_out(t, t.project.slug if t.project else "") for t in result.scalars()]
|
||||||
|
|
||||||
|
|
||||||
@router.get("/tasks/{task_id}", response_model=TaskOut)
|
@router.get("/tasks/{task_id}", response_model=TaskOut)
|
||||||
async def get_task(task_id: str, db: AsyncSession = Depends(get_db)):
|
async def get_task(task_id: str, db: AsyncSession = Depends(get_db)):
|
||||||
task = await _get_task(task_id, db)
|
task = await _get_task(task_id, db)
|
||||||
return _task_out(task)
|
return _task_out(task, task.project.slug if task.project else "")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/tasks", response_model=TaskOut)
|
@router.post("/tasks", response_model=TaskOut)
|
||||||
@ -180,7 +184,7 @@ async def create_task(
|
|||||||
await db.refresh(task)
|
await db.refresh(task)
|
||||||
# Load steps
|
# Load steps
|
||||||
task_full = await _get_task(str(task.id), db)
|
task_full = await _get_task(str(task.id), db)
|
||||||
return _task_out(task_full)
|
return _task_out(task_full, task_full.project.slug if task_full.project else "")
|
||||||
|
|
||||||
|
|
||||||
@router.patch("/tasks/{task_id}", response_model=TaskOut)
|
@router.patch("/tasks/{task_id}", response_model=TaskOut)
|
||||||
@ -208,7 +212,7 @@ async def update_task(task_id: str, req: TaskUpdate, db: AsyncSession = Depends(
|
|||||||
|
|
||||||
await db.commit()
|
await db.commit()
|
||||||
await db.refresh(task)
|
await db.refresh(task)
|
||||||
return _task_out(task)
|
return _task_out(task, task.project.slug if task.project else "")
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/tasks/{task_id}")
|
@router.delete("/tasks/{task_id}")
|
||||||
@ -232,7 +236,7 @@ async def take_task(task_id: str, slug: str = Query(...), db: AsyncSession = Dep
|
|||||||
task.watchers = (task.watchers or []) + [slug]
|
task.watchers = (task.watchers or []) + [slug]
|
||||||
await db.commit()
|
await db.commit()
|
||||||
await db.refresh(task)
|
await db.refresh(task)
|
||||||
return _task_out(task)
|
return _task_out(task, task.project.slug if task.project else "")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/tasks/{task_id}/reject")
|
@router.post("/tasks/{task_id}/reject")
|
||||||
@ -255,7 +259,7 @@ async def assign_task(task_id: str, req: AssignRequest, db: AsyncSession = Depen
|
|||||||
task.watchers = (task.watchers or []) + [req.assignee_slug]
|
task.watchers = (task.watchers or []) + [req.assignee_slug]
|
||||||
await db.commit()
|
await db.commit()
|
||||||
await db.refresh(task)
|
await db.refresh(task)
|
||||||
return _task_out(task)
|
return _task_out(task, task.project.slug if task.project else "")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/tasks/{task_id}/watch")
|
@router.post("/tasks/{task_id}/watch")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user