|
1 | | -import os, sys |
| 1 | +import os |
2 | 2 | from pathlib import Path |
3 | 3 | from dotenv import load_dotenv |
4 | 4 |
|
|
7 | 7 |
|
8 | 8 | BASE_DIR = Path(__file__).resolve().parent.parent |
9 | 9 |
|
10 | | -SECRET_KEY = os.getenv('SECRET_KEY', "django-insecure-6d0sc!g!$b+ecm0!uttm8)zco12u72)*gmtc61j3n_t0(lgf7v") |
11 | | -DEBUG = os.getenv('DEBUG', 'True').lower() == 'true' |
12 | | -ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '').split(',') if os.getenv('ALLOWED_HOSTS') else [] |
| 10 | +# SECURITY WARNING: keep the secret key used in production secret! |
| 11 | +SECRET_KEY = os.getenv('SECRET_KEY', 'generate-a-new-secret-key-for-production') |
13 | 12 |
|
14 | | -# Gemini AI Configuration |
15 | | -GEMINI_API_KEY = os.getenv('GEMINI_API_KEY') |
| 13 | +# SECURITY WARNING: don't run with debug turned on in production! |
| 14 | +DEBUG = os.getenv('DEBUG', 'False').lower() == 'true' |
| 15 | + |
| 16 | +# Production ALLOWED_HOSTS for cPanel |
| 17 | +ALLOWED_HOSTS = [ |
| 18 | + 'roshandamor.me', |
| 19 | + 'www.roshandamor.me', |
| 20 | + '127.0.0.1', |
| 21 | + 'localhost', |
| 22 | +] |
16 | 23 |
|
17 | | -# Spotify Configuration |
| 24 | +# Add environment variable support for dynamic hosts |
| 25 | +env_hosts = os.getenv('ALLOWED_HOSTS', '') |
| 26 | +if env_hosts: |
| 27 | + ALLOWED_HOSTS.extend([host.strip() for host in env_hosts.split(',') if host.strip()]) |
| 28 | + |
| 29 | +# API Keys and External Services |
| 30 | +GEMINI_API_KEY = os.getenv('GEMINI_API_KEY') |
18 | 31 | SPOTIFY_CLIENT_ID = os.getenv('SPOTIFY_CLIENT_ID') |
19 | 32 | SPOTIFY_CLIENT_SECRET = os.getenv('SPOTIFY_CLIENT_SECRET') |
20 | | -SPOTIFY_REDIRECT_URI = os.getenv('SPOTIFY_REDIRECT_URI', 'http://localhost:8000/music/admin/spotify-callback/') |
| 33 | +SPOTIFY_REDIRECT_URI = os.getenv('SPOTIFY_REDIRECT_URI', 'https://roshandamor.me/music/admin/spotify-callback/') |
| 34 | +TINYMCE_API_KEY = os.getenv('TINYMCE_API_KEY', '') |
21 | 35 |
|
22 | 36 | INSTALLED_APPS = [ |
23 | 37 | 'django.contrib.admin', |
|
37 | 51 |
|
38 | 52 | MIDDLEWARE = [ |
39 | 53 | 'django.middleware.security.SecurityMiddleware', |
40 | | - "whitenoise.middleware.WhiteNoiseMiddleware", |
| 54 | + 'whitenoise.middleware.WhiteNoiseMiddleware', |
41 | 55 | 'django.contrib.sessions.middleware.SessionMiddleware', |
| 56 | + 'corsheaders.middleware.CorsMiddleware', |
42 | 57 | 'django.middleware.common.CommonMiddleware', |
43 | 58 | 'django.middleware.csrf.CsrfViewMiddleware', |
44 | 59 | 'django.contrib.auth.middleware.AuthenticationMiddleware', |
|
55 | 70 | 'APP_DIRS': True, |
56 | 71 | 'OPTIONS': { |
57 | 72 | 'context_processors': [ |
| 73 | + 'django.template.context_processors.debug', |
58 | 74 | 'django.template.context_processors.request', |
59 | 75 | 'django.contrib.auth.context_processors.auth', |
60 | 76 | 'django.contrib.messages.context_processors.messages', |
|
66 | 82 |
|
67 | 83 | WSGI_APPLICATION = 'config.wsgi.application' |
68 | 84 |
|
69 | | - |
70 | | -# Database |
71 | | -# https://docs.djangoproject.com/en/5.2/ref/settings/#databases |
72 | | - |
73 | | -DATABASES = { |
74 | | - 'default': { |
75 | | - 'ENGINE': 'django.db.backends.sqlite3', |
76 | | - 'NAME': BASE_DIR / 'db.sqlite3', |
| 85 | +# Database Configuration for cPanel MySQL |
| 86 | +if DEBUG: |
| 87 | + # Local development with SQLite |
| 88 | + DATABASES = { |
| 89 | + 'default': { |
| 90 | + 'ENGINE': 'django.db.backends.sqlite3', |
| 91 | + 'NAME': BASE_DIR / 'db.sqlite3', |
| 92 | + } |
| 93 | + } |
| 94 | +else: |
| 95 | + # Production cPanel MySQL |
| 96 | + DATABASES = { |
| 97 | + 'default': { |
| 98 | + 'ENGINE': 'django.db.backends.mysql', |
| 99 | + 'NAME': os.getenv('MYSQL_DB', 'portfolio_db'), |
| 100 | + 'USER': os.getenv('MYSQL_USER', 'portfolio_user'), |
| 101 | + 'PASSWORD': os.getenv('MYSQL_PASSWORD', ''), |
| 102 | + 'HOST': os.getenv('MYSQL_HOST', 'localhost'), |
| 103 | + 'PORT': os.getenv('MYSQL_PORT', '3306'), |
| 104 | + 'OPTIONS': { |
| 105 | + 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", |
| 106 | + 'charset': 'utf8mb4', |
| 107 | + }, |
| 108 | + } |
77 | 109 | } |
78 | | -} |
79 | 110 |
|
80 | 111 |
|
81 | 112 | # Password validation |
|
106 | 137 | USE_TZ = True |
107 | 138 |
|
108 | 139 |
|
109 | | -# Static files (CSS, JavaScript, Images) |
110 | | -# https://docs.djangoproject.com/en/5.2/howto/static-files/ |
111 | | - |
| 140 | +# Static files configuration for cPanel |
112 | 141 | STATIC_URL = '/static/' |
113 | 142 | STATICFILES_DIRS = [BASE_DIR / 'static'] |
114 | 143 | STATIC_ROOT = BASE_DIR / 'staticfiles' |
115 | 144 |
|
| 145 | +# WhiteNoise configuration for serving static files |
| 146 | +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' |
| 147 | + |
| 148 | +# Media files configuration |
116 | 149 | MEDIA_URL = '/media/' |
117 | 150 | MEDIA_ROOT = BASE_DIR / 'media' |
118 | 151 |
|
119 | 152 | # Default primary key field type |
120 | | -# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field |
121 | | - |
122 | 153 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' |
123 | 154 |
|
124 | | -# TinyMCE settings |
125 | | -TINYMCE_DEFAULT_CONFIG = { |
126 | | - "height": "420px", |
127 | | - "width": "100%", |
128 | | - "menubar": "file edit view insert format tools table help", |
129 | | - "plugins": "advlist autolink lists link image charmap print preview anchor searchreplace visualblocks code fullscreen insertdatetime media table paste code help wordcount", |
130 | | - "toolbar": "undo redo | bold italic underline strikethrough | fontselect fontsizeselect formatselect | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist checklist | forecolor backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap emoticons | fullscreen preview save print | insertfile image media pageembed template link anchor codesample | a11ycheck ltr rtl | showcomments addcomment", |
131 | | - "custom_undo_redo_levels": 10, |
132 | | -} |
133 | | - |
134 | | -# TinyMCE Configuration (for rich text editing in Django admin) |
| 155 | +# TinyMCE Configuration |
135 | 156 | TINYMCE_DEFAULT_CONFIG = { |
136 | 157 | 'height': 300, |
137 | 158 | 'width': '100%', |
|
160 | 181 | 'statusbar': True, |
161 | 182 | } |
162 | 183 |
|
163 | | -# Email settings |
164 | | -# For development - prints emails to console |
165 | | -# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' |
166 | | - |
167 | | -# For production - use SMTP (uncomment and configure the lines below) |
168 | | -EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' |
169 | | -EMAIL_HOST = os.getenv('EMAIL_HOST', 'smtp.gmail.com') # e.g., smtp.gmail.com for Gmail |
170 | | -EMAIL_PORT = int(os.getenv('EMAIL_PORT', '587')) |
171 | | -EMAIL_USE_TLS = os.getenv('EMAIL_USE_TLS', 'True').lower() == 'true' |
172 | | -EMAIL_USE_SSL = os.getenv('EMAIL_USE_SSL', 'False').lower() == 'true' |
173 | | -EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', '') # Your email address |
174 | | -EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD', '') # Your email password or app password |
175 | | - |
176 | | -# Default sender email |
177 | | -DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'noreply@yourportfolio.com') |
178 | | -SERVER_EMAIL = DEFAULT_FROM_EMAIL |
179 | | - |
180 | | -# Site configuration for emails |
| 184 | +# Email Configuration |
| 185 | +if DEBUG: |
| 186 | + # Development: Console backend |
| 187 | + EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' |
| 188 | +else: |
| 189 | + # Production: SMTP backend for cPanel |
| 190 | + EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' |
| 191 | + EMAIL_HOST = os.getenv('EMAIL_HOST', 'mail.roshandamor.me') |
| 192 | + EMAIL_PORT = int(os.getenv('EMAIL_PORT', '465')) |
| 193 | + EMAIL_USE_TLS = os.getenv('EMAIL_USE_TLS', 'False').lower() == 'true' |
| 194 | + EMAIL_USE_SSL = os.getenv('EMAIL_USE_SSL', 'True').lower() == 'true' |
| 195 | + EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', 'noreply@roshandamor.me') |
| 196 | + EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD', '') |
| 197 | + DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'noreply@roshandamor.me') |
| 198 | + SERVER_EMAIL = DEFAULT_FROM_EMAIL |
| 199 | + |
| 200 | +# Site Configuration |
181 | 201 | SITE_NAME = os.getenv('SITE_NAME', 'Roshan Damor Portfolio') |
182 | | -SITE_URL = os.getenv('SITE_URL', 'http://localhost:8000') |
| 202 | +SITE_URL = os.getenv('SITE_URL', 'https://roshandamor.me' if not DEBUG else 'http://localhost:8000') |
183 | 203 |
|
184 | 204 | # Message tags for Bootstrap |
185 | 205 | from django.contrib.messages import constants as messages |
|
191 | 211 | messages.ERROR: 'danger', |
192 | 212 | } |
193 | 213 |
|
194 | | -SPOTIFY_CLIENT_ID = os.getenv('SPOTIFY_CLIENT_ID', "your_client_id") |
195 | | -SPOTIFY_CLIENT_SECRET = os.getenv('SPOTIFY_CLIENT_SECRET', "your_client_secret") |
196 | | -SPOTIFY_REDIRECT_URI = os.getenv('SPOTIFY_REDIRECT_URI', "https://localhost:8000/callback/") |
| 214 | +# External API Configuration |
| 215 | +SPOTIFY_CLIENT_ID = os.getenv('SPOTIFY_CLIENT_ID', '') |
| 216 | +SPOTIFY_CLIENT_SECRET = os.getenv('SPOTIFY_CLIENT_SECRET', '') |
| 217 | +SPOTIFY_REDIRECT_URI = os.getenv('SPOTIFY_REDIRECT_URI', 'https://roshandamor.me/music/admin/spotify-callback/') |
| 218 | + |
| 219 | +# Security Settings for Production |
| 220 | +if not DEBUG: |
| 221 | + # HTTPS and Security |
| 222 | + SECURE_BROWSER_XSS_FILTER = True |
| 223 | + SECURE_CONTENT_TYPE_NOSNIFF = True |
| 224 | + X_FRAME_OPTIONS = 'DENY' |
| 225 | + SECURE_HSTS_SECONDS = 31536000 # 1 year |
| 226 | + SECURE_HSTS_INCLUDE_SUBDOMAINS = True |
| 227 | + SECURE_HSTS_PRELOAD = True |
| 228 | + |
| 229 | + # Session Security |
| 230 | + SESSION_COOKIE_SECURE = True |
| 231 | + CSRF_COOKIE_SECURE = True |
| 232 | + SESSION_COOKIE_HTTPONLY = True |
| 233 | + CSRF_COOKIE_HTTPONLY = True |
| 234 | + |
| 235 | + # Force HTTPS redirects (optional for cPanel) |
| 236 | + # SECURE_SSL_REDIRECT = True |
| 237 | + |
| 238 | +# CORS Configuration |
| 239 | +CORS_ALLOWED_ORIGINS = [ |
| 240 | + "https://roshandamor.me", |
| 241 | + "https://www.roshandamor.me", |
| 242 | +] |
197 | 243 |
|
198 | | -# Notification System Settings |
199 | | -SITE_NAME = "Roshan Damor Portfolio" |
200 | | -SITE_URL = os.getenv('SITE_URL', 'http://localhost:8000') |
| 244 | +if DEBUG: |
| 245 | + CORS_ALLOWED_ORIGINS.extend([ |
| 246 | + "http://localhost:8000", |
| 247 | + "http://127.0.0.1:8000", |
| 248 | + ]) |
201 | 249 |
|
202 | | -# Logging Configuration for Notifications |
| 250 | +# Logging Configuration |
203 | 251 | LOGGING = { |
204 | 252 | 'version': 1, |
205 | 253 | 'disable_existing_loggers': False, |
|
221 | 269 | 'formatter': 'verbose', |
222 | 270 | }, |
223 | 271 | 'console': { |
224 | | - 'level': 'DEBUG', |
| 272 | + 'level': 'DEBUG' if DEBUG else 'INFO', |
225 | 273 | 'class': 'logging.StreamHandler', |
226 | 274 | 'formatter': 'simple', |
227 | 275 | }, |
|
232 | 280 | 'level': 'INFO', |
233 | 281 | 'propagate': True, |
234 | 282 | }, |
| 283 | + 'django': { |
| 284 | + 'handlers': ['console'], |
| 285 | + 'level': 'INFO' if DEBUG else 'WARNING', |
| 286 | + 'propagate': False, |
| 287 | + }, |
235 | 288 | }, |
236 | 289 | } |
0 commit comments