120 lines
4.4 KiB
Python
120 lines
4.4 KiB
Python
"""Domain models for the application."""
|
|
|
|
import enum
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
from uuid import uuid4
|
|
|
|
from sqlalchemy import BigInteger, Boolean, DateTime, Enum, Float, Integer, String, Text, func
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.infra.database import Base
|
|
|
|
|
|
def generate_uuid() -> str:
|
|
"""Generate UUID as string for SQLite compatibility."""
|
|
return str(uuid4())
|
|
|
|
|
|
class AssetType(str, enum.Enum):
|
|
"""Type of media asset."""
|
|
|
|
PHOTO = "photo"
|
|
VIDEO = "video"
|
|
|
|
|
|
class AssetStatus(str, enum.Enum):
|
|
"""Status of media asset."""
|
|
|
|
UPLOADING = "uploading"
|
|
READY = "ready"
|
|
FAILED = "failed"
|
|
|
|
|
|
class User(Base):
|
|
"""User account."""
|
|
|
|
__tablename__ = "users"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=generate_uuid)
|
|
email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False, index=True)
|
|
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False
|
|
)
|
|
|
|
|
|
class Folder(Base):
|
|
"""Folder for organizing assets."""
|
|
|
|
__tablename__ = "folders"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=generate_uuid)
|
|
user_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
parent_folder_id: Mapped[Optional[str]] = mapped_column(
|
|
String(36), nullable=True, index=True
|
|
)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
)
|
|
|
|
|
|
class Asset(Base):
|
|
"""Media asset (photo or video)."""
|
|
|
|
__tablename__ = "assets"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=generate_uuid)
|
|
user_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
|
folder_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True, index=True)
|
|
type: Mapped[AssetType] = mapped_column(Enum(AssetType), nullable=False)
|
|
status: Mapped[AssetStatus] = mapped_column(
|
|
Enum(AssetStatus), default=AssetStatus.UPLOADING, nullable=False, index=True
|
|
)
|
|
original_filename: Mapped[str] = mapped_column(String(512), nullable=False)
|
|
content_type: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
size_bytes: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
|
sha256: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
|
|
|
# Metadata
|
|
captured_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
width: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
|
height: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
|
duration_sec: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
|
|
|
|
# Storage
|
|
storage_key_original: Mapped[str] = mapped_column(String(512), nullable=False)
|
|
storage_key_thumb: Mapped[Optional[str]] = mapped_column(String(512), nullable=True)
|
|
|
|
# Timestamps
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), nullable=False, index=True
|
|
)
|
|
|
|
|
|
class Share(Base):
|
|
"""Public share link for assets or albums."""
|
|
|
|
__tablename__ = "shares"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=generate_uuid)
|
|
owner_user_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
|
asset_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True, index=True)
|
|
album_id: Mapped[Optional[str]] = mapped_column(String(36), nullable=True, index=True)
|
|
|
|
token: Mapped[str] = mapped_column(String(64), unique=True, nullable=False, index=True)
|
|
expires_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
password_hash: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
|
|
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
)
|
|
revoked_at: Mapped[Optional[datetime]] = mapped_column(
|
|
DateTime(timezone=True), nullable=True, index=True
|
|
)
|