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
@@ -0,0 +1,430 @@
|
|
1
|
+
"""
|
2
|
+
Tasks admin interfaces using Django Admin Utilities.
|
3
|
+
|
4
|
+
Enhanced Dramatiq task management with Material Icons and optimized queries.
|
5
|
+
Only available if django-dramatiq is installed.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import logging
|
9
|
+
import subprocess
|
10
|
+
import sys
|
11
|
+
from typing import Dict, Any, Optional
|
12
|
+
from django.db.models import Count
|
13
|
+
from django.contrib import admin, messages
|
14
|
+
from django.contrib.admin.views.main import ChangeList
|
15
|
+
from django.http import JsonResponse
|
16
|
+
from django.urls import path
|
17
|
+
from django.views.decorators.csrf import csrf_exempt
|
18
|
+
from django.db import models
|
19
|
+
from django.db.models import Q
|
20
|
+
from unfold.admin import ModelAdmin
|
21
|
+
|
22
|
+
from django_cfg.modules.django_admin import (
|
23
|
+
OptimizedModelAdmin,
|
24
|
+
DisplayMixin,
|
25
|
+
StatusBadgeConfig,
|
26
|
+
DateTimeDisplayConfig,
|
27
|
+
Icons,
|
28
|
+
ActionVariant,
|
29
|
+
display,
|
30
|
+
action,
|
31
|
+
StandaloneActionsMixin,
|
32
|
+
standalone_action
|
33
|
+
)
|
34
|
+
from django_cfg.modules.django_admin.utils.badges import StatusBadge
|
35
|
+
from django_cfg.modules.django_tasks import DjangoTasks
|
36
|
+
|
37
|
+
# Try to import django-dramatiq components
|
38
|
+
try:
|
39
|
+
from django_dramatiq.models import Task
|
40
|
+
from django_dramatiq.admin import TaskAdmin as BaseDramatiqTaskAdmin
|
41
|
+
DRAMATIQ_AVAILABLE = True
|
42
|
+
except ImportError:
|
43
|
+
Task = None
|
44
|
+
BaseDramatiqTaskAdmin = None
|
45
|
+
DRAMATIQ_AVAILABLE = False
|
46
|
+
|
47
|
+
|
48
|
+
if DRAMATIQ_AVAILABLE:
|
49
|
+
|
50
|
+
class TaskQueueChangeList(ChangeList):
|
51
|
+
"""Custom changelist for task queue management."""
|
52
|
+
|
53
|
+
def __init__(self, *args, **kwargs):
|
54
|
+
super().__init__(*args, **kwargs)
|
55
|
+
self.tasks_service = DjangoTasks()
|
56
|
+
|
57
|
+
|
58
|
+
class TaskQueueAdminMixin(OptimizedModelAdmin, DisplayMixin, StandaloneActionsMixin):
|
59
|
+
"""Mixin for task queue management functionality."""
|
60
|
+
|
61
|
+
change_list_template = 'admin/tasks/taskqueue/change_list.html'
|
62
|
+
actions_list = ['start_workers', 'clear_queues', 'refresh_status']
|
63
|
+
|
64
|
+
def has_add_permission(self, request):
|
65
|
+
return False
|
66
|
+
|
67
|
+
def has_change_permission(self, request, obj=None):
|
68
|
+
return True
|
69
|
+
|
70
|
+
def has_delete_permission(self, request, obj=None):
|
71
|
+
return False
|
72
|
+
|
73
|
+
def get_changelist(self, request, **kwargs):
|
74
|
+
return TaskQueueChangeList
|
75
|
+
|
76
|
+
def changelist_view(self, request, extra_context=None):
|
77
|
+
"""Enhanced changelist with queue statistics."""
|
78
|
+
extra_context = extra_context or {}
|
79
|
+
|
80
|
+
try:
|
81
|
+
tasks_service = DjangoTasks()
|
82
|
+
|
83
|
+
# Queue statistics
|
84
|
+
total_tasks = Task.objects.count()
|
85
|
+
pending_tasks = Task.objects.filter(status='pending').count()
|
86
|
+
running_tasks = Task.objects.filter(status='running').count()
|
87
|
+
failed_tasks = Task.objects.filter(status='failed').count()
|
88
|
+
completed_tasks = Task.objects.filter(status='done').count()
|
89
|
+
|
90
|
+
# Queue status
|
91
|
+
queue_stats = tasks_service.get_queue_stats()
|
92
|
+
|
93
|
+
extra_context.update({
|
94
|
+
'queue_statistics': {
|
95
|
+
'total_tasks': total_tasks,
|
96
|
+
'pending_tasks': pending_tasks,
|
97
|
+
'running_tasks': running_tasks,
|
98
|
+
'failed_tasks': failed_tasks,
|
99
|
+
'completed_tasks': completed_tasks,
|
100
|
+
},
|
101
|
+
'queue_status': queue_stats,
|
102
|
+
'workers_running': tasks_service.are_workers_running(),
|
103
|
+
})
|
104
|
+
|
105
|
+
except Exception as e:
|
106
|
+
extra_context['queue_error'] = str(e)
|
107
|
+
|
108
|
+
return super().changelist_view(request, extra_context)
|
109
|
+
|
110
|
+
@display(description="Queue Status")
|
111
|
+
def queue_status_display(self, obj):
|
112
|
+
"""Display queue status with badge."""
|
113
|
+
return StatusBadge.create(
|
114
|
+
text="Active",
|
115
|
+
variant="success",
|
116
|
+
icon=Icons.PLAY_ARROW
|
117
|
+
)
|
118
|
+
|
119
|
+
@display(description="Worker Status")
|
120
|
+
def worker_status_display(self, obj):
|
121
|
+
"""Display worker status."""
|
122
|
+
return StatusBadge.create(
|
123
|
+
text="Running",
|
124
|
+
variant="info",
|
125
|
+
icon=Icons.SETTINGS
|
126
|
+
)
|
127
|
+
|
128
|
+
@display(description="Task Statistics")
|
129
|
+
def task_stats_display(self, obj):
|
130
|
+
"""Display task statistics."""
|
131
|
+
total = Task.objects.count()
|
132
|
+
pending = Task.objects.filter(status='pending').count()
|
133
|
+
return f"Total: {total}, Pending: {pending}"
|
134
|
+
|
135
|
+
@standalone_action(
|
136
|
+
description="Start Workers",
|
137
|
+
icon=Icons.PLAY_ARROW,
|
138
|
+
variant=ActionVariant.SUCCESS,
|
139
|
+
background=True,
|
140
|
+
success_message="Workers started successfully!",
|
141
|
+
error_message="Failed to start workers."
|
142
|
+
)
|
143
|
+
def start_workers(self, request):
|
144
|
+
"""Start Dramatiq workers."""
|
145
|
+
try:
|
146
|
+
tasks_service = DjangoTasks()
|
147
|
+
tasks_service.start_workers()
|
148
|
+
return True
|
149
|
+
except Exception as e:
|
150
|
+
logging.error(f"Failed to start workers: {e}")
|
151
|
+
return False
|
152
|
+
|
153
|
+
@standalone_action(
|
154
|
+
description="Clear Queues",
|
155
|
+
icon=Icons.CLEAR_ALL,
|
156
|
+
variant=ActionVariant.WARNING,
|
157
|
+
background=True,
|
158
|
+
success_message="Queues cleared successfully!",
|
159
|
+
error_message="Failed to clear queues."
|
160
|
+
)
|
161
|
+
def clear_queues(self, request):
|
162
|
+
"""Clear all task queues."""
|
163
|
+
try:
|
164
|
+
tasks_service = DjangoTasks()
|
165
|
+
tasks_service.clear_queues()
|
166
|
+
return True
|
167
|
+
except Exception as e:
|
168
|
+
logging.error(f"Failed to clear queues: {e}")
|
169
|
+
return False
|
170
|
+
|
171
|
+
@standalone_action(
|
172
|
+
description="Refresh Status",
|
173
|
+
icon=Icons.REFRESH,
|
174
|
+
variant=ActionVariant.INFO,
|
175
|
+
success_message="Status refreshed!",
|
176
|
+
error_message="Failed to refresh status."
|
177
|
+
)
|
178
|
+
def refresh_status(self, request):
|
179
|
+
"""Refresh queue status."""
|
180
|
+
return True
|
181
|
+
|
182
|
+
|
183
|
+
# Unregister the default TaskAdmin and register our enhanced version
|
184
|
+
try:
|
185
|
+
admin.site.unregister(Task)
|
186
|
+
except admin.sites.NotRegistered:
|
187
|
+
pass
|
188
|
+
|
189
|
+
@admin.register(Task)
|
190
|
+
class TaskAdmin(TaskQueueAdminMixin, ModelAdmin):
|
191
|
+
"""Enhanced admin for Dramatiq Task model with queue management functionality."""
|
192
|
+
|
193
|
+
list_display = [
|
194
|
+
'id_display', 'actor_name_display', 'status_display',
|
195
|
+
'queue_name_display', 'created_at_display'
|
196
|
+
]
|
197
|
+
|
198
|
+
list_filter = [
|
199
|
+
'status', 'queue_name', 'actor_name',
|
200
|
+
'created_at', 'updated_at'
|
201
|
+
]
|
202
|
+
|
203
|
+
search_fields = ['actor_name', 'queue_name', 'message_id']
|
204
|
+
|
205
|
+
readonly_fields = [
|
206
|
+
'id_display', 'actor_name', 'queue_name',
|
207
|
+
'args_preview', 'kwargs_preview', 'result_preview',
|
208
|
+
'created_at_display', 'started_at_display', 'finished_at_display',
|
209
|
+
'duration_display', 'retries_display', 'error_message_display'
|
210
|
+
]
|
211
|
+
|
212
|
+
fieldsets = (
|
213
|
+
('Task Information', {
|
214
|
+
'fields': ('id_display', 'status', 'actor_name', 'queue_name')
|
215
|
+
}),
|
216
|
+
('Execution Details', {
|
217
|
+
'fields': ('args_preview', 'kwargs_preview', 'result_preview', 'error_message_display')
|
218
|
+
}),
|
219
|
+
('Timing', {
|
220
|
+
'fields': ('created_at_display', 'started_at_display', 'finished_at_display', 'duration_display')
|
221
|
+
}),
|
222
|
+
('Retry Information', {
|
223
|
+
'fields': ('retries_display',)
|
224
|
+
}),
|
225
|
+
)
|
226
|
+
|
227
|
+
actions = ['retry_failed_tasks', 'cancel_pending_tasks']
|
228
|
+
|
229
|
+
def changelist_view(self, request, extra_context=None):
|
230
|
+
"""Enhanced changelist with task statistics."""
|
231
|
+
extra_context = extra_context or {}
|
232
|
+
|
233
|
+
try:
|
234
|
+
# Task statistics
|
235
|
+
total_tasks = self.get_queryset(request).count()
|
236
|
+
status_stats = self.get_queryset(request).values('status').annotate(
|
237
|
+
count=Count('id')
|
238
|
+
).order_by('status')
|
239
|
+
|
240
|
+
# Actor statistics
|
241
|
+
actor_stats = self.get_queryset(request).values('actor_name').annotate(
|
242
|
+
count=Count('id')
|
243
|
+
).order_by('-count')[:10]
|
244
|
+
|
245
|
+
# Queue statistics
|
246
|
+
queue_stats = self.get_queryset(request).values('queue_name').annotate(
|
247
|
+
count=Count('id')
|
248
|
+
).order_by('-count')
|
249
|
+
|
250
|
+
extra_context.update({
|
251
|
+
'task_statistics': {
|
252
|
+
'total_tasks': total_tasks,
|
253
|
+
'status_distribution': list(status_stats),
|
254
|
+
'top_actors': list(actor_stats),
|
255
|
+
'queue_distribution': list(queue_stats),
|
256
|
+
}
|
257
|
+
})
|
258
|
+
|
259
|
+
except Exception as e:
|
260
|
+
extra_context['task_error'] = str(e)
|
261
|
+
|
262
|
+
return super().changelist_view(request, extra_context)
|
263
|
+
|
264
|
+
@display(description="Task ID")
|
265
|
+
def id_display(self, obj):
|
266
|
+
"""Display task ID with icon."""
|
267
|
+
return StatusBadge.create(
|
268
|
+
text=str(obj.id),
|
269
|
+
variant="info",
|
270
|
+
icon=Icons.TAG
|
271
|
+
)
|
272
|
+
|
273
|
+
@display(description="Actor")
|
274
|
+
def actor_name_display(self, obj):
|
275
|
+
"""Display actor name with icon."""
|
276
|
+
return StatusBadge.create(
|
277
|
+
text=obj.actor_name or "Unknown",
|
278
|
+
variant="default",
|
279
|
+
icon=Icons.FUNCTIONS
|
280
|
+
)
|
281
|
+
|
282
|
+
@display(description="Status")
|
283
|
+
def status_display(self, obj):
|
284
|
+
"""Display task status with appropriate badge."""
|
285
|
+
status_variants = {
|
286
|
+
'pending': 'warning',
|
287
|
+
'running': 'info',
|
288
|
+
'done': 'success',
|
289
|
+
'failed': 'danger',
|
290
|
+
'cancelled': 'secondary'
|
291
|
+
}
|
292
|
+
|
293
|
+
status_icons = {
|
294
|
+
'pending': Icons.SCHEDULE,
|
295
|
+
'running': Icons.PLAY_ARROW,
|
296
|
+
'done': Icons.CHECK_CIRCLE,
|
297
|
+
'failed': Icons.ERROR,
|
298
|
+
'cancelled': Icons.CANCEL
|
299
|
+
}
|
300
|
+
|
301
|
+
return StatusBadge.create(
|
302
|
+
text=obj.status.title(),
|
303
|
+
variant=status_variants.get(obj.status, 'default'),
|
304
|
+
icon=status_icons.get(obj.status, Icons.HELP)
|
305
|
+
)
|
306
|
+
|
307
|
+
@display(description="Queue")
|
308
|
+
def queue_name_display(self, obj):
|
309
|
+
"""Display queue name."""
|
310
|
+
return StatusBadge.create(
|
311
|
+
text=obj.queue_name or "default",
|
312
|
+
variant="info",
|
313
|
+
icon=Icons.QUEUE
|
314
|
+
)
|
315
|
+
|
316
|
+
@display(description="Created")
|
317
|
+
def created_at_display(self, obj):
|
318
|
+
"""Display creation time."""
|
319
|
+
return self.display_datetime_relative(obj.created_at)
|
320
|
+
|
321
|
+
@display(description="Started")
|
322
|
+
def started_at_display(self, obj):
|
323
|
+
"""Display start time."""
|
324
|
+
if obj.started_at:
|
325
|
+
return self.display_datetime_relative(obj.started_at)
|
326
|
+
return "Not started"
|
327
|
+
|
328
|
+
@display(description="Finished")
|
329
|
+
def finished_at_display(self, obj):
|
330
|
+
"""Display finish time."""
|
331
|
+
if obj.finished_at:
|
332
|
+
return self.display_datetime_relative(obj.finished_at)
|
333
|
+
return "Not finished"
|
334
|
+
|
335
|
+
@display(description="Duration")
|
336
|
+
def duration_display(self, obj):
|
337
|
+
"""Display task duration."""
|
338
|
+
if obj.started_at and obj.finished_at:
|
339
|
+
duration = obj.finished_at - obj.started_at
|
340
|
+
return f"{duration.total_seconds():.2f}s"
|
341
|
+
return "N/A"
|
342
|
+
|
343
|
+
@display(description="Retries")
|
344
|
+
def retries_display(self, obj):
|
345
|
+
"""Display retry count."""
|
346
|
+
retries = getattr(obj, 'retries', 0)
|
347
|
+
if retries > 0:
|
348
|
+
return StatusBadge.create(
|
349
|
+
text=str(retries),
|
350
|
+
variant="warning",
|
351
|
+
icon=Icons.REFRESH
|
352
|
+
)
|
353
|
+
return "0"
|
354
|
+
|
355
|
+
@display(description="Error")
|
356
|
+
def error_message_display(self, obj):
|
357
|
+
"""Display error message preview."""
|
358
|
+
if hasattr(obj, 'error') and obj.error:
|
359
|
+
error_text = str(obj.error)
|
360
|
+
if len(error_text) > 100:
|
361
|
+
error_text = error_text[:100] + "..."
|
362
|
+
return error_text
|
363
|
+
return "No error"
|
364
|
+
|
365
|
+
@display(description="Arguments")
|
366
|
+
def args_preview(self, obj):
|
367
|
+
"""Display task arguments preview."""
|
368
|
+
if hasattr(obj, 'args') and obj.args:
|
369
|
+
args_text = str(obj.args)
|
370
|
+
if len(args_text) > 100:
|
371
|
+
args_text = args_text[:100] + "..."
|
372
|
+
return args_text
|
373
|
+
return "No arguments"
|
374
|
+
|
375
|
+
@display(description="Keyword Arguments")
|
376
|
+
def kwargs_preview(self, obj):
|
377
|
+
"""Display task keyword arguments preview."""
|
378
|
+
if hasattr(obj, 'kwargs') and obj.kwargs:
|
379
|
+
kwargs_text = str(obj.kwargs)
|
380
|
+
if len(kwargs_text) > 100:
|
381
|
+
kwargs_text = kwargs_text[:100] + "..."
|
382
|
+
return kwargs_text
|
383
|
+
return "No kwargs"
|
384
|
+
|
385
|
+
@display(description="Result")
|
386
|
+
def result_preview(self, obj):
|
387
|
+
"""Display task result preview."""
|
388
|
+
if hasattr(obj, 'result') and obj.result:
|
389
|
+
result_text = str(obj.result)
|
390
|
+
if len(result_text) > 100:
|
391
|
+
result_text = result_text[:100] + "..."
|
392
|
+
return result_text
|
393
|
+
return "No result"
|
394
|
+
|
395
|
+
@action(description="Retry Failed Tasks", variant=ActionVariant.WARNING)
|
396
|
+
def retry_failed_tasks(self, request, queryset):
|
397
|
+
"""Retry selected failed tasks."""
|
398
|
+
failed_tasks = queryset.filter(status='failed')
|
399
|
+
count = failed_tasks.count()
|
400
|
+
|
401
|
+
if count > 0:
|
402
|
+
# Here you would implement the retry logic
|
403
|
+
messages.success(request, f"Queued {count} tasks for retry.")
|
404
|
+
else:
|
405
|
+
messages.warning(request, "No failed tasks selected.")
|
406
|
+
|
407
|
+
@action(description="Cancel Pending Tasks", variant=ActionVariant.DANGER)
|
408
|
+
def cancel_pending_tasks(self, request, queryset):
|
409
|
+
"""Cancel selected pending tasks."""
|
410
|
+
pending_tasks = queryset.filter(status='pending')
|
411
|
+
count = pending_tasks.count()
|
412
|
+
|
413
|
+
if count > 0:
|
414
|
+
pending_tasks.update(status='cancelled')
|
415
|
+
messages.success(request, f"Cancelled {count} pending tasks.")
|
416
|
+
else:
|
417
|
+
messages.warning(request, "No pending tasks selected.")
|
418
|
+
|
419
|
+
|
420
|
+
# TaskQueueAdminMixin provides queue management functionality to TaskAdmin
|
421
|
+
|
422
|
+
else:
|
423
|
+
# If django-dramatiq is not available, create empty admin classes
|
424
|
+
class TaskQueueAdmin:
|
425
|
+
"""Placeholder when django-dramatiq is not available."""
|
426
|
+
pass
|
427
|
+
|
428
|
+
class TaskAdmin:
|
429
|
+
"""Placeholder when django-dramatiq is not available."""
|
430
|
+
pass
|
django_cfg/apps/urls.py
CHANGED
@@ -52,8 +52,7 @@ def get_django_cfg_urlpatterns() -> List[URLPattern]:
|
|
52
52
|
# if base_module.is_maintenance_enabled():
|
53
53
|
# patterns.append(path('admin/django_cfg_maintenance/', include('django_cfg.apps.maintenance.urls_admin')))
|
54
54
|
|
55
|
-
|
56
|
-
if True:
|
55
|
+
if base_module.is_payments_enabled():
|
57
56
|
patterns.append(path('admin/django_cfg_payments/admin/', include('django_cfg.apps.payments.urls_admin')))
|
58
57
|
|
59
58
|
except Exception:
|
django_cfg/config.py
CHANGED
django_cfg/core/config.py
CHANGED
@@ -19,13 +19,15 @@ from urllib.parse import urlparse
|
|
19
19
|
from django_cfg import (
|
20
20
|
ConfigurationError, ValidationError, EnvironmentError,
|
21
21
|
DatabaseConfig, CacheConfig, EmailConfig, TelegramConfig,
|
22
|
-
UnfoldConfig, DRFConfig, SpectacularConfig, LimitsConfig
|
22
|
+
UnfoldConfig, DRFConfig, SpectacularConfig, LimitsConfig, ApiKeys
|
23
23
|
)
|
24
24
|
from django_cfg.models.tasks import TaskConfig
|
25
25
|
from django_cfg.models.payments import PaymentsConfig
|
26
26
|
|
27
27
|
# Default apps
|
28
28
|
DEFAULT_APPS = [
|
29
|
+
# WhiteNoise for static files (must be before django.contrib.staticfiles)
|
30
|
+
"whitenoise.runserver_nostatic",
|
29
31
|
# Unfold
|
30
32
|
"unfold",
|
31
33
|
"unfold.contrib.filters", # optional, if special filters are needed
|
@@ -329,6 +331,12 @@ class DjangoConfig(BaseModel):
|
|
329
331
|
description="Application limits configuration (file uploads, requests, etc.)",
|
330
332
|
)
|
331
333
|
|
334
|
+
# === API Keys Configuration ===
|
335
|
+
api_keys: Optional[ApiKeys] = Field(
|
336
|
+
default=None,
|
337
|
+
description="API keys for external services (OpenAI, OpenRouter, etc.)",
|
338
|
+
)
|
339
|
+
|
332
340
|
# === Middleware Configuration ===
|
333
341
|
custom_middleware: List[str] = Field(
|
334
342
|
default_factory=list,
|
@@ -776,15 +784,12 @@ class DjangoConfig(BaseModel):
|
|
776
784
|
|
777
785
|
# Add CORS middleware if security domains are configured
|
778
786
|
if self.security_domains:
|
779
|
-
middleware.insert(
|
787
|
+
middleware.insert(2, "corsheaders.middleware.CorsMiddleware") # Insert after WhiteNoise
|
780
788
|
|
781
789
|
# Add Django CFG middleware based on enabled features
|
782
790
|
if self.enable_accounts:
|
783
791
|
middleware.append("django_cfg.middleware.UserActivityMiddleware")
|
784
792
|
|
785
|
-
# Add static no-cache middleware (auto-detects development mode)
|
786
|
-
middleware.append("django_cfg.middleware.StaticNoCacheMiddleware")
|
787
|
-
|
788
793
|
# Add payments middleware if enabled
|
789
794
|
if self.payments and self.payments.enabled:
|
790
795
|
middleware.extend(self.payments.get_middleware_classes())
|
django_cfg/core/generation.py
CHANGED
@@ -332,7 +332,7 @@ class SettingsGenerator:
|
|
332
332
|
"STATICFILES_STORAGE": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
333
333
|
"WHITENOISE_USE_FINDERS": True,
|
334
334
|
"WHITENOISE_AUTOREFRESH": config.debug,
|
335
|
-
"WHITENOISE_MAX_AGE":
|
335
|
+
"WHITENOISE_MAX_AGE": 0 if config.debug else 3600, # No cache in debug, 1 hour
|
336
336
|
}
|
337
337
|
|
338
338
|
# Set paths relative to base directory
|
@@ -1 +1,13 @@
|
|
1
|
-
|
1
|
+
"""
|
2
|
+
Django management commands for django-cfg.
|
3
|
+
|
4
|
+
This package contains all Django management commands including:
|
5
|
+
|
6
|
+
Django App Agent Commands:
|
7
|
+
- app_agent_generate: Generate Django applications with AI assistance
|
8
|
+
- app_agent_diagnose: Diagnose problems in Django/Django-cfg projects
|
9
|
+
- app_agent_info: Show information about Django App Agent capabilities
|
10
|
+
|
11
|
+
Other Commands:
|
12
|
+
- Various utility and maintenance commands
|
13
|
+
"""
|