django-cfg 1.3.7__py3-none-any.whl → 1.3.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/admin/__init__.py +24 -8
- django_cfg/apps/accounts/admin/activity_admin.py +146 -0
- django_cfg/apps/accounts/admin/filters.py +98 -22
- django_cfg/apps/accounts/admin/group_admin.py +86 -0
- django_cfg/apps/accounts/admin/inlines.py +42 -13
- django_cfg/apps/accounts/admin/otp_admin.py +115 -0
- django_cfg/apps/accounts/admin/registration_admin.py +173 -0
- django_cfg/apps/accounts/admin/resources.py +123 -19
- django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
- django_cfg/apps/accounts/admin/user_admin.py +362 -0
- django_cfg/apps/agents/admin/__init__.py +17 -4
- django_cfg/apps/agents/admin/execution_admin.py +204 -183
- django_cfg/apps/agents/admin/registry_admin.py +230 -255
- django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
- django_cfg/apps/agents/core/__init__.py +1 -1
- django_cfg/apps/agents/core/django_agent.py +221 -0
- django_cfg/apps/agents/core/exceptions.py +14 -0
- django_cfg/apps/agents/core/orchestrator.py +18 -3
- django_cfg/apps/knowbase/admin/__init__.py +1 -1
- django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
- django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
- django_cfg/apps/knowbase/admin/document_admin.py +269 -262
- django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
- django_cfg/apps/knowbase/config/settings.py +21 -4
- django_cfg/apps/knowbase/views/chat_views.py +3 -0
- django_cfg/apps/leads/admin/__init__.py +3 -1
- django_cfg/apps/leads/admin/leads_admin.py +235 -35
- django_cfg/apps/maintenance/admin/__init__.py +2 -2
- django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
- django_cfg/apps/maintenance/admin/log_admin.py +143 -61
- django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
- django_cfg/apps/maintenance/admin/site_admin.py +213 -352
- django_cfg/apps/newsletter/admin/__init__.py +29 -2
- django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
- django_cfg/apps/payments/admin/__init__.py +18 -27
- django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
- django_cfg/apps/payments/admin/balance_admin.py +166 -632
- django_cfg/apps/payments/admin/currencies_admin.py +235 -607
- django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
- django_cfg/apps/payments/admin/filters.py +83 -3
- django_cfg/apps/payments/admin/networks_admin.py +269 -0
- django_cfg/apps/payments/admin/payments_admin.py +183 -460
- django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
- django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
- django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
- django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
- django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
- django_cfg/apps/payments/config/__init__.py +14 -15
- django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
- django_cfg/apps/payments/config/helpers.py +8 -13
- django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
- django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
- django_cfg/apps/payments/middleware/api_access.py +32 -6
- django_cfg/apps/payments/migrations/0001_initial.py +33 -46
- django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
- django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
- django_cfg/apps/payments/models/balance.py +12 -0
- django_cfg/apps/payments/models/currencies.py +106 -32
- django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
- django_cfg/apps/payments/models/payments.py +94 -0
- django_cfg/apps/payments/services/core/base.py +4 -4
- django_cfg/apps/payments/services/core/currency_service.py +35 -28
- django_cfg/apps/payments/services/core/payment_service.py +266 -39
- django_cfg/apps/payments/services/providers/__init__.py +3 -0
- django_cfg/apps/payments/services/providers/base.py +303 -41
- django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
- django_cfg/apps/payments/services/providers/models/base.py +145 -0
- django_cfg/apps/payments/services/providers/models/providers.py +87 -0
- django_cfg/apps/payments/services/providers/models/universal.py +48 -0
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
- django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
- django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
- django_cfg/apps/payments/services/providers/registry.py +9 -37
- django_cfg/apps/payments/services/providers/sync_service.py +277 -0
- django_cfg/apps/payments/services/types/requests.py +19 -7
- django_cfg/apps/payments/signals/payment_signals.py +31 -2
- django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
- django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
- django_cfg/apps/payments/tasks/__init__.py +39 -0
- django_cfg/apps/payments/tasks/types.py +73 -0
- django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
- django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
- django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
- django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
- django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
- django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
- django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
- django_cfg/apps/payments/urls.py +3 -2
- django_cfg/apps/payments/urls_admin.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +8 -5
- django_cfg/apps/payments/views/overview/services.py +2 -2
- django_cfg/apps/payments/views/serializers/currencies.py +22 -8
- django_cfg/apps/support/admin/__init__.py +10 -1
- django_cfg/apps/support/admin/support_admin.py +338 -141
- django_cfg/apps/tasks/admin/__init__.py +11 -0
- django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
- django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
- django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
- django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
- django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
- django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
- django_cfg/apps/tasks/tasks/__init__.py +10 -0
- django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
- django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
- django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
- django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
- django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
- django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
- django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
- django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
- django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
- django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
- django_cfg/apps/tasks/urls.py +2 -2
- django_cfg/apps/tasks/urls_admin.py +2 -2
- django_cfg/apps/tasks/utils/__init__.py +1 -0
- django_cfg/apps/tasks/utils/simulator.py +356 -0
- django_cfg/apps/tasks/views/__init__.py +16 -0
- django_cfg/apps/tasks/views/api.py +569 -0
- django_cfg/apps/tasks/views/dashboard.py +58 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +10 -5
- django_cfg/core/generation.py +1 -1
- django_cfg/core/integration/__init__.py +21 -0
- django_cfg/management/commands/__init__.py +13 -1
- django_cfg/management/commands/migrate_all.py +9 -3
- django_cfg/management/commands/migrator.py +11 -6
- django_cfg/management/commands/rundramatiq.py +3 -2
- django_cfg/management/commands/rundramatiq_simulator.py +430 -0
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/models/api_keys.py +115 -0
- django_cfg/models/constance.py +0 -11
- django_cfg/models/payments.py +137 -3
- django_cfg/modules/django_admin/__init__.py +64 -0
- django_cfg/modules/django_admin/decorators/__init__.py +13 -0
- django_cfg/modules/django_admin/decorators/actions.py +106 -0
- django_cfg/modules/django_admin/decorators/display.py +106 -0
- django_cfg/modules/django_admin/mixins/__init__.py +14 -0
- django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
- django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
- django_cfg/modules/django_admin/models/__init__.py +20 -0
- django_cfg/modules/django_admin/models/action_models.py +33 -0
- django_cfg/modules/django_admin/models/badge_models.py +20 -0
- django_cfg/modules/django_admin/models/base.py +26 -0
- django_cfg/modules/django_admin/models/display_models.py +31 -0
- django_cfg/modules/django_admin/utils/badges.py +159 -0
- django_cfg/modules/django_admin/utils/displays.py +247 -0
- django_cfg/modules/django_currency/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
- django_cfg/modules/django_currency/core/converter.py +12 -12
- django_cfg/modules/django_currency/database/__init__.py +2 -2
- django_cfg/modules/django_currency/database/database_loader.py +93 -42
- django_cfg/modules/django_llm/llm/client.py +10 -2
- django_cfg/modules/django_tasks.py +54 -21
- django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
- django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
- django_cfg/modules/django_unfold/dashboard.py +14 -13
- django_cfg/modules/django_unfold/models/config.py +1 -1
- django_cfg/registry/core.py +7 -9
- django_cfg/registry/third_party.py +2 -2
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
- django_cfg/apps/accounts/admin/activity.py +0 -96
- django_cfg/apps/accounts/admin/group.py +0 -17
- django_cfg/apps/accounts/admin/otp.py +0 -59
- django_cfg/apps/accounts/admin/registration_source.py +0 -97
- django_cfg/apps/accounts/admin/twilio_response.py +0 -227
- django_cfg/apps/accounts/admin/user.py +0 -300
- django_cfg/apps/agents/core/agent.py +0 -281
- django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
- django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
- django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
- django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
- django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
- django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
- django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
- django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
- django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
- django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
- django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
- django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
- django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
- django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
- django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
- django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
- django_cfg/apps/payments/config/constance/__init__.py +0 -22
- django_cfg/apps/payments/config/constance/config_service.py +0 -123
- django_cfg/apps/payments/config/constance/fields.py +0 -69
- django_cfg/apps/payments/config/constance/settings.py +0 -160
- django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
- django_cfg/apps/tasks/admin.py +0 -320
- django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
- django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
- django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
- django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
- django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
- django_cfg/apps/tasks/templates/tasks/base.html +0 -96
- django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
- django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
- django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
- django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
- django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
- django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
- django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
- django_cfg/apps/tasks/views.py +0 -461
- django_cfg/management/commands/auto_generate.py +0 -486
- django_cfg/middleware/static_nocache.py +0 -55
- django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
- /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
django_cfg/__init__.py
CHANGED
@@ -1,18 +1,34 @@
|
|
1
1
|
"""
|
2
|
-
|
2
|
+
Accounts admin interfaces using Django Admin Utilities.
|
3
|
+
|
4
|
+
Modern, clean admin interfaces with Material Icons and consistent styling.
|
3
5
|
"""
|
4
6
|
|
5
|
-
from .
|
6
|
-
|
7
|
-
|
8
|
-
from .
|
9
|
-
from .
|
7
|
+
from django.contrib import admin
|
8
|
+
|
9
|
+
# Import all admin classes
|
10
|
+
from .user_admin import CustomUserAdmin
|
11
|
+
from .activity_admin import UserActivityAdmin
|
12
|
+
from .otp_admin import OTPSecretAdmin
|
13
|
+
from .registration_admin import RegistrationSourceAdmin, UserRegistrationSourceAdmin
|
14
|
+
from .group_admin import GroupAdmin
|
15
|
+
from .twilio_admin import TwilioResponseAdmin, TwilioResponseInline
|
16
|
+
|
17
|
+
# All models are registered in their respective admin files using @admin.register
|
18
|
+
# This provides:
|
19
|
+
# - Clean separation of concerns
|
20
|
+
# - Material Icons integration
|
21
|
+
# - Type-safe configurations
|
22
|
+
# - Performance optimizations
|
23
|
+
# - Consistent styling with django_admin module
|
10
24
|
|
11
25
|
__all__ = [
|
12
26
|
'CustomUserAdmin',
|
13
|
-
'
|
27
|
+
'UserActivityAdmin',
|
28
|
+
'OTPSecretAdmin',
|
14
29
|
'RegistrationSourceAdmin',
|
15
30
|
'UserRegistrationSourceAdmin',
|
16
|
-
'UserActivityAdmin',
|
17
31
|
'GroupAdmin',
|
32
|
+
'TwilioResponseAdmin',
|
33
|
+
'TwilioResponseInline',
|
18
34
|
]
|
@@ -0,0 +1,146 @@
|
|
1
|
+
"""
|
2
|
+
User Activity admin interface using Django Admin Utilities.
|
3
|
+
|
4
|
+
Enhanced activity tracking with Material Icons and optimized queries.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from django.contrib import admin
|
8
|
+
from unfold.admin import ModelAdmin
|
9
|
+
|
10
|
+
from django_cfg.modules.django_admin import (
|
11
|
+
OptimizedModelAdmin,
|
12
|
+
DisplayMixin,
|
13
|
+
UserDisplayConfig,
|
14
|
+
DateTimeDisplayConfig,
|
15
|
+
StatusBadgeConfig,
|
16
|
+
Icons,
|
17
|
+
display
|
18
|
+
)
|
19
|
+
from django_cfg.modules.django_admin.utils.badges import StatusBadge
|
20
|
+
|
21
|
+
from ..models import UserActivity
|
22
|
+
from .filters import ActivityTypeFilter
|
23
|
+
|
24
|
+
|
25
|
+
@admin.register(UserActivity)
|
26
|
+
class UserActivityAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin):
|
27
|
+
"""Enhanced admin for UserActivity model using Django Admin Utilities."""
|
28
|
+
|
29
|
+
# Performance optimization
|
30
|
+
select_related_fields = ['user']
|
31
|
+
|
32
|
+
list_display = [
|
33
|
+
'user_display',
|
34
|
+
'activity_type_display',
|
35
|
+
'description_display',
|
36
|
+
'ip_address_display',
|
37
|
+
'created_at_display'
|
38
|
+
]
|
39
|
+
list_display_links = ['user_display', 'activity_type_display']
|
40
|
+
list_filter = [ActivityTypeFilter, 'activity_type', 'created_at']
|
41
|
+
search_fields = ['user__username', 'user__email', 'description', 'ip_address']
|
42
|
+
readonly_fields = ['created_at']
|
43
|
+
date_hierarchy = 'created_at'
|
44
|
+
ordering = ['-created_at']
|
45
|
+
|
46
|
+
fieldsets = (
|
47
|
+
('Activity', {
|
48
|
+
'fields': ('user', 'activity_type', 'description')
|
49
|
+
}),
|
50
|
+
('Related Object', {
|
51
|
+
'fields': ('object_id', 'object_type'),
|
52
|
+
'classes': ('collapse',),
|
53
|
+
'description': 'Optional reference to related model instance'
|
54
|
+
}),
|
55
|
+
('Request Info', {
|
56
|
+
'fields': ('ip_address', 'user_agent'),
|
57
|
+
'classes': ('collapse',)
|
58
|
+
}),
|
59
|
+
('Timestamp', {
|
60
|
+
'fields': ('created_at',)
|
61
|
+
}),
|
62
|
+
)
|
63
|
+
|
64
|
+
@display(description="User")
|
65
|
+
def user_display(self, obj):
|
66
|
+
"""Enhanced user display with avatar."""
|
67
|
+
config = UserDisplayConfig(
|
68
|
+
show_avatar=True,
|
69
|
+
avatar_size=20,
|
70
|
+
show_email=False
|
71
|
+
)
|
72
|
+
return self.display_user_simple(obj.user, config)
|
73
|
+
|
74
|
+
@display(description="Activity")
|
75
|
+
def activity_type_display(self, obj):
|
76
|
+
"""Activity type with appropriate icons."""
|
77
|
+
activity_icons = {
|
78
|
+
'login': Icons.LOGIN,
|
79
|
+
'logout': Icons.LOGOUT,
|
80
|
+
'otp_requested': Icons.EMAIL,
|
81
|
+
'otp_verified': Icons.VERIFIED,
|
82
|
+
'profile_updated': Icons.EDIT,
|
83
|
+
'registration': Icons.PERSON_ADD,
|
84
|
+
}
|
85
|
+
|
86
|
+
activity_variants = {
|
87
|
+
'login': 'success',
|
88
|
+
'logout': 'info',
|
89
|
+
'otp_requested': 'warning',
|
90
|
+
'otp_verified': 'success',
|
91
|
+
'profile_updated': 'info',
|
92
|
+
'registration': 'primary',
|
93
|
+
}
|
94
|
+
|
95
|
+
icon = activity_icons.get(obj.activity_type, Icons.DESCRIPTION)
|
96
|
+
variant = activity_variants.get(obj.activity_type, 'info')
|
97
|
+
|
98
|
+
config = StatusBadgeConfig(
|
99
|
+
show_icons=True,
|
100
|
+
icon=icon,
|
101
|
+
custom_mappings={obj.get_activity_type_display(): variant}
|
102
|
+
)
|
103
|
+
|
104
|
+
return StatusBadge.create(
|
105
|
+
text=obj.get_activity_type_display(),
|
106
|
+
variant=variant,
|
107
|
+
config=config
|
108
|
+
)
|
109
|
+
|
110
|
+
@display(description="Description")
|
111
|
+
def description_display(self, obj):
|
112
|
+
"""Truncated description with full text in tooltip."""
|
113
|
+
if len(obj.description) > 50:
|
114
|
+
truncated = f"{obj.description[:47]}..."
|
115
|
+
config = StatusBadgeConfig(show_icons=True, icon=Icons.DESCRIPTION)
|
116
|
+
return StatusBadge.create(
|
117
|
+
text=truncated,
|
118
|
+
variant="secondary",
|
119
|
+
config=config
|
120
|
+
)
|
121
|
+
|
122
|
+
config = StatusBadgeConfig(show_icons=True, icon=Icons.DESCRIPTION)
|
123
|
+
return StatusBadge.create(
|
124
|
+
text=obj.description,
|
125
|
+
variant="info",
|
126
|
+
config=config
|
127
|
+
)
|
128
|
+
|
129
|
+
@display(description="IP Address")
|
130
|
+
def ip_address_display(self, obj):
|
131
|
+
"""IP address with network icon."""
|
132
|
+
if not obj.ip_address:
|
133
|
+
return "—"
|
134
|
+
|
135
|
+
config = StatusBadgeConfig(show_icons=True, icon=Icons.PUBLIC)
|
136
|
+
return StatusBadge.create(
|
137
|
+
text=obj.ip_address,
|
138
|
+
variant="secondary",
|
139
|
+
config=config
|
140
|
+
)
|
141
|
+
|
142
|
+
@display(description="When")
|
143
|
+
def created_at_display(self, obj):
|
144
|
+
"""Created time with relative display."""
|
145
|
+
config = DateTimeDisplayConfig(show_relative=True)
|
146
|
+
return self.display_datetime_relative(obj, 'created_at', config)
|
@@ -1,51 +1,63 @@
|
|
1
1
|
"""
|
2
2
|
Custom admin filters for Accounts app.
|
3
|
+
|
4
|
+
Enhanced filters with better organization and performance.
|
3
5
|
"""
|
4
6
|
|
5
7
|
from django.contrib import admin
|
6
8
|
from django.utils import timezone
|
7
9
|
from datetime import timedelta
|
10
|
+
from django.db import models
|
11
|
+
from django.db.models import Count
|
8
12
|
|
9
13
|
|
10
14
|
class UserStatusFilter(admin.SimpleListFilter):
|
15
|
+
"""Enhanced user status filter with clear categories."""
|
11
16
|
title = "User Status"
|
12
17
|
parameter_name = "user_status"
|
13
18
|
|
14
19
|
def lookups(self, request, model_admin):
|
15
20
|
return (
|
16
|
-
("active", "Active"),
|
17
|
-
("inactive", "Inactive"),
|
18
|
-
("staff", "Staff"),
|
19
|
-
("superuser", "
|
21
|
+
("active", "✅ Active Users"),
|
22
|
+
("inactive", "❌ Inactive Users"),
|
23
|
+
("staff", "⚙️ Staff Members"),
|
24
|
+
("superuser", "👑 Superusers"),
|
25
|
+
("regular", "👤 Regular Users"),
|
20
26
|
)
|
21
27
|
|
22
28
|
def queryset(self, request, queryset):
|
23
29
|
if self.value() == "active":
|
24
|
-
return queryset.filter(is_active=True, is_staff=False)
|
30
|
+
return queryset.filter(is_active=True, is_staff=False, is_superuser=False)
|
25
31
|
elif self.value() == "inactive":
|
26
32
|
return queryset.filter(is_active=False)
|
27
33
|
elif self.value() == "staff":
|
28
|
-
return queryset.filter(is_staff=True)
|
34
|
+
return queryset.filter(is_staff=True, is_superuser=False)
|
29
35
|
elif self.value() == "superuser":
|
30
36
|
return queryset.filter(is_superuser=True)
|
37
|
+
elif self.value() == "regular":
|
38
|
+
return queryset.filter(is_active=True, is_staff=False, is_superuser=False)
|
31
39
|
return queryset
|
32
40
|
|
33
41
|
|
34
42
|
class OTPStatusFilter(admin.SimpleListFilter):
|
43
|
+
"""Enhanced OTP status filter with time-based categories."""
|
35
44
|
title = "OTP Status"
|
36
45
|
parameter_name = "otp_status"
|
37
46
|
|
38
47
|
def lookups(self, request, model_admin):
|
39
48
|
return (
|
40
|
-
("
|
41
|
-
("used", "Used"),
|
42
|
-
("expired", "Expired"),
|
43
|
-
("recent", "Recent (24h)"),
|
49
|
+
("valid", "✅ Valid & Active"),
|
50
|
+
("used", "🔒 Used"),
|
51
|
+
("expired", "⏰ Expired"),
|
52
|
+
("recent", "🕐 Recent (24h)"),
|
53
|
+
("today", "📅 Today"),
|
44
54
|
)
|
45
55
|
|
46
56
|
def queryset(self, request, queryset):
|
47
57
|
now = timezone.now()
|
48
|
-
|
58
|
+
today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
59
|
+
|
60
|
+
if self.value() == "valid":
|
49
61
|
return queryset.filter(is_used=False, expires_at__gt=now)
|
50
62
|
elif self.value() == "used":
|
51
63
|
return queryset.filter(is_used=True)
|
@@ -53,17 +65,21 @@ class OTPStatusFilter(admin.SimpleListFilter):
|
|
53
65
|
return queryset.filter(is_used=False, expires_at__lte=now)
|
54
66
|
elif self.value() == "recent":
|
55
67
|
return queryset.filter(created_at__gte=now - timedelta(hours=24))
|
68
|
+
elif self.value() == "today":
|
69
|
+
return queryset.filter(created_at__gte=today_start)
|
56
70
|
return queryset
|
57
71
|
|
58
72
|
|
59
73
|
class RegistrationSourceStatusFilter(admin.SimpleListFilter):
|
60
|
-
|
61
|
-
|
74
|
+
"""Registration source status filter."""
|
75
|
+
title = "Source Status"
|
76
|
+
parameter_name = "source_status"
|
62
77
|
|
63
78
|
def lookups(self, request, model_admin):
|
64
79
|
return (
|
65
|
-
("active", "Active"),
|
66
|
-
("inactive", "Inactive"),
|
80
|
+
("active", "✅ Active Sources"),
|
81
|
+
("inactive", "❌ Inactive Sources"),
|
82
|
+
("popular", "🔥 Popular (10+ users)"),
|
67
83
|
)
|
68
84
|
|
69
85
|
def queryset(self, request, queryset):
|
@@ -71,28 +87,88 @@ class RegistrationSourceStatusFilter(admin.SimpleListFilter):
|
|
71
87
|
return queryset.filter(is_active=True)
|
72
88
|
elif self.value() == "inactive":
|
73
89
|
return queryset.filter(is_active=False)
|
90
|
+
elif self.value() == "popular":
|
91
|
+
# Sources with 10 or more users
|
92
|
+
return queryset.annotate(
|
93
|
+
user_count=Count('user_registration_sources')
|
94
|
+
).filter(user_count__gte=10)
|
74
95
|
return queryset
|
75
96
|
|
76
97
|
|
77
98
|
class ActivityTypeFilter(admin.SimpleListFilter):
|
99
|
+
"""Enhanced activity type filter with time-based options."""
|
78
100
|
title = "Activity Type"
|
79
101
|
parameter_name = "activity_type"
|
80
102
|
|
81
103
|
def lookups(self, request, model_admin):
|
82
104
|
return (
|
83
|
-
("login", "Login"),
|
84
|
-
("logout", "Logout"),
|
85
|
-
("otp_requested", "OTP Requested"),
|
86
|
-
("otp_verified", "OTP Verified"),
|
87
|
-
("profile_updated", "Profile Updated"),
|
88
|
-
("registration", "Registration"),
|
89
|
-
("recent", "Recent (24h)"),
|
105
|
+
("login", "🔐 Login"),
|
106
|
+
("logout", "🚪 Logout"),
|
107
|
+
("otp_requested", "📧 OTP Requested"),
|
108
|
+
("otp_verified", "✅ OTP Verified"),
|
109
|
+
("profile_updated", "✏️ Profile Updated"),
|
110
|
+
("registration", "👤 Registration"),
|
111
|
+
("recent", "🕐 Recent (24h)"),
|
112
|
+
("today", "📅 Today"),
|
90
113
|
)
|
91
114
|
|
92
115
|
def queryset(self, request, queryset):
|
93
116
|
now = timezone.now()
|
117
|
+
today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
118
|
+
|
94
119
|
if self.value() == "recent":
|
95
120
|
return queryset.filter(created_at__gte=now - timedelta(hours=24))
|
121
|
+
elif self.value() == "today":
|
122
|
+
return queryset.filter(created_at__gte=today_start)
|
96
123
|
elif self.value():
|
97
124
|
return queryset.filter(activity_type=self.value())
|
98
125
|
return queryset
|
126
|
+
|
127
|
+
|
128
|
+
class TwilioResponseStatusFilter(admin.SimpleListFilter):
|
129
|
+
"""Twilio response status filter."""
|
130
|
+
title = "Response Status"
|
131
|
+
parameter_name = "twilio_status"
|
132
|
+
|
133
|
+
def lookups(self, request, model_admin):
|
134
|
+
return (
|
135
|
+
("success", "✅ Successful"),
|
136
|
+
("error", "❌ With Errors"),
|
137
|
+
("pending", "⏳ Pending"),
|
138
|
+
("recent", "🕐 Recent (24h)"),
|
139
|
+
)
|
140
|
+
|
141
|
+
def queryset(self, request, queryset):
|
142
|
+
now = timezone.now()
|
143
|
+
|
144
|
+
if self.value() == "success":
|
145
|
+
return queryset.filter(error_code__isnull=True, error_message__isnull=True)
|
146
|
+
elif self.value() == "error":
|
147
|
+
return queryset.filter(
|
148
|
+
models.Q(error_code__isnull=False) |
|
149
|
+
models.Q(error_message__isnull=False)
|
150
|
+
)
|
151
|
+
elif self.value() == "pending":
|
152
|
+
return queryset.filter(status__in=['queued', 'sending', 'sent'])
|
153
|
+
elif self.value() == "recent":
|
154
|
+
return queryset.filter(created_at__gte=now - timedelta(hours=24))
|
155
|
+
return queryset
|
156
|
+
|
157
|
+
|
158
|
+
class TwilioResponseTypeFilter(admin.SimpleListFilter):
|
159
|
+
"""Twilio response type filter."""
|
160
|
+
title = "Service Type"
|
161
|
+
parameter_name = "twilio_service"
|
162
|
+
|
163
|
+
def lookups(self, request, model_admin):
|
164
|
+
return (
|
165
|
+
("sms", "📱 SMS"),
|
166
|
+
("voice", "📞 Voice"),
|
167
|
+
("verify", "🔐 Verify"),
|
168
|
+
("email", "📧 Email"),
|
169
|
+
)
|
170
|
+
|
171
|
+
def queryset(self, request, queryset):
|
172
|
+
if self.value():
|
173
|
+
return queryset.filter(service_type=self.value())
|
174
|
+
return queryset
|
@@ -0,0 +1,86 @@
|
|
1
|
+
"""
|
2
|
+
Group admin interface using Django Admin Utilities.
|
3
|
+
|
4
|
+
Enhanced group management with Material Icons and user counts.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from django.contrib import admin
|
8
|
+
from django.contrib.auth.models import Group
|
9
|
+
from unfold.admin import ModelAdmin
|
10
|
+
|
11
|
+
from django_cfg.modules.django_admin import (
|
12
|
+
OptimizedModelAdmin,
|
13
|
+
DisplayMixin,
|
14
|
+
StatusBadgeConfig,
|
15
|
+
Icons,
|
16
|
+
display
|
17
|
+
)
|
18
|
+
from django_cfg.modules.django_admin.utils.badges import StatusBadge
|
19
|
+
|
20
|
+
|
21
|
+
# Unregister the default Group admin
|
22
|
+
admin.site.unregister(Group)
|
23
|
+
|
24
|
+
|
25
|
+
@admin.register(Group)
|
26
|
+
class GroupAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin):
|
27
|
+
"""Enhanced admin for Group model using Django Admin Utilities."""
|
28
|
+
|
29
|
+
list_display = [
|
30
|
+
'name_display',
|
31
|
+
'users_count_display',
|
32
|
+
'permissions_count_display'
|
33
|
+
]
|
34
|
+
list_display_links = ['name_display']
|
35
|
+
search_fields = ['name']
|
36
|
+
filter_horizontal = ['permissions']
|
37
|
+
ordering = ['name']
|
38
|
+
|
39
|
+
fieldsets = (
|
40
|
+
('Group Details', {
|
41
|
+
'fields': ('name',)
|
42
|
+
}),
|
43
|
+
('Permissions', {
|
44
|
+
'fields': ('permissions',),
|
45
|
+
'classes': ('collapse',)
|
46
|
+
}),
|
47
|
+
)
|
48
|
+
|
49
|
+
@display(description="Group Name")
|
50
|
+
def name_display(self, obj):
|
51
|
+
"""Group name display with group icon."""
|
52
|
+
config = StatusBadgeConfig(show_icons=True, icon=Icons.GROUP)
|
53
|
+
return StatusBadge.create(
|
54
|
+
text=obj.name,
|
55
|
+
variant="primary",
|
56
|
+
config=config
|
57
|
+
)
|
58
|
+
|
59
|
+
@display(description="Users")
|
60
|
+
def users_count_display(self, obj):
|
61
|
+
"""Count of users in this group."""
|
62
|
+
count = obj.user_set.count()
|
63
|
+
if count == 0:
|
64
|
+
return "—"
|
65
|
+
|
66
|
+
config = StatusBadgeConfig(show_icons=True, icon=Icons.PEOPLE)
|
67
|
+
return StatusBadge.create(
|
68
|
+
text=f"{count} user{'s' if count != 1 else ''}",
|
69
|
+
variant="info",
|
70
|
+
config=config
|
71
|
+
)
|
72
|
+
|
73
|
+
@display(description="Permissions")
|
74
|
+
def permissions_count_display(self, obj):
|
75
|
+
"""Count of permissions in this group."""
|
76
|
+
count = obj.permissions.count()
|
77
|
+
if count == 0:
|
78
|
+
config = StatusBadgeConfig(show_icons=True, icon=Icons.SECURITY)
|
79
|
+
return StatusBadge.create(text="No permissions", variant="secondary", config=config)
|
80
|
+
|
81
|
+
config = StatusBadgeConfig(show_icons=True, icon=Icons.SECURITY)
|
82
|
+
return StatusBadge.create(
|
83
|
+
text=f"{count} permission{'s' if count != 1 else ''}",
|
84
|
+
variant="warning",
|
85
|
+
config=config
|
86
|
+
)
|
@@ -1,16 +1,24 @@
|
|
1
1
|
"""
|
2
|
-
Inline admin classes for Accounts app.
|
2
|
+
Inline admin classes for Accounts app using Django Admin Utilities.
|
3
|
+
|
4
|
+
Enhanced inline classes with better organization and conditional loading.
|
3
5
|
"""
|
4
6
|
|
5
7
|
from unfold.admin import TabularInline
|
6
|
-
from ..models import UserRegistrationSource, UserActivity
|
7
8
|
|
9
|
+
from django_cfg.modules.base import BaseCfgModule
|
10
|
+
from django_cfg.apps.support.models import Ticket
|
11
|
+
from ..models import UserRegistrationSource, UserActivity
|
8
12
|
|
9
13
|
class UserRegistrationSourceInline(TabularInline):
|
14
|
+
"""Enhanced inline for user registration sources."""
|
10
15
|
model = UserRegistrationSource
|
11
16
|
extra = 0
|
12
17
|
readonly_fields = ["registration_date"]
|
13
18
|
fields = ["source", "first_registration", "registration_date"]
|
19
|
+
ordering = ["-registration_date"]
|
20
|
+
verbose_name = "Registration Source"
|
21
|
+
verbose_name_plural = "Registration Sources"
|
14
22
|
|
15
23
|
def has_add_permission(self, request, obj=None):
|
16
24
|
return True
|
@@ -20,10 +28,14 @@ class UserRegistrationSourceInline(TabularInline):
|
|
20
28
|
|
21
29
|
|
22
30
|
class RegistrationSourceInline(TabularInline):
|
31
|
+
"""Enhanced inline for registration source users."""
|
23
32
|
model = UserRegistrationSource
|
24
33
|
extra = 0
|
25
34
|
readonly_fields = ["registration_date"]
|
26
35
|
fields = ["user", "first_registration", "registration_date"]
|
36
|
+
ordering = ["-registration_date"]
|
37
|
+
verbose_name = "User Registration"
|
38
|
+
verbose_name_plural = "User Registrations"
|
27
39
|
|
28
40
|
def has_add_permission(self, request, obj=None):
|
29
41
|
return True
|
@@ -33,11 +45,19 @@ class RegistrationSourceInline(TabularInline):
|
|
33
45
|
|
34
46
|
|
35
47
|
class UserActivityInline(TabularInline):
|
48
|
+
"""Enhanced inline for user activities."""
|
36
49
|
model = UserActivity
|
37
50
|
extra = 0
|
38
|
-
readonly_fields = ["created_at"]
|
51
|
+
readonly_fields = ["created_at", "activity_type", "description"]
|
39
52
|
fields = ["activity_type", "description", "ip_address", "created_at"]
|
40
53
|
ordering = ["-created_at"]
|
54
|
+
verbose_name = "Activity"
|
55
|
+
verbose_name_plural = "Recent Activities"
|
56
|
+
|
57
|
+
# Show only recent activities to avoid performance issues
|
58
|
+
def get_queryset(self, request):
|
59
|
+
qs = super().get_queryset(request)
|
60
|
+
return qs[:10] # Limit to 10 most recent activities
|
41
61
|
|
42
62
|
def has_add_permission(self, request, obj=None):
|
43
63
|
return False
|
@@ -47,13 +67,12 @@ class UserActivityInline(TabularInline):
|
|
47
67
|
|
48
68
|
|
49
69
|
class UserEmailLogInline(TabularInline):
|
50
|
-
"""
|
70
|
+
"""Enhanced inline for viewing user's email logs."""
|
51
71
|
|
52
72
|
def __init__(self, *args, **kwargs):
|
53
73
|
# Check if newsletter app is available and enabled
|
54
74
|
self.model = None
|
55
75
|
try:
|
56
|
-
from django_cfg.modules.base import BaseCfgModule
|
57
76
|
base_module = BaseCfgModule()
|
58
77
|
|
59
78
|
# Only import if newsletter is enabled
|
@@ -73,7 +92,14 @@ class UserEmailLogInline(TabularInline):
|
|
73
92
|
fields = ["newsletter", "campaign", "subject", "status", "created_at", "sent_at"]
|
74
93
|
ordering = ["-created_at"]
|
75
94
|
verbose_name = "Email Log"
|
76
|
-
verbose_name_plural = "Email
|
95
|
+
verbose_name_plural = "Email History"
|
96
|
+
|
97
|
+
# Show only recent emails to avoid performance issues
|
98
|
+
def get_queryset(self, request):
|
99
|
+
if not self.model:
|
100
|
+
return self.model.objects.none()
|
101
|
+
qs = super().get_queryset(request)
|
102
|
+
return qs[:15] # Limit to 15 most recent emails
|
77
103
|
|
78
104
|
def has_add_permission(self, request, obj=None):
|
79
105
|
return False
|
@@ -86,7 +112,6 @@ class UserEmailLogInline(TabularInline):
|
|
86
112
|
if not self.model:
|
87
113
|
return False
|
88
114
|
try:
|
89
|
-
from django_cfg.modules.base import BaseCfgModule
|
90
115
|
base_module = BaseCfgModule()
|
91
116
|
return base_module.is_newsletter_enabled()
|
92
117
|
except Exception:
|
@@ -94,18 +119,16 @@ class UserEmailLogInline(TabularInline):
|
|
94
119
|
|
95
120
|
|
96
121
|
class UserSupportTicketsInline(TabularInline):
|
97
|
-
"""
|
122
|
+
"""Enhanced inline for viewing user's support tickets."""
|
98
123
|
|
99
124
|
def __init__(self, *args, **kwargs):
|
100
125
|
# Check if support app is available and enabled
|
101
126
|
self.model = None
|
102
127
|
try:
|
103
|
-
from django_cfg.modules.base import BaseCfgModule
|
104
128
|
base_module = BaseCfgModule()
|
105
129
|
|
106
130
|
# Only import if support is enabled
|
107
131
|
if base_module.is_support_enabled():
|
108
|
-
from django_cfg.apps.support.models import Ticket
|
109
132
|
self.model = Ticket
|
110
133
|
except (ImportError, Exception):
|
111
134
|
# Support app not available or not enabled
|
@@ -116,12 +139,19 @@ class UserSupportTicketsInline(TabularInline):
|
|
116
139
|
super().__init__(*args, **kwargs)
|
117
140
|
|
118
141
|
extra = 0
|
119
|
-
readonly_fields = ["uuid", "subject", "status", "created_at"]
|
120
|
-
fields = ["uuid", "subject", "status", "created_at"]
|
142
|
+
readonly_fields = ["uuid", "subject", "status", "priority", "created_at"]
|
143
|
+
fields = ["uuid", "subject", "status", "priority", "created_at"]
|
121
144
|
ordering = ["-created_at"]
|
122
145
|
verbose_name = "Support Ticket"
|
123
146
|
verbose_name_plural = "Support Tickets"
|
124
147
|
|
148
|
+
# Show only recent tickets to avoid performance issues
|
149
|
+
def get_queryset(self, request):
|
150
|
+
if not self.model:
|
151
|
+
return self.model.objects.none()
|
152
|
+
qs = super().get_queryset(request)
|
153
|
+
return qs[:10] # Limit to 10 most recent tickets
|
154
|
+
|
125
155
|
def has_add_permission(self, request, obj=None):
|
126
156
|
return False
|
127
157
|
|
@@ -133,7 +163,6 @@ class UserSupportTicketsInline(TabularInline):
|
|
133
163
|
if not self.model:
|
134
164
|
return False
|
135
165
|
try:
|
136
|
-
from django_cfg.modules.base import BaseCfgModule
|
137
166
|
base_module = BaseCfgModule()
|
138
167
|
return base_module.is_support_enabled()
|
139
168
|
except Exception:
|