"""/bookmarks 收藏。""" from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.core.deps import get_current_user from app.database import get_session from app.models.article import Article from app.models.bookmark import Bookmark from app.models.user import User from app.schemas.misc import BookmarkIn, BookmarkOut router = APIRouter(prefix="/bookmarks", tags=["bookmarks"]) @router.post("", response_model=BookmarkOut, status_code=status.HTTP_201_CREATED) async def add( body: BookmarkIn, user: User = Depends(get_current_user), session: AsyncSession = Depends(get_session), ): result = await session.execute(select(Article).where(Article.id == body.article_id)) art = result.scalar_one_or_none() if not art: raise HTTPException(status.HTTP_404_NOT_FOUND, "Article not found") # 已存在则直接返回 existing = ( await session.execute( select(Bookmark).where( Bookmark.user_id == user.id, Bookmark.article_id == body.article_id ) ) ).scalar_one_or_none() if existing: return BookmarkOut.model_validate(existing) bm = Bookmark(user_id=user.id, article_id=body.article_id, note=body.note) session.add(bm) await session.commit() await session.refresh(bm) return BookmarkOut.model_validate(bm) @router.delete("/{article_id}", status_code=status.HTTP_204_NO_CONTENT) async def remove( article_id: int, user: User = Depends(get_current_user), session: AsyncSession = Depends(get_session), ): bm = ( await session.execute( select(Bookmark).where( Bookmark.user_id == user.id, Bookmark.article_id == article_id ) ) ).scalar_one_or_none() if bm: await session.delete(bm) await session.commit() return None @router.get("", response_model=list[BookmarkOut]) async def list_mine( user: User = Depends(get_current_user), session: AsyncSession = Depends(get_session), ): result = await session.execute( select(Bookmark).where(Bookmark.user_id == user.id).order_by(Bookmark.created_at.desc()) ) rows = result.scalars() return [BookmarkOut.model_validate(b) for b in rows]