227 lines
6.2 KiB
Python
227 lines
6.2 KiB
Python
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
from fastapi import Depends, FastAPI, HTTPException
|
|
from fastapi.responses import FileResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.config import settings
|
|
from app.database import Base, engine, get_db
|
|
from app.models import TrackedEvent, WatchItem, WatchSource
|
|
from app.scheduler import start_scheduler
|
|
from app.schemas import (
|
|
NotificationLogRead,
|
|
ProviderStatusRead,
|
|
PurchaseUpdate,
|
|
SyncResult,
|
|
TrackedEventRead,
|
|
WatchItemCreate,
|
|
WatchItemRead,
|
|
WatchItemUpdate,
|
|
WatchSourceCreate,
|
|
WatchSourceRead,
|
|
WatchSourceUpdate,
|
|
)
|
|
from app.services import (
|
|
list_events,
|
|
list_notifications,
|
|
list_provider_statuses,
|
|
list_watch_sources,
|
|
list_watch_items,
|
|
run_sync,
|
|
)
|
|
|
|
|
|
app = FastAPI(
|
|
title="eventlens",
|
|
version="0.1.0",
|
|
description="Beobachtet Kuenstler und Events in Hamburg oder Deutschland.",
|
|
)
|
|
|
|
frontend_dir = Path(__file__).resolve().parent / "frontend"
|
|
static_dir = frontend_dir / "static"
|
|
app.mount("/static", StaticFiles(directory=static_dir), name="static")
|
|
|
|
|
|
@app.on_event("startup")
|
|
def startup():
|
|
Base.metadata.create_all(bind=engine)
|
|
start_scheduler()
|
|
|
|
|
|
@app.get("/")
|
|
def root():
|
|
return FileResponse(frontend_dir / "index.html")
|
|
|
|
|
|
@app.get("/api")
|
|
def api_info():
|
|
return {
|
|
"service": settings.app_name,
|
|
"status": "running",
|
|
"docs": "/docs",
|
|
}
|
|
|
|
|
|
@app.get("/health")
|
|
def health():
|
|
return {"status": "ok"}
|
|
|
|
|
|
@app.get("/watch-items", response_model=list[WatchItemRead])
|
|
def get_watch_items(db: Session = Depends(get_db)):
|
|
return list_watch_items(db)
|
|
|
|
|
|
@app.post("/watch-items", response_model=WatchItemRead, status_code=201)
|
|
def create_watch_item(payload: WatchItemCreate, db: Session = Depends(get_db)):
|
|
watch_item = WatchItem(
|
|
name=payload.name,
|
|
watch_type=payload.watch_type,
|
|
region_scope=payload.region_scope,
|
|
notes=payload.notes,
|
|
)
|
|
db.add(watch_item)
|
|
db.commit()
|
|
db.refresh(watch_item)
|
|
return watch_item
|
|
|
|
|
|
@app.patch("/watch-items/{watch_item_id}", response_model=WatchItemRead)
|
|
def update_watch_item(
|
|
watch_item_id: int,
|
|
payload: WatchItemUpdate,
|
|
db: Session = Depends(get_db),
|
|
):
|
|
watch_item = db.get(WatchItem, watch_item_id)
|
|
if watch_item is None:
|
|
raise HTTPException(status_code=404, detail="Watch item nicht gefunden.")
|
|
|
|
updates = payload.model_dump(exclude_unset=True)
|
|
for field_name, value in updates.items():
|
|
setattr(watch_item, field_name, value)
|
|
watch_item.updated_at = datetime.utcnow()
|
|
|
|
db.commit()
|
|
db.refresh(watch_item)
|
|
return watch_item
|
|
|
|
|
|
@app.delete("/watch-items/{watch_item_id}", status_code=204)
|
|
def delete_watch_item(watch_item_id: int, db: Session = Depends(get_db)):
|
|
watch_item = db.get(WatchItem, watch_item_id)
|
|
if watch_item is None:
|
|
raise HTTPException(status_code=404, detail="Watch item nicht gefunden.")
|
|
|
|
db.delete(watch_item)
|
|
db.commit()
|
|
|
|
|
|
@app.get("/watch-sources", response_model=list[WatchSourceRead])
|
|
def get_watch_sources(watch_item_id: int | None = None, db: Session = Depends(get_db)):
|
|
return list_watch_sources(db, watch_item_id)
|
|
|
|
|
|
@app.post(
|
|
"/watch-items/{watch_item_id}/sources",
|
|
response_model=WatchSourceRead,
|
|
status_code=201,
|
|
)
|
|
def create_watch_source(
|
|
watch_item_id: int,
|
|
payload: WatchSourceCreate,
|
|
db: Session = Depends(get_db),
|
|
):
|
|
watch_item = db.get(WatchItem, watch_item_id)
|
|
if watch_item is None:
|
|
raise HTTPException(status_code=404, detail="Watch item nicht gefunden.")
|
|
|
|
source = WatchSource(
|
|
watch_item=watch_item,
|
|
label=payload.label,
|
|
url=payload.url,
|
|
parser_type=payload.parser_type,
|
|
)
|
|
db.add(source)
|
|
db.commit()
|
|
db.refresh(source)
|
|
return source
|
|
|
|
|
|
@app.patch("/watch-sources/{source_id}", response_model=WatchSourceRead)
|
|
def update_watch_source(
|
|
source_id: int,
|
|
payload: WatchSourceUpdate,
|
|
db: Session = Depends(get_db),
|
|
):
|
|
source = db.get(WatchSource, source_id)
|
|
if source is None:
|
|
raise HTTPException(status_code=404, detail="Quelle nicht gefunden.")
|
|
|
|
updates = payload.model_dump(exclude_unset=True)
|
|
for field_name, value in updates.items():
|
|
setattr(source, field_name, value)
|
|
source.updated_at = datetime.utcnow()
|
|
db.commit()
|
|
db.refresh(source)
|
|
return source
|
|
|
|
|
|
@app.delete("/watch-sources/{source_id}", status_code=204)
|
|
def delete_watch_source(source_id: int, db: Session = Depends(get_db)):
|
|
source = db.get(WatchSource, source_id)
|
|
if source is None:
|
|
raise HTTPException(status_code=404, detail="Quelle nicht gefunden.")
|
|
|
|
db.delete(source)
|
|
db.commit()
|
|
|
|
|
|
@app.get("/events", response_model=list[TrackedEventRead])
|
|
def get_events(db: Session = Depends(get_db)):
|
|
return list_events(db)
|
|
|
|
|
|
@app.patch("/events/{event_id}/purchase", response_model=TrackedEventRead)
|
|
def update_purchase_status(
|
|
event_id: int,
|
|
payload: PurchaseUpdate,
|
|
db: Session = Depends(get_db),
|
|
):
|
|
tracked_event = db.get(TrackedEvent, event_id)
|
|
if tracked_event is None:
|
|
raise HTTPException(status_code=404, detail="Event nicht gefunden.")
|
|
|
|
tracked_event.is_ticket_purchased = payload.is_ticket_purchased
|
|
tracked_event.purchased_at = datetime.utcnow() if payload.is_ticket_purchased else None
|
|
tracked_event.reminder_notified_at = None
|
|
db.commit()
|
|
db.refresh(tracked_event)
|
|
return tracked_event
|
|
|
|
|
|
@app.delete("/events/{event_id}", status_code=204)
|
|
def delete_event(event_id: int, db: Session = Depends(get_db)):
|
|
tracked_event = db.get(TrackedEvent, event_id)
|
|
if tracked_event is None:
|
|
raise HTTPException(status_code=404, detail="Event nicht gefunden.")
|
|
|
|
db.delete(tracked_event)
|
|
db.commit()
|
|
|
|
|
|
@app.get("/notifications", response_model=list[NotificationLogRead])
|
|
def get_notifications(db: Session = Depends(get_db)):
|
|
return list_notifications(db)
|
|
|
|
|
|
@app.get("/provider-statuses", response_model=list[ProviderStatusRead])
|
|
def get_provider_statuses(db: Session = Depends(get_db)):
|
|
return list_provider_statuses(db)
|
|
|
|
|
|
@app.post("/sync", response_model=SyncResult)
|
|
def trigger_sync(db: Session = Depends(get_db)):
|
|
return run_sync(db)
|