Files
memelord-kkurval/memelord-kkurval.yaml
2026-02-10 14:33:12 +02:00

837 lines
34 KiB
YAML

# 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")