django-cfg 1.4.9__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.
Files changed (193) hide show
  1. django_cfg/apps/agents/management/commands/create_agent.py +1 -1
  2. django_cfg/apps/agents/management/commands/orchestrator_status.py +3 -3
  3. django_cfg/apps/newsletter/serializers.py +40 -3
  4. django_cfg/apps/newsletter/views/campaigns.py +12 -3
  5. django_cfg/apps/newsletter/views/emails.py +14 -3
  6. django_cfg/apps/newsletter/views/subscriptions.py +12 -2
  7. django_cfg/apps/payments/middleware/api_access.py +6 -2
  8. django_cfg/apps/payments/middleware/rate_limiting.py +2 -1
  9. django_cfg/apps/payments/middleware/usage_tracking.py +5 -1
  10. django_cfg/apps/payments/models/managers/api_key_managers.py +0 -1
  11. django_cfg/apps/payments/models/managers/subscription_managers.py +0 -1
  12. django_cfg/apps/payments/services/core/balance_service.py +5 -5
  13. django_cfg/apps/payments/services/core/subscription_service.py +1 -2
  14. django_cfg/apps/payments/views/api/balances.py +8 -7
  15. django_cfg/apps/payments/views/api/base.py +10 -6
  16. django_cfg/apps/payments/views/api/currencies.py +53 -10
  17. django_cfg/apps/payments/views/api/payments.py +3 -1
  18. django_cfg/apps/payments/views/api/subscriptions.py +2 -5
  19. django_cfg/apps/payments/views/api/webhooks.py +72 -7
  20. django_cfg/apps/payments/views/overview/serializers.py +34 -1
  21. django_cfg/apps/payments/views/overview/views.py +2 -1
  22. django_cfg/apps/payments/views/serializers/payments.py +6 -6
  23. django_cfg/apps/urls.py +106 -45
  24. django_cfg/core/base/config_model.py +2 -2
  25. django_cfg/core/constants.py +1 -1
  26. django_cfg/core/generation/integration_generators/__init__.py +1 -1
  27. django_cfg/core/generation/integration_generators/api.py +82 -41
  28. django_cfg/core/integration/display/startup.py +30 -22
  29. django_cfg/core/integration/url_integration.py +15 -16
  30. django_cfg/dashboard/sections/documentation.py +391 -0
  31. django_cfg/management/commands/check_endpoints.py +11 -160
  32. django_cfg/management/commands/check_settings.py +13 -265
  33. django_cfg/management/commands/clear_constance.py +13 -201
  34. django_cfg/management/commands/create_token.py +13 -321
  35. django_cfg/management/commands/generate_clients.py +23 -0
  36. django_cfg/management/commands/list_urls.py +13 -306
  37. django_cfg/management/commands/migrate_all.py +13 -126
  38. django_cfg/management/commands/migrator.py +13 -396
  39. django_cfg/management/commands/rundramatiq.py +15 -247
  40. django_cfg/management/commands/rundramatiq_simulator.py +12 -429
  41. django_cfg/management/commands/runserver_ngrok.py +15 -160
  42. django_cfg/management/commands/script.py +12 -488
  43. django_cfg/management/commands/show_config.py +12 -215
  44. django_cfg/management/commands/show_urls.py +12 -342
  45. django_cfg/management/commands/superuser.py +15 -295
  46. django_cfg/management/commands/task_clear.py +14 -217
  47. django_cfg/management/commands/task_status.py +13 -248
  48. django_cfg/management/commands/test_email.py +15 -86
  49. django_cfg/management/commands/test_telegram.py +14 -61
  50. django_cfg/management/commands/test_twilio.py +15 -105
  51. django_cfg/management/commands/tree.py +13 -383
  52. django_cfg/management/commands/validate_openapi.py +10 -0
  53. django_cfg/middleware/README.md +1 -1
  54. django_cfg/middleware/user_activity.py +3 -3
  55. django_cfg/models/__init__.py +2 -2
  56. django_cfg/models/api/drf/spectacular.py +6 -6
  57. django_cfg/models/django/__init__.py +2 -2
  58. django_cfg/models/django/openapi.py +238 -0
  59. django_cfg/models/django/{revolution.py → revolution_legacy.py} +8 -0
  60. django_cfg/modules/django_admin/management/__init__.py +0 -0
  61. django_cfg/modules/django_admin/management/commands/__init__.py +0 -0
  62. django_cfg/modules/django_admin/management/commands/check_endpoints.py +169 -0
  63. django_cfg/modules/django_admin/management/commands/check_settings.py +355 -0
  64. django_cfg/modules/django_admin/management/commands/clear_constance.py +208 -0
  65. django_cfg/modules/django_admin/management/commands/create_token.py +328 -0
  66. django_cfg/modules/django_admin/management/commands/list_urls.py +313 -0
  67. django_cfg/modules/django_admin/management/commands/migrate_all.py +133 -0
  68. django_cfg/modules/django_admin/management/commands/migrator.py +403 -0
  69. django_cfg/modules/django_admin/management/commands/script.py +496 -0
  70. django_cfg/modules/django_admin/management/commands/show_config.py +225 -0
  71. django_cfg/modules/django_admin/management/commands/show_urls.py +361 -0
  72. django_cfg/modules/django_admin/management/commands/superuser.py +302 -0
  73. django_cfg/modules/django_admin/management/commands/tree.py +390 -0
  74. django_cfg/modules/django_client/__init__.py +20 -0
  75. django_cfg/modules/django_client/apps.py +35 -0
  76. django_cfg/modules/django_client/core/__init__.py +56 -0
  77. django_cfg/modules/django_client/core/archive/__init__.py +11 -0
  78. django_cfg/modules/django_client/core/archive/manager.py +134 -0
  79. django_cfg/modules/django_client/core/cli/__init__.py +12 -0
  80. django_cfg/modules/django_client/core/cli/main.py +235 -0
  81. django_cfg/modules/django_client/core/config/__init__.py +18 -0
  82. django_cfg/modules/django_client/core/config/config.py +188 -0
  83. django_cfg/modules/django_client/core/config/group.py +101 -0
  84. django_cfg/modules/django_client/core/config/service.py +209 -0
  85. django_cfg/modules/django_client/core/generator/__init__.py +115 -0
  86. django_cfg/modules/django_client/core/generator/base.py +767 -0
  87. django_cfg/modules/django_client/core/generator/python.py +751 -0
  88. django_cfg/modules/django_client/core/generator/templates/python/__init__.py.jinja +9 -0
  89. django_cfg/modules/django_client/core/generator/templates/python/api_wrapper.py.jinja +130 -0
  90. django_cfg/modules/django_client/core/generator/templates/python/app_init.py.jinja +6 -0
  91. django_cfg/modules/django_client/core/generator/templates/python/client/app_client.py.jinja +18 -0
  92. django_cfg/modules/django_client/core/generator/templates/python/client/flat_client.py.jinja +38 -0
  93. django_cfg/modules/django_client/core/generator/templates/python/client/main_client.py.jinja +50 -0
  94. django_cfg/modules/django_client/core/generator/templates/python/client/main_client_file.py.jinja +13 -0
  95. django_cfg/modules/django_client/core/generator/templates/python/client/operation_method.py.jinja +7 -0
  96. django_cfg/modules/django_client/core/generator/templates/python/client/sub_client.py.jinja +11 -0
  97. django_cfg/modules/django_client/core/generator/templates/python/client_file.py.jinja +13 -0
  98. django_cfg/modules/django_client/core/generator/templates/python/main_init.py.jinja +50 -0
  99. django_cfg/modules/django_client/core/generator/templates/python/models/app_models.py.jinja +17 -0
  100. django_cfg/modules/django_client/core/generator/templates/python/models/enum_class.py.jinja +15 -0
  101. django_cfg/modules/django_client/core/generator/templates/python/models/enums.py.jinja +8 -0
  102. django_cfg/modules/django_client/core/generator/templates/python/models/models.py.jinja +17 -0
  103. django_cfg/modules/django_client/core/generator/templates/python/models/schema_class.py.jinja +19 -0
  104. django_cfg/modules/django_client/core/generator/templates/python/utils/logger.py.jinja +255 -0
  105. django_cfg/modules/django_client/core/generator/templates/python/utils/schema.py.jinja +12 -0
  106. django_cfg/modules/django_client/core/generator/templates/typescript/app_index.ts.jinja +2 -0
  107. django_cfg/modules/django_client/core/generator/templates/typescript/client/app_client.ts.jinja +18 -0
  108. django_cfg/modules/django_client/core/generator/templates/typescript/client/client.ts.jinja +327 -0
  109. django_cfg/modules/django_client/core/generator/templates/typescript/client/flat_client.ts.jinja +109 -0
  110. django_cfg/modules/django_client/core/generator/templates/typescript/client/main_client_file.ts.jinja +9 -0
  111. django_cfg/modules/django_client/core/generator/templates/typescript/client/operation.ts.jinja +61 -0
  112. django_cfg/modules/django_client/core/generator/templates/typescript/client/sub_client.ts.jinja +15 -0
  113. django_cfg/modules/django_client/core/generator/templates/typescript/client_file.ts.jinja +9 -0
  114. django_cfg/modules/django_client/core/generator/templates/typescript/index.ts.jinja +5 -0
  115. django_cfg/modules/django_client/core/generator/templates/typescript/main_index.ts.jinja +206 -0
  116. django_cfg/modules/django_client/core/generator/templates/typescript/models/app_models.ts.jinja +8 -0
  117. django_cfg/modules/django_client/core/generator/templates/typescript/models/enums.ts.jinja +4 -0
  118. django_cfg/modules/django_client/core/generator/templates/typescript/models/models.ts.jinja +8 -0
  119. django_cfg/modules/django_client/core/generator/templates/typescript/utils/errors.ts.jinja +114 -0
  120. django_cfg/modules/django_client/core/generator/templates/typescript/utils/http.ts.jinja +98 -0
  121. django_cfg/modules/django_client/core/generator/templates/typescript/utils/logger.ts.jinja +251 -0
  122. django_cfg/modules/django_client/core/generator/templates/typescript/utils/schema.ts.jinja +7 -0
  123. django_cfg/modules/django_client/core/generator/templates/typescript/utils/storage.ts.jinja +114 -0
  124. django_cfg/modules/django_client/core/generator/typescript.py +872 -0
  125. django_cfg/modules/django_client/core/groups/__init__.py +13 -0
  126. django_cfg/modules/django_client/core/groups/detector.py +178 -0
  127. django_cfg/modules/django_client/core/groups/manager.py +314 -0
  128. django_cfg/modules/django_client/core/ir/__init__.py +57 -0
  129. django_cfg/modules/django_client/core/ir/context.py +387 -0
  130. django_cfg/modules/django_client/core/ir/operation.py +518 -0
  131. django_cfg/modules/django_client/core/ir/schema.py +353 -0
  132. django_cfg/modules/django_client/core/parser/__init__.py +74 -0
  133. django_cfg/modules/django_client/core/parser/base.py +648 -0
  134. django_cfg/modules/django_client/core/parser/models/__init__.py +74 -0
  135. django_cfg/modules/django_client/core/parser/models/base.py +212 -0
  136. django_cfg/modules/django_client/core/parser/models/components.py +160 -0
  137. django_cfg/modules/django_client/core/parser/models/openapi.py +203 -0
  138. django_cfg/modules/django_client/core/parser/models/operation.py +207 -0
  139. django_cfg/modules/django_client/core/parser/models/schema.py +266 -0
  140. django_cfg/modules/django_client/core/parser/openapi30.py +56 -0
  141. django_cfg/modules/django_client/core/parser/openapi31.py +64 -0
  142. django_cfg/modules/django_client/core/validation/__init__.py +22 -0
  143. django_cfg/modules/django_client/core/validation/checker.py +134 -0
  144. django_cfg/modules/django_client/core/validation/fixer.py +216 -0
  145. django_cfg/modules/django_client/core/validation/reporter.py +480 -0
  146. django_cfg/modules/django_client/core/validation/rules/__init__.py +11 -0
  147. django_cfg/modules/django_client/core/validation/rules/base.py +96 -0
  148. django_cfg/modules/django_client/core/validation/rules/type_hints.py +288 -0
  149. django_cfg/modules/django_client/core/validation/safety.py +266 -0
  150. django_cfg/modules/django_client/management/__init__.py +3 -0
  151. django_cfg/modules/django_client/management/commands/__init__.py +3 -0
  152. django_cfg/modules/django_client/management/commands/generate_client.py +422 -0
  153. django_cfg/modules/django_client/management/commands/validate_openapi.py +343 -0
  154. django_cfg/modules/django_client/spectacular/__init__.py +9 -0
  155. django_cfg/modules/django_client/spectacular/enum_naming.py +192 -0
  156. django_cfg/modules/django_client/urls.py +72 -0
  157. django_cfg/modules/django_email/management/__init__.py +0 -0
  158. django_cfg/modules/django_email/management/commands/__init__.py +0 -0
  159. django_cfg/modules/django_email/management/commands/test_email.py +93 -0
  160. django_cfg/modules/django_logging/django_logger.py +6 -6
  161. django_cfg/modules/django_ngrok/management/__init__.py +0 -0
  162. django_cfg/modules/django_ngrok/management/commands/__init__.py +0 -0
  163. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +167 -0
  164. django_cfg/modules/django_tasks/management/__init__.py +0 -0
  165. django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
  166. django_cfg/modules/django_tasks/management/commands/rundramatiq.py +254 -0
  167. django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +437 -0
  168. django_cfg/modules/django_tasks/management/commands/task_clear.py +226 -0
  169. django_cfg/modules/django_tasks/management/commands/task_status.py +257 -0
  170. django_cfg/modules/django_telegram/management/__init__.py +0 -0
  171. django_cfg/modules/django_telegram/management/commands/__init__.py +0 -0
  172. django_cfg/modules/django_telegram/management/commands/test_telegram.py +68 -0
  173. django_cfg/modules/django_twilio/management/__init__.py +0 -0
  174. django_cfg/modules/django_twilio/management/commands/__init__.py +0 -0
  175. django_cfg/modules/django_twilio/management/commands/test_twilio.py +112 -0
  176. django_cfg/modules/django_unfold/callbacks/main.py +16 -5
  177. django_cfg/modules/django_unfold/callbacks/revolution.py +41 -36
  178. django_cfg/modules/django_unfold/dashboard.py +1 -1
  179. django_cfg/pyproject.toml +2 -6
  180. django_cfg/registry/third_party.py +5 -7
  181. django_cfg/routing/callbacks.py +1 -1
  182. django_cfg/static/admin/css/prose-unfold.css +666 -0
  183. django_cfg/templates/admin/index.html +8 -0
  184. django_cfg/templates/admin/index_new.html +13 -0
  185. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +15 -3
  186. django_cfg/templates/admin/sections/documentation_section.html +172 -0
  187. django_cfg/templates/admin/snippets/tabs/documentation_tab.html +231 -0
  188. {django_cfg-1.4.9.dist-info → django_cfg-1.4.11.dist-info}/METADATA +2 -2
  189. {django_cfg-1.4.9.dist-info → django_cfg-1.4.11.dist-info}/RECORD +192 -71
  190. django_cfg/management/commands/generate.py +0 -107
  191. {django_cfg-1.4.9.dist-info → django_cfg-1.4.11.dist-info}/WHEEL +0 -0
  192. {django_cfg-1.4.9.dist-info → django_cfg-1.4.11.dist-info}/entry_points.txt +0 -0
  193. {django_cfg-1.4.9.dist-info → django_cfg-1.4.11.dist-info}/licenses/LICENSE +0 -0
