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.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/admin/__init__.py +24 -8
- django_cfg/apps/accounts/admin/activity_admin.py +146 -0
- django_cfg/apps/accounts/admin/filters.py +98 -22
- django_cfg/apps/accounts/admin/group_admin.py +86 -0
- django_cfg/apps/accounts/admin/inlines.py +42 -13
- django_cfg/apps/accounts/admin/otp_admin.py +115 -0
- django_cfg/apps/accounts/admin/registration_admin.py +173 -0
- django_cfg/apps/accounts/admin/resources.py +123 -19
- django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
- django_cfg/apps/accounts/admin/user_admin.py +362 -0
- django_cfg/apps/agents/admin/__init__.py +17 -4
- django_cfg/apps/agents/admin/execution_admin.py +204 -183
- django_cfg/apps/agents/admin/registry_admin.py +230 -255
- django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
- django_cfg/apps/agents/core/__init__.py +1 -1
- django_cfg/apps/agents/core/django_agent.py +221 -0
- django_cfg/apps/agents/core/exceptions.py +14 -0
- django_cfg/apps/agents/core/orchestrator.py +18 -3
- django_cfg/apps/knowbase/admin/__init__.py +1 -1
- django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
- django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
- django_cfg/apps/knowbase/admin/document_admin.py +269 -262
- django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
- django_cfg/apps/knowbase/config/settings.py +21 -4
- django_cfg/apps/knowbase/views/chat_views.py +3 -0
- django_cfg/apps/leads/admin/__init__.py +3 -1
- django_cfg/apps/leads/admin/leads_admin.py +235 -35
- django_cfg/apps/maintenance/admin/__init__.py +2 -2
- django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
- django_cfg/apps/maintenance/admin/log_admin.py +143 -61
- django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
- django_cfg/apps/maintenance/admin/site_admin.py +213 -352
- django_cfg/apps/newsletter/admin/__init__.py +29 -2
- django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
- django_cfg/apps/payments/admin/__init__.py +18 -27
- django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
- django_cfg/apps/payments/admin/balance_admin.py +166 -632
- django_cfg/apps/payments/admin/currencies_admin.py +235 -607
- django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
- django_cfg/apps/payments/admin/filters.py +83 -3
- django_cfg/apps/payments/admin/networks_admin.py +269 -0
- django_cfg/apps/payments/admin/payments_admin.py +183 -460
- django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
- django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
- django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
- django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
- django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
- django_cfg/apps/payments/config/__init__.py +14 -15
- django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
- django_cfg/apps/payments/config/helpers.py +8 -13
- django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
- django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
- django_cfg/apps/payments/middleware/api_access.py +32 -6
- django_cfg/apps/payments/migrations/0001_initial.py +33 -46
- django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
- django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
- django_cfg/apps/payments/models/balance.py +12 -0
- django_cfg/apps/payments/models/currencies.py +106 -32
- django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
- django_cfg/apps/payments/models/payments.py +94 -0
- django_cfg/apps/payments/services/core/base.py +4 -4
- django_cfg/apps/payments/services/core/currency_service.py +35 -28
- django_cfg/apps/payments/services/core/payment_service.py +266 -39
- django_cfg/apps/payments/services/providers/__init__.py +3 -0
- django_cfg/apps/payments/services/providers/base.py +303 -41
- django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
- django_cfg/apps/payments/services/providers/models/base.py +145 -0
- django_cfg/apps/payments/services/providers/models/providers.py +87 -0
- django_cfg/apps/payments/services/providers/models/universal.py +48 -0
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
- django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
- django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
- django_cfg/apps/payments/services/providers/registry.py +9 -37
- django_cfg/apps/payments/services/providers/sync_service.py +277 -0
- django_cfg/apps/payments/services/types/requests.py +19 -7
- django_cfg/apps/payments/signals/payment_signals.py +31 -2
- django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
- django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
- django_cfg/apps/payments/tasks/__init__.py +39 -0
- django_cfg/apps/payments/tasks/types.py +73 -0
- django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
- django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
- django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
- django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
- django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
- django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
- django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
- django_cfg/apps/payments/urls.py +3 -2
- django_cfg/apps/payments/urls_admin.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +8 -5
- django_cfg/apps/payments/views/overview/services.py +2 -2
- django_cfg/apps/payments/views/serializers/currencies.py +22 -8
- django_cfg/apps/support/admin/__init__.py +10 -1
- django_cfg/apps/support/admin/support_admin.py +338 -141
- django_cfg/apps/tasks/admin/__init__.py +11 -0
- django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
- django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
- django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
- django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
- django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
- django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
- django_cfg/apps/tasks/tasks/__init__.py +10 -0
- django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
- django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
- django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
- django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
- django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
- django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
- django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
- django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
- django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
- django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
- django_cfg/apps/tasks/urls.py +2 -2
- django_cfg/apps/tasks/urls_admin.py +2 -2
- django_cfg/apps/tasks/utils/__init__.py +1 -0
- django_cfg/apps/tasks/utils/simulator.py +356 -0
- django_cfg/apps/tasks/views/__init__.py +16 -0
- django_cfg/apps/tasks/views/api.py +569 -0
- django_cfg/apps/tasks/views/dashboard.py +58 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +10 -5
- django_cfg/core/generation.py +1 -1
- django_cfg/core/integration/__init__.py +21 -0
- django_cfg/management/commands/__init__.py +13 -1
- django_cfg/management/commands/migrate_all.py +9 -3
- django_cfg/management/commands/migrator.py +11 -6
- django_cfg/management/commands/rundramatiq.py +3 -2
- django_cfg/management/commands/rundramatiq_simulator.py +430 -0
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/models/api_keys.py +115 -0
- django_cfg/models/constance.py +0 -11
- django_cfg/models/payments.py +137 -3
- django_cfg/modules/django_admin/__init__.py +64 -0
- django_cfg/modules/django_admin/decorators/__init__.py +13 -0
- django_cfg/modules/django_admin/decorators/actions.py +106 -0
- django_cfg/modules/django_admin/decorators/display.py +106 -0
- django_cfg/modules/django_admin/mixins/__init__.py +14 -0
- django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
- django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
- django_cfg/modules/django_admin/models/__init__.py +20 -0
- django_cfg/modules/django_admin/models/action_models.py +33 -0
- django_cfg/modules/django_admin/models/badge_models.py +20 -0
- django_cfg/modules/django_admin/models/base.py +26 -0
- django_cfg/modules/django_admin/models/display_models.py +31 -0
- django_cfg/modules/django_admin/utils/badges.py +159 -0
- django_cfg/modules/django_admin/utils/displays.py +247 -0
- django_cfg/modules/django_currency/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
- django_cfg/modules/django_currency/core/converter.py +12 -12
- django_cfg/modules/django_currency/database/__init__.py +2 -2
- django_cfg/modules/django_currency/database/database_loader.py +93 -42
- django_cfg/modules/django_llm/llm/client.py +10 -2
- django_cfg/modules/django_tasks.py +54 -21
- django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
- django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
- django_cfg/modules/django_unfold/dashboard.py +14 -13
- django_cfg/modules/django_unfold/models/config.py +1 -1
- django_cfg/registry/core.py +7 -9
- django_cfg/registry/third_party.py +2 -2
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
- django_cfg/apps/accounts/admin/activity.py +0 -96
- django_cfg/apps/accounts/admin/group.py +0 -17
- django_cfg/apps/accounts/admin/otp.py +0 -59
- django_cfg/apps/accounts/admin/registration_source.py +0 -97
- django_cfg/apps/accounts/admin/twilio_response.py +0 -227
- django_cfg/apps/accounts/admin/user.py +0 -300
- django_cfg/apps/agents/core/agent.py +0 -281
- django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
- django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
- django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
- django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
- django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
- django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
- django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
- django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
- django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
- django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
- django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
- django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
- django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
- django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
- django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
- django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
- django_cfg/apps/payments/config/constance/__init__.py +0 -22
- django_cfg/apps/payments/config/constance/config_service.py +0 -123
- django_cfg/apps/payments/config/constance/fields.py +0 -69
- django_cfg/apps/payments/config/constance/settings.py +0 -160
- django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
- django_cfg/apps/tasks/admin.py +0 -320
- django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
- django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
- django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
- django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
- django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
- django_cfg/apps/tasks/templates/tasks/base.html +0 -96
- django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
- django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
- django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
- django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
- django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
- django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
- django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
- django_cfg/apps/tasks/views.py +0 -461
- django_cfg/management/commands/auto_generate.py +0 -486
- django_cfg/middleware/static_nocache.py +0 -55
- django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
- /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
django_cfg/apps/tasks/views.py
DELETED
@@ -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)
|