"""用户数据服务 — 收藏、阅读状态、个人笔记。无账号体系,数据写入本地 SQLite。""" from __future__ import annotations from datetime import datetime, timezone from sqlalchemy.orm import Session from app.models import Paper, UserBookmark, UserNote, UserReadingStatus # ── 收藏 ────────────────────────────────────────────────────────────── def toggle_bookmark(db: Session, arxiv_id: str) -> dict: """切换收藏状态。返回 {"bookmarked": bool, "arxiv_id": str}。""" paper = db.query(Paper).filter(Paper.arxiv_id == arxiv_id).first() if not paper: return {"error": "not_found"} existing = db.query(UserBookmark).filter(UserBookmark.paper_id == paper.id).first() if existing: db.delete(existing) db.commit() return {"bookmarked": False, "arxiv_id": arxiv_id} else: bookmark = UserBookmark( paper_id=paper.id, created_at=datetime.now(timezone.utc), ) db.add(bookmark) db.commit() return {"bookmarked": True, "arxiv_id": arxiv_id} # ── 阅读状态 ────────────────────────────────────────────────────────── VALID_STATUSES = {"unread", "skimmed", "read_summary", "read_full"} def set_reading_status(db: Session, arxiv_id: str, status: str) -> dict: """设置阅读状态。status 必须是 unread/skimmed/read_summary/read_full。""" if status not in VALID_STATUSES: return {"error": "invalid_status", "valid": sorted(VALID_STATUSES)} paper = db.query(Paper).filter(Paper.arxiv_id == arxiv_id).first() if not paper: return {"error": "not_found"} now = datetime.now(timezone.utc) existing = ( db.query(UserReadingStatus) .filter(UserReadingStatus.paper_id == paper.id) .first() ) if existing: existing.status = status existing.updated_at = now else: db.add( UserReadingStatus( paper_id=paper.id, status=status, updated_at=now, ) ) db.commit() return {"arxiv_id": arxiv_id, "status": status} # ── 笔记 ────────────────────────────────────────────────────────────── def get_note(db: Session, arxiv_id: str) -> dict | None: """获取笔记。返回 {"arxiv_id", "content", "updated_at"} 或 None(论文不存在时)。""" paper = db.query(Paper).filter(Paper.arxiv_id == arxiv_id).first() if not paper: return None note = db.query(UserNote).filter(UserNote.paper_id == paper.id).first() if not note: return {"arxiv_id": arxiv_id, "content": "", "updated_at": None} return { "arxiv_id": arxiv_id, "content": note.content, "updated_at": note.updated_at.isoformat() if note.updated_at else None, } def save_note(db: Session, arxiv_id: str, content: str) -> dict: """创建或更新笔记。返回 {"arxiv_id", "content", "updated_at"}。""" paper = db.query(Paper).filter(Paper.arxiv_id == arxiv_id).first() if not paper: return {"error": "not_found"} now = datetime.now(timezone.utc) existing = db.query(UserNote).filter(UserNote.paper_id == paper.id).first() if existing: existing.content = content existing.updated_at = now else: db.add( UserNote( paper_id=paper.id, content=content, created_at=now, updated_at=now, ) ) db.commit() return { "arxiv_id": arxiv_id, "content": content, "updated_at": now.isoformat(), }