django-cfg 1.3.7__py3-none-any.whl → 1.3.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 (246) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/__init__.py +24 -8
  3. django_cfg/apps/accounts/admin/activity_admin.py +146 -0
  4. django_cfg/apps/accounts/admin/filters.py +98 -22
  5. django_cfg/apps/accounts/admin/group_admin.py +86 -0
  6. django_cfg/apps/accounts/admin/inlines.py +42 -13
  7. django_cfg/apps/accounts/admin/otp_admin.py +115 -0
  8. django_cfg/apps/accounts/admin/registration_admin.py +173 -0
  9. django_cfg/apps/accounts/admin/resources.py +123 -19
  10. django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
  11. django_cfg/apps/accounts/admin/user_admin.py +362 -0
  12. django_cfg/apps/agents/admin/__init__.py +17 -4
  13. django_cfg/apps/agents/admin/execution_admin.py +204 -183
  14. django_cfg/apps/agents/admin/registry_admin.py +230 -255
  15. django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
  16. django_cfg/apps/agents/core/__init__.py +1 -1
  17. django_cfg/apps/agents/core/django_agent.py +221 -0
  18. django_cfg/apps/agents/core/exceptions.py +14 -0
  19. django_cfg/apps/agents/core/orchestrator.py +18 -3
  20. django_cfg/apps/knowbase/admin/__init__.py +1 -1
  21. django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
  22. django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
  23. django_cfg/apps/knowbase/admin/document_admin.py +269 -262
  24. django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
  25. django_cfg/apps/knowbase/config/settings.py +21 -4
  26. django_cfg/apps/knowbase/views/chat_views.py +3 -0
  27. django_cfg/apps/leads/admin/__init__.py +3 -1
  28. django_cfg/apps/leads/admin/leads_admin.py +235 -35
  29. django_cfg/apps/maintenance/admin/__init__.py +2 -2
  30. django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
  31. django_cfg/apps/maintenance/admin/log_admin.py +143 -61
  32. django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
  33. django_cfg/apps/maintenance/admin/site_admin.py +213 -352
  34. django_cfg/apps/newsletter/admin/__init__.py +29 -2
  35. django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
  36. django_cfg/apps/payments/admin/__init__.py +18 -27
  37. django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
  38. django_cfg/apps/payments/admin/balance_admin.py +166 -632
  39. django_cfg/apps/payments/admin/currencies_admin.py +235 -607
  40. django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
  41. django_cfg/apps/payments/admin/filters.py +83 -3
  42. django_cfg/apps/payments/admin/networks_admin.py +269 -0
  43. django_cfg/apps/payments/admin/payments_admin.py +183 -460
  44. django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
  45. django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
  46. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
  47. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
  48. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
  49. django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
  50. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
  51. django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
  52. django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
  53. django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
  54. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
  55. django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
  56. django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
  57. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
  58. django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
  59. django_cfg/apps/payments/config/__init__.py +14 -15
  60. django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
  61. django_cfg/apps/payments/config/helpers.py +8 -13
  62. django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
  63. django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
  64. django_cfg/apps/payments/middleware/api_access.py +32 -6
  65. django_cfg/apps/payments/migrations/0001_initial.py +33 -46
  66. django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
  67. django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
  68. django_cfg/apps/payments/models/balance.py +12 -0
  69. django_cfg/apps/payments/models/currencies.py +106 -32
  70. django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
  71. django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
  72. django_cfg/apps/payments/models/payments.py +94 -0
  73. django_cfg/apps/payments/services/core/base.py +4 -4
  74. django_cfg/apps/payments/services/core/currency_service.py +35 -28
  75. django_cfg/apps/payments/services/core/payment_service.py +266 -39
  76. django_cfg/apps/payments/services/providers/__init__.py +3 -0
  77. django_cfg/apps/payments/services/providers/base.py +303 -41
  78. django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
  79. django_cfg/apps/payments/services/providers/models/base.py +145 -0
  80. django_cfg/apps/payments/services/providers/models/providers.py +87 -0
  81. django_cfg/apps/payments/services/providers/models/universal.py +48 -0
  82. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
  83. django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
  84. django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
  85. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
  86. django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
  87. django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
  88. django_cfg/apps/payments/services/providers/registry.py +9 -37
  89. django_cfg/apps/payments/services/providers/sync_service.py +277 -0
  90. django_cfg/apps/payments/services/types/requests.py +19 -7
  91. django_cfg/apps/payments/signals/payment_signals.py +31 -2
  92. django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
  93. django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
  94. django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
  95. django_cfg/apps/payments/tasks/__init__.py +39 -0
  96. django_cfg/apps/payments/tasks/types.py +73 -0
  97. django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
  98. django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
  99. django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
  100. django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
  101. django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
  102. django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
  103. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
  104. django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
  105. django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
  106. django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
  107. django_cfg/apps/payments/urls.py +3 -2
  108. django_cfg/apps/payments/urls_admin.py +1 -1
  109. django_cfg/apps/payments/views/api/currencies.py +8 -5
  110. django_cfg/apps/payments/views/overview/services.py +2 -2
  111. django_cfg/apps/payments/views/serializers/currencies.py +22 -8
  112. django_cfg/apps/support/admin/__init__.py +10 -1
  113. django_cfg/apps/support/admin/support_admin.py +338 -141
  114. django_cfg/apps/tasks/admin/__init__.py +11 -0
  115. django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
  116. django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
  117. django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
  118. django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
  119. django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
  120. django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
  121. django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
  122. django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
  123. django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
  124. django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
  125. django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
  126. django_cfg/apps/tasks/tasks/__init__.py +10 -0
  127. django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
  128. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
  129. django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
  130. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
  131. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
  132. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
  133. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
  134. django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
  135. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
  136. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
  137. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
  138. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
  139. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
  140. django_cfg/apps/tasks/urls.py +2 -2
  141. django_cfg/apps/tasks/urls_admin.py +2 -2
  142. django_cfg/apps/tasks/utils/__init__.py +1 -0
  143. django_cfg/apps/tasks/utils/simulator.py +356 -0
  144. django_cfg/apps/tasks/views/__init__.py +16 -0
  145. django_cfg/apps/tasks/views/api.py +569 -0
  146. django_cfg/apps/tasks/views/dashboard.py +58 -0
  147. django_cfg/config.py +1 -1
  148. django_cfg/core/config.py +10 -5
  149. django_cfg/core/generation.py +1 -1
  150. django_cfg/core/integration/__init__.py +21 -0
  151. django_cfg/management/commands/__init__.py +13 -1
  152. django_cfg/management/commands/migrate_all.py +9 -3
  153. django_cfg/management/commands/migrator.py +11 -6
  154. django_cfg/management/commands/rundramatiq.py +3 -2
  155. django_cfg/management/commands/rundramatiq_simulator.py +430 -0
  156. django_cfg/middleware/__init__.py +0 -2
  157. django_cfg/models/api_keys.py +115 -0
  158. django_cfg/models/constance.py +0 -11
  159. django_cfg/models/payments.py +137 -3
  160. django_cfg/modules/django_admin/__init__.py +64 -0
  161. django_cfg/modules/django_admin/decorators/__init__.py +13 -0
  162. django_cfg/modules/django_admin/decorators/actions.py +106 -0
  163. django_cfg/modules/django_admin/decorators/display.py +106 -0
  164. django_cfg/modules/django_admin/mixins/__init__.py +14 -0
  165. django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
  166. django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
  167. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
  168. django_cfg/modules/django_admin/models/__init__.py +20 -0
  169. django_cfg/modules/django_admin/models/action_models.py +33 -0
  170. django_cfg/modules/django_admin/models/badge_models.py +20 -0
  171. django_cfg/modules/django_admin/models/base.py +26 -0
  172. django_cfg/modules/django_admin/models/display_models.py +31 -0
  173. django_cfg/modules/django_admin/utils/badges.py +159 -0
  174. django_cfg/modules/django_admin/utils/displays.py +247 -0
  175. django_cfg/modules/django_currency/__init__.py +2 -2
  176. django_cfg/modules/django_currency/clients/__init__.py +2 -2
  177. django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
  178. django_cfg/modules/django_currency/core/converter.py +12 -12
  179. django_cfg/modules/django_currency/database/__init__.py +2 -2
  180. django_cfg/modules/django_currency/database/database_loader.py +93 -42
  181. django_cfg/modules/django_llm/llm/client.py +10 -2
  182. django_cfg/modules/django_tasks.py +54 -21
  183. django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
  184. django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
  185. django_cfg/modules/django_unfold/dashboard.py +14 -13
  186. django_cfg/modules/django_unfold/models/config.py +1 -1
  187. django_cfg/registry/core.py +7 -9
  188. django_cfg/registry/third_party.py +2 -2
  189. django_cfg/template_archive/django_sample.zip +0 -0
  190. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
  191. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
  192. django_cfg/apps/accounts/admin/activity.py +0 -96
  193. django_cfg/apps/accounts/admin/group.py +0 -17
  194. django_cfg/apps/accounts/admin/otp.py +0 -59
  195. django_cfg/apps/accounts/admin/registration_source.py +0 -97
  196. django_cfg/apps/accounts/admin/twilio_response.py +0 -227
  197. django_cfg/apps/accounts/admin/user.py +0 -300
  198. django_cfg/apps/agents/core/agent.py +0 -281
  199. django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
  200. django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
  201. django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
  202. django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
  203. django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
  204. django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
  205. django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
  206. django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
  207. django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
  208. django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
  209. django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
  210. django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
  211. django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
  212. django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
  213. django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
  214. django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
  215. django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
  216. django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
  217. django_cfg/apps/payments/config/constance/__init__.py +0 -22
  218. django_cfg/apps/payments/config/constance/config_service.py +0 -123
  219. django_cfg/apps/payments/config/constance/fields.py +0 -69
  220. django_cfg/apps/payments/config/constance/settings.py +0 -160
  221. django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
  222. django_cfg/apps/tasks/admin.py +0 -320
  223. django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
  224. django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
  225. django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
  226. django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
  227. django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
  228. django_cfg/apps/tasks/templates/tasks/base.html +0 -96
  229. django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
  230. django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
  231. django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
  232. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
  233. django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
  234. django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
  235. django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
  236. django_cfg/apps/tasks/views.py +0 -461
  237. django_cfg/management/commands/auto_generate.py +0 -486
  238. django_cfg/middleware/static_nocache.py +0 -55
  239. django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
  240. /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
  241. /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
  242. /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
  243. /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
  244. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
  245. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
  246. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -1,461 +0,0 @@
