kanban-app/backend/app/models/file_attachment.py

76 lines
2.8 KiB
Python
Raw Permalink Normal View History

2026-03-20 17:17:01 +00:00
import uuid
from datetime import UTC, datetime
from sqlalchemy import Index
from app import db
class FileAttachment(db.Model):
"""Polymorphic file attachment model for Cards, Comments, and other entities"""
__tablename__ = "file_attachments"
id = db.Column(db.Integer, primary_key=True)
uuid = db.Column(
db.String(36), nullable=False, unique=True, default=lambda: str(uuid.uuid4())
)
filename = db.Column(db.String(255), nullable=False)
original_name = db.Column(db.String(255), nullable=False)
file_type = db.Column(db.String(50), nullable=False) # 'image', 'pdf', 'document'
mime_type = db.Column(db.String(100), nullable=False)
file_size = db.Column(db.Integer, nullable=False)
# MinIO storage information
minio_bucket = db.Column(db.String(100), nullable=False)
minio_object_name = db.Column(db.String(255), nullable=False, unique=True)
# Thumbnail information (optional, for images)
thumbnail_minio_object_name = db.Column(db.String(255))
thumbnail_minio_bucket = db.Column(db.String(100))
# Polymorphic relationship - can attach to different entity types
attachable_type = db.Column(
db.String(50), nullable=False
) # 'Card', 'Comment', 'Epic'
attachable_id = db.Column(db.Integer, nullable=False) # ID of the attached entity
# Upload metadata
uploaded_by = db.Column(
db.Integer, db.ForeignKey("users.id", ondelete="CASCADE"), nullable=False
)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(UTC))
# Relationships
uploader = db.relationship("User", backref="uploaded_files")
# Indexes for efficient queries
__table_args__ = (
Index("ix_file_attachments_attachable", "attachable_type", "attachable_id"),
Index("ix_file_attachments_user", "uploaded_by"),
Index("ix_file_attachments_uuid", "uuid"),
)
def to_dict(self):
"""Convert file attachment to dictionary"""
return {
"id": self.id,
"uuid": self.uuid,
"filename": self.filename,
"original_name": self.original_name,
"file_type": self.file_type,
"mime_type": self.mime_type,
"file_size": self.file_size,
"minio_bucket": self.minio_bucket,
"minio_object_name": self.minio_object_name,
"thumbnail_minio_object_name": self.thumbnail_minio_object_name,
"thumbnail_minio_bucket": self.thumbnail_minio_bucket,
"attachable_type": self.attachable_type,
"attachable_id": self.attachable_id,
"uploaded_by": self.uploaded_by,
"created_at": self.created_at.isoformat() if self.created_at else None,
}
def __repr__(self):
return f"<FileAttachment {self.original_name} ({self.file_type})>"