# models/database/media.py """ CORE media file model for vendor media library. This is a CORE framework model used across multiple modules. MediaFile provides vendor-uploaded media files (images, documents, videos). For product-media associations, use: from app.modules.catalog.models import ProductMedia Files are stored in vendor-specific directories: uploads/vendors/{vendor_id}/{folder}/{filename} """ from sqlalchemy import ( Boolean, Column, ForeignKey, Index, Integer, String, Text, ) from sqlalchemy.dialects.sqlite import JSON from sqlalchemy.orm import relationship from app.core.database import Base from models.database.base import TimestampMixin class MediaFile(Base, TimestampMixin): """Vendor media file record. Stores metadata about uploaded files. Actual files are stored in the filesystem at uploads/vendors/{vendor_id}/{folder}/ """ __tablename__ = "media_files" id = Column(Integer, primary_key=True, index=True) vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=False) # File identification filename = Column(String(255), nullable=False) # Stored filename (UUID-based) original_filename = Column(String(255)) # Original uploaded filename file_path = Column(String(500), nullable=False) # Relative path from uploads/ # File properties media_type = Column(String(20), nullable=False) # image, video, document mime_type = Column(String(100)) file_size = Column(Integer) # bytes # Image/video dimensions width = Column(Integer) height = Column(Integer) # Thumbnail (for images/videos) thumbnail_path = Column(String(500)) # Metadata alt_text = Column(String(500)) description = Column(Text) folder = Column(String(100), default="general") # products, general, etc. tags = Column(JSON) # List of tags for categorization extra_metadata = Column(JSON) # Additional metadata (EXIF, etc.) # Status is_optimized = Column(Boolean, default=False) optimized_size = Column(Integer) # Size after optimization # Usage tracking usage_count = Column(Integer, default=0) # How many times used # Relationships vendor = relationship("Vendor", back_populates="media_files") # ProductMedia relationship uses string reference to avoid circular import product_associations = relationship( "ProductMedia", back_populates="media", cascade="all, delete-orphan", ) __table_args__ = ( Index("idx_media_vendor_id", "vendor_id"), Index("idx_media_vendor_folder", "vendor_id", "folder"), Index("idx_media_vendor_type", "vendor_id", "media_type"), Index("idx_media_filename", "filename"), ) def __repr__(self): return ( f"" ) @property def file_url(self) -> str: """Get the public URL for this file.""" return f"/uploads/{self.file_path}" @property def thumbnail_url(self) -> str | None: """Get the thumbnail URL if available.""" if self.thumbnail_path: return f"/uploads/{self.thumbnail_path}" return None @property def is_image(self) -> bool: """Check if this is an image file.""" return self.media_type == "image" @property def is_video(self) -> bool: """Check if this is a video file.""" return self.media_type == "video" @property def is_document(self) -> bool: """Check if this is a document file.""" return self.media_type == "document" # Re-export ProductMedia from its canonical location for backwards compatibility from app.modules.catalog.models import ProductMedia # noqa: E402, F401 __all__ = ["MediaFile", "ProductMedia"]