django-cfg 1.4.20__py3-none-any.whl → 1.4.23__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 +4 -4
- django_cfg/apps/accounts/__init__.py +1 -1
- django_cfg/apps/accounts/__models.py +30 -29
- django_cfg/apps/accounts/admin/__init__.py +14 -3
- django_cfg/apps/accounts/admin/activity_admin.py +19 -19
- django_cfg/apps/accounts/admin/filters.py +7 -6
- django_cfg/apps/accounts/admin/group_admin.py +10 -16
- django_cfg/apps/accounts/admin/inlines.py +21 -19
- django_cfg/apps/accounts/admin/otp_admin.py +12 -12
- django_cfg/apps/accounts/admin/registration_admin.py +24 -24
- django_cfg/apps/accounts/admin/resources.py +49 -48
- django_cfg/apps/accounts/admin/twilio_admin.py +37 -37
- django_cfg/apps/accounts/admin/user_admin.py +45 -41
- django_cfg/apps/accounts/management/commands/otp_test.py +11 -11
- django_cfg/apps/accounts/managers/__init__.py +1 -1
- django_cfg/apps/accounts/managers/user_manager.py +6 -7
- django_cfg/apps/accounts/migrations/0001_initial.py +3 -2
- django_cfg/apps/accounts/models/__init__.py +15 -16
- django_cfg/apps/accounts/models/activity.py +5 -5
- django_cfg/apps/accounts/models/integrations.py +15 -15
- django_cfg/apps/accounts/models/registration.py +3 -2
- django_cfg/apps/accounts/models/user.py +3 -2
- django_cfg/apps/accounts/serializers/__init__.py +10 -3
- django_cfg/apps/accounts/serializers/otp.py +5 -4
- django_cfg/apps/accounts/serializers/profile.py +4 -5
- django_cfg/apps/accounts/serializers/webhook.py +13 -13
- django_cfg/apps/accounts/services/activity_service.py +13 -12
- django_cfg/apps/accounts/services/otp_service.py +16 -14
- django_cfg/apps/accounts/signals.py +18 -16
- django_cfg/apps/accounts/urls.py +10 -5
- django_cfg/apps/accounts/utils/notifications.py +22 -22
- django_cfg/apps/accounts/views/__init__.py +1 -1
- django_cfg/apps/accounts/views/otp.py +15 -14
- django_cfg/apps/accounts/views/profile.py +14 -10
- django_cfg/apps/accounts/views/webhook.py +46 -48
- django_cfg/apps/agents/__init__.py +3 -3
- django_cfg/apps/agents/admin/__init__.py +1 -1
- django_cfg/apps/agents/admin/execution_admin.py +68 -72
- django_cfg/apps/agents/admin/registry_admin.py +50 -54
- django_cfg/apps/agents/admin/toolsets_admin.py +63 -67
- django_cfg/apps/agents/apps.py +3 -3
- django_cfg/apps/agents/core/__init__.py +4 -4
- django_cfg/apps/agents/core/dependencies.py +24 -23
- django_cfg/apps/agents/core/django_agent.py +41 -39
- django_cfg/apps/agents/core/exceptions.py +12 -12
- django_cfg/apps/agents/core/models.py +16 -15
- django_cfg/apps/agents/core/orchestrator.py +58 -58
- django_cfg/apps/agents/examples/simple_example.py +24 -19
- django_cfg/apps/agents/integration/__init__.py +1 -1
- django_cfg/apps/agents/integration/middleware.py +12 -11
- django_cfg/apps/agents/integration/registry.py +52 -49
- django_cfg/apps/agents/integration/signals.py +5 -5
- django_cfg/apps/agents/management/commands/create_agent.py +39 -38
- django_cfg/apps/agents/management/commands/orchestrator_status.py +40 -39
- django_cfg/apps/agents/managers/__init__.py +8 -3
- django_cfg/apps/agents/managers/execution.py +42 -41
- django_cfg/apps/agents/managers/registry.py +40 -39
- django_cfg/apps/agents/managers/toolsets.py +87 -86
- django_cfg/apps/agents/migrations/0001_initial.py +2 -1
- django_cfg/apps/agents/models/__init__.py +2 -2
- django_cfg/apps/agents/models/execution.py +43 -42
- django_cfg/apps/agents/models/registry.py +46 -45
- django_cfg/apps/agents/models/toolsets.py +63 -62
- django_cfg/apps/agents/patterns/__init__.py +5 -5
- django_cfg/apps/agents/patterns/content_agents.py +17 -16
- django_cfg/apps/agents/toolsets/__init__.py +3 -3
- django_cfg/apps/agents/toolsets/cache_toolset.py +56 -55
- django_cfg/apps/agents/toolsets/django_toolset.py +43 -42
- django_cfg/apps/agents/toolsets/file_toolset.py +64 -63
- django_cfg/apps/agents/toolsets/orm_toolset.py +75 -74
- django_cfg/apps/agents/urls.py +3 -2
- django_cfg/apps/api/commands/urls.py +1 -0
- django_cfg/apps/api/commands/views.py +23 -26
- django_cfg/apps/api/endpoints/checker.py +5 -4
- django_cfg/apps/api/endpoints/drf_views.py +2 -2
- django_cfg/apps/api/endpoints/tests.py +6 -5
- django_cfg/apps/api/endpoints/urls.py +2 -1
- django_cfg/apps/api/endpoints/views.py +1 -0
- django_cfg/apps/api/health/drf_views.py +6 -6
- django_cfg/apps/api/health/urls.py +2 -1
- django_cfg/apps/api/health/views.py +41 -41
- django_cfg/{modules/django_ipc_client → apps/ipc}/__init__.py +6 -6
- django_cfg/apps/ipc/apps.py +28 -0
- django_cfg/apps/ipc/serializers/__init__.py +19 -0
- django_cfg/apps/ipc/serializers/serializers.py +229 -0
- django_cfg/apps/ipc/services/__init__.py +7 -0
- django_cfg/apps/ipc/services/client/__init__.py +23 -0
- django_cfg/{modules/django_ipc_client → apps/ipc/services/client}/client.py +7 -6
- django_cfg/{modules/django_ipc_client → apps/ipc/services/client}/exceptions.py +1 -1
- django_cfg/{modules/django_ipc_client/dashboard → apps/ipc/services}/monitor.py +23 -5
- django_cfg/{modules/django_ipc_client/dashboard/static/django_ipc_dashboard/js/dashboard.js → apps/ipc/static/django_cfg_ipc/js/dashboard.mjs} +131 -63
- django_cfg/{modules/django_ipc_client/dashboard/templates/django_ipc_dashboard → apps/ipc/templates/django_cfg_ipc}/base.html +5 -10
- django_cfg/apps/ipc/templates/django_cfg_ipc/dashboard.html +202 -0
- django_cfg/apps/ipc/urls.py +21 -0
- django_cfg/apps/ipc/urls_admin.py +20 -0
- django_cfg/apps/ipc/views/__init__.py +8 -0
- django_cfg/apps/ipc/views/dashboard.py +15 -0
- django_cfg/apps/ipc/views/viewsets.py +245 -0
- django_cfg/apps/knowbase/admin/__init__.py +2 -2
- django_cfg/apps/knowbase/admin/actions/__init__.py +1 -1
- django_cfg/apps/knowbase/admin/actions/visibility_actions.py +2 -1
- django_cfg/apps/knowbase/admin/archive_admin.py +81 -84
- django_cfg/apps/knowbase/admin/chat_admin.py +70 -72
- django_cfg/apps/knowbase/admin/document_admin.py +10 -11
- django_cfg/apps/knowbase/admin/external_data_admin.py +69 -71
- django_cfg/apps/knowbase/admin/helpers/__init__.py +1 -1
- django_cfg/apps/knowbase/admin/helpers/configs.py +2 -2
- django_cfg/apps/knowbase/admin/helpers/statistics.py +1 -1
- django_cfg/apps/knowbase/apps.py +13 -13
- django_cfg/apps/knowbase/config/__init__.py +7 -6
- django_cfg/apps/knowbase/config/constance_fields.py +14 -12
- django_cfg/apps/knowbase/config/constance_settings.py +32 -31
- django_cfg/apps/knowbase/config/settings.py +28 -28
- django_cfg/apps/knowbase/examples/external_data_usage.py +35 -32
- django_cfg/apps/knowbase/management/commands/knowbase_stats.py +33 -32
- django_cfg/apps/knowbase/management/commands/setup_knowbase.py +11 -13
- django_cfg/apps/knowbase/managers/__init__.py +2 -2
- django_cfg/apps/knowbase/managers/archive.py +86 -85
- django_cfg/apps/knowbase/managers/base.py +5 -5
- django_cfg/apps/knowbase/managers/chat.py +29 -28
- django_cfg/apps/knowbase/managers/document.py +39 -39
- django_cfg/apps/knowbase/managers/external_data.py +74 -73
- django_cfg/apps/knowbase/migrations/0001_initial.py +2 -1
- django_cfg/apps/knowbase/migrations/0002_archiveitem_archiveitemchunk_documentarchive_and_more.py +2 -1
- django_cfg/apps/knowbase/migrations/0003_alter_documentarchive_archive_type.py +29 -0
- django_cfg/apps/knowbase/mixins/__init__.py +4 -4
- django_cfg/apps/knowbase/mixins/config/__init__.py +1 -1
- django_cfg/apps/knowbase/mixins/config/meta_config.py +1 -1
- django_cfg/apps/knowbase/mixins/config.py +19 -18
- django_cfg/apps/knowbase/mixins/creator.py +7 -7
- django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +29 -28
- django_cfg/apps/knowbase/mixins/external_data_mixin.py +6 -5
- django_cfg/apps/knowbase/mixins/generators/__init__.py +1 -1
- django_cfg/apps/knowbase/mixins/generators/content_generator.py +2 -2
- django_cfg/apps/knowbase/mixins/service.py +47 -45
- django_cfg/apps/knowbase/models/__init__.py +7 -7
- django_cfg/apps/knowbase/models/archive.py +72 -72
- django_cfg/apps/knowbase/models/base.py +12 -13
- django_cfg/apps/knowbase/models/chat.py +20 -19
- django_cfg/apps/knowbase/models/document.py +37 -35
- django_cfg/apps/knowbase/models/external_data.py +41 -42
- django_cfg/apps/knowbase/serializers/__init__.py +7 -7
- django_cfg/apps/knowbase/serializers/archive_serializers.py +50 -42
- django_cfg/apps/knowbase/serializers/chat_serializers.py +16 -15
- django_cfg/apps/knowbase/serializers/document_serializers.py +13 -12
- django_cfg/apps/knowbase/serializers/external_data_serializers.py +31 -31
- django_cfg/apps/knowbase/serializers/public_serializers.py +10 -9
- django_cfg/apps/knowbase/services/__init__.py +7 -7
- django_cfg/apps/knowbase/services/archive/__init__.py +7 -7
- django_cfg/apps/knowbase/services/archive/analyzers/__init__.py +1 -1
- django_cfg/apps/knowbase/services/archive/analyzers/tag_generator.py +1 -1
- django_cfg/apps/knowbase/services/archive/archive_service.py +109 -112
- django_cfg/apps/knowbase/services/archive/chunking/__init__.py +3 -3
- django_cfg/apps/knowbase/services/archive/chunking/base.py +1 -0
- django_cfg/apps/knowbase/services/archive/chunking/json_chunker.py +4 -3
- django_cfg/apps/knowbase/services/archive/chunking/markdown_chunker.py +5 -4
- django_cfg/apps/knowbase/services/archive/chunking/python_chunker.py +6 -5
- django_cfg/apps/knowbase/services/archive/chunking/text_chunker.py +4 -3
- django_cfg/apps/knowbase/services/archive/chunking_service.py +3 -7
- django_cfg/apps/knowbase/services/archive/context/__init__.py +1 -1
- django_cfg/apps/knowbase/services/archive/context/builders.py +2 -1
- django_cfg/apps/knowbase/services/archive/context/models.py +2 -1
- django_cfg/apps/knowbase/services/archive/exceptions.py +5 -5
- django_cfg/apps/knowbase/services/archive/extraction_service.py +111 -110
- django_cfg/apps/knowbase/services/archive/vectorization_service.py +80 -77
- django_cfg/apps/knowbase/services/base.py +11 -9
- django_cfg/apps/knowbase/services/chat_service.py +40 -39
- django_cfg/apps/knowbase/services/document_service.py +28 -27
- django_cfg/apps/knowbase/services/embedding/__init__.py +9 -9
- django_cfg/apps/knowbase/services/embedding/async_processor.py +38 -40
- django_cfg/apps/knowbase/services/embedding/batch_processor.py +45 -42
- django_cfg/apps/knowbase/services/embedding/batch_result.py +7 -6
- django_cfg/apps/knowbase/services/embedding/models.py +52 -51
- django_cfg/apps/knowbase/services/embedding/processors.py +24 -23
- django_cfg/apps/knowbase/services/embedding/utils.py +17 -17
- django_cfg/apps/knowbase/services/prompt_builder.py +24 -23
- django_cfg/apps/knowbase/services/search_service.py +52 -49
- django_cfg/apps/knowbase/signals/__init__.py +2 -5
- django_cfg/apps/knowbase/signals/archive_signals.py +35 -34
- django_cfg/apps/knowbase/signals/chat_signals.py +6 -5
- django_cfg/apps/knowbase/signals/document_signals.py +22 -22
- django_cfg/apps/knowbase/signals/external_data_signals.py +22 -22
- django_cfg/apps/knowbase/tasks/__init__.py +6 -7
- django_cfg/apps/knowbase/tasks/archive_tasks.py +41 -41
- django_cfg/apps/knowbase/tasks/document_processing.py +49 -44
- django_cfg/apps/knowbase/tasks/external_data_tasks.py +46 -44
- django_cfg/apps/knowbase/tasks/maintenance.py +26 -24
- django_cfg/apps/knowbase/urls.py +3 -2
- django_cfg/apps/knowbase/urls_admin.py +6 -3
- django_cfg/apps/knowbase/urls_system.py +4 -5
- django_cfg/apps/knowbase/utils/chunk_settings.py +22 -20
- django_cfg/apps/knowbase/utils/text_processing.py +76 -75
- django_cfg/apps/knowbase/utils/validation.py +9 -9
- django_cfg/apps/knowbase/views/__init__.py +5 -5
- django_cfg/apps/knowbase/views/archive_views.py +90 -87
- django_cfg/apps/knowbase/views/base.py +9 -12
- django_cfg/apps/knowbase/views/chat_views.py +35 -32
- django_cfg/apps/knowbase/views/document_views.py +27 -28
- django_cfg/apps/knowbase/views/public_views.py +19 -19
- django_cfg/apps/leads/admin/leads_admin.py +41 -45
- django_cfg/apps/leads/admin/resources.py +14 -14
- django_cfg/apps/leads/admin.py +7 -9
- django_cfg/apps/leads/apps.py +1 -1
- django_cfg/apps/leads/models.py +17 -17
- django_cfg/apps/leads/serializers.py +5 -4
- django_cfg/apps/leads/signals.py +7 -7
- django_cfg/apps/leads/tests.py +47 -47
- django_cfg/apps/leads/urls.py +2 -2
- django_cfg/apps/leads/views.py +11 -11
- django_cfg/apps/maintenance/__init__.py +3 -3
- django_cfg/apps/maintenance/admin/__init__.py +1 -1
- django_cfg/apps/maintenance/admin/api_key_admin.py +36 -36
- django_cfg/apps/maintenance/admin/log_admin.py +35 -37
- django_cfg/apps/maintenance/admin/scheduled_admin.py +47 -51
- django_cfg/apps/maintenance/admin/site_admin.py +49 -52
- django_cfg/apps/maintenance/apps.py +2 -2
- django_cfg/apps/maintenance/management/commands/maintenance.py +53 -52
- django_cfg/apps/maintenance/management/commands/process_scheduled_maintenance.py +44 -44
- django_cfg/apps/maintenance/management/commands/sync_cloudflare.py +32 -32
- django_cfg/apps/maintenance/managers/__init__.py +1 -1
- django_cfg/apps/maintenance/managers/cloudflare_site_manager.py +39 -38
- django_cfg/apps/maintenance/managers/maintenance_log_manager.py +32 -31
- django_cfg/apps/maintenance/migrations/0001_initial.py +1 -0
- django_cfg/apps/maintenance/models/__init__.py +2 -2
- django_cfg/apps/maintenance/models/cloudflare_api_key.py +15 -15
- django_cfg/apps/maintenance/models/cloudflare_site.py +24 -22
- django_cfg/apps/maintenance/models/maintenance_log.py +15 -14
- django_cfg/apps/maintenance/models/scheduled_maintenance.py +53 -52
- django_cfg/apps/maintenance/services/__init__.py +3 -3
- django_cfg/apps/maintenance/services/bulk_operations_service.py +68 -68
- django_cfg/apps/maintenance/services/maintenance_service.py +59 -58
- django_cfg/apps/maintenance/services/scheduled_maintenance_service.py +52 -52
- django_cfg/apps/maintenance/services/site_sync_service.py +64 -65
- django_cfg/apps/maintenance/utils/__init__.py +1 -1
- django_cfg/apps/maintenance/utils/retry_utils.py +17 -17
- django_cfg/apps/newsletter/admin/__init__.py +12 -16
- django_cfg/apps/newsletter/admin/newsletter_admin.py +90 -87
- django_cfg/apps/newsletter/admin/resources.py +29 -29
- django_cfg/apps/newsletter/admin.py +39 -32
- django_cfg/apps/newsletter/management/commands/test_newsletter.py +3 -3
- django_cfg/apps/newsletter/managers/__init__.py +1 -1
- django_cfg/apps/newsletter/migrations/0001_initial.py +2 -1
- django_cfg/apps/newsletter/models.py +34 -33
- django_cfg/apps/newsletter/serializers.py +13 -13
- django_cfg/apps/newsletter/services/email_service.py +42 -40
- django_cfg/apps/newsletter/signals.py +4 -3
- django_cfg/apps/newsletter/urls.py +7 -7
- django_cfg/apps/newsletter/views/__init__.py +14 -19
- django_cfg/apps/newsletter/views/campaigns.py +19 -19
- django_cfg/apps/newsletter/views/emails.py +20 -20
- django_cfg/apps/newsletter/views/newsletters.py +5 -5
- django_cfg/apps/newsletter/views/subscriptions.py +24 -24
- django_cfg/apps/newsletter/views/tracking.py +6 -5
- django_cfg/apps/payments/admin/__init__.py +6 -5
- django_cfg/apps/payments/admin/api_keys_admin.py +43 -45
- django_cfg/apps/payments/admin/balance_admin.py +41 -47
- django_cfg/apps/payments/admin/currencies_admin.py +60 -62
- django_cfg/apps/payments/admin/endpoint_groups_admin.py +14 -28
- django_cfg/apps/payments/admin/filters.py +59 -59
- django_cfg/apps/payments/admin/networks_admin.py +36 -50
- django_cfg/apps/payments/admin/payments_admin.py +47 -49
- django_cfg/apps/payments/admin/subscriptions_admin.py +30 -32
- django_cfg/apps/payments/admin/tariffs_admin.py +37 -42
- django_cfg/apps/payments/admin_interface/serializers/__init__.py +12 -13
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +28 -27
- django_cfg/apps/payments/admin_interface/serializers/webhook_serializers.py +4 -5
- django_cfg/apps/payments/admin_interface/templates/payments/base.html +407 -3
- django_cfg/apps/payments/admin_interface/templates/payments/components/ngrok_status.html +13 -13
- django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +5 -1
- django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +105 -49
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +4 -1
- django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +16 -8
- django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +16 -8
- django_cfg/apps/payments/admin_interface/views/__init__.py +8 -9
- django_cfg/apps/payments/admin_interface/views/api/__init__.py +3 -3
- django_cfg/apps/payments/admin_interface/views/api/payments.py +52 -54
- django_cfg/apps/payments/admin_interface/views/api/stats.py +33 -30
- django_cfg/apps/payments/admin_interface/views/api/users.py +10 -11
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +46 -51
- django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +9 -9
- django_cfg/apps/payments/admin_interface/views/base.py +17 -19
- django_cfg/apps/payments/admin_interface/views/dashboard.py +10 -10
- django_cfg/apps/payments/admin_interface/views/forms.py +21 -20
- django_cfg/apps/payments/apps.py +7 -6
- django_cfg/apps/payments/config/__init__.py +4 -4
- django_cfg/apps/payments/config/django_cfg_integration.py +22 -21
- django_cfg/apps/payments/config/helpers.py +14 -12
- django_cfg/apps/payments/management/commands/cleanup_expired_data.py +85 -86
- django_cfg/apps/payments/management/commands/currency_stats.py +84 -87
- django_cfg/apps/payments/management/commands/manage_currencies.py +59 -58
- django_cfg/apps/payments/management/commands/manage_providers.py +103 -105
- django_cfg/apps/payments/management/commands/process_pending_payments.py +67 -70
- django_cfg/apps/payments/management/commands/test_providers.py +83 -84
- django_cfg/apps/payments/middleware/__init__.py +1 -1
- django_cfg/apps/payments/middleware/api_access.py +77 -78
- django_cfg/apps/payments/middleware/rate_limiting.py +72 -72
- django_cfg/apps/payments/middleware/usage_tracking.py +66 -64
- django_cfg/apps/payments/migrations/0001_initial.py +2 -1
- django_cfg/apps/payments/models/__init__.py +11 -12
- django_cfg/apps/payments/models/api_keys.py +29 -27
- django_cfg/apps/payments/models/balance.py +38 -38
- django_cfg/apps/payments/models/base.py +12 -11
- django_cfg/apps/payments/models/currencies.py +53 -52
- django_cfg/apps/payments/models/managers/__init__.py +13 -14
- django_cfg/apps/payments/models/managers/api_key_managers.py +55 -53
- django_cfg/apps/payments/models/managers/balance_managers.py +98 -97
- django_cfg/apps/payments/models/managers/currency_managers.py +70 -69
- django_cfg/apps/payments/models/managers/payment_managers.py +113 -111
- django_cfg/apps/payments/models/managers/subscription_managers.py +99 -97
- django_cfg/apps/payments/models/payments.py +167 -73
- django_cfg/apps/payments/models/subscriptions.py +56 -54
- django_cfg/apps/payments/models/tariffs.py +35 -34
- django_cfg/apps/payments/services/__init__.py +33 -36
- django_cfg/apps/payments/services/cache/__init__.py +7 -1
- django_cfg/apps/payments/services/cache_service/__init__.py +22 -20
- django_cfg/apps/payments/services/cache_service/api_key_cache.py +6 -5
- django_cfg/apps/payments/services/cache_service/interfaces.py +5 -5
- django_cfg/apps/payments/services/cache_service/keys.py +8 -8
- django_cfg/apps/payments/services/cache_service/rate_limit_cache.py +8 -7
- django_cfg/apps/payments/services/cache_service/simple_cache.py +17 -14
- django_cfg/apps/payments/services/core/__init__.py +3 -3
- django_cfg/apps/payments/services/core/balance_service.py +69 -65
- django_cfg/apps/payments/services/core/base.py +25 -22
- django_cfg/apps/payments/services/core/currency/__init__.py +1 -1
- django_cfg/apps/payments/services/core/currency/currency_converter.py +2 -0
- django_cfg/apps/payments/services/core/currency_service.py +68 -66
- django_cfg/apps/payments/services/core/operations/__init__.py +1 -1
- django_cfg/apps/payments/services/core/operations/payment_canceller.py +2 -1
- django_cfg/apps/payments/services/core/operations/payment_creator.py +2 -1
- django_cfg/apps/payments/services/core/operations/status_checker.py +2 -1
- django_cfg/apps/payments/services/core/payment_service.py +10 -7
- django_cfg/apps/payments/services/core/providers/provider_client.py +2 -2
- django_cfg/apps/payments/services/core/subscription_service.py +77 -74
- django_cfg/apps/payments/services/core/utils/data_converter.py +1 -0
- django_cfg/apps/payments/services/core/utils/statistics_calculator.py +1 -0
- django_cfg/apps/payments/services/core/webhook_service.py +67 -63
- django_cfg/apps/payments/services/integrations/__init__.py +3 -3
- django_cfg/apps/payments/services/integrations/ngrok_service.py +1 -0
- django_cfg/apps/payments/services/integrations/providers_config.py +3 -2
- django_cfg/apps/payments/services/providers/base.py +59 -57
- django_cfg/apps/payments/services/providers/models/__init__.py +7 -14
- django_cfg/apps/payments/services/providers/models/base.py +15 -15
- django_cfg/apps/payments/services/providers/models/providers.py +13 -12
- django_cfg/apps/payments/services/providers/models/universal.py +6 -5
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +4 -4
- django_cfg/apps/payments/services/providers/nowpayments/config.py +9 -8
- django_cfg/apps/payments/services/providers/nowpayments/models.py +15 -15
- django_cfg/apps/payments/services/providers/nowpayments/parsers/data/__init__.py +2 -2
- django_cfg/apps/payments/services/providers/nowpayments/parsers/data/patterns.py +26 -26
- django_cfg/apps/payments/services/providers/nowpayments/parsers/parser.py +3 -2
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +95 -99
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +41 -40
- django_cfg/apps/payments/services/providers/registry.py +65 -63
- django_cfg/apps/payments/services/providers/sync_service.py +50 -50
- django_cfg/apps/payments/services/types/__init__.py +21 -22
- django_cfg/apps/payments/services/types/data.py +14 -13
- django_cfg/apps/payments/services/types/requests.py +21 -22
- django_cfg/apps/payments/services/types/responses.py +16 -15
- django_cfg/apps/payments/services/types/webhooks.py +30 -30
- django_cfg/apps/payments/signals/__init__.py +4 -6
- django_cfg/apps/payments/signals/api_key_signals.py +36 -35
- django_cfg/apps/payments/signals/balance_signals.py +28 -26
- django_cfg/apps/payments/signals/payment_signals.py +29 -28
- django_cfg/apps/payments/signals/subscription_signals.py +39 -38
- django_cfg/apps/payments/static/payments/js/ngrok-status.js +12 -8
- django_cfg/apps/payments/static/payments/js/payment-detail.js +1 -1
- django_cfg/apps/payments/static/payments/js/payment-form.js +3 -3
- django_cfg/apps/payments/static/payments/js/payment-list.js +13 -6
- django_cfg/apps/payments/static/payments/js/webhook-dashboard-mjs.js +241 -0
- django_cfg/apps/payments/tasks/__init__.py +11 -12
- django_cfg/apps/payments/tasks/types.py +10 -9
- django_cfg/apps/payments/tasks/usage_tracking.py +44 -46
- django_cfg/apps/payments/templatetags/payment_tags.py +27 -27
- django_cfg/apps/payments/urls.py +31 -14
- django_cfg/apps/payments/urls_admin.py +10 -10
- django_cfg/apps/payments/views/api/__init__.py +32 -33
- django_cfg/apps/payments/views/api/api_keys.py +62 -62
- django_cfg/apps/payments/views/api/balances.py +63 -64
- django_cfg/apps/payments/views/api/base.py +52 -52
- django_cfg/apps/payments/views/api/currencies.py +75 -63
- django_cfg/apps/payments/views/api/payments.py +73 -74
- django_cfg/apps/payments/views/api/subscriptions.py +71 -72
- django_cfg/apps/payments/views/api/webhooks.py +85 -84
- django_cfg/apps/payments/views/overview/__init__.py +7 -7
- django_cfg/apps/payments/views/overview/serializers.py +13 -14
- django_cfg/apps/payments/views/overview/services.py +66 -67
- django_cfg/apps/payments/views/overview/urls.py +2 -1
- django_cfg/apps/payments/views/overview/views.py +31 -31
- django_cfg/apps/payments/views/serializers/__init__.py +35 -36
- django_cfg/apps/payments/views/serializers/api_keys.py +59 -57
- django_cfg/apps/payments/views/serializers/balances.py +34 -33
- django_cfg/apps/payments/views/serializers/currencies.py +36 -34
- django_cfg/apps/payments/views/serializers/payments.py +48 -47
- django_cfg/apps/payments/views/serializers/subscriptions.py +50 -45
- django_cfg/apps/payments/views/serializers/webhooks.py +17 -16
- django_cfg/apps/support/admin/__init__.py +3 -3
- django_cfg/apps/support/admin/resources.py +26 -26
- django_cfg/apps/support/admin/support_admin.py +44 -48
- django_cfg/apps/support/admin.py +16 -15
- django_cfg/apps/support/apps.py +1 -1
- django_cfg/apps/support/managers/message_manager.py +4 -4
- django_cfg/apps/support/managers/ticket_manager.py +13 -12
- django_cfg/apps/support/migrations/0001_initial.py +2 -1
- django_cfg/apps/support/models.py +3 -1
- django_cfg/apps/support/serializers.py +4 -2
- django_cfg/apps/support/signals.py +12 -10
- django_cfg/apps/support/urls.py +4 -3
- django_cfg/apps/support/utils/support_email_service.py +11 -9
- django_cfg/apps/support/views/__init__.py +3 -3
- django_cfg/apps/support/views/admin.py +9 -9
- django_cfg/apps/support/views/api.py +12 -13
- django_cfg/apps/support/views/chat.py +14 -14
- django_cfg/apps/tasks/admin/tasks_admin.py +65 -74
- django_cfg/apps/tasks/apps.py +2 -2
- django_cfg/apps/tasks/serializers.py +6 -6
- django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +44 -20
- django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +7 -5
- django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +5 -3
- django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +5 -3
- django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +5 -3
- django_cfg/apps/tasks/tasks/demo_tasks.py +12 -11
- django_cfg/apps/tasks/templates/tasks/components/tasks_mjs_integration.html +269 -0
- django_cfg/apps/tasks/templates/tasks/pages/dashboard-improved.html +168 -0
- django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +21 -2
- django_cfg/apps/tasks/urls.py +3 -2
- django_cfg/apps/tasks/urls_admin.py +1 -0
- django_cfg/apps/tasks/utils/simulator.py +49 -52
- django_cfg/apps/tasks/views/api.py +75 -73
- django_cfg/apps/tasks/views/dashboard.py +5 -4
- django_cfg/apps/urls.py +20 -11
- django_cfg/apps.py +6 -5
- django_cfg/cli/commands/create_project.py +7 -6
- django_cfg/cli/commands/info.py +25 -25
- django_cfg/cli/utils.py +27 -27
- django_cfg/config.py +1 -1
- django_cfg/core/__init__.py +8 -8
- django_cfg/core/base/config_model.py +13 -12
- django_cfg/core/builders/apps_builder.py +2 -2
- django_cfg/core/builders/middleware_builder.py +1 -1
- django_cfg/core/builders/security_builder.py +1 -1
- django_cfg/core/config.py +2 -2
- django_cfg/core/environment/detector.py +27 -28
- django_cfg/core/exceptions.py +1 -1
- django_cfg/core/generation/core_generators/settings.py +1 -1
- django_cfg/core/generation/core_generators/static.py +11 -5
- django_cfg/core/generation/core_generators/templates.py +1 -1
- django_cfg/core/generation/data_generators/__init__.py +1 -1
- django_cfg/core/generation/data_generators/cache.py +1 -1
- django_cfg/core/generation/data_generators/database.py +1 -1
- django_cfg/core/generation/generation.py +1 -3
- django_cfg/core/generation/integration_generators/__init__.py +2 -2
- django_cfg/core/generation/integration_generators/api.py +12 -2
- django_cfg/core/generation/integration_generators/sessions.py +1 -1
- django_cfg/core/generation/integration_generators/tailwind.py +1 -1
- django_cfg/core/generation/integration_generators/tasks.py +1 -1
- django_cfg/core/generation/integration_generators/third_party.py +1 -1
- django_cfg/core/generation/orchestrator.py +1 -1
- django_cfg/core/generation/protocols.py +1 -1
- django_cfg/core/generation/utility_generators/__init__.py +1 -1
- django_cfg/core/generation/utility_generators/email.py +1 -1
- django_cfg/core/generation/utility_generators/i18n.py +1 -1
- django_cfg/core/generation/utility_generators/limits.py +1 -1
- django_cfg/core/generation/utility_generators/logging.py +1 -1
- django_cfg/core/generation/utility_generators/security.py +1 -1
- django_cfg/core/generation/utils/helpers.py +1 -1
- django_cfg/core/integration/__init__.py +5 -5
- django_cfg/core/integration/commands_collector.py +38 -39
- django_cfg/core/integration/display/__init__.py +2 -2
- django_cfg/core/integration/display/base.py +30 -30
- django_cfg/core/integration/display/ngrok.py +35 -36
- django_cfg/core/integration/display/startup.py +149 -139
- django_cfg/core/integration/url_integration.py +10 -10
- django_cfg/core/integration/version_checker.py +20 -19
- django_cfg/core/services/config_service.py +4 -4
- django_cfg/core/state/__init__.py +1 -1
- django_cfg/core/state/registry.py +1 -1
- django_cfg/core/types/__init__.py +8 -1
- django_cfg/core/validation.py +36 -39
- django_cfg/management/commands/check_endpoints.py +3 -1
- django_cfg/management/commands/check_settings.py +3 -1
- django_cfg/management/commands/clear_constance.py +3 -1
- django_cfg/management/commands/create_token.py +3 -1
- django_cfg/management/commands/generate_clients.py +3 -1
- django_cfg/management/commands/migrate_all.py +3 -1
- django_cfg/management/commands/rundramatiq.py +3 -1
- django_cfg/management/commands/rundramatiq_simulator.py +3 -1
- django_cfg/management/commands/runserver_ngrok.py +3 -1
- django_cfg/management/commands/show_config.py +3 -1
- django_cfg/management/commands/superuser.py +3 -1
- django_cfg/management/commands/task_clear.py +3 -1
- django_cfg/management/commands/task_status.py +3 -1
- django_cfg/management/commands/test_email.py +3 -1
- django_cfg/management/commands/test_telegram.py +3 -1
- django_cfg/management/commands/test_twilio.py +3 -1
- django_cfg/management/commands/validate_openapi.py +3 -1
- django_cfg/middleware/pagination.py +8 -8
- django_cfg/middleware/public_endpoints.py +24 -23
- django_cfg/middleware/user_activity.py +27 -25
- django_cfg/models/__init__.py +19 -20
- django_cfg/models/api/__init__.py +4 -4
- django_cfg/models/api/config.py +23 -21
- django_cfg/models/api/cors.py +17 -16
- django_cfg/models/api/drf/__init__.py +1 -1
- django_cfg/models/api/drf/config.py +2 -1
- django_cfg/models/api/drf/redoc.py +2 -1
- django_cfg/models/api/drf/spectacular.py +4 -2
- django_cfg/models/api/drf/swagger.py +2 -1
- django_cfg/models/api/jwt.py +37 -36
- django_cfg/models/api/keys.py +13 -12
- django_cfg/models/api/limits.py +31 -30
- django_cfg/models/base/config.py +40 -41
- django_cfg/models/base/module.py +8 -8
- django_cfg/models/django/__init__.py +1 -1
- django_cfg/models/django/constance.py +8 -7
- django_cfg/models/django/environment.py +5 -3
- django_cfg/models/django/openapi.py +6 -16
- django_cfg/models/django/revolution_legacy.py +17 -16
- django_cfg/models/infrastructure/__init__.py +1 -1
- django_cfg/models/infrastructure/cache.py +46 -45
- django_cfg/models/infrastructure/database/config.py +4 -6
- django_cfg/models/infrastructure/database/converters.py +1 -1
- django_cfg/models/infrastructure/database/parsers.py +1 -1
- django_cfg/models/infrastructure/database/validators.py +1 -1
- django_cfg/models/infrastructure/logging.py +59 -57
- django_cfg/models/infrastructure/security.py +26 -24
- django_cfg/models/ngrok/auth.py +2 -1
- django_cfg/models/ngrok/config.py +3 -2
- django_cfg/models/ngrok/tunnel.py +2 -1
- django_cfg/models/payments/__init__.py +1 -1
- django_cfg/models/payments/api_keys.py +3 -1
- django_cfg/models/payments/config.py +4 -1
- django_cfg/models/payments/providers/base.py +2 -1
- django_cfg/models/payments/providers/nowpayments.py +3 -1
- django_cfg/models/services/__init__.py +1 -1
- django_cfg/models/services/base.py +2 -1
- django_cfg/models/services/email.py +28 -26
- django_cfg/models/services/telegram.py +2 -1
- django_cfg/models/tasks/__init__.py +2 -2
- django_cfg/models/tasks/backends.py +4 -3
- django_cfg/models/tasks/config.py +6 -4
- django_cfg/models/tasks/utils.py +3 -3
- django_cfg/modules/base.py +18 -17
- django_cfg/modules/django_admin/__init__.py +14 -15
- django_cfg/modules/django_admin/decorators/__init__.py +1 -1
- django_cfg/modules/django_admin/decorators/actions.py +8 -7
- django_cfg/modules/django_admin/decorators/display.py +9 -7
- django_cfg/modules/django_admin/icons/__init__.py +1 -1
- django_cfg/modules/django_admin/icons/constants.py +27 -27
- django_cfg/modules/django_admin/icons/generate_icons.py +54 -54
- django_cfg/modules/django_admin/management/commands/check_endpoints.py +5 -3
- django_cfg/modules/django_admin/management/commands/check_settings.py +40 -44
- django_cfg/modules/django_admin/management/commands/clear_constance.py +29 -30
- django_cfg/modules/django_admin/management/commands/create_token.py +42 -42
- django_cfg/modules/django_admin/management/commands/list_urls.py +37 -38
- django_cfg/modules/django_admin/management/commands/migrate_all.py +13 -15
- django_cfg/modules/django_admin/management/commands/migrator.py +17 -17
- django_cfg/modules/django_admin/management/commands/script.py +58 -60
- django_cfg/modules/django_admin/management/commands/show_config.py +32 -30
- django_cfg/modules/django_admin/management/commands/show_urls.py +46 -44
- django_cfg/modules/django_admin/management/commands/superuser.py +47 -48
- django_cfg/modules/django_admin/management/commands/tree.py +50 -54
- django_cfg/modules/django_admin/mixins/display_mixin.py +16 -15
- django_cfg/modules/django_admin/mixins/optimization_mixin.py +9 -8
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +25 -24
- django_cfg/modules/django_admin/models/__init__.py +4 -4
- django_cfg/modules/django_admin/models/action_models.py +3 -1
- django_cfg/modules/django_admin/models/badge_models.py +4 -2
- django_cfg/modules/django_admin/models/base.py +3 -3
- django_cfg/modules/django_admin/models/display_models.py +1 -0
- django_cfg/modules/django_admin/utils/badges.py +27 -26
- django_cfg/modules/django_admin/utils/displays.py +49 -49
- django_cfg/modules/django_client/apps.py +21 -3
- django_cfg/modules/django_client/core/__init__.py +9 -10
- django_cfg/modules/django_client/core/archive/manager.py +2 -2
- django_cfg/modules/django_client/core/cli/main.py +1 -3
- django_cfg/modules/django_client/core/config/config.py +3 -1
- django_cfg/modules/django_client/core/config/group.py +1 -0
- django_cfg/modules/django_client/core/config/service.py +2 -1
- django_cfg/modules/django_client/core/generator/__init__.py +1 -1
- django_cfg/modules/django_client/core/generator/base.py +2 -2
- django_cfg/modules/django_client/core/generator/python/async_client_gen.py +1 -1
- django_cfg/modules/django_client/core/generator/python/files_generator.py +1 -1
- django_cfg/modules/django_client/core/generator/python/generator.py +4 -4
- django_cfg/modules/django_client/core/generator/python/models_generator.py +1 -1
- django_cfg/modules/django_client/core/generator/python/operations_generator.py +2 -2
- django_cfg/modules/django_client/core/generator/python/sync_client_gen.py +1 -1
- django_cfg/modules/django_client/core/generator/typescript/client_generator.py +3 -1
- django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +14 -13
- django_cfg/modules/django_client/core/generator/typescript/files_generator.py +1 -0
- django_cfg/modules/django_client/core/generator/typescript/generator.py +6 -6
- django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +12 -10
- django_cfg/modules/django_client/core/generator/typescript/models_generator.py +2 -1
- django_cfg/modules/django_client/core/generator/typescript/naming.py +2 -3
- django_cfg/modules/django_client/core/generator/typescript/operations_generator.py +12 -10
- django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +3 -2
- django_cfg/modules/django_client/core/generator/typescript/templates/client/client.ts.jinja +14 -6
- django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +4 -10
- django_cfg/modules/django_client/core/groups/__init__.py +1 -1
- django_cfg/modules/django_client/core/groups/detector.py +2 -1
- django_cfg/modules/django_client/core/groups/manager.py +2 -1
- django_cfg/modules/django_client/core/ir/schema.py +1 -1
- django_cfg/modules/django_client/core/parser/base.py +0 -2
- django_cfg/modules/django_client/core/parser/models/schema.py +1 -1
- django_cfg/modules/django_client/core/validation/__init__.py +1 -1
- django_cfg/modules/django_client/core/validation/fixer.py +1 -2
- django_cfg/modules/django_client/core/validation/reporter.py +2 -2
- django_cfg/modules/django_client/core/validation/safety.py +1 -1
- django_cfg/modules/django_client/management/commands/generate_client.py +14 -11
- django_cfg/modules/django_client/management/commands/validate_openapi.py +4 -6
- django_cfg/modules/django_client/spectacular/__init__.py +1 -1
- django_cfg/modules/django_client/spectacular/async_detection.py +3 -2
- django_cfg/modules/django_client/spectacular/enum_naming.py +1 -1
- django_cfg/modules/django_client/spectacular/schema.py +5 -5
- django_cfg/modules/django_client/system/__init__.py +24 -0
- django_cfg/modules/django_client/system/base_generator.py +123 -0
- django_cfg/modules/django_client/system/generate_mjs_clients.py +174 -0
- django_cfg/modules/django_client/system/mjs_generator.py +219 -0
- django_cfg/modules/django_client/system/schema_parser.py +195 -0
- django_cfg/modules/django_client/system/templates/api_client.js.j2 +87 -0
- django_cfg/modules/django_client/system/templates/app_index.js.j2 +13 -0
- django_cfg/modules/django_client/system/templates/base_client.js.j2 +166 -0
- django_cfg/modules/django_client/system/templates/main_index.js.j2 +80 -0
- django_cfg/modules/django_client/system/templates/types.js.j2 +24 -0
- django_cfg/modules/django_client/urls.py +3 -2
- django_cfg/modules/django_currency/__init__.py +17 -18
- django_cfg/modules/django_currency/clients/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/coinpaprika_client.py +48 -48
- django_cfg/modules/django_currency/clients/hybrid_client.py +76 -75
- django_cfg/modules/django_currency/core/__init__.py +7 -13
- django_cfg/modules/django_currency/core/converter.py +25 -24
- django_cfg/modules/django_currency/core/models.py +9 -8
- django_cfg/modules/django_currency/database/__init__.py +4 -4
- django_cfg/modules/django_currency/database/database_loader.py +65 -66
- django_cfg/modules/django_currency/examples/example_database_usage.py +29 -28
- django_cfg/modules/django_currency/utils/cache.py +10 -11
- django_cfg/modules/django_dashboard/__init__.py +4 -5
- django_cfg/modules/django_dashboard/components.py +11 -7
- django_cfg/modules/django_dashboard/debug.py +1 -3
- django_cfg/modules/django_dashboard/management/commands/debug_dashboard.py +3 -3
- django_cfg/modules/django_dashboard/sections/base.py +2 -1
- django_cfg/modules/django_dashboard/sections/commands.py +3 -2
- django_cfg/modules/django_dashboard/sections/documentation.py +8 -6
- django_cfg/modules/django_dashboard/sections/overview.py +13 -9
- django_cfg/modules/django_dashboard/sections/stats.py +2 -2
- django_cfg/modules/django_dashboard/sections/system.py +2 -1
- django_cfg/modules/django_drf_theme/templatetags/tailwind_tags.py +12 -4
- django_cfg/modules/django_email/management/commands/test_email.py +8 -7
- django_cfg/modules/django_email/service.py +5 -4
- django_cfg/modules/django_health/service.py +46 -44
- django_cfg/modules/django_import_export/__init__.py +7 -3
- django_cfg/modules/django_llm/__init__.py +3 -2
- django_cfg/modules/django_llm/example.py +58 -56
- django_cfg/modules/django_llm/llm/__init__.py +1 -1
- django_cfg/modules/django_llm/llm/cache.py +21 -20
- django_cfg/modules/django_llm/llm/client.py +9 -9
- django_cfg/modules/django_llm/llm/costs.py +14 -14
- django_cfg/modules/django_llm/llm/embeddings/__init__.py +1 -1
- django_cfg/modules/django_llm/llm/embeddings/mock_embedder.py +1 -2
- django_cfg/modules/django_llm/llm/embeddings/openai_embedder.py +1 -2
- django_cfg/modules/django_llm/llm/extractor.py +8 -8
- django_cfg/modules/django_llm/llm/models.py +5 -5
- django_cfg/modules/django_llm/llm/models_api/models_query.py +2 -2
- django_cfg/modules/django_llm/llm/models_cache.py +91 -92
- django_cfg/modules/django_llm/llm/providers/config_builder.py +1 -1
- django_cfg/modules/django_llm/llm/providers/provider_manager.py +2 -1
- django_cfg/modules/django_llm/llm/requests/cache_manager.py +1 -1
- django_cfg/modules/django_llm/llm/requests/chat_handler.py +2 -2
- django_cfg/modules/django_llm/llm/requests/embedding_handler.py +1 -1
- django_cfg/modules/django_llm/llm/responses/response_builder.py +2 -2
- django_cfg/modules/django_llm/llm/stats/stats_manager.py +1 -1
- django_cfg/modules/django_llm/llm/tokenizer.py +10 -9
- django_cfg/modules/django_llm/translator/__init__.py +1 -1
- django_cfg/modules/django_llm/translator/cache.py +36 -35
- django_cfg/modules/django_llm/translator/detectors/__init__.py +1 -1
- django_cfg/modules/django_llm/translator/detectors/script_detector.py +0 -1
- django_cfg/modules/django_llm/translator/stats/stats_tracker.py +1 -1
- django_cfg/modules/django_llm/translator/translator.py +5 -4
- django_cfg/modules/django_llm/translator/translators/__init__.py +1 -1
- django_cfg/modules/django_llm/translator/translators/json_translator.py +1 -1
- django_cfg/modules/django_llm/translator/utils/__init__.py +1 -1
- django_cfg/modules/django_llm/translator/utils/prompt_builder.py +0 -1
- django_cfg/modules/django_logging/__init__.py +1 -1
- django_cfg/modules/django_logging/django_logger.py +33 -34
- django_cfg/modules/django_logging/logger.py +3 -7
- django_cfg/modules/django_ngrok/__init__.py +7 -7
- django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +33 -30
- django_cfg/modules/django_ngrok/service.py +33 -32
- django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +4 -36
- django_cfg/modules/django_tailwind/templates/django_tailwind/components/navbar.html +1 -1
- django_cfg/modules/django_tasks/__init__.py +5 -5
- django_cfg/modules/django_tasks/dramatiq_setup.py +1 -1
- django_cfg/modules/django_tasks/factory.py +1 -1
- django_cfg/modules/django_tasks/management/commands/rundramatiq.py +39 -40
- django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +79 -80
- django_cfg/modules/django_tasks/management/commands/task_clear.py +34 -34
- django_cfg/modules/django_tasks/management/commands/task_status.py +34 -34
- django_cfg/modules/django_tasks/service.py +4 -3
- django_cfg/modules/django_tasks/settings.py +1 -1
- django_cfg/modules/django_telegram/__init__.py +4 -4
- django_cfg/modules/django_telegram/management/commands/test_telegram.py +4 -5
- django_cfg/modules/django_telegram/service.py +4 -3
- django_cfg/modules/django_telegram/utils.py +1 -1
- django_cfg/modules/django_twilio/__init__.py +15 -16
- django_cfg/modules/django_twilio/_imports.py +1 -1
- django_cfg/modules/django_twilio/base.py +9 -5
- django_cfg/modules/django_twilio/email_otp.py +4 -3
- django_cfg/modules/django_twilio/exceptions.py +36 -36
- django_cfg/modules/django_twilio/management/commands/test_twilio.py +6 -7
- django_cfg/modules/django_twilio/models.py +54 -53
- django_cfg/modules/django_twilio/sendgrid_service.py +70 -72
- django_cfg/modules/django_twilio/simple_service.py +42 -41
- django_cfg/modules/django_twilio/sms.py +1 -0
- django_cfg/modules/django_twilio/twilio_service.py +79 -83
- django_cfg/modules/django_twilio/unified.py +6 -5
- django_cfg/modules/django_twilio/utils.py +2 -3
- django_cfg/modules/django_twilio/whatsapp.py +3 -2
- django_cfg/modules/django_unfold/__init__.py +7 -6
- django_cfg/modules/django_unfold/callbacks/actions.py +6 -5
- django_cfg/modules/django_unfold/callbacks/apizones.py +122 -0
- django_cfg/modules/django_unfold/callbacks/base.py +9 -8
- django_cfg/modules/django_unfold/callbacks/charts.py +36 -37
- django_cfg/modules/django_unfold/callbacks/commands.py +2 -2
- django_cfg/modules/django_unfold/callbacks/main.py +27 -27
- django_cfg/modules/django_unfold/callbacks/statistics.py +12 -12
- django_cfg/modules/django_unfold/callbacks/system.py +5 -5
- django_cfg/modules/django_unfold/callbacks/users.py +4 -4
- django_cfg/modules/django_unfold/dashboard.py +29 -29
- django_cfg/modules/django_unfold/models/__init__.py +23 -8
- django_cfg/modules/django_unfold/models/config.py +84 -81
- django_cfg/modules/django_unfold/models/dashboard.py +20 -19
- django_cfg/modules/django_unfold/models/dropdown.py +6 -4
- django_cfg/modules/django_unfold/models/navigation.py +6 -4
- django_cfg/modules/django_unfold/models/tabs.py +4 -3
- django_cfg/modules/django_unfold/models.py +2 -3
- django_cfg/modules/django_unfold/system_monitor.py +27 -25
- django_cfg/modules/django_unfold/tailwind.py +12 -14
- django_cfg/modules/django_unfold/utils.py +7 -6
- django_cfg/pyproject.toml +1 -1
- django_cfg/registry/__init__.py +3 -3
- django_cfg/registry/core.py +8 -8
- django_cfg/registry/modules.py +2 -2
- django_cfg/registry/services.py +2 -2
- django_cfg/registry/third_party.py +3 -3
- django_cfg/routing/__init__.py +3 -3
- django_cfg/routing/callbacks.py +27 -26
- django_cfg/routing/routers.py +2 -2
- django_cfg/static/js/api/accounts/client.mjs +69 -0
- django_cfg/static/js/api/accounts/index.mjs +13 -0
- django_cfg/static/js/api/base.mjs +166 -0
- django_cfg/static/js/api/index.mjs +100 -0
- django_cfg/static/js/api/ipc/client.mjs +74 -0
- django_cfg/static/js/api/ipc/index.mjs +13 -0
- django_cfg/static/js/api/leads/client.mjs +71 -0
- django_cfg/static/js/api/leads/index.mjs +13 -0
- django_cfg/static/js/api/newsletter/client.mjs +109 -0
- django_cfg/static/js/api/newsletter/index.mjs +13 -0
- django_cfg/static/js/api/payments/client.mjs +1264 -0
- django_cfg/static/js/api/payments/index.mjs +13 -0
- django_cfg/static/js/api/support/client.mjs +84 -0
- django_cfg/static/js/api/support/index.mjs +13 -0
- django_cfg/static/js/api/tasks/client.mjs +74 -0
- django_cfg/static/js/api/tasks/index.mjs +13 -0
- django_cfg/static/js/api/types.mjs +729 -0
- django_cfg/static/js/api-loader.mjs +169 -0
- django_cfg/templates/admin/snippets/zones/zones_table.html +4 -3
- django_cfg/templatetags/django_cfg.py +4 -4
- django_cfg/utils/path_resolution.py +49 -50
- django_cfg/utils/smart_defaults.py +27 -29
- django_cfg/utils/version_check.py +14 -14
- {django_cfg-1.4.20.dist-info → django_cfg-1.4.23.dist-info}/METADATA +1 -1
- django_cfg-1.4.23.dist-info/RECORD +1137 -0
- django_cfg/apps/payments/static/payments/js/api-client.js +0 -408
- django_cfg/modules/django_ipc_client/dashboard/README.md +0 -517
- django_cfg/modules/django_ipc_client/dashboard/UNFOLD_INTEGRATION.md +0 -439
- django_cfg/modules/django_ipc_client/dashboard/__init__.py +0 -11
- django_cfg/modules/django_ipc_client/dashboard/apps.py +0 -22
- django_cfg/modules/django_ipc_client/dashboard/templates/django_ipc_dashboard/dashboard.html +0 -200
- django_cfg/modules/django_ipc_client/dashboard/urls.py +0 -22
- django_cfg/modules/django_ipc_client/dashboard/urls_admin.py +0 -9
- django_cfg/modules/django_ipc_client/dashboard/views.py +0 -251
- django_cfg/modules/django_rpc_old/POETRY.md +0 -344
- django_cfg/modules/django_rpc_old/README.md +0 -397
- django_cfg/modules/django_rpc_old/TESTING.md +0 -358
- django_cfg/modules/django_rpc_old/__init__.py +0 -39
- django_cfg/modules/django_rpc_old/client.py +0 -531
- django_cfg/modules/django_rpc_old/config.py +0 -279
- django_cfg/modules/django_rpc_old/exceptions.py +0 -172
- django_cfg/modules/django_unfold/callbacks/revolution.py +0 -81
- django_cfg-1.4.20.dist-info/RECORD +0 -1110
- /django_cfg/{modules/django_ipc_client → apps/ipc}/README.md +0 -0
- /django_cfg/{modules/django_ipc_client → apps/ipc/services/client}/config.py +0 -0
- {django_cfg-1.4.20.dist-info → django_cfg-1.4.23.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.20.dist-info → django_cfg-1.4.23.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.20.dist-info → django_cfg-1.4.23.dist-info}/licenses/LICENSE +0 -0
@@ -6,50 +6,53 @@ Enhanced newsletter management with Material Icons and optimized queries.
|
|
6
6
|
|
7
7
|
from django import forms
|
8
8
|
from django.contrib import admin, messages
|
9
|
-
from django.urls import reverse
|
10
|
-
from django.http import HttpResponseRedirect
|
11
|
-
from django.db import models
|
12
9
|
from django.db.models import Count, Q
|
13
10
|
from unfold.admin import ModelAdmin, TabularInline
|
14
11
|
from unfold.contrib.forms.widgets import WysiwygWidget
|
15
|
-
from django_cfg import ImportExportModelAdmin, ExportMixin, ImportForm, ExportForm
|
16
12
|
|
13
|
+
from django_cfg import ExportForm, ExportMixin, ImportExportModelAdmin, ImportForm
|
17
14
|
from django_cfg.modules.django_admin import (
|
18
|
-
|
19
|
-
DisplayMixin,
|
20
|
-
StatusBadgeConfig,
|
15
|
+
ActionVariant,
|
21
16
|
DateTimeDisplayConfig,
|
17
|
+
DisplayMixin,
|
22
18
|
Icons,
|
23
|
-
|
19
|
+
OptimizedModelAdmin,
|
20
|
+
StatusBadgeConfig,
|
21
|
+
action,
|
24
22
|
display,
|
25
|
-
action
|
26
23
|
)
|
27
24
|
from django_cfg.modules.django_admin.utils.badges import StatusBadge
|
28
25
|
|
29
|
-
from ..models import EmailLog, Newsletter,
|
30
|
-
from .filters import
|
31
|
-
|
26
|
+
from ..models import EmailLog, Newsletter, NewsletterCampaign, NewsletterSubscription
|
27
|
+
from .filters import (
|
28
|
+
EmailClickedFilter,
|
29
|
+
EmailOpenedFilter,
|
30
|
+
HasUserFilter,
|
31
|
+
UserEmailFilter,
|
32
|
+
UserNameFilter,
|
33
|
+
)
|
34
|
+
from .resources import EmailLogResource, NewsletterResource, NewsletterSubscriptionResource
|
32
35
|
|
33
36
|
|
34
37
|
@admin.register(EmailLog)
|
35
38
|
class EmailLogAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ExportMixin):
|
36
39
|
"""Admin interface for EmailLog using Django Admin Utilities."""
|
37
|
-
|
40
|
+
|
38
41
|
# Performance optimization
|
39
42
|
select_related_fields = ['user', 'newsletter']
|
40
|
-
|
43
|
+
|
41
44
|
# Export-only configuration
|
42
45
|
resource_class = EmailLogResource
|
43
46
|
export_form_class = ExportForm
|
44
|
-
|
47
|
+
|
45
48
|
list_display = [
|
46
|
-
'user_display', 'recipient_display', 'subject_display', 'newsletter_display',
|
49
|
+
'user_display', 'recipient_display', 'subject_display', 'newsletter_display',
|
47
50
|
'status_display', 'created_at_display', 'sent_at_display', 'tracking_display'
|
48
51
|
]
|
49
52
|
list_display_links = ['subject_display']
|
50
53
|
ordering = ['-created_at']
|
51
54
|
list_filter = [
|
52
|
-
'status', 'created_at', 'sent_at', 'newsletter',
|
55
|
+
'status', 'created_at', 'sent_at', 'newsletter',
|
53
56
|
EmailOpenedFilter, EmailClickedFilter, HasUserFilter, UserEmailFilter, UserNameFilter
|
54
57
|
]
|
55
58
|
autocomplete_fields = ['user']
|
@@ -64,7 +67,7 @@ class EmailLogAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ExportMixin):
|
|
64
67
|
]
|
65
68
|
readonly_fields = ['created_at', 'sent_at', 'newsletter']
|
66
69
|
raw_id_fields = ['user', 'newsletter']
|
67
|
-
|
70
|
+
|
68
71
|
fieldsets = [
|
69
72
|
('📧 Email Information', {
|
70
73
|
'fields': ['recipient', 'subject', 'body'],
|
@@ -87,14 +90,14 @@ class EmailLogAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ExportMixin):
|
|
87
90
|
'classes': ('tab', 'collapse')
|
88
91
|
})
|
89
92
|
]
|
90
|
-
|
93
|
+
|
91
94
|
@display(description="User")
|
92
95
|
def user_display(self, obj: EmailLog) -> str:
|
93
96
|
"""Display user."""
|
94
97
|
if not obj.user:
|
95
98
|
return "—"
|
96
99
|
return self.display_user_simple(obj.user)
|
97
|
-
|
100
|
+
|
98
101
|
@display(description="Recipient", ordering="recipient")
|
99
102
|
def recipient_display(self, obj: EmailLog) -> str:
|
100
103
|
"""Display recipient email."""
|
@@ -104,37 +107,37 @@ class EmailLogAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ExportMixin):
|
|
104
107
|
variant="info",
|
105
108
|
config=config
|
106
109
|
)
|
107
|
-
|
110
|
+
|
108
111
|
@display(description="Subject", ordering="subject")
|
109
112
|
def subject_display(self, obj: EmailLog) -> str:
|
110
113
|
"""Display email subject."""
|
111
114
|
if not obj.subject:
|
112
115
|
return "—"
|
113
|
-
|
116
|
+
|
114
117
|
subject = obj.subject
|
115
118
|
if len(subject) > 50:
|
116
119
|
subject = subject[:47] + "..."
|
117
|
-
|
120
|
+
|
118
121
|
config = StatusBadgeConfig(show_icons=True, icon=Icons.MAIL)
|
119
122
|
return StatusBadge.create(
|
120
123
|
text=subject,
|
121
124
|
variant="primary",
|
122
125
|
config=config
|
123
126
|
)
|
124
|
-
|
127
|
+
|
125
128
|
@display(description="Newsletter")
|
126
129
|
def newsletter_display(self, obj: EmailLog) -> str:
|
127
130
|
"""Display newsletter link."""
|
128
131
|
if not obj.newsletter:
|
129
132
|
return "—"
|
130
|
-
|
133
|
+
|
131
134
|
config = StatusBadgeConfig(show_icons=True, icon=Icons.CAMPAIGN)
|
132
135
|
return StatusBadge.create(
|
133
136
|
text=obj.newsletter.title,
|
134
137
|
variant="secondary",
|
135
138
|
config=config
|
136
139
|
)
|
137
|
-
|
140
|
+
|
138
141
|
@display(description="Status")
|
139
142
|
def status_display(self, obj: EmailLog) -> str:
|
140
143
|
"""Display email status."""
|
@@ -149,13 +152,13 @@ class EmailLogAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ExportMixin):
|
|
149
152
|
icon=Icons.SCHEDULE if obj.status == 'pending' else Icons.CHECK_CIRCLE if obj.status == 'sent' else Icons.ERROR if obj.status == 'failed' else Icons.BOUNCE_EMAIL
|
150
153
|
)
|
151
154
|
return self.display_status_auto(obj, 'status', status_config)
|
152
|
-
|
155
|
+
|
153
156
|
@display(description="Created")
|
154
157
|
def created_at_display(self, obj: EmailLog) -> str:
|
155
158
|
"""Created time with relative display."""
|
156
159
|
config = DateTimeDisplayConfig(show_relative=True)
|
157
160
|
return self.display_datetime_relative(obj, 'created_at', config)
|
158
|
-
|
161
|
+
|
159
162
|
@display(description="Sent")
|
160
163
|
def sent_at_display(self, obj: EmailLog) -> str:
|
161
164
|
"""Sent time with relative display."""
|
@@ -163,40 +166,40 @@ class EmailLogAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ExportMixin):
|
|
163
166
|
return "Not sent"
|
164
167
|
config = DateTimeDisplayConfig(show_relative=True)
|
165
168
|
return self.display_datetime_relative(obj, 'sent_at', config)
|
166
|
-
|
169
|
+
|
167
170
|
@display(description="Tracking")
|
168
171
|
def tracking_display(self, obj: EmailLog) -> str:
|
169
172
|
"""Display tracking status with badges."""
|
170
173
|
badges = []
|
171
|
-
|
174
|
+
|
172
175
|
if obj.is_opened:
|
173
176
|
config = StatusBadgeConfig(show_icons=True, icon=Icons.VISIBILITY)
|
174
177
|
badges.append(StatusBadge.create(text="Opened", variant="success", config=config))
|
175
178
|
else:
|
176
179
|
config = StatusBadgeConfig(show_icons=True, icon=Icons.VISIBILITY_OFF)
|
177
180
|
badges.append(StatusBadge.create(text="Not Opened", variant="secondary", config=config))
|
178
|
-
|
181
|
+
|
179
182
|
if obj.is_clicked:
|
180
183
|
config = StatusBadgeConfig(show_icons=True, icon=Icons.MOUSE)
|
181
184
|
badges.append(StatusBadge.create(text="Clicked", variant="info", config=config))
|
182
185
|
else:
|
183
186
|
config = StatusBadgeConfig(show_icons=True, icon=Icons.TOUCH_APP)
|
184
187
|
badges.append(StatusBadge.create(text="Not Clicked", variant="secondary", config=config))
|
185
|
-
|
188
|
+
|
186
189
|
return " | ".join(badges)
|
187
190
|
|
188
191
|
|
189
192
|
@admin.register(Newsletter)
|
190
193
|
class NewsletterAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportModelAdmin):
|
191
194
|
"""Admin interface for Newsletter using Django Admin Utilities."""
|
192
|
-
|
195
|
+
|
193
196
|
# Import/Export configuration
|
194
197
|
resource_class = NewsletterResource
|
195
198
|
import_form_class = ImportForm
|
196
199
|
export_form_class = ExportForm
|
197
|
-
|
200
|
+
|
198
201
|
list_display = [
|
199
|
-
'title_display', 'description_display', 'active_display',
|
202
|
+
'title_display', 'description_display', 'active_display',
|
200
203
|
'auto_subscribe_display', 'subscribers_count_display', 'created_at_display'
|
201
204
|
]
|
202
205
|
list_display_links = ['title_display']
|
@@ -204,7 +207,7 @@ class NewsletterAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExpor
|
|
204
207
|
list_filter = ['is_active', 'auto_subscribe', 'created_at']
|
205
208
|
search_fields = ['title', 'description']
|
206
209
|
readonly_fields = ['subscribers_count', 'created_at', 'updated_at']
|
207
|
-
|
210
|
+
|
208
211
|
fieldsets = [
|
209
212
|
('📰 Newsletter Information', {
|
210
213
|
'fields': ['title', 'description'],
|
@@ -223,9 +226,9 @@ class NewsletterAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExpor
|
|
223
226
|
'classes': ('tab', 'collapse')
|
224
227
|
})
|
225
228
|
]
|
226
|
-
|
229
|
+
|
227
230
|
actions = ['activate_newsletters', 'deactivate_newsletters', 'enable_auto_subscribe']
|
228
|
-
|
231
|
+
|
229
232
|
@display(description="Title", ordering="title")
|
230
233
|
def title_display(self, obj: Newsletter) -> str:
|
231
234
|
"""Display newsletter title."""
|
@@ -235,19 +238,19 @@ class NewsletterAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExpor
|
|
235
238
|
variant="primary",
|
236
239
|
config=config
|
237
240
|
)
|
238
|
-
|
241
|
+
|
239
242
|
@display(description="Description")
|
240
243
|
def description_display(self, obj: Newsletter) -> str:
|
241
244
|
"""Display newsletter description."""
|
242
245
|
if not obj.description:
|
243
246
|
return "—"
|
244
|
-
|
247
|
+
|
245
248
|
description = obj.description
|
246
249
|
if len(description) > 100:
|
247
250
|
description = description[:97] + "..."
|
248
|
-
|
251
|
+
|
249
252
|
return description
|
250
|
-
|
253
|
+
|
251
254
|
@display(description="Active")
|
252
255
|
def active_display(self, obj: Newsletter) -> str:
|
253
256
|
"""Display active status."""
|
@@ -257,7 +260,7 @@ class NewsletterAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExpor
|
|
257
260
|
else:
|
258
261
|
config = StatusBadgeConfig(show_icons=True, icon=Icons.CANCEL)
|
259
262
|
return StatusBadge.create(text="Inactive", variant="secondary", config=config)
|
260
|
-
|
263
|
+
|
261
264
|
@display(description="Auto Subscribe")
|
262
265
|
def auto_subscribe_display(self, obj: Newsletter) -> str:
|
263
266
|
"""Display auto subscribe status."""
|
@@ -266,7 +269,7 @@ class NewsletterAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExpor
|
|
266
269
|
return StatusBadge.create(text="Auto", variant="info", config=config)
|
267
270
|
else:
|
268
271
|
return "Manual"
|
269
|
-
|
272
|
+
|
270
273
|
@display(description="Subscribers")
|
271
274
|
def subscribers_count_display(self, obj: Newsletter) -> str:
|
272
275
|
"""Display subscribers count."""
|
@@ -277,25 +280,25 @@ class NewsletterAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExpor
|
|
277
280
|
return "1 subscriber"
|
278
281
|
else:
|
279
282
|
return f"{count} subscribers"
|
280
|
-
|
283
|
+
|
281
284
|
@display(description="Created")
|
282
285
|
def created_at_display(self, obj: Newsletter) -> str:
|
283
286
|
"""Created time with relative display."""
|
284
287
|
config = DateTimeDisplayConfig(show_relative=True)
|
285
288
|
return self.display_datetime_relative(obj, 'created_at', config)
|
286
|
-
|
289
|
+
|
287
290
|
@action(description="Activate newsletters", variant=ActionVariant.SUCCESS)
|
288
291
|
def activate_newsletters(self, request, queryset):
|
289
292
|
"""Activate selected newsletters."""
|
290
293
|
count = queryset.update(is_active=True)
|
291
294
|
messages.success(request, f"Successfully activated {count} newsletters.")
|
292
|
-
|
295
|
+
|
293
296
|
@action(description="Deactivate newsletters", variant=ActionVariant.DANGER)
|
294
297
|
def deactivate_newsletters(self, request, queryset):
|
295
298
|
"""Deactivate selected newsletters."""
|
296
299
|
count = queryset.update(is_active=False)
|
297
300
|
messages.warning(request, f"Successfully deactivated {count} newsletters.")
|
298
|
-
|
301
|
+
|
299
302
|
@action(description="Enable auto subscribe", variant=ActionVariant.INFO)
|
300
303
|
def enable_auto_subscribe(self, request, queryset):
|
301
304
|
"""Enable auto subscribe for selected newsletters."""
|
@@ -305,7 +308,7 @@ class NewsletterAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExpor
|
|
305
308
|
|
306
309
|
class NewsletterSubscriptionInline(TabularInline):
|
307
310
|
"""Inline for newsletter subscriptions."""
|
308
|
-
|
311
|
+
|
309
312
|
model = NewsletterSubscription
|
310
313
|
fields = ['email', 'user', 'is_active', 'subscribed_at']
|
311
314
|
readonly_fields = ['subscribed_at']
|
@@ -315,17 +318,17 @@ class NewsletterSubscriptionInline(TabularInline):
|
|
315
318
|
@admin.register(NewsletterSubscription)
|
316
319
|
class NewsletterSubscriptionAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportModelAdmin):
|
317
320
|
"""Admin interface for NewsletterSubscription using Django Admin Utilities."""
|
318
|
-
|
321
|
+
|
319
322
|
# Performance optimization
|
320
323
|
select_related_fields = ['user', 'newsletter']
|
321
|
-
|
324
|
+
|
322
325
|
# Import/Export configuration
|
323
326
|
resource_class = NewsletterSubscriptionResource
|
324
327
|
import_form_class = ImportForm
|
325
328
|
export_form_class = ExportForm
|
326
|
-
|
329
|
+
|
327
330
|
list_display = [
|
328
|
-
'email_display', 'newsletter_display', 'user_display', 'active_display',
|
331
|
+
'email_display', 'newsletter_display', 'user_display', 'active_display',
|
329
332
|
'subscribed_at_display', 'unsubscribed_at_display'
|
330
333
|
]
|
331
334
|
list_display_links = ['email_display']
|
@@ -334,7 +337,7 @@ class NewsletterSubscriptionAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin,
|
|
334
337
|
search_fields = ['email', 'user__email', 'newsletter__title']
|
335
338
|
readonly_fields = ['subscribed_at', 'unsubscribed_at']
|
336
339
|
autocomplete_fields = ['user', 'newsletter']
|
337
|
-
|
340
|
+
|
338
341
|
fieldsets = [
|
339
342
|
('📧 Subscription Information', {
|
340
343
|
'fields': ['email', 'newsletter', 'user'],
|
@@ -349,9 +352,9 @@ class NewsletterSubscriptionAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin,
|
|
349
352
|
'classes': ('tab',)
|
350
353
|
})
|
351
354
|
]
|
352
|
-
|
355
|
+
|
353
356
|
actions = ['activate_subscriptions', 'deactivate_subscriptions']
|
354
|
-
|
357
|
+
|
355
358
|
@display(description="Email", ordering="email")
|
356
359
|
def email_display(self, obj: NewsletterSubscription) -> str:
|
357
360
|
"""Display subscription email."""
|
@@ -361,27 +364,27 @@ class NewsletterSubscriptionAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin,
|
|
361
364
|
variant="info",
|
362
365
|
config=config
|
363
366
|
)
|
364
|
-
|
367
|
+
|
365
368
|
@display(description="Newsletter")
|
366
369
|
def newsletter_display(self, obj: NewsletterSubscription) -> str:
|
367
370
|
"""Display newsletter."""
|
368
371
|
if not obj.newsletter:
|
369
372
|
return "—"
|
370
|
-
|
373
|
+
|
371
374
|
config = StatusBadgeConfig(show_icons=True, icon=Icons.CAMPAIGN)
|
372
375
|
return StatusBadge.create(
|
373
376
|
text=obj.newsletter.title,
|
374
377
|
variant="primary",
|
375
378
|
config=config
|
376
379
|
)
|
377
|
-
|
380
|
+
|
378
381
|
@display(description="User")
|
379
382
|
def user_display(self, obj: NewsletterSubscription) -> str:
|
380
383
|
"""Display user."""
|
381
384
|
if not obj.user:
|
382
385
|
return "—"
|
383
386
|
return self.display_user_simple(obj.user)
|
384
|
-
|
387
|
+
|
385
388
|
@display(description="Active")
|
386
389
|
def active_display(self, obj: NewsletterSubscription) -> str:
|
387
390
|
"""Display active status."""
|
@@ -391,13 +394,13 @@ class NewsletterSubscriptionAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin,
|
|
391
394
|
else:
|
392
395
|
config = StatusBadgeConfig(show_icons=True, icon=Icons.CANCEL)
|
393
396
|
return StatusBadge.create(text="Inactive", variant="secondary", config=config)
|
394
|
-
|
397
|
+
|
395
398
|
@display(description="Subscribed")
|
396
399
|
def subscribed_at_display(self, obj: NewsletterSubscription) -> str:
|
397
400
|
"""Subscribed time with relative display."""
|
398
401
|
config = DateTimeDisplayConfig(show_relative=True)
|
399
402
|
return self.display_datetime_relative(obj, 'subscribed_at', config)
|
400
|
-
|
403
|
+
|
401
404
|
@display(description="Unsubscribed")
|
402
405
|
def unsubscribed_at_display(self, obj: NewsletterSubscription) -> str:
|
403
406
|
"""Unsubscribed time with relative display."""
|
@@ -405,13 +408,13 @@ class NewsletterSubscriptionAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin,
|
|
405
408
|
return "—"
|
406
409
|
config = DateTimeDisplayConfig(show_relative=True)
|
407
410
|
return self.display_datetime_relative(obj, 'unsubscribed_at', config)
|
408
|
-
|
411
|
+
|
409
412
|
@action(description="Activate subscriptions", variant=ActionVariant.SUCCESS)
|
410
413
|
def activate_subscriptions(self, request, queryset):
|
411
414
|
"""Activate selected subscriptions."""
|
412
415
|
count = queryset.update(is_active=True)
|
413
416
|
messages.success(request, f"Successfully activated {count} subscriptions.")
|
414
|
-
|
417
|
+
|
415
418
|
@action(description="Deactivate subscriptions", variant=ActionVariant.DANGER)
|
416
419
|
def deactivate_subscriptions(self, request, queryset):
|
417
420
|
"""Deactivate selected subscriptions."""
|
@@ -431,14 +434,14 @@ class NewsletterCampaignAdminForm(forms.ModelForm):
|
|
431
434
|
@admin.register(NewsletterCampaign)
|
432
435
|
class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, ImportExportModelAdmin):
|
433
436
|
"""Admin interface for NewsletterCampaign using Django Admin Utilities."""
|
434
|
-
|
437
|
+
|
435
438
|
# Performance optimization
|
436
439
|
select_related_fields = ['newsletter']
|
437
|
-
|
440
|
+
|
438
441
|
form = NewsletterCampaignAdminForm
|
439
|
-
|
442
|
+
|
440
443
|
list_display = [
|
441
|
-
'subject_display', 'newsletter_display', 'status_display',
|
444
|
+
'subject_display', 'newsletter_display', 'status_display',
|
442
445
|
'sent_at_display', 'recipient_count_display'
|
443
446
|
]
|
444
447
|
list_display_links = ['subject_display']
|
@@ -447,7 +450,7 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
447
450
|
search_fields = ['subject', 'newsletter__title', 'main_html_content']
|
448
451
|
readonly_fields = ['sent_at', 'recipient_count', 'created_at']
|
449
452
|
autocomplete_fields = ['newsletter']
|
450
|
-
|
453
|
+
|
451
454
|
fieldsets = [
|
452
455
|
('📧 Campaign Information', {
|
453
456
|
'fields': ['subject', 'newsletter'],
|
@@ -466,9 +469,9 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
466
469
|
'classes': ('tab', 'collapse')
|
467
470
|
})
|
468
471
|
]
|
469
|
-
|
472
|
+
|
470
473
|
actions = ['send_campaigns', 'schedule_campaigns', 'cancel_campaigns']
|
471
|
-
|
474
|
+
|
472
475
|
@display(description="Subject", ordering="subject")
|
473
476
|
def subject_display(self, obj: NewsletterCampaign) -> str:
|
474
477
|
"""Display campaign subject."""
|
@@ -478,20 +481,20 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
478
481
|
variant="primary",
|
479
482
|
config=config
|
480
483
|
)
|
481
|
-
|
484
|
+
|
482
485
|
@display(description="Newsletter")
|
483
486
|
def newsletter_display(self, obj: NewsletterCampaign) -> str:
|
484
487
|
"""Display newsletter."""
|
485
488
|
if not obj.newsletter:
|
486
489
|
return "—"
|
487
|
-
|
490
|
+
|
488
491
|
config = StatusBadgeConfig(show_icons=True, icon=Icons.CAMPAIGN)
|
489
492
|
return StatusBadge.create(
|
490
493
|
text=obj.newsletter.title,
|
491
494
|
variant="secondary",
|
492
495
|
config=config
|
493
496
|
)
|
494
|
-
|
497
|
+
|
495
498
|
@display(description="Status")
|
496
499
|
def status_display(self, obj: NewsletterCampaign) -> str:
|
497
500
|
"""Display campaign status."""
|
@@ -508,8 +511,8 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
508
511
|
icon=Icons.EDIT if obj.status == 'draft' else Icons.SCHEDULE if obj.status == 'scheduled' else Icons.SEND if obj.status == 'sending' else Icons.CHECK_CIRCLE if obj.status == 'sent' else Icons.ERROR if obj.status == 'failed' else Icons.CANCEL
|
509
512
|
)
|
510
513
|
return self.display_status_auto(obj, 'status', status_config)
|
511
|
-
|
512
|
-
|
514
|
+
|
515
|
+
|
513
516
|
@display(description="Sent")
|
514
517
|
def sent_at_display(self, obj: NewsletterCampaign) -> str:
|
515
518
|
"""Sent time with relative display."""
|
@@ -517,7 +520,7 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
517
520
|
return "Not sent"
|
518
521
|
config = DateTimeDisplayConfig(show_relative=True)
|
519
522
|
return self.display_datetime_relative(obj, 'sent_at', config)
|
520
|
-
|
523
|
+
|
521
524
|
@display(description="Recipients")
|
522
525
|
def recipient_count_display(self, obj: NewsletterCampaign) -> str:
|
523
526
|
"""Display recipients count."""
|
@@ -528,7 +531,7 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
528
531
|
return "1 recipient"
|
529
532
|
else:
|
530
533
|
return f"{count} recipients"
|
531
|
-
|
534
|
+
|
532
535
|
@action(description="Send campaigns", variant=ActionVariant.SUCCESS)
|
533
536
|
def send_campaigns(self, request, queryset):
|
534
537
|
"""Send selected campaigns."""
|
@@ -536,10 +539,10 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
536
539
|
if sendable_count == 0:
|
537
540
|
messages.error(request, "No sendable campaigns selected.")
|
538
541
|
return
|
539
|
-
|
542
|
+
|
540
543
|
queryset.filter(status__in=['draft', 'scheduled']).update(status='sending')
|
541
544
|
messages.success(request, f"Started sending {sendable_count} campaigns.")
|
542
|
-
|
545
|
+
|
543
546
|
@action(description="Schedule campaigns", variant=ActionVariant.WARNING)
|
544
547
|
def schedule_campaigns(self, request, queryset):
|
545
548
|
"""Schedule selected campaigns."""
|
@@ -547,10 +550,10 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
547
550
|
if schedulable_count == 0:
|
548
551
|
messages.error(request, "No draft campaigns selected.")
|
549
552
|
return
|
550
|
-
|
553
|
+
|
551
554
|
queryset.filter(status='draft').update(status='scheduled')
|
552
555
|
messages.warning(request, f"Scheduled {schedulable_count} campaigns.")
|
553
|
-
|
556
|
+
|
554
557
|
@action(description="Cancel campaigns", variant=ActionVariant.DANGER)
|
555
558
|
def cancel_campaigns(self, request, queryset):
|
556
559
|
"""Cancel selected campaigns."""
|
@@ -558,14 +561,14 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
558
561
|
if cancelable_count == 0:
|
559
562
|
messages.error(request, "No cancelable campaigns selected.")
|
560
563
|
return
|
561
|
-
|
564
|
+
|
562
565
|
queryset.filter(status__in=['draft', 'scheduled']).update(status='cancelled')
|
563
566
|
messages.error(request, f"Cancelled {cancelable_count} campaigns.")
|
564
|
-
|
567
|
+
|
565
568
|
def changelist_view(self, request, extra_context=None):
|
566
569
|
"""Add campaign statistics to changelist."""
|
567
570
|
extra_context = extra_context or {}
|
568
|
-
|
571
|
+
|
569
572
|
queryset = self.get_queryset(request)
|
570
573
|
stats = queryset.aggregate(
|
571
574
|
total_campaigns=Count('id'),
|
@@ -574,7 +577,7 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
574
577
|
sent_campaigns=Count('id', filter=Q(status='sent')),
|
575
578
|
failed_campaigns=Count('id', filter=Q(status='failed'))
|
576
579
|
)
|
577
|
-
|
580
|
+
|
578
581
|
extra_context['campaign_stats'] = {
|
579
582
|
'total_campaigns': stats['total_campaigns'] or 0,
|
580
583
|
'draft_campaigns': stats['draft_campaigns'] or 0,
|
@@ -582,5 +585,5 @@ class NewsletterCampaignAdmin(OptimizedModelAdmin, DisplayMixin, ModelAdmin, Imp
|
|
582
585
|
'sent_campaigns': stats['sent_campaigns'] or 0,
|
583
586
|
'failed_campaigns': stats['failed_campaigns'] or 0
|
584
587
|
}
|
585
|
-
|
588
|
+
|
586
589
|
return super().changelist_view(request, extra_context)
|