Coverage for src/settings.py: 100%
77 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-09-21 16:24 +0300
« prev ^ index » next coverage.py v7.9.2, created at 2025-09-21 16:24 +0300
1import os
2from pathlib import Path
3from datetime import timedelta
5from django.utils.translation import gettext_lazy as _
6from decouple import config
8import cloudinary
9import cloudinary.uploader
10import cloudinary.api
12import sentry_sdk
14from .unfold import UNFOLD
16BASE_DIR = Path(__file__).resolve().parent.parent
18SECRET_KEY = os.getenv('SECRET_KEY', config('SECRET_KEY'))
20DEBUG = os.getenv('DEBUG', config('DEBUG')) == 'True'
22ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', config('ALLOWED_HOSTS')).split(',')
24CSRF_TRUSTED_ORIGINS = os.getenv(
25 'CSRF_TRUSTED_ORIGINS', config('CSRF_TRUSTED_ORIGINS', [])
26).split(',')
28CORS_ALLOWED_ORIGINS = os.getenv(
29 'CORS_ALLOWED_ORIGINS', config('CORS_ALLOWED_ORIGINS')
30).split(',')
32OPENAI_API_KEY = os.getenv(
33 'OPENAI_API_KEY', config('OPENAI_API_KEY')
34)
35PINECONE_API_KEY = os.getenv(
36 'PINECONE_API_KEY', config('PINECONE_API_KEY')
37)
38PINECONE_INDEX_NAME = os.getenv(
39 'PINECONE_INDEX_NAME', config('PINECONE_INDEX_NAME')
40)
41LANGSMITH_API_KEY = os.getenv(
42 'LANGSMITH_API_KEY', config('LANGSMITH_API_KEY')
43)
44LANGSMITH_TRACING = "true"
45LANGSMITH_ENDPOINT = "https://api.smith.langchain.com"
46LANGSMITH_PROJECT = "pr-impassioned-warfare-85"
48os.environ['OPENAI_API_KEY'] = OPENAI_API_KEY
49os.environ['LANGSMITH_API_KEY'] = LANGSMITH_API_KEY
50os.environ['LANGSMITH_ENDPOINT'] = LANGSMITH_ENDPOINT
51os.environ['PINECONE_API_KEY'] = PINECONE_API_KEY
52os.environ['PINECONE_INDEX_NAME'] = PINECONE_INDEX_NAME
53os.environ['LANGSMITH_TRACING_V2'] = 'true'
55# Custom Django applications in this project
56PROJECT_APPS = [
57 'src.accounts',
58 'src.chatbot',
59 'src.common',
60 'src.products',
61 'src.shopping_bags',
62 'src.wishlists',
63 'src.orders',
64]
66INSTALLED_APPS = [
67 'unfold',
68 'unfold.contrib.filters',
69 'unfold.contrib.forms',
70 'cloudinary',
71 'cloudinary_storage',
72 'django_celery_beat',
73 'daphne',
74 'django.contrib.admin',
75 'django.contrib.auth',
76 'django.contrib.contenttypes',
77 'django.contrib.sessions',
78 'django.contrib.messages',
79 'django.contrib.staticfiles',
80 'rest_framework',
81 'rest_framework_simplejwt',
82 'rest_framework_simplejwt.token_blacklist',
83 'corsheaders',
84 'drf_spectacular',
85] + PROJECT_APPS
87ASGI_APPLICATION = 'src.asgi.application'
89REST_FRAMEWORK = {
90 'DEFAULT_AUTHENTICATION_CLASSES': [
91 'rest_framework_simplejwt.authentication.JWTAuthentication',
92 ],
93 'DEFAULT_PERMISSION_CLASSES': [
94 'rest_framework.permissions.IsAuthenticated',
95 ],
96 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
98}
100SIMPLE_JWT = {
101 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),
102 'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
103}
105SPECTACULAR_SETTINGS = {
106 'TITLE': 'DRF React Gems',
107 'DESCRIPTION': 'E-commerce platform',
108 'VERSION': '1.0.0',
109}
111MIDDLEWARE = [
112 'corsheaders.middleware.CorsMiddleware',
113 'django.middleware.security.SecurityMiddleware',
114 'whitenoise.middleware.WhiteNoiseMiddleware',
115 'django.contrib.sessions.middleware.SessionMiddleware',
116 'django.middleware.common.CommonMiddleware',
117 'django.middleware.csrf.CsrfViewMiddleware',
118 'django.contrib.auth.middleware.AuthenticationMiddleware',
119 'django.contrib.messages.middleware.MessageMiddleware',
120 'django.middleware.clickjacking.XFrameOptionsMiddleware',
121]
123ROOT_URLCONF = 'src.urls'
125TEMPLATES = [
126 {
127 'BACKEND': 'django.template.backends.django.DjangoTemplates',
128 'DIRS': [BASE_DIR / 'templates'],
129 'APP_DIRS': True,
130 'OPTIONS': {
131 'context_processors': [
132 'django.template.context_processors.request',
133 'django.contrib.auth.context_processors.auth',
134 'django.contrib.messages.context_processors.messages',
135 ],
136 },
137 },
138]
140WSGI_APPLICATION = 'src.wsgi.application'
142AUTHENTICATION_BACKENDS = [
143 # Custom authentication backend
144 'src.accounts.authentication.CustomAuthBackendBackend',
145 'django.contrib.auth.backends.ModelBackend',
146]
148DATABASES = {
149 'default': {
150 'ENGINE': 'django.db.backends.postgresql',
151 'NAME': os.getenv('DB_NAME', config('DB_NAME')),
152 'USER': os.getenv('DB_USER', config('DB_USER')),
153 'PASSWORD': os.getenv('DB_PASS', config('DB_PASS')),
154 'HOST': os.getenv('DB_HOST', config('DB_HOST')),
155 'PORT': os.getenv('DB_PORT', config('DB_PORT')),
156 }
157}
159AUTH_PASSWORD_VALIDATORS = [
160 {
161 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
162 },
163 {
164 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
165 'OPTIONS': {'min_length': 6},
166 },
167 {
168 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
169 },
170 {
171 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
172 },
173 # Custom validators
174 {
175 'NAME': 'src.accounts.validators.password.DigitRequiredValidator',
176 },
177 {
178 'NAME': 'src.accounts.validators.password.UpperCaseLetterRequiredValidator',
179 },
180 {
181 'NAME': 'src.accounts.validators.password.LowerCaseLetterRequiredValidator',
182 },
183 {
184 'NAME': 'src.accounts.validators.password.NoWhiteSpacesRequiredValidator',
185 },
186 {
187 'NAME': 'src.accounts.validators.password.SpecialCharRequiredValidator',
188 },
189]
191AUTH_USER_MODEL = 'accounts.UserCredential'
193PASSWORD_RESET_TIMEOUT = 3600
195LANGUAGE_CODE = 'en-us'
196TIME_ZONE = 'UTC'
197USE_I18N = True
198USE_TZ = True
200STATIC_URL = 'static/'
201STATIC_ROOT = BASE_DIR / 'staticfiles'
203STATICFILES_DIRS = [
204 BASE_DIR / 'static',
205]
207STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
209STORAGES = {
210 "default": {
211 "BACKEND": "cloudinary_storage.storage.MediaCloudinaryStorage",
212 },
213 "staticfiles": {
214 "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
215 },
216}
218MEDIA_URL = 'media/'
219MEDIA_ROOT = BASE_DIR / 'mediafiles/'
221DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
223cloudinary.config(
224 cloud_name=os.getenv('CLOUD_NAME', config('CLOUD_NAME')),
225 api_key=os.getenv('CLOUD_API_KEY', config('CLOUD_API_KEY')),
226 api_secret=os.getenv('CLOUD_API_SECRET', config('CLOUD_API_SECRET')),
227)
229CELERY_BROKER_URL = os.getenv('CELERY_BROKER_URL', config('CELERY_BROKER_URL'))
230CELERY_RESULT_BACKEND = os.getenv(
231 'CELERY_RESULT_BACKEND', config('CELERY_RESULT_BACKEND')
232)
233CELERY_ACCEPT_CONTENT = ['application/json']
234CELERY_TASK_SERIALIZER = 'json'
235CELERY_RESULT_SERIALIZER = 'json'
236CELERY_TIMEZONE = TIME_ZONE
237CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'
238CELERY_BROKER_POOL_LIMIT = 2
239CELERY_RESULT_BACKEND_CONNECTION_RETRY_ON_STARTUP = True
241EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
242EMAIL_USE_TLS = True
243EMAIL_USE_SSL = False
244EMAIL_HOST = os.getenv('EMAIL_HOST', config('EMAIL_HOST'))
245EMAIL_PORT = os.getenv('EMAIL_PORT', config('EMAIL_PORT'))
246EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', config('EMAIL_HOST_USER'))
247DEFAULT_FROM_EMAIL = os.getenv(
248 'DEFAULT_FROM_EMAIL', config('DEFAULT_FROM_EMAIL')
249)
250SERVER_EMAIL = os.getenv('SERVER_EMAIL', config('SERVER_EMAIL'))
251EMAIL_HOST_PASSWORD = os.getenv(
252 'EMAIL_HOST_PASSWORD', config('EMAIL_HOST_PASSWORD')
253)
255sentry_sdk.init(
256 dsn=os.getenv('SENTRY_DSN', config('SENTRY_DSN')),
257 send_default_pii=True,
258)
260FRONTEND_URL = os.getenv('FRONTEND_URL', config('FRONTEND_URL'))