django-cfg 1.4.10__py3-none-any.whl → 1.4.13__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 (225) 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/views/api/currencies.py +49 -6
  8. django_cfg/apps/payments/views/api/webhooks.py +72 -7
  9. django_cfg/apps/payments/views/overview/serializers.py +34 -1
  10. django_cfg/apps/payments/views/overview/views.py +2 -1
  11. django_cfg/apps/payments/views/serializers/payments.py +6 -6
  12. django_cfg/apps/urls.py +106 -45
  13. django_cfg/core/base/config_model.py +2 -2
  14. django_cfg/core/constants.py +1 -1
  15. django_cfg/core/generation/integration_generators/__init__.py +1 -1
  16. django_cfg/core/generation/integration_generators/api.py +73 -49
  17. django_cfg/core/integration/display/startup.py +30 -22
  18. django_cfg/core/integration/url_integration.py +15 -16
  19. django_cfg/management/commands/check_endpoints.py +11 -160
  20. django_cfg/management/commands/check_settings.py +13 -348
  21. django_cfg/management/commands/clear_constance.py +13 -201
  22. django_cfg/management/commands/create_token.py +13 -321
  23. django_cfg/management/commands/generate_clients.py +23 -0
  24. django_cfg/management/commands/list_urls.py +13 -306
  25. django_cfg/management/commands/migrate_all.py +13 -126
  26. django_cfg/management/commands/migrator.py +13 -396
  27. django_cfg/management/commands/rundramatiq.py +15 -247
  28. django_cfg/management/commands/rundramatiq_simulator.py +12 -429
  29. django_cfg/management/commands/runserver_ngrok.py +15 -160
  30. django_cfg/management/commands/script.py +12 -488
  31. django_cfg/management/commands/show_config.py +12 -215
  32. django_cfg/management/commands/show_urls.py +12 -342
  33. django_cfg/management/commands/superuser.py +15 -295
  34. django_cfg/management/commands/task_clear.py +14 -217
  35. django_cfg/management/commands/task_status.py +13 -248
  36. django_cfg/management/commands/test_email.py +15 -86
  37. django_cfg/management/commands/test_telegram.py +14 -61
  38. django_cfg/management/commands/test_twilio.py +15 -105
  39. django_cfg/management/commands/tree.py +13 -383
  40. django_cfg/management/commands/validate_openapi.py +10 -0
  41. django_cfg/middleware/README.md +1 -1
  42. django_cfg/middleware/user_activity.py +3 -3
  43. django_cfg/models/__init__.py +2 -2
  44. django_cfg/models/api/drf/spectacular.py +6 -6
  45. django_cfg/models/django/__init__.py +2 -2
  46. django_cfg/models/django/openapi.py +162 -0
  47. django_cfg/modules/django_admin/management/commands/check_endpoints.py +169 -0
  48. django_cfg/modules/django_admin/management/commands/check_settings.py +355 -0
  49. django_cfg/modules/django_admin/management/commands/clear_constance.py +208 -0
  50. django_cfg/modules/django_admin/management/commands/create_token.py +328 -0
  51. django_cfg/modules/django_admin/management/commands/list_urls.py +313 -0
  52. django_cfg/modules/django_admin/management/commands/migrate_all.py +133 -0
  53. django_cfg/modules/django_admin/management/commands/migrator.py +403 -0
  54. django_cfg/modules/django_admin/management/commands/script.py +496 -0
  55. django_cfg/modules/django_admin/management/commands/show_config.py +225 -0
  56. django_cfg/modules/django_admin/management/commands/show_urls.py +361 -0
  57. django_cfg/modules/django_admin/management/commands/superuser.py +302 -0
  58. django_cfg/modules/django_admin/management/commands/tree.py +390 -0
  59. django_cfg/modules/django_client/__init__.py +20 -0
  60. django_cfg/modules/django_client/apps.py +35 -0
  61. django_cfg/modules/django_client/core/__init__.py +56 -0
  62. django_cfg/modules/django_client/core/archive/__init__.py +11 -0
  63. django_cfg/modules/django_client/core/archive/manager.py +134 -0
  64. django_cfg/modules/django_client/core/cli/__init__.py +12 -0
  65. django_cfg/modules/django_client/core/cli/main.py +235 -0
  66. django_cfg/modules/django_client/core/config/__init__.py +18 -0
  67. django_cfg/modules/django_client/core/config/config.py +208 -0
  68. django_cfg/modules/django_client/core/config/group.py +101 -0
  69. django_cfg/modules/django_client/core/config/service.py +209 -0
  70. django_cfg/modules/django_client/core/generator/__init__.py +115 -0
  71. django_cfg/modules/django_client/core/generator/base.py +838 -0
  72. django_cfg/modules/django_client/core/generator/python/__init__.py +16 -0
  73. django_cfg/modules/django_client/core/generator/python/async_client_gen.py +174 -0
  74. django_cfg/modules/django_client/core/generator/python/files_generator.py +180 -0
  75. django_cfg/modules/django_client/core/generator/python/generator.py +182 -0
  76. django_cfg/modules/django_client/core/generator/python/models_generator.py +318 -0
  77. django_cfg/modules/django_client/core/generator/python/operations_generator.py +278 -0
  78. django_cfg/modules/django_client/core/generator/python/sync_client_gen.py +102 -0
  79. django_cfg/modules/django_client/core/generator/python/templates/__init__.py.jinja +9 -0
  80. django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +153 -0
  81. django_cfg/modules/django_client/core/generator/python/templates/app_init.py.jinja +6 -0
  82. django_cfg/modules/django_client/core/generator/python/templates/client/app_client.py.jinja +18 -0
  83. django_cfg/modules/django_client/core/generator/python/templates/client/flat_client.py.jinja +38 -0
  84. django_cfg/modules/django_client/core/generator/python/templates/client/main_client.py.jinja +68 -0
  85. django_cfg/modules/django_client/core/generator/python/templates/client/main_client_file.py.jinja +14 -0
  86. django_cfg/modules/django_client/core/generator/python/templates/client/operation_method.py.jinja +9 -0
  87. django_cfg/modules/django_client/core/generator/python/templates/client/sub_client.py.jinja +18 -0
  88. django_cfg/modules/django_client/core/generator/python/templates/client/sync_main_client.py.jinja +50 -0
  89. django_cfg/modules/django_client/core/generator/python/templates/client/sync_operation_method.py.jinja +9 -0
  90. django_cfg/modules/django_client/core/generator/python/templates/client/sync_sub_client.py.jinja +18 -0
  91. django_cfg/modules/django_client/core/generator/python/templates/client_file.py.jinja +13 -0
  92. django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +52 -0
  93. django_cfg/modules/django_client/core/generator/python/templates/models/app_models.py.jinja +17 -0
  94. django_cfg/modules/django_client/core/generator/python/templates/models/enum_class.py.jinja +17 -0
  95. django_cfg/modules/django_client/core/generator/python/templates/models/enums.py.jinja +8 -0
  96. django_cfg/modules/django_client/core/generator/python/templates/models/models.py.jinja +17 -0
  97. django_cfg/modules/django_client/core/generator/python/templates/models/schema_class.py.jinja +21 -0
  98. django_cfg/modules/django_client/core/generator/python/templates/pyproject.toml.jinja +55 -0
  99. django_cfg/modules/django_client/core/generator/python/templates/utils/logger.py.jinja +255 -0
  100. django_cfg/modules/django_client/core/generator/python/templates/utils/retry.py.jinja +271 -0
  101. django_cfg/modules/django_client/core/generator/python/templates/utils/schema.py.jinja +12 -0
  102. django_cfg/modules/django_client/core/generator/typescript/__init__.py +14 -0
  103. django_cfg/modules/django_client/core/generator/typescript/client_generator.py +165 -0
  104. django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +428 -0
  105. django_cfg/modules/django_client/core/generator/typescript/files_generator.py +207 -0
  106. django_cfg/modules/django_client/core/generator/typescript/generator.py +432 -0
  107. django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +536 -0
  108. django_cfg/modules/django_client/core/generator/typescript/models_generator.py +245 -0
  109. django_cfg/modules/django_client/core/generator/typescript/operations_generator.py +298 -0
  110. django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +329 -0
  111. django_cfg/modules/django_client/core/generator/typescript/templates/api_instance.ts.jinja +131 -0
  112. django_cfg/modules/django_client/core/generator/typescript/templates/app_index.ts.jinja +2 -0
  113. django_cfg/modules/django_client/core/generator/typescript/templates/client/app_client.ts.jinja +18 -0
  114. django_cfg/modules/django_client/core/generator/typescript/templates/client/client.ts.jinja +403 -0
  115. django_cfg/modules/django_client/core/generator/typescript/templates/client/flat_client.ts.jinja +109 -0
  116. django_cfg/modules/django_client/core/generator/typescript/templates/client/main_client_file.ts.jinja +10 -0
  117. django_cfg/modules/django_client/core/generator/typescript/templates/client/operation.ts.jinja +61 -0
  118. django_cfg/modules/django_client/core/generator/typescript/templates/client/sub_client.ts.jinja +15 -0
  119. django_cfg/modules/django_client/core/generator/typescript/templates/client_file.ts.jinja +9 -0
  120. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +45 -0
  121. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/index.ts.jinja +30 -0
  122. django_cfg/modules/django_client/core/generator/typescript/templates/index.ts.jinja +5 -0
  123. django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +268 -0
  124. django_cfg/modules/django_client/core/generator/typescript/templates/models/app_models.ts.jinja +8 -0
  125. django_cfg/modules/django_client/core/generator/typescript/templates/models/enums.ts.jinja +4 -0
  126. django_cfg/modules/django_client/core/generator/typescript/templates/models/models.ts.jinja +8 -0
  127. django_cfg/modules/django_client/core/generator/typescript/templates/package.json.jinja +52 -0
  128. django_cfg/modules/django_client/core/generator/typescript/templates/schemas/index.ts.jinja +21 -0
  129. django_cfg/modules/django_client/core/generator/typescript/templates/schemas/schema.ts.jinja +24 -0
  130. django_cfg/modules/django_client/core/generator/typescript/templates/tsconfig.json.jinja +20 -0
  131. django_cfg/modules/django_client/core/generator/typescript/templates/utils/errors.ts.jinja +116 -0
  132. django_cfg/modules/django_client/core/generator/typescript/templates/utils/http.ts.jinja +98 -0
  133. django_cfg/modules/django_client/core/generator/typescript/templates/utils/logger.ts.jinja +259 -0
  134. django_cfg/modules/django_client/core/generator/typescript/templates/utils/retry.ts.jinja +175 -0
  135. django_cfg/modules/django_client/core/generator/typescript/templates/utils/schema.ts.jinja +7 -0
  136. django_cfg/modules/django_client/core/generator/typescript/templates/utils/storage.ts.jinja +158 -0
  137. django_cfg/modules/django_client/core/groups/__init__.py +13 -0
  138. django_cfg/modules/django_client/core/groups/detector.py +178 -0
  139. django_cfg/modules/django_client/core/groups/manager.py +314 -0
  140. django_cfg/modules/django_client/core/ir/__init__.py +57 -0
  141. django_cfg/modules/django_client/core/ir/context.py +387 -0
  142. django_cfg/modules/django_client/core/ir/operation.py +518 -0
  143. django_cfg/modules/django_client/core/ir/schema.py +353 -0
  144. django_cfg/modules/django_client/core/parser/__init__.py +74 -0
  145. django_cfg/modules/django_client/core/parser/base.py +648 -0
  146. django_cfg/modules/django_client/core/parser/models/__init__.py +74 -0
  147. django_cfg/modules/django_client/core/parser/models/base.py +212 -0
  148. django_cfg/modules/django_client/core/parser/models/components.py +160 -0
  149. django_cfg/modules/django_client/core/parser/models/openapi.py +203 -0
  150. django_cfg/modules/django_client/core/parser/models/operation.py +207 -0
  151. django_cfg/modules/django_client/core/parser/models/schema.py +266 -0
  152. django_cfg/modules/django_client/core/parser/openapi30.py +56 -0
  153. django_cfg/modules/django_client/core/parser/openapi31.py +64 -0
  154. django_cfg/modules/django_client/core/validation/__init__.py +22 -0
  155. django_cfg/modules/django_client/core/validation/checker.py +134 -0
  156. django_cfg/modules/django_client/core/validation/fixer.py +216 -0
  157. django_cfg/modules/django_client/core/validation/reporter.py +480 -0
  158. django_cfg/modules/django_client/core/validation/rules/__init__.py +11 -0
  159. django_cfg/modules/django_client/core/validation/rules/base.py +96 -0
  160. django_cfg/modules/django_client/core/validation/rules/type_hints.py +288 -0
  161. django_cfg/modules/django_client/core/validation/safety.py +266 -0
  162. django_cfg/modules/django_client/management/__init__.py +3 -0
  163. django_cfg/modules/django_client/management/commands/__init__.py +3 -0
  164. django_cfg/modules/django_client/management/commands/generate_client.py +427 -0
  165. django_cfg/modules/django_client/management/commands/validate_openapi.py +343 -0
  166. django_cfg/modules/django_client/pytest.ini +30 -0
  167. django_cfg/modules/django_client/spectacular/__init__.py +10 -0
  168. django_cfg/modules/django_client/spectacular/async_detection.py +187 -0
  169. django_cfg/modules/django_client/spectacular/enum_naming.py +192 -0
  170. django_cfg/modules/django_client/urls.py +72 -0
  171. django_cfg/{dashboard → modules/django_dashboard}/DEBUG_README.md +2 -2
  172. django_cfg/{dashboard → modules/django_dashboard}/REFACTORING_SUMMARY.md +1 -1
  173. django_cfg/modules/django_dashboard/management/__init__.py +0 -0
  174. django_cfg/modules/django_dashboard/management/commands/__init__.py +0 -0
  175. django_cfg/{dashboard → modules/django_dashboard}/management/commands/debug_dashboard.py +5 -5
  176. django_cfg/modules/django_dashboard/sections/documentation.py +391 -0
  177. django_cfg/modules/django_email/management/__init__.py +0 -0
  178. django_cfg/modules/django_email/management/commands/__init__.py +0 -0
  179. django_cfg/modules/django_email/management/commands/test_email.py +93 -0
  180. django_cfg/modules/django_logging/LOGGING_GUIDE.md +1 -1
  181. django_cfg/modules/django_logging/django_logger.py +6 -6
  182. django_cfg/modules/django_ngrok/management/__init__.py +0 -0
  183. django_cfg/modules/django_ngrok/management/commands/__init__.py +0 -0
  184. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +167 -0
  185. django_cfg/modules/django_tasks/management/__init__.py +0 -0
  186. django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
  187. django_cfg/modules/django_tasks/management/commands/rundramatiq.py +254 -0
  188. django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +437 -0
  189. django_cfg/modules/django_tasks/management/commands/task_clear.py +226 -0
  190. django_cfg/modules/django_tasks/management/commands/task_status.py +257 -0
  191. django_cfg/modules/django_telegram/management/__init__.py +0 -0
  192. django_cfg/modules/django_telegram/management/commands/__init__.py +0 -0
  193. django_cfg/modules/django_telegram/management/commands/test_telegram.py +68 -0
  194. django_cfg/modules/django_twilio/management/__init__.py +0 -0
  195. django_cfg/modules/django_twilio/management/commands/__init__.py +0 -0
  196. django_cfg/modules/django_twilio/management/commands/test_twilio.py +112 -0
  197. django_cfg/modules/django_unfold/callbacks/main.py +21 -10
  198. django_cfg/modules/django_unfold/callbacks/revolution.py +41 -36
  199. django_cfg/pyproject.toml +2 -6
  200. django_cfg/registry/third_party.py +5 -7
  201. django_cfg/routing/callbacks.py +1 -1
  202. django_cfg/static/admin/css/prose-unfold.css +666 -0
  203. django_cfg/templates/admin/index.html +8 -0
  204. django_cfg/templates/admin/index_new.html +13 -0
  205. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +15 -3
  206. django_cfg/templates/admin/sections/documentation_section.html +172 -0
  207. django_cfg/templates/admin/snippets/tabs/documentation_tab.html +231 -0
  208. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/METADATA +2 -2
  209. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/RECORD +224 -74
  210. django_cfg/management/commands/generate.py +0 -107
  211. /django_cfg/models/django/{revolution.py → revolution_legacy.py} +0 -0
  212. /django_cfg/{dashboard → modules/django_admin}/management/__init__.py +0 -0
  213. /django_cfg/{dashboard → modules/django_admin}/management/commands/__init__.py +0 -0
  214. /django_cfg/{dashboard → modules/django_dashboard}/__init__.py +0 -0
  215. /django_cfg/{dashboard → modules/django_dashboard}/components.py +0 -0
  216. /django_cfg/{dashboard → modules/django_dashboard}/debug.py +0 -0
  217. /django_cfg/{dashboard → modules/django_dashboard}/sections/__init__.py +0 -0
  218. /django_cfg/{dashboard → modules/django_dashboard}/sections/base.py +0 -0
  219. /django_cfg/{dashboard → modules/django_dashboard}/sections/commands.py +0 -0
  220. /django_cfg/{dashboard → modules/django_dashboard}/sections/overview.py +0 -0
  221. /django_cfg/{dashboard → modules/django_dashboard}/sections/stats.py +0 -0
  222. /django_cfg/{dashboard → modules/django_dashboard}/sections/system.py +0 -0
  223. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/WHEEL +0 -0
  224. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/entry_points.txt +0 -0
  225. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,257 @@
