django-cfg 1.2.31__py3-none-any.whl → 1.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/api/health/views.py +4 -2
- django_cfg/apps/knowbase/config/settings.py +16 -15
- django_cfg/apps/payments/README.md +326 -0
- django_cfg/apps/payments/admin/__init__.py +20 -10
- django_cfg/apps/payments/admin/api_keys_admin.py +521 -237
- django_cfg/apps/payments/admin/balance_admin.py +592 -297
- django_cfg/apps/payments/admin/currencies_admin.py +526 -222
- django_cfg/apps/payments/admin/filters.py +306 -199
- django_cfg/apps/payments/admin/payments_admin.py +465 -70
- django_cfg/apps/payments/admin/subscriptions_admin.py +578 -128
- django_cfg/apps/payments/admin_interface/__init__.py +18 -0
- django_cfg/apps/payments/admin_interface/templates/payments/base.html +162 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +38 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/loading_spinner.html +16 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/notification.html +27 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_card.html +86 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_card.html +39 -0
- django_cfg/apps/payments/admin_interface/templates/payments/currency_converter.html +382 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +300 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +303 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +382 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_status.html +500 -0
- django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +594 -0
- django_cfg/apps/payments/admin_interface/views/__init__.py +23 -0
- django_cfg/apps/payments/admin_interface/views/payment_views.py +259 -0
- django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +37 -0
- django_cfg/apps/payments/apps.py +34 -9
- django_cfg/apps/payments/config/__init__.py +28 -51
- django_cfg/apps/payments/config/constance/__init__.py +22 -0
- django_cfg/apps/payments/config/constance/config_service.py +123 -0
- django_cfg/apps/payments/config/constance/fields.py +69 -0
- django_cfg/apps/payments/config/constance/settings.py +160 -0
- django_cfg/apps/payments/config/django_cfg_integration.py +202 -0
- django_cfg/apps/payments/config/helpers.py +130 -0
- django_cfg/apps/payments/management/__init__.py +1 -3
- django_cfg/apps/payments/management/commands/__init__.py +1 -3
- django_cfg/apps/payments/management/commands/manage_currencies.py +303 -151
- django_cfg/apps/payments/management/commands/manage_providers.py +333 -160
- django_cfg/apps/payments/middleware/__init__.py +3 -1
- django_cfg/apps/payments/middleware/api_access.py +329 -222
- django_cfg/apps/payments/middleware/rate_limiting.py +342 -152
- django_cfg/apps/payments/middleware/usage_tracking.py +249 -240
- django_cfg/apps/payments/migrations/0001_initial.py +708 -536
- django_cfg/apps/payments/models/__init__.py +13 -18
- django_cfg/apps/payments/models/api_keys.py +121 -43
- django_cfg/apps/payments/models/balance.py +150 -115
- django_cfg/apps/payments/models/base.py +68 -15
- django_cfg/apps/payments/models/currencies.py +172 -148
- django_cfg/apps/payments/models/managers/__init__.py +44 -0
- django_cfg/apps/payments/models/managers/api_key_managers.py +329 -0
- django_cfg/apps/payments/models/managers/balance_managers.py +599 -0
- django_cfg/apps/payments/models/managers/currency_managers.py +385 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +511 -0
- django_cfg/apps/payments/models/managers/subscription_managers.py +641 -0
- django_cfg/apps/payments/models/payments.py +235 -285
- django_cfg/apps/payments/models/subscriptions.py +257 -177
- django_cfg/apps/payments/models/tariffs.py +147 -40
- django_cfg/apps/payments/services/__init__.py +209 -56
- django_cfg/apps/payments/services/cache/__init__.py +6 -6
- django_cfg/apps/payments/services/cache/{simple_cache.py → cache_service.py} +112 -12
- django_cfg/apps/payments/services/core/__init__.py +10 -6
- django_cfg/apps/payments/services/core/balance_service.py +435 -360
- django_cfg/apps/payments/services/core/base.py +166 -0
- django_cfg/apps/payments/services/core/currency_service.py +478 -0
- django_cfg/apps/payments/services/core/payment_service.py +346 -467
- django_cfg/apps/payments/services/core/subscription_service.py +425 -481
- django_cfg/apps/payments/services/core/webhook_service.py +410 -0
- django_cfg/apps/payments/services/integrations/__init__.py +29 -0
- django_cfg/apps/payments/services/integrations/ngrok_service.py +47 -0
- django_cfg/apps/payments/services/integrations/providers_config.py +107 -0
- django_cfg/apps/payments/services/providers/__init__.py +9 -14
- django_cfg/apps/payments/services/providers/base.py +234 -174
- django_cfg/apps/payments/services/providers/nowpayments.py +478 -0
- django_cfg/apps/payments/services/providers/registry.py +367 -301
- django_cfg/apps/payments/services/types/__init__.py +78 -0
- django_cfg/apps/payments/services/types/data.py +177 -0
- django_cfg/apps/payments/services/types/requests.py +150 -0
- django_cfg/apps/payments/services/types/responses.py +156 -0
- django_cfg/apps/payments/services/types/webhooks.py +232 -0
- django_cfg/apps/payments/signals/__init__.py +33 -8
- django_cfg/apps/payments/signals/api_key_signals.py +210 -129
- django_cfg/apps/payments/signals/balance_signals.py +174 -0
- django_cfg/apps/payments/signals/payment_signals.py +128 -103
- django_cfg/apps/payments/signals/subscription_signals.py +194 -142
- django_cfg/apps/payments/static/payments/css/components.css +380 -0
- django_cfg/apps/payments/static/payments/css/dashboard.css +188 -0
- django_cfg/apps/payments/static/payments/js/components.js +545 -0
- django_cfg/apps/payments/static/payments/js/utils.js +412 -0
- django_cfg/apps/payments/templatetags/__init__.py +1 -1
- django_cfg/apps/payments/templatetags/payment_tags.py +466 -0
- django_cfg/apps/payments/urls.py +45 -48
- django_cfg/apps/payments/urls_admin.py +33 -42
- django_cfg/apps/payments/views/api/__init__.py +101 -0
- django_cfg/apps/payments/views/api/api_keys.py +387 -0
- django_cfg/apps/payments/views/api/balances.py +381 -0
- django_cfg/apps/payments/views/api/base.py +298 -0
- django_cfg/apps/payments/views/api/currencies.py +402 -0
- django_cfg/apps/payments/views/api/payments.py +415 -0
- django_cfg/apps/payments/views/api/subscriptions.py +475 -0
- django_cfg/apps/payments/views/api/webhooks.py +476 -0
- django_cfg/apps/payments/views/serializers/__init__.py +99 -0
- django_cfg/apps/payments/views/serializers/api_keys.py +424 -0
- django_cfg/apps/payments/views/serializers/balances.py +300 -0
- django_cfg/apps/payments/views/serializers/currencies.py +335 -0
- django_cfg/apps/payments/views/serializers/payments.py +387 -0
- django_cfg/apps/payments/views/serializers/subscriptions.py +429 -0
- django_cfg/apps/payments/views/serializers/webhooks.py +137 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +40 -4
- django_cfg/core/generation.py +25 -4
- django_cfg/core/integration/README.md +363 -0
- django_cfg/core/integration/__init__.py +47 -0
- django_cfg/core/integration/commands_collector.py +239 -0
- django_cfg/core/integration/display/__init__.py +15 -0
- django_cfg/core/integration/display/base.py +157 -0
- django_cfg/core/integration/display/ngrok.py +164 -0
- django_cfg/core/integration/display/startup.py +815 -0
- django_cfg/core/integration/url_integration.py +123 -0
- django_cfg/core/integration/version_checker.py +160 -0
- django_cfg/management/commands/auto_generate.py +4 -0
- django_cfg/management/commands/check_settings.py +6 -0
- django_cfg/management/commands/clear_constance.py +5 -2
- django_cfg/management/commands/create_token.py +6 -0
- django_cfg/management/commands/list_urls.py +6 -0
- django_cfg/management/commands/migrate_all.py +6 -0
- django_cfg/management/commands/migrator.py +3 -0
- django_cfg/management/commands/rundramatiq.py +6 -0
- django_cfg/management/commands/runserver_ngrok.py +51 -29
- django_cfg/management/commands/script.py +6 -0
- django_cfg/management/commands/show_config.py +12 -2
- django_cfg/management/commands/show_urls.py +4 -0
- django_cfg/management/commands/superuser.py +6 -0
- django_cfg/management/commands/task_clear.py +4 -1
- django_cfg/management/commands/task_status.py +3 -1
- django_cfg/management/commands/test_email.py +3 -0
- django_cfg/management/commands/test_telegram.py +6 -0
- django_cfg/management/commands/test_twilio.py +6 -0
- django_cfg/management/commands/tree.py +6 -0
- django_cfg/management/commands/validate_config.py +155 -149
- django_cfg/models/constance.py +31 -11
- django_cfg/models/payments.py +175 -492
- django_cfg/modules/django_logger.py +160 -146
- django_cfg/modules/django_unfold/dashboard.py +64 -16
- django_cfg/registry/core.py +1 -0
- django_cfg/template_archive/django_sample.zip +0 -0
- django_cfg/utils/smart_defaults.py +222 -571
- django_cfg/utils/toolkit.py +51 -11
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/METADATA +4 -1
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/RECORD +153 -185
- django_cfg/apps/payments/__init__.py +0 -8
- django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
- django_cfg/apps/payments/config/module.py +0 -70
- django_cfg/apps/payments/config/providers.py +0 -105
- django_cfg/apps/payments/config/settings.py +0 -96
- django_cfg/apps/payments/config/utils.py +0 -52
- django_cfg/apps/payments/decorators.py +0 -291
- django_cfg/apps/payments/management/commands/README.md +0 -146
- django_cfg/apps/payments/management/commands/currency_stats.py +0 -304
- django_cfg/apps/payments/managers/__init__.py +0 -23
- django_cfg/apps/payments/managers/api_key_manager.py +0 -35
- django_cfg/apps/payments/managers/balance_manager.py +0 -361
- django_cfg/apps/payments/managers/currency_manager.py +0 -306
- django_cfg/apps/payments/managers/payment_manager.py +0 -192
- django_cfg/apps/payments/managers/subscription_manager.py +0 -37
- django_cfg/apps/payments/managers/tariff_manager.py +0 -29
- django_cfg/apps/payments/migrations/0002_network_providercurrency_and_more.py +0 -241
- django_cfg/apps/payments/migrations/0003_add_usd_rate_cache.py +0 -30
- django_cfg/apps/payments/models/events.py +0 -73
- django_cfg/apps/payments/serializers/__init__.py +0 -57
- django_cfg/apps/payments/serializers/api_keys.py +0 -51
- django_cfg/apps/payments/serializers/balance.py +0 -59
- django_cfg/apps/payments/serializers/currencies.py +0 -63
- django_cfg/apps/payments/serializers/payments.py +0 -62
- django_cfg/apps/payments/serializers/subscriptions.py +0 -71
- django_cfg/apps/payments/serializers/tariffs.py +0 -56
- django_cfg/apps/payments/services/billing/__init__.py +0 -8
- django_cfg/apps/payments/services/cache/base.py +0 -30
- django_cfg/apps/payments/services/core/fallback_service.py +0 -432
- django_cfg/apps/payments/services/internal_types.py +0 -461
- django_cfg/apps/payments/services/middleware/__init__.py +0 -8
- django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
- django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -76
- django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
- django_cfg/apps/payments/services/providers/cryptapi/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/cryptapi/config.py +0 -8
- django_cfg/apps/payments/services/providers/cryptapi/models.py +0 -192
- django_cfg/apps/payments/services/providers/cryptapi/provider.py +0 -439
- django_cfg/apps/payments/services/providers/cryptomus/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/cryptomus/models.py +0 -176
- django_cfg/apps/payments/services/providers/cryptomus/provider.py +0 -429
- django_cfg/apps/payments/services/providers/cryptomus/provider_v2.py +0 -564
- django_cfg/apps/payments/services/providers/models/__init__.py +0 -34
- django_cfg/apps/payments/services/providers/models/currencies.py +0 -190
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/nowpayments/models.py +0 -196
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +0 -380
- django_cfg/apps/payments/services/providers/stripe/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/stripe/models.py +0 -184
- django_cfg/apps/payments/services/providers/stripe/provider.py +0 -109
- django_cfg/apps/payments/services/security/__init__.py +0 -34
- django_cfg/apps/payments/services/security/error_handler.py +0 -635
- django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
- django_cfg/apps/payments/services/security/webhook_validator.py +0 -474
- django_cfg/apps/payments/static/payments/css/payments.css +0 -340
- django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
- django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
- django_cfg/apps/payments/static/payments/js/theme.js +0 -86
- django_cfg/apps/payments/tasks/__init__.py +0 -12
- django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +0 -50
- django_cfg/apps/payments/templates/payments/base.html +0 -182
- django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
- django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
- django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -43
- django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
- django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -34
- django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -148
- django_cfg/apps/payments/templates/payments/dashboard.html +0 -258
- django_cfg/apps/payments/templates/payments/dashboard_simple_test.html +0 -35
- django_cfg/apps/payments/templates/payments/payment_create.html +0 -579
- django_cfg/apps/payments/templates/payments/payment_detail.html +0 -373
- django_cfg/apps/payments/templates/payments/payment_list.html +0 -354
- django_cfg/apps/payments/templates/payments/stats.html +0 -261
- django_cfg/apps/payments/templates/payments/test.html +0 -213
- django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
- django_cfg/apps/payments/utils/__init__.py +0 -43
- django_cfg/apps/payments/utils/billing_utils.py +0 -342
- django_cfg/apps/payments/utils/config_utils.py +0 -239
- django_cfg/apps/payments/utils/middleware_utils.py +0 -228
- django_cfg/apps/payments/utils/validation_utils.py +0 -94
- django_cfg/apps/payments/views/__init__.py +0 -63
- django_cfg/apps/payments/views/api_key_views.py +0 -164
- django_cfg/apps/payments/views/balance_views.py +0 -75
- django_cfg/apps/payments/views/currency_views.py +0 -122
- django_cfg/apps/payments/views/payment_views.py +0 -149
- django_cfg/apps/payments/views/subscription_views.py +0 -135
- django_cfg/apps/payments/views/tariff_views.py +0 -131
- django_cfg/apps/payments/views/templates/__init__.py +0 -25
- django_cfg/apps/payments/views/templates/ajax.py +0 -451
- django_cfg/apps/payments/views/templates/base.py +0 -212
- django_cfg/apps/payments/views/templates/dashboard.py +0 -60
- django_cfg/apps/payments/views/templates/payment_detail.py +0 -102
- django_cfg/apps/payments/views/templates/payment_management.py +0 -158
- django_cfg/apps/payments/views/templates/qr_code.py +0 -174
- django_cfg/apps/payments/views/templates/stats.py +0 -244
- django_cfg/apps/payments/views/templates/utils.py +0 -181
- django_cfg/apps/payments/views/webhook_views.py +0 -266
- django_cfg/apps/payments/viewsets.py +0 -66
- django_cfg/core/integration.py +0 -160
- django_cfg/template_archive/.gitignore +0 -1
- django_cfg/template_archive/__init__.py +0 -0
- django_cfg/urls.py +0 -33
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/WHEEL +0 -0
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,10 @@
|
|
1
1
|
"""
|
2
2
|
Smart defaults system for django_cfg.
|
3
3
|
|
4
|
-
Following
|
5
|
-
-
|
6
|
-
-
|
7
|
-
-
|
8
|
-
- No mutable default arguments
|
4
|
+
Following KISS principle:
|
5
|
+
- Simple, clear configuration
|
6
|
+
- No complex environment logic
|
7
|
+
- Logging handled by django_logger module
|
9
8
|
"""
|
10
9
|
|
11
10
|
from typing import Dict, Any, Optional, List
|
@@ -16,604 +15,256 @@ from django_cfg.models.services import EmailConfig
|
|
16
15
|
from django_cfg.core.exceptions import ConfigurationError
|
17
16
|
|
18
17
|
|
18
|
+
def get_log_filename() -> str:
|
19
|
+
"""
|
20
|
+
Determine the correct log filename based on project type.
|
21
|
+
|
22
|
+
Returns:
|
23
|
+
- 'django-cfg.log' for django-cfg projects
|
24
|
+
- 'django.log' for regular Django projects
|
25
|
+
"""
|
26
|
+
try:
|
27
|
+
# Check for django-cfg in installed apps
|
28
|
+
from django.conf import settings
|
29
|
+
if hasattr(settings, 'INSTALLED_APPS'):
|
30
|
+
for app in settings.INSTALLED_APPS:
|
31
|
+
if 'django_cfg' in app:
|
32
|
+
return 'django-cfg.log'
|
33
|
+
|
34
|
+
# Default to regular Django log
|
35
|
+
return 'django.log'
|
36
|
+
|
37
|
+
except Exception:
|
38
|
+
# Fallback to django-cfg filename (since we're in django-cfg module)
|
39
|
+
return 'django-cfg.log'
|
40
|
+
|
41
|
+
|
19
42
|
class SmartDefaults:
|
20
43
|
"""
|
21
44
|
Environment-aware smart defaults for Django configuration.
|
22
45
|
|
23
|
-
|
24
|
-
|
25
|
-
- DEBUG flag
|
26
|
-
- Available services (Redis, SMTP, etc.)
|
27
|
-
- Security requirements
|
46
|
+
Provides intelligent defaults based on environment detection
|
47
|
+
with comprehensive type safety and validation.
|
28
48
|
"""
|
29
49
|
|
30
|
-
@
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
environment: Current environment
|
43
|
-
debug: Django DEBUG setting
|
44
|
-
|
45
|
-
Returns:
|
46
|
-
Configured cache backend
|
47
|
-
|
48
|
-
Raises:
|
49
|
-
ConfigurationError: If configuration cannot be applied
|
50
|
-
"""
|
51
|
-
try:
|
52
|
-
# Create a copy to avoid modifying the original
|
53
|
-
config: CacheConfig = cache_config.model_copy()
|
54
|
-
|
55
|
-
# Environment-specific adjustments
|
56
|
-
if environment == "testing":
|
57
|
-
# Testing: Use dummy cache with very short timeouts
|
58
|
-
config.backend_override = "django.core.cache.backends.dummy.DummyCache"
|
59
|
-
config.timeout = min(config.timeout, 1) # Max 1 second for tests
|
60
|
-
|
61
|
-
elif environment == "development" or debug:
|
62
|
-
# Development: Prefer memory cache, shorter timeouts
|
63
|
-
if not config.redis_url:
|
64
|
-
# No Redis configured - use memory cache
|
65
|
-
config.timeout = min(config.timeout, 300) # Max 5 minutes
|
66
|
-
else:
|
67
|
-
# Redis available - use it but with shorter timeouts
|
68
|
-
config.timeout = min(config.timeout, 600) # Max 10 minutes
|
69
|
-
config.max_connections = min(config.max_connections, 20) # Fewer connections
|
70
|
-
|
71
|
-
elif environment in ("production", "staging"):
|
72
|
-
# Production: Use Redis if available, longer timeouts
|
73
|
-
if config.redis_url:
|
74
|
-
config.timeout = max(config.timeout, 300) # Min 5 minutes
|
75
|
-
config.max_connections = max(config.max_connections, 50) # More connections
|
76
|
-
else:
|
77
|
-
# Production without Redis - warn but use file cache
|
78
|
-
config.backend_override = "django.core.cache.backends.filebased.FileBasedCache"
|
79
|
-
|
80
|
-
# Apply compression for production
|
81
|
-
if environment == "production" and config.redis_url:
|
82
|
-
config.compress = True
|
83
|
-
|
84
|
-
return config
|
85
|
-
|
86
|
-
except Exception as e:
|
87
|
-
raise ConfigurationError(
|
88
|
-
f"Failed to configure cache backend: {e}",
|
89
|
-
context={
|
90
|
-
'environment': environment,
|
91
|
-
'debug': debug,
|
92
|
-
'cache_config': cache_config.model_dump()
|
93
|
-
}
|
94
|
-
) from e
|
50
|
+
@staticmethod
|
51
|
+
def get_database_defaults(environment: str = "development", debug: bool = False, engine: str = "sqlite3") -> Dict[str, Any]:
|
52
|
+
"""Get database configuration defaults."""
|
53
|
+
return {
|
54
|
+
'ENGINE': 'django.db.backends.sqlite3',
|
55
|
+
'NAME': Path('db') / 'db.sqlite3',
|
56
|
+
'ATOMIC_REQUESTS': True,
|
57
|
+
'CONN_MAX_AGE': 60,
|
58
|
+
'OPTIONS': {
|
59
|
+
'timeout': 20,
|
60
|
+
}
|
61
|
+
}
|
95
62
|
|
96
|
-
@
|
97
|
-
def
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
Args:
|
107
|
-
email_config: Base email configuration
|
108
|
-
environment: Current environment
|
109
|
-
debug: Django DEBUG setting
|
110
|
-
|
111
|
-
Returns:
|
112
|
-
Configured email backend
|
113
|
-
|
114
|
-
Raises:
|
115
|
-
ConfigurationError: If configuration cannot be applied
|
116
|
-
"""
|
117
|
-
try:
|
118
|
-
# Create a copy to avoid modifying the original
|
119
|
-
config = email_config.model_copy()
|
120
|
-
|
121
|
-
# Environment-specific adjustments
|
122
|
-
if environment == "testing":
|
123
|
-
# Testing: Use in-memory backend
|
124
|
-
config.backend_override = "django.core.mail.backends.locmem.EmailBackend"
|
125
|
-
config.timeout = min(config.timeout, 5) # Very short timeout
|
126
|
-
|
127
|
-
elif environment == "development":
|
128
|
-
# Development: Use SMTP if configured (allow real email sending in dev)
|
129
|
-
if config.username and config.password:
|
130
|
-
# SMTP configured - use SMTP backend
|
131
|
-
config.backend_override = "django.core.mail.backends.smtp.EmailBackend"
|
132
|
-
# Note: No fallback to console - let user decide via backend setting
|
133
|
-
|
134
|
-
elif environment in ("production", "staging"):
|
135
|
-
# Production: Use SMTP if properly configured
|
136
|
-
if config.username and config.password:
|
137
|
-
config.backend_override = "django.core.mail.backends.smtp.EmailBackend"
|
138
|
-
|
139
|
-
# Production email security
|
140
|
-
if config.port == 587:
|
141
|
-
config.use_tls = True
|
142
|
-
config.use_ssl = False
|
143
|
-
elif config.port == 465:
|
144
|
-
config.use_tls = False
|
145
|
-
config.use_ssl = True
|
146
|
-
|
147
|
-
# Longer timeout for production
|
148
|
-
config.timeout = max(config.timeout, 30)
|
149
|
-
else:
|
150
|
-
# Production without SMTP - fallback to console with warning
|
151
|
-
config.backend_override = "django.core.mail.backends.console.EmailBackend"
|
152
|
-
|
153
|
-
return config
|
154
|
-
|
155
|
-
except Exception as e:
|
156
|
-
raise ConfigurationError(
|
157
|
-
f"Failed to configure email backend: {e}",
|
158
|
-
context={
|
159
|
-
'environment': environment,
|
160
|
-
'debug': debug,
|
161
|
-
'email_config': email_config.model_dump(exclude={'password'})
|
63
|
+
@staticmethod
|
64
|
+
def get_cache_defaults() -> Dict[str, Any]:
|
65
|
+
"""Get cache configuration defaults."""
|
66
|
+
return {
|
67
|
+
'default': {
|
68
|
+
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
69
|
+
'LOCATION': 'default-cache',
|
70
|
+
'TIMEOUT': 300,
|
71
|
+
'OPTIONS': {
|
72
|
+
'MAX_ENTRIES': 1000,
|
162
73
|
}
|
163
|
-
|
74
|
+
}
|
75
|
+
}
|
164
76
|
|
165
|
-
@
|
77
|
+
@staticmethod
|
166
78
|
def get_security_defaults(
|
79
|
+
security_domains=None,
|
80
|
+
environment: str = "development",
|
81
|
+
debug: bool = False,
|
82
|
+
ssl_redirect=None,
|
83
|
+
cors_allow_headers=None
|
84
|
+
) -> Dict[str, Any]:
|
85
|
+
"""Get security configuration defaults."""
|
86
|
+
return {
|
87
|
+
'USE_TZ': True,
|
88
|
+
'USE_I18N': True,
|
89
|
+
'USE_L10N': True,
|
90
|
+
'SECURE_BROWSER_XSS_FILTER': not debug,
|
91
|
+
'SECURE_CONTENT_TYPE_NOSNIFF': not debug,
|
92
|
+
'X_FRAME_OPTIONS': 'DENY' if not debug else 'SAMEORIGIN',
|
93
|
+
'SECURE_HSTS_SECONDS': 31536000 if not debug else 0,
|
94
|
+
'SECURE_HSTS_INCLUDE_SUBDOMAINS': not debug,
|
95
|
+
'SECURE_HSTS_PRELOAD': not debug,
|
96
|
+
}
|
97
|
+
|
98
|
+
@classmethod
|
99
|
+
def get_logging_defaults(
|
167
100
|
cls,
|
168
|
-
domains: List[str],
|
169
101
|
environment: Optional[str] = None,
|
170
|
-
debug: bool = False
|
171
|
-
ssl_redirect: Optional[bool] = None,
|
172
|
-
cors_allow_headers: Optional[List[str]] = None
|
102
|
+
debug: bool = False
|
173
103
|
) -> Dict[str, Any]:
|
174
104
|
"""
|
175
|
-
|
105
|
+
Simple logging configuration.
|
106
|
+
|
107
|
+
NOTE: Real logging setup is handled by django_cfg.modules.django_logger
|
108
|
+
This provides minimal fallback configuration only.
|
176
109
|
|
177
110
|
Args:
|
178
|
-
|
179
|
-
|
180
|
-
debug: Django DEBUG setting
|
181
|
-
ssl_redirect: Force SSL redirect on/off (None = auto based on domains)
|
182
|
-
cors_allow_headers: Additional CORS headers to extend defaults
|
111
|
+
environment: Environment name (ignored - for compatibility)
|
112
|
+
debug: Debug mode (ignored - for compatibility)
|
183
113
|
|
184
114
|
Returns:
|
185
|
-
|
115
|
+
Minimal Django logging configuration
|
186
116
|
"""
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
csrf_settings = cls._generate_csrf_settings(domains, is_dev)
|
201
|
-
settings.update(csrf_settings)
|
202
|
-
|
203
|
-
# Generate security headers for production
|
204
|
-
if environment == "production":
|
205
|
-
security_headers = cls._generate_security_headers(domains, ssl_redirect)
|
206
|
-
settings.update(security_headers)
|
207
|
-
|
208
|
-
return settings
|
209
|
-
|
210
|
-
except Exception as e:
|
211
|
-
raise ConfigurationError(
|
212
|
-
f"Failed to generate security defaults: {e}",
|
213
|
-
context={
|
214
|
-
'domains': domains,
|
215
|
-
'environment': environment,
|
216
|
-
'debug': debug
|
217
|
-
}
|
218
|
-
) from e
|
219
|
-
|
220
|
-
@classmethod
|
221
|
-
def _generate_cors_settings(
|
222
|
-
cls,
|
223
|
-
domains: List[str],
|
224
|
-
is_dev: bool,
|
225
|
-
cors_allow_headers: Optional[List[str]] = None
|
226
|
-
) -> Dict[str, Any]:
|
227
|
-
"""Generate CORS-specific settings."""
|
228
|
-
settings = {
|
229
|
-
'CORS_ALLOW_CREDENTIALS': True,
|
230
|
-
'CORS_ALLOW_HEADERS': cls._get_cors_headers(cors_allow_headers)
|
117
|
+
# Minimal fallback - actual logging is configured by django_logger module
|
118
|
+
return {
|
119
|
+
'version': 1,
|
120
|
+
'disable_existing_loggers': False,
|
121
|
+
'handlers': {
|
122
|
+
'console': {
|
123
|
+
'class': 'logging.StreamHandler',
|
124
|
+
},
|
125
|
+
},
|
126
|
+
'root': {
|
127
|
+
'handlers': ['console'],
|
128
|
+
'level': 'INFO',
|
129
|
+
},
|
231
130
|
}
|
232
|
-
|
233
|
-
if is_dev:
|
234
|
-
# Development: Allow all origins for convenience
|
235
|
-
settings['CORS_ALLOW_ALL_ORIGINS'] = True
|
236
|
-
else:
|
237
|
-
# Production: Restrict to specified domains
|
238
|
-
settings['CORS_ALLOWED_ORIGINS'] = cls._build_allowed_origins(domains)
|
239
|
-
|
240
|
-
return settings
|
241
131
|
|
242
|
-
@
|
243
|
-
def
|
244
|
-
"""
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
return {}
|
255
|
-
|
256
|
-
@classmethod
|
257
|
-
def _generate_security_headers(
|
258
|
-
cls,
|
259
|
-
domains: List[str],
|
260
|
-
ssl_redirect: Optional[bool] = None
|
261
|
-
) -> Dict[str, Any]:
|
262
|
-
"""Generate security headers for production."""
|
263
|
-
settings = {
|
264
|
-
'SECURE_BROWSER_XSS_FILTER': True,
|
265
|
-
'SECURE_CONTENT_TYPE_NOSNIFF': True,
|
266
|
-
'SECURE_HSTS_SECONDS': 31536000, # 1 year
|
267
|
-
'SECURE_HSTS_INCLUDE_SUBDOMAINS': True,
|
268
|
-
'SECURE_HSTS_PRELOAD': True,
|
269
|
-
'X_FRAME_OPTIONS': 'DENY',
|
270
|
-
}
|
271
|
-
|
272
|
-
# SSL settings - configurable or auto-detect based on domains
|
273
|
-
should_use_ssl = ssl_redirect if ssl_redirect is not None else bool(domains)
|
274
|
-
|
275
|
-
if should_use_ssl:
|
276
|
-
settings.update({
|
277
|
-
'SECURE_SSL_REDIRECT': True,
|
278
|
-
'SESSION_COOKIE_SECURE': True,
|
279
|
-
'CSRF_COOKIE_SECURE': True,
|
280
|
-
})
|
281
|
-
elif ssl_redirect is False:
|
282
|
-
# Explicitly disable SSL redirect
|
283
|
-
settings.update({
|
284
|
-
'SECURE_SSL_REDIRECT': False,
|
285
|
-
'SESSION_COOKIE_SECURE': False,
|
286
|
-
'CSRF_COOKIE_SECURE': False,
|
287
|
-
})
|
288
|
-
|
289
|
-
return settings
|
290
|
-
|
291
|
-
@classmethod
|
292
|
-
def _get_cors_headers(cls, cors_allow_headers: Optional[List[str]] = None) -> List[str]:
|
293
|
-
"""
|
294
|
-
Get CORS headers with defaults extended by custom headers.
|
295
|
-
|
296
|
-
Note: The default headers are defined in DjangoConfig.cors_allow_headers.
|
297
|
-
This method should be consistent with those defaults.
|
298
|
-
"""
|
299
|
-
# Default headers - should match DjangoConfig.cors_allow_headers defaults
|
300
|
-
default_headers = [
|
301
|
-
"accept",
|
302
|
-
"accept-encoding",
|
303
|
-
"authorization",
|
304
|
-
"content-type",
|
305
|
-
"dnt",
|
306
|
-
"origin",
|
307
|
-
"user-agent",
|
308
|
-
"x-csrftoken",
|
309
|
-
"x-requested-with",
|
310
|
-
"x-api-key",
|
311
|
-
"x-api-token",
|
132
|
+
@staticmethod
|
133
|
+
def get_middleware_defaults() -> List[str]:
|
134
|
+
"""Get middleware configuration defaults."""
|
135
|
+
return [
|
136
|
+
'corsheaders.middleware.CorsMiddleware',
|
137
|
+
'django.middleware.security.SecurityMiddleware',
|
138
|
+
'django.contrib.sessions.middleware.SessionMiddleware',
|
139
|
+
'django.middleware.common.CommonMiddleware',
|
140
|
+
'django.middleware.csrf.CsrfViewMiddleware',
|
141
|
+
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
142
|
+
'django.contrib.messages.middleware.MessageMiddleware',
|
143
|
+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
312
144
|
]
|
313
|
-
|
314
|
-
if not cors_allow_headers:
|
315
|
-
return default_headers
|
316
|
-
|
317
|
-
# Extend with custom headers and remove duplicates while preserving order
|
318
|
-
return cls._merge_headers(default_headers, cors_allow_headers)
|
319
145
|
|
320
|
-
@
|
321
|
-
def
|
322
|
-
"""
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
@classmethod
|
336
|
-
def _build_allowed_origins(cls, domains: List[str]) -> List[str]:
|
337
|
-
"""Build CORS allowed origins for production."""
|
338
|
-
allowed_origins = []
|
339
|
-
|
340
|
-
for domain in domains:
|
341
|
-
# Add HTTPS version
|
342
|
-
allowed_origins.append(f"https://{domain}")
|
146
|
+
@staticmethod
|
147
|
+
def get_installed_apps_defaults() -> List[str]:
|
148
|
+
"""Get default installed apps."""
|
149
|
+
return [
|
150
|
+
# Unfold admin
|
151
|
+
"unfold",
|
152
|
+
"unfold.contrib.filters",
|
153
|
+
"unfold.contrib.forms",
|
154
|
+
"unfold.contrib.inlines",
|
155
|
+
"import_export",
|
156
|
+
"unfold.contrib.import_export",
|
157
|
+
"unfold.contrib.guardian",
|
158
|
+
"unfold.contrib.simple_history",
|
159
|
+
"unfold.contrib.location_field",
|
160
|
+
"unfold.contrib.constance",
|
343
161
|
|
344
|
-
#
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
162
|
+
# Django core
|
163
|
+
"django.contrib.admin",
|
164
|
+
"django.contrib.auth",
|
165
|
+
"django.contrib.contenttypes",
|
166
|
+
"django.contrib.sessions",
|
167
|
+
"django.contrib.messages",
|
168
|
+
"django.contrib.staticfiles",
|
169
|
+
"django.contrib.humanize",
|
170
|
+
|
171
|
+
# Third-party
|
172
|
+
"corsheaders",
|
173
|
+
"rest_framework",
|
174
|
+
"rest_framework.authtoken",
|
175
|
+
"rest_framework_simplejwt",
|
176
|
+
"rest_framework_simplejwt.token_blacklist",
|
177
|
+
"rest_framework_nested",
|
178
|
+
"rangefilter",
|
179
|
+
"django_filters",
|
180
|
+
"drf_spectacular",
|
181
|
+
"drf_spectacular_sidecar",
|
182
|
+
"django_json_widget",
|
183
|
+
"django_extensions",
|
184
|
+
"constance",
|
185
|
+
"constance.backends.database",
|
186
|
+
|
187
|
+
# Django CFG
|
188
|
+
"django_cfg",
|
189
|
+
]
|
349
190
|
|
350
|
-
@
|
351
|
-
def
|
352
|
-
"""
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
])
|
369
|
-
else:
|
370
|
-
# External domains: add both for dev flexibility
|
371
|
-
csrf_origins.extend([
|
372
|
-
f"https://{domain}",
|
373
|
-
f"http://{domain}",
|
374
|
-
])
|
375
|
-
|
376
|
-
return csrf_origins
|
191
|
+
@staticmethod
|
192
|
+
def get_templates_defaults() -> List[Dict[str, Any]]:
|
193
|
+
"""Get templates configuration defaults."""
|
194
|
+
return [
|
195
|
+
{
|
196
|
+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
197
|
+
'DIRS': ['templates'],
|
198
|
+
'APP_DIRS': True,
|
199
|
+
'OPTIONS': {
|
200
|
+
'context_processors': [
|
201
|
+
'django.template.context_processors.debug',
|
202
|
+
'django.template.context_processors.request',
|
203
|
+
'django.contrib.auth.context_processors.auth',
|
204
|
+
'django.contrib.messages.context_processors.messages',
|
205
|
+
],
|
206
|
+
},
|
207
|
+
},
|
208
|
+
]
|
377
209
|
|
378
|
-
@
|
379
|
-
def
|
380
|
-
"""
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
return csrf_origins
|
210
|
+
@staticmethod
|
211
|
+
def get_static_files_defaults() -> Dict[str, Any]:
|
212
|
+
"""Get static files configuration defaults."""
|
213
|
+
return {
|
214
|
+
'STATIC_URL': '/static/',
|
215
|
+
'STATIC_ROOT': Path('staticfiles'),
|
216
|
+
'STATICFILES_DIRS': [
|
217
|
+
Path('static'),
|
218
|
+
],
|
219
|
+
'MEDIA_URL': '/media/',
|
220
|
+
'MEDIA_ROOT': Path('media'),
|
221
|
+
}
|
392
222
|
|
393
|
-
@
|
394
|
-
def
|
395
|
-
"""
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
return False
|
409
|
-
|
410
|
-
# Don't add www if domain already starts with www
|
411
|
-
return not domain.startswith('www.')
|
223
|
+
@staticmethod
|
224
|
+
def get_rest_framework_defaults() -> Dict[str, Any]:
|
225
|
+
"""Get Django REST Framework defaults."""
|
226
|
+
return {
|
227
|
+
'DEFAULT_AUTHENTICATION_CLASSES': [
|
228
|
+
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
229
|
+
'rest_framework.authentication.SessionAuthentication',
|
230
|
+
],
|
231
|
+
'DEFAULT_PERMISSION_CLASSES': [
|
232
|
+
'rest_framework.permissions.IsAuthenticated',
|
233
|
+
],
|
234
|
+
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
235
|
+
'PAGE_SIZE': 20,
|
236
|
+
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
237
|
+
}
|
412
238
|
|
413
|
-
@
|
414
|
-
def
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
environment: Current environment
|
425
|
-
debug: Django DEBUG setting
|
426
|
-
engine: Database engine (to determine which options to apply)
|
427
|
-
|
428
|
-
Returns:
|
429
|
-
Database settings dictionary
|
430
|
-
"""
|
431
|
-
try:
|
432
|
-
defaults = {}
|
433
|
-
|
434
|
-
if environment == "testing":
|
435
|
-
# Testing: Use in-memory SQLite
|
436
|
-
defaults = {
|
437
|
-
'ENGINE': 'django.db.backends.sqlite3',
|
438
|
-
'NAME': ':memory:',
|
439
|
-
'OPTIONS': {
|
440
|
-
'timeout': 1, # Very short timeout for tests
|
441
|
-
}
|
442
|
-
}
|
443
|
-
|
444
|
-
elif environment == "development" or debug:
|
445
|
-
# Development: Only add PostgreSQL/MySQL specific options
|
446
|
-
if engine and engine in ("django.db.backends.postgresql", "django.db.backends.mysql"):
|
447
|
-
defaults = {
|
448
|
-
'OPTIONS': {
|
449
|
-
'connect_timeout': 5, # Short timeout for dev
|
450
|
-
}
|
451
|
-
}
|
452
|
-
# Add sslmode only for PostgreSQL
|
453
|
-
if engine == "django.db.backends.postgresql":
|
454
|
-
defaults['OPTIONS']['sslmode'] = 'prefer'
|
455
|
-
else:
|
456
|
-
# For SQLite, no special options needed
|
457
|
-
defaults = {}
|
458
|
-
|
459
|
-
elif environment in ("production", "staging"):
|
460
|
-
# Production: Only add PostgreSQL/MySQL specific options
|
461
|
-
if engine and engine in ("django.db.backends.postgresql", "django.db.backends.mysql"):
|
462
|
-
if engine == "django.db.backends.postgresql":
|
463
|
-
# psycopg3 supports connection pooling with proper parameters
|
464
|
-
defaults = {
|
465
|
-
'OPTIONS': {
|
466
|
-
'connect_timeout': 10,
|
467
|
-
# psycopg3 connection pool parameters
|
468
|
-
'pool': {
|
469
|
-
'min_size': 1,
|
470
|
-
'max_size': 20,
|
471
|
-
'timeout': 30.0,
|
472
|
-
}
|
473
|
-
}
|
474
|
-
}
|
475
|
-
else:
|
476
|
-
# MySQL
|
477
|
-
defaults = {
|
478
|
-
'OPTIONS': {
|
479
|
-
'connect_timeout': 10,
|
480
|
-
}
|
481
|
-
}
|
482
|
-
# Add sslmode only for PostgreSQL
|
483
|
-
if engine == "django.db.backends.postgresql":
|
484
|
-
defaults['OPTIONS']['sslmode'] = 'require' # Require SSL in production
|
485
|
-
else:
|
486
|
-
# For SQLite, no special options needed
|
487
|
-
defaults = {}
|
488
|
-
|
489
|
-
return defaults
|
490
|
-
|
491
|
-
except Exception as e:
|
492
|
-
raise ConfigurationError(
|
493
|
-
f"Failed to generate database defaults: {e}",
|
494
|
-
context={
|
495
|
-
'environment': environment,
|
496
|
-
'debug': debug
|
497
|
-
}
|
498
|
-
) from e
|
239
|
+
@staticmethod
|
240
|
+
def get_cors_defaults() -> Dict[str, Any]:
|
241
|
+
"""Get CORS configuration defaults."""
|
242
|
+
return {
|
243
|
+
'CORS_ALLOWED_ORIGINS': [
|
244
|
+
"http://localhost:3000",
|
245
|
+
"http://127.0.0.1:3000",
|
246
|
+
],
|
247
|
+
'CORS_ALLOW_CREDENTIALS': True,
|
248
|
+
'CORS_ALLOW_ALL_ORIGINS': False,
|
249
|
+
}
|
499
250
|
|
500
|
-
@
|
501
|
-
def
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
Returns:
|
514
|
-
Logging configuration dictionary
|
515
|
-
"""
|
516
|
-
try:
|
517
|
-
if environment == "testing":
|
518
|
-
# Testing: Minimal logging
|
519
|
-
return {
|
520
|
-
'version': 1,
|
521
|
-
'disable_existing_loggers': False,
|
522
|
-
'handlers': {
|
523
|
-
'null': {
|
524
|
-
'class': 'logging.NullHandler',
|
525
|
-
},
|
526
|
-
},
|
527
|
-
'root': {
|
528
|
-
'handlers': ['null'],
|
529
|
-
},
|
530
|
-
}
|
531
|
-
|
532
|
-
elif environment == "development" or debug:
|
533
|
-
# Development: Console logging with colors
|
534
|
-
return {
|
535
|
-
'version': 1,
|
536
|
-
'disable_existing_loggers': False,
|
537
|
-
'formatters': {
|
538
|
-
'verbose': {
|
539
|
-
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
|
540
|
-
'style': '{',
|
541
|
-
},
|
542
|
-
},
|
543
|
-
'handlers': {
|
544
|
-
'console': {
|
545
|
-
'class': 'logging.StreamHandler',
|
546
|
-
'formatter': 'verbose',
|
547
|
-
},
|
548
|
-
},
|
549
|
-
'root': {
|
550
|
-
'handlers': ['console'],
|
551
|
-
'level': 'DEBUG',
|
552
|
-
},
|
553
|
-
'loggers': {
|
554
|
-
'django': {
|
555
|
-
'handlers': ['console'],
|
556
|
-
'level': 'INFO',
|
557
|
-
'propagate': False,
|
558
|
-
},
|
559
|
-
},
|
560
|
-
}
|
561
|
-
|
562
|
-
elif environment in ("production", "staging"):
|
563
|
-
# Production: File and structured logging
|
564
|
-
return {
|
565
|
-
'version': 1,
|
566
|
-
'disable_existing_loggers': False,
|
567
|
-
'formatters': {
|
568
|
-
'json': {
|
569
|
-
'class': 'pythonjsonlogger.jsonlogger.JsonFormatter',
|
570
|
-
'format': '%(asctime)s %(name)s %(levelname)s %(message)s'
|
571
|
-
},
|
572
|
-
'standard': {
|
573
|
-
'format': '{levelname} {asctime} {name} {message}',
|
574
|
-
'style': '{',
|
575
|
-
},
|
576
|
-
},
|
577
|
-
'handlers': {
|
578
|
-
'file': {
|
579
|
-
'class': 'logging.handlers.RotatingFileHandler',
|
580
|
-
'filename': 'logs/django.log',
|
581
|
-
'maxBytes': 1024*1024*10, # 10MB
|
582
|
-
'backupCount': 5,
|
583
|
-
'formatter': 'json' if environment == "production" else 'standard',
|
584
|
-
},
|
585
|
-
'console': {
|
586
|
-
'class': 'logging.StreamHandler',
|
587
|
-
'formatter': 'standard',
|
588
|
-
},
|
589
|
-
},
|
590
|
-
'root': {
|
591
|
-
'handlers': ['file', 'console'],
|
592
|
-
'level': 'WARNING' if environment == "production" else 'INFO',
|
593
|
-
},
|
594
|
-
'loggers': {
|
595
|
-
'django': {
|
596
|
-
'handlers': ['file'],
|
597
|
-
'level': 'INFO',
|
598
|
-
'propagate': False,
|
599
|
-
},
|
600
|
-
},
|
601
|
-
}
|
602
|
-
|
603
|
-
# Fallback
|
604
|
-
return {}
|
605
|
-
|
606
|
-
except Exception as e:
|
607
|
-
raise ConfigurationError(
|
608
|
-
f"Failed to generate logging defaults: {e}",
|
609
|
-
context={
|
610
|
-
'environment': environment,
|
611
|
-
'debug': debug
|
612
|
-
}
|
613
|
-
) from e
|
251
|
+
@staticmethod
|
252
|
+
def configure_cache_backend(cache_config, environment: str, debug: bool):
|
253
|
+
"""Configure cache backend - simplified."""
|
254
|
+
if cache_config is None:
|
255
|
+
return CacheConfig()
|
256
|
+
return cache_config
|
257
|
+
|
258
|
+
@staticmethod
|
259
|
+
def configure_email_backend(email_config, environment: str, debug: bool):
|
260
|
+
"""Configure email backend - simplified."""
|
261
|
+
if email_config is None:
|
262
|
+
return EmailConfig()
|
263
|
+
return email_config
|
614
264
|
|
615
265
|
|
616
266
|
# Export the main class
|
617
267
|
__all__ = [
|
618
268
|
"SmartDefaults",
|
269
|
+
"get_log_filename",
|
619
270
|
]
|