104 lines
3.4 KiB
Python
104 lines
3.4 KiB
Python
"""用户数据 JSON API — 收藏、阅读状态、笔记。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
from fastapi.responses import HTMLResponse
|
|
from pydantic import BaseModel
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.database import get_db
|
|
from app.services.user_data import (
|
|
get_note,
|
|
save_note,
|
|
set_reading_status,
|
|
toggle_bookmark,
|
|
)
|
|
|
|
router = APIRouter(prefix="/api", tags=["user-data"])
|
|
|
|
|
|
# ── 请求模型 ──────────────────────────────────────────────────────────
|
|
|
|
|
|
class ReadingStatusRequest(BaseModel):
|
|
status: str
|
|
|
|
|
|
class NoteRequest(BaseModel):
|
|
content: str
|
|
|
|
|
|
# ── 收藏 ──────────────────────────────────────────────────────────────
|
|
|
|
|
|
@router.post("/bookmark/{arxiv_id}")
|
|
def bookmark_toggle(arxiv_id: str, request: Request, db: Session = Depends(get_db)):
|
|
"""切换收藏状态。支持 HTMX 局部刷新和 JSON 响应。"""
|
|
result = toggle_bookmark(db, arxiv_id)
|
|
|
|
if "error" in result:
|
|
raise HTTPException(status_code=404, detail=result["error"])
|
|
|
|
# HTMX 请求 → 返回 HTML 片段
|
|
if request.headers.get("HX-Request"):
|
|
star = "★" if result["bookmarked"] else "☆"
|
|
active_class = " active" if result["bookmarked"] else ""
|
|
html = (
|
|
f'<button class="btn-bookmark{active_class}" '
|
|
f'hx-post="/api/bookmark/{arxiv_id}" '
|
|
f'hx-target="#user-data-{arxiv_id}" '
|
|
f'hx-swap="outerHTML">'
|
|
f"{star}</button>"
|
|
)
|
|
return HTMLResponse(content=html)
|
|
|
|
return result
|
|
|
|
|
|
# ── 阅读状态 ──────────────────────────────────────────────────────────
|
|
|
|
|
|
@router.post("/reading-status/{arxiv_id}")
|
|
def reading_status_update(
|
|
arxiv_id: str,
|
|
body: ReadingStatusRequest,
|
|
db: Session = Depends(get_db),
|
|
):
|
|
"""更新阅读状态。"""
|
|
result = set_reading_status(db, arxiv_id, body.status)
|
|
|
|
if "error" in result:
|
|
if result["error"] == "not_found":
|
|
raise HTTPException(status_code=404, detail="Paper not found")
|
|
elif result["error"] == "invalid_status":
|
|
raise HTTPException(
|
|
status_code=422,
|
|
detail=f"Invalid status. Valid: {result['valid']}",
|
|
)
|
|
|
|
return result
|
|
|
|
|
|
# ── 笔记 ──────────────────────────────────────────────────────────────
|
|
|
|
|
|
@router.get("/note/{arxiv_id}")
|
|
def note_get(arxiv_id: str, db: Session = Depends(get_db)):
|
|
"""获取笔记。"""
|
|
result = get_note(db, arxiv_id)
|
|
if result is None:
|
|
raise HTTPException(status_code=404, detail="Paper not found")
|
|
return result
|
|
|
|
|
|
@router.post("/note/{arxiv_id}")
|
|
def note_save(arxiv_id: str, body: NoteRequest, db: Session = Depends(get_db)):
|
|
"""保存笔记。"""
|
|
result = save_note(db, arxiv_id, body.content)
|
|
|
|
if "error" in result:
|
|
raise HTTPException(status_code=404, detail=result["error"])
|
|
|
|
return result
|