from fastapi import APIRouter from sqlalchemy import select, func from sqlalchemy.orm import selectinload from app.api.deps import DbSession, CurrentUser from app.models import Activity, Participant, Dispute, ActivityType from app.models.dispute import DisputeStatus from app.schemas import FeedResponse, ActivityResponse, UserPublic router = APIRouter(tags=["feed"]) @router.get("/marathons/{marathon_id}/feed", response_model=FeedResponse) async def get_feed( marathon_id: int, current_user: CurrentUser, db: DbSession, limit: int = 20, offset: int = 0, ): """Get activity feed for marathon""" # Check user is participant result = await db.execute( select(Participant).where( Participant.user_id == current_user.id, Participant.marathon_id == marathon_id, ) ) if not result.scalar_one_or_none(): return FeedResponse(items=[], total=0, has_more=False) # Get total count total = await db.scalar( select(func.count()).select_from(Activity).where(Activity.marathon_id == marathon_id) ) # Get activities result = await db.execute( select(Activity) .options(selectinload(Activity.user)) .where(Activity.marathon_id == marathon_id) .order_by(Activity.created_at.desc()) .limit(limit) .offset(offset) ) activities = result.scalars().all() # Get assignment_ids from complete activities to check for disputes complete_assignment_ids = [] for a in activities: if a.type == ActivityType.COMPLETE.value and a.data and a.data.get("assignment_id"): complete_assignment_ids.append(a.data["assignment_id"]) # Get disputes for these assignments disputes_map: dict[int, str] = {} if complete_assignment_ids: result = await db.execute( select(Dispute).where(Dispute.assignment_id.in_(complete_assignment_ids)) ) for dispute in result.scalars().all(): disputes_map[dispute.assignment_id] = dispute.status items = [] for a in activities: data = dict(a.data) if a.data else {} # Add dispute status to complete activities if a.type == ActivityType.COMPLETE.value and a.data and a.data.get("assignment_id"): assignment_id = a.data["assignment_id"] if assignment_id in disputes_map: data["dispute_status"] = disputes_map[assignment_id] items.append( ActivityResponse( id=a.id, type=a.type, user=UserPublic.model_validate(a.user), data=data if data else None, created_at=a.created_at, ) ) return FeedResponse( items=items, total=total, has_more=(offset + limit) < total, )