1
- """
2
- Views for Django CFG Tasks app.
3
-
4
- Provides DRF ViewSets for task management with nested router structure.
5
- """
6
-
7
- import logging
8
- from typing import Dict, Any
9
-
10
- from django.shortcuts import render
11
- from rest_framework import viewsets, status
12
- from rest_framework.response import Response
13
- from rest_framework.permissions import IsAdminUser
14
- from rest_framework.authentication import SessionAuthentication, BasicAuthentication
15
- from rest_framework.decorators import action
16
- from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiParameter
17
-
18
- from ...modules.django_tasks import DjangoTasks
19
- from .serializers import (
20
- QueueStatusSerializer,
21
- TaskStatisticsSerializer,
22
- WorkerActionSerializer,
23
- QueueActionSerializer,
24
- APIResponseSerializer
25
- )
26
-
27
- logger = logging.getLogger(__name__)
28
-
29
-
30
- class TaskManagementViewSet(viewsets.GenericViewSet):
31
- """
32
- Main ViewSet for comprehensive task management.
33
-
34
- Provides all task-related operations in a single ViewSet with nested actions.
35
- """
36
-
37
- authentication_classes = [SessionAuthentication, BasicAuthentication]
38
- permission_classes = [IsAdminUser]
39
- serializer_class = APIResponseSerializer # Default serializer for the viewset
40
-
41
- def get_serializer_class(self):
42
- """Return the appropriate serializer class based on the action."""
43
- if self.action == 'queue_status':
44
- return QueueStatusSerializer
45
- elif self.action == 'queue_manage':
46
- return QueueActionSerializer
47
- elif self.action == 'worker_manage':
48
- return WorkerActionSerializer
49
- elif self.action == 'task_statistics':
50
- return TaskStatisticsSerializer
51
- return super().get_serializer_class()
52
-
53
- def get_tasks_service(self):
54
- """Get DjangoTasks service instance."""
55
- return DjangoTasks()
56
-
57
- @action(detail=False, methods=['get'], url_path='queues/status')
58
- @extend_schema(
59
- summary="Get queue status",
60
- description="Retrieve current status of all task queues including pending and failed counts",
61
- responses={
62
- 200: OpenApiResponse(response=QueueStatusSerializer, description="Queue status retrieved successfully"),
63
- 500: OpenApiResponse(response=APIResponseSerializer, description="Internal server error")
64
- },
65
- tags=["Task Management"]
66
- )
67
- def queue_status(self, request):
68
- """Get current queue status."""
69
- try:
70
- tasks_service = self.get_tasks_service()
71
- status_data = self._get_queue_status(tasks_service)
72
-
73
- return Response({
74
- 'success': True,
75
- 'data': status_data
76
- })
77
-
78
- except Exception as e:
79
- logger.error(f"Queue status API error: {e}")
80
- return Response({
81
- 'success': False,
82
- 'error': str(e)
83
- }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
84
-
85
- @action(detail=False, methods=['post'], url_path='queues/manage')
86
- @extend_schema(
87
- summary="Manage queues",
88
- description="Clear, purge, or flush task queues",
89
- request=QueueActionSerializer,
90
- responses={
91
- 200: OpenApiResponse(response=APIResponseSerializer, description="Queue action completed successfully"),
92
- 400: OpenApiResponse(response=APIResponseSerializer, description="Invalid request data"),
93
- 500: OpenApiResponse(response=APIResponseSerializer, description="Internal server error")
94
- },
95
- tags=["Task Management"]
96
- )
97
- def queue_manage(self, request):
98
- """Manage task queues."""
99
- serializer = QueueActionSerializer(data=request.data)
100
- serializer.is_valid(raise_exception=True)
101
-
102
- try:
103
- action = serializer.validated_data['action']
104
- queue_names = serializer.validated_data.get('queue_names', [])
105
-
106
- # TODO: Implement actual queue management
107
- target = f"queues: {', '.join(queue_names)}" if queue_names else "all queues"
108
- message = f"Queue {action} command sent for {target}"
109
-
110
- return Response({
111
- 'success': True,
112
- 'message': message
113
- })
114
-
115
- except Exception as e:
116
- logger.error(f"Queue management API error: {e}")
117
- return Response({
118
- 'success': False,
119
- 'error': str(e)
120
- }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
121
-
122
- @action(detail=False, methods=['post'], url_path='workers/manage')
123
- @extend_schema(
124
- summary="Manage workers",
125
- description="Start, stop, or restart Dramatiq workers",
126
- request=WorkerActionSerializer,
127
- responses={
128
- 200: OpenApiResponse(response=APIResponseSerializer, description="Worker action completed successfully"),
129
- 400: OpenApiResponse(response=APIResponseSerializer, description="Invalid request data"),
130
- 500: OpenApiResponse(response=APIResponseSerializer, description="Internal server error")
131
- },
132
- tags=["Task Management"]
133
- )
134
- def worker_manage(self, request):
135
- """Manage worker processes."""
136
- serializer = WorkerActionSerializer(data=request.data)
137
- serializer.is_valid(raise_exception=True)
138
-
139
- try:
140
- action = serializer.validated_data['action']
141
- processes = serializer.validated_data.get('processes', 1)
142
- threads = serializer.validated_data.get('threads', 2)
143
-
144
- # TODO: Implement actual worker management
145
- message = f"Worker {action} command sent (processes: {processes}, threads: {threads})"
146
-
147
- return Response({
148
- 'success': True,
149
- 'message': message
150
- })
151
-
152
- except Exception as e:
153
- logger.error(f"Worker management API error: {e}")
154
- return Response({
155
- 'success': False,
156
- 'error': str(e)
157
- }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
158
-
159
- @action(detail=False, methods=['get'], url_path='tasks/stats')
160
- @extend_schema(
161
- summary="Get task statistics",
162
- description="Retrieve task execution statistics and recent task history",
163
- responses={
164
- 200: OpenApiResponse(response=TaskStatisticsSerializer, description="Task statistics retrieved successfully"),
165
- 500: OpenApiResponse(response=APIResponseSerializer, description="Internal server error")
166
- },
167
- tags=["Task Management"]
168
- )
169
- def task_stats(self, request):
170
- """Get task execution statistics."""
171
- try:
172
- tasks_service = self.get_tasks_service()
173
- stats_data = self._get_task_statistics(tasks_service)
174
-
175
- return Response({
176
- 'success': True,
177
- 'data': stats_data
178
- })
179
-
180
- except Exception as e:
181
- logger.error(f"Task stats API error: {e}")
182
- return Response({
183
- 'success': False,
184
- 'error': str(e)
185
- }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
186
-
187
- @action(detail=False, methods=['get'], url_path='tasks/list')
188
- @extend_schema(
189
- summary="Get detailed task list",
190
- description="Get detailed list of all tasks with filtering options",
191
- parameters=[
192
- OpenApiParameter(name='status', description='Filter by task status', required=False, type=str),
193
- OpenApiParameter(name='queue', description='Filter by queue name', required=False, type=str),
194
- OpenApiParameter(name='search', description='Search in task names', required=False, type=str),
195
- OpenApiParameter(name='limit', description='Limit number of results', required=False, type=int),
196
- OpenApiParameter(name='offset', description='Offset for pagination', required=False, type=int),
197
- ],
198
- responses={
199
- 200: OpenApiResponse(response=APIResponseSerializer, description="Task list retrieved successfully"),
200
- 500: OpenApiResponse(response=APIResponseSerializer, description="Internal server error")
201
- },
202
- tags=["Task Management"]
203
- )
204
- def task_list(self, request):
205
- """Get detailed task list with filtering."""
206
- try:
207
- tasks_service = self.get_tasks_service()
208
- data = self._get_detailed_task_list(tasks_service, request.query_params)
209
-
210
- return Response({
211
- 'success': True,
212
- 'data': data
213
- })
214
-
215
- except Exception as e:
216
- logger.error(f"Task list API error: {e}")
217
- return Response({
218
- 'success': False,
219
- 'error': str(e)
220
- }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
221
-
222
- def _get_queue_status(self, tasks_service: DjangoTasks) -> Dict[str, Any]:
223
- """Get current queue status."""
224
- try:
225
- redis_client = tasks_service.get_redis_client()
226
-
227
- if not redis_client:
228
- return {
229
- 'error': 'Redis connection not available',
230
- 'queues': {},
231
- 'workers': 0,
232
- 'redis_connected': False,
233
- 'timestamp': tasks_service._get_current_timestamp()
234
- }
235
-
236
- # Get queue information
237
- queues_info = {}
238
- config = tasks_service.config
239
-
240
- if config and config.dramatiq and config.dramatiq.queues:
241
- for queue_name in config.dramatiq.queues:
242
- # Try different queue key patterns
243
- queue_keys = [
244
- f"dramatiq:queue:{queue_name}",
245
- f"dramatiq:default.DQ.{queue_name}",
246
- f"dramatiq:{queue_name}"
247
- ]
248
-
249
- queue_length = 0
250
- failed_length = 0
251
-
252
- # Check for pending tasks
253
- for queue_key in queue_keys:
254
- length = redis_client.llen(queue_key)
255
- if length > 0:
256
- queue_length = length
257
- break
258
-
259
- # Check for failed tasks
260
- failed_keys = [
261
- f"dramatiq:queue:{queue_name}.failed",
262
- f"dramatiq:default.DQ.{queue_name}.failed",
263
- f"dramatiq:{queue_name}.failed"
264
- ]
265
-
266
- for failed_key in failed_keys:
267
- length = redis_client.llen(failed_key)
268
- if length > 0:
269
- failed_length = length
270
- break
271
-
272
- queues_info[queue_name] = {
273
- 'pending': queue_length,
274
- 'failed': failed_length,
275
- 'total': queue_length + failed_length
276
- }
277
-
278
- # Get worker information
279
- worker_keys = redis_client.keys("dramatiq:worker:*")
280
- active_workers = len(worker_keys) if worker_keys else 0
281
-
282
- return {
283
- 'queues': queues_info,
284
- 'workers': active_workers,
285
- 'redis_connected': True,
286
- 'timestamp': tasks_service._get_current_timestamp()
287
- }
288
-
289
- except Exception as e:
290
- logger.error(f"Queue status error: {e}")
291
- return {
292
- 'error': str(e),
293
- 'queues': {},
294
- 'workers': 0,
295
- 'redis_connected': False,
296
- 'timestamp': tasks_service._get_current_timestamp()
297
- }
298
-
299
- def _get_task_statistics(self, tasks_service: DjangoTasks) -> Dict[str, Any]:
300
- """Get task execution statistics."""
301
- try:
302
- # Try to import django_dramatiq models
303
- try:
304
- from django_dramatiq.models import Task
305
- from django.db.models import Count
306
-
307
- # Check if Task model has tasks manager (django_dramatiq uses 'tasks' not 'objects')
308
- if not hasattr(Task, 'tasks'):
309
- logger.warning("Task model does not have tasks manager")
310
- return {
311
- 'statistics': {'total': 0},
312
- 'recent_tasks': [],
313
- 'error': 'Task model not properly initialized',
314
- 'timestamp': tasks_service._get_current_timestamp()
315
- }
316
-
317
- # Get task counts by status
318
- stats = Task.tasks.aggregate(
319
- total=Count('id'),
320
- )
321
-
322
- # Get recent tasks
323
- recent_tasks = list(
324
- Task.tasks.order_by('-created_at')[:10]
325
- .values('actor_name', 'status', 'created_at', 'updated_at')
326
- )
327
-
328
- return {
329
- 'statistics': stats,
330
- 'recent_tasks': recent_tasks,
331
- 'timestamp': tasks_service._get_current_timestamp()
332
- }
333
-
334
- except ImportError:
335
- return {
336
- 'error': 'django_dramatiq not available',
337
- 'statistics': {'total': 0},
338
- 'recent_tasks': [],
339
- 'timestamp': tasks_service._get_current_timestamp()
340
- }
341
-
342
- except Exception as e:
343
- logger.error(f"Task statistics error: {e}")
344
- return {
345
- 'error': str(e),
346
- 'statistics': {'total': 0},
347
- 'recent_tasks': [],
348
- 'timestamp': tasks_service._get_current_timestamp()
349
- }
350
-
351
- def _get_detailed_task_list(self, tasks_service: DjangoTasks, query_params) -> Dict[str, Any]:
352
- """Get detailed task list with filtering."""
353
- try:
354
- # Import django_dramatiq models if available
355
- try:
356
- from django_dramatiq.models import Task
357
- from django.db.models import Q
358
-
359
- # Check if Task model has tasks manager
360
- if not hasattr(Task, 'tasks'):
361
- logger.warning("Task model does not have tasks manager")
362
- return {
363
- 'tasks': [],
364
- 'total': 0,
365
- 'error': 'Task model not properly initialized',
366
- 'timestamp': tasks_service._get_current_timestamp()
367
- }
368
-
369
- # Build query
370
- queryset = Task.tasks.all()
371
-
372
- # Apply filters
373
- status_filter = query_params.get('status')
374
- if status_filter:
375
- queryset = queryset.filter(status=status_filter)
376
-
377
- queue_filter = query_params.get('queue')
378
- if queue_filter:
379
- queryset = queryset.filter(queue_name=queue_filter)
380
-
381
- search_filter = query_params.get('search')
382
- if search_filter:
383
- queryset = queryset.filter(
384
- Q(actor_name__icontains=search_filter) |
385
- Q(id__icontains=search_filter)
386
- )
387
-
388
- # Get total count before pagination
389
- total_count = queryset.count()
390
-
391
- # Apply pagination
392
- limit = int(query_params.get('limit', 50))
393
- offset = int(query_params.get('offset', 0))
394
- queryset = queryset.order_by('-created_at')[offset:offset + limit]
395
-
396
- # Convert to list of dictionaries
397
- tasks = []
398
- for task in queryset:
399
- task_data = {
400
- 'id': str(task.id),
401
- 'actor_name': task.actor_name,
402
- 'status': task.status,
403
- 'queue': getattr(task, 'queue_name', 'default'),
404
- 'created_at': task.created_at.isoformat() if task.created_at else None,
405
- 'updated_at': task.updated_at.isoformat() if task.updated_at else None,
406
- 'args': task.args if hasattr(task, 'args') else None,
407
- 'kwargs': task.kwargs if hasattr(task, 'kwargs') else None,
408
- 'result': task.result if hasattr(task, 'result') else None,
409
- 'traceback': task.traceback if hasattr(task, 'traceback') else None,
410
- 'progress': getattr(task, 'progress', None),
411
- }
412
- tasks.append(task_data)
413
-
414
- return {
415
- 'tasks': tasks,
416
- 'total': total_count,
417
- 'limit': limit,
418
- 'offset': offset,
419
- 'timestamp': tasks_service._get_current_timestamp()
420
- }
421
-
422
- except ImportError:
423
- return {
424
- 'error': 'django_dramatiq not available',
425
- 'tasks': [],
426
- 'total': 0,
427
- 'timestamp': tasks_service._get_current_timestamp()
428
- }
429
-
430
- except Exception as e:
431
- logger.error(f"Task list error: {e}")
432
- return {
433
- 'error': str(e),
434
- 'tasks': [],
435
- 'total': 0,
436
- 'timestamp': tasks_service._get_current_timestamp()
437
- }
438
-
439
-
440
-
441
-
442
- def dashboard_view(request):
443
- """Dashboard view for task management."""
444
- try:
445
- # Use main ViewSet to get data
446
- main_viewset = TaskManagementViewSet()
447
- tasks_service = main_viewset.get_tasks_service()
448
-
449
- context = {
450
- 'queue_status': main_viewset._get_queue_status(tasks_service),
451
- 'task_stats': main_viewset._get_task_statistics(tasks_service),
452
- }
453
-
454
- return render(request, 'tasks/dashboard.html', context)
455
-
456
- except Exception as e:
457
- logger.error(f"Dashboard view error: {e}")
458
- context = {
459
- 'error': str(e)
460
- }
461
- return render(request, 'tasks/dashboard.html', context)