124 lines
4.2 KiB
Python
124 lines
4.2 KiB
Python
from datetime import datetime
|
|
from app import db
|
|
|
|
|
|
class ExtraFile(db.Model):
|
|
"""Model for extra files attached to sets (BrickLink XML, Stud.io, box art, etc)."""
|
|
|
|
__tablename__ = 'extra_files'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
set_id = db.Column(db.Integer, db.ForeignKey('sets.id', ondelete='CASCADE'), nullable=False)
|
|
|
|
# File information
|
|
file_name = db.Column(db.String(255), nullable=False)
|
|
original_filename = db.Column(db.String(255), nullable=False) # Original name before hashing
|
|
file_path = db.Column(db.String(500), nullable=False)
|
|
file_type = db.Column(db.String(50), nullable=False) # Extension
|
|
file_size = db.Column(db.Integer, nullable=False) # Size in bytes
|
|
|
|
# Metadata
|
|
description = db.Column(db.Text)
|
|
category = db.Column(db.String(50)) # 'bricklink', 'studio', 'box_art', 'document', 'photo', 'other'
|
|
|
|
# Tracking
|
|
uploaded_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
|
|
uploaded_by = db.Column(db.Integer, db.ForeignKey('users.id'))
|
|
|
|
# Relationships
|
|
lego_set = db.relationship('Set', back_populates='extra_files')
|
|
uploader = db.relationship('User', backref='uploaded_files')
|
|
|
|
def __repr__(self):
|
|
return f'<ExtraFile {self.file_name} for Set {self.set_id}>'
|
|
|
|
@property
|
|
def file_size_formatted(self):
|
|
"""Return human-readable file size."""
|
|
size = self.file_size
|
|
for unit in ['B', 'KB', 'MB', 'GB']:
|
|
if size < 1024.0:
|
|
return f"{size:.1f} {unit}"
|
|
size /= 1024.0
|
|
return f"{size:.1f} TB"
|
|
|
|
@property
|
|
def file_icon(self):
|
|
"""Return Bootstrap icon class based on file type."""
|
|
icon_map = {
|
|
# Images
|
|
'jpg': 'file-image',
|
|
'jpeg': 'file-image',
|
|
'png': 'file-image',
|
|
'gif': 'file-image',
|
|
'webp': 'file-image',
|
|
'bmp': 'file-image',
|
|
|
|
# Documents
|
|
'pdf': 'file-pdf',
|
|
'doc': 'file-word',
|
|
'docx': 'file-word',
|
|
'txt': 'file-text',
|
|
'rtf': 'file-text',
|
|
|
|
# Spreadsheets
|
|
'xls': 'file-excel',
|
|
'xlsx': 'file-excel',
|
|
'csv': 'file-spreadsheet',
|
|
|
|
# Data files
|
|
'xml': 'file-code',
|
|
'json': 'file-code',
|
|
|
|
# 3D/CAD files
|
|
'ldr': 'box-seam', # LDraw
|
|
'mpd': 'box-seam', # LDraw
|
|
'io': 'box-seam', # Stud.io
|
|
'lxf': 'box-seam', # LEGO Digital Designer
|
|
'lxfml': 'box-seam',
|
|
|
|
# Archives
|
|
'zip': 'file-zip',
|
|
'rar': 'file-zip',
|
|
'7z': 'file-zip',
|
|
'tar': 'file-zip',
|
|
'gz': 'file-zip',
|
|
|
|
# Other
|
|
'default': 'file-earmark'
|
|
}
|
|
|
|
return icon_map.get(self.file_type.lower(), icon_map['default'])
|
|
|
|
@property
|
|
def is_image(self):
|
|
"""Check if file is an image."""
|
|
image_types = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp']
|
|
return self.file_type.lower() in image_types
|
|
|
|
@property
|
|
def can_preview(self):
|
|
"""Check if file can be previewed in browser."""
|
|
preview_types = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf', 'txt']
|
|
return self.file_type.lower() in preview_types
|
|
|
|
def to_dict(self):
|
|
"""Convert to dictionary for JSON responses."""
|
|
return {
|
|
'id': self.id,
|
|
'set_id': self.set_id,
|
|
'file_name': self.file_name,
|
|
'original_filename': self.original_filename,
|
|
'file_path': self.file_path.replace('\\', '/'),
|
|
'file_type': self.file_type,
|
|
'file_size': self.file_size,
|
|
'file_size_formatted': self.file_size_formatted,
|
|
'description': self.description,
|
|
'category': self.category,
|
|
'uploaded_at': self.uploaded_at.isoformat(),
|
|
'is_image': self.is_image,
|
|
'can_preview': self.can_preview,
|
|
'file_icon': self.file_icon,
|
|
'download_url': f'/extra-files/download/{self.id}'
|
|
}
|