1
+ """
2
+ Django management command for checking task system status.
3
+
4
+ This command provides comprehensive status information about the
5
+ Dramatiq task system, including queue statistics, worker status,
6
+ and configuration details.
7
+ """
8
+
9
+ from django.core.management.base import BaseCommand, CommandError
10
+ from django.conf import settings
11
+ from typing import Any, Dict, List
12
+ import json
13
+ import logging
14
+ from django_cfg.modules.django_logging import get_logger
15
+
16
+ logger = get_logger('task_status')
17
+
18
+
19
+ class Command(BaseCommand):
20
+ """
21
+ Display comprehensive task system status.
22
+
23
+ Shows information about:
24
+ - Task system configuration
25
+ - Redis connection status
26
+ - Queue statistics
27
+ - Worker status
28
+ - Discovered task modules
29
+ """
30
+
31
+ # Web execution metadata
32
+ web_executable = True
33
+ requires_input = False
34
+ is_destructive = False
35
+
36
+ help = "Display task system status and statistics"
37
+
38
+ def add_arguments(self, parser):
39
+ """Add command line arguments."""
40
+ parser.add_argument(
41
+ "--format",
42
+ choices=["text", "json"],
43
+ default="text",
44
+ help="Output format (default: text)",
45
+ )
46
+ parser.add_argument(
47
+ "--verbose",
48
+ action="store_true",
49
+ help="Show detailed information",
50
+ )
51
+
52
+ def handle(self, *args, **options):
53
+ """Handle the command execution."""
54
+ logger.info("Starting task_status command")
55
+ try:
56
+ # Import here to avoid issues if dramatiq is not installed
57
+ from django_cfg.modules.django_tasks import get_task_service
58
+
59
+ # Get task service
60
+ task_service = get_task_service()
61
+
62
+ # Get comprehensive health status
63
+ status = task_service.get_health_status()
64
+
65
+ # Format and display output
66
+ if options["format"] == "json":
67
+ self._output_json(status)
68
+ else:
69
+ self._output_text(status, options["verbose"])
70
+
71
+ except ImportError:
72
+ raise CommandError(
73
+ "Dramatiq dependencies not installed. "
74
+ "Install with: pip install django-cfg[tasks]"
75
+ )
76
+ except Exception as e:
77
+ logger.exception("Failed to get task status")
78
+ raise CommandError(f"Failed to get status: {e}")
79
+
80
+ def _output_json(self, status: Dict[str, Any]):
81
+ """Output status in JSON format."""
82
+ self.stdout.write(json.dumps(status, indent=2, default=str))
83
+
84
+ def _output_text(self, status: Dict[str, Any], verbose: bool):
85
+ """Output status in human-readable text format."""
86
+ # Header
87
+ self.stdout.write(
88
+ self.style.SUCCESS("=== Django-CFG Task System Status ===")
89
+ )
90
+ self.stdout.write()
91
+
92
+ # Basic status
93
+ enabled = status.get("enabled", False)
94
+ if enabled:
95
+ self.stdout.write(
96
+ self.style.SUCCESS("✓ Task system is ENABLED")
97
+ )
98
+ else:
99
+ self.stdout.write(
100
+ self.style.ERROR("✗ Task system is DISABLED")
101
+ )
102
+ return
103
+
104
+ # Redis connection
105
+ redis_ok = status.get("redis_connection", False)
106
+ if redis_ok:
107
+ self.stdout.write(
108
+ self.style.SUCCESS("✓ Redis connection is OK")
109
+ )
110
+ else:
111
+ self.stdout.write(
112
+ self.style.ERROR("✗ Redis connection FAILED")
113
+ )
114
+
115
+ # Configuration validation
116
+ config_valid = status.get("configuration_valid", False)
117
+ if config_valid:
118
+ self.stdout.write(
119
+ self.style.SUCCESS("✓ Configuration is VALID")
120
+ )
121
+ else:
122
+ self.stdout.write(
123
+ self.style.ERROR("✗ Configuration is INVALID")
124
+ )
125
+
126
+ self.stdout.write()
127
+
128
+ # Configuration details (if verbose)
129
+ if verbose:
130
+ self._show_configuration_details()
131
+
132
+ # Queue statistics
133
+ queues = status.get("queues", [])
134
+ if queues:
135
+ self.stdout.write(
136
+ self.style.SUCCESS("=== Queue Statistics ===")
137
+ )
138
+ for queue in queues:
139
+ name = queue.get("name", "unknown")
140
+ pending = queue.get("pending", 0)
141
+ running = queue.get("running", 0)
142
+ completed = queue.get("completed", 0)
143
+ failed = queue.get("failed", 0)
144
+
145
+ self.stdout.write(f"Queue: {name}")
146
+ self.stdout.write(f" Pending: {pending}")
147
+ self.stdout.write(f" Running: {running}")
148
+ self.stdout.write(f" Completed: {completed}")
149
+ self.stdout.write(f" Failed: {failed}")
150
+ self.stdout.write()
151
+
152
+ # Worker status
153
+ workers = status.get("workers", [])
154
+ if workers:
155
+ self.stdout.write(
156
+ self.style.SUCCESS("=== Worker Status ===")
157
+ )
158
+ for worker in workers:
159
+ worker_id = worker.get("id", "unknown")
160
+ worker_status = worker.get("status", "unknown")
161
+ current_task = worker.get("current_task")
162
+ processed = worker.get("processed_tasks", 0)
163
+
164
+ status_style = (
165
+ self.style.SUCCESS if worker_status == "active"
166
+ else self.style.WARNING if worker_status == "idle"
167
+ else self.style.ERROR
168
+ )
169
+
170
+ self.stdout.write(f"Worker: {worker_id}")
171
+ self.stdout.write(f" Status: {status_style(worker_status)}")
172
+ if current_task:
173
+ self.stdout.write(f" Current Task: {current_task}")
174
+ self.stdout.write(f" Processed: {processed}")
175
+ self.stdout.write()
176
+ else:
177
+ self.stdout.write(
178
+ self.style.WARNING("No active workers found")
179
+ )
180
+
181
+ # Discovered modules
182
+ modules = status.get("discovered_modules", [])
183
+ if modules:
184
+ self.stdout.write(
185
+ self.style.SUCCESS("=== Discovered Task Modules ===")
186
+ )
187
+ for module in modules:
188
+ self.stdout.write(f" - {module}")
189
+ self.stdout.write()
190
+ else:
191
+ self.stdout.write(
192
+ self.style.WARNING("No task modules discovered")
193
+ )
194
+
195
+ # Error information
196
+ if "error" in status:
197
+ self.stdout.write(
198
+ self.style.ERROR(f"Error: {status['error']}")
199
+ )
200
+
201
+ def _show_configuration_details(self):
202
+ """Show detailed configuration information."""
203
+ try:
204
+ from django_cfg.modules.django_tasks import get_task_service
205
+
206
+ task_service = get_task_service()
207
+ config = task_service.config
208
+
209
+ if not config:
210
+ self.stdout.write(
211
+ self.style.WARNING("Configuration not available")
212
+ )
213
+ return
214
+
215
+ self.stdout.write(
216
+ self.style.SUCCESS("=== Configuration Details ===")
217
+ )
218
+
219
+ # Basic settings
220
+ self.stdout.write(f"Backend: {config.backend}")
221
+ self.stdout.write(f"Enabled: {config.enabled}")
222
+ self.stdout.write(f"Auto-discover: {config.auto_discover_tasks}")
223
+ self.stdout.write()
224
+
225
+ # Dramatiq settings
226
+ dramatiq = config.dramatiq
227
+ self.stdout.write("Dramatiq Configuration:")
228
+ self.stdout.write(f" Redis DB: {dramatiq.redis_db}")
229
+ self.stdout.write(f" Max Retries: {dramatiq.max_retries}")
230
+ self.stdout.write(f" Processes: {dramatiq.processes}")
231
+ self.stdout.write(f" Threads: {dramatiq.threads}")
232
+ self.stdout.write(f" Queues: {', '.join(dramatiq.queues)}")
233
+ self.stdout.write(f" Time Limit: {dramatiq.time_limit_seconds}s")
234
+ self.stdout.write(f" Max Age: {dramatiq.max_age_seconds}s")
235
+ self.stdout.write()
236
+
237
+ # Worker settings
238
+ worker = config.worker
239
+ self.stdout.write("Worker Configuration:")
240
+ self.stdout.write(f" Log Level: {worker.log_level}")
241
+ self.stdout.write(f" Shutdown Timeout: {worker.shutdown_timeout}s")
242
+ self.stdout.write(f" Health Check: {worker.health_check_enabled}")
243
+ if worker.max_memory_mb:
244
+ self.stdout.write(f" Memory Limit: {worker.max_memory_mb}MB")
245
+ self.stdout.write()
246
+
247
+ # Middleware
248
+ if dramatiq.middleware:
249
+ self.stdout.write("Middleware Stack:")
250
+ for middleware in dramatiq.middleware:
251
+ self.stdout.write(f" - {middleware}")
252
+ self.stdout.write()
253
+
254
+ except Exception as e:
255
+ self.stdout.write(
256
+ self.style.ERROR(f"Failed to show configuration: {e}")
257
+ )
@@ -0,0 +1,68 @@
1
+ """
2
+ Test Telegram Command
3
+
4
+ Tests Telegram notification functionality using django_cfg configuration.
5
+ """
6
+
7
+ from django.core.management.base import BaseCommand
8
+ from django_cfg.modules.django_logging import get_logger
9
+
10
+
11
+
12
+ logger = get_logger('test_telegram')
13
+
14
+ class Command(BaseCommand):
15
+ """Command to test Telegram functionality."""
16
+
17
+ # Web execution metadata
18
+ web_executable = True
19
+ requires_input = False
20
+ is_destructive = False
21
+
22
+ help = "Test Telegram notification functionality"
23
+
24
+ def add_arguments(self, parser):
25
+ parser.add_argument(
26
+ "--message",
27
+ type=str,
28
+ help="Message to send",
29
+ default="Test message from UnrealON"
30
+ )
31
+
32
+ def handle(self, *args, **options):
33
+ logger.info("Starting test_telegram command")
34
+ message = options["message"]
35
+
36
+ self.stdout.write("🚀 Testing Telegram notification service")
37
+
38
+ # Get telegram service from django-cfg (автоматически настроен!)
39
+ try:
40
+ from django_cfg.modules.django_telegram import DjangoTelegram
41
+ telegram_service = DjangoTelegram()
42
+
43
+ self.stdout.write("\n📱 Sending test messages...")
44
+
45
+ # Send info message (модуль сам знает настройки!)
46
+ self.stdout.write("\n1️⃣ Sending info message...")
47
+ telegram_service.send_info(
48
+ message,
49
+ {
50
+ "Type": "System Test",
51
+ "Status": "Running",
52
+ "Environment": "Development"
53
+ }
54
+ )
55
+ self.stdout.write(self.style.SUCCESS("✅ Info message sent!"))
56
+
57
+ # Send success message
58
+ self.stdout.write("\n2️⃣ Sending success message...")
59
+ telegram_service.send_success(
60
+ "Test completed successfully!",
61
+ {"Message": message}
62
+ )
63
+ self.stdout.write(self.style.SUCCESS("✅ Success message sent!"))
64
+
65
+ self.stdout.write(self.style.SUCCESS("\n✅ All test messages sent successfully!"))
66
+
67
+ except Exception as e:
68
+ self.stdout.write(self.style.ERROR(f"\n❌ Failed to send Telegram messages: {e}"))
@@ -0,0 +1,112 @@
1
+ """
2
+ Test Twilio Command
3
+
4
+ Tests Twilio messaging functionality using django_cfg configuration.
5
+ """
6
+
7
+ from django.core.management.base import BaseCommand
8
+ from django_cfg.modules.django_logging import get_logger
9
+
10
+
11
+
12
+ logger = get_logger('test_twilio')
13
+
14
+ class Command(BaseCommand):
15
+ """Command to test Twilio functionality."""
16
+
17
+ # Web execution metadata
18
+ web_executable = True
19
+ requires_input = False
20
+ is_destructive = False
21
+
22
+ help = "Test Twilio messaging functionality"
23
+
24
+ def add_arguments(self, parser):
25
+ parser.add_argument(
26
+ "--to",
27
+ type=str,
28
+ help="Phone number to send test message to",
29
+ default="+6281339646301"
30
+ )
31
+ parser.add_argument(
32
+ "--message",
33
+ type=str,
34
+ help="Message to send",
35
+ default="Test message from Django CFG Twilio"
36
+ )
37
+ parser.add_argument(
38
+ "--whatsapp",
39
+ action="store_true",
40
+ help="Send WhatsApp message (default: SMS)"
41
+ )
42
+ parser.add_argument(
43
+ "--content-sid",
44
+ type=str,
45
+ help="Content template SID for WhatsApp (optional)"
46
+ )
47
+
48
+ def handle(self, *args, **options):
49
+ logger.info("Starting test_twilio command")
50
+ to_number = options["to"]
51
+ message = options["message"]
52
+ is_whatsapp = options["whatsapp"]
53
+ content_sid = options.get("content_sid")
54
+
55
+ self.stdout.write("🚀 Testing Twilio messaging service")
56
+
57
+ try:
58
+ from django_cfg.modules.django_twilio import SimpleTwilioService
59
+ twilio_service = SimpleTwilioService()
60
+
61
+ if is_whatsapp:
62
+ self.stdout.write(f"\n📱 Sending WhatsApp message to {to_number}...")
63
+
64
+ if content_sid:
65
+ # Send with template
66
+ result = twilio_service.send_whatsapp_message(
67
+ to=to_number,
68
+ body="", # Not used with templates
69
+ content_sid=content_sid,
70
+ content_variables={"1": "12/1", "2": "3pm"}
71
+ )
72
+ self.stdout.write(self.style.SUCCESS("✅ WhatsApp template message sent!"))
73
+ else:
74
+ # Send regular message
75
+ result = twilio_service.send_whatsapp_message(
76
+ to=to_number,
77
+ body=message
78
+ )
79
+ self.stdout.write(self.style.SUCCESS("✅ WhatsApp message sent!"))
80
+ else:
81
+ self.stdout.write(f"\n📱 Sending SMS to {to_number}...")
82
+ result = twilio_service.send_sms_message(
83
+ to=to_number,
84
+ body=message
85
+ )
86
+ self.stdout.write(self.style.SUCCESS("✅ SMS message sent!"))
87
+
88
+ # Show result details
89
+ self.stdout.write(f"\n📊 Message Details:")
90
+ self.stdout.write(f" SID: {result['sid']}")
91
+ self.stdout.write(f" Status: {result['status']}")
92
+ self.stdout.write(f" To: {result['to']}")
93
+ self.stdout.write(f" From: {result['from']}")
94
+ self.stdout.write(f" Created: {result['date_created']}")
95
+
96
+ if result.get('price'):
97
+ self.stdout.write(f" Price: {result['price']} {result['price_unit']}")
98
+
99
+ self.stdout.write(self.style.SUCCESS("\n✅ Twilio test completed successfully!"))
100
+
101
+ except ImportError as e:
102
+ self.stdout.write(self.style.ERROR(f"\n❌ Twilio dependencies not installed: {e}"))
103
+ self.stdout.write("💡 Install with: pip install twilio")
104
+
105
+ except Exception as e:
106
+ self.stdout.write(self.style.ERROR(f"\n❌ Failed to send message: {e}"))
107
+ self.stdout.write("\n💡 Troubleshooting:")
108
+ self.stdout.write(" 1. Check your Twilio credentials in config.dev.yaml")
109
+ self.stdout.write(" 2. Ensure account_sid starts with 'AC' and is 34 characters")
110
+ self.stdout.write(" 3. Verify auth_token is 32 characters")
111
+ self.stdout.write(" 4. For WhatsApp: use sandbox number +14155238886")
112
+ self.stdout.write(" 5. For SMS: ensure your number is verified")
@@ -19,16 +19,17 @@ from .system import SystemCallbacks
19
19
  from .actions import ActionsCallbacks
