itcloud/backend/src/app/domain/models.py

103 lines
3.8 KiB
Python
Raw Normal View History

2025-12-30 13:35:19 +01:00
"""Domain models for the application."""
import enum
from datetime import datetime
from typing import Optional
from uuid import uuid4
2025-12-30 14:00:44 +01:00
from sqlalchemy import BigInteger, Boolean, DateTime, Enum, Float, Integer, String, Text, func
2025-12-30 13:35:19 +01:00
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 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)
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)
2025-12-30 14:00:44 +01:00
size_bytes: Mapped[int] = mapped_column(BigInteger, nullable=False)
2025-12-30 13:35:19 +01:00
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
)