from decouple import config from pathlib import Path import os BASE_DIR = Path(__file__).resolve().parent.parent.parent SECRET_KEY = config('SECRET_KEY') DEBUG = config('DEBUG', default=False, cast=bool) ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='').split(',') DJANGO_APPS = [ 'unfold', 'unfold.contrib.filters', 'unfold.contrib.forms', 'unfold.contrib.import_export', 'unfold.contrib.location_field', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] THIRD_PARTY_APPS = [ 'corsheaders', 'import_export', 'simplemde', 'location_field', "django_prometheus", ] LOCAL_APPS = [ "core", "apps.users", "apps.notifications", "apps.blog", "apps.gallery", "apps.events", "apps.certificates", "apps.communications", "apps.payments", ] INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS MIDDLEWARE = [ "django_prometheus.middleware.PrometheusBeforeMiddleware", 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', "django_prometheus.middleware.PrometheusAfterMiddleware", ] ROOT_URLCONF = 'config.urls' 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', ], }, }, ] WSGI_APPLICATION = 'config.wsgi.application' # Database DATABASES = { 'default': { 'ENGINE': config('DB_ENGINE', 'django.db.backends.sqlite3'), 'NAME': config('DB_NAME', BASE_DIR / 'db.sqlite3'), 'USER': config('DB_USER'), 'PASSWORD': config('DB_PASSWORD'), 'HOST': config('DB_HOST', default='localhost'), 'PORT': config('DB_PORT', default='5432'), } } # Password validation 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', }, ] LANGUAGE_CODE = 'en-us' TIME_ZONE = 'Asia/Tehran' LANGUAGES = [ ('en', 'English'), ('fa', 'فارسی'), ] USE_I18N = True USE_L10N = True USE_TZ = True # For RTL support in admin LOCALE_PATHS = [BASE_DIR / 'locale'] STATIC_URL = config('STATIC_URL', default='/static/') STATIC_ROOT = BASE_DIR / 'staticfiles' STATICFILES_DIRS = [BASE_DIR / 'static'] MEDIA_URL = config('MEDIA_URL', default='/media/') MEDIA_ROOT = BASE_DIR / 'media' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' AUTH_USER_MODEL = 'users.User' # CORS / CSRF Settings CORS_ALLOWED_ORIGINS = config( 'CORS_ALLOWED_ORIGINS', default='https://east-guilan-ce.ir', ).split(',') CORS_ALLOW_CREDENTIALS = config('CORS_ALLOW_CREDENTIALS', default=True, cast=bool) CSRF_TRUSTED_ORIGINS = config( 'CSRF_TRUSTED_ORIGINS', default='https://east-guilan-ce.ir', ).split(',') CSRF_COOKIE_SECURE = config('CSRF_COOKIE_SECURE', default=True, cast=bool) SESSION_COOKIE_SECURE = config('SESSION_COOKIE_SECURE', default=True, cast=bool) # Email Configuration EMAIL_BACKEND = config('EMAIL_BACKEND', default='django.core.mail.backends.console.EmailBackend') EMAIL_HOST = config('EMAIL_HOST', default='') EMAIL_PORT = config('EMAIL_PORT', default=587, cast=int) EMAIL_USE_SSL = config('EMAIL_USE_SSL', default=False, cast=bool) EMAIL_USE_TLS = config('EMAIL_USE_TLS', default=True, cast=bool) EMAIL_HOST_USER = config('EMAIL_HOST_USER', default='') EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', default='') DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', default='webmaster@localhost') SMS_APIKEY = config('SMS_APIKEY', default='') SMS_AUTH_OTP_TEMPLATE_ID = config('SMS_AUTH_OTP_TEMPLATE_ID', default='') SMS_EVENT_CANCELLATION_TEMPLATE_ID = config('SMS_EVENT_CANCELLATION_TEMPLATE_ID', default='') SMS_EVENT_RESCHEDULE_TEMPLATE_ID = config('SMS_EVENT_RESCHEDULE_TEMPLATE_ID', default='') SMS_PAYMENT_STATUS_TEMPLATE_ID = config('SMS_PAYMENT_STATUS_TEMPLATE_ID', default='') # JWT Configuration JWT_SECRET_KEY = config('JWT_SECRET_KEY', default=SECRET_KEY) JWT_ALGORITHM = config('JWT_ALGORITHM', default='HS256') JWT_ACCESS_TOKEN_LIFETIME = config('JWT_ACCESS_TOKEN_LIFETIME', default=3600, cast=int) JWT_REFRESH_TOKEN_LIFETIME = config('JWT_REFRESH_TOKEN_LIFETIME', default=86400, cast=int) # Redis Configuration REDIS_URL = config('REDIS_URL', default='redis://localhost:6379/0') # Cache Configuration CACHES = { 'default': { 'BACKEND': 'django_prometheus.cache.backends.redis.RedisCache', 'LOCATION': REDIS_URL, } } # Celery Configuration CELERY_BROKER_URL = config('CELERY_BROKER_URL', default=REDIS_URL) CELERY_RESULT_BACKEND = config('CELERY_RESULT_BACKEND', default=REDIS_URL) # Logging Configuration LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'verbose': { 'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}', 'style': '{', }, 'simple': { 'format': '{levelname} {message}', 'style': '{', }, }, 'handlers': { 'file': { 'level': 'INFO', 'class': 'logging.FileHandler', 'filename': BASE_DIR / 'logs' / 'django.log', 'formatter': 'verbose', }, 'console': { 'level': 'INFO', 'class': 'logging.StreamHandler', 'formatter': 'simple', }, }, 'root': { 'handlers': ['console'], 'level': 'INFO', }, 'loggers': { 'django': { 'handlers': ['file', 'console'], 'level': 'INFO', 'propagate': False, }, 'apps': { 'handlers': ['file', 'console'], 'level': 'INFO', 'propagate': False, }, }, } # Create logs directory os.makedirs(BASE_DIR / 'logs', exist_ok=True) BACKEND_ROOT = config('DJANGO_HOST', default='http://localhost:8000/') FRONTEND_ROOT = config('FRONTEND_ROOT', default='http://localhost:3000/') FRONTEND_PASSWORD_RESET_PAGE = config('FRONTEND_PASSWORD_RESET_PAGE', default='http://localhost:3000/api/auth/reset-password-confirm/') FRONTEND_CALLBACK_URL = config('FRONTEND_CALLBACK_URL', default='http://localhost:3000/payments/result') GOOGLE_OAUTH_CLIENT_ID = config('GOOGLE_OAUTH_CLIENT_ID', default='') GOOGLE_OAUTH_CLIENT_SECRET = config('GOOGLE_OAUTH_CLIENT_SECRET', default='') GOOGLE_OAUTH_REDIRECT_URI = config('GOOGLE_OAUTH_REDIRECT_URI', default='') GOOGLE_OAUTH_FRONTEND_CALLBACK_URL = config('GOOGLE_OAUTH_FRONTEND_CALLBACK_URL', default='http://localhost:8080/auth/google/callback') NOTIFICATIONS_ENABLED = config('NOTIFICATIONS_ENABLED', default=True, cast=bool) NOTIFICATION_STREAM_TOKEN_LIFETIME_SECONDS = config('NOTIFICATION_STREAM_TOKEN_LIFETIME_SECONDS', default=300, cast=int) NOTIFICATION_SSE_HEARTBEAT_SECONDS = config('NOTIFICATION_SSE_HEARTBEAT_SECONDS', default=20, cast=int) NOTIFICATION_SSE_RETRY_MS = config('NOTIFICATION_SSE_RETRY_MS', default=3000, cast=int) NOTIFICATION_REDIS_CHANNEL_PREFIX = config('NOTIFICATION_REDIS_CHANNEL_PREFIX', default='notif') NOTIFICATION_RETENTION_DAYS = config('NOTIFICATION_RETENTION_DAYS', default=30, cast=int) NOTIFICATION_DEFAULT_PAGE_SIZE = config('NOTIFICATION_DEFAULT_PAGE_SIZE', default=20, cast=int) NOTIFICATION_MAX_PAGE_SIZE = config('NOTIFICATION_MAX_PAGE_SIZE', default=100, cast=int) BLOG_ASSET_MAX_SIZE_MB = config('BLOG_ASSET_MAX_SIZE_MB', default=50, cast=int) BLOG_IMAGE_ASSET_MAX_SIZE_MB = config('BLOG_IMAGE_ASSET_MAX_SIZE_MB', default=10, cast=int) if DATABASES["default"]["ENGINE"] == "django.db.backends.postgresql": DATABASES["default"]["ENGINE"] = "django_prometheus.db.backends.postgresql" from config.services.unfold import * from config.services.location import * from config.services.notifications import * from config.services.zarinpal import *