| from sqlalchemy import Column, Integer, String, Float, DateTime, Text, ForeignKey, Boolean
|
| from sqlalchemy.orm import relationship
|
| from sqlalchemy.sql import func
|
|
|
| from .db import Base
|
|
|
|
|
| class User(Base):
|
| """
|
| Stores user information from Firebase or OTP authentication.
|
| """
|
| __tablename__ = "users"
|
|
|
| id = Column(Integer, primary_key=True, index=True)
|
| email = Column(String, unique=True, index=True, nullable=False)
|
| name = Column(String, nullable=True)
|
| picture = Column(String, nullable=True)
|
|
|
|
|
| auth_method = Column(String, default='firebase')
|
|
|
|
|
| firebase_uid = Column(String, unique=True, index=True, nullable=True)
|
|
|
|
|
| email_verified = Column(Boolean, default=False)
|
|
|
| created_at = Column(
|
| DateTime(timezone=True),
|
| server_default=func.now(),
|
| )
|
|
|
|
|
|
|
| extractions = relationship(
|
| "ExtractionRecord",
|
| back_populates="user",
|
| primaryjoin="User.id == ExtractionRecord.user_id"
|
| )
|
|
|
|
|
| api_keys = relationship(
|
| "APIKey",
|
| back_populates="user",
|
| cascade="all, delete-orphan"
|
| )
|
|
|
|
|
| class ExtractionRecord(Base):
|
| """
|
| Stores one extraction run so the History page can show past jobs.
|
| We'll fill it from the /api/extract endpoint later.
|
| """
|
|
|
| __tablename__ = "extractions"
|
|
|
| id = Column(Integer, primary_key=True, index=True)
|
| user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
|
|
|
| file_name = Column(String, index=True)
|
| file_type = Column(String)
|
| file_size = Column(String)
|
|
|
| status = Column(String)
|
| confidence = Column(Float)
|
| fields_extracted = Column(Integer)
|
| total_time_ms = Column(Integer)
|
|
|
| raw_output = Column(Text)
|
| file_base64 = Column(Text, nullable=True)
|
| error_message = Column(Text, nullable=True)
|
|
|
| created_at = Column(
|
| DateTime(timezone=True),
|
| server_default=func.now(),
|
| )
|
|
|
|
|
|
|
| user = relationship(
|
| "User",
|
| back_populates="extractions",
|
| primaryjoin="ExtractionRecord.user_id == User.id"
|
| )
|
|
|
|
|
| shared_from_extraction_id = Column(Integer, ForeignKey("extractions.id"), nullable=True, index=True)
|
| shared_by_user_id = Column(Integer, ForeignKey("users.id"), nullable=True, index=True)
|
|
|
|
|
| class ShareToken(Base):
|
| """
|
| Stores share tokens for sharing extractions with other users.
|
| """
|
| __tablename__ = "share_tokens"
|
|
|
| id = Column(Integer, primary_key=True, index=True)
|
| token = Column(String, unique=True, index=True, nullable=False)
|
| extraction_id = Column(Integer, ForeignKey("extractions.id"), nullable=False, index=True)
|
| sender_user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
|
| recipient_email = Column(String, nullable=True, index=True)
|
| expires_at = Column(DateTime(timezone=True), nullable=True)
|
| accessed = Column(Boolean, default=False)
|
| accessed_at = Column(DateTime(timezone=True), nullable=True)
|
| accessed_by_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
|
|
| created_at = Column(
|
| DateTime(timezone=True),
|
| server_default=func.now(),
|
| )
|
|
|
|
|
| class APIKey(Base):
|
| """
|
| Stores API keys for external application authentication.
|
| API keys are hashed before storage for security.
|
| """
|
| __tablename__ = "api_keys"
|
|
|
| id = Column(Integer, primary_key=True, index=True)
|
| user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
|
| name = Column(String, nullable=False)
|
| key_hash = Column(String, unique=True, index=True, nullable=False)
|
| key_prefix = Column(String, nullable=False)
|
| is_active = Column(Boolean, default=True, nullable=False)
|
| last_used_at = Column(DateTime(timezone=True), nullable=True)
|
| created_at = Column(
|
| DateTime(timezone=True),
|
| server_default=func.now(),
|
| )
|
|
|
|
|
| user = relationship(
|
| "User",
|
| back_populates="api_keys"
|
| )
|
|
|