@@ -17,9 +17,16 @@ from rest_framework.decorators import api_view, permission_classes
17
17
  from rest_framework.permissions import AllowAny
18
18
  from rest_framework.response import Response
19
19
  from rest_framework.views import APIView
20
+ from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
20
21
 
21
22
  from ...services.core.webhook_service import WebhookService
22
23
  from ...services.types import WebhookValidationRequest, WebhookProcessingResult
24
+ from ..serializers.webhooks import (
25
+ WebhookResponseSerializer,
26
+ WebhookHealthSerializer,
27
+ WebhookStatsSerializer,
28
+ SupportedProvidersSerializer,
29
+ )
23
30
  from django_cfg.modules.django_logging import get_logger
24
31
 
25
32
  logger = get_logger("webhook_views")
@@ -29,7 +36,7 @@ logger = get_logger("webhook_views")
29
36
  class UniversalWebhookView(APIView):
30
37
  """
31
38
  Universal webhook handler for all payment providers.
32
-
39
+
33
40
  Features:
34
41
  - Provider-agnostic webhook processing
35
42
  - Signature validation and security
@@ -37,13 +44,29 @@ class UniversalWebhookView(APIView):
37
44
  - Comprehensive logging and monitoring
38
45
  - Integration with ngrok for development
39
46
  """
