django-cfg 1.5.8__py3-none-any.whl → 1.5.14__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.

Files changed (119) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/api/commands/serializers.py +152 -0
  3. django_cfg/apps/api/commands/views.py +32 -0
  4. django_cfg/apps/business/accounts/management/commands/otp_test.py +5 -2
  5. django_cfg/apps/business/agents/management/commands/create_agent.py +5 -194
  6. django_cfg/apps/business/agents/management/commands/load_agent_templates.py +205 -0
  7. django_cfg/apps/business/agents/management/commands/orchestrator_status.py +4 -2
  8. django_cfg/apps/business/knowbase/management/commands/knowbase_stats.py +4 -2
  9. django_cfg/apps/business/knowbase/management/commands/setup_knowbase.py +4 -2
  10. django_cfg/apps/business/newsletter/management/commands/test_newsletter.py +5 -2
  11. django_cfg/apps/business/payments/management/commands/check_payment_status.py +4 -2
  12. django_cfg/apps/business/payments/management/commands/create_payment.py +4 -2
  13. django_cfg/apps/business/payments/management/commands/sync_currencies.py +4 -2
  14. django_cfg/apps/integrations/centrifugo/management/commands/generate_centrifugo_clients.py +5 -5
  15. django_cfg/apps/integrations/centrifugo/serializers/__init__.py +2 -1
  16. django_cfg/apps/integrations/centrifugo/serializers/publishes.py +22 -2
  17. django_cfg/apps/integrations/centrifugo/views/monitoring.py +25 -40
  18. django_cfg/apps/integrations/grpc/admin/__init__.py +7 -1
  19. django_cfg/apps/integrations/grpc/admin/config.py +113 -9
  20. django_cfg/apps/integrations/grpc/admin/grpc_api_key.py +129 -0
  21. django_cfg/apps/integrations/grpc/admin/grpc_request_log.py +72 -63
  22. django_cfg/apps/integrations/grpc/admin/grpc_server_status.py +236 -0
  23. django_cfg/apps/integrations/grpc/auth/__init__.py +11 -3
  24. django_cfg/apps/integrations/grpc/auth/api_key_auth.py +320 -0
  25. django_cfg/apps/integrations/grpc/interceptors/logging.py +17 -20
  26. django_cfg/apps/integrations/grpc/interceptors/metrics.py +15 -14
  27. django_cfg/apps/integrations/grpc/interceptors/request_logger.py +79 -59
  28. django_cfg/apps/integrations/grpc/management/commands/generate_protos.py +130 -0
  29. django_cfg/apps/integrations/grpc/management/commands/rungrpc.py +171 -96
  30. django_cfg/apps/integrations/grpc/management/commands/test_grpc_integration.py +75 -0
  31. django_cfg/apps/integrations/grpc/managers/__init__.py +2 -0
  32. django_cfg/apps/integrations/grpc/managers/grpc_api_key.py +192 -0
  33. django_cfg/apps/integrations/grpc/managers/grpc_server_status.py +19 -11
  34. django_cfg/apps/integrations/grpc/migrations/0005_grpcapikey.py +143 -0
  35. django_cfg/apps/integrations/grpc/migrations/0006_grpcrequestlog_api_key_and_more.py +34 -0
  36. django_cfg/apps/integrations/grpc/models/__init__.py +2 -0
  37. django_cfg/apps/integrations/grpc/models/grpc_api_key.py +198 -0
  38. django_cfg/apps/integrations/grpc/models/grpc_request_log.py +11 -0
  39. django_cfg/apps/integrations/grpc/models/grpc_server_status.py +39 -4
  40. django_cfg/apps/integrations/grpc/serializers/__init__.py +22 -6
  41. django_cfg/apps/integrations/grpc/serializers/api_keys.py +63 -0
  42. django_cfg/apps/integrations/grpc/serializers/charts.py +118 -120
  43. django_cfg/apps/integrations/grpc/serializers/config.py +65 -51
  44. django_cfg/apps/integrations/grpc/serializers/health.py +7 -7
  45. django_cfg/apps/integrations/grpc/serializers/proto_files.py +74 -0
  46. django_cfg/apps/integrations/grpc/serializers/requests.py +13 -7
  47. django_cfg/apps/integrations/grpc/serializers/service_registry.py +181 -112
  48. django_cfg/apps/integrations/grpc/serializers/services.py +14 -32
  49. django_cfg/apps/integrations/grpc/serializers/stats.py +50 -12
  50. django_cfg/apps/integrations/grpc/serializers/testing.py +66 -58
  51. django_cfg/apps/integrations/grpc/services/__init__.py +2 -0
  52. django_cfg/apps/integrations/grpc/services/monitoring_service.py +149 -43
  53. django_cfg/apps/integrations/grpc/services/proto_files_manager.py +268 -0
  54. django_cfg/apps/integrations/grpc/services/service_registry.py +48 -46
  55. django_cfg/apps/integrations/grpc/services/testing_service.py +10 -15
  56. django_cfg/apps/integrations/grpc/urls.py +8 -0
  57. django_cfg/apps/integrations/grpc/utils/__init__.py +4 -13
  58. django_cfg/apps/integrations/grpc/utils/integration_test.py +334 -0
  59. django_cfg/apps/integrations/grpc/utils/proto_gen.py +48 -8
  60. django_cfg/apps/integrations/grpc/utils/streaming_logger.py +177 -0
  61. django_cfg/apps/integrations/grpc/views/__init__.py +4 -0
  62. django_cfg/apps/integrations/grpc/views/api_keys.py +255 -0
  63. django_cfg/apps/integrations/grpc/views/charts.py +21 -14
  64. django_cfg/apps/integrations/grpc/views/config.py +8 -6
  65. django_cfg/apps/integrations/grpc/views/monitoring.py +51 -79
  66. django_cfg/apps/integrations/grpc/views/proto_files.py +214 -0
  67. django_cfg/apps/integrations/grpc/views/services.py +30 -21
  68. django_cfg/apps/integrations/grpc/views/testing.py +45 -43
  69. django_cfg/apps/integrations/rq/views/jobs.py +19 -9
  70. django_cfg/apps/integrations/rq/views/schedule.py +7 -3
  71. django_cfg/apps/system/dashboard/serializers/commands.py +25 -1
  72. django_cfg/apps/system/dashboard/services/commands_service.py +12 -1
  73. django_cfg/apps/system/maintenance/management/commands/maintenance.py +5 -2
  74. django_cfg/apps/system/maintenance/management/commands/process_scheduled_maintenance.py +4 -2
  75. django_cfg/apps/system/maintenance/management/commands/sync_cloudflare.py +5 -2
  76. django_cfg/config.py +33 -0
  77. django_cfg/core/generation/integration_generators/grpc_generator.py +30 -32
  78. django_cfg/management/commands/check_endpoints.py +2 -2
  79. django_cfg/management/commands/check_settings.py +3 -10
  80. django_cfg/management/commands/clear_constance.py +3 -10
  81. django_cfg/management/commands/create_token.py +4 -11
  82. django_cfg/management/commands/list_urls.py +4 -10
  83. django_cfg/management/commands/migrate_all.py +18 -12
  84. django_cfg/management/commands/migrator.py +4 -11
  85. django_cfg/management/commands/script.py +4 -10
  86. django_cfg/management/commands/show_config.py +8 -16
  87. django_cfg/management/commands/show_urls.py +5 -11
  88. django_cfg/management/commands/superuser.py +4 -11
  89. django_cfg/management/commands/tree.py +5 -10
  90. django_cfg/management/utils/README.md +402 -0
  91. django_cfg/management/utils/__init__.py +29 -0
  92. django_cfg/management/utils/mixins.py +176 -0
  93. django_cfg/middleware/pagination.py +53 -54
  94. django_cfg/models/api/grpc/__init__.py +15 -21
  95. django_cfg/models/api/grpc/config.py +155 -73
  96. django_cfg/models/ngrok/config.py +7 -6
  97. django_cfg/modules/django_client/core/generator/python/files_generator.py +5 -13
  98. django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +16 -4
  99. django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +2 -3
  100. django_cfg/modules/django_client/core/generator/typescript/files_generator.py +6 -5
  101. django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +12 -8
  102. django_cfg/modules/django_client/core/parser/base.py +114 -30
  103. django_cfg/modules/django_client/management/commands/generate_client.py +5 -2
  104. django_cfg/modules/django_client/management/commands/validate_openapi.py +5 -2
  105. django_cfg/modules/django_email/management/commands/test_email.py +4 -10
  106. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +16 -13
  107. django_cfg/modules/django_telegram/management/commands/test_telegram.py +4 -11
  108. django_cfg/modules/django_twilio/management/commands/test_twilio.py +4 -11
  109. django_cfg/modules/django_unfold/navigation.py +6 -18
  110. django_cfg/pyproject.toml +1 -1
  111. django_cfg/registry/modules.py +1 -4
  112. django_cfg/requirements.txt +52 -0
  113. django_cfg/static/frontend/admin.zip +0 -0
  114. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/METADATA +1 -1
  115. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/RECORD +118 -97
  116. django_cfg/apps/integrations/grpc/auth/jwt_auth.py +0 -295
  117. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/WHEEL +0 -0
  118. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/entry_points.txt +0 -0
  119. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/licenses/LICENSE +0 -0
