fediversion/backend/routers/verticals.py
fullsizemalt 19c5e97e7f
Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
feat: Add scene filtering to verticals API
- GET /verticals now supports ?scene= parameter
- Add GET /verticals/scenes endpoint
- Filter verticals by is_active=true
2025-12-28 16:07:46 -08:00

278 lines
8.2 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session, select
from typing import List
from database import get_session
from models import User, Vertical, UserVerticalPreference
from auth import get_current_user
from pydantic import BaseModel
from datetime import datetime
router = APIRouter(prefix="/verticals", tags=["verticals"])
class VerticalRead(BaseModel):
id: int
name: str
slug: str
description: str | None = None
class UserVerticalPreferenceRead(BaseModel):
vertical_id: int
vertical: VerticalRead
display_mode: str
priority: int
notify_on_show: bool
class UserVerticalPreferenceCreate(BaseModel):
vertical_id: int
display_mode: str = "primary" # primary, secondary, attribution_only, hidden
priority: int = 0
notify_on_show: bool = True
class UserVerticalPreferenceUpdate(BaseModel):
display_mode: str | None = None
priority: int | None = None
notify_on_show: bool | None = None
class BulkVerticalPreferencesCreate(BaseModel):
"""For onboarding - set multiple band preferences at once"""
vertical_ids: List[int]
display_mode: str = "primary"
# --- Public endpoints ---
@router.get("/", response_model=List[VerticalRead])
def list_verticals(
scene: str | None = None,
session: Session = Depends(get_session)
):
"""List all available verticals (bands), optionally filtered by scene"""
from models import Scene, VerticalScene
if scene:
# Filter by scene
scene_obj = session.exec(select(Scene).where(Scene.slug == scene)).first()
if not scene_obj:
raise HTTPException(status_code=404, detail="Scene not found")
vertical_ids = session.exec(
select(VerticalScene.vertical_id).where(VerticalScene.scene_id == scene_obj.id)
).all()
verticals = session.exec(
select(Vertical)
.where(Vertical.id.in_(vertical_ids))
.where(Vertical.is_active == True)
).all()
else:
verticals = session.exec(
select(Vertical).where(Vertical.is_active == True)
).all()
return verticals
class SceneRead(BaseModel):
id: int
name: str
slug: str
description: str | None = None
@router.get("/scenes", response_model=List[SceneRead])
def list_scenes(session: Session = Depends(get_session)):
"""List all scenes (genres)"""
from models import Scene
scenes = session.exec(select(Scene)).all()
return scenes
@router.get("/{slug}", response_model=VerticalRead)
def get_vertical(slug: str, session: Session = Depends(get_session)):
"""Get a specific vertical by slug"""
vertical = session.exec(select(Vertical).where(Vertical.slug == slug)).first()
if not vertical:
raise HTTPException(status_code=404, detail="Vertical not found")
return vertical
# --- User preference endpoints ---
@router.get("/preferences/me", response_model=List[UserVerticalPreferenceRead])
def get_my_vertical_preferences(
session: Session = Depends(get_session),
current_user: User = Depends(get_current_user)
):
"""Get current user's band preferences"""
prefs = session.exec(
select(UserVerticalPreference)
.where(UserVerticalPreference.user_id == current_user.id)
.order_by(UserVerticalPreference.priority)
).all()
# Enrich with vertical data
result = []
for pref in prefs:
vertical = session.get(Vertical, pref.vertical_id)
if vertical:
result.append({
"vertical_id": pref.vertical_id,
"vertical": vertical,
"display_mode": pref.display_mode,
"priority": pref.priority,
"notify_on_show": pref.notify_on_show
})
return result
@router.post("/preferences", response_model=UserVerticalPreferenceRead)
def add_vertical_preference(
pref: UserVerticalPreferenceCreate,
session: Session = Depends(get_session),
current_user: User = Depends(get_current_user)
):
"""Add a band to user's preferences"""
# Check vertical exists
vertical = session.get(Vertical, pref.vertical_id)
if not vertical:
raise HTTPException(status_code=404, detail="Vertical not found")
# Check if already exists
existing = session.exec(
select(UserVerticalPreference)
.where(UserVerticalPreference.user_id == current_user.id)
.where(UserVerticalPreference.vertical_id == pref.vertical_id)
).first()
if existing:
raise HTTPException(status_code=400, detail="Preference already exists")
db_pref = UserVerticalPreference(
user_id=current_user.id,
vertical_id=pref.vertical_id,
display_mode=pref.display_mode,
priority=pref.priority,
notify_on_show=pref.notify_on_show
)
session.add(db_pref)
session.commit()
session.refresh(db_pref)
return {
"vertical_id": db_pref.vertical_id,
"vertical": vertical,
"display_mode": db_pref.display_mode,
"priority": db_pref.priority,
"notify_on_show": db_pref.notify_on_show
}
@router.post("/preferences/bulk", response_model=List[UserVerticalPreferenceRead])
def set_vertical_preferences_bulk(
data: BulkVerticalPreferencesCreate,
session: Session = Depends(get_session),
current_user: User = Depends(get_current_user)
):
"""Set multiple band preferences at once (for onboarding)"""
result = []
for idx, vid in enumerate(data.vertical_ids):
vertical = session.get(Vertical, vid)
if not vertical:
continue
# Upsert
existing = session.exec(
select(UserVerticalPreference)
.where(UserVerticalPreference.user_id == current_user.id)
.where(UserVerticalPreference.vertical_id == vid)
).first()
if existing:
existing.display_mode = data.display_mode
existing.priority = idx
session.add(existing)
pref = existing
else:
pref = UserVerticalPreference(
user_id=current_user.id,
vertical_id=vid,
display_mode=data.display_mode,
priority=idx,
notify_on_show=True
)
session.add(pref)
result.append({
"vertical_id": vid,
"vertical": vertical,
"display_mode": data.display_mode,
"priority": idx,
"notify_on_show": True
})
session.commit()
return result
@router.put("/preferences/{vertical_id}", response_model=UserVerticalPreferenceRead)
def update_vertical_preference(
vertical_id: int,
data: UserVerticalPreferenceUpdate,
session: Session = Depends(get_session),
current_user: User = Depends(get_current_user)
):
"""Update a specific band preference"""
pref = session.exec(
select(UserVerticalPreference)
.where(UserVerticalPreference.user_id == current_user.id)
.where(UserVerticalPreference.vertical_id == vertical_id)
).first()
if not pref:
raise HTTPException(status_code=404, detail="Preference not found")
vertical = session.get(Vertical, vertical_id)
update_data = data.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(pref, key, value)
session.add(pref)
session.commit()
session.refresh(pref)
return {
"vertical_id": pref.vertical_id,
"vertical": vertical,
"display_mode": pref.display_mode,
"priority": pref.priority,
"notify_on_show": pref.notify_on_show
}
@router.delete("/preferences/{vertical_id}")
def delete_vertical_preference(
vertical_id: int,
session: Session = Depends(get_session),
current_user: User = Depends(get_current_user)
):
"""Remove a band from user's preferences"""
pref = session.exec(
select(UserVerticalPreference)
.where(UserVerticalPreference.user_id == current_user.id)
.where(UserVerticalPreference.vertical_id == vertical_id)
).first()
if not pref:
raise HTTPException(status_code=404, detail="Preference not found")
session.delete(pref)
session.commit()
return {"ok": True}