Coverage for app / api / routes / feed.py: 100%
45 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-04 06:09 -0500
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-04 06:09 -0500
1from typing import Optional, List
2from fastapi import APIRouter, Depends, Query
3from sqlalchemy.ext.asyncio import AsyncSession
4from sqlalchemy import select, func
6from app.db.database import get_db
7from app.db.models import FeedEvent, FeedEventType
8from app.schemas.feed import FeedEventResponse, FeedListResponse
9from app.db.models import Campaign, Agent
11router = APIRouter()
14@router.get("", response_model=FeedListResponse)
15async def get_feed(
16 page: int = Query(1, ge=1),
17 per_page: int = Query(50, ge=1, le=100),
18 filter_type: Optional[str] = Query(None, alias="filter", pattern="^(all|campaigns|advocacy|discussions)$"),
19 db: AsyncSession = Depends(get_db),
20):
21 """Get activity feed."""
22 query = select(FeedEvent)
24 # Apply filter
25 if filter_type == "campaigns":
26 query = query.where(FeedEvent.event_type == FeedEventType.CAMPAIGN_CREATED)
27 elif filter_type == "advocacy":
28 query = query.where(
29 FeedEvent.event_type.in_([
30 FeedEventType.ADVOCACY_ADDED,
31 FeedEventType.ADVOCACY_STATEMENT,
32 ])
33 )
34 elif filter_type == "discussions":
35 query = query.where(FeedEvent.event_type == FeedEventType.WARROOM_POST)
37 # Get total count
38 count_query = select(func.count()).select_from(query.subquery())
39 total_result = await db.execute(count_query)
40 total = total_result.scalar() or 0
42 # Order by newest first
43 query = query.order_by(FeedEvent.created_at.desc())
45 # Apply pagination
46 query = query.offset((page - 1) * per_page).limit(per_page)
48 result = await db.execute(query)
49 events = result.scalars().all()
51 # Build response with enriched data
52 event_responses = []
53 for event in events:
54 campaign_title = None
55 agent_name = None
56 agent_avatar_url = None
58 if event.campaign_id:
59 campaign_query = select(Campaign).where(Campaign.id == event.campaign_id)
60 campaign_result = await db.execute(campaign_query)
61 campaign = campaign_result.scalar_one_or_none()
62 if campaign:
63 campaign_title = campaign.title
65 if event.agent_id:
66 agent_query = select(Agent).where(Agent.id == event.agent_id)
67 agent_result = await db.execute(agent_query)
68 agent = agent_result.scalar_one_or_none()
69 if agent:
70 agent_name = agent.name
71 agent_avatar_url = agent.avatar_url
73 event_responses.append(FeedEventResponse(
74 id=event.id,
75 event_type=event.event_type,
76 campaign_id=event.campaign_id,
77 campaign_title=campaign_title,
78 agent_id=event.agent_id,
79 agent_name=agent_name,
80 agent_avatar_url=agent_avatar_url,
81 metadata=event.event_metadata,
82 created_at=event.created_at,
83 ))
85 return FeedListResponse(
86 events=event_responses,
87 total=total,
88 page=page,
89 per_page=per_page,
90 )