import os import uuid from werkzeug.utils import secure_filename from PIL import Image def allowed_file(filename, allowed_extensions): """Check if file has allowed extension""" return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in allowed_extensions def save_image(file, upload_folder, allowed_extensions): """ Save uploaded image file with validation Args: file: FileStorage object from Flask request upload_folder: Directory to save images allowed_extensions: Set of allowed file extensions Returns: str: Relative path to saved image, or None if validation fails Raises: ValueError: If file validation fails """ if not file or file.filename == '': raise ValueError("No file provided") if not allowed_file(file.filename, allowed_extensions): raise ValueError(f"File type not allowed. Allowed types: {', '.join(allowed_extensions)}") # Verify it's actually an image try: img = Image.open(file.stream) img.verify() file.stream.seek(0) # Reset stream after verification except Exception as e: raise ValueError(f"Invalid image file: {str(e)}") # Generate unique filename original_filename = secure_filename(file.filename) extension = original_filename.rsplit('.', 1)[1].lower() unique_filename = f"{uuid.uuid4()}.{extension}" # Ensure upload folder exists os.makedirs(upload_folder, exist_ok=True) # Save file filepath = os.path.join(upload_folder, unique_filename) file.save(filepath) # Return relative path (for storing in database) return f"/static/images/{unique_filename}" def delete_image(image_path, base_folder): """ Delete an image file Args: image_path: Relative path to image (e.g., /static/images/abc123.jpg) base_folder: Base folder for the application """ if not image_path: return # Remove leading slash and construct full path relative_path = image_path.lstrip('/') full_path = os.path.join(base_folder, relative_path) try: if os.path.exists(full_path): os.remove(full_path) except Exception as e: # Log error but don't fail the operation print(f"Error deleting image {full_path}: {str(e)}")