"""Articles router.""" from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_current_user, get_db from app.models.article import CleanedArticle from app.models.user import User from app.schemas.article import ArticleListParams, ArticleOut from app.schemas.common import MessageResponse, PaginatedResponse router = APIRouter(prefix="/articles", tags=["articles"]) @router.get("", response_model=PaginatedResponse) async def list_articles( params: ArticleListParams = Depends(), db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): """List cleaned articles with filters.""" query = select(CleanedArticle) if params.feed_id: query = query.where(CleanedArticle.feed_id == params.feed_id) if params.category: query = query.where(CleanedArticle.category == params.category) if params.tag: query = query.where(CleanedArticle.tags.contains([params.tag])) if params.search: query = query.where( CleanedArticle.title.ilike(f"%{params.search}%") | CleanedArticle.ai_summary.ilike(f"%{params.search}%") ) if params.is_read is not None: # CleanedArticle doesn't have is_read in current schema; placeholder pass # Count count_query = select(func.count()).select_from(query.subquery()) total = (await db.execute(count_query)).scalar_one() # Paginate query = ( query.offset(params.skip) .limit(params.limit) .order_by(CleanedArticle.published_at.desc().nulls_last()) ) result = await db.execute(query) items = result.scalars().all() return { "total": total, "items": [ArticleOut.model_validate(item) for item in items], } @router.get("/{article_id}", response_model=ArticleOut) async def get_article( article_id: str, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): """Get a single cleaned article.""" article = await db.get(CleanedArticle, article_id) if not article: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Article not found") return ArticleOut.model_validate(article) @router.put("/{article_id}/read", response_model=MessageResponse) async def mark_article_read( article_id: str, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): """Mark an article as read (placeholder).""" # In Phase 1, cleaned_articles doesn't have is_read field yet return {"message": "Article marked as read"}