249 lines
7.7 KiB
Python
249 lines
7.7 KiB
Python
import os
|
|
from datetime import timedelta
|
|
from pathlib import Path
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
|
|
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
|
|
|
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY")
|
|
|
|
DEBUG = os.getenv("DEBUG", "False").lower() in ("true", "1", "yes")
|
|
|
|
DJANGO_APPS = [
|
|
"unfold",
|
|
"unfold.contrib.filters",
|
|
"unfold.contrib.forms",
|
|
"unfold.contrib.import_export",
|
|
"django.contrib.admin",
|
|
"django.contrib.auth",
|
|
"django.contrib.contenttypes",
|
|
"django.contrib.sessions",
|
|
"django.contrib.messages",
|
|
"django.contrib.staticfiles",
|
|
]
|
|
|
|
THIRD_PARTY_APPS = [
|
|
"rest_framework",
|
|
"rest_framework_simplejwt",
|
|
"rest_framework.authtoken",
|
|
"rest_framework_simplejwt.token_blacklist",
|
|
"drf_spectacular",
|
|
"drf_spectacular_sidecar",
|
|
"django_filters",
|
|
"import_export",
|
|
"corsheaders",
|
|
"auditlog",
|
|
]
|
|
|
|
LOCAL_APPS = [
|
|
"apps.users",
|
|
"apps.workspaces",
|
|
"apps.clients",
|
|
"apps.projects",
|
|
"apps.tags",
|
|
"apps.time_entries",
|
|
"apps.notifications",
|
|
"apps.reports",
|
|
]
|
|
|
|
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
|
|
|
|
MIDDLEWARE = [
|
|
"django.middleware.security.SecurityMiddleware",
|
|
"corsheaders.middleware.CorsMiddleware",
|
|
"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",
|
|
"core.middlewares.current_user.CurrentUserMiddleware",
|
|
"core.middlewares.exception_logging.ExceptionLoggingMiddleware",
|
|
"config.services.logging.RequestLoggingMiddleware",
|
|
"auditlog.middleware.AuditlogMiddleware",
|
|
]
|
|
|
|
ROOT_URLCONF = "config.urls"
|
|
|
|
AUTH_USER_MODEL = "users.User"
|
|
|
|
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",
|
|
],
|
|
},
|
|
},
|
|
]
|
|
|
|
ASGI_APPLICATION = "config.asgi.application"
|
|
|
|
DATABASES = {
|
|
"default": {
|
|
"ENGINE": "django.db.backends.postgresql",
|
|
"NAME": os.getenv("POSTGRES_DB"),
|
|
"USER": os.getenv("POSTGRES_USER"),
|
|
"PASSWORD": os.getenv("POSTGRES_PASSWORD"),
|
|
"HOST": os.getenv("POSTGRES_HOST"),
|
|
"PORT": os.getenv("POSTGRES_PORT"),
|
|
"CONN_MAX_AGE": 0,
|
|
"DISABLE_SERVER_SIDE_CURSORS": True,
|
|
}
|
|
}
|
|
|
|
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",
|
|
},
|
|
]
|
|
|
|
REST_FRAMEWORK = {
|
|
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
|
"DEFAULT_AUTHENTICATION_CLASSES": [
|
|
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
|
],
|
|
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.AllowAny"],
|
|
"DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
|
|
"DATETIME_FORMAT": "%Y-%m-%d %H:%M",
|
|
"DATE_FORMAT": "%Y-%m-%d",
|
|
"DEFAULT_THROTTLE_CLASSES": [
|
|
"rest_framework.throttling.AnonRateThrottle",
|
|
"rest_framework.throttling.UserRateThrottle",
|
|
],
|
|
"EXCEPTION_HANDLER": "core.exceptions.handlers.exception_handler",
|
|
}
|
|
|
|
LANGUAGE_CODE = os.getenv("LANGUAGE_CODE", "en-us")
|
|
TIME_ZONE = os.getenv("TIME_ZONE", "Asia/Tehran")
|
|
USE_I18N = True
|
|
USE_TZ = True
|
|
|
|
STATIC_URL = "/static/"
|
|
STATIC_ROOT = BASE_DIR / "static"
|
|
MEDIA_URL = "/media/"
|
|
MEDIA_ROOT = BASE_DIR / "media"
|
|
|
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
|
|
|
SPECTACULAR_SETTINGS = {
|
|
"TITLE": "Qlockify.ir API Documentation",
|
|
"DESCRIPTION": "API documentation for Qlockify.ir",
|
|
"VERSION": "1.0.0",
|
|
"SERVE_INCLUDE_SCHEMA": True,
|
|
"SWAGGER_UI_SETTINGS": {
|
|
"deepLinking": True,
|
|
},
|
|
"COMPONENT_SPLIT_REQUEST": True,
|
|
"ENUM_NAME_OVERRIDES": {},
|
|
"TAG_SORTING": "alpha",
|
|
"SWAGGER_UI_DIST": "SIDECAR",
|
|
"SWAGGER_UI_FAVICON_HREF": "SIDECAR",
|
|
"REDOC_DIST": "SIDECAR",
|
|
}
|
|
|
|
JWT_ACCESS_TOKEN_LIFETIME = int(os.getenv("JWT_ACCESS_TOKEN_LIFETIME_MINUTES", 60))
|
|
JWT_REFRESH_TOKEN_LIFETIME = int(os.getenv("JWT_REFRESH_TOKEN_LIFETIME_DAYS", 7))
|
|
JWT_ROTATE_REFRESH_TOKENS = os.getenv("JWT_ROTATE_REFRESH_TOKENS", "True") == "True"
|
|
JWT_BLACKLIST_AFTER_ROTATION = os.getenv("JWT_BLACKLIST_AFTER_ROTATION", "True") == "True"
|
|
JWT_ALGORITHM = os.getenv("JWT_ALGORITHM", "HS256")
|
|
|
|
SIMPLE_JWT = {
|
|
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=JWT_ACCESS_TOKEN_LIFETIME),
|
|
"REFRESH_TOKEN_LIFETIME": timedelta(days=JWT_REFRESH_TOKEN_LIFETIME),
|
|
"ROTATE_REFRESH_TOKENS": JWT_ROTATE_REFRESH_TOKENS,
|
|
"BLACKLIST_AFTER_ROTATION": JWT_BLACKLIST_AFTER_ROTATION,
|
|
"ALGORITHM": JWT_ALGORITHM,
|
|
"SIGNING_KEY": SECRET_KEY,
|
|
"AUTH_HEADER_TYPES": ("Bearer",),
|
|
"AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
|
|
"USER_ID_FIELD": "id",
|
|
"USER_ID_CLAIM": "user_id",
|
|
}
|
|
|
|
REDIS_HOST = os.getenv("REDIS_HOST", "localhost")
|
|
REDIS_PORT = os.getenv("REDIS_PORT", "6379")
|
|
REDIS_PASSWORD = os.getenv("REDIS_PASSWORD", "")
|
|
|
|
if REDIS_PASSWORD:
|
|
REDIS_URL = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/0"
|
|
else:
|
|
REDIS_URL = f"redis://{REDIS_HOST}:{REDIS_PORT}/0"
|
|
|
|
CACHES = {
|
|
"default": {
|
|
"BACKEND": "django_redis.cache.RedisCache",
|
|
"LOCATION": REDIS_URL,
|
|
"OPTIONS": {
|
|
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
|
},
|
|
}
|
|
}
|
|
|
|
CELERY_BROKER_URL = os.getenv("CELERY_BROKER_URL", "redis://127.0.0.1:6379/0")
|
|
CELERY_RESULT_BACKEND = os.getenv("CELERY_RESULT_BACKEND", "redis://127.0.0.1:6379/1")
|
|
CELERY_ACCEPT_CONTENT = ["json"]
|
|
CELERY_TASK_SERIALIZER = "json"
|
|
CELERY_RESULT_SERIALIZER = "json"
|
|
CELERY_TASK_ALWAYS_EAGER = False
|
|
CELERY_TIMEZONE = os.getenv("TIME_ZONE")
|
|
CELERY_TASK_TRACK_STARTED = True
|
|
|
|
NOTIFICATIONS_ENABLED = os.getenv("NOTIFICATIONS_ENABLED", "True") == "True"
|
|
NOTIFICATION_STREAM_TOKEN_LIFETIME_SECONDS = int(
|
|
os.getenv("NOTIFICATION_STREAM_TOKEN_LIFETIME_SECONDS", "90")
|
|
)
|
|
NOTIFICATION_SSE_HEARTBEAT_SECONDS = int(
|
|
os.getenv("NOTIFICATION_SSE_HEARTBEAT_SECONDS", "20")
|
|
)
|
|
NOTIFICATION_SSE_RETRY_MS = int(os.getenv("NOTIFICATION_SSE_RETRY_MS", "5000"))
|
|
NOTIFICATION_DEFAULT_PAGE_SIZE = int(
|
|
os.getenv("NOTIFICATION_DEFAULT_PAGE_SIZE", "20")
|
|
)
|
|
NOTIFICATION_MAX_PAGE_SIZE = int(os.getenv("NOTIFICATION_MAX_PAGE_SIZE", "50"))
|
|
NOTIFICATION_REDIS_CHANNEL_PREFIX = os.getenv(
|
|
"NOTIFICATION_REDIS_CHANNEL_PREFIX", "notif:user"
|
|
)
|
|
NOTIFICATION_RETENTION_DAYS = int(os.getenv("NOTIFICATION_RETENTION_DAYS", "30"))
|
|
NOTIFICATION_TOAST_LEVELS = tuple(
|
|
level.strip()
|
|
for level in os.getenv(
|
|
"NOTIFICATION_TOAST_LEVELS", "info,success,warning,error"
|
|
).split(",")
|
|
if level.strip()
|
|
)
|
|
|
|
REPORT_EXPORT_RETENTION_DAYS = int(os.getenv("REPORT_EXPORT_RETENTION_DAYS", "7"))
|
|
|
|
CELERY_IMPORTS = ("apps.users.tasks", "apps.notifications.tasks", "apps.reports.tasks")
|
|
|
|
|
|
STORAGES = {
|
|
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
|
"images": {"BACKEND": "config.services.storage.UploadStorage"},
|
|
"staticfiles": {
|
|
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
|
|
},
|
|
}
|
|
|
|
SMS_APIKEY = os.getenv("SMS_APIKEY", "")
|
|
BASE_URL = os.getenv("BASE_URL", "")
|