"""Feed router — personalized feed, trending, new.""" from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from app.database import get_db from app.models import User, Shader from app.schemas import ShaderFeedItem, DwellReport from app.middleware.auth import get_optional_user, get_current_user router = APIRouter() # Common filter for public, published shaders _FEED_FILTER = [Shader.is_public == True, Shader.status == "published"] @router.get("", response_model=list[ShaderFeedItem]) async def get_feed( limit: int = Query(20, ge=1, le=50), cursor: str | None = Query(None), db: AsyncSession = Depends(get_db), user: User | None = Depends(get_optional_user), ): query = ( select(Shader) .where(*_FEED_FILTER) .order_by(Shader.created_at.desc()) .limit(limit) ) result = await db.execute(query) return result.scalars().all() @router.get("/trending", response_model=list[ShaderFeedItem]) async def get_trending( limit: int = Query(20, ge=1, le=50), db: AsyncSession = Depends(get_db), ): query = ( select(Shader) .where(*_FEED_FILTER) .order_by(Shader.score.desc()) .limit(limit) ) result = await db.execute(query) return result.scalars().all() @router.get("/new", response_model=list[ShaderFeedItem]) async def get_new( limit: int = Query(20, ge=1, le=50), db: AsyncSession = Depends(get_db), ): query = ( select(Shader) .where(*_FEED_FILTER) .order_by(Shader.created_at.desc()) .limit(limit) ) result = await db.execute(query) return result.scalars().all() @router.post("/dwell", status_code=204) async def report_dwell( body: DwellReport, db: AsyncSession = Depends(get_db), user: User | None = Depends(get_optional_user), ): from app.models import EngagementEvent event = EngagementEvent( user_id=user.id if user else None, session_id=body.session_id, shader_id=body.shader_id, event_type="dwell", dwell_secs=body.dwell_secs, event_metadata={"replayed": body.replayed}, ) db.add(event)