20
20
  from .charts import ChartsCallbacks
21
21
  from .commands import CommandsCallbacks
22
- from .revolution import RevolutionCallbacks
22
+ from .revolution import OpenAPIClientCallbacks
23
23
  from .users import UsersCallbacks
24
24
  from .base import get_user_admin_urls
25
25
 
26
26
  # Import new dashboard sections
27
- from django_cfg.dashboard.sections.overview import OverviewSection
28
- from django_cfg.dashboard.sections.stats import StatsSection
29
- from django_cfg.dashboard.sections.system import SystemSection
30
- from django_cfg.dashboard.sections.commands import CommandsSection
31
- from django_cfg.dashboard.debug import save_section_render
27
+ from django_cfg.modules.django_dashboard.sections.overview import OverviewSection
28
+ from django_cfg.modules.django_dashboard.sections.stats import StatsSection
29
+ from django_cfg.modules.django_dashboard.sections.system import SystemSection
30
+ from django_cfg.modules.django_dashboard.sections.commands import CommandsSection
31
+ from django_cfg.modules.django_dashboard.sections.documentation import DocumentationSection
32
+ from django_cfg.modules.django_dashboard.debug import save_section_render
32
33
 
33
34
  logger = logging.getLogger(__name__)
34
35
 
@@ -40,7 +41,7 @@ class UnfoldCallbacks(
40
41
  ActionsCallbacks,
41
42
  ChartsCallbacks,
42
43
  CommandsCallbacks,
43
- RevolutionCallbacks,
44
+ OpenAPIClientCallbacks,
44
45
  UsersCallbacks
45
46
  ):