40
-
47
+
41
48
  permission_classes = [AllowAny] # Webhooks don't use standard auth
49
+ serializer_class = WebhookResponseSerializer # For OpenAPI schema generation
42
50
 
43
51
  def __init__(self, **kwargs):
44
52
  super().__init__(**kwargs)
45
53
  self.webhook_service = WebhookService()
46
-
54
+
55
+ @extend_schema(
56
+ summary="Process Webhook",
57
+ description="Process incoming webhook from payment provider",
58
+ parameters=[
59
+ OpenApiParameter(
60
+ name='provider',
61
+ description='Payment provider name (nowpayments, stripe, etc.)',
62
+ required=True,
63
+ type=OpenApiTypes.STR,
64
+ location=OpenApiParameter.PATH
65
+ )
66
+ ],
67
+ responses={200: WebhookResponseSerializer},
68
+ tags=["Webhooks"]
69
+ )
47
70
  def post(self, request: HttpRequest, provider: str) -> JsonResponse:
48
71
  """
49
72
  Handle incoming webhook from any payment provider.
@@ -144,10 +167,25 @@ class UniversalWebhookView(APIView):
144
167
  request_id
145
168
  )
146
169
 
170
+ @extend_schema(
171
+ summary="Webhook Endpoint Info",
172
+ description="Get webhook endpoint information for debugging and configuration",
173
+ parameters=[
174
+ OpenApiParameter(
175
+ name='provider',
176
+ description='Payment provider name',
177
+ required=True,
178
+ type=OpenApiTypes.STR,
179
+ location=OpenApiParameter.PATH
180
+ )
181
+ ],
182
+ responses={200: WebhookResponseSerializer},
183
+ tags=["Webhooks"]
184
+ )
147
185
  def get(self, request: HttpRequest, provider: str) -> JsonResponse:
148
186
  """
