django-cfg 1.3.7__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.
Files changed (251) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/__init__.py +24 -8
  3. django_cfg/apps/accounts/admin/activity_admin.py +146 -0
  4. django_cfg/apps/accounts/admin/filters.py +98 -22
  5. django_cfg/apps/accounts/admin/group_admin.py +86 -0
  6. django_cfg/apps/accounts/admin/inlines.py +42 -13
  7. django_cfg/apps/accounts/admin/otp_admin.py +115 -0
  8. django_cfg/apps/accounts/admin/registration_admin.py +173 -0
  9. django_cfg/apps/accounts/admin/resources.py +123 -19
  10. django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
  11. django_cfg/apps/accounts/admin/user_admin.py +362 -0
  12. django_cfg/apps/agents/admin/__init__.py +17 -4
  13. django_cfg/apps/agents/admin/execution_admin.py +204 -183
  14. django_cfg/apps/agents/admin/registry_admin.py +230 -255
  15. django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
  16. django_cfg/apps/agents/core/__init__.py +1 -1
  17. django_cfg/apps/agents/core/django_agent.py +221 -0
  18. django_cfg/apps/agents/core/exceptions.py +14 -0
  19. django_cfg/apps/agents/core/orchestrator.py +18 -3
  20. django_cfg/apps/knowbase/admin/__init__.py +1 -1
  21. django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
  22. django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
  23. django_cfg/apps/knowbase/admin/document_admin.py +269 -262
  24. django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
  25. django_cfg/apps/knowbase/config/settings.py +21 -4
  26. django_cfg/apps/knowbase/views/chat_views.py +3 -0
  27. django_cfg/apps/leads/admin/__init__.py +3 -1
  28. django_cfg/apps/leads/admin/leads_admin.py +235 -35
  29. django_cfg/apps/maintenance/admin/__init__.py +2 -2
  30. django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
  31. django_cfg/apps/maintenance/admin/log_admin.py +143 -61
  32. django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
  33. django_cfg/apps/maintenance/admin/site_admin.py +213 -352
  34. django_cfg/apps/newsletter/admin/__init__.py +29 -2
  35. django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
  36. django_cfg/apps/payments/admin/__init__.py +18 -27
  37. django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
  38. django_cfg/apps/payments/admin/balance_admin.py +166 -632
  39. django_cfg/apps/payments/admin/currencies_admin.py +235 -607
  40. django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
  41. django_cfg/apps/payments/admin/filters.py +83 -3
  42. django_cfg/apps/payments/admin/networks_admin.py +258 -0
  43. django_cfg/apps/payments/admin/payments_admin.py +171 -461
  44. django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
  45. django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
  46. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +105 -34
  47. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +12 -16
  48. django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
  49. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +13 -18
  50. django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
  51. django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
  52. django_cfg/apps/payments/middleware/api_access.py +32 -6
  53. django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +26 -0
  54. django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +28 -0
  55. django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +30 -0
  56. django_cfg/apps/payments/models/balance.py +12 -0
  57. django_cfg/apps/payments/models/currencies.py +106 -32
  58. django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
  59. django_cfg/apps/payments/services/core/currency_service.py +35 -28
  60. django_cfg/apps/payments/services/core/payment_service.py +1 -1
  61. django_cfg/apps/payments/services/providers/__init__.py +3 -0
  62. django_cfg/apps/payments/services/providers/base.py +95 -39
  63. django_cfg/apps/payments/services/providers/models/__init__.py +40 -0
  64. django_cfg/apps/payments/services/providers/models/base.py +122 -0
  65. django_cfg/apps/payments/services/providers/models/providers.py +87 -0
  66. django_cfg/apps/payments/services/providers/models/universal.py +48 -0
  67. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
  68. django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
  69. django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
  70. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
  71. django_cfg/apps/payments/services/providers/{nowpayments.py → nowpayments/provider.py} +240 -209
  72. django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
  73. django_cfg/apps/payments/services/providers/registry.py +4 -32
  74. django_cfg/apps/payments/services/providers/sync_service.py +277 -0
  75. django_cfg/apps/payments/static/payments/js/api-client.js +23 -5
  76. django_cfg/apps/payments/static/payments/js/payment-form.js +65 -8
  77. django_cfg/apps/payments/tasks/__init__.py +39 -0
  78. django_cfg/apps/payments/tasks/types.py +73 -0
  79. django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
  80. django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
  81. django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
  82. django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
  83. django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
  84. django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
  85. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
  86. django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
  87. django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
  88. django_cfg/apps/payments/urls_admin.py +1 -1
  89. django_cfg/apps/payments/views/api/currencies.py +5 -5
  90. django_cfg/apps/payments/views/overview/services.py +2 -2
  91. django_cfg/apps/payments/views/serializers/currencies.py +4 -3
  92. django_cfg/apps/support/admin/__init__.py +10 -1
  93. django_cfg/apps/support/admin/support_admin.py +338 -141
  94. django_cfg/apps/tasks/admin/__init__.py +11 -0
  95. django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
  96. django_cfg/config.py +1 -1
  97. django_cfg/core/config.py +10 -5
  98. django_cfg/core/generation.py +1 -1
  99. django_cfg/management/commands/__init__.py +13 -1
  100. django_cfg/management/commands/app_agent_diagnose.py +470 -0
  101. django_cfg/management/commands/app_agent_generate.py +342 -0
  102. django_cfg/management/commands/app_agent_info.py +308 -0
  103. django_cfg/management/commands/migrate_all.py +9 -3
  104. django_cfg/management/commands/migrator.py +11 -6
  105. django_cfg/management/commands/rundramatiq.py +3 -2
  106. django_cfg/middleware/__init__.py +0 -2
  107. django_cfg/models/api_keys.py +115 -0
  108. django_cfg/modules/django_admin/__init__.py +64 -0
  109. django_cfg/modules/django_admin/decorators/__init__.py +13 -0
  110. django_cfg/modules/django_admin/decorators/actions.py +106 -0
  111. django_cfg/modules/django_admin/decorators/display.py +106 -0
  112. django_cfg/modules/django_admin/mixins/__init__.py +14 -0
  113. django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
  114. django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
  115. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
  116. django_cfg/modules/django_admin/models/__init__.py +20 -0
  117. django_cfg/modules/django_admin/models/action_models.py +33 -0
  118. django_cfg/modules/django_admin/models/badge_models.py +20 -0
  119. django_cfg/modules/django_admin/models/base.py +26 -0
  120. django_cfg/modules/django_admin/models/display_models.py +31 -0
  121. django_cfg/modules/django_admin/utils/badges.py +159 -0
  122. django_cfg/modules/django_admin/utils/displays.py +247 -0
  123. django_cfg/modules/django_app_agent/__init__.py +87 -0
  124. django_cfg/modules/django_app_agent/agents/__init__.py +40 -0
  125. django_cfg/modules/django_app_agent/agents/base/__init__.py +24 -0
  126. django_cfg/modules/django_app_agent/agents/base/agent.py +354 -0
  127. django_cfg/modules/django_app_agent/agents/base/context.py +236 -0
  128. django_cfg/modules/django_app_agent/agents/base/executor.py +430 -0
  129. django_cfg/modules/django_app_agent/agents/generation/__init__.py +12 -0
  130. django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +15 -0
  131. django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +147 -0
  132. django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +99 -0
  133. django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +32 -0
  134. django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +290 -0
  135. django_cfg/modules/django_app_agent/agents/interfaces.py +376 -0
  136. django_cfg/modules/django_app_agent/core/__init__.py +33 -0
  137. django_cfg/modules/django_app_agent/core/config.py +300 -0
  138. django_cfg/modules/django_app_agent/core/exceptions.py +359 -0
  139. django_cfg/modules/django_app_agent/models/__init__.py +71 -0
  140. django_cfg/modules/django_app_agent/models/base.py +283 -0
  141. django_cfg/modules/django_app_agent/models/context.py +496 -0
  142. django_cfg/modules/django_app_agent/models/enums.py +481 -0
  143. django_cfg/modules/django_app_agent/models/requests.py +500 -0
  144. django_cfg/modules/django_app_agent/models/responses.py +585 -0
  145. django_cfg/modules/django_app_agent/pytest.ini +6 -0
  146. django_cfg/modules/django_app_agent/services/__init__.py +42 -0
  147. django_cfg/modules/django_app_agent/services/app_generator/__init__.py +30 -0
  148. django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +133 -0
  149. django_cfg/modules/django_app_agent/services/app_generator/context.py +40 -0
  150. django_cfg/modules/django_app_agent/services/app_generator/main.py +202 -0
  151. django_cfg/modules/django_app_agent/services/app_generator/structure.py +316 -0
  152. django_cfg/modules/django_app_agent/services/app_generator/validation.py +125 -0
  153. django_cfg/modules/django_app_agent/services/base.py +437 -0
  154. django_cfg/modules/django_app_agent/services/context_builder/__init__.py +34 -0
  155. django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +141 -0
  156. django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +276 -0
  157. django_cfg/modules/django_app_agent/services/context_builder/main.py +272 -0
  158. django_cfg/modules/django_app_agent/services/context_builder/models.py +40 -0
  159. django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +85 -0
  160. django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +31 -0
  161. django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +311 -0
  162. django_cfg/modules/django_app_agent/services/project_scanner/main.py +221 -0
  163. django_cfg/modules/django_app_agent/services/project_scanner/models.py +59 -0
  164. django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +94 -0
  165. django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +28 -0
  166. django_cfg/modules/django_app_agent/services/questioning_service/main.py +273 -0
  167. django_cfg/modules/django_app_agent/services/questioning_service/models.py +111 -0
  168. django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +251 -0
  169. django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +347 -0
  170. django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +356 -0
  171. django_cfg/modules/django_app_agent/services/report_service.py +332 -0
  172. django_cfg/modules/django_app_agent/services/template_manager/__init__.py +18 -0
  173. django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +236 -0
  174. django_cfg/modules/django_app_agent/services/template_manager/main.py +159 -0
  175. django_cfg/modules/django_app_agent/services/template_manager/models.py +36 -0
  176. django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +100 -0
  177. django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +105 -0
  178. django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +31 -0
  179. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +44 -0
  180. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +81 -0
  181. django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +107 -0
  182. django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +139 -0
  183. django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +91 -0
  184. django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +195 -0
  185. django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +35 -0
  186. django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +211 -0
  187. django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +200 -0
  188. django_cfg/modules/django_app_agent/services/validation_service/__init__.py +25 -0
  189. django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +333 -0
  190. django_cfg/modules/django_app_agent/services/validation_service/main.py +242 -0
  191. django_cfg/modules/django_app_agent/services/validation_service/models.py +66 -0
  192. django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +352 -0
  193. django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +272 -0
  194. django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +203 -0
  195. django_cfg/modules/django_app_agent/ui/__init__.py +25 -0
  196. django_cfg/modules/django_app_agent/ui/cli.py +419 -0
  197. django_cfg/modules/django_app_agent/ui/rich_components.py +622 -0
  198. django_cfg/modules/django_app_agent/utils/__init__.py +38 -0
  199. django_cfg/modules/django_app_agent/utils/logging.py +360 -0
  200. django_cfg/modules/django_app_agent/utils/validation.py +417 -0
  201. django_cfg/modules/django_currency/__init__.py +2 -2
  202. django_cfg/modules/django_currency/clients/__init__.py +2 -2
  203. django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
  204. django_cfg/modules/django_currency/core/converter.py +12 -12
  205. django_cfg/modules/django_currency/database/__init__.py +2 -2
  206. django_cfg/modules/django_currency/database/database_loader.py +93 -42
  207. django_cfg/modules/django_llm/llm/client.py +10 -2
  208. django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
  209. django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
  210. django_cfg/modules/django_unfold/dashboard.py +14 -13
  211. django_cfg/modules/django_unfold/models/config.py +1 -1
  212. django_cfg/registry/core.py +3 -0
  213. django_cfg/registry/third_party.py +2 -2
  214. django_cfg/template_archive/django_sample.zip +0 -0
  215. {django_cfg-1.3.7.dist-info → django_cfg-1.3.9.dist-info}/METADATA +2 -1
  216. {django_cfg-1.3.7.dist-info → django_cfg-1.3.9.dist-info}/RECORD +223 -117
  217. django_cfg/apps/accounts/admin/activity.py +0 -96
  218. django_cfg/apps/accounts/admin/group.py +0 -17
  219. django_cfg/apps/accounts/admin/otp.py +0 -59
  220. django_cfg/apps/accounts/admin/registration_source.py +0 -97
  221. django_cfg/apps/accounts/admin/twilio_response.py +0 -227
  222. django_cfg/apps/accounts/admin/user.py +0 -300
  223. django_cfg/apps/agents/core/agent.py +0 -281
  224. django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
  225. django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
  226. django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
  227. django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
  228. django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
  229. django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
  230. django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
  231. django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
  232. django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
  233. django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
  234. django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
  235. django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
  236. django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
  237. django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
  238. django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
  239. django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
  240. django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
  241. django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
  242. django_cfg/apps/tasks/admin.py +0 -320
  243. django_cfg/middleware/static_nocache.py +0 -55
  244. django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
  245. /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
  246. /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
  247. /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
  248. /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
  249. {django_cfg-1.3.7.dist-info → django_cfg-1.3.9.dist-info}/WHEEL +0 -0
  250. {django_cfg-1.3.7.dist-info → django_cfg-1.3.9.dist-info}/entry_points.txt +0 -0
  251. {django_cfg-1.3.7.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/config.py CHANGED
@@ -5,7 +5,7 @@ Configuration settings for the django-cfg library itself.
5
5
  """
6
6
 
7
7
  from typing import List
8
- from .modules.django_unfold.icons import Icons
8
+ from .modules.django_admin.icons import Icons
9
9
  from .modules.django_unfold.models.dropdown import SiteDropdownItem
10
10
 
11
11
 
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(1, "corsheaders.middleware.CorsMiddleware")
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())
@@ -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": 31536000, # 1 year
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
- # Django management commands
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
+ """