""" 回忆录相关 API 路由 """ from fastapi import APIRouter, Depends, HTTPException, Query, Body from pydantic import BaseModel from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from database import get_async_db from database.models import Book as BookModel from database.models import User as UserModel from services.pdf_service import pdf_service from middleware.auth import get_current_user router = APIRouter(prefix="/api/books", tags=["books"]) @router.get("/current") async def get_current_book( current_user: UserModel = Depends(get_current_user), db: AsyncSession = Depends(get_async_db) ): """获取当前回忆录(需要认证)""" stmt = select(BookModel).where(BookModel.user_id == current_user.id).order_by(BookModel.updated_at.desc()).limit(1) result = await db.execute(stmt) book = result.scalar_one_or_none() if not book: return {"message": "No book found"} return { "id": book.id, "title": book.title, "total_pages": book.total_pages, "total_words": book.total_words, "cover_image_url": book.cover_image_url, "has_update": book.has_update, "last_update_chapter_id": book.last_update_chapter_id, } @router.post("/clear-update") async def clear_book_update( current_user: UserModel = Depends(get_current_user), db: AsyncSession = Depends(get_async_db), ): """清除回忆录更新标记""" stmt = select(BookModel).where(BookModel.user_id == current_user.id).order_by(BookModel.updated_at.desc()).limit(1) result = await db.execute(stmt) book = result.scalar_one_or_none() if not book: return {"status": "ok", "message": "No book found"} book.has_update = False await db.commit() return {"status": "ok"} class UpdateBookRequest(BaseModel): title: str subtitle: str | None = None # 目前数据库不支持subtitle,但保留字段以便将来扩展 @router.put("/{book_id}") async def update_book( book_id: str, request: UpdateBookRequest = Body(...), current_user: UserModel = Depends(get_current_user), db: AsyncSession = Depends(get_async_db) ): """更新书籍标题(需要认证,只能更新自己的回忆录)""" book = await db.get(BookModel, book_id) if not book: raise HTTPException(status_code=404, detail="Book not found") # 验证用户权限 if book.user_id != current_user.id: raise HTTPException(status_code=403, detail="无权更新此回忆录") # 更新标题 book.title = request.title # subtitle字段目前数据库不支持,暂时忽略 await db.commit() await db.refresh(book) return { "id": book.id, "title": book.title, "total_pages": book.total_pages, "total_words": book.total_words, "cover_image_url": book.cover_image_url, "has_update": book.has_update, "last_update_chapter_id": book.last_update_chapter_id, } class ExportPdfRequest(BaseModel): book_id: str @router.post("/export-pdf") async def export_pdf( request: ExportPdfRequest = Body(...), current_user: UserModel = Depends(get_current_user), db: AsyncSession = Depends(get_async_db) ): """导出 PDF(需要认证,只能导出自己的回忆录)""" book = await db.get(BookModel, request.book_id) if not book: raise HTTPException(status_code=404, detail="Book not found") # 验证用户权限 if book.user_id != current_user.id: raise HTTPException(status_code=403, detail="无权导出此回忆录") # 获取所有 active 章节 from database.models import Chapter stmt = select(Chapter).where( Chapter.user_id == current_user.id, Chapter.is_active == True ).order_by(Chapter.order_index) result = await db.execute(stmt) chapters = result.scalars().all() # 生成 PDF pdf_bytes = await pdf_service.generate_pdf(book, chapters) return { "pdf_base64": pdf_bytes.decode('latin1'), # 简化处理,实际应该用 base64 "filename": f"{book.title}.pdf" }