149
187
  Handle GET requests for webhook endpoint info.
150
-
188
+
151
189
  Useful for debugging and provider configuration verification.
152
190
  """
153
191
 
@@ -314,12 +352,18 @@ class UniversalWebhookView(APIView):
314
352
  return JsonResponse(response_data, status=status_code)
315
353
 
316
354
 
355
+ @extend_schema(
356
+ summary="Webhook Health Check",
357
+ description="Check webhook service health status and recent activity metrics",
358
+ responses={200: WebhookHealthSerializer},
359
+ tags=["Webhooks"]
360
+ )
317
361
  @api_view(['GET'])
318
362
  @permission_classes([AllowAny])
319
363
  def webhook_health_check(request):
320
364
  """
321
365
  Health check endpoint for webhook service.
322
-
366
+
323
367
  Returns service status and recent activity metrics.
324
368
  """
325
369
 
@@ -362,12 +406,27 @@ def webhook_health_check(request):
362
406
  }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
363
407
 
364
408
 
409
+ @extend_schema(
410
+ summary="Webhook Statistics",
411
+ description="Get webhook processing statistics for a given time period",
412
+ parameters=[
413
+ OpenApiParameter(
414
+ name='days',
415
+ description='Number of days to analyze (1-365)',
416
+ required=False,
417
+ type=OpenApiTypes.INT,
418
+ default=30
419
+ )
420
+ ],
421
+ responses={200: WebhookStatsSerializer},
422
+ tags=["Webhooks"]
423
+ )
365
424
  @api_view(['GET'])
366
425
  @permission_classes([AllowAny])
367
426
  def webhook_stats(request):
368
427
  """
369
428
  Get webhook processing statistics.
370
-
429
+
371
430
  Query parameters:
372
431
  - days: Number of days to analyze (default: 30)
373
432
  """
@@ -408,12 +467,18 @@ def webhook_stats(request):
408
467
  }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
409
468
 
410
469
 
470
+ @extend_schema(
471
+ summary="Supported Webhook Providers",
472
+ description="Get list of supported webhook providers with configuration details",
473
+ responses={200: SupportedProvidersSerializer},
474
+ tags=["Webhooks"]
475
+ )
411
476
  @api_view(['GET'])
412
477
  @permission_classes([AllowAny])
413
478
  def supported_providers(request):
414
479
  """
415
480
  Get list of supported webhook providers.
416
-
481
+
417
482
  Returns provider information and webhook URLs.
