init
This commit is contained in:
951
backend/trznice/settings.py
Normal file
951
backend/trznice/settings.py
Normal file
@@ -0,0 +1,951 @@
|
||||
"""
|
||||
Django settings for trznice project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 5.1.3.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/5.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/5.1/ref/settings/
|
||||
"""
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
from pathlib import Path
|
||||
|
||||
from django.core.management.utils import get_random_secret_key
|
||||
from django.db import OperationalError, connections
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv() # Pouze načte proměnné lokálně, pokud nejsou dostupné
|
||||
|
||||
#---------------- ENV VARIABLES USECASE--------------
|
||||
# v jiné app si to importneš skrz: from django.conf import settings
|
||||
# a použiješ takto: settings.FRONTEND_URL
|
||||
|
||||
FRONTEND_URL = os.getenv("FRONTEND_URL", "http://localhost:5173")
|
||||
#-------------------------BASE ⚙️------------------------
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Pavel
|
||||
# from django.conf.locale.en import formats as en_formats
|
||||
|
||||
DATETIME_INPUT_FORMATS = [
|
||||
"%Y-%m-%d", # '2025-07-25'
|
||||
"%Y-%m-%d %H:%M", # '2025-07-25 14:30'
|
||||
"%Y-%m-%d %H:%M:%S", # '2025-07-25 14:30:59'
|
||||
"%Y-%m-%dT%H:%M", # '2025-07-25T14:30'
|
||||
"%Y-%m-%dT%H:%M:%S", # '2025-07-25T14:30:59'
|
||||
]
|
||||
|
||||
LANGUAGE_CODE = 'cs'
|
||||
|
||||
TIME_ZONE = 'Europe/Prague'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
if os.getenv("DEBUG", "") == "True":
|
||||
DEBUG = True
|
||||
else:
|
||||
DEBUG = False
|
||||
|
||||
print(f"\nDEBUG state: {str(DEBUG)}\nDEBUG .env raw: {os.getenv('DEBUG', '')}\n")
|
||||
|
||||
#-----------------------BASE END⚙️--------------------------
|
||||
|
||||
#--------------- URLS 🌐 -------------------
|
||||
|
||||
ASGI_APPLICATION = 'trznice.asgi.application' #daphne
|
||||
ROOT_URLCONF = 'trznice.urls'
|
||||
LOGIN_URL = '/admin' #nastavení Login adresy
|
||||
|
||||
#-----------------------------------------
|
||||
|
||||
|
||||
|
||||
#----------------------------------- LOGS -------------------------------------------
|
||||
#slouží pro tisknutí do konzole v dockeru skrz: logger.debug("content")
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "verbose",
|
||||
},
|
||||
},
|
||||
"formatters": {
|
||||
"verbose": {
|
||||
"format": "{levelname} {asctime} {name}: {message}",
|
||||
"style": "{",
|
||||
},
|
||||
},
|
||||
"root": {
|
||||
"handlers": ["console"],
|
||||
"level": "DEBUG" if DEBUG else "INFO",
|
||||
},
|
||||
}
|
||||
|
||||
"""
|
||||
import logging
|
||||
|
||||
# Vytvoř si logger podle názvu souboru (modulu)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
logger.debug("Ladicí zpráva – vidíš jen když je DEBUG = True")
|
||||
logger.info("Informace – např. že uživatel klikl na tlačítko")
|
||||
logger.warning("Varování – něco nečekaného, ale ne kritického")
|
||||
logger.error("Chyba – něco se pokazilo, ale aplikace jede dál")
|
||||
logger.critical("Kritická chyba – selhání systému, třeba pád služby")
|
||||
"""
|
||||
|
||||
#---------------------------------- END LOGS ---------------------------------------
|
||||
|
||||
#-------------------------------------SECURITY 🔐------------------------------------
|
||||
|
||||
if DEBUG:
|
||||
SECRET_KEY = 'pernament'
|
||||
else:
|
||||
SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", get_random_secret_key())
|
||||
|
||||
# Honor reverse proxy host/port even without SSL
|
||||
USE_X_FORWARDED_HOST = True
|
||||
# Optionally honor proto if you terminate SSL at proxy
|
||||
# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
|
||||
SESSION_COOKIE_AGE = 86400 # one day
|
||||
|
||||
|
||||
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',
|
||||
},
|
||||
]
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
#'trznice.backend.EmailOrUsernameModelBackend', #custom backend z authentication aplikace
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
]
|
||||
|
||||
#--------------------------------END SECURITY 🔐-------------------------------------
|
||||
|
||||
#-------------------------------------CORS + HOSTs 🌐🔐------------------------------------
|
||||
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
from urllib.parse import urlparse
|
||||
parsed = urlparse(FRONTEND_URL)
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = [
|
||||
f"{parsed.scheme}://{parsed.hostname}:{parsed.port or (443 if parsed.scheme=='https' else 80)}",
|
||||
|
||||
"http://192.168.67.98",
|
||||
"https://itsolutions.vontor.cz",
|
||||
"https://react.vontor.cz",
|
||||
|
||||
"http://localhost:5173",
|
||||
"http://localhost:3000",
|
||||
|
||||
"http://127.0.0.1:5173",
|
||||
"http://127.0.0.1:3000",
|
||||
|
||||
#server
|
||||
"http://192.168.67.98",
|
||||
"https://itsolutions.vontor.cz",
|
||||
"https://react.vontor.cz",
|
||||
|
||||
#nginx docker (local)
|
||||
"http://localhost",
|
||||
"http://localhost:80",
|
||||
"http://127.0.0.1",
|
||||
]
|
||||
|
||||
if DEBUG:
|
||||
CORS_ALLOWED_ORIGINS = [
|
||||
f"{parsed.scheme}://{parsed.hostname}:{parsed.port or (443 if parsed.scheme=='https' else 80)}",
|
||||
|
||||
"http://localhost:5173",
|
||||
"http://localhost:3000",
|
||||
"http://127.0.0.1:5173",
|
||||
"http://127.0.0.1:3000",
|
||||
|
||||
#server
|
||||
"http://192.168.67.98",
|
||||
"https://itsolutions.vontor.cz",
|
||||
"https://react.vontor.cz",
|
||||
|
||||
#nginx docker (local)
|
||||
"http://localhost",
|
||||
"http://localhost:80",
|
||||
"http://127.0.0.1",
|
||||
]
|
||||
else:
|
||||
CORS_ALLOWED_ORIGINS = [
|
||||
"http://192.168.67.98",
|
||||
"https://itsolutions.vontor.cz",
|
||||
"https://react.vontor.cz",
|
||||
]
|
||||
|
||||
CORS_ALLOW_CREDENTIALS = True
|
||||
CORS_ALLOW_ALL_ORIGINS = False # Tohle musí být false, když používáš credentials
|
||||
|
||||
SESSION_COOKIE_SAMESITE = None
|
||||
CSRF_COOKIE_SAMESITE = None
|
||||
|
||||
print("CORS_ALLOWED_ORIGINS =", CORS_ALLOWED_ORIGINS)
|
||||
print("CSRF_TRUSTED_ORIGINS =", CSRF_TRUSTED_ORIGINS)
|
||||
print("ALLOWED_HOSTS =", ALLOWED_HOSTS)
|
||||
|
||||
|
||||
|
||||
#--------------------------------END CORS + HOSTs 🌐🔐---------------------------------
|
||||
|
||||
|
||||
#--------------------------------------SSL 🧾------------------------------------
|
||||
|
||||
if os.getenv("SSL", "") == "True":
|
||||
USE_SSL = True
|
||||
else:
|
||||
USE_SSL = False
|
||||
|
||||
|
||||
if USE_SSL is True:
|
||||
print("SSL turned on!")
|
||||
SESSION_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_SECURE = True
|
||||
SECURE_SSL_REDIRECT = True
|
||||
SECURE_BROWSER_XSS_FILTER = True
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
# USE_X_FORWARDED_HOST stays True (set above)
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
else:
|
||||
SESSION_COOKIE_SECURE = False
|
||||
CSRF_COOKIE_SECURE = False
|
||||
SECURE_SSL_REDIRECT = False
|
||||
SECURE_BROWSER_XSS_FILTER = False
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = False
|
||||
# USE_X_FORWARDED_HOST stays True (set above)
|
||||
print(f"\nUsing SSL: {USE_SSL}\n")
|
||||
|
||||
#--------------------------------END-SSL 🧾---------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------REST FRAMEWORK 🛠️------------------------------------
|
||||
|
||||
# ⬇️ Základní lifetime konfigurace
|
||||
ACCESS_TOKEN_LIFETIME = timedelta(minutes=60)
|
||||
REFRESH_TOKEN_LIFETIME = timedelta(days=5)
|
||||
|
||||
# ⬇️ Nastavení SIMPLE_JWT podle režimu
|
||||
if DEBUG:
|
||||
SIMPLE_JWT = {
|
||||
"ACCESS_TOKEN_LIFETIME": ACCESS_TOKEN_LIFETIME,
|
||||
"REFRESH_TOKEN_LIFETIME": REFRESH_TOKEN_LIFETIME,
|
||||
|
||||
"AUTH_COOKIE": "access_token",
|
||||
"AUTH_COOKIE_REFRESH": "refresh_token",
|
||||
|
||||
"AUTH_COOKIE_DOMAIN": None,
|
||||
"AUTH_COOKIE_SECURE": False,
|
||||
"AUTH_COOKIE_HTTP_ONLY": True,
|
||||
|
||||
"ROTATE_REFRESH_TOKENS": False,
|
||||
"BLACKLIST_AFTER_ROTATION": False,
|
||||
|
||||
"AUTH_COOKIE_PATH": "/",
|
||||
"AUTH_COOKIE_SAMESITE": "Lax", # change to "None" only if you serve via HTTPS; keep Lax if using same-origin
|
||||
# ...existing code...
|
||||
|
||||
}
|
||||
else:
|
||||
SIMPLE_JWT = {
|
||||
"ACCESS_TOKEN_LIFETIME": ACCESS_TOKEN_LIFETIME,
|
||||
"REFRESH_TOKEN_LIFETIME": REFRESH_TOKEN_LIFETIME,
|
||||
|
||||
"AUTH_COOKIE": "access_token",
|
||||
"AUTH_COOKIE_REFRESH": "refresh_token", # ensure refresh cookie is recognized/used
|
||||
"AUTH_COOKIE_DOMAIN": None,
|
||||
"AUTH_COOKIE_SECURE": True, # HTTPS only
|
||||
"AUTH_COOKIE_HTTP_ONLY": True,
|
||||
"AUTH_COOKIE_PATH": "/",
|
||||
"AUTH_COOKIE_SAMESITE": "None", # potřebné pro cross-origin
|
||||
|
||||
"ROTATE_REFRESH_TOKENS": True,
|
||||
"BLACKLIST_AFTER_ROTATION": True,
|
||||
}
|
||||
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
"DATETIME_FORMAT": "%Y-%m-%d %H:%M",
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'account.tokens.CookieJWTAuthentication',
|
||||
'rest_framework_simplejwt.authentication.JWTAuthentication', # <-- allow Bearer Authorization
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
),
|
||||
'DEFAULT_PERMISSION_CLASSES': (
|
||||
'rest_framework.permissions.AllowAny',
|
||||
),
|
||||
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
||||
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
|
||||
}
|
||||
|
||||
|
||||
#--------------------------------END REST FRAMEWORK 🛠️-------------------------------------
|
||||
|
||||
|
||||
|
||||
#-------------------------------------APPS 📦------------------------------------
|
||||
MY_CREATED_APPS = [
|
||||
'account',
|
||||
'booking',
|
||||
'product',
|
||||
'servicedesk',
|
||||
'commerce',
|
||||
'configuration',
|
||||
]
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'daphne', #asgi bude fungovat lokálně (musí být na začátku)
|
||||
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
'corsheaders', #cors
|
||||
|
||||
'django_celery_beat', #slouží k plánování úkolů pro Celery
|
||||
|
||||
|
||||
#'chat.apps.GlobalChatCheck', #tohle se spusti při každé django inicializaci (migration, createmigration, runserver)
|
||||
|
||||
#'authentication',
|
||||
|
||||
'storages',# Adds support for external storage services like Amazon S3 via django-storages
|
||||
'django_filters',
|
||||
|
||||
'channels' ,# django channels
|
||||
|
||||
'rest_framework',
|
||||
'rest_framework_api_key',
|
||||
'rest_framework_simplejwt.token_blacklist',
|
||||
|
||||
'drf_spectacular', #rest framework, grafické zobrazení
|
||||
|
||||
#Nastavení stránky
|
||||
#'constance',
|
||||
#'constance.backends.database',
|
||||
|
||||
'django.contrib.sitemaps',
|
||||
|
||||
'tinymce',
|
||||
|
||||
|
||||
#kvůli bugum je lepší to dát na poslední místo v INSTALLED_APPS
|
||||
'django_cleanup.apps.CleanupConfig', #app která maže nepoužité soubory(media) z databáze na S3
|
||||
]
|
||||
|
||||
#skládaní dohromady INSTALLED_APPS
|
||||
INSTALLED_APPS = INSTALLED_APPS[:-1] + MY_CREATED_APPS + INSTALLED_APPS[-1:]
|
||||
|
||||
# -------------------------------------END APPS 📦------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------MIDDLEWARE 🧩------------------------------------
|
||||
# Middleware is a framework of hooks into Django's request/response processing.
|
||||
|
||||
MIDDLEWARE = [
|
||||
# Middleware that allows your backend to accept requests from other domains (CORS)
|
||||
"corsheaders.middleware.CorsMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
|
||||
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
|
||||
#CUSTOM
|
||||
#'tools.middleware.CustomMaxUploadSizeMiddleware',
|
||||
|
||||
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',# díky tomu funguje načítaní static files
|
||||
]
|
||||
|
||||
#--------------------------------END MIDDLEWARE 🧩---------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------CACHE + CHANNELS(ws) 📡🗄️------------------------------------
|
||||
|
||||
# Caching settings for Redis (using Docker's internal network name for Redis)
|
||||
if DEBUG is False:
|
||||
#PRODUCTION
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
|
||||
'LOCATION': 'redis://redis:6379/0', # Using the service name `redis` from Docker Compose
|
||||
'OPTIONS': {
|
||||
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
|
||||
'PASSWORD': os.getenv('REDIS_PASSWORD'), # Make sure to set REDIS_PASSWORD in your environment
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
# WebSockets Channel Layers (using Redis in production)
|
||||
CHANNEL_LAYERS = {
|
||||
'default': {
|
||||
'BACKEND': 'channels_redis.core.RedisChannelLayer',
|
||||
'CONFIG': {
|
||||
'hosts': [('redis', 6379)], # Use `redis` service in Docker Compose
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
else:
|
||||
#DEVELOPMENT
|
||||
# Use in-memory channel layer for development (when DEBUG is True)
|
||||
CHANNEL_LAYERS = {
|
||||
'default': {
|
||||
'BACKEND': 'channels.layers.InMemoryChannelLayer',
|
||||
}
|
||||
}
|
||||
|
||||
# Use in-memory cache for development (when DEBUG is True)
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||
}
|
||||
}
|
||||
|
||||
#--------------------------------END CACHE + CHANNELS(ws) 📡🗄️---------------------------------
|
||||
|
||||
#-------------------------------------CELERY 📅------------------------------------
|
||||
|
||||
# CELERY_BROKER_URL = 'redis://localhost:6379/0'
|
||||
CELERY_BROKER_URL = os.getenv("CELERY_BROKER_URL")
|
||||
CELERY_RESULT_BACKEND = os.getenv("CELERY_RESULT_BACKEND")
|
||||
|
||||
try:
|
||||
import redis
|
||||
# test connection
|
||||
r = redis.Redis(host='localhost', port=6379, db=0)
|
||||
r.ping()
|
||||
except Exception:
|
||||
CELERY_BROKER_URL = 'memory://'
|
||||
|
||||
CELERY_ACCEPT_CONTENT = os.getenv("CELERY_ACCEPT_CONTENT")
|
||||
CELERY_TASK_SERIALIZER = os.getenv("CELERY_TASK_SERIALIZER")
|
||||
CELERY_TIMEZONE = os.getenv("CELERY_TIMEZONE")
|
||||
|
||||
CELERY_BEAT_SCHEDULER = os.getenv("CELERY_BEAT_SCHEDULER")
|
||||
# if DEBUG:
|
||||
# CELERY_BROKER_URL = 'redis://localhost:6379/0'
|
||||
# try:
|
||||
# import redis
|
||||
# # test connection
|
||||
# r = redis.Redis(host='localhost', port=6379, db=0)
|
||||
# r.ping()
|
||||
# except Exception:
|
||||
# CELERY_BROKER_URL = 'memory://'
|
||||
|
||||
# CELERY_ACCEPT_CONTENT = ['json']
|
||||
# CELERY_TASK_SERIALIZER = 'json'
|
||||
# CELERY_TIMEZONE = 'Europe/Prague'
|
||||
|
||||
# CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'
|
||||
|
||||
# from celery.schedules import crontab
|
||||
|
||||
# CELERY_BEAT_SCHEDULE = {
|
||||
# 'hard_delete_soft_deleted_monthly': {
|
||||
# 'task': 'trznice.tasks.hard_delete_soft_deleted_records',
|
||||
# 'schedule': crontab(minute=0, hour=0, day_of_month=1), # každý první den v měsíci o půlnoci
|
||||
# },
|
||||
# 'delete_old_reservations_monthly': {
|
||||
# 'task': 'account.tasks.delete_old_reservations',
|
||||
# 'schedule': crontab(minute=0, hour=1, day_of_month=1), # každý první den v měsíci v 1:00 ráno
|
||||
# },
|
||||
# }
|
||||
# else:
|
||||
# # Nebo nastav dummy broker, aby se úlohy neodesílaly
|
||||
# CELERY_BROKER_URL = 'memory://' # broker v paměti, pro testování bez Redis
|
||||
|
||||
#-------------------------------------END CELERY 📅------------------------------------
|
||||
|
||||
|
||||
#-------------------------------------DATABASE 💾------------------------------------
|
||||
|
||||
# Nastavuje výchozí typ primárního klíče pro modely.
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
# říka že se úkladá do databáze, místo do cookie
|
||||
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
|
||||
|
||||
USE_DOCKER_DB = os.getenv("USE_DOCKER_DB", "False") in ["True", "true", "1", True]
|
||||
|
||||
if USE_DOCKER_DB is False:
|
||||
# DEV
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3', # Database engine
|
||||
'NAME': BASE_DIR / 'db.sqlite3', # Path to the SQLite database file
|
||||
}
|
||||
}
|
||||
else:
|
||||
#DOCKER
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': os.getenv('DATABASE_ENGINE'),
|
||||
'NAME': os.getenv('POSTGRES_DB'),
|
||||
'USER': os.getenv('POSTGRES_USER'),
|
||||
'PASSWORD': os.getenv('POSTGRES_PASSWORD'),
|
||||
'HOST': os.getenv('DATABASE_HOST'),
|
||||
'PORT': os.getenv('DATABASE_PORT'),
|
||||
}
|
||||
}
|
||||
|
||||
print(f"\nUsing Docker DB: {USE_DOCKER_DB}\nDatabase settings: {DATABASES}\n")
|
||||
|
||||
AUTH_USER_MODEL = 'account.CustomUser' #class CustomUser(AbstractUser) best practice to use AbstractUser
|
||||
|
||||
#--------------------------------END DATABASE 💾---------------------------------
|
||||
|
||||
#--------------------------------------PAGE SETTINGS -------------------------------------
|
||||
CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend'
|
||||
|
||||
# Configuration for Constance(variables)
|
||||
CONSTANCE_CONFIG = {
|
||||
'BITCOIN_WALLET': ('', 'Public BTC wallet address'),
|
||||
'SUPPORT_EMAIL': ('admin@example.com', 'Support email'),
|
||||
}
|
||||
|
||||
#--------------------------------------EMAIL 📧--------------------------------------
|
||||
|
||||
if DEBUG:
|
||||
# DEVELOPMENT
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # Use console backend for development
|
||||
# EMAILY SE BUDOU POSÍLAT DO KONZOLE!!!
|
||||
else:
|
||||
# PRODUCTION
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
|
||||
EMAIL_HOST = os.getenv("EMAIL_HOST_DEV")
|
||||
EMAIL_PORT = int(os.getenv("EMAIL_PORT_DEV", 465))
|
||||
EMAIL_USE_TLS = True # ❌ Keep this OFF when using SSL
|
||||
EMAIL_USE_SSL = False # ✅ Must be True for port 465
|
||||
EMAIL_HOST_USER = os.getenv("EMAIL_USER_DEV")
|
||||
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_USER_PASSWORD_DEV")
|
||||
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
|
||||
EMAIL_TIMEOUT = 10
|
||||
|
||||
print("---------EMAIL----------\nEMAIL_HOST =", os.getenv("EMAIL_HOST_DEV"))
|
||||
print("EMAIL_PORT =", os.getenv("EMAIL_PORT_DEV"))
|
||||
print("EMAIL_USER =", os.getenv("EMAIL_USER_DEV"))
|
||||
print("EMAIL_USER_PASSWORD =", os.getenv("EMAIL_USER_PASSWORD_DEV"), "\n------------------------")
|
||||
|
||||
#----------------------------------EMAIL END 📧-------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------TEMPLATES 🗂️------------------------------------
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
"DIRS": [BASE_DIR / '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',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
#--------------------------------END TEMPLATES 🗂️---------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------MEDIA + STATIC 🖼️, AWS ☁️------------------------------------
|
||||
|
||||
# nastavení složky pro globalstaticfiles (static složky django hledá samo)
|
||||
STATICFILES_DIRS = [
|
||||
BASE_DIR / 'globalstaticfiles',
|
||||
]
|
||||
|
||||
|
||||
|
||||
if os.getenv("USE_AWS", "") == "True":
|
||||
USE_AWS = True
|
||||
else:
|
||||
USE_AWS = False
|
||||
|
||||
print(f"\n-------------- USE_AWS: {USE_AWS} --------------")
|
||||
|
||||
if USE_AWS is False:
|
||||
# DEVELOPMENT
|
||||
|
||||
|
||||
# Development: Use local file system storage for static files
|
||||
STORAGES = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||
},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
|
||||
},
|
||||
}
|
||||
|
||||
# Media and Static URL for local dev
|
||||
MEDIA_URL = os.getenv("MEDIA_URL", "/media/") # URL prefix for media files
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Local folder for user-uploaded files
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# Local folder for collected static files
|
||||
STATIC_ROOT = BASE_DIR / 'collectedstaticfiles'
|
||||
|
||||
elif USE_AWS:
|
||||
# PRODUCTION
|
||||
|
||||
AWS_LOCATION = "static"
|
||||
|
||||
# Production: Use S3 storage
|
||||
STORAGES = {
|
||||
"default": {
|
||||
"BACKEND" : "storages.backends.s3boto3.S3StaticStorage",
|
||||
},
|
||||
|
||||
"staticfiles": {
|
||||
"BACKEND" : "storages.backends.s3boto3.S3StaticStorage",
|
||||
},
|
||||
}
|
||||
|
||||
# Media and Static URL for AWS S3
|
||||
MEDIA_URL = f'https://{os.getenv("AWS_STORAGE_BUCKET_NAME")}.s3.amazonaws.com/media/'
|
||||
STATIC_URL = f'https://{os.getenv("AWS_STORAGE_BUCKET_NAME")}.s3.amazonaws.com/static/'
|
||||
|
||||
CSRF_TRUSTED_ORIGINS.append(STATIC_URL)
|
||||
|
||||
# Static files should be collected to a local directory and then uploaded to S3
|
||||
STATIC_ROOT = BASE_DIR / 'collectedstaticfiles'
|
||||
|
||||
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
|
||||
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
|
||||
AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
|
||||
AWS_S3_REGION_NAME = os.getenv('AWS_S3_REGION_NAME', 'us-east-1') # Default to 'us-east-1' if not set
|
||||
AWS_S3_SIGNATURE_VERSION = 's3v4' # Use AWS Signature Version 4
|
||||
AWS_S3_USE_SSL = True
|
||||
AWS_S3_FILE_OVERWRITE = True
|
||||
AWS_DEFAULT_ACL = None # Set to None to avoid setting a default ACL
|
||||
|
||||
|
||||
|
||||
print(f"Static url: {STATIC_URL}\nStatic storage: {STORAGES}\n----------------------------")
|
||||
|
||||
#--------------------------------END: MEDIA + STATIC 🖼️, AWS ☁️---------------------------------
|
||||
|
||||
|
||||
|
||||
#-------------------------------------TINY MCE ✍️------------------------------------
|
||||
|
||||
TINYMCE_JS_URL = 'https://cdn.tiny.cloud/1/no-api-key/tinymce/7/tinymce.min.js'
|
||||
|
||||
TINYMCE_DEFAULT_CONFIG = {
|
||||
"height": "320px",
|
||||
"width": "960px",
|
||||
"menubar": "file edit view insert format tools table help",
|
||||
"plugins": "advlist autolink lists link image charmap print preview anchor searchreplace visualblocks code "
|
||||
"fullscreen insertdatetime media table paste code help wordcount spellchecker",
|
||||
"toolbar": "undo redo | bold italic underline strikethrough | fontselect fontsizeselect formatselect | alignleft "
|
||||
"aligncenter alignright alignjustify | outdent indent | numlist bullist checklist | forecolor "
|
||||
"backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap emoticons | "
|
||||
"fullscreen preview save print | insertfile image media pageembed template link anchor codesample | "
|
||||
"a11ycheck ltr rtl | showcomments addcomment code",
|
||||
"custom_undo_redo_levels": 10,
|
||||
}
|
||||
TINYMCE_SPELLCHECKER = True
|
||||
TINYMCE_COMPRESSOR = True
|
||||
|
||||
#--------------------------------END-TINY-MCE-SECTION ✍️---------------------------------
|
||||
|
||||
|
||||
|
||||
#-------------------------------------DRF SPECTACULAR 📊------------------------------------
|
||||
|
||||
SPECTACULAR_DEFAULTS: Dict[str, Any] = {
|
||||
# A regex specifying the common denominator for all operation paths. If
|
||||
# SCHEMA_PATH_PREFIX is set to None, drf-spectacular will attempt to estimate
|
||||
# a common prefix. Use '' to disable.
|
||||
# Mainly used for tag extraction, where paths like '/api/v1/albums' with
|
||||
# a SCHEMA_PATH_PREFIX regex '/api/v[0-9]' would yield the tag 'albums'.
|
||||
'SCHEMA_PATH_PREFIX': None,
|
||||
|
||||
# Remove matching SCHEMA_PATH_PREFIX from operation path. Usually used in
|
||||
# conjunction with appended prefixes in SERVERS.
|
||||
'SCHEMA_PATH_PREFIX_TRIM': False,
|
||||
|
||||
# Insert a manual path prefix to the operation path, e.g. '/service/backend'.
|
||||
# Use this for example to align paths when the API is mounted as a sub-resource
|
||||
# behind a proxy and Django is not aware of that. Alternatively, prefixes can
|
||||
# also specified via SERVERS, but this makes the operation path more explicit.
|
||||
'SCHEMA_PATH_PREFIX_INSERT': '',
|
||||
|
||||
# Coercion of {pk} to {id} is controlled by SCHEMA_COERCE_PATH_PK. Additionally,
|
||||
# some libraries (e.g. drf-nested-routers) use "_pk" suffixed path variables.
|
||||
# This setting globally coerces path variables like "{user_pk}" to "{user_id}".
|
||||
'SCHEMA_COERCE_PATH_PK_SUFFIX': False,
|
||||
|
||||
# Schema generation parameters to influence how components are constructed.
|
||||
# Some schema features might not translate well to your target.
|
||||
# Demultiplexing/modifying components might help alleviate those issues.
|
||||
'DEFAULT_GENERATOR_CLASS': 'drf_spectacular.generators.SchemaGenerator',
|
||||
|
||||
# Create separate components for PATCH endpoints (without required list)
|
||||
'COMPONENT_SPLIT_PATCH': True,
|
||||
|
||||
# Split components into request and response parts where appropriate
|
||||
# This setting is highly recommended to achieve the most accurate API
|
||||
# description, however it comes at the cost of having more components.
|
||||
'COMPONENT_SPLIT_REQUEST': True,
|
||||
|
||||
# Aid client generator targets that have trouble with read-only properties.
|
||||
'COMPONENT_NO_READ_ONLY_REQUIRED': False,
|
||||
|
||||
# Adds "minLength: 1" to fields that do not allow blank strings. Deactivated
|
||||
# by default because serializers do not strictly enforce this on responses and
|
||||
# so "minLength: 1" may not always accurately describe API behavior.
|
||||
# Gets implicitly enabled by COMPONENT_SPLIT_REQUEST, because this can be
|
||||
# accurately modeled when request and response components are separated.
|
||||
'ENFORCE_NON_BLANK_FIELDS': False,
|
||||
|
||||
# This version string will end up the in schema header. The default OpenAPI
|
||||
# version is 3.0.3, which is heavily tested. We now also support 3.1.0,
|
||||
# which contains the same features and a few mandatory, but minor changes.
|
||||
'OAS_VERSION': '3.0.3',
|
||||
|
||||
# Configuration for serving a schema subset with SpectacularAPIView
|
||||
'SERVE_URLCONF': None,
|
||||
|
||||
# complete public schema or a subset based on the requesting user
|
||||
'SERVE_PUBLIC': True,
|
||||
|
||||
# include schema endpoint into schema
|
||||
'SERVE_INCLUDE_SCHEMA': True,
|
||||
|
||||
# list of authentication/permission classes for spectacular's views.
|
||||
'SERVE_PERMISSIONS': ['rest_framework.permissions.AllowAny'], #account.permissions.AdminOnly
|
||||
|
||||
# None will default to DRF's AUTHENTICATION_CLASSES
|
||||
'SERVE_AUTHENTICATION': None,
|
||||
|
||||
# Dictionary of general configuration to pass to the SwaggerUI({ ... })
|
||||
# https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/
|
||||
# The settings are serialized with json.dumps(). If you need customized JS, use a
|
||||
# string instead. The string must then contain valid JS and is passed unchanged.
|
||||
'SWAGGER_UI_SETTINGS': {
|
||||
'deepLinking': True,
|
||||
},
|
||||
|
||||
# Initialize SwaggerUI with additional OAuth2 configuration.
|
||||
# https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/
|
||||
'SWAGGER_UI_OAUTH2_CONFIG': {},
|
||||
|
||||
# Dictionary of general configuration to pass to the Redoc.init({ ... })
|
||||
# https://redocly.com/docs/redoc/config/#functional-settings
|
||||
# The settings are serialized with json.dumps(). If you need customized JS, use a
|
||||
# string instead. The string must then contain valid JS and is passed unchanged.
|
||||
'REDOC_UI_SETTINGS': {},
|
||||
|
||||
# CDNs for swagger and redoc. You can change the version or even host your
|
||||
# own depending on your requirements. For self-hosting, have a look at
|
||||
# the sidecar option in the README.
|
||||
'SWAGGER_UI_DIST': 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@latest',
|
||||
'SWAGGER_UI_FAVICON_HREF': 'https://cdn.jsdelivr.net/npm/swagger-ui-dist@latest/favicon-32x32.png',
|
||||
'REDOC_DIST': 'https://cdn.jsdelivr.net/npm/redoc@latest',
|
||||
|
||||
# Append OpenAPI objects to path and components in addition to the generated objects
|
||||
'APPEND_PATHS': {},
|
||||
'APPEND_COMPONENTS': {},
|
||||
|
||||
|
||||
# Postprocessing functions that run at the end of schema generation.
|
||||
# must satisfy interface result = hook(generator, request, public, result)
|
||||
'POSTPROCESSING_HOOKS': [
|
||||
'drf_spectacular.hooks.postprocess_schema_enums'
|
||||
],
|
||||
|
||||
# Preprocessing functions that run before schema generation.
|
||||
# must satisfy interface result = hook(endpoints=result) where result
|
||||
# is a list of Tuples (path, path_regex, method, callback).
|
||||
# Example: 'drf_spectacular.hooks.preprocess_exclude_path_format'
|
||||
'PREPROCESSING_HOOKS': [],
|
||||
|
||||
# Determines how operations should be sorted. If you intend to do sorting with a
|
||||
# PREPROCESSING_HOOKS, be sure to disable this setting. If configured, the sorting
|
||||
# is applied after the PREPROCESSING_HOOKS. Accepts either
|
||||
# True (drf-spectacular's alpha-sorter), False, or a callable for sort's key arg.
|
||||
'SORT_OPERATIONS': True,
|
||||
|
||||
# enum name overrides. dict with keys "YourEnum" and their choice values "field.choices"
|
||||
# e.g. {'SomeEnum': ['A', 'B'], 'OtherEnum': 'import.path.to.choices'}
|
||||
'ENUM_NAME_OVERRIDES': {},
|
||||
|
||||
# Adds "blank" and "null" enum choices where appropriate. disable on client generation issues
|
||||
'ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE': True,
|
||||
|
||||
# Add/Append a list of (``choice value`` - choice name) to the enum description string.
|
||||
'ENUM_GENERATE_CHOICE_DESCRIPTION': True,
|
||||
|
||||
# Optional suffix for generated enum.
|
||||
# e.g. {'ENUM_SUFFIX': "Type"} would produce an enum name 'StatusType'.
|
||||
'ENUM_SUFFIX': 'Enum',
|
||||
|
||||
# function that returns a list of all classes that should be excluded from doc string extraction
|
||||
'GET_LIB_DOC_EXCLUDES': 'drf_spectacular.plumbing.get_lib_doc_excludes',
|
||||
|
||||
# Function that returns a mocked request for view processing. For CLI usage
|
||||
# original_request will be None.
|
||||
# interface: request = build_mock_request(method, path, view, original_request, **kwargs)
|
||||
'GET_MOCK_REQUEST': 'drf_spectacular.plumbing.build_mock_request',
|
||||
|
||||
# Camelize names like "operationId" and path parameter names
|
||||
# Camelization of the operation schema itself requires the addition of
|
||||
# 'drf_spectacular.contrib.djangorestframework_camel_case.camelize_serializer_fields'
|
||||
# to POSTPROCESSING_HOOKS. Please note that the hook depends on
|
||||
# ``djangorestframework_camel_case``, while CAMELIZE_NAMES itself does not.
|
||||
'CAMELIZE_NAMES': False,
|
||||
|
||||
# Changes the location of the action/method on the generated OperationId. For example,
|
||||
# "POST": "group_person_list", "group_person_create"
|
||||
# "PRE": "list_group_person", "create_group_person"
|
||||
'OPERATION_ID_METHOD_POSITION': 'POST',
|
||||
|
||||
# Determines if and how free-form 'additionalProperties' should be emitted in the schema. Some
|
||||
# code generator targets are sensitive to this. None disables generic 'additionalProperties'.
|
||||
# allowed values are 'dict', 'bool', None
|
||||
'GENERIC_ADDITIONAL_PROPERTIES': 'dict',
|
||||
|
||||
# Path converter schema overrides (e.g. <int:foo>). Can be used to either modify default
|
||||
# behavior or provide a schema for custom converters registered with register_converter(...).
|
||||
# Takes converter labels as keys and either basic python types, OpenApiType, or raw schemas
|
||||
# as values. Example: {'aint': OpenApiTypes.INT, 'bint': str, 'cint': {'type': ...}}
|
||||
'PATH_CONVERTER_OVERRIDES': {},
|
||||
|
||||
# Determines whether operation parameters should be sorted alphanumerically or just in
|
||||
# the order they arrived. Accepts either True, False, or a callable for sort's key arg.
|
||||
'SORT_OPERATION_PARAMETERS': True,
|
||||
|
||||
# @extend_schema allows to specify status codes besides 200. This functionality is usually used
|
||||
# to describe error responses, which rarely make use of list mechanics. Therefore, we suppress
|
||||
# listing (pagination and filtering) on non-2XX status codes by default. Toggle this to enable
|
||||
# list responses with ListSerializers/many=True irrespective of the status code.
|
||||
'ENABLE_LIST_MECHANICS_ON_NON_2XX': False,
|
||||
|
||||
# This setting allows you to deviate from the default manager by accessing a different model
|
||||
# property. We use "objects" by default for compatibility reasons. Using "_default_manager"
|
||||
# will likely fix most issues, though you are free to choose any name.
|
||||
"DEFAULT_QUERY_MANAGER": 'objects',
|
||||
|
||||
# Controls which authentication methods are exposed in the schema. If not None, will hide
|
||||
# authentication classes that are not contained in the whitelist. Use full import paths
|
||||
# like ['rest_framework.authentication.TokenAuthentication', ...].
|
||||
# Empty list ([]) will hide all authentication methods. The default None will show all.
|
||||
'AUTHENTICATION_WHITELIST': None,
|
||||
# Controls which parsers are exposed in the schema. Works analog to AUTHENTICATION_WHITELIST.
|
||||
# List of allowed parsers or None to allow all.
|
||||
'PARSER_WHITELIST': None,
|
||||
# Controls which renderers are exposed in the schema. Works analog to AUTHENTICATION_WHITELIST.
|
||||
# rest_framework.renderers.BrowsableAPIRenderer is ignored by default if whitelist is None
|
||||
'RENDERER_WHITELIST': None,
|
||||
|
||||
# Option for turning off error and warn messages
|
||||
'DISABLE_ERRORS_AND_WARNINGS': False,
|
||||
|
||||
# Runs exemplary schema generation and emits warnings as part of "./manage.py check --deploy"
|
||||
'ENABLE_DJANGO_DEPLOY_CHECK': True,
|
||||
|
||||
# General schema metadata. Refer to spec for valid inputs
|
||||
# https://spec.openapis.org/oas/v3.0.3#openapi-object
|
||||
'TITLE': 'e-Tržnice API',
|
||||
'DESCRIPTION': 'This is the API documentation for e-Tržnice.',
|
||||
'TOS': None,
|
||||
# Optional: MAY contain "name", "url", "email"
|
||||
'CONTACT': {},
|
||||
# Optional: MUST contain "name", MAY contain URL
|
||||
|
||||
'LICENSE': {},
|
||||
# Statically set schema version. May also be an empty string. When used together with
|
||||
# view versioning, will become '0.0.0 (v2)' for 'v2' versioned requests.
|
||||
# Set VERSION to None if only the request version should be rendered.
|
||||
'VERSION': '1.0.0',
|
||||
# Optional list of servers.
|
||||
# Each entry MUST contain "url", MAY contain "description", "variables"
|
||||
# e.g. [{'url': 'https://example.com/v1', 'description': 'Text'}, ...]
|
||||
'SERVERS': [],
|
||||
# Tags defined in the global scope
|
||||
'TAGS': [],
|
||||
# Optional: List of OpenAPI 3.1 webhooks. Each entry should be an import path to an
|
||||
# OpenApiWebhook instance.
|
||||
'WEBHOOKS': [],
|
||||
# Optional: MUST contain 'url', may contain "description"
|
||||
'EXTERNAL_DOCS': {},
|
||||
|
||||
# Arbitrary specification extensions attached to the schema's info object.
|
||||
# https://swagger.io/specification/#specification-extensions
|
||||
'EXTENSIONS_INFO': {},
|
||||
|
||||
# Arbitrary specification extensions attached to the schema's root object.
|
||||
# https://swagger.io/specification/#specification-extensions
|
||||
'EXTENSIONS_ROOT': {},
|
||||
|
||||
# Oauth2 related settings. used for example by django-oauth2-toolkit.
|
||||
# https://spec.openapis.org/oas/v3.0.3#oauth-flows-object
|
||||
'OAUTH2_FLOWS': [],
|
||||
'OAUTH2_AUTHORIZATION_URL': None,
|
||||
'OAUTH2_TOKEN_URL': None,
|
||||
'OAUTH2_REFRESH_URL': None,
|
||||
'OAUTH2_SCOPES': None,
|
||||
}
|
||||
Reference in New Issue
Block a user