django-cfg 1.4.10__py3-none-any.whl โ 1.4.11__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/apps/agents/management/commands/create_agent.py +1 -1
- django_cfg/apps/agents/management/commands/orchestrator_status.py +3 -3
- django_cfg/apps/newsletter/serializers.py +40 -3
- django_cfg/apps/newsletter/views/campaigns.py +12 -3
- django_cfg/apps/newsletter/views/emails.py +14 -3
- django_cfg/apps/newsletter/views/subscriptions.py +12 -2
- django_cfg/apps/payments/views/api/currencies.py +49 -6
- django_cfg/apps/payments/views/api/webhooks.py +72 -7
- django_cfg/apps/payments/views/overview/serializers.py +34 -1
- django_cfg/apps/payments/views/overview/views.py +2 -1
- django_cfg/apps/payments/views/serializers/payments.py +6 -6
- django_cfg/apps/urls.py +106 -45
- django_cfg/core/base/config_model.py +2 -2
- django_cfg/core/constants.py +1 -1
- django_cfg/core/generation/integration_generators/__init__.py +1 -1
- django_cfg/core/generation/integration_generators/api.py +72 -49
- django_cfg/core/integration/display/startup.py +30 -22
- django_cfg/core/integration/url_integration.py +15 -16
- django_cfg/dashboard/sections/documentation.py +391 -0
- django_cfg/management/commands/check_endpoints.py +11 -160
- django_cfg/management/commands/check_settings.py +13 -348
- django_cfg/management/commands/clear_constance.py +13 -201
- django_cfg/management/commands/create_token.py +13 -321
- django_cfg/management/commands/generate_clients.py +23 -0
- django_cfg/management/commands/list_urls.py +13 -306
- django_cfg/management/commands/migrate_all.py +13 -126
- django_cfg/management/commands/migrator.py +13 -396
- django_cfg/management/commands/rundramatiq.py +15 -247
- django_cfg/management/commands/rundramatiq_simulator.py +12 -429
- django_cfg/management/commands/runserver_ngrok.py +15 -160
- django_cfg/management/commands/script.py +12 -488
- django_cfg/management/commands/show_config.py +12 -215
- django_cfg/management/commands/show_urls.py +12 -342
- django_cfg/management/commands/superuser.py +15 -295
- django_cfg/management/commands/task_clear.py +14 -217
- django_cfg/management/commands/task_status.py +13 -248
- django_cfg/management/commands/test_email.py +15 -86
- django_cfg/management/commands/test_telegram.py +14 -61
- django_cfg/management/commands/test_twilio.py +15 -105
- django_cfg/management/commands/tree.py +13 -383
- django_cfg/management/commands/validate_openapi.py +10 -0
- django_cfg/middleware/README.md +1 -1
- django_cfg/middleware/user_activity.py +3 -3
- django_cfg/models/__init__.py +2 -2
- django_cfg/models/api/drf/spectacular.py +6 -6
- django_cfg/models/django/__init__.py +2 -2
- django_cfg/models/django/openapi.py +238 -0
- django_cfg/modules/django_admin/management/__init__.py +0 -0
- django_cfg/modules/django_admin/management/commands/__init__.py +0 -0
- django_cfg/modules/django_admin/management/commands/check_endpoints.py +169 -0
- django_cfg/modules/django_admin/management/commands/check_settings.py +355 -0
- django_cfg/modules/django_admin/management/commands/clear_constance.py +208 -0
- django_cfg/modules/django_admin/management/commands/create_token.py +328 -0
- django_cfg/modules/django_admin/management/commands/list_urls.py +313 -0
- django_cfg/modules/django_admin/management/commands/migrate_all.py +133 -0
- django_cfg/modules/django_admin/management/commands/migrator.py +403 -0
- django_cfg/modules/django_admin/management/commands/script.py +496 -0
- django_cfg/modules/django_admin/management/commands/show_config.py +225 -0
- django_cfg/modules/django_admin/management/commands/show_urls.py +361 -0
- django_cfg/modules/django_admin/management/commands/superuser.py +302 -0
- django_cfg/modules/django_admin/management/commands/tree.py +390 -0
- django_cfg/modules/django_client/__init__.py +20 -0
- django_cfg/modules/django_client/apps.py +35 -0
- django_cfg/modules/django_client/core/__init__.py +56 -0
- django_cfg/modules/django_client/core/archive/__init__.py +11 -0
- django_cfg/modules/django_client/core/archive/manager.py +134 -0
- django_cfg/modules/django_client/core/cli/__init__.py +12 -0
- django_cfg/modules/django_client/core/cli/main.py +235 -0
- django_cfg/modules/django_client/core/config/__init__.py +18 -0
- django_cfg/modules/django_client/core/config/config.py +188 -0
- django_cfg/modules/django_client/core/config/group.py +101 -0
- django_cfg/modules/django_client/core/config/service.py +209 -0
- django_cfg/modules/django_client/core/generator/__init__.py +115 -0
- django_cfg/modules/django_client/core/generator/base.py +767 -0
- django_cfg/modules/django_client/core/generator/python.py +751 -0
- django_cfg/modules/django_client/core/generator/templates/python/__init__.py.jinja +9 -0
- django_cfg/modules/django_client/core/generator/templates/python/api_wrapper.py.jinja +130 -0
- django_cfg/modules/django_client/core/generator/templates/python/app_init.py.jinja +6 -0
- django_cfg/modules/django_client/core/generator/templates/python/client/app_client.py.jinja +18 -0
- django_cfg/modules/django_client/core/generator/templates/python/client/flat_client.py.jinja +38 -0
- django_cfg/modules/django_client/core/generator/templates/python/client/main_client.py.jinja +50 -0
- django_cfg/modules/django_client/core/generator/templates/python/client/main_client_file.py.jinja +13 -0
- django_cfg/modules/django_client/core/generator/templates/python/client/operation_method.py.jinja +7 -0
- django_cfg/modules/django_client/core/generator/templates/python/client/sub_client.py.jinja +11 -0
- django_cfg/modules/django_client/core/generator/templates/python/client_file.py.jinja +13 -0
- django_cfg/modules/django_client/core/generator/templates/python/main_init.py.jinja +50 -0
- django_cfg/modules/django_client/core/generator/templates/python/models/app_models.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/templates/python/models/enum_class.py.jinja +15 -0
- django_cfg/modules/django_client/core/generator/templates/python/models/enums.py.jinja +8 -0
- django_cfg/modules/django_client/core/generator/templates/python/models/models.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/templates/python/models/schema_class.py.jinja +19 -0
- django_cfg/modules/django_client/core/generator/templates/python/utils/logger.py.jinja +255 -0
- django_cfg/modules/django_client/core/generator/templates/python/utils/schema.py.jinja +12 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/app_index.ts.jinja +2 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/client/app_client.ts.jinja +18 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/client/client.ts.jinja +327 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/client/flat_client.ts.jinja +109 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/client/main_client_file.ts.jinja +9 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/client/operation.ts.jinja +61 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/client/sub_client.ts.jinja +15 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/client_file.ts.jinja +9 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/index.ts.jinja +5 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/main_index.ts.jinja +206 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/models/app_models.ts.jinja +8 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/models/enums.ts.jinja +4 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/models/models.ts.jinja +8 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/utils/errors.ts.jinja +114 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/utils/http.ts.jinja +98 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/utils/logger.ts.jinja +251 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/utils/schema.ts.jinja +7 -0
- django_cfg/modules/django_client/core/generator/templates/typescript/utils/storage.ts.jinja +114 -0
- django_cfg/modules/django_client/core/generator/typescript.py +872 -0
- django_cfg/modules/django_client/core/groups/__init__.py +13 -0
- django_cfg/modules/django_client/core/groups/detector.py +178 -0
- django_cfg/modules/django_client/core/groups/manager.py +314 -0
- django_cfg/modules/django_client/core/ir/__init__.py +57 -0
- django_cfg/modules/django_client/core/ir/context.py +387 -0
- django_cfg/modules/django_client/core/ir/operation.py +518 -0
- django_cfg/modules/django_client/core/ir/schema.py +353 -0
- django_cfg/modules/django_client/core/parser/__init__.py +74 -0
- django_cfg/modules/django_client/core/parser/base.py +648 -0
- django_cfg/modules/django_client/core/parser/models/__init__.py +74 -0
- django_cfg/modules/django_client/core/parser/models/base.py +212 -0
- django_cfg/modules/django_client/core/parser/models/components.py +160 -0
- django_cfg/modules/django_client/core/parser/models/openapi.py +203 -0
- django_cfg/modules/django_client/core/parser/models/operation.py +207 -0
- django_cfg/modules/django_client/core/parser/models/schema.py +266 -0
- django_cfg/modules/django_client/core/parser/openapi30.py +56 -0
- django_cfg/modules/django_client/core/parser/openapi31.py +64 -0
- django_cfg/modules/django_client/core/validation/__init__.py +22 -0
- django_cfg/modules/django_client/core/validation/checker.py +134 -0
- django_cfg/modules/django_client/core/validation/fixer.py +216 -0
- django_cfg/modules/django_client/core/validation/reporter.py +480 -0
- django_cfg/modules/django_client/core/validation/rules/__init__.py +11 -0
- django_cfg/modules/django_client/core/validation/rules/base.py +96 -0
- django_cfg/modules/django_client/core/validation/rules/type_hints.py +288 -0
- django_cfg/modules/django_client/core/validation/safety.py +266 -0
- django_cfg/modules/django_client/management/__init__.py +3 -0
- django_cfg/modules/django_client/management/commands/__init__.py +3 -0
- django_cfg/modules/django_client/management/commands/generate_client.py +422 -0
- django_cfg/modules/django_client/management/commands/validate_openapi.py +343 -0
- django_cfg/modules/django_client/spectacular/__init__.py +9 -0
- django_cfg/modules/django_client/spectacular/enum_naming.py +192 -0
- django_cfg/modules/django_client/urls.py +72 -0
- django_cfg/modules/django_email/management/__init__.py +0 -0
- django_cfg/modules/django_email/management/commands/__init__.py +0 -0
- django_cfg/modules/django_email/management/commands/test_email.py +93 -0
- django_cfg/modules/django_logging/django_logger.py +6 -6
- django_cfg/modules/django_ngrok/management/__init__.py +0 -0
- django_cfg/modules/django_ngrok/management/commands/__init__.py +0 -0
- django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +167 -0
- django_cfg/modules/django_tasks/management/__init__.py +0 -0
- django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
- django_cfg/modules/django_tasks/management/commands/rundramatiq.py +254 -0
- django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +437 -0
- django_cfg/modules/django_tasks/management/commands/task_clear.py +226 -0
- django_cfg/modules/django_tasks/management/commands/task_status.py +257 -0
- django_cfg/modules/django_telegram/management/__init__.py +0 -0
- django_cfg/modules/django_telegram/management/commands/__init__.py +0 -0
- django_cfg/modules/django_telegram/management/commands/test_telegram.py +68 -0
- django_cfg/modules/django_twilio/management/__init__.py +0 -0
- django_cfg/modules/django_twilio/management/commands/__init__.py +0 -0
- django_cfg/modules/django_twilio/management/commands/test_twilio.py +112 -0
- django_cfg/modules/django_unfold/callbacks/main.py +16 -5
- django_cfg/modules/django_unfold/callbacks/revolution.py +41 -36
- django_cfg/pyproject.toml +2 -6
- django_cfg/registry/third_party.py +5 -7
- django_cfg/routing/callbacks.py +1 -1
- django_cfg/static/admin/css/prose-unfold.css +666 -0
- django_cfg/templates/admin/index.html +8 -0
- django_cfg/templates/admin/index_new.html +13 -0
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +15 -3
- django_cfg/templates/admin/sections/documentation_section.html +172 -0
- django_cfg/templates/admin/snippets/tabs/documentation_tab.html +231 -0
- {django_cfg-1.4.10.dist-info โ django_cfg-1.4.11.dist-info}/METADATA +2 -2
- {django_cfg-1.4.10.dist-info โ django_cfg-1.4.11.dist-info}/RECORD +180 -59
- django_cfg/management/commands/generate.py +0 -107
- /django_cfg/models/django/{revolution.py โ revolution_legacy.py} +0 -0
- {django_cfg-1.4.10.dist-info โ django_cfg-1.4.11.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.10.dist-info โ django_cfg-1.4.11.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.10.dist-info โ django_cfg-1.4.11.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,355 @@
|
|
1
|
+
"""
|
2
|
+
Django CFG Settings Checker
|
3
|
+
|
4
|
+
Comprehensive validation and debugging tool for django-cfg configuration.
|
5
|
+
Helps diagnose email, database, and other configuration issues.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import os
|
9
|
+
import sys
|
10
|
+
from pathlib import Path
|
11
|
+
from django.core.management.base import BaseCommand
|
12
|
+
from django.conf import settings
|
13
|
+
from django.core.exceptions import ImproperlyConfigured
|
14
|
+
from django.core.mail import get_connection
|
15
|
+
from datetime import datetime
|
16
|
+
from django_cfg.modules.django_logging import get_logger
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
logger = get_logger('check_settings')
|
21
|
+
|
22
|
+
class Command(BaseCommand):
|
23
|
+
"""Command to check and debug django-cfg settings."""
|
24
|
+
|
25
|
+
# Web execution metadata
|
26
|
+
web_executable = True
|
27
|
+
requires_input = False
|
28
|
+
is_destructive = False
|
29
|
+
|
30
|
+
help = "Check and debug django-cfg configuration settings"
|
31
|
+
|
32
|
+
def add_arguments(self, parser):
|
33
|
+
parser.add_argument(
|
34
|
+
'--email-test',
|
35
|
+
action='store_true',
|
36
|
+
help='Test email configuration and SMTP connection'
|
37
|
+
)
|
38
|
+
parser.add_argument(
|
39
|
+
'--verbose',
|
40
|
+
action='store_true',
|
41
|
+
help='Show detailed configuration information'
|
42
|
+
)
|
43
|
+
|
44
|
+
def handle(self, *args, **options):
|
45
|
+
"""Main command handler."""
|
46
|
+
logger.info("Starting check_settings command")
|
47
|
+
self.stdout.write(self.style.SUCCESS("\n๐ Django CFG Settings Checker\n"))
|
48
|
+
|
49
|
+
# Show basic info
|
50
|
+
self.show_environment_info()
|
51
|
+
self.show_email_config()
|
52
|
+
self.show_drf_config()
|
53
|
+
|
54
|
+
if options['verbose']:
|
55
|
+
self.show_database_config()
|
56
|
+
self.show_app_config()
|
57
|
+
self.show_cors_config()
|
58
|
+
|
59
|
+
if options['email_test']:
|
60
|
+
self.test_email_connection()
|
61
|
+
|
62
|
+
def show_environment_info(self):
|
63
|
+
"""Show environment and debug information."""
|
64
|
+
self.stdout.write(self.style.SUCCESS("๐ Environment Information:"))
|
65
|
+
|
66
|
+
# Debug mode
|
67
|
+
debug = getattr(settings, 'DEBUG', False)
|
68
|
+
self.stdout.write(f" ๐ DEBUG: {debug}")
|
69
|
+
|
70
|
+
# Environment detection
|
71
|
+
env_vars = {
|
72
|
+
'DJANGO_SETTINGS_MODULE': os.environ.get('DJANGO_SETTINGS_MODULE', 'Not set'),
|
73
|
+
'ENVIRONMENT': os.environ.get('ENVIRONMENT', 'Not set'),
|
74
|
+
}
|
75
|
+
|
76
|
+
for key, value in env_vars.items():
|
77
|
+
self.stdout.write(f" ๐ {key}: {value}")
|
78
|
+
|
79
|
+
def show_email_config(self):
|
80
|
+
"""Show detailed email configuration."""
|
81
|
+
self.stdout.write(self.style.SUCCESS("\n๐ง Email Configuration:"))
|
82
|
+
|
83
|
+
# Basic email settings
|
84
|
+
email_settings = {
|
85
|
+
'EMAIL_BACKEND': getattr(settings, 'EMAIL_BACKEND', 'Not set'),
|
86
|
+
'EMAIL_HOST': getattr(settings, 'EMAIL_HOST', 'Not set'),
|
87
|
+
'EMAIL_PORT': getattr(settings, 'EMAIL_PORT', 'Not set'),
|
88
|
+
'EMAIL_USE_TLS': getattr(settings, 'EMAIL_USE_TLS', 'Not set'),
|
89
|
+
'EMAIL_USE_SSL': getattr(settings, 'EMAIL_USE_SSL', 'Not set'),
|
90
|
+
'EMAIL_HOST_USER': getattr(settings, 'EMAIL_HOST_USER', 'Not set'),
|
91
|
+
'DEFAULT_FROM_EMAIL': getattr(settings, 'DEFAULT_FROM_EMAIL', 'Not set'),
|
92
|
+
}
|
93
|
+
|
94
|
+
# Show password status (not actual password)
|
95
|
+
password_set = bool(getattr(settings, 'EMAIL_HOST_PASSWORD', None))
|
96
|
+
email_settings['EMAIL_HOST_PASSWORD'] = '***SET***' if password_set else 'Not set'
|
97
|
+
|
98
|
+
for key, value in email_settings.items():
|
99
|
+
icon = "โ
" if value != 'Not set' else "โ"
|
100
|
+
self.stdout.write(f" {icon} {key}: {value}")
|
101
|
+
|
102
|
+
# Analyze backend type
|
103
|
+
backend = email_settings['EMAIL_BACKEND']
|
104
|
+
if 'console' in backend:
|
105
|
+
self.stdout.write(self.style.WARNING(" โ ๏ธ Console backend - emails will be printed to console"))
|
106
|
+
elif 'locmem' in backend:
|
107
|
+
self.stdout.write(self.style.WARNING(" โ ๏ธ Local memory backend - emails stored in memory"))
|
108
|
+
elif 'filebased' in backend:
|
109
|
+
self.stdout.write(self.style.WARNING(" โ ๏ธ File backend - emails saved to files"))
|
110
|
+
elif 'smtp' in backend:
|
111
|
+
self.stdout.write(self.style.SUCCESS(" ๐ค SMTP backend - emails will be sent via SMTP"))
|
112
|
+
|
113
|
+
# Check django-cfg email service
|
114
|
+
try:
|
115
|
+
from django_cfg.modules.django_email import DjangoEmailService
|
116
|
+
email_service = DjangoEmailService()
|
117
|
+
backend_info = email_service.get_backend_info()
|
118
|
+
|
119
|
+
self.stdout.write(f"\n ๐ง Django CFG Email Service:")
|
120
|
+
self.stdout.write(f" Backend: {backend_info['backend']}")
|
121
|
+
self.stdout.write(f" Configured: {backend_info['configured']}")
|
122
|
+
|
123
|
+
except Exception as e:
|
124
|
+
self.stdout.write(self.style.ERROR(f" โ Django CFG Email Service error: {e}"))
|
125
|
+
|
126
|
+
def show_drf_config(self):
|
127
|
+
"""Show DRF and Spectacular configuration."""
|
128
|
+
self.stdout.write(self.style.SUCCESS("\n๐ DRF & Spectacular Configuration:"))
|
129
|
+
|
130
|
+
# Check REST_FRAMEWORK settings
|
131
|
+
rest_framework = getattr(settings, 'REST_FRAMEWORK', {})
|
132
|
+
if rest_framework:
|
133
|
+
self.stdout.write(" โ
REST_FRAMEWORK configured")
|
134
|
+
|
135
|
+
# Show key DRF settings
|
136
|
+
drf_settings = {
|
137
|
+
'DEFAULT_SCHEMA_CLASS': rest_framework.get('DEFAULT_SCHEMA_CLASS', 'Not set'),
|
138
|
+
'DEFAULT_AUTHENTICATION_CLASSES': rest_framework.get('DEFAULT_AUTHENTICATION_CLASSES', []),
|
139
|
+
'DEFAULT_PERMISSION_CLASSES': rest_framework.get('DEFAULT_PERMISSION_CLASSES', []),
|
140
|
+
'DEFAULT_PAGINATION_CLASS': rest_framework.get('DEFAULT_PAGINATION_CLASS', 'Not set'),
|
141
|
+
'PAGE_SIZE': rest_framework.get('PAGE_SIZE', 'Not set'),
|
142
|
+
}
|
143
|
+
|
144
|
+
for key, value in drf_settings.items():
|
145
|
+
icon = "โ
" if value and value != 'Not set' else "โ"
|
146
|
+
if isinstance(value, list):
|
147
|
+
if value:
|
148
|
+
self.stdout.write(f" {icon} {key}:")
|
149
|
+
for item in value:
|
150
|
+
self.stdout.write(f" - {item}")
|
151
|
+
else:
|
152
|
+
self.stdout.write(f" {icon} {key}: []")
|
153
|
+
else:
|
154
|
+
self.stdout.write(f" {icon} {key}: {value}")
|
155
|
+
else:
|
156
|
+
self.stdout.write(" โ REST_FRAMEWORK not configured")
|
157
|
+
|
158
|
+
# Check SPECTACULAR_SETTINGS
|
159
|
+
spectacular = getattr(settings, 'SPECTACULAR_SETTINGS', {})
|
160
|
+
if spectacular:
|
161
|
+
self.stdout.write("\n โ
SPECTACULAR_SETTINGS configured")
|
162
|
+
|
163
|
+
# Show key Spectacular settings
|
164
|
+
spectacular_settings = {
|
165
|
+
'TITLE': spectacular.get('TITLE', 'Not set'),
|
166
|
+
'VERSION': spectacular.get('VERSION', 'Not set'),
|
167
|
+
'SCHEMA_PATH_PREFIX': spectacular.get('SCHEMA_PATH_PREFIX', 'Not set'),
|
168
|
+
'SERVE_INCLUDE_SCHEMA': spectacular.get('SERVE_INCLUDE_SCHEMA', 'Not set'),
|
169
|
+
}
|
170
|
+
|
171
|
+
for key, value in spectacular_settings.items():
|
172
|
+
icon = "โ
" if value != 'Not set' else "โ"
|
173
|
+
self.stdout.write(f" {icon} {key}: {value}")
|
174
|
+
else:
|
175
|
+
self.stdout.write("\n โ SPECTACULAR_SETTINGS not configured")
|
176
|
+
|
177
|
+
# Check SimpleJWT settings
|
178
|
+
simple_jwt = getattr(settings, 'SIMPLE_JWT', {})
|
179
|
+
if simple_jwt:
|
180
|
+
self.stdout.write("\n โ
SIMPLE_JWT configured")
|
181
|
+
|
182
|
+
jwt_settings = {
|
183
|
+
'ACCESS_TOKEN_LIFETIME': simple_jwt.get('ACCESS_TOKEN_LIFETIME', 'Not set'),
|
184
|
+
'REFRESH_TOKEN_LIFETIME': simple_jwt.get('REFRESH_TOKEN_LIFETIME', 'Not set'),
|
185
|
+
'ALGORITHM': simple_jwt.get('ALGORITHM', 'Not set'),
|
186
|
+
}
|
187
|
+
|
188
|
+
for key, value in jwt_settings.items():
|
189
|
+
icon = "โ
" if value != 'Not set' else "โ"
|
190
|
+
self.stdout.write(f" {icon} {key}: {value}")
|
191
|
+
else:
|
192
|
+
self.stdout.write("\n โ SIMPLE_JWT not configured")
|
193
|
+
|
194
|
+
# Get django-cfg config
|
195
|
+
try:
|
196
|
+
from django_cfg.core.state import get_current_config
|
197
|
+
config = get_current_config()
|
198
|
+
|
199
|
+
if config:
|
200
|
+
self.stdout.write("\n ๐ Django-CFG Config:")
|
201
|
+
self.stdout.write(f" drf: {'โ
Configured' if config.drf else 'โ Not set'}")
|
202
|
+
self.stdout.write(f" spectacular: {'โ
Configured' if config.spectacular else 'โ Not set'}")
|
203
|
+
self.stdout.write(f" jwt: {'โ
Configured' if config.jwt else 'โ Not set'}")
|
204
|
+
self.stdout.write(f" openapi_client: {'โ
Configured' if hasattr(config, 'openapi_client') and config.openapi_client else 'โ Not set'}")
|
205
|
+
except Exception as e:
|
206
|
+
self.stdout.write(self.style.ERROR(f" โ Error getting django-cfg config: {e}"))
|
207
|
+
|
208
|
+
def show_database_config(self):
|
209
|
+
"""Show database configuration."""
|
210
|
+
self.stdout.write(self.style.SUCCESS("\n๐๏ธ Database Configuration:"))
|
211
|
+
|
212
|
+
databases = getattr(settings, 'DATABASES', {})
|
213
|
+
for db_name, db_config in databases.items():
|
214
|
+
engine = db_config.get('ENGINE', 'Unknown')
|
215
|
+
name = db_config.get('NAME', 'Unknown')
|
216
|
+
host = db_config.get('HOST', 'localhost')
|
217
|
+
port = db_config.get('PORT', 'default')
|
218
|
+
|
219
|
+
self.stdout.write(f" ๐ {db_name}:")
|
220
|
+
self.stdout.write(f" Engine: {engine}")
|
221
|
+
self.stdout.write(f" Name: {name}")
|
222
|
+
if host and host != 'localhost':
|
223
|
+
self.stdout.write(f" Host: {host}:{port}")
|
224
|
+
|
225
|
+
def show_app_config(self):
|
226
|
+
"""Show installed apps configuration."""
|
227
|
+
self.stdout.write(self.style.SUCCESS("\n๐ฆ Django CFG Apps:"))
|
228
|
+
|
229
|
+
installed_apps = getattr(settings, 'INSTALLED_APPS', [])
|
230
|
+
cfg_apps = [app for app in installed_apps if 'django_cfg' in app]
|
231
|
+
|
232
|
+
for app in cfg_apps:
|
233
|
+
self.stdout.write(f" โ
{app}")
|
234
|
+
|
235
|
+
if not cfg_apps:
|
236
|
+
self.stdout.write(" โ No django_cfg apps found")
|
237
|
+
|
238
|
+
def show_cors_config(self):
|
239
|
+
"""Show CORS and security configuration."""
|
240
|
+
self.stdout.write(self.style.SUCCESS("\n๐ CORS & Security Configuration:"))
|
241
|
+
|
242
|
+
# Get current config
|
243
|
+
try:
|
244
|
+
from django_cfg.core.state import get_current_config
|
245
|
+
config = get_current_config()
|
246
|
+
|
247
|
+
if config:
|
248
|
+
self.stdout.write(f" ๐ Security Domains: {config.security_domains}")
|
249
|
+
self.stdout.write(f" ๐ CORS Headers: {config.cors_allow_headers}")
|
250
|
+
self.stdout.write(f" ๐ SSL Redirect: {config.ssl_redirect}")
|
251
|
+
else:
|
252
|
+
self.stdout.write(" โ ๏ธ No django-cfg config instance found")
|
253
|
+
|
254
|
+
except Exception as e:
|
255
|
+
self.stdout.write(self.style.ERROR(f" โ Error getting config: {e}"))
|
256
|
+
|
257
|
+
# Show Django settings
|
258
|
+
cors_settings = {
|
259
|
+
'CORS_ALLOW_ALL_ORIGINS': getattr(settings, 'CORS_ALLOW_ALL_ORIGINS', None),
|
260
|
+
'CORS_ALLOWED_ORIGINS': getattr(settings, 'CORS_ALLOWED_ORIGINS', None),
|
261
|
+
'CORS_ALLOW_CREDENTIALS': getattr(settings, 'CORS_ALLOW_CREDENTIALS', None),
|
262
|
+
'CORS_ALLOW_HEADERS': getattr(settings, 'CORS_ALLOW_HEADERS', None),
|
263
|
+
'CSRF_TRUSTED_ORIGINS': getattr(settings, 'CSRF_TRUSTED_ORIGINS', None),
|
264
|
+
}
|
265
|
+
|
266
|
+
self.stdout.write("\n ๐ง Generated Django Settings:")
|
267
|
+
for key, value in cors_settings.items():
|
268
|
+
if value is not None:
|
269
|
+
icon = "โ
"
|
270
|
+
if key == 'CORS_ALLOW_HEADERS' and isinstance(value, list):
|
271
|
+
# Show first few headers for readability
|
272
|
+
display_value = value[:3] + ['...'] if len(value) > 3 else value
|
273
|
+
self.stdout.write(f" {icon} {key}: {display_value} ({len(value)} total)")
|
274
|
+
elif key in ['CORS_ALLOWED_ORIGINS', 'CSRF_TRUSTED_ORIGINS'] and isinstance(value, list):
|
275
|
+
self.stdout.write(f" {icon} {key}: {value}")
|
276
|
+
else:
|
277
|
+
self.stdout.write(f" {icon} {key}: {value}")
|
278
|
+
else:
|
279
|
+
self.stdout.write(f" โญ {key}: Not set")
|
280
|
+
|
281
|
+
# Analysis
|
282
|
+
self.stdout.write("\n ๐ CORS Analysis:")
|
283
|
+
if cors_settings['CORS_ALLOW_ALL_ORIGINS']:
|
284
|
+
self.stdout.write(" ๐ก Development mode: All origins allowed")
|
285
|
+
elif cors_settings['CORS_ALLOWED_ORIGINS']:
|
286
|
+
origins_count = len(cors_settings['CORS_ALLOWED_ORIGINS'])
|
287
|
+
self.stdout.write(f" ๐ข Production mode: {origins_count} specific origins allowed")
|
288
|
+
else:
|
289
|
+
self.stdout.write(" ๐ด No CORS origins configured")
|
290
|
+
|
291
|
+
def test_email_connection(self):
|
292
|
+
"""Test email connection."""
|
293
|
+
self.stdout.write(self.style.SUCCESS("\n๐งช Testing Email Connection:"))
|
294
|
+
|
295
|
+
try:
|
296
|
+
# Test Django's email connection
|
297
|
+
connection = get_connection()
|
298
|
+
connection.open()
|
299
|
+
self.stdout.write(" โ
Django email connection successful")
|
300
|
+
connection.close()
|
301
|
+
|
302
|
+
except Exception as e:
|
303
|
+
self.stdout.write(self.style.ERROR(f" โ Django email connection failed: {e}"))
|
304
|
+
|
305
|
+
try:
|
306
|
+
# Test django-cfg email service
|
307
|
+
from django_cfg.modules.django_email import DjangoEmailService
|
308
|
+
email_service = DjangoEmailService()
|
309
|
+
|
310
|
+
# Try to send a test email (dry run)
|
311
|
+
self.stdout.write(" ๐ Testing django-cfg email service...")
|
312
|
+
|
313
|
+
# Just check if service can be initialized
|
314
|
+
backend_info = email_service.get_backend_info()
|
315
|
+
if backend_info['configured']:
|
316
|
+
self.stdout.write(" โ
Django CFG email service is properly configured")
|
317
|
+
else:
|
318
|
+
self.stdout.write(self.style.WARNING(" โ ๏ธ Django CFG email service configuration incomplete"))
|
319
|
+
|
320
|
+
except Exception as e:
|
321
|
+
self.stdout.write(self.style.ERROR(f" โ Django CFG email service test failed: {e}"))
|
322
|
+
|
323
|
+
# Show recommendations
|
324
|
+
self.show_email_recommendations()
|
325
|
+
|
326
|
+
def show_email_recommendations(self):
|
327
|
+
"""Show email configuration recommendations."""
|
328
|
+
self.stdout.write(self.style.SUCCESS("\n๐ก Email Configuration Recommendations:"))
|
329
|
+
|
330
|
+
backend = getattr(settings, 'EMAIL_BACKEND', '')
|
331
|
+
debug = getattr(settings, 'DEBUG', False)
|
332
|
+
|
333
|
+
if 'console' in backend and not debug:
|
334
|
+
self.stdout.write(" โ ๏ธ Console backend in production - emails won't be delivered")
|
335
|
+
self.stdout.write(" Consider switching to SMTP backend")
|
336
|
+
|
337
|
+
if 'smtp' in backend:
|
338
|
+
host = getattr(settings, 'EMAIL_HOST', '')
|
339
|
+
user = getattr(settings, 'EMAIL_HOST_USER', '')
|
340
|
+
password = getattr(settings, 'EMAIL_HOST_PASSWORD', '')
|
341
|
+
|
342
|
+
if not host:
|
343
|
+
self.stdout.write(" โ SMTP host not configured")
|
344
|
+
if not user:
|
345
|
+
self.stdout.write(" โ SMTP username not configured")
|
346
|
+
if not password:
|
347
|
+
self.stdout.write(" โ SMTP password not configured")
|
348
|
+
|
349
|
+
if host and user and password:
|
350
|
+
self.stdout.write(" โ
SMTP configuration appears complete")
|
351
|
+
|
352
|
+
self.stdout.write("\n ๐ For more help:")
|
353
|
+
self.stdout.write(" - Check your config.dev.yaml email settings")
|
354
|
+
self.stdout.write(" - Verify SMTP credentials with your email provider")
|
355
|
+
self.stdout.write(" - Test with: python manage.py test_email")
|
@@ -0,0 +1,208 @@
|
|
1
|
+
"""
|
2
|
+
Clear Constance Command for Django Config Toolkit
|
3
|
+
Clear Constance configuration cache and database records.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from django.core.management.base import BaseCommand
|
7
|
+
from django.core.cache import cache
|
8
|
+
from django.conf import settings
|
9
|
+
from django_cfg.modules.django_logging import get_logger
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
class Command(BaseCommand):
|
15
|
+
logger = get_logger('clear_constance')
|
16
|
+
|
17
|
+
# Web execution metadata
|
18
|
+
web_executable = False
|
19
|
+
requires_input = True
|
20
|
+
is_destructive = True
|
21
|
+
|
22
|
+
help = 'Clear Constance configuration cache and database records'
|
23
|
+
|
24
|
+
def add_arguments(self, parser):
|
25
|
+
parser.add_argument(
|
26
|
+
'--cache-only',
|
27
|
+
action='store_true',
|
28
|
+
help='Clear only cache, not database records'
|
29
|
+
)
|
30
|
+
parser.add_argument(
|
31
|
+
'--db-only',
|
32
|
+
action='store_true',
|
33
|
+
help='Clear only database records, not cache'
|
34
|
+
)
|
35
|
+
parser.add_argument(
|
36
|
+
'--confirm',
|
37
|
+
action='store_true',
|
38
|
+
help='Skip confirmation prompt'
|
39
|
+
)
|
40
|
+
parser.add_argument(
|
41
|
+
'--dry-run',
|
42
|
+
action='store_true',
|
43
|
+
help='Show what would be cleared without actually clearing'
|
44
|
+
)
|
45
|
+
|
46
|
+
def handle(self, *args, **options):
|
47
|
+
"""Handle the command execution."""
|
48
|
+
self.logger.info("Starting clear_constance command")
|
49
|
+
self.stdout.write(self.style.SUCCESS('๐งน Constance Clear Tool - Django Config Toolkit\n'))
|
50
|
+
|
51
|
+
# Check if constance is installed
|
52
|
+
if 'constance' not in settings.INSTALLED_APPS:
|
53
|
+
self.stdout.write(self.style.ERROR('โ Constance is not installed or not in INSTALLED_APPS'))
|
54
|
+
return
|
55
|
+
|
56
|
+
# Determine what to clear
|
57
|
+
clear_cache = not options['db_only']
|
58
|
+
clear_db = not options['cache_only']
|
59
|
+
|
60
|
+
if options['dry_run']:
|
61
|
+
self._show_dry_run(clear_cache, clear_db)
|
62
|
+
return
|
63
|
+
|
64
|
+
# Confirm action
|
65
|
+
if not options['confirm']:
|
66
|
+
if not self._confirm_clear(clear_cache, clear_db):
|
67
|
+
self.stdout.write('Operation cancelled')
|
68
|
+
return
|
69
|
+
|
70
|
+
# Perform clearing
|
71
|
+
self._clear_constance(clear_cache, clear_db)
|
72
|
+
|
73
|
+
def _show_dry_run(self, clear_cache, clear_db):
|
74
|
+
"""Show what would be cleared in dry run mode."""
|
75
|
+
self.stdout.write(self.style.SUCCESS('=== Dry Run - What would be cleared ==='))
|
76
|
+
|
77
|
+
if clear_cache:
|
78
|
+
self.stdout.write('๐๏ธ Cache: All Django cache entries')
|
79
|
+
self.stdout.write('๐๏ธ Cache: Constance-specific cache entries')
|
80
|
+
|
81
|
+
if clear_db:
|
82
|
+
self.stdout.write('๐๏ธ Database: All Constance configuration records')
|
83
|
+
|
84
|
+
# Try to show current records count
|
85
|
+
try:
|
86
|
+
from django.apps import apps
|
87
|
+
Constance = apps.get_model('constance', 'Constance')
|
88
|
+
count = Constance.objects.count()
|
89
|
+
self.stdout.write(f' Current records: {count}')
|
90
|
+
except Exception as e:
|
91
|
+
self.stdout.write(f' Could not count records: {e}')
|
92
|
+
|
93
|
+
self.stdout.write('\nโ
Dry run completed - nothing was actually cleared')
|
94
|
+
|
95
|
+
def _confirm_clear(self, clear_cache, clear_db) -> bool:
|
96
|
+
"""Confirm the clear operation with user."""
|
97
|
+
actions = []
|
98
|
+
if clear_cache:
|
99
|
+
actions.append('cache')
|
100
|
+
if clear_db:
|
101
|
+
actions.append('database records')
|
102
|
+
|
103
|
+
action_text = ' and '.join(actions)
|
104
|
+
|
105
|
+
self.stdout.write(
|
106
|
+
self.style.WARNING(f'โ ๏ธ This will clear Constance {action_text}')
|
107
|
+
)
|
108
|
+
self.stdout.write('This action cannot be undone!')
|
109
|
+
|
110
|
+
response = input('Are you sure? [y/N]: ').lower().strip()
|
111
|
+
return response in ['y', 'yes']
|
112
|
+
|
113
|
+
def _clear_constance(self, clear_cache, clear_db):
|
114
|
+
"""Clear Constance cache and/or database records."""
|
115
|
+
cleared_items = []
|
116
|
+
|
117
|
+
# Clear cache
|
118
|
+
if clear_cache:
|
119
|
+
try:
|
120
|
+
self.stdout.write('๐งน Clearing Django cache...')
|
121
|
+
cache.clear()
|
122
|
+
self.stdout.write(self.style.SUCCESS('โ
Django cache cleared'))
|
123
|
+
cleared_items.append('cache')
|
124
|
+
|
125
|
+
# Also try to clear specific constance cache keys
|
126
|
+
try:
|
127
|
+
from constance import config as constance_config
|
128
|
+
# Force reload of constance configuration
|
129
|
+
if hasattr(constance_config, '_backend'):
|
130
|
+
constance_config._backend = None
|
131
|
+
self.stdout.write(self.style.SUCCESS('โ
Constance cache backend reset'))
|
132
|
+
except Exception as e:
|
133
|
+
self.stdout.write(self.style.WARNING(f'โ ๏ธ Could not reset Constance backend: {e}'))
|
134
|
+
|
135
|
+
except Exception as e:
|
136
|
+
self.stdout.write(self.style.ERROR(f'โ Failed to clear cache: {e}'))
|
137
|
+
|
138
|
+
# Clear database records
|
139
|
+
if clear_db:
|
140
|
+
try:
|
141
|
+
self.stdout.write('๐๏ธ Clearing Constance database records...')
|
142
|
+
|
143
|
+
from django.apps import apps
|
144
|
+
Constance = apps.get_model('constance', 'Constance')
|
145
|
+
|
146
|
+
# Count records before deletion
|
147
|
+
count_before = Constance.objects.count()
|
148
|
+
self.stdout.write(f' Found {count_before} Constance records')
|
149
|
+
|
150
|
+
if count_before > 0:
|
151
|
+
# Delete all records
|
152
|
+
deleted_info = Constance.objects.all().delete()
|
153
|
+
deleted_count = deleted_info[0] if deleted_info else 0
|
154
|
+
|
155
|
+
self.stdout.write(self.style.SUCCESS(f'โ
Deleted {deleted_count} Constance records'))
|
156
|
+
cleared_items.append(f'{deleted_count} database records')
|
157
|
+
else:
|
158
|
+
self.stdout.write('โน๏ธ No Constance records found to delete')
|
159
|
+
|
160
|
+
except Exception as e:
|
161
|
+
self.stdout.write(self.style.ERROR(f'โ Failed to clear database records: {e}'))
|
162
|
+
|
163
|
+
# Show summary
|
164
|
+
if cleared_items:
|
165
|
+
self.stdout.write(
|
166
|
+
self.style.SUCCESS(f'\n๐ Successfully cleared: {", ".join(cleared_items)}')
|
167
|
+
)
|
168
|
+
self.stdout.write('\n๐ก Next steps:')
|
169
|
+
self.stdout.write(' 1. Restart your Django server')
|
170
|
+
self.stdout.write(' 2. Visit Django admin to reconfigure settings')
|
171
|
+
self.stdout.write(' 3. Check that boolean fields now work correctly')
|
172
|
+
else:
|
173
|
+
self.stdout.write(self.style.WARNING('โ ๏ธ Nothing was cleared'))
|
174
|
+
|
175
|
+
def _show_current_status(self):
|
176
|
+
"""Show current Constance status."""
|
177
|
+
self.stdout.write(self.style.SUCCESS('\n๐ Current Constance Status:'))
|
178
|
+
|
179
|
+
# Check database records
|
180
|
+
try:
|
181
|
+
from django.apps import apps
|
182
|
+
Constance = apps.get_model('constance', 'Constance')
|
183
|
+
db_count = Constance.objects.count()
|
184
|
+
self.stdout.write(f' Database records: {db_count}')
|
185
|
+
|
186
|
+
if db_count > 0:
|
187
|
+
self.stdout.write(' Recent records:')
|
188
|
+
for record in Constance.objects.all()[:5]:
|
189
|
+
self.stdout.write(f' - {record.key}: {record.value}')
|
190
|
+
if db_count > 5:
|
191
|
+
self.stdout.write(f' ... and {db_count - 5} more')
|
192
|
+
except Exception as e:
|
193
|
+
self.stdout.write(f' Database: Error - {e}')
|
194
|
+
|
195
|
+
# Check cache
|
196
|
+
try:
|
197
|
+
from django.core.cache import cache
|
198
|
+
# Try to get a test key to see if cache is working
|
199
|
+
test_key = 'constance_test_key'
|
200
|
+
cache.set(test_key, 'test_value', 1)
|
201
|
+
test_result = cache.get(test_key)
|
202
|
+
|
203
|
+
if test_result:
|
204
|
+
self.stdout.write(' Cache: Working')
|
205
|
+
else:
|
206
|
+
self.stdout.write(' Cache: Not working or empty')
|
207
|
+
except Exception as e:
|
208
|
+
self.stdout.write(f' Cache: Error - {e}')
|