418
483
  """
419
484
 
@@ -201,5 +201,38 @@ class TimePeriodSerializer(serializers.Serializer):
201
201
  ('90d', 'Last 90 days'),
202
202
  ('1y', 'Last year'),
203
203
  ]
204
-
204
+
205
205
  period = serializers.ChoiceField(choices=PERIOD_CHOICES, default='30d')
206
+
207
+
208
+ class CurrencyAnalyticsItemSerializer(serializers.Serializer):
209
+ """
210
+ Analytics data for a single currency
211
+ """
212
+ currency_code = serializers.CharField(help_text="Currency code (e.g., BTC)")
213
+ currency_name = serializers.CharField(help_text="Currency name (e.g., Bitcoin)")
214
+ total_payments = serializers.IntegerField(help_text="Total number of payments")
215
+ total_amount = serializers.FloatField(help_text="Total amount in USD")
216
+ completed_payments = serializers.IntegerField(help_text="Number of completed payments")
217
+ average_amount = serializers.FloatField(help_text="Average payment amount in USD")
218
+ success_rate = serializers.FloatField(help_text="Success rate percentage")
219
+
220
+
221
+ class ProviderAnalyticsItemSerializer(serializers.Serializer):
222
+ """
223
+ Analytics data for a single payment provider
224
+ """
225
+ provider = serializers.CharField(help_text="Provider code")
226
+ provider_display = serializers.CharField(help_text="Provider display name")
227
+ total_payments = serializers.IntegerField(help_text="Total number of payments")
228
+ total_amount = serializers.FloatField(help_text="Total amount in USD")
229
+ completed_payments = serializers.IntegerField(help_text="Number of completed payments")
230
+ success_rate = serializers.FloatField(help_text="Success rate percentage")
231
+
232
+
233
+ class PaymentAnalyticsResponseSerializer(serializers.Serializer):
234
+ """
235
+ Payment analytics response with currency and provider breakdown
236
+ """
237
+ currency_analytics = CurrencyAnalyticsItemSerializer(many=True, help_text="Analytics by currency")
238
+ provider_analytics = ProviderAnalyticsItemSerializer(many=True, help_text="Analytics by provider")
@@ -26,6 +26,7 @@ from .serializers import (
26
26
  BalanceOverviewSerializer,
27
27
  SubscriptionOverviewSerializer,
28
28
  APIKeysOverviewSerializer,
29
+ PaymentAnalyticsResponseSerializer,
29
30
  )
30
31
 
31
32
 
@@ -95,7 +96,7 @@ from .serializers import (
95
96
  default=10
96
97
  )
97
98
  ],
98
- responses={200: 'object'} # Generic object since it's a dict with currency_analytics and provider_analytics
99
+ responses={200: PaymentAnalyticsResponseSerializer}
99
100
  ),
100
101
  balance_overview=extend_schema(
101
102
  summary="Balance Overview",
@@ -27,7 +27,7 @@ class PaymentListSerializer(serializers.ModelSerializer):
27
27
  status_display = serializers.CharField(source='get_status_display', read_only=True)
28
28
  amount_display = serializers.SerializerMethodField(read_only=True)
29
29
 
30
- def get_amount_display(self, obj):
30
+ def get_amount_display(self, obj) -> str:
31
31
  """Get formatted amount display."""
32
32
  return f"${obj.amount_usd:.2f}"
33
33
 
@@ -64,23 +64,23 @@ class PaymentSerializer(serializers.ModelSerializer):
64
64
  is_failed = serializers.SerializerMethodField(read_only=True)
65
65
  is_expired = serializers.SerializerMethodField(read_only=True)
66
66
 
67
- def get_amount_display(self, obj):
67
+ def get_amount_display(self, obj) -> str:
68
68
  """Get formatted amount display."""
69
69
  return f"${obj.amount_usd:.2f}"
70
70
 
71
- def get_is_pending(self, obj):
71
+ def get_is_pending(self, obj) -> bool:
72
72
  """Check if payment is pending."""
73
73
  return obj.status == obj.PaymentStatus.PENDING
74
74
 
75
- def get_is_completed(self, obj):
75
+ def get_is_completed(self, obj) -> bool:
76
76
  """Check if payment is completed."""
77
77
  return obj.status == obj.PaymentStatus.COMPLETED
78
78
 
79
- def get_is_failed(self, obj):
79
+ def get_is_failed(self, obj) -> bool:
80
80
  """Check if payment is failed."""
81
81
  return obj.status == obj.PaymentStatus.FAILED
82
82
 
83
- def get_is_expired(self, obj):
83
+ def get_is_expired(self, obj) -> bool:
84
84
  """Check if payment is expired."""
85
85
  return obj.status == obj.PaymentStatus.EXPIRED
86
86
 
django_cfg/apps/urls.py CHANGED
@@ -5,67 +5,128 @@ Built-in API endpoints for django_cfg functionality.
5
5
  """
6
6
 
7
7
  from django.urls import path, include
8
- from typing import List
8
+ from typing import List, Dict
9
9
  from django.urls import URLPattern
10
10
 
11
11
 
