django-cfg 1.5.8__py3-none-any.whl → 1.5.20__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.
Potentially problematic release.
This version of django-cfg might be problematic. Click here for more details.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/api/commands/serializers.py +152 -0
- django_cfg/apps/api/commands/views.py +32 -0
- django_cfg/apps/business/accounts/management/commands/otp_test.py +5 -2
- django_cfg/apps/business/accounts/serializers/profile.py +42 -0
- django_cfg/apps/business/agents/management/commands/create_agent.py +5 -194
- django_cfg/apps/business/agents/management/commands/load_agent_templates.py +205 -0
- django_cfg/apps/business/agents/management/commands/orchestrator_status.py +4 -2
- django_cfg/apps/business/knowbase/management/commands/knowbase_stats.py +4 -2
- django_cfg/apps/business/knowbase/management/commands/setup_knowbase.py +4 -2
- django_cfg/apps/business/newsletter/management/commands/test_newsletter.py +5 -2
- django_cfg/apps/business/payments/management/commands/check_payment_status.py +4 -2
- django_cfg/apps/business/payments/management/commands/create_payment.py +4 -2
- django_cfg/apps/business/payments/management/commands/sync_currencies.py +4 -2
- django_cfg/apps/business/support/serializers.py +3 -2
- django_cfg/apps/integrations/centrifugo/apps.py +2 -1
- django_cfg/apps/integrations/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +151 -12
- django_cfg/apps/integrations/centrifugo/management/commands/generate_centrifugo_clients.py +6 -6
- django_cfg/apps/integrations/centrifugo/serializers/__init__.py +2 -1
- django_cfg/apps/integrations/centrifugo/serializers/publishes.py +22 -2
- django_cfg/apps/integrations/centrifugo/services/__init__.py +6 -0
- django_cfg/apps/integrations/centrifugo/services/client/__init__.py +6 -1
- django_cfg/apps/integrations/centrifugo/services/client/direct_client.py +282 -0
- django_cfg/apps/integrations/centrifugo/services/publisher.py +371 -0
- django_cfg/apps/integrations/centrifugo/services/token_generator.py +122 -0
- django_cfg/apps/integrations/centrifugo/urls.py +8 -0
- django_cfg/apps/integrations/centrifugo/views/__init__.py +2 -0
- django_cfg/apps/integrations/centrifugo/views/monitoring.py +25 -40
- django_cfg/apps/integrations/centrifugo/views/testing_api.py +0 -79
- django_cfg/apps/integrations/centrifugo/views/token_api.py +101 -0
- django_cfg/apps/integrations/centrifugo/views/wrapper.py +257 -0
- django_cfg/apps/integrations/grpc/admin/__init__.py +7 -1
- django_cfg/apps/integrations/grpc/admin/config.py +113 -9
- django_cfg/apps/integrations/grpc/admin/grpc_api_key.py +129 -0
- django_cfg/apps/integrations/grpc/admin/grpc_request_log.py +72 -63
- django_cfg/apps/integrations/grpc/admin/grpc_server_status.py +236 -0
- django_cfg/apps/integrations/grpc/auth/__init__.py +11 -3
- django_cfg/apps/integrations/grpc/auth/api_key_auth.py +320 -0
- django_cfg/apps/integrations/grpc/centrifugo/__init__.py +29 -0
- django_cfg/apps/integrations/grpc/centrifugo/bridge.py +277 -0
- django_cfg/apps/integrations/grpc/centrifugo/config.py +167 -0
- django_cfg/apps/integrations/grpc/centrifugo/demo.py +626 -0
- django_cfg/apps/integrations/grpc/centrifugo/test_publish.py +229 -0
- django_cfg/apps/integrations/grpc/centrifugo/transformers.py +89 -0
- django_cfg/apps/integrations/grpc/interceptors/__init__.py +3 -1
- django_cfg/apps/integrations/grpc/interceptors/centrifugo.py +541 -0
- django_cfg/apps/integrations/grpc/interceptors/logging.py +17 -20
- django_cfg/apps/integrations/grpc/interceptors/metrics.py +15 -14
- django_cfg/apps/integrations/grpc/interceptors/request_logger.py +79 -59
- django_cfg/apps/integrations/grpc/management/commands/compile_proto.py +105 -0
- django_cfg/apps/integrations/grpc/management/commands/generate_protos.py +185 -0
- django_cfg/apps/integrations/grpc/management/commands/rungrpc.py +474 -95
- django_cfg/apps/integrations/grpc/management/commands/test_grpc_integration.py +75 -0
- django_cfg/apps/integrations/grpc/management/proto/__init__.py +3 -0
- django_cfg/apps/integrations/grpc/management/proto/compiler.py +194 -0
- django_cfg/apps/integrations/grpc/managers/__init__.py +2 -0
- django_cfg/apps/integrations/grpc/managers/grpc_api_key.py +192 -0
- django_cfg/apps/integrations/grpc/managers/grpc_server_status.py +19 -11
- django_cfg/apps/integrations/grpc/migrations/0005_grpcapikey.py +143 -0
- django_cfg/apps/integrations/grpc/migrations/0006_grpcrequestlog_api_key_and_more.py +34 -0
- django_cfg/apps/integrations/grpc/models/__init__.py +2 -0
- django_cfg/apps/integrations/grpc/models/grpc_api_key.py +198 -0
- django_cfg/apps/integrations/grpc/models/grpc_request_log.py +11 -0
- django_cfg/apps/integrations/grpc/models/grpc_server_status.py +39 -4
- django_cfg/apps/integrations/grpc/serializers/__init__.py +22 -6
- django_cfg/apps/integrations/grpc/serializers/api_keys.py +63 -0
- django_cfg/apps/integrations/grpc/serializers/charts.py +118 -120
- django_cfg/apps/integrations/grpc/serializers/config.py +65 -51
- django_cfg/apps/integrations/grpc/serializers/health.py +7 -7
- django_cfg/apps/integrations/grpc/serializers/proto_files.py +74 -0
- django_cfg/apps/integrations/grpc/serializers/requests.py +13 -7
- django_cfg/apps/integrations/grpc/serializers/service_registry.py +181 -112
- django_cfg/apps/integrations/grpc/serializers/services.py +14 -32
- django_cfg/apps/integrations/grpc/serializers/stats.py +50 -12
- django_cfg/apps/integrations/grpc/serializers/testing.py +66 -58
- django_cfg/apps/integrations/grpc/services/__init__.py +2 -0
- django_cfg/apps/integrations/grpc/services/discovery.py +7 -1
- django_cfg/apps/integrations/grpc/services/monitoring_service.py +149 -43
- django_cfg/apps/integrations/grpc/services/proto_files_manager.py +268 -0
- django_cfg/apps/integrations/grpc/services/service_registry.py +48 -46
- django_cfg/apps/integrations/grpc/services/testing_service.py +10 -15
- django_cfg/apps/integrations/grpc/urls.py +8 -0
- django_cfg/apps/integrations/grpc/utils/SERVER_LOGGING.md +164 -0
- django_cfg/apps/integrations/grpc/utils/__init__.py +4 -13
- django_cfg/apps/integrations/grpc/utils/integration_test.py +334 -0
- django_cfg/apps/integrations/grpc/utils/proto_gen.py +48 -8
- django_cfg/apps/integrations/grpc/utils/streaming_logger.py +378 -0
- django_cfg/apps/integrations/grpc/views/__init__.py +4 -0
- django_cfg/apps/integrations/grpc/views/api_keys.py +255 -0
- django_cfg/apps/integrations/grpc/views/charts.py +21 -14
- django_cfg/apps/integrations/grpc/views/config.py +8 -6
- django_cfg/apps/integrations/grpc/views/monitoring.py +51 -79
- django_cfg/apps/integrations/grpc/views/proto_files.py +214 -0
- django_cfg/apps/integrations/grpc/views/services.py +30 -21
- django_cfg/apps/integrations/grpc/views/testing.py +45 -43
- django_cfg/apps/integrations/rq/views/jobs.py +19 -9
- django_cfg/apps/integrations/rq/views/schedule.py +7 -3
- django_cfg/apps/system/dashboard/serializers/commands.py +25 -1
- django_cfg/apps/system/dashboard/serializers/config.py +95 -9
- django_cfg/apps/system/dashboard/serializers/statistics.py +9 -4
- django_cfg/apps/system/dashboard/services/commands_service.py +12 -1
- django_cfg/apps/system/frontend/views.py +87 -6
- django_cfg/apps/system/maintenance/management/commands/maintenance.py +5 -2
- django_cfg/apps/system/maintenance/management/commands/process_scheduled_maintenance.py +4 -2
- django_cfg/apps/system/maintenance/management/commands/sync_cloudflare.py +5 -2
- django_cfg/config.py +33 -0
- django_cfg/core/builders/security_builder.py +1 -0
- django_cfg/core/generation/integration_generators/api.py +2 -0
- django_cfg/core/generation/integration_generators/grpc_generator.py +30 -32
- django_cfg/management/commands/check_endpoints.py +2 -2
- django_cfg/management/commands/check_settings.py +3 -10
- django_cfg/management/commands/clear_constance.py +3 -10
- django_cfg/management/commands/create_token.py +4 -11
- django_cfg/management/commands/list_urls.py +4 -10
- django_cfg/management/commands/migrate_all.py +18 -12
- django_cfg/management/commands/migrator.py +4 -11
- django_cfg/management/commands/script.py +4 -10
- django_cfg/management/commands/show_config.py +8 -16
- django_cfg/management/commands/show_urls.py +5 -11
- django_cfg/management/commands/superuser.py +4 -11
- django_cfg/management/commands/tree.py +5 -10
- django_cfg/management/utils/README.md +402 -0
- django_cfg/management/utils/__init__.py +29 -0
- django_cfg/management/utils/mixins.py +176 -0
- django_cfg/middleware/pagination.py +53 -54
- django_cfg/models/api/grpc/__init__.py +15 -21
- django_cfg/models/api/grpc/config.py +155 -73
- django_cfg/models/ngrok/config.py +7 -6
- django_cfg/modules/django_client/core/generator/python/files_generator.py +5 -13
- django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +16 -4
- django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +2 -3
- django_cfg/modules/django_client/core/generator/typescript/files_generator.py +6 -5
- django_cfg/modules/django_client/core/generator/typescript/generator.py +26 -0
- django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +7 -1
- django_cfg/modules/django_client/core/generator/typescript/models_generator.py +5 -0
- django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +11 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +1 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/function.ts.jinja +29 -1
- django_cfg/modules/django_client/core/generator/typescript/templates/hooks/hooks.ts.jinja +4 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +12 -8
- django_cfg/modules/django_client/core/ir/schema.py +15 -1
- django_cfg/modules/django_client/core/parser/base.py +126 -30
- django_cfg/modules/django_client/management/commands/generate_client.py +5 -2
- django_cfg/modules/django_client/management/commands/validate_openapi.py +5 -2
- django_cfg/modules/django_email/management/commands/test_email.py +4 -10
- django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +16 -13
- django_cfg/modules/django_telegram/management/commands/test_telegram.py +4 -11
- django_cfg/modules/django_twilio/management/commands/test_twilio.py +4 -11
- django_cfg/modules/django_unfold/navigation.py +6 -18
- django_cfg/pyproject.toml +1 -1
- django_cfg/registry/modules.py +1 -4
- django_cfg/requirements.txt +52 -0
- django_cfg/static/frontend/admin.zip +0 -0
- {django_cfg-1.5.8.dist-info → django_cfg-1.5.20.dist-info}/METADATA +1 -1
- {django_cfg-1.5.8.dist-info → django_cfg-1.5.20.dist-info}/RECORD +158 -121
- django_cfg/apps/integrations/grpc/auth/jwt_auth.py +0 -295
- {django_cfg-1.5.8.dist-info → django_cfg-1.5.20.dist-info}/WHEEL +0 -0
- {django_cfg-1.5.8.dist-info → django_cfg-1.5.20.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.5.8.dist-info → django_cfg-1.5.20.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,16 +5,19 @@ Automatically discovers and syncs Cloudflare zones with Django models.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
from django.core.management.base import
|
|
8
|
+
from django.core.management.base import CommandError
|
|
9
9
|
from django.utils import timezone
|
|
10
10
|
|
|
11
|
+
from django_cfg.management.utils import AdminCommand
|
|
12
|
+
|
|
11
13
|
from ...models import CloudflareApiKey
|
|
12
14
|
from ...services.site_sync_service import SiteSyncService
|
|
13
15
|
|
|
14
16
|
|
|
15
|
-
class Command(
|
|
17
|
+
class Command(AdminCommand):
|
|
16
18
|
"""Sync sites with Cloudflare zones."""
|
|
17
19
|
|
|
20
|
+
command_name = 'sync_cloudflare'
|
|
18
21
|
help = 'Sync CloudflareSite models with actual Cloudflare zones'
|
|
19
22
|
|
|
20
23
|
def add_arguments(self, parser):
|
django_cfg/config.py
CHANGED
|
@@ -9,6 +9,39 @@ from typing import List
|
|
|
9
9
|
from .modules.django_admin.icons import Icons
|
|
10
10
|
from .modules.django_unfold.models.dropdown import SiteDropdownItem
|
|
11
11
|
|
|
12
|
+
|
|
13
|
+
def is_feature_available(feature: str) -> bool:
|
|
14
|
+
"""
|
|
15
|
+
Check if a feature is available (dependencies installed).
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
feature: Feature name (e.g., 'grpc', 'centrifugo', 'dramatiq')
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
True if feature dependencies are available
|
|
22
|
+
"""
|
|
23
|
+
if feature == "grpc":
|
|
24
|
+
try:
|
|
25
|
+
import grpc # noqa
|
|
26
|
+
import grpc_reflection # noqa
|
|
27
|
+
return True
|
|
28
|
+
except ImportError:
|
|
29
|
+
return False
|
|
30
|
+
elif feature == "centrifugo":
|
|
31
|
+
try:
|
|
32
|
+
import cent # noqa
|
|
33
|
+
return True
|
|
34
|
+
except ImportError:
|
|
35
|
+
return False
|
|
36
|
+
elif feature == "dramatiq":
|
|
37
|
+
try:
|
|
38
|
+
import dramatiq # noqa
|
|
39
|
+
return True
|
|
40
|
+
except ImportError:
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
return False
|
|
44
|
+
|
|
12
45
|
# Library configuration
|
|
13
46
|
LIB_NAME = "django-cfg"
|
|
14
47
|
LIB_SITE_URL = "https://djangocfg.com"
|
|
@@ -125,6 +125,8 @@ class APIFrameworksGenerator:
|
|
|
125
125
|
],
|
|
126
126
|
# Add authentication classes from smart defaults
|
|
127
127
|
"DEFAULT_AUTHENTICATION_CLASSES": drf_defaults["DEFAULT_AUTHENTICATION_CLASSES"],
|
|
128
|
+
# Force ISO 8601 datetime format with Z suffix for all datetime fields
|
|
129
|
+
"DATETIME_FORMAT": "%Y-%m-%dT%H:%M:%SZ",
|
|
128
130
|
}
|
|
129
131
|
|
|
130
132
|
# Note: We don't set DEFAULT_PERMISSION_CLASSES here to allow public endpoints
|
|
@@ -119,9 +119,10 @@ class GRPCSettingsGenerator:
|
|
|
119
119
|
if grpc_proto:
|
|
120
120
|
settings["GRPC_PROTO"] = grpc_proto
|
|
121
121
|
|
|
122
|
-
logger.info("✅ gRPC framework enabled")
|
|
122
|
+
logger.info("✅ gRPC framework enabled (async)")
|
|
123
123
|
logger.info(f" - Server: {self.config.grpc.server.host}:{self.config.grpc.server.port}")
|
|
124
|
-
|
|
124
|
+
max_streams = self.config.grpc.server.max_concurrent_streams or "unlimited"
|
|
125
|
+
logger.info(f" - Max concurrent streams: {max_streams}")
|
|
125
126
|
logger.info(f" - Auth: {'enabled' if self.config.grpc.auth.enabled else 'disabled'}")
|
|
126
127
|
logger.info(f" - Reflection: {'enabled' if self.config.grpc.server.enable_reflection else 'disabled'}")
|
|
127
128
|
|
|
@@ -169,7 +170,8 @@ class GRPCSettingsGenerator:
|
|
|
169
170
|
server_settings = {
|
|
170
171
|
"host": server_config.host,
|
|
171
172
|
"port": server_config.port,
|
|
172
|
-
"
|
|
173
|
+
"max_concurrent_streams": server_config.max_concurrent_streams,
|
|
174
|
+
"asyncio_debug": server_config.asyncio_debug,
|
|
173
175
|
"enable_reflection": server_config.enable_reflection,
|
|
174
176
|
"enable_health_check": server_config.enable_health_check,
|
|
175
177
|
"max_send_message_length": server_config.max_send_message_length,
|
|
@@ -200,21 +202,11 @@ class GRPCSettingsGenerator:
|
|
|
200
202
|
auth_settings = {
|
|
201
203
|
"enabled": auth_config.enabled,
|
|
202
204
|
"require_auth": auth_config.require_auth,
|
|
203
|
-
"
|
|
204
|
-
"
|
|
205
|
-
"jwt_algorithm": auth_config.jwt_algorithm,
|
|
206
|
-
"jwt_verify_exp": auth_config.jwt_verify_exp,
|
|
207
|
-
"jwt_leeway": auth_config.jwt_leeway,
|
|
205
|
+
"api_key_header": auth_config.api_key_header,
|
|
206
|
+
"accept_django_secret_key": auth_config.accept_django_secret_key,
|
|
208
207
|
"public_methods": auth_config.public_methods,
|
|
209
208
|
}
|
|
210
209
|
|
|
211
|
-
# Use JWT secret from auth config or fall back to Django SECRET_KEY
|
|
212
|
-
if auth_config.jwt_secret_key:
|
|
213
|
-
auth_settings["jwt_secret_key"] = auth_config.jwt_secret_key
|
|
214
|
-
else:
|
|
215
|
-
# Will be resolved from Django settings at runtime
|
|
216
|
-
auth_settings["jwt_secret_key"] = None # Signal to use Django SECRET_KEY
|
|
217
|
-
|
|
218
210
|
return auth_settings
|
|
219
211
|
|
|
220
212
|
def _build_grpc_proto_settings(self) -> Dict[str, Any]:
|
|
@@ -240,10 +232,13 @@ class GRPCSettingsGenerator:
|
|
|
240
232
|
"""
|
|
241
233
|
Build list of server interceptors.
|
|
242
234
|
|
|
243
|
-
Interceptors are
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
235
|
+
IMPORTANT: Interceptors are executed in reverse order for requests!
|
|
236
|
+
The first interceptor in the list wraps all others.
|
|
237
|
+
|
|
238
|
+
Correct order for our use case:
|
|
239
|
+
1. Auth interceptor (MUST be first to set context.api_key before logging)
|
|
240
|
+
2. Request logger interceptor (uses context.api_key from auth)
|
|
241
|
+
3. Logging interceptor (if dev mode)
|
|
247
242
|
4. Metrics interceptor (if dev mode)
|
|
248
243
|
5. Custom interceptors (from config)
|
|
249
244
|
|
|
@@ -255,30 +250,33 @@ class GRPCSettingsGenerator:
|
|
|
255
250
|
# Check if we're in dev mode
|
|
256
251
|
is_dev = self.config.env_mode in ("local", "development", "dev")
|
|
257
252
|
|
|
258
|
-
#
|
|
259
|
-
|
|
260
|
-
"django_cfg.apps.integrations.grpc.interceptors.RequestLoggerInterceptor"
|
|
261
|
-
)
|
|
253
|
+
# NOTE: Interceptors are applied in REVERSE order (last added = first executed)!
|
|
254
|
+
# So add them in reverse order of execution:
|
|
262
255
|
|
|
263
|
-
# Add
|
|
256
|
+
# 4. Add metrics interceptor in dev mode (executed LAST)
|
|
264
257
|
if is_dev:
|
|
265
258
|
interceptors.append(
|
|
266
|
-
"django_cfg.apps.integrations.grpc.interceptors.
|
|
259
|
+
"django_cfg.apps.integrations.grpc.interceptors.MetricsInterceptor"
|
|
267
260
|
)
|
|
268
261
|
|
|
269
|
-
# Add
|
|
270
|
-
if
|
|
262
|
+
# 3. Add logging interceptor in dev mode (executed 3rd)
|
|
263
|
+
if is_dev:
|
|
271
264
|
interceptors.append(
|
|
272
|
-
"django_cfg.apps.integrations.grpc.
|
|
265
|
+
"django_cfg.apps.integrations.grpc.interceptors.LoggingInterceptor"
|
|
273
266
|
)
|
|
274
267
|
|
|
275
|
-
# Add
|
|
276
|
-
|
|
268
|
+
# 2. Add request logger interceptor (executed 2nd - needs context vars from auth)
|
|
269
|
+
interceptors.append(
|
|
270
|
+
"django_cfg.apps.integrations.grpc.interceptors.RequestLoggerInterceptor"
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
# 1. Add auth interceptor LAST in list (executed FIRST - sets contextvars!)
|
|
274
|
+
if self.config.grpc.auth.enabled:
|
|
277
275
|
interceptors.append(
|
|
278
|
-
"django_cfg.apps.integrations.grpc.
|
|
276
|
+
"django_cfg.apps.integrations.grpc.auth.ApiKeyAuthInterceptor"
|
|
279
277
|
)
|
|
280
278
|
|
|
281
|
-
# Add custom interceptors from server config
|
|
279
|
+
# 5. Add custom interceptors from server config
|
|
282
280
|
if self.config.grpc.server.interceptors:
|
|
283
281
|
interceptors.extend(self.config.grpc.server.interceptors)
|
|
284
282
|
|
|
@@ -10,13 +10,13 @@ Usage:
|
|
|
10
10
|
|
|
11
11
|
import json
|
|
12
12
|
|
|
13
|
-
from django.core.management.base import BaseCommand
|
|
14
13
|
from django.urls import reverse
|
|
15
14
|
|
|
16
15
|
from django_cfg.apps.api.endpoints.endpoints_status.checker import check_all_endpoints
|
|
16
|
+
from django_cfg.management.utils import SafeCommand
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class Command(
|
|
19
|
+
class Command(SafeCommand):
|
|
20
20
|
help = 'Check status of all Django CFG API endpoints'
|
|
21
21
|
|
|
22
22
|
def add_arguments(self, parser):
|
|
@@ -9,20 +9,13 @@ import os
|
|
|
9
9
|
|
|
10
10
|
from django.conf import settings
|
|
11
11
|
from django.core.mail import get_connection
|
|
12
|
-
from django.core.management.base import BaseCommand
|
|
13
12
|
|
|
14
|
-
from django_cfg.
|
|
13
|
+
from django_cfg.management.utils import SafeCommand
|
|
15
14
|
|
|
16
|
-
logger = get_logger('check_settings')
|
|
17
15
|
|
|
18
|
-
class Command(
|
|
16
|
+
class Command(SafeCommand):
|
|
19
17
|
"""Command to check and debug django-cfg settings."""
|
|
20
18
|
|
|
21
|
-
# Web execution metadata
|
|
22
|
-
web_executable = True
|
|
23
|
-
requires_input = False
|
|
24
|
-
is_destructive = False
|
|
25
|
-
|
|
26
19
|
help = "Check and debug django-cfg configuration settings"
|
|
27
20
|
|
|
28
21
|
def add_arguments(self, parser):
|
|
@@ -39,7 +32,7 @@ class Command(BaseCommand):
|
|
|
39
32
|
|
|
40
33
|
def handle(self, *args, **options):
|
|
41
34
|
"""Main command handler."""
|
|
42
|
-
logger.info("Starting check_settings command")
|
|
35
|
+
self.logger.info("Starting check_settings command")
|
|
43
36
|
self.stdout.write(self.style.SUCCESS("\n🔍 Django CFG Settings Checker\n"))
|
|
44
37
|
|
|
45
38
|
# Show basic info
|
|
@@ -5,19 +5,12 @@ Clear Constance configuration cache and database records.
|
|
|
5
5
|
|
|
6
6
|
from django.conf import settings
|
|
7
7
|
from django.core.cache import cache
|
|
8
|
-
from django.core.management.base import BaseCommand
|
|
9
8
|
|
|
10
|
-
from django_cfg.
|
|
9
|
+
from django_cfg.management.utils import DestructiveCommand
|
|
11
10
|
|
|
12
11
|
|
|
13
|
-
class Command(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# Web execution metadata
|
|
17
|
-
web_executable = False
|
|
18
|
-
requires_input = True
|
|
19
|
-
is_destructive = True
|
|
20
|
-
|
|
12
|
+
class Command(DestructiveCommand):
|
|
13
|
+
command_name = 'clear_constance'
|
|
21
14
|
help = 'Clear Constance configuration cache and database records'
|
|
22
15
|
|
|
23
16
|
def add_arguments(self, parser):
|
|
@@ -10,21 +10,14 @@ from pathlib import Path
|
|
|
10
10
|
|
|
11
11
|
import questionary
|
|
12
12
|
from django.contrib.auth import get_user_model
|
|
13
|
-
from django.core.management.base import BaseCommand
|
|
14
13
|
|
|
15
|
-
from django_cfg.
|
|
14
|
+
from django_cfg.management.utils import InteractiveCommand
|
|
16
15
|
|
|
17
16
|
User = get_user_model()
|
|
18
17
|
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class Command(BaseCommand):
|
|
23
|
-
# Web execution metadata
|
|
24
|
-
web_executable = False
|
|
25
|
-
requires_input = True
|
|
26
|
-
is_destructive = False
|
|
27
|
-
|
|
19
|
+
class Command(InteractiveCommand):
|
|
20
|
+
command_name = 'create_token'
|
|
28
21
|
help = 'Create API tokens and authentication tokens'
|
|
29
22
|
|
|
30
23
|
def add_arguments(self, parser):
|
|
@@ -52,7 +45,7 @@ class Command(BaseCommand):
|
|
|
52
45
|
)
|
|
53
46
|
|
|
54
47
|
def handle(self, *args, **options):
|
|
55
|
-
logger.info("Starting create_token command")
|
|
48
|
+
self.logger.info("Starting create_token command")
|
|
56
49
|
if options['user'] and options['type']:
|
|
57
50
|
self.create_token_for_user(
|
|
58
51
|
username=options['user'],
|
|
@@ -8,7 +8,6 @@ Useful for development and webhook configuration.
|
|
|
8
8
|
import re
|
|
9
9
|
|
|
10
10
|
from django.conf import settings
|
|
11
|
-
from django.core.management.base import BaseCommand
|
|
12
11
|
from django.urls import get_resolver
|
|
13
12
|
from rich.align import Align
|
|
14
13
|
|
|
@@ -19,18 +18,13 @@ from rich.table import Table
|
|
|
19
18
|
from rich.text import Text
|
|
20
19
|
|
|
21
20
|
from django_cfg.core.state import get_current_config
|
|
22
|
-
from django_cfg.
|
|
21
|
+
from django_cfg.management.utils import SafeCommand
|
|
23
22
|
|
|
24
|
-
logger = get_logger('list_urls')
|
|
25
23
|
|
|
26
|
-
class Command(
|
|
24
|
+
class Command(SafeCommand):
|
|
27
25
|
"""Command to display all available URLs in the project."""
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
web_executable = True
|
|
31
|
-
requires_input = False
|
|
32
|
-
is_destructive = False
|
|
33
|
-
|
|
27
|
+
command_name = 'list_urls'
|
|
34
28
|
help = "Display all available URLs with Rich formatting"
|
|
35
29
|
|
|
36
30
|
def __init__(self, *args, **kwargs):
|
|
@@ -62,7 +56,7 @@ class Command(BaseCommand):
|
|
|
62
56
|
)
|
|
63
57
|
|
|
64
58
|
def handle(self, *args, **options):
|
|
65
|
-
logger.info("Starting list_urls command")
|
|
59
|
+
self.logger.info("Starting list_urls command")
|
|
66
60
|
filter_str = options["filter"]
|
|
67
61
|
webhook_only = options["webhook"]
|
|
68
62
|
api_only = options["api"]
|
|
@@ -5,18 +5,24 @@ Migrate all databases based on django-cfg configuration.
|
|
|
5
5
|
|
|
6
6
|
from django.apps import apps
|
|
7
7
|
from django.core.management import call_command
|
|
8
|
-
from django.core.management.base import BaseCommand
|
|
9
8
|
|
|
10
9
|
from django_cfg.core.state import get_current_config
|
|
11
|
-
from django_cfg.
|
|
10
|
+
from django_cfg.management.utils import AdminCommand
|
|
12
11
|
|
|
13
|
-
logger = get_logger('migrate_all')
|
|
14
12
|
|
|
15
|
-
class Command(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
class Command(AdminCommand):
|
|
14
|
+
"""
|
|
15
|
+
Migrate all databases - destructive but non-interactive admin command.
|
|
16
|
+
|
|
17
|
+
This command is marked as destructive because it modifies the database schema,
|
|
18
|
+
but it doesn't require user input during execution.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
command_name = 'migrate_all'
|
|
22
|
+
|
|
23
|
+
# Override AdminCommand defaults
|
|
24
|
+
web_executable = False # Too risky for web execution
|
|
25
|
+
is_destructive = True # Modifies database schema
|
|
20
26
|
|
|
21
27
|
help = "Migrate all databases based on django-cfg configuration"
|
|
22
28
|
|
|
@@ -34,7 +40,7 @@ class Command(BaseCommand):
|
|
|
34
40
|
|
|
35
41
|
def handle(self, *args, **options):
|
|
36
42
|
"""Run migrations for all configured databases."""
|
|
37
|
-
logger.info("Starting migrate_all command")
|
|
43
|
+
self.logger.info("Starting migrate_all command")
|
|
38
44
|
dry_run = options.get("dry_run", False)
|
|
39
45
|
skip_makemigrations = options.get("skip_makemigrations", False)
|
|
40
46
|
|
|
@@ -76,7 +82,7 @@ class Command(BaseCommand):
|
|
|
76
82
|
call_command("migrate", app_label, database=db_name, verbosity=1)
|
|
77
83
|
except Exception as e:
|
|
78
84
|
self.stdout.write(self.style.ERROR(f" ❌ Migration failed for {app_label} on {db_name}: {e}"))
|
|
79
|
-
logger.error(f"Migration failed for {app_label} on {db_name}: {e}")
|
|
85
|
+
self.logger.error(f"Migration failed for {app_label} on {db_name}: {e}")
|
|
80
86
|
raise SystemExit(1)
|
|
81
87
|
else:
|
|
82
88
|
self.stdout.write(f" Would run: migrate {app_label} --database={db_name}")
|
|
@@ -88,7 +94,7 @@ class Command(BaseCommand):
|
|
|
88
94
|
call_command("migrate", database=db_name, verbosity=1)
|
|
89
95
|
except Exception as e:
|
|
90
96
|
self.stdout.write(self.style.ERROR(f" ❌ Migration failed for all apps on {db_name}: {e}"))
|
|
91
|
-
logger.error(f"Migration failed for all apps on {db_name}: {e}")
|
|
97
|
+
self.logger.error(f"Migration failed for all apps on {db_name}: {e}")
|
|
92
98
|
raise SystemExit(1)
|
|
93
99
|
else:
|
|
94
100
|
self.stdout.write(f" Would run: migrate --database={db_name}")
|
|
@@ -100,7 +106,7 @@ class Command(BaseCommand):
|
|
|
100
106
|
call_command("migrate", "constance", database="default", verbosity=1)
|
|
101
107
|
except Exception as e:
|
|
102
108
|
self.stdout.write(self.style.ERROR(f"❌ Constance migration failed: {e}"))
|
|
103
|
-
logger.error(f"Constance migration failed: {e}")
|
|
109
|
+
self.logger.error(f"Constance migration failed: {e}")
|
|
104
110
|
raise SystemExit(1)
|
|
105
111
|
else:
|
|
106
112
|
self.stdout.write(" Would run: migrate constance --database=default")
|
|
@@ -9,22 +9,15 @@ import questionary
|
|
|
9
9
|
from django.apps import apps
|
|
10
10
|
from django.conf import settings
|
|
11
11
|
from django.core.management import call_command
|
|
12
|
-
from django.core.management.base import BaseCommand
|
|
13
12
|
from django.db import connections
|
|
14
13
|
from django.db.migrations.recorder import MigrationRecorder
|
|
15
14
|
|
|
16
15
|
from django_cfg.core.config import DEFAULT_APPS
|
|
17
|
-
from django_cfg.
|
|
16
|
+
from django_cfg.management.utils import DestructiveCommand
|
|
18
17
|
|
|
19
|
-
logger = get_logger('migrator')
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class Command(BaseCommand):
|
|
23
|
-
# Web execution metadata
|
|
24
|
-
web_executable = False
|
|
25
|
-
requires_input = True
|
|
26
|
-
is_destructive = True
|
|
27
18
|
|
|
19
|
+
class Command(DestructiveCommand):
|
|
20
|
+
command_name = 'migrator'
|
|
28
21
|
help = "Smart migration command with interactive menu for multiple databases"
|
|
29
22
|
|
|
30
23
|
def add_arguments(self, parser):
|
|
@@ -132,7 +125,7 @@ class Command(BaseCommand):
|
|
|
132
125
|
|
|
133
126
|
def _raise_system_exit(self, message):
|
|
134
127
|
self.stdout.write(self.style.ERROR(f"❌ {message}"))
|
|
135
|
-
logger.error(message)
|
|
128
|
+
self.logger.error(message)
|
|
136
129
|
# raise SystemExit(1)
|
|
137
130
|
|
|
138
131
|
def migrate_database(self, db_name):
|
|
@@ -10,18 +10,12 @@ from pathlib import Path
|
|
|
10
10
|
import questionary
|
|
11
11
|
from django.conf import settings
|
|
12
12
|
from django.core.management import call_command
|
|
13
|
-
from django.core.management.base import BaseCommand
|
|
14
|
-
|
|
15
|
-
from django_cfg.modules.django_logging import get_logger
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
from django_cfg.management.utils import InteractiveCommand
|
|
18
15
|
|
|
19
|
-
class Command(BaseCommand):
|
|
20
|
-
# Web execution metadata
|
|
21
|
-
web_executable = False
|
|
22
|
-
requires_input = True
|
|
23
|
-
is_destructive = False
|
|
24
16
|
|
|
17
|
+
class Command(InteractiveCommand):
|
|
18
|
+
command_name = 'script'
|
|
25
19
|
help = 'Run custom scripts and manage Django applications'
|
|
26
20
|
|
|
27
21
|
def add_arguments(self, parser):
|
|
@@ -52,7 +46,7 @@ class Command(BaseCommand):
|
|
|
52
46
|
)
|
|
53
47
|
|
|
54
48
|
def handle(self, *args, **options):
|
|
55
|
-
logger.info("Starting script command")
|
|
49
|
+
self.logger.info("Starting script command")
|
|
56
50
|
if options['list']:
|
|
57
51
|
self.list_scripts()
|
|
58
52
|
elif options['create']:
|
|
@@ -10,19 +10,11 @@ import json
|
|
|
10
10
|
import os
|
|
11
11
|
|
|
12
12
|
from django.conf import settings
|
|
13
|
-
from django.core.management.base import BaseCommand
|
|
14
13
|
|
|
15
|
-
from django_cfg.
|
|
14
|
+
from django_cfg.management.utils import SafeCommand
|
|
16
15
|
|
|
17
|
-
logger = get_logger('show_config')
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class Command(BaseCommand):
|
|
21
|
-
# Web execution metadata
|
|
22
|
-
web_executable = True
|
|
23
|
-
requires_input = False
|
|
24
|
-
is_destructive = False
|
|
25
16
|
|
|
17
|
+
class Command(SafeCommand):
|
|
26
18
|
help = 'Show Django Config configuration'
|
|
27
19
|
|
|
28
20
|
def add_arguments(self, parser):
|
|
@@ -40,23 +32,23 @@ class Command(BaseCommand):
|
|
|
40
32
|
|
|
41
33
|
def handle(self, *args, **options):
|
|
42
34
|
"""Show configuration in requested format."""
|
|
43
|
-
logger.info("Starting show_config command")
|
|
35
|
+
self.logger.info("Starting show_config command")
|
|
44
36
|
try:
|
|
45
37
|
# Get the config instance from Django settings
|
|
46
38
|
config = self._get_config_instance()
|
|
47
|
-
logger.info("Successfully retrieved configuration instance")
|
|
39
|
+
self.logger.info("Successfully retrieved configuration instance")
|
|
48
40
|
|
|
49
41
|
if options['format'] == 'json':
|
|
50
|
-
logger.info("Displaying configuration in JSON format")
|
|
42
|
+
self.logger.info("Displaying configuration in JSON format")
|
|
51
43
|
self._show_json_format(config, options['include_secrets'])
|
|
52
44
|
else:
|
|
53
|
-
logger.info("Displaying configuration in table format")
|
|
45
|
+
self.logger.info("Displaying configuration in table format")
|
|
54
46
|
self._show_table_format(config, options['include_secrets'])
|
|
55
47
|
|
|
56
|
-
logger.info("show_config command completed successfully")
|
|
48
|
+
self.logger.info("show_config command completed successfully")
|
|
57
49
|
except Exception as e:
|
|
58
50
|
error_msg = f'Failed to show configuration: {e}'
|
|
59
|
-
logger.error(error_msg, exc_info=True)
|
|
51
|
+
self.logger.error(error_msg, exc_info=True)
|
|
60
52
|
self.stdout.write(
|
|
61
53
|
self.style.ERROR(f'❌ {error_msg}')
|
|
62
54
|
)
|
|
@@ -6,16 +6,14 @@ import re
|
|
|
6
6
|
from typing import List, Optional, Tuple
|
|
7
7
|
|
|
8
8
|
from django.conf import settings
|
|
9
|
-
from django.core.management.base import
|
|
9
|
+
from django.core.management.base import CommandParser
|
|
10
10
|
from django.urls import get_resolver
|
|
11
11
|
from django.utils.termcolors import make_style
|
|
12
12
|
|
|
13
|
-
from django_cfg.
|
|
13
|
+
from django_cfg.management.utils import SafeCommand
|
|
14
14
|
|
|
15
|
-
logger = get_logger('show_urls')
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
class Command(BaseCommand):
|
|
16
|
+
class Command(SafeCommand):
|
|
19
17
|
"""
|
|
20
18
|
Display all URL patterns in the Django project.
|
|
21
19
|
|
|
@@ -23,11 +21,7 @@ class Command(BaseCommand):
|
|
|
23
21
|
in a hierarchical format with colors and filtering options.
|
|
24
22
|
"""
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
web_executable = True
|
|
28
|
-
requires_input = False
|
|
29
|
-
is_destructive = False
|
|
30
|
-
|
|
24
|
+
command_name = 'show_urls'
|
|
31
25
|
help = 'Display all URL patterns in the project'
|
|
32
26
|
|
|
33
27
|
def __init__(self, *args, **kwargs):
|
|
@@ -88,7 +82,7 @@ class Command(BaseCommand):
|
|
|
88
82
|
|
|
89
83
|
def handle(self, *args, **options) -> None:
|
|
90
84
|
"""Main command handler."""
|
|
91
|
-
logger.info("Starting show_urls command")
|
|
85
|
+
self.logger.info("Starting show_urls command")
|
|
92
86
|
self.options = options
|
|
93
87
|
|
|
94
88
|
# Disable colors if requested
|
|
@@ -7,22 +7,15 @@ import questionary
|
|
|
7
7
|
from django.contrib.auth import get_user_model
|
|
8
8
|
from django.core.exceptions import ValidationError
|
|
9
9
|
from django.core.management import call_command
|
|
10
|
-
from django.core.management.base import BaseCommand
|
|
11
10
|
from django.core.validators import validate_email
|
|
12
11
|
|
|
13
|
-
from django_cfg.
|
|
12
|
+
from django_cfg.management.utils import InteractiveCommand
|
|
14
13
|
|
|
15
14
|
User = get_user_model()
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class Command(BaseCommand):
|
|
21
|
-
# Web execution metadata
|
|
22
|
-
web_executable = False
|
|
23
|
-
requires_input = True
|
|
24
|
-
is_destructive = False
|
|
25
|
-
|
|
17
|
+
class Command(InteractiveCommand):
|
|
18
|
+
command_name = 'superuser'
|
|
26
19
|
help = 'Create a superuser with enhanced validation and configuration'
|
|
27
20
|
|
|
28
21
|
def add_arguments(self, parser):
|
|
@@ -58,7 +51,7 @@ class Command(BaseCommand):
|
|
|
58
51
|
)
|
|
59
52
|
|
|
60
53
|
def handle(self, *args, **options):
|
|
61
|
-
logger.info("Starting superuser command")
|
|
54
|
+
self.logger.info("Starting superuser command")
|
|
62
55
|
if options['interactive'] or not any([options['username'], options['email'], options['password']]):
|
|
63
56
|
self.create_superuser_interactive()
|
|
64
57
|
else:
|
|
@@ -8,22 +8,17 @@ import subprocess
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
10
|
from django.conf import settings
|
|
11
|
-
from django.core.management.base import
|
|
11
|
+
from django.core.management.base import CommandError
|
|
12
12
|
|
|
13
13
|
from django_cfg.core.state import get_current_config
|
|
14
|
-
from django_cfg.
|
|
14
|
+
from django_cfg.management.utils import SafeCommand
|
|
15
15
|
from django_cfg.utils.path_resolution import PathResolver
|
|
16
16
|
|
|
17
|
-
logger = get_logger('tree')
|
|
18
17
|
|
|
19
|
-
class Command(
|
|
18
|
+
class Command(SafeCommand):
|
|
20
19
|
"""Display Django project structure in tree format."""
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
web_executable = True
|
|
24
|
-
requires_input = False
|
|
25
|
-
is_destructive = False
|
|
26
|
-
|
|
21
|
+
command_name = 'tree'
|
|
27
22
|
help = "Display Django project structure based on django-cfg configuration"
|
|
28
23
|
|
|
29
24
|
def add_arguments(self, parser):
|
|
@@ -83,7 +78,7 @@ class Command(BaseCommand):
|
|
|
83
78
|
|
|
84
79
|
def handle(self, *args, **options):
|
|
85
80
|
"""Execute the command."""
|
|
86
|
-
logger.info("Starting tree command")
|
|
81
|
+
self.logger.info("Starting tree command")
|
|
87
82
|
try:
|
|
88
83
|
# Get django-cfg configuration
|
|
89
84
|
config = get_current_config()
|