fix imports (w/o backend.) and fix Items route (had wrong content)
This commit is contained in:
parent
e702418221
commit
2d11a362ea
7 changed files with 169 additions and 206 deletions
|
|
@ -4,7 +4,7 @@ from uuid import UUID as UUID_t
|
|||
from datetime import date
|
||||
import re, ast, operator
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from backend import models
|
||||
import models
|
||||
|
||||
ALLOWED_NAMES = {"days", "nights"}
|
||||
ALLOWED_NODES = (
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
from uuid import UUID
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from backend.database import Base, engine
|
||||
from backend.routes import items, tags, trips, trip_items
|
||||
from database import Base, engine
|
||||
from routes import items, tags, trips, trip_items, dev_seed
|
||||
|
||||
|
||||
# Create tables (for MVP without Alembic)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from sqlalchemy import (
|
|||
)
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import relationship
|
||||
from .database import Base
|
||||
from database import Base
|
||||
|
||||
|
||||
class User(Base):
|
||||
|
|
|
|||
|
|
@ -1,37 +1,31 @@
|
|||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from uuid import UUID
|
||||
from backend.database import get_db
|
||||
from backend import models
|
||||
from backend.schemas import TripCreate, TripOut, TripUpdate, TripRegenerationResult
|
||||
from backend.crud import generate_trip_items
|
||||
from database import get_db
|
||||
import models
|
||||
from schemas import ItemCreate, ItemOut
|
||||
|
||||
router = APIRouter(prefix="/trips", tags=["trips"])
|
||||
router = APIRouter(prefix="/items", tags=["items"])
|
||||
|
||||
@router.get("/", response_model=list[TripOut])
|
||||
def list_trips(db: Session = Depends(get_db)):
|
||||
trips = (
|
||||
db.query(models.Trip)
|
||||
.options(
|
||||
joinedload(models.Trip.selected_tags).joinedload(models.TripTagSelected.tag),
|
||||
joinedload(models.Trip.marked_tags).joinedload(models.TripTagMarked.tag),
|
||||
)
|
||||
@router.get("/", response_model=list[ItemOut])
|
||||
def list_items(db: Session = Depends(get_db)):
|
||||
items = (
|
||||
db.query(models.Item)
|
||||
.options(joinedload(models.Item.tags).joinedload(models.ItemTag.tag))
|
||||
.all()
|
||||
)
|
||||
# pydantic can handle relationships if orm_mode
|
||||
return [
|
||||
TripOut(
|
||||
id=t.id,
|
||||
name=t.name,
|
||||
start_date=t.start_date,
|
||||
end_date=t.end_date,
|
||||
selected_tags=[st.tag for st in t.selected_tags],
|
||||
marked_tags=[mt.tag for mt in t.marked_tags],
|
||||
)
|
||||
for t in trips
|
||||
models.Item(
|
||||
id=it.id,
|
||||
user_id=it.user_id,
|
||||
name=it.name,
|
||||
tags=it.tags,
|
||||
) for it in items
|
||||
]
|
||||
|
||||
@router.post("/", response_model=TripOut)
|
||||
def create_trip(payload: TripCreate, db: Session = Depends(get_db)):
|
||||
@router.post("/", response_model=ItemOut)
|
||||
def create_item(payload: ItemCreate, db: Session = Depends(get_db)):
|
||||
user = db.query(models.User).first()
|
||||
if not user:
|
||||
from uuid import uuid4
|
||||
|
|
@ -39,85 +33,31 @@ def create_trip(payload: TripCreate, db: Session = Depends(get_db)):
|
|||
db.add(user)
|
||||
db.flush()
|
||||
|
||||
trip = models.Trip(user_id=user.id, name=payload.name, start_date=payload.start_date, end_date=payload.end_date)
|
||||
db.add(trip)
|
||||
db.flush()
|
||||
item = models.Item(user_id=user.id, name=payload.name)
|
||||
|
||||
# attach selected & marked
|
||||
if payload.selected_tag_ids:
|
||||
for tid in payload.selected_tag_ids:
|
||||
db.add(models.TripTagSelected(trip_id=trip.id, tag_id=tid))
|
||||
if payload.marked_tag_ids:
|
||||
for tid in payload.marked_tag_ids:
|
||||
db.add(models.TripTagMarked(trip_id=trip.id, tag_id=tid))
|
||||
|
||||
db.flush()
|
||||
|
||||
# generate items per rules
|
||||
created_ids, _ = generate_trip_items(
|
||||
db,
|
||||
trip=trip,
|
||||
selected_tag_ids=payload.selected_tag_ids,
|
||||
marked_tag_ids=payload.marked_tag_ids,
|
||||
)
|
||||
if payload.tag_ids:
|
||||
links = []
|
||||
tags = db.query(models.Tag).filter(models.Tag.id.in_(payload.tag_ids), models.Tag.user_id == user.id).all()
|
||||
for t in tags:
|
||||
links.append(models.ItemTag(item=item, tag=t))
|
||||
item.tags = links
|
||||
|
||||
db.add(item)
|
||||
db.commit()
|
||||
db.refresh(item)
|
||||
|
||||
# reload with relationships
|
||||
trip = (
|
||||
db.query(models.Trip)
|
||||
.options(
|
||||
joinedload(models.Trip.selected_tags).joinedload(models.TripTagSelected.tag),
|
||||
joinedload(models.Trip.marked_tags).joinedload(models.TripTagMarked.tag),
|
||||
)
|
||||
.get(trip.id)
|
||||
)
|
||||
return TripOut(
|
||||
id=trip.id,
|
||||
name=trip.name,
|
||||
start_date=trip.start_date,
|
||||
end_date=trip.end_date,
|
||||
selected_tags=[st.tag for st in trip.selected_tags],
|
||||
marked_tags=[mt.tag for mt in trip.marked_tags],
|
||||
# eager load for response
|
||||
item = (
|
||||
db.query(models.Item)
|
||||
.options(joinedload(models.Item.tags).joinedload(models.ItemTag.tag))
|
||||
.get(item.id)
|
||||
)
|
||||
return item
|
||||
|
||||
@router.put("/{trip_id}/reconfigure", response_model=TripRegenerationResult)
|
||||
def reconfigure_trip(trip_id: UUID, payload: TripUpdate, db: Session = Depends(get_db)):
|
||||
trip = db.get(models.Trip, trip_id)
|
||||
if not trip:
|
||||
raise HTTPException(status_code=404, detail="Trip not found")
|
||||
|
||||
# update base fields
|
||||
if payload.name is not None:
|
||||
trip.name = payload.name
|
||||
if payload.start_date is not None:
|
||||
trip.start_date = payload.start_date
|
||||
if payload.end_date is not None:
|
||||
trip.end_date = payload.end_date
|
||||
db.flush()
|
||||
|
||||
# update selected/marked join tables if provided
|
||||
if payload.selected_tag_ids is not None:
|
||||
# replace all
|
||||
db.query(models.TripTagSelected).filter_by(trip_id=trip.id).delete()
|
||||
for tid in payload.selected_tag_ids:
|
||||
db.add(models.TripTagSelected(trip_id=trip.id, tag_id=tid))
|
||||
if payload.marked_tag_ids is not None:
|
||||
db.query(models.TripTagMarked).filter_by(trip_id=trip.id).delete()
|
||||
for tid in payload.marked_tag_ids:
|
||||
db.add(models.TripTagMarked(trip_id=trip.id, tag_id=tid))
|
||||
db.flush()
|
||||
|
||||
# read back lists
|
||||
sel_ids = [row.tag_id for row in db.query(models.TripTagSelected).filter_by(trip_id=trip.id).all()]
|
||||
mrk_ids = [row.tag_id for row in db.query(models.TripTagMarked).filter_by(trip_id=trip.id).all()]
|
||||
|
||||
created_ids, deleted_checked = generate_trip_items(
|
||||
db, trip=trip, selected_tag_ids=sel_ids, marked_tag_ids=mrk_ids
|
||||
)
|
||||
@router.delete("/{item_id}", status_code=204)
|
||||
def delete_item(item_id: UUID, db: Session = Depends(get_db)):
|
||||
item = db.get(models.Item, item_id)
|
||||
if not item:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
db.delete(item)
|
||||
db.commit()
|
||||
return {
|
||||
"trip_id": trip.id,
|
||||
"deleted_checked_trip_item_ids": deleted_checked,
|
||||
"created_trip_item_ids": created_ids,
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
from backend.database import get_db
|
||||
from backend import models
|
||||
from backend.schemas import TagCreate, TagOut
|
||||
from database import get_db
|
||||
import models
|
||||
from schemas import TagCreate, TagOut
|
||||
|
||||
router = APIRouter(prefix="/tags", tags=["tags"])
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from uuid import UUID
|
||||
from backend.database import get_db
|
||||
from backend import models
|
||||
from backend.schemas import TripItemOut
|
||||
from database import get_db
|
||||
import models
|
||||
from schemas import TripItemOut
|
||||
|
||||
router = APIRouter(prefix="/trip-items", tags=["trip-items"])
|
||||
|
||||
|
|
|
|||
|
|
@ -1,102 +1,123 @@
|
|||
import re
|
||||
from uuid import UUID, uuid4
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from schemas import TripCreate, TripItemOut, TripOut
|
||||
from models import Item, Trip, TripItem
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from uuid import UUID
|
||||
from database import get_db
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import selectinload
|
||||
from config import FIXED_USER_ID
|
||||
import models
|
||||
from schemas import TripCreate, TripOut, TripUpdate, TripRegenerationResult
|
||||
from crud import generate_trip_items
|
||||
|
||||
router = APIRouter(prefix="/trips", tags=["Trips"])
|
||||
|
||||
@router.post("/", response_model=TripOut)
|
||||
async def create_trip(trip: TripCreate, db: AsyncSession = Depends(get_db)):
|
||||
user_id = FIXED_USER_ID
|
||||
|
||||
db_trip = Trip(
|
||||
id=uuid4(),
|
||||
name=trip.name,
|
||||
user_id=user_id,
|
||||
start_date=trip.start_date,
|
||||
end_date=trip.end_date,
|
||||
selected_tags=trip.selected_tags,
|
||||
marked_tags=trip.marked_tags
|
||||
)
|
||||
|
||||
await db.commit() # damit ID vorhanden ist
|
||||
db.add(db_trip)
|
||||
|
||||
# Tage berechnen
|
||||
days = (trip.end_date - trip.start_date).days + 1
|
||||
nights = days - 1
|
||||
|
||||
# relevante Items
|
||||
result = await db.execute(select(Item).where(Item.user_id == user_id).options(selectinload(Item.tags)))
|
||||
all_items = result.scalars().all()
|
||||
|
||||
trip_items = []
|
||||
|
||||
for item in all_items:
|
||||
item_tag_names = [tag.name for tag in item.tags]
|
||||
|
||||
if not set(item_tag_names).issubset(set(trip.selected_tags)):
|
||||
continue
|
||||
|
||||
item_text = replace_placeholders(item.name, days, nights)
|
||||
|
||||
# markierte Tags matchen?
|
||||
matching_marked = set(item_tag_names) & set(trip.marked_tags)
|
||||
|
||||
if matching_marked:
|
||||
for tag in matching_marked:
|
||||
trip_items.append(TripItem(
|
||||
id=uuid4(),
|
||||
trip_id=db_trip.id,
|
||||
item_id=item.id,
|
||||
tag=tag,
|
||||
name=item.name,
|
||||
calculated_label=item_text,
|
||||
checked=False
|
||||
))
|
||||
else:
|
||||
trip_items.append(TripItem(
|
||||
id=uuid4(),
|
||||
trip_id=db_trip.id,
|
||||
item_id=item.id,
|
||||
tag=None,
|
||||
name=item.name,
|
||||
calculated_label=item_text,
|
||||
checked=False
|
||||
))
|
||||
|
||||
db.add_all(trip_items)
|
||||
await db.commit()
|
||||
# return {"status": "trip created", "trip_id": str(db_trip.id)}
|
||||
return db_trip
|
||||
|
||||
|
||||
@router.get("/{trip_id}/items", response_model=list[TripItemOut])
|
||||
async def get_trip_items(trip_id: UUID, db: AsyncSession = Depends(get_db)):
|
||||
result = await db.execute(select(TripItem).where(TripItem.trip_id == trip_id).options(selectinload(TripItem.item)))
|
||||
items = result.scalars().all()
|
||||
return [TripItemOut.model_validate(item) for item in items]
|
||||
router = APIRouter(prefix="/trips", tags=["trips"])
|
||||
|
||||
@router.get("/", response_model=list[TripOut])
|
||||
async def get_trips(db: AsyncSession = Depends(get_db)):
|
||||
user_id = FIXED_USER_ID
|
||||
result = await db.execute(select(Trip).where(Trip.user_id == user_id))
|
||||
trips = result.scalars().all()
|
||||
return trips
|
||||
def list_trips(db: Session = Depends(get_db)):
|
||||
trips = (
|
||||
db.query(models.Trip)
|
||||
.options(
|
||||
joinedload(models.Trip.selected_tags).joinedload(models.TripTagSelected.tag),
|
||||
joinedload(models.Trip.marked_tags).joinedload(models.TripTagMarked.tag),
|
||||
)
|
||||
.all()
|
||||
)
|
||||
return [
|
||||
TripOut(
|
||||
id=t.id,
|
||||
name=t.name,
|
||||
start_date=t.start_date,
|
||||
end_date=t.end_date,
|
||||
selected_tags=[st.tag for st in t.selected_tags],
|
||||
marked_tags=[mt.tag for mt in t.marked_tags],
|
||||
)
|
||||
for t in trips
|
||||
]
|
||||
|
||||
def replace_placeholders(text: str, days: int, nights: int) -> str:
|
||||
def replacer(match):
|
||||
expr = match.group(1)
|
||||
expr = expr.replace("days", str(days)).replace("nights", str(nights))
|
||||
try:
|
||||
return str(eval(expr))
|
||||
except:
|
||||
return match.group(0)
|
||||
@router.post("/", response_model=TripOut)
|
||||
def create_trip(payload: TripCreate, db: Session = Depends(get_db)):
|
||||
user = db.query(models.User).first()
|
||||
if not user:
|
||||
from uuid import uuid4
|
||||
user = models.User(id=uuid4(), name="Demo")
|
||||
db.add(user)
|
||||
db.flush()
|
||||
|
||||
return re.sub(r"{(.*?)}", replacer, text)
|
||||
trip = models.Trip(user_id=user.id, name=payload.name, start_date=payload.start_date, end_date=payload.end_date)
|
||||
db.add(trip)
|
||||
db.flush()
|
||||
|
||||
# attach selected & marked
|
||||
if payload.selected_tag_ids:
|
||||
for tid in payload.selected_tag_ids:
|
||||
db.add(models.TripTagSelected(trip_id=trip.id, tag_id=tid))
|
||||
if payload.marked_tag_ids:
|
||||
for tid in payload.marked_tag_ids:
|
||||
db.add(models.TripTagMarked(trip_id=trip.id, tag_id=tid))
|
||||
|
||||
db.flush()
|
||||
|
||||
# generate items per rules
|
||||
created_ids, _ = generate_trip_items(
|
||||
db,
|
||||
trip=trip,
|
||||
selected_tag_ids=payload.selected_tag_ids,
|
||||
marked_tag_ids=payload.marked_tag_ids,
|
||||
)
|
||||
|
||||
db.commit()
|
||||
|
||||
# reload with relationships
|
||||
trip = (
|
||||
db.query(models.Trip)
|
||||
.options(
|
||||
joinedload(models.Trip.selected_tags).joinedload(models.TripTagSelected.tag),
|
||||
joinedload(models.Trip.marked_tags).joinedload(models.TripTagMarked.tag),
|
||||
)
|
||||
.get(trip.id)
|
||||
)
|
||||
return TripOut(
|
||||
id=trip.id,
|
||||
name=trip.name,
|
||||
start_date=trip.start_date,
|
||||
end_date=trip.end_date,
|
||||
selected_tags=[st.tag for st in trip.selected_tags],
|
||||
marked_tags=[mt.tag for mt in trip.marked_tags],
|
||||
)
|
||||
|
||||
@router.put("/{trip_id}/reconfigure", response_model=TripRegenerationResult)
|
||||
def reconfigure_trip(trip_id: UUID, payload: TripUpdate, db: Session = Depends(get_db)):
|
||||
trip = db.get(models.Trip, trip_id)
|
||||
if not trip:
|
||||
raise HTTPException(status_code=404, detail="Trip not found")
|
||||
|
||||
# update base fields
|
||||
if payload.name is not None:
|
||||
trip.name = payload.name
|
||||
if payload.start_date is not None:
|
||||
trip.start_date = payload.start_date
|
||||
if payload.end_date is not None:
|
||||
trip.end_date = payload.end_date
|
||||
db.flush()
|
||||
|
||||
# update selected/marked join tables if provided
|
||||
if payload.selected_tag_ids is not None:
|
||||
# replace all
|
||||
db.query(models.TripTagSelected).filter_by(trip_id=trip.id).delete()
|
||||
for tid in payload.selected_tag_ids:
|
||||
db.add(models.TripTagSelected(trip_id=trip.id, tag_id=tid))
|
||||
if payload.marked_tag_ids is not None:
|
||||
db.query(models.TripTagMarked).filter_by(trip_id=trip.id).delete()
|
||||
for tid in payload.marked_tag_ids:
|
||||
db.add(models.TripTagMarked(trip_id=trip.id, tag_id=tid))
|
||||
db.flush()
|
||||
|
||||
# read back lists
|
||||
sel_ids = [row.tag_id for row in db.query(models.TripTagSelected).filter_by(trip_id=trip.id).all()]
|
||||
mrk_ids = [row.tag_id for row in db.query(models.TripTagMarked).filter_by(trip_id=trip.id).all()]
|
||||
|
||||
created_ids, deleted_checked = generate_trip_items(
|
||||
db, trip=trip, selected_tag_ids=sel_ids, marked_tag_ids=mrk_ids
|
||||
)
|
||||
db.commit()
|
||||
return {
|
||||
"trip_id": trip.id,
|
||||
"deleted_checked_trip_item_ids": deleted_checked,
|
||||
"created_trip_item_ids": created_ids,
|
||||
}
|
||||
Loading…
Reference in a new issue