""" Storage configuration for thrillwiki project. This module configures static files, media files, and storage backends including WhiteNoise for static file serving. Why python-decouple? - Already used in base.py for consistency - Simpler API than django-environ - Sufficient for our configuration needs - Better separation of config from code """ from pathlib import Path from decouple import config # ============================================================================= # Base Directory # ============================================================================= # This will be set by the importing module, but we define a fallback BASE_DIR = Path(__file__).resolve().parent.parent.parent # ============================================================================= # Static Files Configuration # ============================================================================= # https://docs.djangoproject.com/en/5.0/howto/static-files/ STATIC_URL = config("STATIC_URL", default="static/") STATICFILES_DIRS = [BASE_DIR / "static"] STATIC_ROOT = BASE_DIR / "staticfiles" # ============================================================================= # WhiteNoise Configuration # ============================================================================= # https://whitenoise.readthedocs.io/ # WhiteNoise serves static files efficiently without a separate web server # Compression quality for Brotli/Gzip (1-100, higher = better but slower) WHITENOISE_COMPRESSION_QUALITY = config( "WHITENOISE_COMPRESSION_QUALITY", default=90, cast=int ) # Cache max-age for static files (1 year for immutable content) WHITENOISE_MAX_AGE = config( "WHITENOISE_MAX_AGE", default=31536000, cast=int ) # Don't fail on missing manifest entries (graceful degradation) WHITENOISE_MANIFEST_STRICT = config( "WHITENOISE_MANIFEST_STRICT", default=False, cast=bool ) # Additional MIME types WHITENOISE_MIMETYPES = { ".webp": "image/webp", ".woff2": "font/woff2", } # Skip compressing already compressed formats WHITENOISE_SKIP_COMPRESS_EXTENSIONS = [ "jpg", "jpeg", "png", "gif", "webp", # Images "zip", "gz", "tgz", "bz2", "tbz", "xz", "br", # Archives "swf", "flv", # Flash "woff", "woff2", # Fonts "mp3", "mp4", "ogg", "webm", # Media ] # ============================================================================= # Media Files Configuration # ============================================================================= # User-uploaded content MEDIA_URL = config("MEDIA_URL", default="/media/") MEDIA_ROOT = BASE_DIR.parent / "shared" / "media" # ============================================================================= # Storage Backends Configuration # ============================================================================= # Django 4.2+ storage configuration STORAGES = { # Default storage for user uploads (FileField, ImageField) "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", "OPTIONS": { "location": str(MEDIA_ROOT), }, }, # Static files storage "staticfiles": { "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", "OPTIONS": { "location": str(STATIC_ROOT), }, }, } # ============================================================================= # File Upload Security Settings # ============================================================================= # These settings help prevent denial-of-service attacks via file uploads # Maximum size (in bytes) of file to upload into memory (2.5MB) # Files larger than this are written to disk FILE_UPLOAD_MAX_MEMORY_SIZE = config( "FILE_UPLOAD_MAX_MEMORY_SIZE", default=2621440, cast=int ) # Maximum size (in bytes) of request data (10MB) # This limits the total size of POST request body DATA_UPLOAD_MAX_MEMORY_SIZE = config( "DATA_UPLOAD_MAX_MEMORY_SIZE", default=10485760, cast=int ) # Maximum number of GET/POST parameters (1000) DATA_UPLOAD_MAX_NUMBER_FIELDS = config( "DATA_UPLOAD_MAX_NUMBER_FIELDS", default=1000, cast=int ) # File upload permissions (0o644 = rw-r--r--) FILE_UPLOAD_PERMISSIONS = 0o644 # Directory permissions for uploaded files (0o755 = rwxr-xr-x) FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755