mirror of
https://git.victorphan.net/basketballcantho/ten-project.git
synced 2026-08-05 09:53:10 +07:00
153 lines
4.5 KiB
Python
153 lines
4.5 KiB
Python
from datetime import datetime, timezone
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
|
|
from ..database import get_db
|
|
from ..dependencies import get_current_user
|
|
from ..models import Annotation, PDF, User
|
|
from ..schemas import AnnotationIn, AnnotationOut
|
|
|
|
router = APIRouter(prefix="/annotations", tags=["annotations"])
|
|
|
|
|
|
def _verify_pdf_ownership(db: Session, pdf_id: int, user_id: int) -> PDF:
|
|
pdf = db.get(PDF, pdf_id)
|
|
if not pdf or pdf.user_id != user_id:
|
|
raise HTTPException(status_code=404, detail="PDF not found.")
|
|
return pdf
|
|
|
|
|
|
def _any_pdf_or_404(db: Session, pdf_id: int) -> PDF:
|
|
"""Return PDF regardless of owner — any authenticated user may read annotations."""
|
|
pdf = db.get(PDF, pdf_id)
|
|
if not pdf:
|
|
raise HTTPException(status_code=404, detail="PDF not found.")
|
|
return pdf
|
|
|
|
|
|
# ── GET /api/annotations/{pdf_id}/{page_number} ───────────────────────────────
|
|
|
|
@router.get("/{pdf_id}/{page_number}", response_model=AnnotationOut)
|
|
def get_annotation(
|
|
pdf_id: int,
|
|
page_number: int,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
_any_pdf_or_404(db, pdf_id)
|
|
|
|
ann = (
|
|
db.query(Annotation)
|
|
.filter(
|
|
Annotation.pdf_id == pdf_id,
|
|
Annotation.user_id == current_user.id,
|
|
Annotation.page_number == page_number,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
# Return empty canvas if no annotation exists yet — not an error
|
|
if ann is None:
|
|
return AnnotationOut(
|
|
id=0,
|
|
pdf_id=pdf_id,
|
|
page_number=page_number,
|
|
canvas_data={},
|
|
updated_at=datetime.now(timezone.utc),
|
|
)
|
|
|
|
return ann
|
|
|
|
|
|
# ── GET /api/annotations/{pdf_id}/{page_number}/all ───────────────────────────
|
|
# Returns a merged canvas_data whose "objects" array contains annotations from
|
|
# ALL users for the given page. Any authenticated user may call this.
|
|
|
|
@router.get("/{pdf_id}/{page_number}/all", response_model=AnnotationOut)
|
|
def get_all_annotations(
|
|
pdf_id: int,
|
|
page_number: int,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
_any_pdf_or_404(db, pdf_id)
|
|
|
|
rows = (
|
|
db.query(Annotation)
|
|
.filter(
|
|
Annotation.pdf_id == pdf_id,
|
|
Annotation.page_number == page_number,
|
|
)
|
|
.all()
|
|
)
|
|
|
|
if not rows:
|
|
return AnnotationOut(
|
|
id=0,
|
|
pdf_id=pdf_id,
|
|
page_number=page_number,
|
|
canvas_data={},
|
|
updated_at=datetime.now(timezone.utc),
|
|
)
|
|
|
|
# Merge all objects arrays; use canvas metadata (background etc.) from latest record
|
|
latest = max(rows, key=lambda r: r.updated_at)
|
|
base: dict = dict(latest.canvas_data) if latest.canvas_data else {}
|
|
merged_objects: list = []
|
|
for row in rows:
|
|
for obj in (row.canvas_data or {}).get("objects", []):
|
|
# Tag each object with its owner so the frontend can avoid re-saving
|
|
# other users' objects under the current user's record (prevents duplicates).
|
|
obj_copy = dict(obj)
|
|
obj_copy["_owner_id"] = row.user_id
|
|
merged_objects.append(obj_copy)
|
|
base["objects"] = merged_objects
|
|
|
|
return AnnotationOut(
|
|
id=latest.id,
|
|
pdf_id=pdf_id,
|
|
page_number=page_number,
|
|
canvas_data=base,
|
|
updated_at=latest.updated_at,
|
|
)
|
|
|
|
|
|
# ── PUT /api/annotations/{pdf_id}/{page_number} ───────────────────────────────
|
|
|
|
@router.put("/{pdf_id}/{page_number}", response_model=AnnotationOut)
|
|
def upsert_annotation(
|
|
pdf_id: int,
|
|
page_number: int,
|
|
body: AnnotationIn,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
_any_pdf_or_404(db, pdf_id)
|
|
|
|
ann = (
|
|
db.query(Annotation)
|
|
.filter(
|
|
Annotation.pdf_id == pdf_id,
|
|
Annotation.user_id == current_user.id,
|
|
Annotation.page_number == page_number,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if ann is None:
|
|
ann = Annotation(
|
|
pdf_id=pdf_id,
|
|
user_id=current_user.id,
|
|
page_number=page_number,
|
|
canvas_data=body.canvas_data,
|
|
)
|
|
db.add(ann)
|
|
else:
|
|
ann.canvas_data = body.canvas_data
|
|
ann.updated_at = datetime.now(timezone.utc)
|
|
|
|
db.commit()
|
|
db.refresh(ann)
|
|
return ann
|