django-cfg 1.3.5__py3-none-any.whl → 1.3.9__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 +258 -0
- django_cfg/apps/payments/admin/payments_admin.py +171 -461
- 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 +105 -34
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +12 -16
- django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +13 -18
- 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/0002_currency_usd_rate_currency_usd_rate_updated_at.py +26 -0
- django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +28 -0
- django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +30 -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/services/core/currency_service.py +35 -28
- django_cfg/apps/payments/services/core/payment_service.py +1 -1
- django_cfg/apps/payments/services/providers/__init__.py +3 -0
- django_cfg/apps/payments/services/providers/base.py +95 -39
- django_cfg/apps/payments/services/providers/models/__init__.py +40 -0
- django_cfg/apps/payments/services/providers/models/base.py +122 -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.py → nowpayments/provider.py} +240 -209
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
- django_cfg/apps/payments/services/providers/registry.py +4 -32
- django_cfg/apps/payments/services/providers/sync_service.py +277 -0
- django_cfg/apps/payments/static/payments/js/api-client.js +23 -5
- django_cfg/apps/payments/static/payments/js/payment-form.js +65 -8
- 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/urls_admin.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +5 -5
- django_cfg/apps/payments/views/overview/services.py +2 -2
- django_cfg/apps/payments/views/serializers/currencies.py +4 -3
- 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/urls.py +1 -2
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +10 -5
- django_cfg/core/generation.py +1 -1
- django_cfg/management/commands/__init__.py +13 -1
- django_cfg/management/commands/app_agent_diagnose.py +470 -0
- django_cfg/management/commands/app_agent_generate.py +342 -0
- django_cfg/management/commands/app_agent_info.py +308 -0
- 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/middleware/__init__.py +0 -2
- django_cfg/models/api_keys.py +115 -0
- 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_app_agent/__init__.py +87 -0
- django_cfg/modules/django_app_agent/agents/__init__.py +40 -0
- django_cfg/modules/django_app_agent/agents/base/__init__.py +24 -0
- django_cfg/modules/django_app_agent/agents/base/agent.py +354 -0
- django_cfg/modules/django_app_agent/agents/base/context.py +236 -0
- django_cfg/modules/django_app_agent/agents/base/executor.py +430 -0
- django_cfg/modules/django_app_agent/agents/generation/__init__.py +12 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +15 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +147 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +99 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +32 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +290 -0
- django_cfg/modules/django_app_agent/agents/interfaces.py +376 -0
- django_cfg/modules/django_app_agent/core/__init__.py +33 -0
- django_cfg/modules/django_app_agent/core/config.py +300 -0
- django_cfg/modules/django_app_agent/core/exceptions.py +359 -0
- django_cfg/modules/django_app_agent/models/__init__.py +71 -0
- django_cfg/modules/django_app_agent/models/base.py +283 -0
- django_cfg/modules/django_app_agent/models/context.py +496 -0
- django_cfg/modules/django_app_agent/models/enums.py +481 -0
- django_cfg/modules/django_app_agent/models/requests.py +500 -0
- django_cfg/modules/django_app_agent/models/responses.py +585 -0
- django_cfg/modules/django_app_agent/pytest.ini +6 -0
- django_cfg/modules/django_app_agent/services/__init__.py +42 -0
- django_cfg/modules/django_app_agent/services/app_generator/__init__.py +30 -0
- django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +133 -0
- django_cfg/modules/django_app_agent/services/app_generator/context.py +40 -0
- django_cfg/modules/django_app_agent/services/app_generator/main.py +202 -0
- django_cfg/modules/django_app_agent/services/app_generator/structure.py +316 -0
- django_cfg/modules/django_app_agent/services/app_generator/validation.py +125 -0
- django_cfg/modules/django_app_agent/services/base.py +437 -0
- django_cfg/modules/django_app_agent/services/context_builder/__init__.py +34 -0
- django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +141 -0
- django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +276 -0
- django_cfg/modules/django_app_agent/services/context_builder/main.py +272 -0
- django_cfg/modules/django_app_agent/services/context_builder/models.py +40 -0
- django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +85 -0
- django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +31 -0
- django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +311 -0
- django_cfg/modules/django_app_agent/services/project_scanner/main.py +221 -0
- django_cfg/modules/django_app_agent/services/project_scanner/models.py +59 -0
- django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +94 -0
- django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +28 -0
- django_cfg/modules/django_app_agent/services/questioning_service/main.py +273 -0
- django_cfg/modules/django_app_agent/services/questioning_service/models.py +111 -0
- django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +251 -0
- django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +347 -0
- django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +356 -0
- django_cfg/modules/django_app_agent/services/report_service.py +332 -0
- django_cfg/modules/django_app_agent/services/template_manager/__init__.py +18 -0
- django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +236 -0
- django_cfg/modules/django_app_agent/services/template_manager/main.py +159 -0
- django_cfg/modules/django_app_agent/services/template_manager/models.py +36 -0
- django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +100 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +105 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +31 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +44 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +81 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +107 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +139 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +91 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +195 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +35 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +211 -0
- django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +200 -0
- django_cfg/modules/django_app_agent/services/validation_service/__init__.py +25 -0
- django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +333 -0
- django_cfg/modules/django_app_agent/services/validation_service/main.py +242 -0
- django_cfg/modules/django_app_agent/services/validation_service/models.py +66 -0
- django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +352 -0
- django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +272 -0
- django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +203 -0
- django_cfg/modules/django_app_agent/ui/__init__.py +25 -0
- django_cfg/modules/django_app_agent/ui/cli.py +419 -0
- django_cfg/modules/django_app_agent/ui/rich_components.py +622 -0
- django_cfg/modules/django_app_agent/utils/__init__.py +38 -0
- django_cfg/modules/django_app_agent/utils/logging.py +360 -0
- django_cfg/modules/django_app_agent/utils/validation.py +417 -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_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 +3 -0
- django_cfg/registry/third_party.py +2 -2
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/METADATA +2 -1
- {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/RECORD +224 -118
- 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/tasks/admin.py +0 -320
- 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.5.dist-info → django_cfg-1.3.9.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/licenses/LICENSE +0 -0
django_cfg/apps/tasks/admin.py
DELETED
@@ -1,320 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Admin interface for Dramatiq task management.
|
3
|
-
|
4
|
-
Provides web interface for starting workers, checking queue status,
|
5
|
-
and clearing queues with AJAX endpoints and interactive buttons.
|
6
|
-
"""
|
7
|
-
|
8
|
-
import logging
|
9
|
-
import subprocess
|
10
|
-
import sys
|
11
|
-
from typing import Dict, Any
|
12
|
-
|
13
|
-
from django.db.models import Count
|
14
|
-
from django.contrib import admin
|
15
|
-
from django.contrib.admin.views.main import ChangeList
|
16
|
-
from django.http import JsonResponse
|
17
|
-
from django.urls import path
|
18
|
-
from django.views.decorators.csrf import csrf_exempt
|
19
|
-
from unfold.admin import ModelAdmin
|
20
|
-
|
21
|
-
try:
|
22
|
-
from django_dramatiq.models import Task
|
23
|
-
from django_dramatiq.admin import TaskAdmin as BaseDramatiqTaskAdmin
|
24
|
-
except ImportError:
|
25
|
-
Task = None
|
26
|
-
BaseDramatiqTaskAdmin = None
|
27
|
-
|
28
|
-
from ...modules.django_tasks import DjangoTasks
|
29
|
-
|
30
|
-
|
31
|
-
class TaskQueueChangeList(ChangeList):
|
32
|
-
"""Custom changelist for task queue management."""
|
33
|
-
|
34
|
-
def __init__(self, *args, **kwargs):
|
35
|
-
super().__init__(*args, **kwargs)
|
36
|
-
self.tasks_service = DjangoTasks()
|
37
|
-
|
38
|
-
|
39
|
-
class TaskQueueAdmin(ModelAdmin):
|
40
|
-
"""
|
41
|
-
Enhanced admin for Dramatiq task management.
|
42
|
-
|
43
|
-
Provides buttons for:
|
44
|
-
- Starting/stopping workers
|
45
|
-
- Checking queue status
|
46
|
-
- Clearing queues
|
47
|
-
- Viewing task statistics
|
48
|
-
"""
|
49
|
-
|
50
|
-
def __init__(self, *args, **kwargs):
|
51
|
-
super().__init__(*args, **kwargs)
|
52
|
-
self.logger = logging.getLogger(__name__)
|
53
|
-
self.tasks_service = DjangoTasks()
|
54
|
-
|
55
|
-
def get_urls(self):
|
56
|
-
"""Add custom URLs for task management."""
|
57
|
-
urls = super().get_urls()
|
58
|
-
custom_urls = [
|
59
|
-
path('queue-status/', csrf_exempt(self.queue_status_view), name='dramatiq_queue_status'),
|
60
|
-
path('start-workers/', csrf_exempt(self.start_workers_view), name='dramatiq_start_workers'),
|
61
|
-
path('clear-queues/', csrf_exempt(self.clear_queues_view), name='dramatiq_clear_queues'),
|
62
|
-
path('task-stats/', csrf_exempt(self.task_stats_view), name='dramatiq_task_stats'),
|
63
|
-
]
|
64
|
-
return custom_urls + urls
|
65
|
-
|
66
|
-
def queue_status_view(self, request):
|
67
|
-
"""Get queue status and statistics."""
|
68
|
-
if request.method != 'GET':
|
69
|
-
return JsonResponse({'success': False, 'error': 'Method not allowed'}, status=405)
|
70
|
-
|
71
|
-
try:
|
72
|
-
# Get queue status using tasks service
|
73
|
-
status_data = self._get_queue_status()
|
74
|
-
|
75
|
-
return JsonResponse({
|
76
|
-
'success': True,
|
77
|
-
'data': status_data
|
78
|
-
})
|
79
|
-
|
80
|
-
except Exception as e:
|
81
|
-
self.logger.error(f"Queue status check failed: {e}")
|
82
|
-
return JsonResponse({
|
83
|
-
'success': False,
|
84
|
-
'error': str(e)
|
85
|
-
}, status=500)
|
86
|
-
|
87
|
-
def start_workers_view(self, request):
|
88
|
-
"""Start Dramatiq workers."""
|
89
|
-
if request.method != 'POST':
|
90
|
-
return JsonResponse({'success': False, 'error': 'Method not allowed'}, status=405)
|
91
|
-
|
92
|
-
try:
|
93
|
-
# Get parameters from request
|
94
|
-
processes = int(request.POST.get('processes', 2))
|
95
|
-
threads = int(request.POST.get('threads', 8))
|
96
|
-
queues = request.POST.get('queues', '')
|
97
|
-
|
98
|
-
# Validate parameters
|
99
|
-
if processes < 1 or processes > 16:
|
100
|
-
return JsonResponse({
|
101
|
-
'success': False,
|
102
|
-
'error': 'Processes must be between 1 and 16'
|
103
|
-
}, status=400)
|
104
|
-
|
105
|
-
if threads < 1 or threads > 32:
|
106
|
-
return JsonResponse({
|
107
|
-
'success': False,
|
108
|
-
'error': 'Threads must be between 1 and 32'
|
109
|
-
}, status=400)
|
110
|
-
|
111
|
-
# Build command
|
112
|
-
cmd = [sys.executable, 'manage.py', 'rundramatiq']
|
113
|
-
cmd.extend(['--processes', str(processes)])
|
114
|
-
cmd.extend(['--threads', str(threads)])
|
115
|
-
|
116
|
-
if queues:
|
117
|
-
cmd.extend(['--queues', queues])
|
118
|
-
|
119
|
-
# Start workers in background
|
120
|
-
process = subprocess.Popen(
|
121
|
-
cmd,
|
122
|
-
stdout=subprocess.PIPE,
|
123
|
-
stderr=subprocess.PIPE,
|
124
|
-
cwd=None # Use current working directory
|
125
|
-
)
|
126
|
-
|
127
|
-
return JsonResponse({
|
128
|
-
'success': True,
|
129
|
-
'message': f'Started {processes} worker processes with {threads} threads each',
|
130
|
-
'pid': process.pid,
|
131
|
-
'command': ' '.join(cmd)
|
132
|
-
})
|
133
|
-
|
134
|
-
except Exception as e:
|
135
|
-
self.logger.error(f"Start workers failed: {e}")
|
136
|
-
return JsonResponse({
|
137
|
-
'success': False,
|
138
|
-
'error': str(e)
|
139
|
-
}, status=500)
|
140
|
-
|
141
|
-
def clear_queues_view(self, request):
|
142
|
-
"""Clear Dramatiq queues."""
|
143
|
-
if request.method != 'POST':
|
144
|
-
return JsonResponse({'success': False, 'error': 'Method not allowed'}, status=405)
|
145
|
-
|
146
|
-
try:
|
147
|
-
# Get parameters
|
148
|
-
queue_name = request.POST.get('queue', '')
|
149
|
-
failed_only = request.POST.get('failed_only', 'false').lower() == 'true'
|
150
|
-
|
151
|
-
# Build command
|
152
|
-
cmd = [sys.executable, 'manage.py', 'task_clear', '--confirm']
|
153
|
-
|
154
|
-
if queue_name:
|
155
|
-
cmd.extend(['--queue', queue_name])
|
156
|
-
|
157
|
-
if failed_only:
|
158
|
-
cmd.append('--failed-only')
|
159
|
-
|
160
|
-
# Execute command
|
161
|
-
result = subprocess.run(
|
162
|
-
cmd,
|
163
|
-
capture_output=True,
|
164
|
-
text=True,
|
165
|
-
timeout=30
|
166
|
-
)
|
167
|
-
|
168
|
-
if result.returncode == 0:
|
169
|
-
return JsonResponse({
|
170
|
-
'success': True,
|
171
|
-
'message': 'Queues cleared successfully',
|
172
|
-
'output': result.stdout
|
173
|
-
})
|
174
|
-
else:
|
175
|
-
return JsonResponse({
|
176
|
-
'success': False,
|
177
|
-
'error': result.stderr or 'Clear command failed'
|
178
|
-
}, status=500)
|
179
|
-
|
180
|
-
except subprocess.TimeoutExpired:
|
181
|
-
return JsonResponse({
|
182
|
-
'success': False,
|
183
|
-
'error': 'Clear operation timed out'
|
184
|
-
}, status=500)
|
185
|
-
except Exception as e:
|
186
|
-
self.logger.error(f"Clear queues failed: {e}")
|
187
|
-
return JsonResponse({
|
188
|
-
'success': False,
|
189
|
-
'error': str(e)
|
190
|
-
}, status=500)
|
191
|
-
|
192
|
-
def task_stats_view(self, request):
|
193
|
-
"""Get task statistics."""
|
194
|
-
if request.method != 'GET':
|
195
|
-
return JsonResponse({'success': False, 'error': 'Method not allowed'}, status=405)
|
196
|
-
|
197
|
-
try:
|
198
|
-
# Get task statistics using tasks service
|
199
|
-
stats_data = self._get_task_statistics()
|
200
|
-
|
201
|
-
return JsonResponse({
|
202
|
-
'success': True,
|
203
|
-
'data': stats_data
|
204
|
-
})
|
205
|
-
|
206
|
-
except Exception as e:
|
207
|
-
self.logger.error(f"Task stats failed: {e}")
|
208
|
-
return JsonResponse({
|
209
|
-
'success': False,
|
210
|
-
'error': str(e)
|
211
|
-
}, status=500)
|
212
|
-
|
213
|
-
def _get_queue_status(self) -> Dict[str, Any]:
|
214
|
-
"""Get current queue status."""
|
215
|
-
try:
|
216
|
-
# Use tasks service to get Redis connection
|
217
|
-
redis_client = self.tasks_service.get_redis_client()
|
218
|
-
|
219
|
-
if not redis_client:
|
220
|
-
return {
|
221
|
-
'error': 'Redis connection not available',
|
222
|
-
'queues': {},
|
223
|
-
'workers': 0
|
224
|
-
}
|
225
|
-
|
226
|
-
# Get queue information
|
227
|
-
queues_info = {}
|
228
|
-
config = self.tasks_service.config
|
229
|
-
|
230
|
-
if config and config.dramatiq and config.dramatiq.queues:
|
231
|
-
for queue_name in config.dramatiq.queues:
|
232
|
-
queue_key = f"dramatiq:default.DQ.{queue_name}"
|
233
|
-
queue_length = redis_client.llen(queue_key)
|
234
|
-
|
235
|
-
# Get failed queue length
|
236
|
-
failed_key = f"dramatiq:default.DQ.{queue_name}.failed"
|
237
|
-
failed_length = redis_client.llen(failed_key)
|
238
|
-
|
239
|
-
queues_info[queue_name] = {
|
240
|
-
'pending': queue_length,
|
241
|
-
'failed': failed_length,
|
242
|
-
'total': queue_length + failed_length
|
243
|
-
}
|
244
|
-
|
245
|
-
# Get worker information (simplified)
|
246
|
-
worker_keys = redis_client.keys("dramatiq:worker:*")
|
247
|
-
active_workers = len(worker_keys) if worker_keys else 0
|
248
|
-
|
249
|
-
return {
|
250
|
-
'queues': queues_info,
|
251
|
-
'workers': active_workers,
|
252
|
-
'redis_connected': True,
|
253
|
-
'timestamp': self.tasks_service._get_current_timestamp()
|
254
|
-
}
|
255
|
-
|
256
|
-
except Exception as e:
|
257
|
-
self.logger.error(f"Queue status error: {e}")
|
258
|
-
return {
|
259
|
-
'error': str(e),
|
260
|
-
'queues': {},
|
261
|
-
'workers': 0,
|
262
|
-
'redis_connected': False
|
263
|
-
}
|
264
|
-
|
265
|
-
def _get_task_statistics(self) -> Dict[str, Any]:
|
266
|
-
"""Get task execution statistics."""
|
267
|
-
try:
|
268
|
-
if not Task:
|
269
|
-
return {'error': 'django_dramatiq not available'}
|
270
|
-
|
271
|
-
|
272
|
-
stats = Task.tasks.aggregate(
|
273
|
-
total=Count('id'),
|
274
|
-
# Add more aggregations as needed
|
275
|
-
)
|
276
|
-
|
277
|
-
# Get recent tasks
|
278
|
-
recent_tasks = list(
|
279
|
-
Task.tasks.order_by('-created_at')[:10]
|
280
|
-
.values('actor_name', 'status', 'created_at', 'updated_at')
|
281
|
-
)
|
282
|
-
|
283
|
-
return {
|
284
|
-
'statistics': stats,
|
285
|
-
'recent_tasks': recent_tasks,
|
286
|
-
'timestamp': self.tasks_service._get_current_timestamp()
|
287
|
-
}
|
288
|
-
|
289
|
-
except Exception as e:
|
290
|
-
self.logger.error(f"Task statistics error: {e}")
|
291
|
-
return {'error': str(e)}
|
292
|
-
|
293
|
-
|
294
|
-
# Register the enhanced admin if django_dramatiq is available
|
295
|
-
if Task and BaseDramatiqTaskAdmin:
|
296
|
-
# Unregister the default admin
|
297
|
-
admin.site.unregister(Task)
|
298
|
-
|
299
|
-
# Register our enhanced admin
|
300
|
-
@admin.register(Task)
|
301
|
-
class EnhancedTaskAdmin(TaskQueueAdmin, BaseDramatiqTaskAdmin):
|
302
|
-
"""Enhanced Task admin with queue management buttons."""
|
303
|
-
|
304
|
-
def get_changelist(self, request, **kwargs):
|
305
|
-
"""Use custom changelist."""
|
306
|
-
return TaskQueueChangeList
|
307
|
-
|
308
|
-
def changelist_view(self, request, extra_context=None):
|
309
|
-
"""Add extra context for queue management."""
|
310
|
-
extra_context = extra_context or {}
|
311
|
-
|
312
|
-
# Add queue status to context
|
313
|
-
try:
|
314
|
-
queue_status = self._get_queue_status()
|
315
|
-
extra_context['queue_status'] = queue_status
|
316
|
-
except Exception as e:
|
317
|
-
self.logger.error(f"Failed to get queue status: {e}")
|
318
|
-
extra_context['queue_status'] = {'error': str(e)}
|
319
|
-
|
320
|
-
return super().changelist_view(request, extra_context)
|
@@ -1,55 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Static files no-cache middleware for django-cfg.
|
3
|
-
|
4
|
-
Automatically disables caching for static files in development environments
|
5
|
-
to prevent browser caching issues during development.
|
6
|
-
"""
|
7
|
-
|
8
|
-
from django.conf import settings
|
9
|
-
from django_cfg.core.config import EnvironmentMode
|
10
|
-
|
11
|
-
|
12
|
-
class StaticNoCacheMiddleware:
|
13
|
-
"""
|
14
|
-
Middleware to disable caching for static files in development.
|
15
|
-
|
16
|
-
This ensures that JavaScript and CSS files are always fresh during development,
|
17
|
-
preventing browser caching issues when files are updated.
|
18
|
-
|
19
|
-
Automatically detects development mode based on:
|
20
|
-
- DEBUG setting
|
21
|
-
- ENV_MODE environment variable
|
22
|
-
"""
|
23
|
-
|
24
|
-
def __init__(self, get_response):
|
25
|
-
self.get_response = get_response
|
26
|
-
|
27
|
-
# Determine if we should disable caching
|
28
|
-
self.should_disable_cache = self._should_disable_cache()
|
29
|
-
|
30
|
-
def _should_disable_cache(self):
|
31
|
-
"""Determine if caching should be disabled based on environment."""
|
32
|
-
# Always disable in DEBUG mode
|
33
|
-
if settings.DEBUG:
|
34
|
-
return True
|
35
|
-
|
36
|
-
# Check ENV_MODE if available
|
37
|
-
env_mode = getattr(settings, 'ENV_MODE', None)
|
38
|
-
if env_mode == EnvironmentMode.DEVELOPMENT or env_mode == EnvironmentMode.TEST:
|
39
|
-
return True
|
40
|
-
|
41
|
-
return False
|
42
|
-
|
43
|
-
def __call__(self, request):
|
44
|
-
response = self.get_response(request)
|
45
|
-
|
46
|
-
# Apply no-cache headers for static files in development
|
47
|
-
if self.should_disable_cache and request.path.startswith('/static/'):
|
48
|
-
response['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
|
49
|
-
response['Pragma'] = 'no-cache'
|
50
|
-
response['Expires'] = '0'
|
51
|
-
# Add ETag removal to prevent conditional requests
|
52
|
-
if 'ETag' in response:
|
53
|
-
del response['ETag']
|
54
|
-
|
55
|
-
return response
|
@@ -1,157 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import requests
|
3
|
-
import time
|
4
|
-
from datetime import datetime
|
5
|
-
from typing import Dict, Set, Optional
|
6
|
-
from cachetools import TTLCache
|
7
|
-
|
8
|
-
from ..core.models import Rate, YahooFinanceResponse
|
9
|
-
from ..core.exceptions import RateFetchError
|
10
|
-
|
11
|
-
logger = logging.getLogger(__name__)
|
12
|
-
|
13
|
-
|
14
|
-
class YahooFinanceClient:
|
15
|
-
"""Simple Yahoo Finance client without yfinance dependency."""
|
16
|
-
|
17
|
-
BASE_URL = "https://query1.finance.yahoo.com/v8/finance/chart"
|
18
|
-
|
19
|
-
def __init__(self, cache_ttl: int = 3600):
|
20
|
-
"""Initialize Yahoo Finance client with TTL cache."""
|
21
|
-
self._rate_cache = TTLCache(maxsize=500, ttl=cache_ttl)
|
22
|
-
self._session = requests.Session()
|
23
|
-
self._session.headers.update({
|
24
|
-
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
25
|
-
})
|
26
|
-
self._last_request_time = 0
|
27
|
-
self._rate_limit_delay = 1.0 # 1 second between requests
|
28
|
-
|
29
|
-
def _get_yahoo_symbol(self, base: str, quote: str) -> str:
|
30
|
-
"""Convert currency pair to Yahoo Finance symbol format."""
|
31
|
-
# Yahoo uses format like EURUSD=X for forex pairs
|
32
|
-
return f"{base}{quote}=X"
|
33
|
-
|
34
|
-
def fetch_rate(self, base: str, quote: str) -> Rate:
|
35
|
-
"""
|
36
|
-
Fetch forex rate from Yahoo Finance with caching.
|
37
|
-
|
38
|
-
Args:
|
39
|
-
base: Base currency code (e.g., EUR)
|
40
|
-
quote: Quote currency code (e.g., USD)
|
41
|
-
|
42
|
-
Returns:
|
43
|
-
Rate object with exchange rate data
|
44
|
-
|
45
|
-
Raises:
|
46
|
-
RateFetchError: If rate fetch fails
|
47
|
-
"""
|
48
|
-
base = base.upper()
|
49
|
-
quote = quote.upper()
|
50
|
-
cache_key = f"{base}_{quote}"
|
51
|
-
|
52
|
-
# Try cache first
|
53
|
-
if cache_key in self._rate_cache:
|
54
|
-
logger.debug(f"Retrieved rate {base}/{quote} from Yahoo cache")
|
55
|
-
return self._rate_cache[cache_key]
|
56
|
-
|
57
|
-
symbol = self._get_yahoo_symbol(base, quote)
|
58
|
-
|
59
|
-
# Rate limiting
|
60
|
-
current_time = time.time()
|
61
|
-
time_since_last_request = current_time - self._last_request_time
|
62
|
-
if time_since_last_request < self._rate_limit_delay:
|
63
|
-
sleep_time = self._rate_limit_delay - time_since_last_request
|
64
|
-
logger.debug(f"Rate limiting: sleeping for {sleep_time:.2f}s")
|
65
|
-
time.sleep(sleep_time)
|
66
|
-
|
67
|
-
try:
|
68
|
-
response = self._session.get(f"{self.BASE_URL}/{symbol}")
|
69
|
-
self._last_request_time = time.time()
|
70
|
-
response.raise_for_status()
|
71
|
-
|
72
|
-
raw_data = response.json()
|
73
|
-
|
74
|
-
# Validate response using Pydantic model
|
75
|
-
try:
|
76
|
-
yahoo_response = YahooFinanceResponse(**raw_data)
|
77
|
-
except Exception as e:
|
78
|
-
raise RateFetchError(f"Invalid Yahoo Finance response format: {e}")
|
79
|
-
|
80
|
-
if not yahoo_response.chart.result:
|
81
|
-
raise RateFetchError(f"No data returned for {symbol}")
|
82
|
-
|
83
|
-
meta = yahoo_response.chart.result[0].meta
|
84
|
-
rate_value = meta.regularMarketPrice
|
85
|
-
timestamp = datetime.fromtimestamp(meta.regularMarketTime)
|
86
|
-
|
87
|
-
rate = Rate(
|
88
|
-
source="yahoo",
|
89
|
-
base_currency=base,
|
90
|
-
quote_currency=quote,
|
91
|
-
rate=float(rate_value),
|
92
|
-
timestamp=timestamp
|
93
|
-
)
|
94
|
-
|
95
|
-
self._rate_cache[cache_key] = rate
|
96
|
-
logger.info(f"Fetched rate {base}/{quote} = {rate_value} from Yahoo Finance")
|
97
|
-
return rate
|
98
|
-
|
99
|
-
except requests.exceptions.RequestException as e:
|
100
|
-
logger.error(f"Failed to fetch rate from Yahoo Finance: {e}")
|
101
|
-
raise RateFetchError(f"Yahoo Finance API error: {e}")
|
102
|
-
except (KeyError, TypeError, ValueError) as e:
|
103
|
-
logger.error(f"Failed to parse Yahoo Finance response: {e}")
|
104
|
-
raise RateFetchError(f"Invalid response format: {e}")
|
105
|
-
except Exception as e:
|
106
|
-
logger.error(f"Unexpected error fetching from Yahoo Finance: {e}")
|
107
|
-
raise RateFetchError(f"Yahoo Finance fetch failed: {e}")
|
108
|
-
|
109
|
-
def supports_pair(self, base: str, quote: str) -> bool:
|
110
|
-
"""
|
111
|
-
Check if Yahoo Finance supports the given currency pair.
|
112
|
-
|
113
|
-
Yahoo Finance primarily supports major forex pairs.
|
114
|
-
"""
|
115
|
-
base = base.upper()
|
116
|
-
quote = quote.upper()
|
117
|
-
|
118
|
-
# Major currencies supported by Yahoo Finance
|
119
|
-
major_currencies = {
|
120
|
-
'USD', 'EUR', 'GBP', 'JPY', 'CHF', 'CAD', 'AUD', 'NZD',
|
121
|
-
'SEK', 'NOK', 'DKK', 'PLN', 'CZK', 'HUF', 'RUB', 'CNY',
|
122
|
-
'INR', 'KRW', 'SGD', 'HKD', 'THB', 'MXN', 'BRL', 'ZAR',
|
123
|
-
'TRY', 'ILS'
|
124
|
-
}
|
125
|
-
|
126
|
-
return base in major_currencies and quote in major_currencies
|
127
|
-
|
128
|
-
def get_all_supported_currencies(self) -> Dict[str, str]:
|
129
|
-
"""Get all major currencies supported by Yahoo Finance."""
|
130
|
-
return {
|
131
|
-
'USD': 'US Dollar',
|
132
|
-
'EUR': 'Euro',
|
133
|
-
'GBP': 'British Pound',
|
134
|
-
'JPY': 'Japanese Yen',
|
135
|
-
'CHF': 'Swiss Franc',
|
136
|
-
'CAD': 'Canadian Dollar',
|
137
|
-
'AUD': 'Australian Dollar',
|
138
|
-
'NZD': 'New Zealand Dollar',
|
139
|
-
'SEK': 'Swedish Krona',
|
140
|
-
'NOK': 'Norwegian Krone',
|
141
|
-
'DKK': 'Danish Krone',
|
142
|
-
'PLN': 'Polish Zloty',
|
143
|
-
'CZK': 'Czech Koruna',
|
144
|
-
'HUF': 'Hungarian Forint',
|
145
|
-
'RUB': 'Russian Ruble',
|
146
|
-
'CNY': 'Chinese Yuan',
|
147
|
-
'INR': 'Indian Rupee',
|
148
|
-
'KRW': 'South Korean Won',
|
149
|
-
'SGD': 'Singapore Dollar',
|
150
|
-
'HKD': 'Hong Kong Dollar',
|
151
|
-
'THB': 'Thai Baht',
|
152
|
-
'MXN': 'Mexican Peso',
|
153
|
-
'BRL': 'Brazilian Real',
|
154
|
-
'ZAR': 'South African Rand',
|
155
|
-
'TRY': 'Turkish Lira',
|
156
|
-
'ILS': 'Israeli Shekel'
|
157
|
-
}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|