import logging from datetime import datetime from os import getenv, name from pathlib import Path from typing import Any EVIBES_VERSION = "2025.4" RELEASE_DATE = datetime(2025, 9, 13) BASE_DIR = Path(__file__).resolve().parent.parent.parent SECRET_KEY = getenv("SECRET_KEY", "SUPER_SECRET_KEY") DEBUG = bool(int(getenv("DEBUG", "1"))) ALLOWED_HOSTS: set[str] = { "app", "worker", "beat", "localhost", "127.0.0.1", } if DEBUG: ALLOWED_HOSTS.add("*") else: for entry in getenv("ALLOWED_HOSTS", "").split(" "): ALLOWED_HOSTS.add(entry) ALLOWED_HOSTS: tuple[str, ...] = tuple(ALLOWED_HOSTS) CSRF_TRUSTED_ORIGINS: set[str] = { "http://127.0.0.1", "http://localhost", } for entry in getenv("CSRF_TRUSTED_ORIGINS", "").split(" "): CSRF_TRUSTED_ORIGINS.add(entry) CSRF_TRUSTED_ORIGINS: tuple[str, ...] = tuple(CSRF_TRUSTED_ORIGINS) if DEBUG: CORS_ALLOW_ALL_ORIGINS = True else: CORS_ALLOWED_ORIGINS: set[str] = { "http://127.0.0.1", "http://localhost", } for entry in getenv("CORS_ALLOWED_ORIGINS", "").split(" "): CORS_ALLOWED_ORIGINS.add(entry) CORS_ALLOWED_ORIGINS: tuple[str, ...] = tuple(CORS_ALLOWED_ORIGINS) CORS_ALLOW_METHODS = ( "DELETE", "GET", "OPTIONS", "PATCH", "POST", "PUT", ) CORS_ALLOW_HEADERS = ( "accept", "accept-encoding", "accept-language", "content-type", "connection", "user-agent", "authorization", "host", "x-csrftoken", "x-requested-with", "x-evibes-authv", "baggage", "sentry-trace", "dnt", "sec-fetch-dest", "sec-fetch-mode", "sec-fetch-site", "sec-gpc", "origin", "referer", ) USE_X_FORWARDED_HOST = True SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") if not DEBUG else None X_FRAME_OPTIONS = "SAMEORIGIN" UNSAFE_CACHE_KEYS: list[str] = [] SITE_ID: int = 1 INSTALLED_APPS: list[str] = [ "django_prometheus", "constance", "jazzmin", "modeltranslation", "django.contrib.admin", "django.contrib.admindocs", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "django.contrib.sitemaps", "django.contrib.gis", "django.contrib.humanize", "health_check", "health_check.db", "health_check.cache", "health_check.storage", "health_check.contrib.migrations", "health_check.contrib.celery_ping", "health_check.contrib.psutil", "health_check.contrib.redis", "health_check.contrib.db_heartbeat", "health_check.contrib.mail", "cacheops", "django_celery_beat", "django_celery_results", "django_extensions", "django_redis", "django_summernote", "widget_tweaks", "mptt", "rest_framework", "rest_framework_simplejwt", "rest_framework_simplejwt.token_blacklist", "drf_spectacular", "drf_spectacular_sidecar", "django_json_widget", "django_elasticsearch_dsl", "dbbackup", "corsheaders", "constance.backends.database", "django_mailbox", "graphene_django", "channels", "engine.core", "engine.payments", "engine.authv", "engine.blog", ] if DEBUG: wn_app_index = INSTALLED_APPS.index("django.contrib.staticfiles") - 1 INSTALLED_APPS.insert(wn_app_index, "whitenoise.runserver_nostatic") MIDDLEWARE: list[str] = [ "evibes.middleware.BlockInvalidHostMiddleware", "django_prometheus.middleware.PrometheusBeforeMiddleware", "django.middleware.security.SecurityMiddleware", "whitenoise.middleware.WhiteNoiseMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "corsheaders.middleware.CorsMiddleware", "evibes.middleware.CustomCommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.contrib.admindocs.middleware.XViewMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "evibes.middleware.CustomLocaleMiddleware", "djangorestframework_camel_case.middleware.CamelCaseMiddleWare", "django_prometheus.middleware.PrometheusAfterMiddleware", ] TEMPLATES: list[dict[str, str | list[str | Path] | dict[str, str | list[str]] | Path | bool]] = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [ BASE_DIR / "engine/authv/templates", BASE_DIR / "engine/core/templates", BASE_DIR / "engine/payments/templates", ], "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", ], }, }, ] USE_I18N: bool = True LANGUAGES: tuple[tuple[str, str], ...] = ( ("ar-ar", "العربية"), ("cs-cz", "Česky"), ("da-dk", "Dansk"), ("de-de", "Deutsch"), ("en-gb", "English (British)"), ("en-us", "English (American)"), ("es-es", "Español"), ("fa-ir", "فارسی"), ("fr-fr", "Français"), ("he-il", "עברית"), ("hi-in", "हिंदी"), ("hr-hr", "Hrvatski"), ("id-id", "Bahasa Indonesia"), ("it-it", "Italiano"), ("ja-jp", "日本語"), ("kk-kz", "Қазақ"), ("ko-kr", "한국어"), ("nl-nl", "Nederlands"), ("no-no", "Norsk"), ("pl-pl", "Polska"), ("pt-br", "Português"), ("ro-ro", "Română"), ("ru-ru", "Русский"), ("sv-se", "Svenska"), ("th-th", "ไทย"), ("tr-tr", "Türkçe"), ("vi-vn", "Tiếng Việt"), ("zh-hans", "简体中文"), ) LANGUAGE_CODE: str = "en-gb" CURRENCIES_BY_LANGUAGES: tuple[tuple[str, str], ...] = ( ("ar-ar", "AED"), ("cs-cz", "CZK"), ("da-dk", "DKK"), ("de-de", "EUR"), ("en-gb", "GBP"), ("en-us", "USD"), ("es-es", "EUR"), ("fa-ir", "IRR"), ("fr-fr", "EUR"), ("he-il", "ILS"), ("hi-in", "INR"), ("hr-hr", "EUR"), ("id-id", "IDR"), ("it-it", "EUR"), ("ja-jp", "JPY"), ("kk-kz", "KZT"), ("ko-kr", "KRW"), ("nl-nl", "EUR"), ("no-no", "NOK"), ("pl-pl", "PLN"), ("pt-br", "BRL"), ("ro-ro", "RON"), ("ru-ru", "RUB"), ("sv-se", "SEK"), ("th-th", "THB"), ("tr-tr", "TRY"), ("vi-vn", "VND"), ("zh-hans", "CNY"), ) CURRENCIES_WITH_SYMBOLS: tuple[tuple[str, str], ...] = ( ("AED", "د.إ"), ("BRL", "R$"), ("CNY", "¥"), ("CZK", "Kč"), ("DKK", "kr"), ("EUR", "€"), ("GBP", "£"), ("IDR", "Rp"), ("ILS", "₪"), ("INR", "₹"), ("IRR", "﷼"), ("JPY", "¥"), ("KRW", "₩"), ("KZT", "₸"), ("NOK", "kr"), ("PLN", "zł"), ("RON", "lei"), ("RUB", "₽"), ("SEK", "kr"), ("THB", "฿"), ("TRY", "₺"), ("USD", "$"), ("VND", "₫"), ) CURRENCY_CODE: str = dict(CURRENCIES_BY_LANGUAGES).get(LANGUAGE_CODE) # type: ignore[assignment] MODELTRANSLATION_FALLBACK_LANGUAGES: tuple[str, ...] = (LANGUAGE_CODE, "en-us", "de-de") ROOT_URLCONF: str = "evibes.urls" WSGI_APPLICATION: str = "evibes.wsgi.application" ASGI_APPLICATION: str = "evibes.asgi.application" DEFAULT_AUTO_FIELD: str = "django.db.models.BigAutoField" TIME_ZONE: str = getenv("TIME_ZONE", "Europe/London") STATIC_URL: str = ( f"http://api.{getenv('EVIBES_BASE_DOMAIN')}/static/" if DEBUG else f"https://api.{getenv('EVIBES_BASE_DOMAIN')}/static/" ) STATIC_ROOT: Path = BASE_DIR / "static" MEDIA_URL: str = ( f"http://api.{getenv('EVIBES_BASE_DOMAIN')}/media/" if DEBUG else f"https://api.{getenv('EVIBES_BASE_DOMAIN')}/media/" ) MEDIA_ROOT: Path = BASE_DIR / "media" AUTH_USER_MODEL: str = "authv.User" AUTH_PASSWORD_VALIDATORS: list[dict[str, str | int]] = [ { "NAME": "django.contrib.authv.password_validation.UserAttributeSimilarityValidator", }, { "NAME": "django.contrib.authv.password_validation.MinimumLengthValidator", }, { "NAME": "django.contrib.authv.password_validation.CommonPasswordValidator", }, { "NAME": "django.contrib.authv.password_validation.NumericPasswordValidator", }, ] APPEND_SLASH: bool = True REDIS_PASSWORD: str = getenv("REDIS_PASSWORD", default="") REDIS_URL: str = f"redis://:{REDIS_PASSWORD}@redis:6379/0" CHANNEL_LAYERS: dict[str, dict[str, str | dict[str, list[str]]]] = { "default": { "BACKEND": "channels_redis.core.RedisChannelLayer", "CONFIG": { "hosts": [getenv("CHANNEL_REDIS_URL", REDIS_URL)], }, }, } INTERNAL_IPS: list[str] = [ "127.0.0.1", ] if getenv("SENTRY_DSN"): import sentry_sdk from sentry_sdk.integrations.celery import CeleryIntegration from sentry_sdk.integrations.django import DjangoIntegration from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.redis import RedisIntegration from sentry_sdk.types import Event, Hint def scrub_sensitive(data: dict[str, Any] | list[Any] | str) -> dict[str, Any] | list[Any] | str | None: if isinstance(data, dict): cleaned: dict[str, Any] = {} for key, value in data.items(): if key.lower() in ("password", "confirm_password"): cleaned[key] = "[FILTERED]" else: cleaned[key] = scrub_sensitive(value) return cleaned if isinstance(data, list): return [scrub_sensitive(item) for item in data] return data def before_send(event: Event, hint: Hint) -> Event: if hint: pass request = event.get("request", {}) data = request.get("data", {}) if data: request["data"] = scrub_sensitive(data) # type: ignore [arg-type] event["request"] = request return event ignore_errors: list[str] = [] sentry_sdk.init( dsn=getenv("SENTRY_DSN"), integrations=[ DjangoIntegration(), LoggingIntegration(level=logging.INFO, event_level=logging.ERROR), CeleryIntegration(), RedisIntegration(), ], environment="development" if DEBUG else "production", release=f"evibes@{EVIBES_VERSION}", traces_sample_rate=1.0 if DEBUG else 0.2, profiles_sample_rate=1.0 if DEBUG else 0.1, max_request_body_size="always", before_send=before_send, ignore_errors=ignore_errors, debug=False, ) SESSION_COOKIE_HTTPONLY: bool = True CSRF_COOKIE_HTTPONLY: bool = True LANGUAGE_COOKIE_HTTPONLY: bool = True DATA_UPLOAD_MAX_NUMBER_FIELDS: int = 8888 ADMINS: list[tuple[str, ...]] = [("Egor Gorbunov", "contact@fureunoir.com")] STORAGES: dict[str, dict[str, str | int | bool | None]] = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { "BACKEND": "whitenoise.storage.CompressedStaticFilesStorage" if DEBUG else "whitenoise.storage.CompressedManifestStaticFilesStorage" }, "dbbackup": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, } if name == "nt": GDAL_LIBRARY_PATH = r"C:\OSGeo4W\bin\gdal311.dll" GEOS_LIBRARY_PATH = r"C:\OSGeo4W\bin\geos_c.dll"