feat: add GET /api/briefing/news unified news endpoint
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -322,3 +322,58 @@ async def delete_rss_reaction(item_id: int):
|
|||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
||||||
return jsonify({"ok": True})
|
return jsonify({"ok": True})
|
||||||
|
|
||||||
|
|
||||||
|
@briefing_bp.route("/news", methods=["GET"])
|
||||||
|
@_REQUIRE
|
||||||
|
async def list_news():
|
||||||
|
"""Return recent RSS articles with optional feed filter and pagination.
|
||||||
|
|
||||||
|
Query params:
|
||||||
|
days — lookback window (default 2, max 90)
|
||||||
|
limit — items per page (default 40, max 100)
|
||||||
|
offset — pagination offset (default 0)
|
||||||
|
feed_id — optional integer filter by feed
|
||||||
|
"""
|
||||||
|
from sqlalchemy import text as _text
|
||||||
|
|
||||||
|
days = min(int(request.args.get("days", 2)), 90)
|
||||||
|
limit = min(int(request.args.get("limit", 40)), 100)
|
||||||
|
offset = max(int(request.args.get("offset", 0)), 0)
|
||||||
|
feed_id = request.args.get("feed_id", type=int)
|
||||||
|
|
||||||
|
async with async_session() as session:
|
||||||
|
result = await session.execute(
|
||||||
|
_text("""
|
||||||
|
SELECT
|
||||||
|
i.id, i.title, i.url, i.content, i.published_at,
|
||||||
|
i.topics, f.title AS feed_title,
|
||||||
|
r.reaction
|
||||||
|
FROM rss_items i
|
||||||
|
JOIN rss_feeds f ON f.id = i.feed_id
|
||||||
|
LEFT JOIN rss_item_reactions r
|
||||||
|
ON r.rss_item_id = i.id AND r.user_id = :uid
|
||||||
|
WHERE f.user_id = :uid
|
||||||
|
AND (:feed_id IS NULL OR f.id = :feed_id)
|
||||||
|
AND i.published_at >= NOW() - make_interval(days => :days)
|
||||||
|
ORDER BY i.published_at DESC NULLS LAST
|
||||||
|
LIMIT :limit OFFSET :offset
|
||||||
|
""").bindparams(uid=g.user.id, days=days, limit=limit,
|
||||||
|
offset=offset, feed_id=feed_id)
|
||||||
|
)
|
||||||
|
rows = result.mappings().all()
|
||||||
|
|
||||||
|
items = [
|
||||||
|
{
|
||||||
|
"id": r["id"],
|
||||||
|
"title": r["title"],
|
||||||
|
"url": r["url"],
|
||||||
|
"snippet": (r["content"] or "")[:300],
|
||||||
|
"published_at": r["published_at"].isoformat() if r["published_at"] else None,
|
||||||
|
"topics": r["topics"] or [],
|
||||||
|
"source": r["feed_title"],
|
||||||
|
"reaction": r["reaction"],
|
||||||
|
}
|
||||||
|
for r in rows
|
||||||
|
]
|
||||||
|
return jsonify({"items": items, "offset": offset, "limit": limit})
|
||||||
|
|||||||
Reference in New Issue
Block a user