Files
lifeos-dev/routers/capture.py

93 lines
3.1 KiB
Python

"""Capture: quick text capture queue with conversion."""
from fastapi import APIRouter, Request, Form, Depends
from fastapi.templating import Jinja2Templates
from fastapi.responses import RedirectResponse
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import text
from typing import Optional
from core.database import get_db
from core.base_repository import BaseRepository
from core.sidebar import get_sidebar_data
router = APIRouter(prefix="/capture", tags=["capture"])
templates = Jinja2Templates(directory="templates")
@router.get("/")
async def list_capture(request: Request, show: str = "unprocessed", db: AsyncSession = Depends(get_db)):
sidebar = await get_sidebar_data(db)
if show == "all":
filters = {}
else:
filters = {"processed": False}
result = await db.execute(text("""
SELECT * FROM capture WHERE is_deleted = false
AND (:show_all OR processed = false)
ORDER BY created_at DESC
"""), {"show_all": show == "all"})
items = [dict(r._mapping) for r in result]
return templates.TemplateResponse("capture.html", {
"request": request, "sidebar": sidebar, "items": items,
"show": show,
"page_title": "Capture", "active_nav": "capture",
})
@router.post("/add")
async def add_capture(
request: Request,
raw_text: str = Form(...),
db: AsyncSession = Depends(get_db),
):
repo = BaseRepository("capture", db)
# Multi-line: split into individual items
lines = [l.strip() for l in raw_text.strip().split("\n") if l.strip()]
for line in lines:
await repo.create({"raw_text": line, "processed": False})
return RedirectResponse(url="/capture", status_code=303)
@router.post("/{capture_id}/to-task")
async def convert_to_task(
capture_id: str,
request: Request,
domain_id: str = Form(...),
project_id: Optional[str] = Form(None),
db: AsyncSession = Depends(get_db),
):
capture_repo = BaseRepository("capture", db)
item = await capture_repo.get(capture_id)
if not item:
return RedirectResponse(url="/capture", status_code=303)
task_repo = BaseRepository("tasks", db)
data = {"title": item["raw_text"], "domain_id": domain_id, "status": "open", "priority": 3}
if project_id and project_id.strip():
data["project_id"] = project_id
task = await task_repo.create(data)
await capture_repo.update(capture_id, {
"processed": True,
"converted_to_type": "task",
"converted_to_id": str(task["id"]),
})
return RedirectResponse(url="/capture", status_code=303)
@router.post("/{capture_id}/dismiss")
async def dismiss_capture(capture_id: str, db: AsyncSession = Depends(get_db)):
repo = BaseRepository("capture", db)
await repo.update(capture_id, {"processed": True})
return RedirectResponse(url="/capture", status_code=303)
@router.post("/{capture_id}/delete")
async def delete_capture(capture_id: str, db: AsyncSession = Depends(get_db)):
repo = BaseRepository("capture", db)
await repo.soft_delete(capture_id)
return RedirectResponse(url="/capture", status_code=303)