Files
serv_benchmark/backend/app/utils/file_organizer.py
2026-01-11 23:41:30 +01:00

158 lines
4.1 KiB
Python

"""
File Organizer - Organize uploads by hostname
"""
import os
import re
from pathlib import Path
from typing import Tuple
def sanitize_hostname(hostname: str) -> str:
"""
Sanitize hostname for use as directory name
Args:
hostname: The hostname to sanitize
Returns:
Sanitized hostname safe for use as directory name
"""
# Remove invalid characters
sanitized = re.sub(r'[^\w\-.]', '_', hostname)
# Remove leading/trailing dots and underscores
sanitized = sanitized.strip('._')
# Replace multiple underscores with single
sanitized = re.sub(r'_+', '_', sanitized)
# Limit length
sanitized = sanitized[:100]
# Default if empty
return sanitized if sanitized else 'unknown'
def get_device_upload_paths(base_upload_dir: str, hostname: str) -> Tuple[str, str]:
"""
Get organized upload paths for a device
Args:
base_upload_dir: Base upload directory (e.g., "./uploads")
hostname: Device hostname
Returns:
Tuple of (images_path, files_path)
"""
sanitized_hostname = sanitize_hostname(hostname)
images_path = os.path.join(base_upload_dir, sanitized_hostname, "images")
files_path = os.path.join(base_upload_dir, sanitized_hostname, "files")
return images_path, files_path
def ensure_device_directories(base_upload_dir: str, hostname: str) -> Tuple[str, str]:
"""
Ensure device upload directories exist
Args:
base_upload_dir: Base upload directory
hostname: Device hostname
Returns:
Tuple of (images_path, files_path)
"""
images_path, files_path = get_device_upload_paths(base_upload_dir, hostname)
# Create directories if they don't exist
Path(images_path).mkdir(parents=True, exist_ok=True)
Path(files_path).mkdir(parents=True, exist_ok=True)
return images_path, files_path
def get_upload_path(base_upload_dir: str, hostname: str, is_image: bool, filename: str) -> str:
"""
Get the full upload path for a file
Args:
base_upload_dir: Base upload directory
hostname: Device hostname
is_image: True if file is an image, False for documents
filename: The filename to store
Returns:
Full path where file should be stored
"""
images_path, files_path = ensure_device_directories(base_upload_dir, hostname)
target_dir = images_path if is_image else files_path
return os.path.join(target_dir, filename)
def is_image_file(filename: str, mime_type: str = None) -> bool:
"""
Check if a file is an image based on extension and/or mime type
Args:
filename: The filename
mime_type: Optional MIME type
Returns:
True if file is an image
"""
# Check extension
image_extensions = {'.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.svg'}
ext = os.path.splitext(filename)[1].lower()
if ext in image_extensions:
return True
# Check MIME type if provided
if mime_type and mime_type.startswith('image/'):
return True
return False
def migrate_existing_files(base_upload_dir: str, hostname: str, file_list: list) -> dict:
"""
Migrate existing files to new organized structure
Args:
base_upload_dir: Base upload directory
hostname: Device hostname
file_list: List of tuples (filename, is_image)
Returns:
Dictionary mapping old paths to new paths
"""
images_path, files_path = ensure_device_directories(base_upload_dir, hostname)
migrations = {}
for filename, is_image in file_list:
old_path = os.path.join(base_upload_dir, filename)
if is_image:
new_path = os.path.join(images_path, filename)
else:
new_path = os.path.join(files_path, filename)
migrations[old_path] = new_path
return migrations
def get_relative_path(full_path: str, base_upload_dir: str) -> str:
"""
Get relative path from base upload directory
Args:
full_path: Full file path
base_upload_dir: Base upload directory
Returns:
Relative path from base directory
"""
return os.path.relpath(full_path, base_upload_dir)