mirror of
https://git.victorphan.net/basketballcantho/ten-project.git
synced 2026-08-05 11:23:10 +07:00
67 lines
2.5 KiB
Python
67 lines
2.5 KiB
Python
from datetime import datetime, timezone
|
|
from sqlalchemy import (
|
|
Column,
|
|
Integer,
|
|
String,
|
|
Text,
|
|
ForeignKey,
|
|
DateTime,
|
|
UniqueConstraint,
|
|
)
|
|
from sqlalchemy.dialects.postgresql import JSONB
|
|
from sqlalchemy.orm import relationship
|
|
from .database import Base
|
|
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
username = Column(String(64), unique=True, nullable=False, index=True)
|
|
email = Column(String(255), unique=True, nullable=False, index=True)
|
|
password_hash = Column(String(255), nullable=False)
|
|
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False)
|
|
|
|
# Relationships
|
|
pdfs = relationship("PDF", back_populates="owner", cascade="all, delete-orphan")
|
|
annotations = relationship("Annotation", back_populates="owner", cascade="all, delete-orphan")
|
|
|
|
|
|
class PDF(Base):
|
|
__tablename__ = "pdfs"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
title = Column(String(255), nullable=False)
|
|
file_path = Column(Text, nullable=False) # path inside Docker volume
|
|
total_pages = Column(Integer, nullable=True) # populated after upload processing
|
|
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False)
|
|
|
|
# Relationships
|
|
owner = relationship("User", back_populates="pdfs")
|
|
annotations = relationship("Annotation", back_populates="pdf", cascade="all, delete-orphan")
|
|
|
|
|
|
class Annotation(Base):
|
|
__tablename__ = "annotations"
|
|
__table_args__ = (
|
|
# One annotation record per (pdf, user, page) — upsert target
|
|
UniqueConstraint("pdf_id", "user_id", "page_number", name="uq_annotation_pdf_user_page"),
|
|
)
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
pdf_id = Column(Integer, ForeignKey("pdfs.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
page_number = Column(Integer, nullable=False) # 1-based
|
|
canvas_data = Column(JSONB, nullable=False, default=dict) # Fabric.js JSON state
|
|
updated_at = Column(
|
|
DateTime(timezone=True),
|
|
default=lambda: datetime.now(timezone.utc),
|
|
onupdate=lambda: datetime.now(timezone.utc),
|
|
nullable=False,
|
|
)
|
|
|
|
# Relationships
|
|
pdf = relationship("PDF", back_populates="annotations")
|
|
owner = relationship("User", back_populates="annotations")
|