fediversion/backend/routers/bands.py
fullsizemalt cf7748a980
Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
feat: Add band profile and musician profile pages with API endpoints and database support
2025-12-28 23:00:30 -08:00

112 lines
3.5 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session, select, func
from typing import List, Optional
from database import get_session
from models import (
Vertical, Artist, Musician, BandMembership,
PerformanceGuest, Performance, Show, Song, Venue
)
router = APIRouter(prefix="/bands", tags=["bands"])
@router.get("")
async def list_bands(
scene: Optional[str] = None,
is_featured: Optional[bool] = None,
session: Session = Depends(get_session)
):
"""List all active bands, optionally filtered"""
query = select(Vertical).where(Vertical.is_active == True)
if is_featured is not None:
query = query.where(Vertical.is_featured == is_featured)
bands = session.exec(query.order_by(Vertical.name)).all()
return bands
@router.get("/{slug}")
async def get_band_profile(slug: str, session: Session = Depends(get_session)):
"""Get comprehensive band profile including members and stats"""
vertical = session.exec(
select(Vertical).where(Vertical.slug == slug)
).first()
if not vertical:
raise HTTPException(status_code=404, detail="Band not found")
# Get members via BandMembership if primary_artist_id exists
current_members = []
past_members = []
if vertical.primary_artist_id:
# Get all memberships for this band's artist
memberships = session.exec(
select(BandMembership, Musician)
.join(Musician, BandMembership.musician_id == Musician.id)
.where(BandMembership.artist_id == vertical.primary_artist_id)
.order_by(BandMembership.start_date)
).all()
for membership, musician in memberships:
member_data = {
"id": musician.id,
"name": musician.name,
"slug": musician.slug,
"image_url": musician.image_url,
"role": membership.role,
"primary_instrument": musician.primary_instrument,
"start_date": membership.start_date,
"end_date": membership.end_date,
"notes": membership.notes,
}
if membership.end_date is None:
current_members.append(member_data)
else:
past_members.append(member_data)
# Get stats
show_count = session.exec(
select(func.count(Show.id)).where(Show.vertical_id == vertical.id)
).one()
song_count = session.exec(
select(func.count(Song.id)).where(Song.vertical_id == vertical.id)
).one()
# Get venue count (distinct venues from shows)
venue_count = session.exec(
select(func.count(func.distinct(Show.venue_id)))
.where(Show.vertical_id == vertical.id)
).one()
# Get first and last show dates
first_show = session.exec(
select(Show.date)
.where(Show.vertical_id == vertical.id)
.order_by(Show.date.asc())
.limit(1)
).first()
last_show = session.exec(
select(Show.date)
.where(Show.vertical_id == vertical.id)
.order_by(Show.date.desc())
.limit(1)
).first()
stats = {
"total_shows": show_count,
"total_songs": song_count,
"total_venues": venue_count,
"first_show": first_show,
"last_show": last_show,
}
return {
"band": vertical,
"current_members": current_members,
"past_members": past_members,
"stats": stats,
}