Normalize uploaded documents into structured markdown, add clearer parser errors for missing dependencies, and cover the ingestion flow with backend tests. This also replaces deprecated UTC timestamp helpers in the touched backend paths so the knowledge pipeline stays warning-free. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
92 lines
2.8 KiB
Python
92 lines
2.8 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, desc
|
|
from app.database import get_db
|
|
from app.models.task import Task, TaskStatus
|
|
from app.models.user import User
|
|
from app.routers.auth import get_current_user
|
|
from app.schemas.task import TaskCreate, TaskUpdate, TaskOut
|
|
|
|
router = APIRouter(prefix="/api/tasks", tags=["看板"])
|
|
|
|
|
|
@router.get("", response_model=list[TaskOut])
|
|
async def list_tasks(
|
|
status: TaskStatus | None = None,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
query = select(Task).where(Task.user_id == current_user.id)
|
|
if status:
|
|
query = query.where(Task.status == status)
|
|
query = query.order_by(desc(Task.created_at))
|
|
result = await db.execute(query)
|
|
return result.scalars().all()
|
|
|
|
|
|
@router.post("", response_model=TaskOut, status_code=201)
|
|
async def create_task(
|
|
data: TaskCreate,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
import json
|
|
task = Task(
|
|
user_id=current_user.id,
|
|
title=data.title,
|
|
description=data.description,
|
|
priority=data.priority,
|
|
due_date=data.due_date,
|
|
tags=json.dumps(data.tags) if data.tags else None,
|
|
)
|
|
db.add(task)
|
|
await db.commit()
|
|
await db.refresh(task)
|
|
return task
|
|
|
|
|
|
@router.patch("/{task_id}", response_model=TaskOut)
|
|
async def update_task(
|
|
task_id: str,
|
|
data: TaskUpdate,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
import json
|
|
result = await db.execute(
|
|
select(Task).where(Task.id == task_id, Task.user_id == current_user.id)
|
|
)
|
|
task = result.scalar_one_or_none()
|
|
if not task:
|
|
raise HTTPException(status_code=404, detail="任务不存在")
|
|
|
|
for field, value in data.model_dump(exclude_none=True).items():
|
|
if field == "tags":
|
|
setattr(task, field, json.dumps(value))
|
|
elif field == "status" and value == TaskStatus.DONE:
|
|
from datetime import UTC, datetime
|
|
task.completed_at = datetime.now(UTC)
|
|
setattr(task, field, value)
|
|
else:
|
|
setattr(task, field, value)
|
|
|
|
await db.commit()
|
|
await db.refresh(task)
|
|
return task
|
|
|
|
|
|
@router.delete("/{task_id}", status_code=204)
|
|
async def delete_task(
|
|
task_id: str,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
result = await db.execute(
|
|
select(Task).where(Task.id == task_id, Task.user_id == current_user.id)
|
|
)
|
|
task = result.scalar_one_or_none()
|
|
if not task:
|
|
raise HTTPException(status_code=404, detail="任务不存在")
|
|
await db.delete(task)
|
|
await db.commit()
|