import socket from pathlib import Path import environ import os import logging import sys from django.utils.translation import gettext_lazy as _ from pkmntrade_club._version import __version__, get_version_info # set default values to local dev values env = environ.Env( DEBUG=(bool, False), # MUST STAY FALSE FOR DEFAULT FOR SECURITY REASONS (e.g. if app can't access .env, prevent showing debug output) DISABLE_SIGNUPS=(bool, True), DISABLE_CACHE=(bool, True), DJANGO_DATABASE_URL=(str, 'postgresql://postgres@localhost:5432/postgres?sslmode=disable'), DJANGO_EMAIL_HOST=(str, ''), DJANGO_EMAIL_PORT=(int, 587), DJANGO_EMAIL_USER=(str, ''), DJANGO_EMAIL_PASSWORD=(str, ''), DJANGO_EMAIL_USE_TLS=(bool, True), DJANGO_DEFAULT_FROM_EMAIL=(str, ''), SECRET_KEY=(str, '0000000000000000000000000000000000000000000000000000000000000000'), ALLOWED_HOSTS=(str, 'localhost,127.0.0.1'), PUBLIC_HOST=(str, 'localhost'), ACCOUNT_EMAIL_VERIFICATION=(str, 'none'), SCHEME=(str, 'http'), REDIS_URL=(str, 'redis://localhost:6379'), CACHE_TIMEOUT=(int, 604800), TIME_ZONE=(str, 'America/Los_Angeles'), ) LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'verbose': { 'format': '%(asctime)s %(name)-12s %(levelname)-8s %(message)s', }, }, 'handlers': { 'console': { 'level': 'INFO', 'class': 'logging.StreamHandler', 'stream': sys.stdout, 'formatter': 'verbose', 'filters': [], }, }, 'loggers': { 'django': { 'handlers': ['console'], 'level': 'INFO', }, 'django.server': { 'handlers': ['console'], 'level': 'INFO', 'propagate': False, }, 'granian.access': { 'handlers': ['console'], 'level': 'INFO', 'propagate': False, }, '_granian': { 'handlers': ['console'], 'level': 'INFO', 'propagate': False, }, '': { 'handlers': ['console'], 'level': 'INFO', }, }, } # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # Take environment variables from .env file environ.Env.read_env(os.path.join(BASE_DIR, '.env')) SCHEME = env('SCHEME') PUBLIC_HOST = env('PUBLIC_HOST') REDIS_URL = env('REDIS_URL') CACHE_TIMEOUT = env('CACHE_TIMEOUT') DISABLE_SIGNUPS = env('DISABLE_SIGNUPS') DISABLE_CACHE = env('DISABLE_CACHE') VERSION = __version__ VERSION_INFO = get_version_info() # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/ # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = env('SECRET_KEY') # https://docs.djangoproject.com/en/dev/ref/settings/#debug # SECURITY WARNING: don't run with debug turned on in production! DEBUG = env('DEBUG') # https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts ALLOWED_HOSTS = env('ALLOWED_HOSTS').split(',') try: current_web_worker_hostname = socket.gethostname() ALLOWED_HOSTS.append(current_web_worker_hostname) logging.getLogger(__name__).info(f"Added {current_web_worker_hostname} to allowed hosts.") except Exception: logging.getLogger(__name__).info(f"Error determining server hostname for allowed hosts.") CSRF_TRUSTED_ORIGINS = [f"{SCHEME}://{PUBLIC_HOST}"] FIRST_PARTY_APPS = [ 'pkmntrade_club.accounts', 'pkmntrade_club.cards', 'pkmntrade_club.common', 'pkmntrade_club.home', 'pkmntrade_club.theme', 'pkmntrade_club.trades', ] # Application definition # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps INSTALLED_APPS = [ "django_daisy", "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "whitenoise.runserver_nostatic", "django.contrib.staticfiles", "django.contrib.sites", "django_celery_beat", "allauth", "allauth.account", 'allauth.socialaccount.providers.google', "crispy_forms", "crispy_tailwind", "tailwind", "django_linear_migrations", 'health_check', 'health_check.db', 'health_check.cache', 'health_check.storage', 'health_check.contrib.migrations', 'health_check.contrib.celery', 'health_check.contrib.celery_ping', 'health_check.contrib.psutil', 'health_check.contrib.redis', "meta", ] + FIRST_PARTY_APPS if DEBUG: INSTALLED_APPS = [ *INSTALLED_APPS, "django_browser_reload", "debug_toolbar", ] TAILWIND_APP_NAME = 'theme' META_SITE_NAME = 'PKMN Trade Club' META_SITE_PROTOCOL = SCHEME META_USE_SITES = True META_IMAGE_URL = f'{SCHEME}://{PUBLIC_HOST}/' # https://docs.djangoproject.com/en/dev/ref/settings/#middleware MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "whitenoise.middleware.WhiteNoiseMiddleware", # WhiteNoise "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "debug_toolbar.middleware.DebugToolbarMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "allauth.account.middleware.AccountMiddleware", # django-allauth ] if DEBUG: MIDDLEWARE = [ *MIDDLEWARE, "django_browser_reload.middleware.BrowserReloadMiddleware", ] HEALTH_CHECK = { 'DISK_USAGE_MAX': 90, # percent 'MEMORY_MIN': 100, # in MB } DAISY_SETTINGS = { 'SITE_TITLE': 'PKMN Trade Club Admin', 'DONT_SUPPORT_ME': True, } # https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf ROOT_URLCONF = 'pkmntrade_club.django_project.urls' # https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application WSGI_APPLICATION = 'pkmntrade_club.django_project.wsgi.app' ASGI_APPLICATION = 'pkmntrade_club.django_project.asgi.application' # https://docs.djangoproject.com/en/dev/ref/settings/#templates TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "theme/templates", BASE_DIR / "theme"], "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", "pkmntrade_club.common.context_processors.cache_settings", "pkmntrade_club.common.context_processors.version_info", ], }, }, ] # https://docs.djangoproject.com/en/dev/ref/settings/#databases DATABASES = { 'default': env.db(var="DJANGO_DATABASE_URL"), } # Password validation # https://docs.djangoproject.com/en/dev/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/dev/topics/i18n/ # https://docs.djangoproject.com/en/dev/ref/settings/#language-code LANGUAGE_CODE = "en-us" # https://docs.djangoproject.com/en/dev/ref/settings/#time-zone TIME_ZONE = env('TIME_ZONE') # https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-USE_I18N USE_I18N = True # https://docs.djangoproject.com/en/dev/ref/settings/#use-tz USE_TZ = True # https://docs.djangoproject.com/en/dev/ref/settings/#locale-paths LOCALE_PATHS = [BASE_DIR / 'locale'] # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.0/howto/static-files/ # https://docs.djangoproject.com/en/dev/ref/settings/#static-root STATIC_ROOT = BASE_DIR / "staticfiles" # https://docs.djangoproject.com/en/dev/ref/settings/#static-url STATIC_URL = "/static/" # https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS STATICFILES_DIRS = [ BASE_DIR / "static", # For general static files BASE_DIR / "theme" / "static", # For Tailwind generated CSS ] # https://docs.djangoproject.com/en/dev/ref/settings/#media-root MEDIA_ROOT = BASE_DIR / "media" # https://docs.djangoproject.com/en/dev/ref/settings/#media-url MEDIA_URL = "/media/" # https://whitenoise.readthedocs.io/en/latest/django.html STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { "BACKEND": "whitenoise.storage.CompressedStaticFilesStorage", }, } # Default primary key field type # https://docs.djangoproject.com/en/stable/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' # django-crispy-forms # https://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs CRISPY_ALLOWED_TEMPLATE_PACKS = 'tailwind' CRISPY_TEMPLATE_PACK = "tailwind" # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" EMAIL_HOST = env('DJANGO_EMAIL_HOST') EMAIL_PORT = env('DJANGO_EMAIL_PORT') EMAIL_HOST_USER = env('DJANGO_EMAIL_USER') EMAIL_HOST_PASSWORD = env('DJANGO_EMAIL_PASSWORD') EMAIL_USE_TLS = env('DJANGO_EMAIL_USE_TLS') # https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email DEFAULT_FROM_EMAIL = env('DJANGO_DEFAULT_FROM_EMAIL') # django-debug-toolbar # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html # https://docs.djangoproject.com/en/dev/ref/settings/#internal-ips INTERNAL_IPS = [ "127.0.0.1", ] # for docker hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) for ip in ips: INTERNAL_IPS.append(ip) INTERNAL_IPS.append(".".join(ip.rsplit(".")[:-1])+ ".1") # https://docs.djangoproject.com/en/dev/topics/auth/customizing/#substituting-a-custom-user-model AUTH_USER_MODEL = "accounts.CustomUser" # django-allauth config # https://docs.djangoproject.com/en/dev/ref/settings/#site-id SITE_ID = 1 # https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url LOGIN_REDIRECT_URL = "home" # https://django-allauth.readthedocs.io/en/latest/views.html#logout-account-logout ACCOUNT_LOGOUT_REDIRECT_URL = "home" # https://django-allauth.readthedocs.io/en/latest/installation.html?highlight=backends AUTHENTICATION_BACKENDS = ( "django.contrib.auth.backends.ModelBackend", "allauth.account.auth_backends.AuthenticationBackend", ) # https://django-allauth.readthedocs.io/en/latest/configuration.html if DISABLE_SIGNUPS: ACCOUNT_ADAPTER = 'pkmntrade_club.accounts.adapter.NoSignupAccountAdapter' SOCIALACCOUNT_ADAPTER = 'pkmntrade_club.accounts.adapter.NoSignupSocialAccountAdapter' # always disable social account signups ACCOUNT_SESSION_REMEMBER = True ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE = True ACCOUNT_AUTHENTICATION_METHOD = "username_email" ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_EMAIL_VERIFICATION = env('ACCOUNT_EMAIL_VERIFICATION') ACCOUNT_EMAIL_NOTIFICATIONS = True ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = False ACCOUNT_DEFAULT_HTTP_PROTOCOL = SCHEME ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True ACCOUNT_USERNAME_MIN_LENGTH = 2 ACCOUNT_CHANGE_EMAIL = True ACCOUNT_UNIQUE_EMAIL = True ACCOUNT_LOGIN_BY_CODE_ENABLED = True ACCOUNT_LOGIN_BY_CODE_REQUIRED = False ACCOUNT_SIGNUP_FORM_HONEYPOT_FIELD = "website" ACCOUNT_USERNAME_REQUIRED = True ACCOUNT_FORMS = { "signup": "pkmntrade_club.accounts.forms.CustomUserCreationForm", } SOCIALACCOUNT_EMAIL_AUTHENTICATION = False SOCIALACCOUNT_EMAIL_AUTHENTICATION_AUTO_CONNECT = False SOCIALACCOUNT_ONLY = False SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" SESSION_COOKIE_HTTPONLY = True # auto-detection doesn't work properly sometimes, so we'll just use the DEBUG setting DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": lambda request: DEBUG} if DISABLE_CACHE: CACHES = { "default": { "BACKEND": "django.core.cache.backends.dummy.DummyCache", } } else: CACHES = { "default": { "BACKEND": "django.core.cache.backends.redis.RedisCache", "LOCATION": REDIS_URL, } } CELERY_BROKER_URL = REDIS_URL CELERY_RESULT_BACKEND = REDIS_URL CELERY_TIMEZONE = TIME_ZONE CELERY_ENABLE_UTC = True CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"