12
+ def _register_group_urls(patterns: List[URLPattern], groups: Dict) -> None:
13
+ """
14
+ Auto-register URLs from OpenAPI groups using convention.
15
+
16
+ Convention: cfg_{app} → /cfg/{app}/
17
+
18
+ Args:
19
+ patterns: URL patterns list to append to
20
+ groups: OpenAPI groups dict
21
+ """
22
+ for group_name in groups.keys():
23
+ # Only django-cfg apps (convention: cfg_*)
24
+ if not group_name.startswith('cfg_'):
25
+ continue
26
+
27
+ # Extract app name: cfg_payments → payments
28
+ app_name = group_name[4:]
29
+
30
+ # Register main URLs: /cfg/{app}/
31
+ try:
32
+ patterns.append(
33
+ path(f'cfg/{app_name}/', include(f'django_cfg.apps.{app_name}.urls'))
34
+ )
35
+ except ImportError:
36
+ pass # URL module doesn't exist
37
+
38
+ # Register admin URLs: /cfg/{app}/admin/ (if exists)
39
+ try:
40
+ patterns.append(
41
+ path(f'cfg/{app_name}/admin/', include(f'django_cfg.apps.{app_name}.urls_admin'))
42
+ )
43
+ except ImportError:
44
+ pass # Admin URL module doesn't exist
45
+
46
+
47
+ def _register_apps_fallback(patterns: List[URLPattern]) -> None:
48
+ """
49
+ Fallback: Register apps when OpenAPI is disabled.
50
+
51
+ Uses BaseCfgModule checks to determine which apps are enabled.
52
+
53
+ Args:
54
+ patterns: URL patterns list to append to
55
+ """
56
+ from django_cfg.modules.base import BaseCfgModule
57
+ base_module = BaseCfgModule()
58
+
59
+ # Business logic apps
60
+ if base_module.is_support_enabled():
61
+ patterns.append(path('cfg/support/', include('django_cfg.apps.support.urls')))
62
+
63
+ if base_module.is_accounts_enabled():
64
+ patterns.append(path('cfg/accounts/', include('django_cfg.apps.accounts.urls')))
65
+
66
+ if base_module.is_newsletter_enabled():
67
+ patterns.append(path('cfg/newsletter/', include('django_cfg.apps.newsletter.urls')))
68
+
69
+ if base_module.is_leads_enabled():
70
+ patterns.append(path('cfg/leads/', include('django_cfg.apps.leads.urls')))
71
+
72
+ if base_module.is_knowbase_enabled():
73
+ patterns.append(path('cfg/knowbase/', include('django_cfg.apps.knowbase.urls')))
74
+
75
+ if base_module.is_agents_enabled():
76
+ patterns.append(path('cfg/agents/', include('django_cfg.apps.agents.urls')))
77
+
78
+ if base_module.should_enable_tasks():
79
+ patterns.append(path('cfg/tasks/', include('django_cfg.apps.tasks.urls')))
80
+ patterns.append(path('cfg/tasks/admin/', include('django_cfg.apps.tasks.urls_admin')))
81
+
82
+ if base_module.is_payments_enabled():
83
+ patterns.append(path('cfg/payments/', include('django_cfg.apps.payments.urls')))
84
+ patterns.append(path('cfg/payments/admin/', include('django_cfg.apps.payments.urls_admin')))
85
+
86
+ # Standalone apps
87
+ if base_module.is_maintenance_enabled():
88
+ patterns.append(
89
+ path('admin/django_cfg_maintenance/', include('django_cfg.apps.maintenance.urls_admin'))
90
+ )
91
+
92
+ if base_module.is_rpc_enabled():
93
+ patterns.append(path('rpc/', include('django_cfg.modules.django_ipc_client.dashboard.urls')))
94
+ patterns.append(path('admin/rpc/', include('django_cfg.modules.django_ipc_client.dashboard.urls_admin')))
95
+
96
+
12
97
  def get_django_cfg_urlpatterns() -> List[URLPattern]:
13
98
  """
14
- Get Django CFG URL patterns based on enabled applications.
15
-
99
+ Get Django CFG URL patterns based on OpenAPI groups.
100
+
16
101
  Returns:
17
- List of URL patterns for enabled django_cfg applications
102
+ List of URL patterns for django_cfg
18
103
  """
19
- from django_cfg.modules.base import BaseCfgModule
20
-
21
104
  patterns = [
22
105
  # Core APIs (always enabled)
23
106
  path('health/', include('django_cfg.apps.api.health.urls')),
24
107
  path('endpoints/', include('django_cfg.apps.api.endpoints.urls')),
25
108
  path('commands/', include('django_cfg.apps.api.commands.urls')),
26
-
109
+
110
+ # OpenAPI schemas (if enabled)
111
+ # Provides /openapi/{group}/schema/
112
+ path('openapi/', include('django_cfg.modules.django_client.urls')),
27
113
  ]
28
-
114
+
29
115
  try:
30
- # Use BaseModule to check enabled applications
31
- base_module = BaseCfgModule()
32
-
33
- # All business logic apps are handled by Django Revolution zones
34
- # to maintain consistency and enable client generation
35
- # if base_module.is_support_enabled():
36
- # patterns.append(path('support/', include('django_cfg.apps.support.urls')))
37
- #
38
- # if base_module.is_accounts_enabled():
39
- # patterns.append(path('accounts/', include('django_cfg.apps.accounts.urls')))
40
-
41
- # Newsletter and Leads are handled by Django Revolution zones
42
- # to avoid URL namespace conflicts and enable client generation
43
- # if base_module.is_newsletter_enabled():
44
- # patterns.append(path('newsletter/', include('django_cfg.apps.newsletter.urls')))
45
- #
46
- # if base_module.is_leads_enabled():
47
- # patterns.append(path('leads/', include('django_cfg.apps.leads.urls')))
48
-
49
- # Tasks app - enabled when knowbase or agents are enabled
50
- if base_module.should_enable_tasks():
51
- patterns.append(path('admin/django_cfg_tasks/admin/', include('django_cfg.apps.tasks.urls_admin')))
52
-
53
- # Maintenance app - multi-site maintenance mode with Cloudflare
54
- # if base_module.is_maintenance_enabled():
55
- # patterns.append(path('admin/django_cfg_maintenance/', include('django_cfg.apps.maintenance.urls_admin')))
56
-
57
- if base_module.is_payments_enabled():
58
- patterns.append(path('admin/django_cfg_payments/admin/', include('django_cfg.apps.payments.urls_admin')))
59
-
60
- # RPC Dashboard - WebSocket & RPC activity monitoring
61
- if base_module.is_rpc_enabled():
62
- patterns.append(path('admin/rpc/', include('django_cfg.modules.django_ipc_client.dashboard.urls_admin')))
116
+ # Auto-register from OpenAPI groups (preferred)
117
+ from django_cfg.modules.django_client.core import get_openapi_service
118
+ service = get_openapi_service()
119
+
120
+ if service and service.is_enabled():
121
+ _register_group_urls(patterns, service.get_groups())
122
+ else:
123
+ # Fallback: Use BaseCfgModule when OpenAPI disabled
124
+ _register_apps_fallback(patterns)
63
125
 
64
126
  except Exception:
