You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
3.8 KiB
Python
130 lines
3.8 KiB
Python
# backend/app/routers/trip.py
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlmodel import Session, select
|
|
|
|
from ..agents.travel_agent import run_planner
|
|
from ..auth.deps import current_user
|
|
from ..auth.scope import scoped
|
|
from ..db import get_session
|
|
from ..models import (
|
|
Person,
|
|
SavedTrip,
|
|
Trip,
|
|
TripChecklist,
|
|
TripDay,
|
|
TripPrep,
|
|
TripRoute,
|
|
TripStay,
|
|
)
|
|
from ..schemas import (
|
|
PlanRequest,
|
|
PlanResultOut,
|
|
SavedTripOut,
|
|
UpcomingTripOut,
|
|
WatchToggleRequest,
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def _saved_out(r: SavedTrip) -> SavedTripOut:
|
|
return SavedTripOut(
|
|
id=r.id,
|
|
title=r.title,
|
|
tag=r.tag,
|
|
note=r.note,
|
|
now=r.now,
|
|
delta=r.delta,
|
|
down=r.down,
|
|
watch=r.watch,
|
|
hint=r.hint,
|
|
spark=r.spark,
|
|
)
|
|
|
|
|
|
@router.get("/trip/upcoming", response_model=UpcomingTripOut)
|
|
def upcoming(s: Session = Depends(get_session), user: Person = Depends(current_user)):
|
|
trip = s.exec(scoped(select(Trip), Trip, user.id)).first()
|
|
if not trip:
|
|
raise HTTPException(404, "no trip")
|
|
routes = {
|
|
r.dir: {
|
|
"mode": r.mode,
|
|
"from": r.from_st,
|
|
"ft": r.ft,
|
|
"to": r.to_st,
|
|
"tt": r.tt,
|
|
"seat": r.seat,
|
|
"note": r.note,
|
|
}
|
|
for r in s.exec(select(TripRoute).where(TripRoute.trip_id == trip.id)).all()
|
|
}
|
|
stay = s.exec(select(TripStay).where(TripStay.trip_id == trip.id)).first()
|
|
preps = s.exec(
|
|
select(TripPrep).where(TripPrep.trip_id == trip.id).order_by(TripPrep.sort_order)
|
|
).all()
|
|
days = s.exec(
|
|
select(TripDay).where(TripDay.trip_id == trip.id).order_by(TripDay.sort_order)
|
|
).all()
|
|
checks = s.exec(
|
|
select(TripChecklist)
|
|
.where(TripChecklist.trip_id == trip.id)
|
|
.order_by(TripChecklist.sort_order)
|
|
).all()
|
|
# check 그룹화 (group → items[])
|
|
groups: list[dict] = []
|
|
gindex: dict[str, int] = {}
|
|
for c in checks:
|
|
if c.group not in gindex:
|
|
gindex[c.group] = len(groups)
|
|
groups.append({"name": c.group, "items": []})
|
|
item = {"id": c.id, "text": c.text}
|
|
if c.auto:
|
|
item["auto"] = c.auto
|
|
groups[gindex[c.group]]["items"].append(item)
|
|
return UpcomingTripOut(
|
|
trip={
|
|
"id": trip.id,
|
|
"dday": trip.dday,
|
|
"title": trip.title,
|
|
"dates": trip.dates,
|
|
"purpose": trip.purpose,
|
|
"brief": trip.brief,
|
|
"weather": trip.weather,
|
|
},
|
|
route=routes,
|
|
stay=({"name": stay.name, "desc": stay.desc, "conf": stay.conf} if stay else {}),
|
|
prep=[{"text": p.text, "state": p.state} for p in preps],
|
|
days=[{"id": d.id, "tab": d.tab, "items": d.items} for d in days],
|
|
check=groups,
|
|
expense={
|
|
"budget": trip.expense_budget,
|
|
"planned": trip.expense_planned,
|
|
"rows": trip.expense_rows,
|
|
"note": trip.expense_note,
|
|
},
|
|
)
|
|
|
|
|
|
@router.get("/trip/saved", response_model=list[SavedTripOut])
|
|
def saved(s: Session = Depends(get_session)):
|
|
rows = s.exec(select(SavedTrip).order_by(SavedTrip.sort_order)).all()
|
|
return [_saved_out(r) for r in rows]
|
|
|
|
|
|
@router.post("/trip/saved/{sid}/watch", response_model=SavedTripOut)
|
|
def toggle_watch(sid: str, req: WatchToggleRequest, s: Session = Depends(get_session)):
|
|
r = s.get(SavedTrip, sid)
|
|
if not r:
|
|
raise HTTPException(404, "no saved trip")
|
|
r.watch = req.watch if req.watch is not None else (not r.watch)
|
|
s.add(r)
|
|
s.commit()
|
|
s.refresh(r)
|
|
return _saved_out(r)
|
|
|
|
|
|
@router.post("/trip/plan", response_model=PlanResultOut)
|
|
def plan(req: PlanRequest, s: Session = Depends(get_session)):
|
|
return run_planner(s, req.text)
|