@@ -33,7 +33,6 @@
33
33
  */
34
34
 
35
35
  import { APIClient } from "./client";
36
- import { OPENAPI_SCHEMA } from "./schema";
37
36
  import {
38
37
  StorageAdapter,
39
38
  LocalStorageAdapter,
@@ -82,9 +81,6 @@ export * as Hooks from "./_utils/hooks";
82
81
  // Re-export core client
83
82
  export { APIClient };
84
83
 
85
- // Re-export OpenAPI schema
86
- export { OPENAPI_SCHEMA };
87
-
88
84
  // Re-export storage adapters for convenience
89
85
  export type { StorageAdapter };
90
86
  export { LocalStorageAdapter, CookieStorageAdapter, MemoryStorageAdapter };
@@ -267,11 +263,19 @@ export class API {
267
263
  }
268
264
 
269
265
  /**
270
- * Get OpenAPI schema
271
- * @returns Complete OpenAPI specification for this API
266
+ * Get OpenAPI schema path
267
+ * @returns Path to the OpenAPI schema JSON file
268
+ *
269
+ * Note: The OpenAPI schema is available in the schema.json file.
270
+ * You can load it dynamically using:
271
+ * ```typescript
272
+ * const schema = await fetch('./schema.json').then(r => r.json());
273
+ * // or using fs in Node.js:
274
+ * // const schema = JSON.parse(fs.readFileSync('./schema.json', 'utf-8'));
275
+ * ```
272
276
  */
273
- getSchema(): any {
274
- return OPENAPI_SCHEMA;
277
+ getSchemaPath(): string {
278
+ return './schema.json';
275
279
  }
276
280
  }
277
281
 
@@ -62,8 +62,12 @@ class BaseParser(ABC):
62
62
  IRContext with all schemas and operations
63
63
 
64
64
  Raises:
65
- ValueError: If COMPONENT_SPLIT_REQUEST is not detected
65
+ ValueError: If COMPONENT_SPLIT_REQUEST is not detected or schema name conflicts found
66
66
  """
67
+ # CRITICAL: Validate schema names BEFORE parsing
68
+ # This prevents generation from starting with invalid schemas
69
+ self._validate_schema_names()
70
+
67
71
  # Parse metadata
68
72
  openapi_info = self._parse_openapi_info()
69
73
  django_metadata = self._parse_django_metadata()
@@ -237,54 +241,134 @@ class BaseParser(ABC):
237
241
 
238
242
  return False
239
243
 
240
- # ===== Schema Parsing =====
244
+ # ===== Schema Validation =====
245
+
246
+ def _validate_schema_names(self) -> None:
247
+ """
248
+ Validate schema names for conflicts BEFORE parsing.
249
+
250
+ This method checks for:
251
+ 1. Case-insensitive duplicates (e.g., "User" and "user")
252
+ 2. Exact duplicates (e.g., "GRPCServerInfo" from two different serializers)
253
+
254
+ Raises:
255
+ ValueError: If schema name conflicts are detected (hard exit with traceback)
256
+
257
+ Example conflicts:
258
+ - Case-insensitive: "Profile" and "profile" → filesystem conflict
259
+ - Exact duplicate: "HealthCheck" from multiple serializers → schema conflict
260
+ """
261
+ import traceback
262
+ import sys
241
263
 
242
- def _parse_all_schemas(self) -> dict[str, IRSchemaObject]:
243
- """Parse all schemas from components."""
244
264
  if not self.spec.components or not self.spec.components.schemas:
245
- return {}
265
+ return # No schemas to validate
246
266
 
247
- # Check for duplicate schema names with different casing
248
267
  schema_names = list(self.spec.components.schemas.keys())
249
268
  lowercase_map = {}
250
- exact_duplicate_map = {}
269
+ exact_duplicate_sources = {}
251
270
 
252
271
  for name in schema_names:
253
272
  lowercase = name.lower()
254
273
 
255
274
  # Check case-insensitive duplicates
256
275
  if lowercase in lowercase_map:
257
- raise ValueError(
258
- f"Duplicate schema names with different casing detected:\n"
259
- f" - {lowercase_map[lowercase]}\n"
260
- f" - {name}\n"
261
- f"This causes conflicts in case-insensitive file systems.\n"
262
- f"Please rename one of the serializers in your Django code."
276
+ existing_name = lowercase_map[lowercase]
277
+ error_msg = (
278
+ f"\n{'=' * 80}\n"
279
+ f" SCHEMA NAME CONFLICT DETECTED\n"
280
+ f"{'=' * 80}\n\n"
281
+ f"Conflict Type: Case-insensitive duplicate\n"
282
+ f"Schema Names:\n"
283
+ f" 1. '{existing_name}'\n"
284
+ f" 2. '{name}'\n\n"
285
+ f"Problem:\n"
286
+ f" These names differ only in casing and will cause conflicts on\n"
287
+ f" case-insensitive filesystems (macOS, Windows).\n\n"
288
+ f"Solution:\n"
289
+ f" Rename one of the Django serializers to make them distinct.\n"
290
+ f" Example: {name}Serializer → {name}DetailSerializer\n\n"
291
+ f"{'=' * 80}\n"
263
292
  )
264
- lowercase_map[lowercase] = name
265
293
 
266
- # Check exact duplicates
267
- if name in exact_duplicate_map:
268
- # Get schema titles to show source serializer names
269
- schema1 = self.spec.components.schemas.get(name)
270
- title1 = getattr(schema1, 'title', 'Unknown')
271
- title2 = exact_duplicate_map[name]
294
+ # Print full error with traceback
295
+ print(error_msg, file=sys.stderr)
296
+ print("\n🔍 Traceback (schema validation):", file=sys.stderr)
297
+ traceback.print_stack(file=sys.stderr)
272
298
 
299
+ # Hard exit - stop generation immediately
273
300
  raise ValueError(
274
- f"Duplicate schema name detected: '{name}'\n"
275
- f"Multiple serializers are generating the same schema name:\n"
276
- f" - {title1}\n"
277
- f" - {title2}\n"
278
- f"This causes schema conflicts in the generated API client.\n"
279
- f"Please rename one of the serializers to make them unique.\n"
280
- f"Example: HealthCheckSerializer → GRPCHealthCheckSerializer"
301
+ f"Case-insensitive schema name conflict: '{existing_name}' vs '{name}'. "
302
+ f"Cannot generate client with conflicting schema names."
281
303
  )
282
304
 
283
- # Store with title for later comparison
305
+ lowercase_map[lowercase] = name
306
+
307
+ # Track schema sources for exact duplicate detection
284
308
  schema = self.spec.components.schemas.get(name)
285
- title = getattr(schema, 'title', name)
286
- exact_duplicate_map[name] = title
309
+ if schema and not isinstance(schema, ReferenceObject):
310
+ # Get source information from schema
311
+ title = getattr(schema, 'title', name)
312
+ description = getattr(schema, 'description', '')
313
+
314
+ # Create signature for duplicate detection
315
+ if name in exact_duplicate_sources:
316
+ # Found exact duplicate!
317
+ existing = exact_duplicate_sources[name]
318
+ error_msg = (
319
+ f"\n{'=' * 80}\n"
320
+ f"❌ SCHEMA NAME CONFLICT DETECTED\n"
321
+ f"{'=' * 80}\n\n"
322
+ f"Conflict Type: Exact duplicate schema name\n"
323
+ f"Schema Name: '{name}'\n\n"
324
+ f"Sources:\n"
325
+ f" 1. {existing['title']}\n"
326
+ f" Description: {existing['description'][:100]}\n"
327
+ f" 2. {title}\n"
328
+ f" Description: {description[:100]}\n\n"
329
+ f"Problem:\n"
330
+ f" Multiple serializers are generating the same schema name '{name}'.\n"
331
+ f" This causes schema conflicts in the generated API client and\n"
332
+ f" OpenAPI documentation.\n\n"
333
+ f"Solution:\n"
334
+ f" Rename one of the serializers to make them unique.\n"
335
+ f" Examples:\n"
336
+ f" - HealthCheckSerializer → GRPCHealthCheckSerializer\n"
337
+ f" - ServerInfoSerializer → GRPCServerStatusSerializer\n\n"
338
+ f"{'=' * 80}\n"
339
+ )
340
+
341
+ # Print full error with traceback
342
+ print(error_msg, file=sys.stderr)
343
+ print("\n🔍 Traceback (schema validation):", file=sys.stderr)
344
+ traceback.print_stack(file=sys.stderr)
345
+
346
+ # Hard exit - stop generation immediately
347
+ raise ValueError(
348
+ f"Duplicate schema name detected: '{name}'. "
349
+ f"Multiple serializers are generating this schema. "
350
+ f"Cannot generate client with conflicting schemas."
351
+ )
352
+
353
+ # Store for duplicate detection
354
+ exact_duplicate_sources[name] = {
355
+ 'title': title,
356
+ 'description': description,
357
+ }
358
+
359
+ # ===== Schema Parsing =====
360
+
361
+ def _parse_all_schemas(self) -> dict[str, IRSchemaObject]:
362
+ """
363
+ Parse all schemas from components.
364
+
365
+ Note: Schema name validation is done in _validate_schema_names()
366
+ which is called BEFORE this method in parse().
367
+ """
368
+ if not self.spec.components or not self.spec.components.schemas:
369
+ return {}
287
370
 
371
+ # Parse schemas (validation already done in _validate_schema_names)
288
372
  schemas = {}
289
373
  for name, schema_or_ref in self.spec.components.schemas.items():
290
374
  # Skip references for now
@@ -8,12 +8,15 @@ Usage:
8
8
  """
9
9
 
10
10
 
11
- from django.core.management.base import BaseCommand, CommandError
11
+ from django.core.management.base import CommandError
12
12
 
13
+ from django_cfg.management.utils import AdminCommand
13
14
 
14
- class Command(BaseCommand):
15
+
16
+ class Command(AdminCommand):
15
17
  """Generate OpenAPI clients for configured application groups."""
16
18
 
19
+ command_name = 'generate_client'
17
20
  help = "Generate Python, TypeScript, and Go API clients from OpenAPI schemas"
18
21
 
19
22
  def add_arguments(self, parser):
@@ -12,12 +12,15 @@ Usage:
12
12
  from pathlib import Path
13
13
  from typing import List
14
14
 
15
- from django.core.management.base import BaseCommand, CommandError
15
+ from django.core.management.base import CommandError
16
16
 
17
+ from django_cfg.management.utils import AdminCommand
17
18
 
18
- class Command(BaseCommand):
19
+
20
+ class Command(AdminCommand):
19
21
  """Validate and fix OpenAPI schema quality issues in DRF serializers."""
20
22
 
23
+ command_name = 'validate_openapi'
21
24
  help = "Validate and auto-fix OpenAPI schema quality issues"
22
25
 
23
26
  def add_arguments(self, parser):
@@ -5,22 +5,16 @@ Tests email sending functionality using django_cfg configuration.
5
5
  """
6
6
 
7
7
  from django.contrib.auth import get_user_model
8
- from django.core.management.base import BaseCommand
9
8
 
10
- from django_cfg.modules.django_logging import get_logger
9
+ from django_cfg.management.utils import SafeCommand
11
10
 
12
11
  User = get_user_model()
13
- logger = get_logger('test_email')
14
12
 
15
13
 
16
- class Command(BaseCommand):
14
+ class Command(SafeCommand):
17
15
  """Command to test email functionality."""
18
16
 
19
- # Web execution metadata
20
- web_executable = True
21
- requires_input = False
22
- is_destructive = False
23
-
17
+ command_name = 'test_email'
24
18
  help = "Test email sending functionality"
25
19
 
26
20
  def add_arguments(self, parser):
@@ -48,7 +42,7 @@ class Command(BaseCommand):
48
42
  subject = options["subject"]
49
43
  message = options["message"]
50
44
 
51
- logger.info(f"Starting email test for {email}")
45
+ self.logger.info(f"Starting email test for {email}")
52
46
  self.stdout.write(f"🚀 Testing email service for {email}")
53
47
 
54
48
  # Create test user if not exists
@@ -12,8 +12,6 @@ from django.core.management.commands.runserver import Command as RunServerComman
12
12
  from django_cfg.modules.django_logging import get_logger
13
13
  from django_cfg.modules.django_ngrok import get_ngrok_service
14
14
 
15
- logger = get_logger('runserver_ngrok')
16
-
17
15
 
18
16
  class Command(RunServerCommand):
19
17
  """Enhanced runserver command with ngrok tunnel support."""
@@ -25,6 +23,11 @@ class Command(RunServerCommand):
25
23
 
26
24
  help = f'{RunServerCommand.help.rstrip(".")} with ngrok tunnel.'
27
25
 
26
+ def __init__(self, *args, **kwargs):
27
+ """Initialize with logger."""
28
+ super().__init__(*args, **kwargs)
29
+ self.logger = get_logger('runserver_ngrok')
30
+
28
31
  def add_arguments(self, parser):
29
32
  super().add_arguments(parser)
30
33
  parser.add_argument(
@@ -76,14 +79,14 @@ class Command(RunServerCommand):
76
79
  ngrok_service = get_ngrok_service()
77
80
 
78
81
  self.stdout.write("🚇 Starting ngrok tunnel...")
79
- logger.info(f"Starting ngrok tunnel for port {server_port}")
82
+ self.logger.info(f"Starting ngrok tunnel for port {server_port}")
80
83
 
81
84
  tunnel_url = ngrok_service.start_tunnel(server_port)
82
85
 
83
86
  if tunnel_url:
84
87
  # Wait for tunnel to be fully established
85
88
  self.stdout.write("⏳ Waiting for tunnel to be established...")
86
- logger.info("Waiting for ngrok tunnel to be fully established")
89
+ self.logger.info("Waiting for ngrok tunnel to be fully established")
87
90
 
88
91
  max_retries = 10
89
92
  retry_count = 0
@@ -98,10 +101,10 @@ class Command(RunServerCommand):
98
101
  current_url = ngrok_service.get_tunnel_url()
99
102
  if current_url and current_url == tunnel_url:
100
103
  tunnel_ready = True
101
- logger.info(f"Ngrok tunnel established successfully: {tunnel_url}")
104
+ self.logger.info(f"Ngrok tunnel established successfully: {tunnel_url}")
102
105
  break
103
106
  except Exception as e:
104
- logger.warning(f"Tunnel check attempt {retry_count} failed: {e}")
107
+ self.logger.warning(f"Tunnel check attempt {retry_count} failed: {e}")
105
108
 
106
109
  self.stdout.write(f"⏳ Tunnel check {retry_count}/{max_retries}...")
107
110
 
@@ -116,16 +119,16 @@ class Command(RunServerCommand):
116
119
  self.stdout.write(
117
120
  self.style.SUCCESS(f"✅ Ngrok tunnel ready: {tunnel_url}")
118
121
  )
119
- logger.info(f"Ngrok tunnel fully ready: {tunnel_url}")
122
+ self.logger.info(f"Ngrok tunnel fully ready: {tunnel_url}")
120
123
  else:
121
124
  self.stdout.write(
122
125
  self.style.WARNING("⚠️ Ngrok tunnel started but may not be fully ready")
123
126
  )
124
- logger.warning("Ngrok tunnel started but readiness check failed")
127
+ self.logger.warning("Ngrok tunnel started but readiness check failed")
125
128
  else:
126
129
  error_msg = "Failed to start ngrok tunnel"
127
130
  self.stdout.write(self.style.ERROR(f"❌ {error_msg}"))
128
- logger.error(error_msg)
131
+ self.logger.error(error_msg)
129
132
 
130
133
  def _set_ngrok_env_vars(self, tunnel_url: str):
131
134
  """Set environment variables with ngrok URL for easy access."""
@@ -145,10 +148,10 @@ class Command(RunServerCommand):
145
148
  os.environ['NGROK_API_URL'] = tunnel_url
146
149
 
147
150
  # Environment variables set - no need for verbose output
148
- logger.info(f"Set ngrok environment variables: {tunnel_url}")
151
+ self.logger.info(f"Set ngrok environment variables: {tunnel_url}")
149
152
 
150
153
  except Exception as e:
151
- logger.warning(f"Could not set ngrok environment variables: {e}")
154
+ self.logger.warning(f"Could not set ngrok environment variables: {e}")
152
155
 
153
156
  def _update_allowed_hosts(self, tunnel_url: str):
154
157
  """Update ALLOWED_HOSTS with ngrok domain."""
@@ -164,7 +167,7 @@ class Command(RunServerCommand):
164
167
  if hasattr(settings, 'ALLOWED_HOSTS'):
165
168
  if ngrok_host not in settings.ALLOWED_HOSTS:
166
169
  settings.ALLOWED_HOSTS.append(ngrok_host)
167
- logger.info(f"Added {ngrok_host} to ALLOWED_HOSTS")
170
+ self.logger.info(f"Added {ngrok_host} to ALLOWED_HOSTS")
168
171
 
169
172
  except Exception as e:
170
- logger.warning(f"Could not update ALLOWED_HOSTS: {e}")
173
+ self.logger.warning(f"Could not update ALLOWED_HOSTS: {e}")
@@ -4,20 +4,13 @@ Test Telegram Command
4
4
  Tests Telegram notification functionality using django_cfg configuration.
5
5
  """
6
6
 
7
- from django.core.management.base import BaseCommand
7
+ from django_cfg.management.utils import SafeCommand
8
8
 
9
- from django_cfg.modules.django_logging import get_logger
10
9
 
11
- logger = get_logger('test_telegram')
12
-
13
- class Command(BaseCommand):
10
+ class Command(SafeCommand):
14
11
  """Command to test Telegram functionality."""
15
12
 
16
- # Web execution metadata
17
- web_executable = True
18
- requires_input = False
19
- is_destructive = False
20
-
13
+ command_name = 'test_telegram'
21
14
  help = "Test Telegram notification functionality"
22
15
 
23
16
  def add_arguments(self, parser):
@@ -29,7 +22,7 @@ class Command(BaseCommand):
29
22
  )
