adding
This commit is contained in:
+88
-70
@@ -1,11 +1,10 @@
|
||||
# config/settings.py
|
||||
"""
|
||||
تنظیمات جنگو برای بکاند «پیامکبان».
|
||||
همهی مقادیر حساس/محیطی از .env خوانده میشوند (با python-decouple) تا برای
|
||||
بالا آوردن روی هر سروری فقط کافی باشد یک فایل .env ساخته شود؛ نیازی به تغییر
|
||||
کد نیست.
|
||||
تنظیمات جنگو برای پروژه «شاپشیپ».
|
||||
همهی مقادیر حساس/محیطی از .env خوانده میشوند.
|
||||
"""
|
||||
|
||||
import os
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
|
||||
@@ -13,24 +12,26 @@ from decouple import Config, Csv, RepositoryEnv
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# مسیر .env را عمداً صریح میدهیم (نه decouple.config پیشفرض که بر اساس
|
||||
# فریم صدازننده حدس میزند) — آن حدسِ مبتنیبر عمقِ استک، بسته به اینکه
|
||||
# جنگو از کجا اجرا شود (manage.py check در برابر gunicorn در برابر
|
||||
# manage.py shell)، میتواند مسیر اشتباه را پیدا کند و بیصدا از مقادیر
|
||||
# default() استفاده کند — یعنی .env واقعی هیچوقت خوانده نمیشود.
|
||||
# ============================================
|
||||
# بارگذاری فایل .env
|
||||
# ============================================
|
||||
_env_path = BASE_DIR / ".env"
|
||||
if not _env_path.exists():
|
||||
raise RuntimeError(
|
||||
f"فایل .env پیدا نشد ({_env_path}) — یکبار «cp .env.example .env» بزن و مقادیر واقعی را پر کن."
|
||||
f"❌ فایل .env پیدا نشد ({_env_path}) — لطفاً یک فایل .env ایجاد کنید."
|
||||
)
|
||||
config = Config(RepositoryEnv(str(_env_path)))
|
||||
|
||||
# -------------------- امنیت و محیط اجرا --------------------
|
||||
SECRET_KEY = config("SECRET_KEY", default="django-insecure-change-me-in-production")
|
||||
DEBUG = config("DEBUG", default=False, cast=bool)
|
||||
# ============================================
|
||||
# امنیت و محیط اجرا
|
||||
# ============================================
|
||||
SECRET_KEY = config("SECRET_KEY")
|
||||
DEBUG = False
|
||||
ALLOWED_HOSTS = config("ALLOWED_HOSTS", default="localhost,127.0.0.1", cast=Csv())
|
||||
|
||||
# -------------------- اپلیکیشنها --------------------
|
||||
# ============================================
|
||||
# اپلیکیشنها
|
||||
# ============================================
|
||||
DJANGO_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
@@ -60,6 +61,9 @@ LOCAL_APPS = [
|
||||
|
||||
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
|
||||
|
||||
# ============================================
|
||||
# Middleware
|
||||
# ============================================
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
@@ -75,6 +79,9 @@ MIDDLEWARE = [
|
||||
ROOT_URLCONF = "config.urls"
|
||||
WSGI_APPLICATION = "config.wsgi.application"
|
||||
|
||||
# ============================================
|
||||
# Templates
|
||||
# ============================================
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
@@ -91,44 +98,43 @@ TEMPLATES = [
|
||||
},
|
||||
]
|
||||
|
||||
# -------------------- دیتابیس --------------------
|
||||
# پیشفرض SQLite (بدون نیاز به .env برای اجرای محلی)؛ برای پروداکشن/داکر با
|
||||
# گذاشتن DB_ENGINE=django.db.backends.postgresql در .env به PostgreSQL سوییچ کن.
|
||||
if config("DB_ENGINE", default="django.db.backends.sqlite3") == "django.db.backends.sqlite3":
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
}
|
||||
}
|
||||
else:
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": config("DB_ENGINE"),
|
||||
"NAME": config("DB_NAME"),
|
||||
"USER": config("DB_USER"),
|
||||
"PASSWORD": config("DB_PASSWORD"),
|
||||
"HOST": config("DB_HOST", default="localhost"),
|
||||
"PORT": config("DB_PORT", default="5432"),
|
||||
}
|
||||
# ============================================
|
||||
# Database
|
||||
# ============================================
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": config("DB_ENGINE", default="django.db.backends.sqlite3"),
|
||||
"NAME": config("DB_NAME", default=BASE_DIR / "db.sqlite3"),
|
||||
"USER": config("DB_USER", default=""),
|
||||
"PASSWORD": config("DB_PASSWORD", default=""),
|
||||
"HOST": config("DB_HOST", default=""),
|
||||
"PORT": config("DB_PORT", default=""),
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Auth
|
||||
# ============================================
|
||||
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"},
|
||||
]
|
||||
|
||||
AUTH_USER_MODEL = "account.User"
|
||||
|
||||
# -------------------- بینالملل --------------------
|
||||
# ============================================
|
||||
# بینالملل
|
||||
# ============================================
|
||||
LANGUAGE_CODE = "fa-ir"
|
||||
TIME_ZONE = "Asia/Tehran"
|
||||
USE_I18N = True
|
||||
USE_TZ = True
|
||||
|
||||
# -------------------- فایلهای استاتیک --------------------
|
||||
# استاتیک (CSS/JS پنل ادمین و غیره) را WhiteNoise middleware سرو میکند —
|
||||
# چه DEBUG=True چه False، بدون نیاز به تغییری در urls.py.
|
||||
# ============================================
|
||||
# فایلهای استاتیک
|
||||
# ============================================
|
||||
STATIC_URL = "/static/"
|
||||
STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||
STORAGES = {
|
||||
@@ -137,34 +143,30 @@ STORAGES = {
|
||||
},
|
||||
}
|
||||
|
||||
# -------------------- لندینگپیج --------------------
|
||||
# پوشهی landing/ (HTML/CSS ساده، بدون build step) دقیقا از ریشهی دامنه
|
||||
# سرو میشود — یعنی landing/index.html روی «/»، landing/articles/index.html
|
||||
# روی «/articles/» و غیره؛ همان WhiteNoise که استاتیک را سرو میکند، این
|
||||
# را هم سرو میکند، بدون نیاز به هیچ view یا route دستی در urls.py.
|
||||
# ============================================
|
||||
# Landing Page
|
||||
# ============================================
|
||||
WHITENOISE_ROOT = BASE_DIR / "landing"
|
||||
WHITENOISE_INDEX_FILE = True
|
||||
|
||||
# -------------------- فایلهای رسانه (آپلودی) --------------------
|
||||
# فعلا هیچ مدلی ImageField/FileField ندارد، ولی مسیرش را از الان آماده
|
||||
# میکنیم. برخلاف استاتیک، WhiteNoise رسانه را سرو نمیکند — سروش در
|
||||
# urls.py و فقط برای DEBUG=True است (dev)؛ در production باید Nginx/سرور
|
||||
# وب مستقیم از MEDIA_ROOT سرو کند، نه خودِ جنگو.
|
||||
# ============================================
|
||||
# فایلهای رسانه
|
||||
# ============================================
|
||||
MEDIA_URL = "/media/"
|
||||
MEDIA_ROOT = BASE_DIR / "media"
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
# -------------------- CORS --------------------
|
||||
# ============================================
|
||||
# CORS
|
||||
# ============================================
|
||||
CORS_ALLOWED_ORIGINS = config("CORS_ALLOWED_ORIGINS", default="", cast=Csv())
|
||||
CORS_ALLOW_ALL_ORIGINS = config("CORS_ALLOW_ALL_ORIGINS", default=False, cast=bool)
|
||||
|
||||
# دامنههای مجاز برای پنل ادمین (فرمهای session-cookie/CSRF جنگو، برخلاف
|
||||
# JWT API که این محدودیت را ندارد) — بدون این، پشت HTTPS/دامنهی واقعی، لاگین
|
||||
# ادمین با خطای «CSRF verification failed» رد میشود.
|
||||
CSRF_TRUSTED_ORIGINS = config("CSRF_TRUSTED_ORIGINS", default="", cast=Csv())
|
||||
|
||||
# -------------------- Django REST Framework --------------------
|
||||
# ============================================
|
||||
# Django REST Framework
|
||||
# ============================================
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||
@@ -182,6 +184,9 @@ REST_FRAMEWORK = {
|
||||
},
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Simple JWT
|
||||
# ============================================
|
||||
SIMPLE_JWT = {
|
||||
"ACCESS_TOKEN_LIFETIME": timedelta(days=config("JWT_ACCESS_LIFETIME_DAYS", default=1, cast=int)),
|
||||
"REFRESH_TOKEN_LIFETIME": timedelta(days=config("JWT_REFRESH_LIFETIME_DAYS", default=30, cast=int)),
|
||||
@@ -191,38 +196,51 @@ SIMPLE_JWT = {
|
||||
"USER_ID_CLAIM": "user_id",
|
||||
}
|
||||
|
||||
# -------------------- پیامک (OTP) --------------------
|
||||
# فقط دو مقدار لازم است: نام قالب/پترن پیام و آدرس سرویس ارسال (توکن).
|
||||
# اگر بخواهی خودت payload را با سرویسدهندهات هماهنگ کنی، apps/account/send_sms.py را ببین.
|
||||
SMS_PATTERN_NAME = config("SMS_PATTERN_NAME", default="")
|
||||
# ============================================
|
||||
# ✅ تنظیمات پیامک (فقط OTP با کاوهنگار)
|
||||
# ============================================
|
||||
KAVENEGAR_API_KEY = config("KAVENEGAR_API_KEY", default="")
|
||||
SMS_PATTERN_NAME = config("SMS_PATTERN_NAME", default="shopshipotp")
|
||||
|
||||
# برای سازگاری با کدهای قدیمی (استفاده نمیشود)
|
||||
SMS_TOKEN_URL = config("SMS_TOKEN_URL", default="")
|
||||
|
||||
# -------------------- ارسال گروهی چندکاناله (apps.messaging) --------------------
|
||||
# هرکدام خالی بماند، همان کانال بهجای ارسال خودکار needs_manual برمیگرداند
|
||||
# (صف deep-link سمت اپ) — نه خطا، دقیقا مثل رفتار SMS_TOKEN_URL بالا.
|
||||
|
||||
# پیامک بالک با متن آزاد — جدا از SMS_PATTERN_NAME/SMS_TOKEN_URL که فقط OTP است.
|
||||
KAVENEGAR_API_KEY = config("KAVENEGAR_API_KEY", default="")
|
||||
# ============================================
|
||||
# تنظیمات کانالهای پیامرسان (در صورت نیاز)
|
||||
# ============================================
|
||||
KAVENEGAR_SENDER_LINE = config("KAVENEGAR_SENDER_LINE", default="")
|
||||
|
||||
# WhatsApp Business Cloud API رسمی (Meta) — نیاز به Template تاییدشده دارد.
|
||||
WHATSAPP_ACCESS_TOKEN = config("WHATSAPP_ACCESS_TOKEN", default="")
|
||||
WHATSAPP_PHONE_NUMBER_ID = config("WHATSAPP_PHONE_NUMBER_ID", default="")
|
||||
WHATSAPP_TEMPLATE_NAME = config("WHATSAPP_TEMPLATE_NAME", default="")
|
||||
|
||||
# Bot API رسمی هرکدام — فقط برای مخاطبینی که قبلا با بات چت را شروع کردهاند.
|
||||
TELEGRAM_BOT_TOKEN = config("TELEGRAM_BOT_TOKEN", default="")
|
||||
BALE_BOT_TOKEN = config("BALE_BOT_TOKEN", default="")
|
||||
EITAA_BOT_TOKEN = config("EITAA_BOT_TOKEN", default="")
|
||||
|
||||
# ============================================
|
||||
# لاگینگ
|
||||
# ============================================
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"handlers": {
|
||||
"console": {"class": "logging.StreamHandler"},
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"apps.account": {
|
||||
"handlers": ["console"],
|
||||
"level": "DEBUG",
|
||||
"propagate": True,
|
||||
},
|
||||
"django": {
|
||||
"handlers": ["console"],
|
||||
"level": "INFO",
|
||||
"propagate": True,
|
||||
},
|
||||
},
|
||||
"root": {
|
||||
"handlers": ["console"],
|
||||
"level": "INFO",
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user