"""뉴스 소스 관리 API""" from typing import Annotated from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from core.auth import get_current_user from core.database import get_session from models.news_source import NewsSource from models.user import User router = APIRouter() class NewsSourceResponse(BaseModel): id: int name: str country: str | None feed_url: str feed_type: str category: str | None language: str | None enabled: bool last_fetched_at: str | None created_at: str class Config: from_attributes = True class NewsSourceCreate(BaseModel): name: str country: str | None = None feed_url: str feed_type: str = "rss" category: str | None = None language: str | None = None class NewsSourceUpdate(BaseModel): name: str | None = None feed_url: str | None = None category: str | None = None enabled: bool | None = None @router.get("/sources") async def list_sources( user: Annotated[User, Depends(get_current_user)], session: Annotated[AsyncSession, Depends(get_session)], ): result = await session.execute(select(NewsSource).order_by(NewsSource.id)) return [NewsSourceResponse.model_validate(s) for s in result.scalars().all()] @router.post("/sources") async def create_source( body: NewsSourceCreate, user: Annotated[User, Depends(get_current_user)], session: Annotated[AsyncSession, Depends(get_session)], ): source = NewsSource(**body.model_dump()) session.add(source) await session.commit() return NewsSourceResponse.model_validate(source) @router.patch("/sources/{source_id}") async def update_source( source_id: int, body: NewsSourceUpdate, user: Annotated[User, Depends(get_current_user)], session: Annotated[AsyncSession, Depends(get_session)], ): source = await session.get(NewsSource, source_id) if not source: raise HTTPException(status_code=404) for field, value in body.model_dump(exclude_unset=True).items(): setattr(source, field, value) await session.commit() return NewsSourceResponse.model_validate(source) @router.delete("/sources/{source_id}") async def delete_source( source_id: int, user: Annotated[User, Depends(get_current_user)], session: Annotated[AsyncSession, Depends(get_session)], ): source = await session.get(NewsSource, source_id) if not source: raise HTTPException(status_code=404) await session.delete(source) await session.commit() return {"message": f"소스 {source_id} 삭제됨"} @router.post("/collect") async def trigger_collect( user: Annotated[User, Depends(get_current_user)], ): """수동 수집 트리거""" from workers.news_collector import run import asyncio asyncio.create_task(run()) return {"message": "뉴스 수집 시작됨"}