initial commit

This commit is contained in:
2026-03-11 17:12:28 +08:00
commit 5d1e1cb7cb
61 changed files with 2971 additions and 0 deletions

215
config/settings/base.py Normal file
View File

@@ -0,0 +1,215 @@
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",
]
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", f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/1")
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_IMPORTS = ("apps.users.tasks",)
CELERY_TIMEZONE = os.getenv("TIME_ZONE")
CELERY_TASK_TRACK_STARTED = True
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", "")