65
- # Fallback: include all URLs if config is not available
66
- # Note: This fallback should not be needed in production
67
- pass
68
-
127
+ # Last resort fallback
128
+ _register_apps_fallback(patterns)
129
+
69
130
  return patterns
70
131
 
71
132
 
@@ -313,12 +313,12 @@ class DjangoConfig(BaseModel):
313
313
  # === API Configuration ===
314
314
  drf: Optional[DRFConfig] = Field(
315
315
  default=None,
316
- description="Extended Django REST Framework configuration (supplements Revolution)",
316
+ description="Extended Django REST Framework configuration (supplements OpenAPI Client)",
317
317
  )
318
318
 
319
319
  spectacular: Optional[SpectacularConfig] = Field(
320
320
  default=None,
321
- description="Extended DRF Spectacular configuration (supplements Revolution)",
321
+ description="Extended DRF Spectacular configuration (supplements OpenAPI Client)",
322
322
  )
323
323
 
324
324
  # === Limits Configuration ===
@@ -42,7 +42,7 @@ DEFAULT_APPS: List[str] = [
42
42
  "constance.backends.database",
43
43
  # Django CFG Core
44
44
  "django_cfg",
45
- "django_revolution",
45
+ "django_cfg.modules.django_client",
46
46
  ]
47
47
 
48
48
  # Default middleware stack
@@ -4,7 +4,7 @@ Integration generators module.
4
4
  Contains generators for third-party integrations and frameworks:
5
5
  - Session configuration
6
6
  - External services (Telegram, Unfold, Constance)
7
- - API frameworks (JWT, DRF, Spectacular, Revolution)
7
+ - API frameworks (JWT, DRF, Spectacular, OpenAPI Client)
8
8
  - Background tasks (Dramatiq)
9
9
  """
10
10
 
@@ -1,7 +1,7 @@
1
1
  """
2
2
  API frameworks generator.
3
3
 
4
- Handles JWT, DRF, Spectacular, and Django Revolution configuration.
4
+ Handles JWT, DRF, Spectacular, and Django Client (OpenAPI) configuration.
5
5
  Size: ~250 lines (focused on API frameworks)
6
6
  """
7
7
 
@@ -20,7 +20,7 @@ class APIFrameworksGenerator:
20
20
 
21
21
  Responsibilities:
22
22
  - JWT authentication configuration
23
- - Django Revolution framework
23
+ - Django Client (OpenAPI) framework
24
24
  - Django REST Framework (DRF)
25
25
  - DRF Spectacular (OpenAPI/Swagger)
26
26
  - Auto-configuration and extensions
@@ -56,7 +56,7 @@ class APIFrameworksGenerator:
56
56
 
57
57
  # Generate settings for each API framework
58
58
  settings.update(self._generate_jwt_settings())
59
- settings.update(self._generate_revolution_settings())
59
+ settings.update(self._generate_openapi_client_settings())
60
60
  settings.update(self._apply_drf_spectacular_extensions())
61
61
 
62
62
  return settings
@@ -74,71 +74,104 @@ class APIFrameworksGenerator:
74
74
  jwt_settings = self.config.jwt.to_django_settings(self.config.secret_key)
75
75
  return jwt_settings
76
76
 
77
- def _generate_revolution_settings(self) -> Dict[str, Any]:
77
+ def _generate_openapi_client_settings(self) -> Dict[str, Any]:
78
78
  """
79
- Generate Django Revolution framework settings.
79
+ Generate Django Client (OpenAPI) framework settings.
80
80
 
81
81
  Returns:
82
- Dictionary with Revolution and auto-generated DRF configuration
82
+ Dictionary with OpenAPI configuration and auto-generated DRF configuration
83
83
  """
84
- if not hasattr(self.config, "revolution") or not self.config.revolution:
84
+ if not hasattr(self.config, "openapi_client") or not self.config.openapi_client:
85
85
  return {}
86
86
 
87
87
  settings = {}
88
88
 
89
- # Revolution configuration
90
- revolution_settings = {
91
- "DJANGO_REVOLUTION": {
92
- "api_prefix": self.config.revolution.api_prefix,
93
- "debug": getattr(self.config.revolution, "debug", self.config.debug),
94
- "auto_install_deps": getattr(self.config.revolution, "auto_install_deps", True),
95
- "zones": {
96
- zone_name: zone_config.model_dump()
97
- for zone_name, zone_config in self.config.revolution.get_zones_with_defaults().items()
98
- },
99
- }
89
+ # OpenAPI Client configuration
90
+ openapi_settings = {
91
+ "OPENAPI_CLIENT": self.config.openapi_client.model_dump(),
100
92
  }
101
- settings.update(revolution_settings)
93
+ settings.update(openapi_settings)
102
94
 
103
- # Auto-generate DRF configuration using Revolution's core_config
104
- drf_settings = self._generate_drf_from_revolution()
95
+ # Auto-generate DRF configuration from OpenAPIClientConfig
96
+ drf_settings = self._generate_drf_from_openapi()
105
97
  if drf_settings:
106
98
  settings.update(drf_settings)
107
99
 
108
100
  return settings
109
101
 
110
- def _generate_drf_from_revolution(self) -> Dict[str, Any]:
102
+ def _generate_drf_from_openapi(self) -> Dict[str, Any]:
111
103
  """
112
- Generate DRF + Spectacular settings from Revolution config.
104
+ Generate DRF + Spectacular settings from OpenAPIClientConfig.
113
105
 
114
106
  Returns:
115
107
  Dictionary with DRF and Spectacular configuration