30
23
 
31
24
  def handle(self, *args, **options):
32
- logger.info("Starting test_telegram command")
25
+ self.logger.info("Starting test_telegram command")
33
26
  message = options["message"]
34
27
 
35
28
  self.stdout.write("🚀 Testing Telegram notification service")
@@ -4,20 +4,13 @@ Test Twilio Command
4
4
  Tests Twilio messaging functionality using django_cfg configuration.
5
5
  """
6
6
 
7
- from django.core.management.base import BaseCommand
7
+ from django_cfg.management.utils import SafeCommand
8
8
 
9
- from django_cfg.modules.django_logging import get_logger
10
9
 
11
- logger = get_logger('test_twilio')
12
-
13
- class Command(BaseCommand):
10
+ class Command(SafeCommand):
14
11
  """Command to test Twilio functionality."""
15
12
 
16
- # Web execution metadata
17
- web_executable = True
18
- requires_input = False
19
- is_destructive = False
20
-
13
+ command_name = 'test_twilio'
21
14
  help = "Test Twilio messaging functionality"
22
15
 
23
16
  def add_arguments(self, parser):
@@ -45,7 +38,7 @@ class Command(BaseCommand):
45
38
  )
46
39
 
47
40
  def handle(self, *args, **options):
48
- logger.info("Starting test_twilio command")
41
+ self.logger.info("Starting test_twilio command")
49
42
  to_number = options["to"]
50
43
  message = options["message"]
51
44
  is_whatsapp = options["whatsapp"]
@@ -148,29 +148,17 @@ class NavigationManager(BaseCfgModule):
148
148
 
149
149
  # gRPC Dashboard (if enabled)
150
150
  if self.is_grpc_enabled():
151
- grpc_items = []
152
-
153
- # Monitoring API endpoint
154
- grpc_items.append(
155
- NavigationItem(title="Monitor", icon=Icons.MONITOR_HEART, link="/cfg/admin/admin/dashboard/grpc/")
156
- )
157
-
158
- # Request Logs with safe URL resolution
159
- logs_item = self._create_nav_item(
160
- title="Request Logs",
161
- icon=Icons.LIST_ALT,
162
- url_name="admin:grpc_grpcrequestlog_changelist",
163
- fallback_link="/admin/grpc/grpcrequestlog/"
164
- )
165
- if logs_item:
166
- grpc_items.append(logs_item)
167
-
168
151
  navigation_sections.append(
169
152
  NavigationSection(
170
153
  title="gRPC",
171
154
  separator=True,
172
155
  collapsible=True,
173
- items=grpc_items
156
+ items=[
157
+ NavigationItem(title="Monitor", icon=Icons.MONITOR_HEART, link="/cfg/admin/admin/dashboard/grpc/"),
158
+ NavigationItem(title="Request Logs", icon=Icons.LIST_ALT, link=str(reverse_lazy("admin:grpc_grpcrequestlog_changelist"))),
159
+ NavigationItem(title="API Keys", icon=Icons.KEY, link=str(reverse_lazy("admin:grpc_grpcapikey_changelist"))),
160
+ NavigationItem(title="Server Status", icon=Icons.HEALTH_AND_SAFETY, link=str(reverse_lazy("admin:grpc_grpcserverstatus_changelist"))),
161
+ ]
174
162
  )
175
163
  )
176
164
 
django_cfg/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "django-cfg"
7
- version = "1.5.8"
7
+ version = "1.5.14"
8
8
  description = "Modern Django framework with type-safe Pydantic v2 configuration, Next.js admin integration, real-time WebSockets, and 8 enterprise apps. Replace settings.py with validated models, 90% less code. Production-ready with AI agents, auto-generated TypeScript clients, and zero-config features."
9
9
  readme = "README.md"
10
10
  keywords = [ "django", "configuration", "pydantic", "settings", "type-safety", "pydantic-settings", "django-environ", "startup-validation", "ide-autocomplete", "nextjs-admin", "react-admin", "websocket", "centrifugo", "real-time", "typescript-generation", "ai-agents", "enterprise-django", "django-settings", "type-safe-config", "modern-django",]
@@ -13,11 +13,8 @@ MODULES_REGISTRY = {
13
13
  # Centrifugo module
14
14
  "DjangoCfgCentrifugoConfig": ("django_cfg.apps.integrations.centrifugo.services.client.config", "DjangoCfgCentrifugoConfig"),
15
15
 
16
- # gRPC module
16
+ # gRPC module (uses flat API - no nested config imports needed)
17
17
  "GRPCConfig": ("django_cfg.models.api.grpc", "GRPCConfig"),
18
- "GRPCServerConfig": ("django_cfg.models.api.grpc", "GRPCServerConfig"),
19
- "GRPCAuthConfig": ("django_cfg.models.api.grpc", "GRPCAuthConfig"),
20
- "GRPCProtoConfig": ("django_cfg.models.api.grpc", "GRPCProtoConfig"),
21
18
 
22
19
  # Next.js Admin Integration
23
20
  "NextJsAdminConfig": ("django_cfg.modules.nextjs_admin", "NextJsAdminConfig"),
@@ -0,0 +1,52 @@
1
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2
+ # ⚠️ DJANGO-CFG LIBRARY - TESTING & DEVELOPMENT INSTRUCTIONS
3
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4
+ #
5
+ # ❌ DO NOT test django-cfg library directly from this directory!
6
+ # ❌ DO NOT use pip install -r requirements.txt
7
+ # ❌ DO NOT use poetry install here
8
+ #
9
+ # ✅ This library is AUTOMATICALLY LINKED to the Django test project
10
+ # ✅ All changes in this library are IMMEDIATELY available in the test project
11
+ # ✅ NO installation or build steps needed - just edit and test!
12
+ #
13
+ # 📋 HOW TO TEST YOUR CHANGES:
14
+ #
15
+ # This library (django-cfg-dev) is automatically symlinked to:
16
+ # ../../../../solution/projects/django/
17
+ #
18
+ # All testing MUST be done through the Django project:
19
+ #
20
+ # cd ../../../../solution/projects/django
21
+ # poetry run python manage.py migrate
22
+ # poetry run python manage.py runserver
23
+ # poetry run python manage.py test
24
+ # poetry run pytest
25
+ #
26
+ # 🔄 WORKFLOW:
27
+ #
28
+ # 1. Edit django-cfg library code here (src/django_cfg/...)
29
+ # 2. Changes are INSTANTLY available in the Django project (via symlink)
30
+ # 3. Test your changes by running Django commands from ../../../../solution/projects/django
31
+ # 4. No rebuild or reinstall needed - it's live!
32
+ #
33
+ # 📁 PROJECT STRUCTURE:
34
+ #
35
+ # @projects/django-cfg/
36
+ # ├── projects/django-cfg-dev/ ← Django-CFG library (YOU ARE HERE)
37
+ # │ └── src/django_cfg/ ← Library source code
38
+ # └── solution/projects/django/ ← Django test project (GO HERE)
39
+ # ├── manage.py ← Run commands here
40
+ # ├── pyproject.toml ← Django project dependencies
41
+ # └── .venv/ ← Contains symlink to django-cfg-dev
42
+ #
43
+ # 🔗 SYMLINK DETAILS:
44
+ #
45
+ # The symlink is created automatically via: make install-local
46
+ # Located at: ../../../../solution/projects/django/.venv/lib/python3.12/site-packages/django_cfg
47
+ # Points to: projects/django-cfg-dev/src/django_cfg (this directory)
48
+ #
49
+ # 💡 TIP: If symlink is broken, run from django-cfg root:
50
+ # make install-local
51
+ #
52
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-cfg
3
- Version: 1.5.8
3
+ Version: 1.5.14
4
4
  Summary: Modern Django framework with type-safe Pydantic v2 configuration, Next.js admin integration, real-time WebSockets, and 8 enterprise apps. Replace settings.py with validated models, 90% less code. Production-ready with AI agents, auto-generated TypeScript clients, and zero-config features.
5
5
  Project-URL: Homepage, https://djangocfg.com
6
6
  Project-URL: Documentation, https://djangocfg.com