# kubectl create namespace memelord-kkurval # kubectl diff -n memelord-kkurval -f memelord-kkurval.yaml # kubectl apply -n memelord-kkurval -f memelord-kkurval.yaml --- apiVersion: apps/v1 kind: Deployment # Stateless rakenduste jaoks. Tõmbab enne uue üles kui vana maha läheb. No client impact metadata: name: memelord-kkurval-app spec: replicas: 1 selector: matchLabels: app: memelord-kkurval-app template: metadata: labels: app: memelord-kkurval-app spec: # volumes: # - name: settings # projected: # sources: # - configMap: # name: settings containers: - name: memelord image: ghcr.io/l4rm4nd/memelord:latest imagePullPolicy: Always volumeMounts: - name: settings mountPath: /opt/app/myproject/settings.py readOnly: true subPath: settings.py ports: - name: http containerPort: 8000 env: - name: DOMAIN value: "memelord-kkurval.ee-lte-1.codemowers.io" - name: DB_ENGINE value: postgres - name: POSTGRES_HOST value: memelord-kkurval-database-rw - name: POSTGRES_PORT value: '5432' - name: POSTGRES_DB value: memelord-kkurval - name: POSTGRES_USER valueFrom: secretKeyRef: name: memelord-kkurval-database key: username - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: memelord-kkurval-database key: password - name: REDIS_HOST value: memelord-kkurval-redis - name: REDIS_PORT value: '6379' - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: memelord-kkurval-redis key: redis-password - name: STORAGE_BACKEND value: s3 # S3/MinIO Storage Configuration - name: STORAGE_BACKEND value: "s3" - name: AWS_ACCESS_KEY_ID valueFrom: secretKeyRef: name: memelord-kkurval-bucket key: accessKey - name: AWS_SECRET_ACCESS_KEY valueFrom: secretKeyRef: name: memelord-kkurval-bucket key: secretKey - name: AWS_S3_CUSTOM_DOMAIN value: minio.ee-lte-1.codemowers.io - name: AWS_STORAGE_BUCKET_NAME value: memelord-kkurval - name: AWS_S3_ENDPOINT_URL value: https://minio.ee-lte-1.codemowers.io/ - name: AWS_S3_REGION_NAME value: ee-lte-1 - name: DEBUG value: "True" - name: SECURE_COOKIES value: "True" - name: OIDC_ENABLED value: "True" - name: OIDC_RP_SIGN_ALGO valueFrom: secretKeyRef: name: oidc-client-memelord-kkurval-owner-secrets key: OIDC_ID_TOKEN_SIGNED_RESPONSE_ALG - name: OIDC_OP_JWKS_ENDPOINT value: https://auth.ee-lte-1.codemowers.io/jwks - name: OIDC_RP_CLIENT_ID valueFrom: secretKeyRef: name: oidc-client-memelord-kkurval-owner-secrets key: OIDC_CLIENT_ID - name: OIDC_RP_CLIENT_SECRET valueFrom: secretKeyRef: name: oidc-client-memelord-kkurval-owner-secrets key: OIDC_CLIENT_SECRET - name: OIDC_OP_AUTHORIZATION_ENDPOINT valueFrom: secretKeyRef: name: oidc-client-memelord-kkurval-owner-secrets key: OIDC_IDP_AUTH_URI - name: OIDC_OP_TOKEN_ENDPOINT valueFrom: secretKeyRef: name: oidc-client-memelord-kkurval-owner-secrets key: OIDC_IDP_TOKEN_URI - name: OIDC_OP_USER_ENDPOINT valueFrom: secretKeyRef: name: oidc-client-memelord-kkurval-owner-secrets key: OIDC_IDP_USERINFO_URI # --- # apiVersion: v1 # kind: ConfigMap # metadata: # name: settings # data: # settings.py: | # """ # Django settings for myproject project. # Generated by 'django-admin startproject' using Django 3.2.16. # For more information on this file, see # https://docs.djangoproject.com/en/3.2/topics/settings/ # For the full list of settings and their values, see # https://docs.djangoproject.com/en/3.2/ref/settings/ # """ # from pathlib import Path # from dotenv import load_dotenv # import os # import pytz # import secrets # from django.utils.html import escape # from django.utils.translation import gettext_lazy as _ # from csp.constants import NONE, SELF, UNSAFE_INLINE, UNSAFE_EVAL # # Load environment variables from .env file # load_dotenv() # # Build paths inside the project like this: BASE_DIR / 'subdir'. # BASE_DIR = Path(__file__).resolve().parent.parent # # get debug modus from env # DEBUG = os.environ.get('DEBUG', 'False').lower() in ['true'] # # get container version from env # VERSION = escape(os.environ.get("VERSION", '')) # # Enable/disable public meme feed feature (must be after import os) # ENABLE_PUBLIC_FEED = os.environ.get('ENABLE_PUBLIC_FEED', 'False').lower() in ['true', '1', 'yes'] # # auto-generate a secure secret key or use from env variable # SECRET_KEY = os.environ.get("SECRET_KEY", secrets.token_urlsafe(32)) # # define allowed hosts and trusted domains via env variables # DOMAIN = "" # ALLOWED_HOSTS = ["127.0.0.1"] # CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:8000"] # DOMAIN = str(os.environ.get("DOMAIN", "localhost")) # TRUSTED_PORT = str(os.environ.get("PORT", "8000")) # if DOMAIN: # domains = DOMAIN.split(',') # for domain in domains: # domain = domain.strip().rstrip('/').replace('http://', '').replace('https://', '') # if domain: # ALLOWED_HOSTS.append(domain) # TRUSTED_USER_DOMAIN_HTTP = f"http://{domain}:{TRUSTED_PORT}" # TRUSTED_USER_DOMAIN_HTTP_80_DEFAULT = f"http://{domain}" # TRUSTED_USER_DOMAIN_HTTPS = f"https://{domain}:{TRUSTED_PORT}" # TRUSTED_USER_DOMAIN_HTTPS_443_DEFAULT = f"https://{domain}" # CSRF_TRUSTED_ORIGINS.extend([TRUSTED_USER_DOMAIN_HTTP, TRUSTED_USER_DOMAIN_HTTPS, TRUSTED_USER_DOMAIN_HTTP_80_DEFAULT, TRUSTED_USER_DOMAIN_HTTPS_443_DEFAULT]) # #Session Management # CSRF_COOKIE_HTTPONLY = True # SESSION_EXPIRE_AT_BROWSER_CLOSE = os.environ.get('SESSION_EXPIRE_AT_BROWSER_CLOSE', 'True').lower() in ['true'] # SESSION_COOKIE_AGE = int(os.environ.get('SESSION_COOKIE_AGE', '30')) * 60 # SESSION_COOKIE_NAME = 'Session' # SESSION_COOKIE_SAMESITE = 'Lax' # # ============================================================================= # # REDIS CACHE CONFIGURATION (for sessions and general caching) # # ============================================================================= # # If REDIS_HOST is not set, sessions will use database (backward compatible) # REDIS_HOST = os.environ.get("REDIS_HOST", "") # REDIS_PORT = os.environ.get("REDIS_PORT", "6379") # REDIS_DB = os.environ.get("REDIS_DB", "0") # REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD", "") # if REDIS_HOST: # # Redis is available - use it for caching and sessions # CACHES = { # "default": { # "BACKEND": "django_redis.cache.RedisCache", # "LOCATION": f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}", # "OPTIONS": { # "CLIENT_CLASS": "django_redis.client.DefaultClient", # "PASSWORD": REDIS_PASSWORD if REDIS_PASSWORD else None, # "SOCKET_CONNECT_TIMEOUT": 5, # seconds # "SOCKET_TIMEOUT": 5, # seconds # "RETRY_ON_TIMEOUT": True, # "CONNECTION_POOL_KWARGS": { # "max_connections": 50, # "retry_on_timeout": True, # }, # "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor", # "IGNORE_EXCEPTIONS": True, # Don't crash if Redis is down # }, # "KEY_PREFIX": "memelord", # "TIMEOUT": 300, # 5 minutes default # } # } # # Use Redis for session storage (cloud-native) # SESSION_ENGINE = "django.contrib.sessions.backends.cache" # SESSION_CACHE_ALIAS = "default" # else: # # Redis not configured - use database sessions (backward compatible) # SESSION_ENGINE = "django.contrib.sessions.backends.db" # # No CACHES configuration - Django will use local memory cache # SECURE_COOKIES = os.environ.get('SECURE_COOKIES', 'False').lower() in ['true'] # if SECURE_COOKIES: # # transmit cookies over encrypted https only # SESSION_COOKIE_SECURE = True # CSRF_COOKIE_SECURE = True # # also set hsts response header # SECURE_HSTS_SECONDS = "31536000" # SECURE_HSTS_PRELOAD = True # SECURE_HSTS_INCLUDE_SUBDOMAINS = True # else: # # transmit cookies over unencrypted http # SESSION_COOKIE_SECURE = False # CSRF_COOKIE_SECURE = False # # http security response headers # SECURE_BROWSER_XSS_FILTER = True # SECURE_CONTENT_TYPE_NOSNIFF = True # X_FRAME_OPTIONS = 'DENY' # REFERRER_POLICY = 'same-origin' # # Load from environment, default to "'self'" # raw_frame_ancestors = os.environ.get("CSP_FRAME_ANCESTORS", "'none'") # # Split by comma, strip spaces, and keep properly quoted entries # FRAME_ANCESTORS = [item.strip() for item in raw_frame_ancestors.split(',') if item.strip()] # # Build CSP img-src list dynamically based on storage backend # STORAGE_BACKEND = os.environ.get('STORAGE_BACKEND', 'local').lower() # IMG_SRC_LIST = ["'self'", "data:", "blob:", "https://img.logo.dev"] # # Add S3 domains to CSP if using S3 storage # if STORAGE_BACKEND == 's3': # AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME') # AWS_S3_CUSTOM_DOMAIN = os.environ.get('AWS_S3_CUSTOM_DOMAIN') # AWS_S3_REGION_NAME = os.environ.get('AWS_S3_REGION_NAME', 'us-east-1') # AWS_S3_ENDPOINT_URL = os.environ.get('AWS_S3_ENDPOINT_URL') # AWS_S3_USE_ACCELERATE_ENDPOINT = os.environ.get('AWS_S3_USE_ACCELERATE_ENDPOINT', 'False').lower() in ['true'] # # Always add custom domain if specified (CDN like CloudFront) # if AWS_S3_CUSTOM_DOMAIN: # IMG_SRC_LIST.append(f"https://{AWS_S3_CUSTOM_DOMAIN}") # # Detect S3 provider based on endpoint URL # if AWS_S3_ENDPOINT_URL: # # S3-compatible service detected # from urllib.parse import urlparse # parsed_url = urlparse(AWS_S3_ENDPOINT_URL) # endpoint_domain = parsed_url.netloc # endpoint_scheme = parsed_url.scheme or 'https' # # Add the endpoint domain # IMG_SRC_LIST.append(f"{endpoint_scheme}://{endpoint_domain}") # # Add bucket-based subdomain format if applicable # if endpoint_domain and AWS_STORAGE_BUCKET_NAME: # IMG_SRC_LIST.append(f"{endpoint_scheme}://{AWS_STORAGE_BUCKET_NAME}.{endpoint_domain}") # # Provider-specific URL patterns # endpoint_lower = endpoint_domain.lower() if endpoint_domain else "" # # DigitalOcean Spaces: also add CDN domain # if 'digitaloceanspaces.com' in endpoint_lower: # # DigitalOcean Spaces CDN format: bucket-name.region.cdn.digitaloceanspaces.com # if AWS_STORAGE_BUCKET_NAME and AWS_S3_REGION_NAME: # IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.{AWS_S3_REGION_NAME}.cdn.digitaloceanspaces.com") # # Cloudflare R2: also add public bucket URL format # elif 'r2.cloudflarestorage.com' in endpoint_lower: # # Cloudflare R2 can use custom domains via public.r2.dev # # Format: https://bucket-name.account-id.r2.dev (if public) # # This is typically set via AWS_S3_CUSTOM_DOMAIN, but we note it here # pass # # Wasabi: supports path-style and virtual-hosted-style # elif 'wasabisys.com' in endpoint_lower: # # Already covered by endpoint_domain and bucket subdomain # pass # # Linode Object Storage: supports path-style and virtual-hosted-style # elif 'linodeobjects.com' in endpoint_lower: # # Already covered by endpoint_domain and bucket subdomain # pass # # Backblaze B2: supports path-style and virtual-hosted-style # elif 'backblazeb2.com' in endpoint_lower: # # Already covered by endpoint_domain and bucket subdomain # pass # # MinIO: custom deployment, already covered # # Other S3-compatible services: already covered # else: # # No endpoint URL = Standard AWS S3 # if AWS_STORAGE_BUCKET_NAME: # # Add AWS S3 virtual-hosted-style URLs # IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com") # IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.s3.{AWS_S3_REGION_NAME}.amazonaws.com") # # Add path-style URL format (legacy but still supported) # IMG_SRC_LIST.append("https://s3.amazonaws.com") # IMG_SRC_LIST.append(f"https://s3.{AWS_S3_REGION_NAME}.amazonaws.com") # # Add dual-stack endpoints (IPv6 support) # IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.s3.dualstack.{AWS_S3_REGION_NAME}.amazonaws.com") # # Add S3 Transfer Acceleration endpoint if enabled # if AWS_S3_USE_ACCELERATE_ENDPOINT: # IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.s3-accelerate.amazonaws.com") # IMG_SRC_LIST.append(f"https://{AWS_STORAGE_BUCKET_NAME}.s3-accelerate.dualstack.amazonaws.com") # # Add Azure domains to CSP if using Azure storage # elif STORAGE_BACKEND == 'azure': # AZURE_ACCOUNT_NAME = os.environ.get('AZURE_ACCOUNT_NAME') # AZURE_CUSTOM_DOMAIN = os.environ.get('AZURE_CUSTOM_DOMAIN') # if AZURE_CUSTOM_DOMAIN: # IMG_SRC_LIST.append(f"https://{AZURE_CUSTOM_DOMAIN}") # if AZURE_ACCOUNT_NAME: # IMG_SRC_LIST.append(f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net") # # Add GCS domains to CSP if using GCS storage # elif STORAGE_BACKEND == 'gcs': # GS_BUCKET_NAME = os.environ.get('GS_BUCKET_NAME') # GS_CUSTOM_ENDPOINT = os.environ.get('GS_CUSTOM_ENDPOINT') # if GS_CUSTOM_ENDPOINT: # IMG_SRC_LIST.append(GS_CUSTOM_ENDPOINT) # if GS_BUCKET_NAME: # # GCS can use multiple URL formats # IMG_SRC_LIST.append("https://storage.googleapis.com") # IMG_SRC_LIST.append("https://storage.cloud.google.com") # IMG_SRC_LIST.append(f"https://{GS_BUCKET_NAME}.storage.googleapis.com") # # SFTP/Dropbox typically serve through Django (using 'self' origin) # elif STORAGE_BACKEND == 'sftp': # # SFTP files are retrieved by Django and served through Django views # # Optional: If you have nginx serving the same SFTP directory via HTTP # SFTP_CUSTOM_DOMAIN = os.environ.get('SFTP_CUSTOM_DOMAIN') # if SFTP_CUSTOM_DOMAIN: # IMG_SRC_LIST.append(f"https://{SFTP_CUSTOM_DOMAIN}") # elif STORAGE_BACKEND == 'dropbox': # # Dropbox files are retrieved by Django and served through Django views # # No additional CSP configuration needed # pass # CSP_IMG_SRC_EXTRA = os.environ.get('CSP_IMG_SRC_EXTRA', '') # if CSP_IMG_SRC_EXTRA: # extra_domains = [domain.strip() for domain in CSP_IMG_SRC_EXTRA.split(',') if domain.strip()] # IMG_SRC_LIST.extend(extra_domains) # CONTENT_SECURITY_POLICY = { # "DIRECTIVES": { # "default-src": ["'self'"], # "style-src": ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com", "https://cdn.jsdelivr.net"], # "script-src": ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://cdn.jsdelivr.net"], # "font-src": ["'self'", "https://fonts.googleapis.com", "https://fonts.gstatic.com"], # "img-src": IMG_SRC_LIST, # "object-src": ["'none'"], # "connect-src": ["'self'"], # "frame-ancestors": FRAME_ANCESTORS, # }, # } # # Application definition # INSTALLED_APPS = [ # 'myapp', # 'django_celery_beat', # 'django.contrib.admin', # 'django.contrib.auth', # 'django.contrib.contenttypes', # 'django.contrib.sessions', # 'django.contrib.messages', # 'django.contrib.staticfiles', # 'csp', # 'storages', # ] # MIDDLEWARE = [ # 'django.middleware.security.SecurityMiddleware', # 'django.contrib.sessions.middleware.SessionMiddleware', # #'django.middleware.locale.LocaleMiddleware', # 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', # 'django.contrib.auth.middleware.AuthenticationMiddleware', # 'django.contrib.messages.middleware.MessageMiddleware', # 'django_http_referrer_policy.middleware.ReferrerPolicyMiddleware', # 'csp.middleware.CSPMiddleware', # ] # ROOT_URLCONF = 'myproject.urls' # TEMPLATES = [ # { # 'BACKEND': 'django.template.backends.django.DjangoTemplates', # 'DIRS': [os.path.join(BASE_DIR, 'myapp/templates/registration')], # 'APP_DIRS': True, # 'OPTIONS': { # 'context_processors': [ # 'django.template.context_processors.debug', # 'django.template.context_processors.request', # 'django.contrib.auth.context_processors.auth', # 'django.contrib.messages.context_processors.messages', # ], # }, # }, # ] # # Database # # https://docs.djangoproject.com/en/3.2/ref/settings/#databases # DB_ENGINE = os.environ.get("DB_ENGINE", "sqlite3") # if DB_ENGINE == "sqlite3": # DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'database', 'db.sqlite3'), # } # } # elif DB_ENGINE == "postgres": # DB_HOST = os.environ.get("POSTGRES_HOST", "db") # DB_PORT = os.environ.get("POSTGRES_PORT", "5432") # DB_USER = os.environ.get("POSTGRES_USER", "memelord") # DB_PASSWORD = os.environ.get("POSTGRES_PASSWORD", "memelord") # DB_NAME = os.environ.get("POSTGRES_DB", "memelord") # DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.postgresql', # 'NAME': DB_NAME, # 'HOST': DB_HOST, # 'PORT': DB_PORT, # 'USER': DB_USER, # 'PASSWORD': DB_PASSWORD, # } # } # # Password validation # # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators # AUTH_PASSWORD_VALIDATORS = [ # { # 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', # }, # { # 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', # }, # { # 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', # }, # { # 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', # }, # ] # # Internationalization # # https://docs.djangoproject.com/en/3.2/topics/i18n/ # LANGUAGE_CODE = 'en-us' # TIME_ZONE = os.environ.get('TZ', 'Europe/Berlin') # USE_I18N = True # USE_L10N = True # USE_TZ = True # LANGUAGES = [ # ('en', _('English')), # ('de', _('German')), # ('fr', _('French')), # ('it', _('Italian')), # ] # LOCALE_PATHS = [ # os.path.join(BASE_DIR, 'locale') # ] # # Celery configuration # # http://docs.celeryproject.org/en/latest/configuration.html # LOGS_DIR = os.path.join(BASE_DIR, 'logs') # # ============================================================================= # # LOGGING CONFIGURATION # # ============================================================================= # LOGGING = { # 'version': 1, # 'disable_existing_loggers': False, # 'formatters': { # 'verbose': { # 'format': '{levelname} {asctime} {module} {message}', # 'style': '{', # }, # 'simple': { # 'format': '{levelname} {message}', # 'style': '{', # }, # }, # 'handlers': { # 'console': { # 'class': 'logging.StreamHandler', # 'formatter': 'verbose', # }, # 'file': { # 'class': 'logging.handlers.RotatingFileHandler', # 'filename': os.path.join(LOGS_DIR, 'django.log'), # 'maxBytes': 1024 * 1024 * 15, # 15MB # 'backupCount': 10, # 'formatter': 'verbose', # }, # }, # 'loggers': { # 'django': { # 'handlers': ['console', 'file'], # 'level': os.environ.get('DJANGO_LOG_LEVEL', 'INFO'), # 'propagate': False, # }, # 'myapp': { # 'handlers': ['console', 'file'], # 'level': os.environ.get('DJANGO_LOG_LEVEL', 'INFO'), # 'propagate': False, # }, # 'storages': { # 'handlers': ['console', 'file'], # 'level': 'DEBUG' if DEBUG else 'INFO', # 'propagate': False, # }, # 'boto3': { # 'handlers': ['console', 'file'], # 'level': 'DEBUG' if DEBUG else 'INFO', # 'propagate': False, # }, # 'botocore': { # 'handlers': ['console', 'file'], # 'level': 'DEBUG' if DEBUG else 'INFO', # 'propagate': False, # }, # }, # 'root': { # 'handlers': ['console', 'file'], # 'level': 'INFO', # }, # } # # Create logs directory if it doesn't exist # os.makedirs(LOGS_DIR, exist_ok=True) # STATIC_URL = '/static/' # STATIC_ROOT = os.path.join(BASE_DIR, 'myapp', 'static') # DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' # LOGIN_URL = '/accounts/login/' # LOGIN_REDIRECT_URL = '/' # LOGOUT_REDIRECT_URL = '/post-logout/' # ALLOW_LOGOUT_GET_METHOD = True # WSGI_APPLICATION = 'myproject.wsgi.application' # # check if oidc is enabled # OIDC_ENABLED = os.environ.get('OIDC_ENABLED', 'False').lower() in ['true'] # OIDC_AUTOLOGIN = os.environ.get('OIDC_AUTOLOGIN', 'False').lower() in ['true'] # # Max file upload size in MB (default: 10MB) # # Can be configured via MAX_UPLOAD_SIZE_MB environment variable # MAX_UPLOAD_SIZE_MB = int(os.environ.get('MAX_UPLOAD_SIZE_MB', '10')) * 1024 * 1024 # # ============================================================================= # # STORAGE BACKEND CONFIGURATION # # ============================================================================= # # IMPORTANT: This must be set BEFORE MEDIA_URL and MEDIA_ROOT # # Configure storage backend via STORAGE_BACKEND environment variable # # Supported backends: local, s3, azure, gcs, sftp, dropbox # # Default: local (filesystem storage) # STORAGE_BACKEND = os.environ.get('STORAGE_BACKEND', 'local').lower() # # Django 5.0+ uses STORAGES instead of DEFAULT_FILE_STORAGE # # Set both for compatibility # if STORAGE_BACKEND == 's3': # # Amazon S3 / Compatible S3 Storage (MinIO, DigitalOcean Spaces, etc.) # AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID') # AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY') # AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME') # AWS_S3_REGION_NAME = os.environ.get('AWS_S3_REGION_NAME', 'us-east-1') # AWS_S3_CUSTOM_DOMAIN = os.environ.get('AWS_S3_CUSTOM_DOMAIN') # AWS_S3_ENDPOINT_URL = os.environ.get('AWS_S3_ENDPOINT_URL') # Only set for S3-compatible services (MinIO, etc.) # AWS_DEFAULT_ACL = os.environ.get('AWS_DEFAULT_ACL', 'private') # AWS_S3_OBJECT_PARAMETERS = { # 'CacheControl': 'max-age=86400', # } # AWS_QUERYSTRING_AUTH = os.environ.get('AWS_QUERYSTRING_AUTH', 'True').lower() in ['true'] # AWS_S3_FILE_OVERWRITE = os.environ.get('AWS_S3_FILE_OVERWRITE', 'False').lower() in ['true'] # AWS_LOCATION = os.environ.get('AWS_LOCATION', 'media') # # Use signature version 4 (required for all regions) # AWS_S3_SIGNATURE_VERSION = 's3v4' # # Use virtual-hosted-style URLs (bucket-name.s3.region.amazonaws.com) # # This is the default and recommended format # AWS_S3_ADDRESSING_STYLE = 'virtual' # # Django 5.0+ STORAGES configuration # STORAGES = { # "default": { # "BACKEND": "storages.backends.s3boto3.S3Boto3Storage", # }, # "staticfiles": { # "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", # }, # } # # Legacy setting for older Django versions # DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' # # Update MEDIA_URL # if AWS_S3_CUSTOM_DOMAIN: # MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{AWS_LOCATION}/' # elif AWS_STORAGE_BUCKET_NAME: # # Use region-specific virtual-hosted-style URL # if AWS_S3_REGION_NAME == 'us-east-1': # MEDIA_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/{AWS_LOCATION}/' # else: # MEDIA_URL = f'https://{AWS_STORAGE_BUCKET_NAME}.s3.{AWS_S3_REGION_NAME}.amazonaws.com/{AWS_LOCATION}/' # else: # MEDIA_URL = "/media/" # MEDIA_ROOT = BASE_DIR / "media" # elif STORAGE_BACKEND == 'azure': # # Microsoft Azure Blob Storage # AZURE_ACCOUNT_NAME = os.environ.get('AZURE_ACCOUNT_NAME') # AZURE_ACCOUNT_KEY = os.environ.get('AZURE_ACCOUNT_KEY') # AZURE_CONTAINER = os.environ.get('AZURE_CONTAINER', 'media') # AZURE_SSL = os.environ.get('AZURE_SSL', 'True').lower() in ['true'] # AZURE_UPLOAD_MAX_CONN = int(os.environ.get('AZURE_UPLOAD_MAX_CONN', '2')) # AZURE_CONNECTION_TIMEOUT_SECS = int(os.environ.get('AZURE_CONNECTION_TIMEOUT_SECS', '20')) # AZURE_BLOB_MAX_MEMORY_SIZE = os.environ.get('AZURE_BLOB_MAX_MEMORY_SIZE', '2MB') # AZURE_URL_EXPIRATION_SECS = int(os.environ.get('AZURE_URL_EXPIRATION_SECS', '3600')) # AZURE_OVERWRITE_FILES = os.environ.get('AZURE_OVERWRITE_FILES', 'False').lower() in ['true'] # AZURE_LOCATION = os.environ.get('AZURE_LOCATION', '') # AZURE_CUSTOM_DOMAIN = os.environ.get('AZURE_CUSTOM_DOMAIN') # STORAGES = { # "default": { # "BACKEND": "storages.backends.azure_storage.AzureStorage", # }, # "staticfiles": { # "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", # }, # } # DEFAULT_FILE_STORAGE = 'storages.backends.azure_storage.AzureStorage' # if AZURE_CUSTOM_DOMAIN: # MEDIA_URL = f'https://{AZURE_CUSTOM_DOMAIN}/{AZURE_LOCATION}' # elif AZURE_ACCOUNT_NAME: # MEDIA_URL = f'https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/{AZURE_CONTAINER}/{AZURE_LOCATION}' # else: # MEDIA_URL = "/media/" # MEDIA_ROOT = BASE_DIR / "media" # elif STORAGE_BACKEND == 'gcs': # # Google Cloud Storage # GS_BUCKET_NAME = os.environ.get('GS_BUCKET_NAME') # GS_PROJECT_ID = os.environ.get('GS_PROJECT_ID') # GS_CREDENTIALS = os.environ.get('GS_CREDENTIALS') # GS_DEFAULT_ACL = os.environ.get('GS_DEFAULT_ACL', 'private') # GS_FILE_OVERWRITE = os.environ.get('GS_FILE_OVERWRITE', 'False').lower() in ['true'] # GS_LOCATION = os.environ.get('GS_LOCATION', 'media') # GS_CUSTOM_ENDPOINT = os.environ.get('GS_CUSTOM_ENDPOINT') # GS_QUERYSTRING_AUTH = os.environ.get('GS_QUERYSTRING_AUTH', 'True').lower() in ['true'] # STORAGES = { # "default": { # "BACKEND": "storages.backends.gcloud.GoogleCloudStorage", # }, # "staticfiles": { # "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", # }, # } # DEFAULT_FILE_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage' # if GS_CUSTOM_ENDPOINT: # MEDIA_URL = f'{GS_CUSTOM_ENDPOINT}/{GS_LOCATION}/' # elif GS_BUCKET_NAME: # MEDIA_URL = f'https://storage.googleapis.com/{GS_BUCKET_NAME}/{GS_LOCATION}/' # else: # MEDIA_URL = "/media/" # MEDIA_ROOT = BASE_DIR / "media" # elif STORAGE_BACKEND == 'sftp': # # SFTP Storage # SFTP_STORAGE_HOST = os.environ.get('SFTP_STORAGE_HOST') # SFTP_STORAGE_ROOT = os.environ.get('SFTP_STORAGE_ROOT', '/media/') # SFTP_STORAGE_PARAMS = { # 'port': int(os.environ.get('SFTP_STORAGE_PORT', '22')), # 'username': os.environ.get('SFTP_STORAGE_USERNAME'), # 'password': os.environ.get('SFTP_STORAGE_PASSWORD'), # 'pkey': os.environ.get('SFTP_STORAGE_PRIVATE_KEY'), # } # SFTP_STORAGE_INTERACTIVE = os.environ.get('SFTP_STORAGE_INTERACTIVE', 'False').lower() in ['true'] # SFTP_STORAGE_FILE_MODE = os.environ.get('SFTP_STORAGE_FILE_MODE') # SFTP_STORAGE_DIR_MODE = os.environ.get('SFTP_STORAGE_DIR_MODE') # SFTP_STORAGE_UID = os.environ.get('SFTP_STORAGE_UID') # SFTP_STORAGE_GID = os.environ.get('SFTP_STORAGE_GID') # SFTP_KNOWN_HOST_FILE = os.environ.get('SFTP_KNOWN_HOST_FILE') # STORAGES = { # "default": { # "BACKEND": "storages.backends.sftpstorage.SFTPStorage", # }, # "staticfiles": { # "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", # }, # } # DEFAULT_FILE_STORAGE = 'storages.backends.sftpstorage.SFTPStorage' # MEDIA_URL = "/media/" # MEDIA_ROOT = BASE_DIR / "media" # elif STORAGE_BACKEND == 'dropbox': # # Dropbox Storage # DROPBOX_OAUTH2_TOKEN = os.environ.get('DROPBOX_OAUTH2_TOKEN') # DROPBOX_ROOT_PATH = os.environ.get('DROPBOX_ROOT_PATH', '/media') # DROPBOX_TIMEOUT = int(os.environ.get('DROPBOX_TIMEOUT', '100')) # DROPBOX_WRITE_MODE = os.environ.get('DROPBOX_WRITE_MODE', 'add') # STORAGES = { # "default": { # "BACKEND": "storages.backends.dropbox.DropBoxStorage", # }, # "staticfiles": { # "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", # }, # } # DEFAULT_FILE_STORAGE = 'storages.backends.dropbox.DropBoxStorage' # MEDIA_URL = "/media/" # MEDIA_ROOT = BASE_DIR / "media" # else: # # Local filesystem storage (default) # STORAGES = { # "default": { # "BACKEND": "django.core.files.storage.FileSystemStorage", # }, # "staticfiles": { # "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", # }, # } # DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' # MEDIA_URL = "/media/" # MEDIA_ROOT = BASE_DIR / "media" # if OIDC_ENABLED: # # get oidc config from env # OIDC_CREATE_USER = os.environ.get('OIDC_CREATE_USER', 'True').lower() in ['true'] # OIDC_RP_SIGN_ALGO = os.environ.get('OIDC_RP_SIGN_ALGO', 'HS256') # OIDC_OP_JWKS_ENDPOINT = os.environ.get('OIDC_OP_JWKS_ENDPOINT') # OIDC_RP_IDP_SIGN_KEY = os.environ.get('OIDC_RP_IDP_SIGN_KEY') # OIDC_RP_CLIENT_ID = os.environ.get('OIDC_RP_CLIENT_ID') # OIDC_RP_CLIENT_SECRET = os.environ.get('OIDC_RP_CLIENT_SECRET') # OIDC_OP_AUTHORIZATION_ENDPOINT = os.environ.get('OIDC_OP_AUTHORIZATION_ENDPOINT') # OIDC_OP_TOKEN_ENDPOINT = os.environ.get('OIDC_OP_TOKEN_ENDPOINT') # OIDC_OP_USER_ENDPOINT = os.environ.get('OIDC_OP_USER_ENDPOINT') # OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS = float(os.environ.get('OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS', 900)) # OIDC_USERNAME_ALGO = 'myapp.utils.generate_username' # # Add 'mozilla_django_oidc.middleware.SessionRefresh' to INSTALLED_APPS # INSTALLED_APPS.append('mozilla_django_oidc') # # Add 'mozilla_django_oidc' authentication backend # AUTHENTICATION_BACKENDS = ( # 'django.contrib.auth.backends.ModelBackend', # 'mozilla_django_oidc.auth.OIDCAuthenticationBackend', # ) # # Add 'mozilla_django_oidc.middleware.SessionRefresh' to MIDDLEWARE # # https://mozilla-django-oidc.readthedocs.io/en/stable/installation.html#validate-id-tokens-by-renewing-them # MIDDLEWARE.append('mozilla_django_oidc.middleware.SessionRefresh') # # Fix http callback issue in mozilla-django-oidc by forcing https; https://github.com/mozilla/mozilla-django-oidc/issues/417 # # OIDC should only be setup behind a TLS reverse proxy anyways # SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")