46
47
  """
@@ -145,6 +146,15 @@ class UnfoldCallbacks(
145
146
  logger.error(f"Failed to render commands section: {e}", exc_info=True)
146
147
  commands_section = None
147
148
 
149
+ try:
150
+ documentation_section = DocumentationSection(request).render()
151
+ # Debug: save render (only in debug mode)
152
+ if config and config.debug:
153
+ save_section_render('documentation', documentation_section)
154
+ except Exception as e:
155
+ logger.error(f"Failed to render documentation section: {e}", exc_info=True)
156
+ documentation_section = None
157
+
148
158
  # Combine all stat cards (data already loaded above)
149
159
  all_stats = user_stats + support_stats
150
160
 
@@ -165,6 +175,7 @@ class UnfoldCallbacks(
165
175
  "stats_section": stats_section,
166
176
  "system_section": system_section,
167
177
  "commands_section": commands_section,
178
+ "documentation_section": documentation_section,
168
179
 
169
180
  # Statistics cards
170
181
  "cards": cards_data,
@@ -198,8 +209,8 @@ class UnfoldCallbacks(
198
209
  for action in dashboard_data.quick_actions
199
210
  if action.category == "system"
200
211
  ],
201
-
202
- # Revolution zones
212
+
213
+ # OpenAPI Client groups
203
214
  "zones_table": {
204
215
  "headers": [
205
216
  {"label": "Zone"},
@@ -209,7 +220,7 @@ class UnfoldCallbacks(
209
220
  {"label": "Status"},
210
221
  {"label": "Actions"},
211
222
  ],
212
- "rows": self.get_revolution_zones_data()[0],
223
+ "rows": OpenAPIClientCallbacks().get_openapi_groups_data()[0],
213
224
  },
214
225
 
215
226
  # Recent users
@@ -1,5 +1,5 @@
1
1
  """
