language-learning-app/api/app/routers/bff/articles.py

105 lines
3.2 KiB
Python
Raw Normal View History

2026-03-27 11:04:05 +00:00
import uuid
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
2026-03-27 11:04:05 +00:00
from sqlalchemy.ext.asyncio import AsyncSession
2026-03-27 11:04:05 +00:00
from ...auth import verify_token
from ...config import settings
from ...domain.services.article_service import ArticleService
2026-03-27 11:04:05 +00:00
from ...outbound.postgres.database import get_db
from ...outbound.postgres.repositories.translated_article_repository import TranslatedArticleRepository
router = APIRouter(prefix="/articles", tags=["bff", "articles"])
class ArticleItem(BaseModel):
id: str
published_at: datetime
source_language: str
source_title: str
target_language: str
target_complexities: list[str]
target_title: str
2026-03-27 11:04:05 +00:00
class ArticleListResponse(BaseModel):
articles: list[ArticleItem]
2026-03-27 11:04:05 +00:00
class ArticleDetail(BaseModel):
id: str
published_at: datetime
source_language: str
source_title: str
source_body: str
target_language: str
2026-03-27 11:04:05 +00:00
target_complexities: list[str]
target_title: str
target_body: str
target_audio_url: str | None
target_body_pos: dict | None
target_body_transcript: dict | None
2026-03-27 11:04:05 +00:00
def _audio_url(key: str | None) -> str | None:
if key is None:
return None
return f"{settings.api_base_url}/media/{key}"
2026-03-27 11:04:05 +00:00
@router.get("", response_model=ArticleListResponse, status_code=200)
async def list_articles(
target_language: str = 'fr',
db: AsyncSession = Depends(get_db),
_: dict = Depends(verify_token),
) -> ArticleListResponse:
service = ArticleService(TranslatedArticleRepository(db))
articles = await service.get_all_articles(target_language=target_language)
return ArticleListResponse(
articles=[
ArticleItem(
id=a.id,
published_at=a.published_at,
source_language=a.source_language,
source_title=a.source_title,
target_language=a.target_language,
target_complexities=a.target_complexities,
target_title=a.target_title,
)
for a in articles
]
)
@router.get("/{article_id}", response_model=ArticleDetail, status_code=200)
async def get_article(
article_id: str,
db: AsyncSession = Depends(get_db),
_: dict = Depends(verify_token),
) -> ArticleDetail:
try:
2026-03-27 11:04:05 +00:00
uid = uuid.UUID(article_id)
except ValueError:
raise HTTPException(status_code=400, detail="Invalid article ID")
article = await TranslatedArticleRepository(db).get_by_id(uid)
if article is None:
raise HTTPException(status_code=404, detail="Article not found")
return ArticleDetail(
id=article.id,
published_at=article.published_at,
source_language=article.source_language,
source_title=article.source_title,
source_body=article.source_body,
target_language=article.target_language,
target_complexities=article.target_complexities,
target_title=article.target_title,
target_body=article.target_body,
target_audio_url=_audio_url(article.audio_url),
target_body_pos=article.target_body_pos,
target_body_transcript=article.target_body_transcript,
)