Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
- Add EmptyState component with 6 variants - Add discover.py router with smart filtering - GET /discover/shows (year, venue, city, tour filters) - GET /discover/years - GET /discover/recent - Add GET /attendance/me/stats (by vertical breakdown)
190 lines
5.8 KiB
Python
190 lines
5.8 KiB
Python
"""
|
|
Show Discovery API - smart routing for finding shows.
|
|
"""
|
|
from datetime import date, timedelta
|
|
from typing import List, Optional
|
|
from fastapi import APIRouter, Depends, Query
|
|
from sqlmodel import Session, select, desc
|
|
from pydantic import BaseModel
|
|
from database import get_session
|
|
from models import Show, Venue, Vertical, Tour
|
|
|
|
router = APIRouter(prefix="/discover", tags=["discover"])
|
|
|
|
|
|
class DiscoverShow(BaseModel):
|
|
id: int
|
|
date: str
|
|
slug: str | None
|
|
venue_name: str | None
|
|
venue_city: str | None
|
|
vertical_name: str
|
|
vertical_slug: str
|
|
tour_name: str | None = None
|
|
|
|
|
|
class DiscoverResponse(BaseModel):
|
|
shows: List[DiscoverShow]
|
|
total: int
|
|
filters_applied: dict
|
|
|
|
|
|
@router.get("/shows", response_model=DiscoverResponse)
|
|
def discover_shows(
|
|
vertical: Optional[str] = None,
|
|
year: Optional[int] = None,
|
|
month: Optional[int] = None,
|
|
venue: Optional[str] = None,
|
|
tour: Optional[str] = None,
|
|
city: Optional[str] = None,
|
|
state: Optional[str] = None,
|
|
limit: int = 50,
|
|
offset: int = 0,
|
|
sort: str = "date_desc",
|
|
session: Session = Depends(get_session)
|
|
):
|
|
"""
|
|
Discover shows with smart filtering.
|
|
|
|
Sort options: date_desc, date_asc
|
|
"""
|
|
query = select(Show).where(Show.date.isnot(None))
|
|
|
|
filters = {}
|
|
|
|
# Filter by vertical (band)
|
|
if vertical:
|
|
v = session.exec(select(Vertical).where(Vertical.slug == vertical)).first()
|
|
if v:
|
|
query = query.where(Show.vertical_id == v.id)
|
|
filters["vertical"] = vertical
|
|
|
|
# Filter by year
|
|
if year:
|
|
start = date(year, 1, 1)
|
|
end = date(year, 12, 31)
|
|
query = query.where(Show.date >= start).where(Show.date <= end)
|
|
filters["year"] = year
|
|
|
|
# Filter by month (requires year)
|
|
if month and year:
|
|
start = date(year, month, 1)
|
|
if month == 12:
|
|
end = date(year + 1, 1, 1) - timedelta(days=1)
|
|
else:
|
|
end = date(year, month + 1, 1) - timedelta(days=1)
|
|
query = query.where(Show.date >= start).where(Show.date <= end)
|
|
filters["month"] = month
|
|
|
|
# Filter by tour
|
|
if tour:
|
|
t = session.exec(select(Tour).where(Tour.slug == tour)).first()
|
|
if t:
|
|
query = query.where(Show.tour_id == t.id)
|
|
filters["tour"] = tour
|
|
|
|
# Apply sorting
|
|
if sort == "date_asc":
|
|
query = query.order_by(Show.date)
|
|
else:
|
|
query = query.order_by(desc(Show.date))
|
|
|
|
# Get total count before pagination
|
|
all_shows = session.exec(query).all()
|
|
total = len(all_shows)
|
|
|
|
# Apply pagination
|
|
paginated = all_shows[offset:offset + limit]
|
|
|
|
# Filter by venue/city/state in Python (more flexible)
|
|
results = []
|
|
for show in paginated:
|
|
venue_obj = session.get(Venue, show.venue_id) if show.venue_id else None
|
|
vert_obj = session.get(Vertical, show.vertical_id)
|
|
tour_obj = session.get(Tour, show.tour_id) if show.tour_id else None
|
|
|
|
# City/state filters
|
|
if city and venue_obj and city.lower() not in venue_obj.city.lower():
|
|
continue
|
|
if state and venue_obj and venue_obj.state and state.lower() not in venue_obj.state.lower():
|
|
continue
|
|
if venue and venue_obj and venue.lower() not in venue_obj.name.lower():
|
|
continue
|
|
|
|
results.append(DiscoverShow(
|
|
id=show.id,
|
|
date=show.date.strftime("%Y-%m-%d") if show.date else "",
|
|
slug=show.slug,
|
|
venue_name=venue_obj.name if venue_obj else None,
|
|
venue_city=venue_obj.city if venue_obj else None,
|
|
vertical_name=vert_obj.name if vert_obj else "Unknown",
|
|
vertical_slug=vert_obj.slug if vert_obj else "unknown",
|
|
tour_name=tour_obj.name if tour_obj else None
|
|
))
|
|
|
|
if city:
|
|
filters["city"] = city
|
|
if state:
|
|
filters["state"] = state
|
|
if venue:
|
|
filters["venue"] = venue
|
|
|
|
return DiscoverResponse(
|
|
shows=results,
|
|
total=total,
|
|
filters_applied=filters
|
|
)
|
|
|
|
|
|
@router.get("/years")
|
|
def get_available_years(
|
|
vertical: Optional[str] = None,
|
|
session: Session = Depends(get_session)
|
|
):
|
|
"""Get list of years with shows for filtering UI"""
|
|
query = select(Show).where(Show.date.isnot(None))
|
|
|
|
if vertical:
|
|
v = session.exec(select(Vertical).where(Vertical.slug == vertical)).first()
|
|
if v:
|
|
query = query.where(Show.vertical_id == v.id)
|
|
|
|
shows = session.exec(query).all()
|
|
years = sorted(set(s.date.year for s in shows if s.date), reverse=True)
|
|
|
|
return {"years": years}
|
|
|
|
|
|
@router.get("/recent", response_model=List[DiscoverShow])
|
|
def get_recent_shows(
|
|
limit: int = 10,
|
|
vertical: Optional[str] = None,
|
|
session: Session = Depends(get_session)
|
|
):
|
|
"""Get most recent shows for quick discovery"""
|
|
query = select(Show).where(Show.date.isnot(None))
|
|
|
|
if vertical:
|
|
v = session.exec(select(Vertical).where(Vertical.slug == vertical)).first()
|
|
if v:
|
|
query = query.where(Show.vertical_id == v.id)
|
|
|
|
query = query.order_by(desc(Show.date)).limit(limit)
|
|
shows = session.exec(query).all()
|
|
|
|
results = []
|
|
for show in shows:
|
|
venue = session.get(Venue, show.venue_id) if show.venue_id else None
|
|
vert = session.get(Vertical, show.vertical_id)
|
|
|
|
results.append(DiscoverShow(
|
|
id=show.id,
|
|
date=show.date.strftime("%Y-%m-%d") if show.date else "",
|
|
slug=show.slug,
|
|
venue_name=venue.name if venue else None,
|
|
venue_city=venue.city if venue else None,
|
|
vertical_name=vert.name if vert else "Unknown",
|
|
vertical_slug=vert.slug if vert else "unknown"
|
|
))
|
|
|
|
return results
|