elmeg-demo/backend/routers/feed.py

131 lines
4.2 KiB
Python

from typing import List, Union
from fastapi import APIRouter, Depends, Query
from sqlmodel import Session, select, desc
from database import get_session
from models import Review, Attendance, GroupPost, User, Profile, Performance, Show, Song
from schemas import ReviewRead, AttendanceRead, GroupPostRead
from datetime import datetime
router = APIRouter(prefix="/feed", tags=["feed"])
# We need a unified schema for the feed
from pydantic import BaseModel
class FeedItem(BaseModel):
type: str # review, attendance, post
timestamp: datetime
data: Union[ReviewRead, AttendanceRead, GroupPostRead, dict]
user: dict # Basic user info
entity: dict | None = None # Linked entity info
def get_user_display(session: Session, user_id: int) -> dict:
"""Get consistent user display info using Profile username"""
user = session.get(User, user_id)
if not user:
return {"id": 0, "username": "Deleted User", "avatar_bg_color": "#666", "avatar_text": None}
profile = session.exec(
select(Profile).where(Profile.user_id == user_id)
).first()
return {
"id": user.id,
"username": profile.username if profile else f"User {user_id}",
"display_name": profile.display_name if profile else None,
"avatar_bg_color": user.avatar_bg_color or "#0F4C81",
"avatar_text": user.avatar_text,
}
def get_entity_info(session: Session, review: Review) -> dict | None:
"""Get entity link info for a review"""
if review.performance_id:
perf = session.get(Performance, review.performance_id)
if perf:
song = session.get(Song, perf.song_id)
show = session.get(Show, perf.show_id)
return {
"type": "performance",
"slug": perf.slug,
"title": song.title if song else "Unknown Song",
"date": show.date.isoformat() if show and show.date else None,
}
elif review.show_id:
show = session.get(Show, review.show_id)
if show:
return {
"type": "show",
"slug": show.slug,
"title": show.date.strftime("%Y-%m-%d") if show.date else "Unknown Date",
}
elif review.song_id:
song = session.get(Song, review.song_id)
if song:
return {
"type": "song",
"slug": song.slug,
"title": song.title,
}
return None
@router.get("/", response_model=List[FeedItem])
def get_global_feed(
limit: int = 20,
session: Session = Depends(get_session)
):
# Fetch latest reviews
reviews = session.exec(
select(Review).order_by(desc(Review.created_at)).limit(limit)
).all()
# Fetch latest attendance
attendance = session.exec(
select(Attendance).order_by(desc(Attendance.created_at)).limit(limit)
).all()
# Fetch latest group posts
posts = session.exec(
select(GroupPost).order_by(desc(GroupPost.created_at)).limit(limit)
).all()
feed_items = []
for r in reviews:
feed_items.append(FeedItem(
type="review",
timestamp=r.created_at or datetime.utcnow(),
data=r,
user=get_user_display(session, r.user_id),
entity=get_entity_info(session, r)
))
for a in attendance:
show = session.get(Show, a.show_id) if a.show_id else None
entity_info = None
if show:
entity_info = {
"type": "show",
"slug": show.slug,
"title": show.date.strftime("%Y-%m-%d") if show.date else "Unknown",
}
feed_items.append(FeedItem(
type="attendance",
timestamp=a.created_at,
data=a,
user=get_user_display(session, a.user_id),
entity=entity_info
))
for p in posts:
feed_items.append(FeedItem(
type="post",
timestamp=p.created_at,
data=p,
user=get_user_display(session, p.user_id),
entity=None
))
# Sort by timestamp desc
feed_items.sort(key=lambda x: x.timestamp, reverse=True)
return feed_items[:limit]