116
108
  """
117
109
  try:
118
- from django_revolution import create_drf_spectacular_config
119
-
120
- # Extract DRF parameters from RevolutionConfig
121
- drf_kwargs = {
122
- "title": getattr(self.config.revolution, "drf_title", "API"),
123
- "description": getattr(self.config.revolution, "drf_description", "RESTful API"),
124
- "version": getattr(self.config.revolution, "drf_version", "1.0.0"),
125
- "schema_path_prefix": f"/{self.config.revolution.api_prefix}/",
126
- "enable_browsable_api": getattr(self.config.revolution, "drf_enable_browsable_api", False),
127
- "enable_throttling": getattr(self.config.revolution, "drf_enable_throttling", False),
110
+ # Extract DRF parameters from OpenAPIClientConfig
111
+ openapi_config = self.config.openapi_client
112
+
113
+ # Build REST_FRAMEWORK settings
114
+ rest_framework = {
115
+ "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
116
+ "DEFAULT_PAGINATION_CLASS": "django_cfg.middleware.pagination.DefaultPagination",
117
+ "PAGE_SIZE": 100,
118
+ "DEFAULT_RENDERER_CLASSES": [
119
+ "rest_framework.renderers.JSONRenderer",
120
+ "django_cfg.modules.django_drf_theme.renderers.TailwindBrowsableAPIRenderer",
121
+ ],
122
+ }
123
+
124
+ # Add authentication classes if not browsable
125
+ if not openapi_config.drf_enable_browsable_api:
126
+ rest_framework["DEFAULT_RENDERER_CLASSES"] = [
127
+ "rest_framework.renderers.JSONRenderer",
128
+ ]
129
+
130
+ # Add throttling if enabled
131
+ if openapi_config.drf_enable_throttling:
132
+ rest_framework["DEFAULT_THROTTLE_CLASSES"] = [
133
+ "rest_framework.throttling.AnonRateThrottle",
134
+ "rest_framework.throttling.UserRateThrottle",
135
+ ]
136
+ rest_framework["DEFAULT_THROTTLE_RATES"] = {
137
+ "anon": "100/day",
138
+ "user": "1000/day",
139
+ }
140
+
141
+ # Build SPECTACULAR_SETTINGS
142
+ spectacular_settings = {
143
+ "TITLE": openapi_config.drf_title,
144
+ "DESCRIPTION": openapi_config.drf_description,
145
+ "VERSION": openapi_config.drf_version,
146
+ "SERVE_INCLUDE_SCHEMA": openapi_config.drf_serve_include_schema,
147
+ "SCHEMA_PATH_PREFIX": openapi_config.get_drf_schema_path_prefix(),
148
+ "SWAGGER_UI_SETTINGS": {
149
+ "deepLinking": True,
150
+ "persistAuthorization": True,
151
+ "displayOperationId": True,
152
+ },
153
+ "COMPONENT_SPLIT_REQUEST": True,
154
+ "COMPONENT_SPLIT_PATCH": True,
155
+ # Auto-fix enum naming collisions
156
+ "POSTPROCESSING_HOOKS": [
157
+ "django_cfg.modules.django_client.spectacular.auto_fix_enum_names",
158
+ ],
128
159
  }
129
160
 
130
- # Create DRF + Spectacular config with Revolution's comprehensive settings
131
- drf_settings = create_drf_spectacular_config(**drf_kwargs)
161
+ drf_settings = {
162
+ "REST_FRAMEWORK": rest_framework,
163
+ "SPECTACULAR_SETTINGS": spectacular_settings,
164
+ }
132
165
 
133
- logger.info("🚀 Generated DRF + Spectacular settings using Revolution's create_drf_spectacular_config")
166
+ logger.info("🚀 Generated DRF + Spectacular settings from OpenAPIClientConfig")
167
+ logger.info(" - Pagination: django_cfg.middleware.pagination.DefaultPagination")
168
+ logger.info(" - Renderer: TailwindBrowsableAPIRenderer")
169
+ logger.info(f" - API: {openapi_config.drf_title} v{openapi_config.drf_version}")
134
170
 
135
171
  return drf_settings
136
172
 
137
- except ImportError as e:
138
- logger.warning(f"Could not import django_revolution.create_drf_spectacular_config: {e}")
139
- return {}
140
173
  except Exception as e:
141
- logger.warning(f"Could not generate DRF config from Revolution: {e}")
174
+ logger.warning(f"Could not generate DRF config from OpenAPIClientConfig: {e}")
142
175
  return {}
143
176
 
144
177
  def _apply_drf_spectacular_extensions(self) -> Dict[str, Any]:
@@ -175,7 +208,7 @@ class APIFrameworksGenerator:
175
208
  Returns:
176
209
  Dictionary with Spectacular settings
177
210
  """
178
- # Check if Spectacular settings exist (from Revolution or elsewhere)
211
+ # Check if Spectacular settings exist (from OpenAPI Client or elsewhere)
179
212
  if not hasattr(self, '_has_spectacular_settings'):
180
213
  return {}
181
214
 
@@ -205,9 +238,17 @@ class APIFrameworksGenerator:
205
238
  """
206
239
  Apply DRF settings extensions.
207
240
 
241
+ Note: This method should NOT overwrite existing REST_FRAMEWORK settings.
242
+ It should only add missing settings or extend existing ones.
243
+
208
244
  Returns:
209
245
  Dictionary with DRF settings
210
246
  """
247
+ # Don't override if OpenAPIClientConfig already created full DRF config
248
+ if hasattr(self.config, 'openapi_client') and self.config.openapi_client:
249
+ logger.info("🔧 DRF settings already configured by OpenAPIClientConfig, skipping django-cfg extensions")
250
+ return {}
251
+
211
252
  settings = {}
212
253
 
213
254
  if self.config.drf: