mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 14:31:08 -05:00
refactor: Update environment variable handling in Django settings for consistency and security
This commit is contained in:
@@ -3,32 +3,32 @@ Base Django settings for thrillwiki project.
|
|||||||
Common settings shared across all environments.
|
Common settings shared across all environments.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import environ # type: ignore[import]
|
import environ
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from decouple import config
|
from decouple import config
|
||||||
|
|
||||||
|
|
||||||
# Initialize environment variables with better defaults
|
# Initialize environment variables with better defaults
|
||||||
env = environ.Env(
|
|
||||||
DEBUG=(bool, False),
|
DEBUG = config('DEBUG', default=True)
|
||||||
SECRET_KEY=(str, "django-insecure-change-this-in-production"),
|
SECRET_KEY = config('SECRET_KEY')
|
||||||
ALLOWED_HOSTS=(list, ["localhost", "127.0.0.1"]),
|
ALLOWED_HOSTS = config('ALLOWED_HOSTS')
|
||||||
DATABASE_URL=(
|
DATABASE_URL = config('DATABASE_URL')
|
||||||
str,
|
CACHE_URL = config('CACHE_URL', default="locmem://")
|
||||||
"postgis://thrillwiki_user:thrillwiki@localhost:5432/thrillwiki_test_db",
|
EMAIL_URL = config('EMAIL_URL', default="console://")
|
||||||
),
|
REDIS_URL = config('REDIS_URL', default="redis://127.0.0.1:6379/1")
|
||||||
CACHE_URL=(str, "locmem://"),
|
CORS_ALLOW_ALL_ORIGINS = config('CORS_ALLOW_ALL_ORIGINS', default=False, cast=bool)
|
||||||
EMAIL_URL=(str, "console://"),
|
CORS_ALLOWED_ORIGINS = config('CORS_ALLOWED_ORIGINS', default=[])
|
||||||
REDIS_URL=(str, "redis://127.0.0.1:6379/1"),
|
API_RATE_LIMIT_PER_MINUTE = config('API_RATE_LIMIT_PER_MINUTE', default=60)
|
||||||
CORS_ALLOW_ALL_ORIGINS=(bool, False),
|
API_RATE_LIMIT_PER_HOUR = config('API_RATE_LIMIT_PER_HOUR', default=1000)
|
||||||
CORS_ALLOWED_ORIGINS=(list, []),
|
CACHE_MIDDLEWARE_SECONDS = config('CACHE_MIDDLEWARE_SECONDS', default=300)
|
||||||
API_RATE_LIMIT_PER_MINUTE=(int, 60),
|
CACHE_MIDDLEWARE_KEY_PREFIX = config(
|
||||||
API_RATE_LIMIT_PER_HOUR=(int, 1000),
|
'CACHE_MIDDLEWARE_KEY_PREFIX', default="thrillwiki")
|
||||||
CACHE_MIDDLEWARE_SECONDS=(int, 300),
|
GDAL_LIBRARY_PATH = config(
|
||||||
CACHE_MIDDLEWARE_KEY_PREFIX=(str, "thrillwiki"),
|
'GDAL_LIBRARY_PATH', default="/opt/homebrew/lib/libgdal.dylib")
|
||||||
GDAL_LIBRARY_PATH=(str, "/opt/homebrew/lib/libgdal.dylib"),
|
GEOS_LIBRARY_PATH = config(
|
||||||
GEOS_LIBRARY_PATH=(str, "/opt/homebrew/lib/libgeos_c.dylib"),
|
'GEOS_LIBRARY_PATH', default="/opt/homebrew/lib/libgeos_c.dylib")
|
||||||
)
|
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||||
@@ -42,16 +42,14 @@ if apps_dir.exists() and str(apps_dir) not in sys.path:
|
|||||||
environ.Env.read_env(BASE_DIR / ".env")
|
environ.Env.read_env(BASE_DIR / ".env")
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = env("SECRET_KEY")
|
SECRET_KEY = config('SECRET_KEY')
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
|
||||||
DEBUG = env("DEBUG")
|
|
||||||
|
|
||||||
# Allowed hosts
|
# Allowed hosts
|
||||||
ALLOWED_HOSTS = env("ALLOWED_HOSTS")
|
ALLOWED_HOSTS = config('ALLOWED_HOSTS')
|
||||||
|
|
||||||
# CSRF trusted origins
|
# CSRF trusted origins
|
||||||
CSRF_TRUSTED_ORIGINS = env("CSRF_TRUSTED_ORIGINS", default=[]) # type: ignore[arg-type]
|
CSRF_TRUSTED_ORIGINS = config('CSRF_TRUSTED_ORIGINS',
|
||||||
|
default=[]) # type: ignore[arg-type]
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
DJANGO_APPS = [
|
DJANGO_APPS = [
|
||||||
@@ -142,14 +140,23 @@ TEMPLATES = [
|
|||||||
WSGI_APPLICATION = "thrillwiki.wsgi.application"
|
WSGI_APPLICATION = "thrillwiki.wsgi.application"
|
||||||
|
|
||||||
# Cloudflare Images Settings
|
# Cloudflare Images Settings
|
||||||
STORAGES = {"default": {"BACKEND": "cloudflare_images.storage.CloudflareImagesStorage"}}
|
STORAGES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "cloudflare_images.storage.CloudflareImagesStorage",
|
||||||
|
},
|
||||||
|
"staticfiles": {
|
||||||
|
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
|
||||||
|
"OPTIONS": {
|
||||||
|
"location": str(BASE_DIR / "staticfiles"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
CLOUDFLARE_IMAGES_ACCOUNT_ID = config('CLOUDFLARE_IMAGES_ACCOUNT_ID')
|
CLOUDFLARE_IMAGES_ACCOUNT_ID = config('CLOUDFLARE_IMAGES_ACCOUNT_ID')
|
||||||
CLOUDFLARE_IMAGES_API_KEY = config('CLOUDFLARE_IMAGES_API_KEY')
|
CLOUDFLARE_IMAGES_API_TOKEN = config('CLOUDFLARE_IMAGES_API_TOKEN')
|
||||||
CLOUDFLARE_IMAGES_ACCOUNT_HASH = config('CLOUDFLARE_IMAGES_ACCOUNT_HASH')
|
CLOUDFLARE_IMAGES_ACCOUNT_HASH = config('CLOUDFLARE_IMAGES_ACCOUNT_HASH')
|
||||||
CLOUDFLARE_IMAGES_DOMAIN = config(
|
CLOUDFLARE_IMAGES_DOMAIN = config(
|
||||||
'CLOUDFLARE_IMAGES_DOMAIN', default='imagedelivery.net')
|
'CLOUDFLARE_IMAGES_DOMAIN', default='imagedelivery.net')
|
||||||
|
|
||||||
CLOUDFLARE_EMAIL = config('CLOUDFLARE_EMAIL')
|
|
||||||
# Password validation
|
# Password validation
|
||||||
AUTH_PASSWORD_VALIDATORS = [
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
{
|
{
|
||||||
@@ -242,7 +249,7 @@ TEST_RUNNER = "django.test.runner.DiscoverRunner"
|
|||||||
ROADTRIP_CACHE_TIMEOUT = 3600 * 24 # 24 hours for geocoding
|
ROADTRIP_CACHE_TIMEOUT = 3600 * 24 # 24 hours for geocoding
|
||||||
ROADTRIP_ROUTE_CACHE_TIMEOUT = 3600 * 6 # 6 hours for routes
|
ROADTRIP_ROUTE_CACHE_TIMEOUT = 3600 * 6 # 6 hours for routes
|
||||||
ROADTRIP_MAX_REQUESTS_PER_SECOND = 1 # Respect OSM rate limits
|
ROADTRIP_MAX_REQUESTS_PER_SECOND = 1 # Respect OSM rate limits
|
||||||
ROADTRIP_USER_AGENT = "ThrillWiki Road Trip Planner (https://thrillwiki.com)"
|
ROADTRIP_USER_AGENT = config('ROADTRIP_USER_AGENT')
|
||||||
ROADTRIP_REQUEST_TIMEOUT = 10 # seconds
|
ROADTRIP_REQUEST_TIMEOUT = 10 # seconds
|
||||||
ROADTRIP_MAX_RETRIES = 3
|
ROADTRIP_MAX_RETRIES = 3
|
||||||
ROADTRIP_BACKOFF_FACTOR = 2
|
ROADTRIP_BACKOFF_FACTOR = 2
|
||||||
@@ -282,18 +289,17 @@ REST_FRAMEWORK = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# CORS Settings for API
|
# CORS Settings for API
|
||||||
CORS_ALLOWED_ORIGINS = env("CORS_ALLOWED_ORIGINS", default=[]) # type: ignore[arg-type]
|
CORS_ALLOWED_ORIGINS = config('CORS_ALLOWED_ORIGINS',
|
||||||
|
default=[]) # type: ignore[arg-type]
|
||||||
CORS_ALLOW_CREDENTIALS = True
|
CORS_ALLOW_CREDENTIALS = True
|
||||||
CORS_ALLOW_ALL_ORIGINS = env("CORS_ALLOW_ALL_ORIGINS",
|
CORS_ALLOW_ALL_ORIGINS = config(
|
||||||
default=False) # type: ignore[arg-type]
|
'CORS_ALLOW_ALL_ORIGINS', default=False, cast=bool) # type: ignore[arg-type]
|
||||||
|
|
||||||
# API-specific settings
|
|
||||||
API_RATE_LIMIT_PER_MINUTE = env.int(
|
|
||||||
"API_RATE_LIMIT_PER_MINUTE", default=60) # type: ignore[arg-type]
|
|
||||||
API_RATE_LIMIT_PER_HOUR = env.int(
|
|
||||||
"API_RATE_LIMIT_PER_HOUR", default=1000) # type: ignore[arg-type]
|
|
||||||
|
|
||||||
# drf-spectacular settings
|
API_RATE_LIMIT_PER_MINUTE = config(
|
||||||
|
'API_RATE_LIMIT_PER_MINUTE', default=60, cast=int) # type: ignore[arg-type]
|
||||||
|
API_RATE_LIMIT_PER_HOUR = config(
|
||||||
|
'API_RATE_LIMIT_PER_HOUR', default=1000, cast=int) # type: ignore[arg-type]
|
||||||
SPECTACULAR_SETTINGS = {
|
SPECTACULAR_SETTINGS = {
|
||||||
"TITLE": "ThrillWiki API",
|
"TITLE": "ThrillWiki API",
|
||||||
"DESCRIPTION": "Comprehensive theme park and ride information API",
|
"DESCRIPTION": "Comprehensive theme park and ride information API",
|
||||||
@@ -367,11 +373,9 @@ DJANGO_REDIS_CLIENT_CLASS = "django_redis.client.DefaultClient"
|
|||||||
CACHES = {
|
CACHES = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": DJANGO_REDIS_CACHE_BACKEND,
|
"BACKEND": DJANGO_REDIS_CACHE_BACKEND,
|
||||||
# type: ignore[arg-type]
|
|
||||||
# pyright: ignore[reportArgumentType]
|
|
||||||
# pyright: ignore[reportArgumentType]
|
# pyright: ignore[reportArgumentType]
|
||||||
# type: ignore
|
# type: ignore
|
||||||
"LOCATION": env("REDIS_URL", default="redis://127.0.0.1:6379/1"),
|
"LOCATION": config('REDIS_URL', default="redis://127.0.0.1:6379/1"),
|
||||||
"OPTIONS": {
|
"OPTIONS": {
|
||||||
"CLIENT_CLASS": DJANGO_REDIS_CLIENT_CLASS,
|
"CLIENT_CLASS": DJANGO_REDIS_CLIENT_CLASS,
|
||||||
"PARSER_CLASS": "redis.connection.HiredisParser",
|
"PARSER_CLASS": "redis.connection.HiredisParser",
|
||||||
@@ -388,17 +392,14 @@ CACHES = {
|
|||||||
},
|
},
|
||||||
"sessions": {
|
"sessions": {
|
||||||
"BACKEND": DJANGO_REDIS_CACHE_BACKEND,
|
"BACKEND": DJANGO_REDIS_CACHE_BACKEND,
|
||||||
# type: ignore[arg-type]
|
"LOCATION": config('REDIS_URL', default="redis://127.0.0.1:6379/2"),
|
||||||
# type: ignore
|
|
||||||
"LOCATION": env("REDIS_URL", default="redis://127.0.0.1:6379/2"),
|
|
||||||
"OPTIONS": {
|
"OPTIONS": {
|
||||||
"CLIENT_CLASS": DJANGO_REDIS_CLIENT_CLASS,
|
"CLIENT_CLASS": DJANGO_REDIS_CLIENT_CLASS,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"api": {
|
"api": {
|
||||||
"BACKEND": DJANGO_REDIS_CACHE_BACKEND,
|
"BACKEND": DJANGO_REDIS_CACHE_BACKEND,
|
||||||
# type: ignore[arg-type]
|
"LOCATION": config('REDIS_URL', default="redis://127.0.0.1:6379/3"),
|
||||||
"LOCATION": env("REDIS_URL", default="redis://127.0.0.1:6379/3"),
|
|
||||||
"OPTIONS": {
|
"OPTIONS": {
|
||||||
"CLIENT_CLASS": DJANGO_REDIS_CLIENT_CLASS,
|
"CLIENT_CLASS": DJANGO_REDIS_CLIENT_CLASS,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,13 +2,9 @@
|
|||||||
Local development settings for thrillwiki project.
|
Local development settings for thrillwiki project.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
|
||||||
from .base import *
|
|
||||||
from ..settings import database
|
from ..settings import database
|
||||||
|
import logging
|
||||||
# Import the module and use its members, e.g., email.EMAIL_HOST
|
from .base import * # noqa: F403
|
||||||
|
|
||||||
# Import the module and use its members, e.g., security.SECURE_HSTS_SECONDS
|
|
||||||
|
|
||||||
# Import database configuration
|
# Import database configuration
|
||||||
DATABASES = database.DATABASES
|
DATABASES = database.DATABASES
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from decouple import config
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Run administrative tasks."""
|
"""Run administrative tasks."""
|
||||||
# Auto-detect environment based on command line arguments and environment variables
|
# Auto-detect environment based on command line arguments and environment variables
|
||||||
settings_module = detect_settings_module()
|
settings_module = detect_settings_module()
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings_module)
|
config('DJANGO_SETTINGS_MODULE', settings_module)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
|
|||||||
Reference in New Issue
Block a user