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.
- 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/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.7.dist-info → django_cfg-1.3.9.dist-info}/METADATA +2 -1
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.9.dist-info}/RECORD +223 -117
- 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.7.dist-info → django_cfg-1.3.9.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.9.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.9.dist-info}/licenses/LICENSE +0 -0
@@ -1,300 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
User admin configuration.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from django.contrib import admin
|
6
|
-
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
7
|
-
from django.utils.html import format_html
|
8
|
-
from django.contrib.humanize.templatetags.humanize import naturaltime, naturalday
|
9
|
-
from django.shortcuts import redirect
|
10
|
-
from django.urls import reverse
|
11
|
-
from unfold.admin import ModelAdmin
|
12
|
-
from unfold.forms import AdminPasswordChangeForm, UserChangeForm, UserCreationForm
|
13
|
-
from unfold.decorators import action
|
14
|
-
from unfold.enums import ActionVariant
|
15
|
-
from django_cfg import ImportExportModelAdmin
|
16
|
-
|
17
|
-
from ..models import CustomUser
|
18
|
-
from .filters import UserStatusFilter
|
19
|
-
from .inlines import UserRegistrationSourceInline, UserActivityInline, UserEmailLogInline, UserSupportTicketsInline
|
20
|
-
from .resources import CustomUserResource
|
21
|
-
|
22
|
-
|
23
|
-
@admin.register(CustomUser)
|
24
|
-
class CustomUserAdmin(BaseUserAdmin, ModelAdmin, ImportExportModelAdmin):
|
25
|
-
# Import/Export configuration
|
26
|
-
resource_class = CustomUserResource
|
27
|
-
|
28
|
-
# Forms loaded from `unfold.forms`
|
29
|
-
form = UserChangeForm
|
30
|
-
add_form = UserCreationForm
|
31
|
-
change_password_form = AdminPasswordChangeForm
|
32
|
-
|
33
|
-
list_display = [
|
34
|
-
"avatar",
|
35
|
-
"email",
|
36
|
-
"full_name",
|
37
|
-
"status",
|
38
|
-
"sources_count",
|
39
|
-
"activity_count",
|
40
|
-
"emails_count",
|
41
|
-
"tickets_count",
|
42
|
-
"last_login_display",
|
43
|
-
"date_joined_display",
|
44
|
-
]
|
45
|
-
list_display_links = ["avatar", "email", "full_name"]
|
46
|
-
search_fields = ["email", "first_name", "last_name"]
|
47
|
-
list_filter = [UserStatusFilter, "is_staff", "is_active", "date_joined"]
|
48
|
-
ordering = ["-date_joined"]
|
49
|
-
readonly_fields = ["date_joined", "last_login"]
|
50
|
-
def get_inlines(self, request, obj):
|
51
|
-
"""Get inlines based on enabled apps."""
|
52
|
-
inlines = [UserRegistrationSourceInline, UserActivityInline]
|
53
|
-
|
54
|
-
# Add email log inline if newsletter app is enabled
|
55
|
-
try:
|
56
|
-
from django_cfg.modules.base import BaseCfgModule
|
57
|
-
base_module = BaseCfgModule()
|
58
|
-
if base_module.is_newsletter_enabled():
|
59
|
-
inlines.append(UserEmailLogInline)
|
60
|
-
if base_module.is_support_enabled():
|
61
|
-
inlines.append(UserSupportTicketsInline)
|
62
|
-
except Exception:
|
63
|
-
pass
|
64
|
-
|
65
|
-
return inlines
|
66
|
-
|
67
|
-
# Static actions for Unfold - always show, but check inside methods
|
68
|
-
actions_detail = ["view_user_emails", "view_user_tickets"]
|
69
|
-
|
70
|
-
fieldsets = (
|
71
|
-
(
|
72
|
-
"Personal Information",
|
73
|
-
{
|
74
|
-
"fields": ("email", "first_name", "last_name", "avatar"),
|
75
|
-
},
|
76
|
-
),
|
77
|
-
(
|
78
|
-
"Contact Information",
|
79
|
-
{
|
80
|
-
"fields": ("company", "phone", "position"),
|
81
|
-
},
|
82
|
-
),
|
83
|
-
(
|
84
|
-
"Authentication",
|
85
|
-
{
|
86
|
-
"fields": ("password",),
|
87
|
-
"classes": ("collapse",),
|
88
|
-
},
|
89
|
-
),
|
90
|
-
(
|
91
|
-
"Permissions & Status",
|
92
|
-
{
|
93
|
-
"fields": (
|
94
|
-
("is_active", "is_staff", "is_superuser"),
|
95
|
-
("groups",),
|
96
|
-
("user_permissions",),
|
97
|
-
),
|
98
|
-
},
|
99
|
-
),
|
100
|
-
(
|
101
|
-
"Important Dates",
|
102
|
-
{
|
103
|
-
"fields": ("last_login", "date_joined"),
|
104
|
-
"classes": ("collapse",),
|
105
|
-
},
|
106
|
-
),
|
107
|
-
)
|
108
|
-
|
109
|
-
add_fieldsets = (
|
110
|
-
(
|
111
|
-
None,
|
112
|
-
{
|
113
|
-
"classes": ("wide",),
|
114
|
-
"fields": ("email", "password1", "password2"),
|
115
|
-
},
|
116
|
-
),
|
117
|
-
)
|
118
|
-
|
119
|
-
def full_name(self, obj):
|
120
|
-
"""Get user's full name."""
|
121
|
-
return obj.__class__.objects.get_full_name(obj) or "—"
|
122
|
-
|
123
|
-
full_name.short_description = "Full Name"
|
124
|
-
|
125
|
-
def status(self, obj):
|
126
|
-
"""Enhanced status display with icons."""
|
127
|
-
if obj.is_superuser:
|
128
|
-
return format_html('<span style="color: #dc3545;">👑 Superuser</span>')
|
129
|
-
elif obj.is_staff:
|
130
|
-
return format_html('<span style="color: #fd7e14;">⚙️ Staff</span>')
|
131
|
-
elif obj.is_active:
|
132
|
-
return format_html('<span style="color: #198754;">✅ Active</span>')
|
133
|
-
else:
|
134
|
-
return format_html('<span style="color: #6c757d;">❌ Inactive</span>')
|
135
|
-
|
136
|
-
status.short_description = "Status"
|
137
|
-
|
138
|
-
def sources_count(self, obj):
|
139
|
-
"""Show count of sources for user."""
|
140
|
-
count = obj.user_registration_sources.count()
|
141
|
-
if count == 0:
|
142
|
-
return "—"
|
143
|
-
return f"{count} source{'s' if count != 1 else ''}"
|
144
|
-
|
145
|
-
sources_count.short_description = "Sources"
|
146
|
-
|
147
|
-
def activity_count(self, obj):
|
148
|
-
"""Show count of user activities."""
|
149
|
-
count = obj.activities.count()
|
150
|
-
if count == 0:
|
151
|
-
return "—"
|
152
|
-
return f"{count} activit{'ies' if count != 1 else 'y'}"
|
153
|
-
|
154
|
-
activity_count.short_description = "Activities"
|
155
|
-
|
156
|
-
def emails_count(self, obj):
|
157
|
-
"""Show count of emails sent to user (if newsletter app is enabled)."""
|
158
|
-
try:
|
159
|
-
from django_cfg.modules.base import BaseCfgModule
|
160
|
-
base_module = BaseCfgModule()
|
161
|
-
|
162
|
-
if not base_module.is_newsletter_enabled():
|
163
|
-
return "—"
|
164
|
-
|
165
|
-
from django_cfg.apps.newsletter.models import EmailLog
|
166
|
-
count = EmailLog.objects.filter(user=obj).count()
|
167
|
-
if count == 0:
|
168
|
-
return "—"
|
169
|
-
return f"{count} email{'s' if count != 1 else ''}"
|
170
|
-
except (ImportError, Exception):
|
171
|
-
return "—"
|
172
|
-
|
173
|
-
emails_count.short_description = "Emails"
|
174
|
-
|
175
|
-
def tickets_count(self, obj):
|
176
|
-
"""Show count of support tickets for user (if support app is enabled)."""
|
177
|
-
try:
|
178
|
-
from django_cfg.modules.base import BaseCfgModule
|
179
|
-
base_module = BaseCfgModule()
|
180
|
-
|
181
|
-
if not base_module.is_support_enabled():
|
182
|
-
return "—"
|
183
|
-
|
184
|
-
from django_cfg.apps.support.models import Ticket
|
185
|
-
count = Ticket.objects.filter(user=obj).count()
|
186
|
-
if count == 0:
|
187
|
-
return "—"
|
188
|
-
return f"{count} ticket{'s' if count != 1 else ''}"
|
189
|
-
except (ImportError, Exception):
|
190
|
-
return "—"
|
191
|
-
|
192
|
-
tickets_count.short_description = "Tickets"
|
193
|
-
|
194
|
-
def last_login_display(self, obj):
|
195
|
-
"""Last login with natural time."""
|
196
|
-
if obj.last_login:
|
197
|
-
return naturaltime(obj.last_login)
|
198
|
-
return "Never"
|
199
|
-
|
200
|
-
last_login_display.short_description = "Last Login"
|
201
|
-
|
202
|
-
def date_joined_display(self, obj):
|
203
|
-
"""Join date with natural day."""
|
204
|
-
return naturalday(obj.date_joined)
|
205
|
-
|
206
|
-
date_joined_display.short_description = "Joined"
|
207
|
-
|
208
|
-
def avatar(self, obj):
|
209
|
-
"""Enhanced avatar display."""
|
210
|
-
if obj.avatar:
|
211
|
-
return format_html(
|
212
|
-
'<img src="{}" style="width: 32px; height: 32px; border-radius: 50%; object-fit: cover;" />',
|
213
|
-
obj.avatar.url,
|
214
|
-
)
|
215
|
-
else:
|
216
|
-
initials = obj.__class__.objects.get_initials(obj)
|
217
|
-
return format_html(
|
218
|
-
'<div style="width: 32px; height: 32px; border-radius: 50%; background: #6c757d; '
|
219
|
-
"color: white; display: flex; align-items: center; justify-content: center; "
|
220
|
-
'font-weight: bold; font-size: 12px;">{}</div>',
|
221
|
-
initials,
|
222
|
-
)
|
223
|
-
|
224
|
-
avatar.short_description = "Avatar"
|
225
|
-
|
226
|
-
@action(
|
227
|
-
description="📧 View Email History",
|
228
|
-
icon="mail_outline",
|
229
|
-
variant=ActionVariant.INFO
|
230
|
-
)
|
231
|
-
def view_user_emails(self, request, object_id):
|
232
|
-
"""View all emails sent to this user."""
|
233
|
-
try:
|
234
|
-
# Get the user object
|
235
|
-
user = self.get_object(request, object_id)
|
236
|
-
if not user:
|
237
|
-
self.message_user(request, "User not found.", level='error')
|
238
|
-
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|
239
|
-
|
240
|
-
# Check if newsletter app is enabled
|
241
|
-
from django_cfg.modules.base import BaseCfgModule
|
242
|
-
base_module = BaseCfgModule()
|
243
|
-
|
244
|
-
if not base_module.is_newsletter_enabled():
|
245
|
-
self.message_user(
|
246
|
-
request,
|
247
|
-
"Newsletter app is not enabled.",
|
248
|
-
level='warning'
|
249
|
-
)
|
250
|
-
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|
251
|
-
|
252
|
-
# Redirect to EmailLog changelist filtered by this user
|
253
|
-
url = reverse('admin:django_cfg_newsletter_emaillog_changelist')
|
254
|
-
return redirect(f"{url}?user__id__exact={user.id}")
|
255
|
-
|
256
|
-
except Exception as e:
|
257
|
-
self.message_user(
|
258
|
-
request,
|
259
|
-
f"Error accessing email history: {e}",
|
260
|
-
level='error'
|
261
|
-
)
|
262
|
-
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|
263
|
-
|
264
|
-
@action(
|
265
|
-
description="🎫 View Support Tickets",
|
266
|
-
icon="support_agent",
|
267
|
-
variant=ActionVariant.SUCCESS
|
268
|
-
)
|
269
|
-
def view_user_tickets(self, request, object_id):
|
270
|
-
"""View all support tickets for this user."""
|
271
|
-
try:
|
272
|
-
# Get the user object
|
273
|
-
user = self.get_object(request, object_id)
|
274
|
-
if not user:
|
275
|
-
self.message_user(request, "User not found.", level='error')
|
276
|
-
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|
277
|
-
|
278
|
-
# Check if support app is enabled
|
279
|
-
from django_cfg.modules.base import BaseCfgModule
|
280
|
-
base_module = BaseCfgModule()
|
281
|
-
|
282
|
-
if not base_module.is_support_enabled():
|
283
|
-
self.message_user(
|
284
|
-
request,
|
285
|
-
"Support app is not enabled.",
|
286
|
-
level='warning'
|
287
|
-
)
|
288
|
-
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|
289
|
-
|
290
|
-
# Redirect to Ticket changelist filtered by this user
|
291
|
-
url = reverse('admin:django_cfg_support_ticket_changelist')
|
292
|
-
return redirect(f"{url}?user__id__exact={user.id}")
|
293
|
-
|
294
|
-
except Exception as e:
|
295
|
-
self.message_user(
|
296
|
-
request,
|
297
|
-
f"Error accessing support tickets: {e}",
|
298
|
-
level='error'
|
299
|
-
)
|
300
|
-
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|
@@ -1,281 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Django Agent - Wrapper around Pydantic AI Agent with Django integration.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import time
|
6
|
-
import logging
|
7
|
-
from typing import TypeVar, Generic, Type, Any, Optional, Dict, Callable
|
8
|
-
from dataclasses import dataclass
|
9
|
-
|
10
|
-
from pydantic_ai import Agent
|
11
|
-
from pydantic_ai.models import Model
|
12
|
-
|
13
|
-
from .exceptions import ExecutionError, ConfigurationError
|
14
|
-
from .models import ExecutionResult
|
15
|
-
|
16
|
-
# Type variables for generic typing
|
17
|
-
DepsT = TypeVar('DepsT')
|
18
|
-
OutputT = TypeVar('OutputT')
|
19
|
-
|
20
|
-
logger = logging.getLogger(__name__)
|
21
|
-
|
22
|
-
|
23
|
-
class DjangoAgent(Generic[DepsT, OutputT]):
|
24
|
-
"""
|
25
|
-
Django-integrated agent wrapper around Pydantic AI Agent.
|
26
|
-
|
27
|
-
Provides Django-specific functionality like:
|
28
|
-
- Integration with django_llm module
|
29
|
-
- Caching support
|
30
|
-
- Metrics collection
|
31
|
-
- Error handling
|
32
|
-
- Type safety
|
33
|
-
"""
|
34
|
-
|
35
|
-
def __init__(
|
36
|
-
self,
|
37
|
-
name: str,
|
38
|
-
deps_type: Type[DepsT],
|
39
|
-
output_type: Type[OutputT],
|
40
|
-
instructions: str,
|
41
|
-
model: Optional[str] = None,
|
42
|
-
llm_client: Optional[Any] = None,
|
43
|
-
timeout: int = 300,
|
44
|
-
max_retries: int = 3,
|
45
|
-
enable_caching: bool = True
|
46
|
-
):
|
47
|
-
"""
|
48
|
-
Initialize Django Agent.
|
49
|
-
|
50
|
-
Args:
|
51
|
-
name: Unique agent identifier
|
52
|
-
deps_type: Type for dependency injection (must be dataclass)
|
53
|
-
output_type: Pydantic model for output validation
|
54
|
-
instructions: System prompt for the agent
|
55
|
-
model: Override model (uses client default if None)
|
56
|
-
llm_client: Optional LLM client (uses default if None)
|
57
|
-
timeout: Execution timeout in seconds
|
58
|
-
max_retries: Maximum retry attempts
|
59
|
-
enable_caching: Whether to enable result caching
|
60
|
-
"""
|
61
|
-
self.name = name
|
62
|
-
self.deps_type = deps_type
|
63
|
-
self.output_type = output_type
|
64
|
-
self.instructions = instructions
|
65
|
-
self.timeout = timeout
|
66
|
-
self.max_retries = max_retries
|
67
|
-
self.enable_caching = enable_caching
|
68
|
-
|
69
|
-
# Get LLM client
|
70
|
-
self.llm_client = llm_client or self._get_default_llm_client()
|
71
|
-
|
72
|
-
# Determine model to use
|
73
|
-
model_name = model or self._get_default_model()
|
74
|
-
|
75
|
-
# Create Pydantic AI agent
|
76
|
-
self.agent = Agent[DepsT, OutputT](
|
77
|
-
model=model_name,
|
78
|
-
deps_type=deps_type,
|
79
|
-
output_type=output_type,
|
80
|
-
instructions=instructions,
|
81
|
-
retries=max_retries
|
82
|
-
)
|
83
|
-
|
84
|
-
# Initialize metrics
|
85
|
-
self._execution_count = 0
|
86
|
-
self._total_execution_time = 0.0
|
87
|
-
self._error_count = 0
|
88
|
-
self._cache_hits = 0
|
89
|
-
|
90
|
-
logger.info(f"Initialized DjangoAgent '{name}' with model '{model_name}'")
|
91
|
-
|
92
|
-
async def run(self, prompt: str, deps: DepsT, **kwargs) -> ExecutionResult:
|
93
|
-
"""
|
94
|
-
Run agent with Django-specific enhancements.
|
95
|
-
|
96
|
-
Args:
|
97
|
-
prompt: User prompt/instruction
|
98
|
-
deps: Dependencies instance
|
99
|
-
**kwargs: Additional Pydantic AI parameters
|
100
|
-
|
101
|
-
Returns:
|
102
|
-
ExecutionResult with output, usage, and metadata
|
103
|
-
"""
|
104
|
-
start_time = time.time()
|
105
|
-
self._execution_count += 1
|
106
|
-
|
107
|
-
# Check cache if enabled
|
108
|
-
if self.enable_caching:
|
109
|
-
cached_result = await self._check_cache(prompt, deps)
|
110
|
-
if cached_result:
|
111
|
-
self._cache_hits += 1
|
112
|
-
logger.debug(f"Cache hit for agent '{self.name}'")
|
113
|
-
return ExecutionResult(
|
114
|
-
agent_name=self.name,
|
115
|
-
output=cached_result,
|
116
|
-
execution_time=0.0,
|
117
|
-
cached=True
|
118
|
-
)
|
119
|
-
|
120
|
-
try:
|
121
|
-
# Execute agent
|
122
|
-
logger.debug(f"Executing agent '{self.name}' with prompt: {prompt[:100]}...")
|
123
|
-
|
124
|
-
result = await self.agent.run(prompt, deps=deps, **kwargs)
|
125
|
-
|
126
|
-
execution_time = time.time() - start_time
|
127
|
-
self._total_execution_time += execution_time
|
128
|
-
|
129
|
-
# Extract metrics
|
130
|
-
tokens_used = 0
|
131
|
-
cost = 0.0
|
132
|
-
if hasattr(result, 'usage') and result.usage:
|
133
|
-
tokens_used = getattr(result.usage, 'total_tokens', 0)
|
134
|
-
# Calculate cost based on model and tokens (implement based on your pricing)
|
135
|
-
cost = self._calculate_cost(tokens_used)
|
136
|
-
|
137
|
-
execution_result = ExecutionResult(
|
138
|
-
agent_name=self.name,
|
139
|
-
output=result.output,
|
140
|
-
execution_time=execution_time,
|
141
|
-
tokens_used=tokens_used,
|
142
|
-
cost=cost
|
143
|
-
)
|
144
|
-
|
145
|
-
# Cache result if enabled
|
146
|
-
if self.enable_caching:
|
147
|
-
await self._cache_result(prompt, deps, result.output)
|
148
|
-
|
149
|
-
logger.info(
|
150
|
-
f"Agent '{self.name}' executed successfully in {execution_time:.2f}s "
|
151
|
-
f"(tokens: {tokens_used}, cost: ${cost:.4f})"
|
152
|
-
)
|
153
|
-
|
154
|
-
return execution_result
|
155
|
-
|
156
|
-
except Exception as e:
|
157
|
-
self._error_count += 1
|
158
|
-
execution_time = time.time() - start_time
|
159
|
-
|
160
|
-
logger.error(f"Agent '{self.name}' execution failed: {e}")
|
161
|
-
|
162
|
-
raise ExecutionError(
|
163
|
-
f"Agent '{self.name}' execution failed: {str(e)}",
|
164
|
-
agent_name=self.name,
|
165
|
-
original_error=e
|
166
|
-
)
|
167
|
-
|
168
|
-
def tool(self, func: Callable) -> Callable:
|
169
|
-
"""
|
170
|
-
Register tool with agent.
|
171
|
-
|
172
|
-
Args:
|
173
|
-
func: Function to register as agent tool
|
174
|
-
|
175
|
-
Returns:
|
176
|
-
Decorated function
|
177
|
-
"""
|
178
|
-
return self.agent.tool(func)
|
179
|
-
|
180
|
-
def get_metrics(self) -> Dict[str, Any]:
|
181
|
-
"""Get agent execution metrics."""
|
182
|
-
return {
|
183
|
-
'name': self.name,
|
184
|
-
'execution_count': self._execution_count,
|
185
|
-
'total_execution_time': self._total_execution_time,
|
186
|
-
'average_execution_time': (
|
187
|
-
self._total_execution_time / self._execution_count
|
188
|
-
if self._execution_count > 0 else 0
|
189
|
-
),
|
190
|
-
'error_count': self._error_count,
|
191
|
-
'success_rate': (
|
192
|
-
(self._execution_count - self._error_count) / self._execution_count
|
193
|
-
if self._execution_count > 0 else 0
|
194
|
-
),
|
195
|
-
'cache_hits': self._cache_hits,
|
196
|
-
'cache_hit_rate': (
|
197
|
-
self._cache_hits / self._execution_count
|
198
|
-
if self._execution_count > 0 else 0
|
199
|
-
)
|
200
|
-
}
|
201
|
-
|
202
|
-
def reset_metrics(self):
|
203
|
-
"""Reset agent metrics."""
|
204
|
-
self._execution_count = 0
|
205
|
-
self._total_execution_time = 0.0
|
206
|
-
self._error_count = 0
|
207
|
-
self._cache_hits = 0
|
208
|
-
|
209
|
-
def _get_default_llm_client(self):
|
210
|
-
"""Get default LLM client from django_llm module."""
|
211
|
-
try:
|
212
|
-
from django_cfg.modules.django_llm import DjangoLLM
|
213
|
-
llm_service = DjangoLLM()
|
214
|
-
if llm_service.is_configured:
|
215
|
-
return llm_service.client
|
216
|
-
except ImportError:
|
217
|
-
logger.warning("django_llm module not available, using default client")
|
218
|
-
|
219
|
-
return None
|
220
|
-
|
221
|
-
def _get_default_model(self) -> str:
|
222
|
-
"""Get default model name."""
|
223
|
-
if self.llm_client and hasattr(self.llm_client, 'primary_provider'):
|
224
|
-
if self.llm_client.primary_provider == 'openrouter':
|
225
|
-
return 'openai:gpt-4o-mini'
|
226
|
-
elif self.llm_client.primary_provider == 'openai':
|
227
|
-
return 'openai:gpt-4o-mini'
|
228
|
-
|
229
|
-
return 'openai:gpt-4o-mini' # Default fallback
|
230
|
-
|
231
|
-
async def _check_cache(self, prompt: str, deps: DepsT) -> Optional[Any]:
|
232
|
-
"""Check cache for existing result."""
|
233
|
-
if not self.llm_client or not hasattr(self.llm_client, 'cache'):
|
234
|
-
return None
|
235
|
-
|
236
|
-
try:
|
237
|
-
cache_key = self._generate_cache_key(prompt, deps)
|
238
|
-
return self.llm_client.cache.get(cache_key)
|
239
|
-
except Exception as e:
|
240
|
-
logger.warning(f"Cache check failed: {e}")
|
241
|
-
return None
|
242
|
-
|
243
|
-
async def _cache_result(self, prompt: str, deps: DepsT, result: Any):
|
244
|
-
"""Cache execution result."""
|
245
|
-
if not self.llm_client or not hasattr(self.llm_client, 'cache'):
|
246
|
-
return
|
247
|
-
|
248
|
-
try:
|
249
|
-
cache_key = self._generate_cache_key(prompt, deps)
|
250
|
-
self.llm_client.cache.set(cache_key, result)
|
251
|
-
except Exception as e:
|
252
|
-
logger.warning(f"Cache storage failed: {e}")
|
253
|
-
|
254
|
-
def _generate_cache_key(self, prompt: str, deps: DepsT) -> str:
|
255
|
-
"""Generate cache key for prompt and dependencies."""
|
256
|
-
# Create a simple hash-based key
|
257
|
-
import hashlib
|
258
|
-
|
259
|
-
# Include agent name, prompt, and relevant deps data
|
260
|
-
key_data = f"{self.name}:{prompt}"
|
261
|
-
|
262
|
-
# Add user info if available
|
263
|
-
if hasattr(deps, 'user') and deps.user:
|
264
|
-
key_data += f":user_{deps.user.id}"
|
265
|
-
|
266
|
-
# Add other relevant dependency data
|
267
|
-
if hasattr(deps, 'to_dict'):
|
268
|
-
deps_str = str(sorted(deps.to_dict().items()))
|
269
|
-
key_data += f":deps_{deps_str}"
|
270
|
-
|
271
|
-
return hashlib.md5(key_data.encode()).hexdigest()
|
272
|
-
|
273
|
-
def _calculate_cost(self, tokens_used: int) -> float:
|
274
|
-
"""Calculate cost based on tokens used."""
|
275
|
-
# Implement based on your pricing model
|
276
|
-
# This is a simple example
|
277
|
-
cost_per_1k_tokens = 0.002 # Example: $0.002 per 1K tokens
|
278
|
-
return (tokens_used / 1000) * cost_per_1k_tokens
|
279
|
-
|
280
|
-
def __repr__(self) -> str:
|
281
|
-
return f"DjangoAgent(name='{self.name}', deps_type={self.deps_type.__name__}, output_type={self.output_type.__name__})"
|