2
- Django Revolution integration callbacks.
2
+ Django Client (OpenAPI) integration callbacks.
3
3
  """
4
4
 
5
5
  import logging
@@ -10,67 +10,72 @@ from django.conf import settings
10
10
  logger = logging.getLogger(__name__)
11
11
 
12
12
 
13
- class RevolutionCallbacks:
14
- """Django Revolution integration callbacks."""
15
-
16
- def get_revolution_zones_data(self) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]:
17
- """Get Django Revolution zones data."""
13
+ class OpenAPIClientCallbacks:
14
+ """Django Client (OpenAPI) integration callbacks."""
15
+
16
+ def get_openapi_groups_data(self) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]:
17
+ """Get Django Client (OpenAPI) groups data."""
18
18
  try:
19
- # Try to get revolution config from Django settings
20
- revolution_config = getattr(settings, "DJANGO_REVOLUTION", {})
21
- zones = revolution_config.get("zones", {})
22
- api_prefix = revolution_config.get("api_prefix", "apix")
19
+ # Try to get openapi_client config from Django settings
20
+ openapi_config = getattr(settings, "OPENAPI_CLIENT", {})
21
+ if isinstance(openapi_config, dict):
22
+ groups_list = openapi_config.get("groups", [])
23
+ api_prefix = openapi_config.get("api_prefix", "api")
24
+ else:
25
+ # Handle Pydantic model instance
26
+ groups_list = getattr(openapi_config, "groups", [])
27
+ api_prefix = getattr(openapi_config, "api_prefix", "api")
23
28
 
24
- zones_data = []
29
+ groups_data = []
25
30
  total_apps = 0
26
31
  total_endpoints = 0
27
32
 
28
- for zone_name, zone_config in zones.items():
33
+ for group in groups_list:
29
34
  # Handle both dict and object access
30
- if isinstance(zone_config, dict):
31
- title = zone_config.get("title", zone_name.title())
32
- description = zone_config.get("description", f"{zone_name} zone")
33
- apps = zone_config.get("apps", [])
34
- public = zone_config.get("public", False)
35
- auth_required = zone_config.get("auth_required", True)
35
+ if isinstance(group, dict):
36
+ group_name = group.get("name", "unknown")
37
+ title = group.get("title", group_name.title())
38
+ description = group.get("description", f"{group_name} group")
39
+ apps = group.get("apps", [])
36
40
  else:
37
- # Handle object access (for ZoneConfig instances)
38
- title = getattr(zone_config, "title", zone_name.title())
39
- description = getattr(zone_config, "description", f"{zone_name} zone")
40
- apps = getattr(zone_config, "apps", [])
41
- public = getattr(zone_config, "public", False)
42
- auth_required = getattr(zone_config, "auth_required", True)
41
+ # Handle object access (for OpenAPIGroupConfig instances)
42
+ group_name = getattr(group, "name", "unknown")
43
+ title = getattr(group, "title", group_name.title())
44
+ description = getattr(group, "description", f"{group_name} group")
45
+ apps = getattr(group, "apps", [])
43
46
 
44
47
  # Count actual endpoints by checking URL patterns (simplified estimate)
45
48
  endpoint_count = len(apps) * 3 # Conservative estimate
46
49
 
47
- zones_data.append({
48
- "name": zone_name,
50
+ groups_data.append({
51
+ "name": group_name,
49
52
  "title": title,
50
53
  "description": description,
51
54
  "app_count": len(apps),
52
55
  "endpoint_count": endpoint_count,
53
56
  "status": "active",
54
- "public": public,
55
- "auth_required": auth_required,
56
- "schema_url": f"/schema/{zone_name}/schema/",
57
- "swagger_url": f"/schema/{zone_name}/schema/swagger/",
58
- "redoc_url": f"/schema/{zone_name}/redoc/",
59
- "api_url": f"/{api_prefix}/{zone_name}/",
57
+ "schema_url": f"/schema/{group_name}/",
58
+ "swagger_url": f"/schema/{group_name}/swagger/",
59
+ "redoc_url": f"/schema/{group_name}/redoc/",
60
+ "api_url": f"/{api_prefix}/{group_name}/",
60
61
  })
61
62
 
62
63
  total_apps += len(apps)
63
64
  total_endpoints += endpoint_count
64
65
 
65
- return zones_data, {
66
+ return groups_data, {
66
67
  "total_apps": total_apps,
67
68
  "total_endpoints": total_endpoints,
68
- "total_zones": len(zones),
69
+ "total_groups": len(groups_list),
69
70
  }
70
71
  except Exception as e:
71
- logger.error(f"Error getting revolution zones: {e}")
72
+ logger.error(f"Error getting OpenAPI groups: {e}")
72
73
  return [], {
73
74
  "total_apps": 0,
74
75
  "total_endpoints": 0,
75
- "total_zones": 0,
76
+ "total_groups": 0,
76
77
  }
78
+
79
+
80
+ # Keep backward compatibility alias
81
+ RevolutionCallbacks = OpenAPIClientCallbacks