django-cfg 1.3.11__py3-none-any.whl → 1.4.0__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/inlines.py +11 -5
- django_cfg/apps/accounts/admin/user_admin.py +39 -16
- django_cfg/apps/accounts/serializers/profile.py +1 -1
- django_cfg/apps/accounts/services/otp_service.py +18 -11
- django_cfg/apps/accounts/signals.py +15 -24
- django_cfg/apps/accounts/utils/notifications.py +217 -358
- django_cfg/apps/accounts/views/otp.py +2 -2
- django_cfg/apps/accounts/views/webhook.py +1 -1
- django_cfg/apps/agents/core/django_agent.py +1 -1
- django_cfg/apps/api/commands/views.py +66 -83
- django_cfg/apps/api/health/drf_views.py +269 -0
- django_cfg/apps/api/health/serializers.py +45 -0
- django_cfg/apps/api/health/urls.py +6 -1
- django_cfg/apps/knowbase/admin/actions/__init__.py +13 -0
- django_cfg/apps/knowbase/admin/actions/visibility_actions.py +56 -0
- django_cfg/apps/knowbase/admin/document_admin.py +136 -270
- django_cfg/apps/knowbase/admin/helpers/__init__.py +17 -0
- django_cfg/apps/knowbase/admin/helpers/configs.py +72 -0
- django_cfg/apps/knowbase/admin/helpers/display_helpers.py +156 -0
- django_cfg/apps/knowbase/admin/helpers/statistics.py +108 -0
- django_cfg/apps/knowbase/config/constance_fields.py +1 -1
- django_cfg/apps/knowbase/config/settings.py +2 -2
- django_cfg/apps/knowbase/mixins/__init__.py +19 -2
- django_cfg/apps/knowbase/mixins/config/__init__.py +14 -0
- django_cfg/apps/knowbase/mixins/config/defaults.py +75 -0
- django_cfg/apps/knowbase/mixins/config/meta_config.py +120 -0
- django_cfg/apps/knowbase/mixins/creator.py +10 -10
- django_cfg/apps/knowbase/mixins/external_data_mixin.py +105 -403
- django_cfg/apps/knowbase/mixins/generators/__init__.py +16 -0
- django_cfg/apps/knowbase/mixins/generators/content_generator.py +218 -0
- django_cfg/apps/knowbase/mixins/generators/field_analyzer.py +76 -0
- django_cfg/apps/knowbase/mixins/generators/metadata_generator.py +124 -0
- django_cfg/apps/knowbase/mixins/service.py +2 -2
- django_cfg/apps/knowbase/services/archive/__init__.py +1 -0
- django_cfg/apps/knowbase/services/archive/analyzers/__init__.py +17 -0
- django_cfg/apps/knowbase/services/archive/analyzers/complexity_analyzer.py +33 -0
- django_cfg/apps/knowbase/services/archive/analyzers/purpose_detector.py +36 -0
- django_cfg/apps/knowbase/services/archive/analyzers/quality_analyzer.py +39 -0
- django_cfg/apps/knowbase/services/archive/analyzers/tag_generator.py +103 -0
- django_cfg/apps/knowbase/services/archive/chunking/__init__.py +19 -0
- django_cfg/apps/knowbase/services/archive/chunking/base.py +81 -0
- django_cfg/apps/knowbase/services/archive/chunking/json_chunker.py +62 -0
- django_cfg/apps/knowbase/services/archive/chunking/markdown_chunker.py +107 -0
- django_cfg/apps/knowbase/services/archive/chunking/python_chunker.py +248 -0
- django_cfg/apps/knowbase/services/archive/chunking/text_chunker.py +70 -0
- django_cfg/apps/knowbase/services/archive/chunking_service.py +110 -729
- django_cfg/apps/knowbase/services/archive/context/__init__.py +14 -0
- django_cfg/apps/knowbase/services/archive/context/builders.py +220 -0
- django_cfg/apps/knowbase/services/archive/context/models.py +38 -0
- django_cfg/apps/knowbase/services/embedding/models.py +18 -14
- django_cfg/apps/knowbase/services/embedding/processors.py +6 -3
- django_cfg/apps/knowbase/tasks/document_processing.py +11 -3
- django_cfg/apps/leads/tests.py +1 -1
- django_cfg/apps/payments/admin/api_keys_admin.py +1 -1
- django_cfg/apps/payments/admin/balance_admin.py +1 -1
- django_cfg/apps/payments/admin/currencies_admin.py +1 -1
- django_cfg/apps/payments/admin/payments_admin.py +1 -1
- django_cfg/apps/payments/admin/subscriptions_admin.py +1 -1
- django_cfg/apps/payments/admin_interface/templates/payments/base.html +59 -126
- django_cfg/apps/payments/admin_interface/views/api/payments.py +1 -1
- django_cfg/apps/payments/admin_interface/views/api/stats.py +1 -1
- django_cfg/apps/payments/admin_interface/views/api/users.py +1 -1
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +1 -1
- django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +1 -1
- django_cfg/apps/payments/admin_interface/views/base.py +29 -2
- django_cfg/apps/payments/apps.py +1 -1
- django_cfg/apps/payments/config/django_cfg_integration.py +2 -2
- django_cfg/apps/payments/config/helpers.py +3 -2
- django_cfg/apps/payments/management/commands/cleanup_expired_data.py +1 -1
- django_cfg/apps/payments/management/commands/currency_stats.py +1 -1
- django_cfg/apps/payments/management/commands/manage_currencies.py +1 -1
- django_cfg/apps/payments/management/commands/manage_providers.py +1 -1
- django_cfg/apps/payments/management/commands/process_pending_payments.py +1 -1
- django_cfg/apps/payments/management/commands/test_providers.py +1 -1
- django_cfg/apps/payments/middleware/api_access.py +1 -1
- django_cfg/apps/payments/middleware/rate_limiting.py +1 -1
- django_cfg/apps/payments/middleware/usage_tracking.py +1 -1
- django_cfg/apps/payments/models/balance.py +2 -2
- django_cfg/apps/payments/models/managers/api_key_managers.py +1 -1
- django_cfg/apps/payments/models/managers/balance_managers.py +1 -1
- django_cfg/apps/payments/models/managers/currency_managers.py +1 -1
- django_cfg/apps/payments/models/managers/payment_managers.py +1 -1
- django_cfg/apps/payments/models/managers/subscription_managers.py +1 -1
- django_cfg/apps/payments/models/payments.py +2 -2
- django_cfg/apps/payments/services/cache_service/__init__.py +1 -1
- django_cfg/apps/payments/services/cache_service/simple_cache.py +10 -5
- django_cfg/apps/payments/services/core/base.py +1 -1
- django_cfg/apps/payments/services/core/currency/__init__.py +13 -0
- django_cfg/apps/payments/services/core/currency/currency_converter.py +57 -0
- django_cfg/apps/payments/services/core/currency/currency_validator.py +61 -0
- django_cfg/apps/payments/services/core/operations/__init__.py +15 -0
- django_cfg/apps/payments/services/core/operations/payment_canceller.py +100 -0
- django_cfg/apps/payments/services/core/operations/payment_creator.py +196 -0
- django_cfg/apps/payments/services/core/operations/status_checker.py +100 -0
- django_cfg/apps/payments/services/core/payment_service.py +124 -612
- django_cfg/apps/payments/services/core/providers/__init__.py +13 -0
- django_cfg/apps/payments/services/core/providers/provider_client.py +132 -0
- django_cfg/apps/payments/services/core/providers/status_mapper.py +89 -0
- django_cfg/apps/payments/services/core/utils/__init__.py +13 -0
- django_cfg/apps/payments/services/core/utils/data_converter.py +48 -0
- django_cfg/apps/payments/services/core/utils/statistics_calculator.py +69 -0
- django_cfg/apps/payments/services/providers/base.py +1 -1
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +3 -3
- django_cfg/apps/payments/services/providers/nowpayments/parsers/__init__.py +9 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers/data/__init__.py +23 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers/data/constants.py +23 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers/data/currency_names.py +244 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers/data/patterns.py +511 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers/parser.py +168 -0
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +1 -1
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +1 -1
- django_cfg/apps/payments/services/providers/registry.py +1 -1
- django_cfg/apps/payments/services/providers/sync_service.py +1 -1
- django_cfg/apps/payments/signals/__init__.py +1 -1
- django_cfg/apps/payments/signals/api_key_signals.py +1 -1
- django_cfg/apps/payments/signals/balance_signals.py +1 -1
- django_cfg/apps/payments/signals/payment_signals.py +1 -1
- django_cfg/apps/payments/signals/subscription_signals.py +1 -1
- django_cfg/apps/payments/views/api/api_keys.py +1 -1
- django_cfg/apps/payments/views/api/balances.py +1 -1
- django_cfg/apps/payments/views/api/base.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +1 -1
- django_cfg/apps/payments/views/api/payments.py +1 -1
- django_cfg/apps/payments/views/api/subscriptions.py +1 -1
- django_cfg/apps/payments/views/api/webhooks.py +1 -1
- django_cfg/apps/payments/views/serializers/api_keys.py +1 -1
- django_cfg/apps/payments/views/serializers/balances.py +1 -1
- django_cfg/apps/payments/views/serializers/currencies.py +1 -1
- django_cfg/apps/payments/views/serializers/payments.py +1 -1
- django_cfg/apps/payments/views/serializers/subscriptions.py +1 -1
- django_cfg/apps/payments/views/serializers/webhooks.py +1 -1
- django_cfg/apps/support/admin/support_admin.py +21 -13
- django_cfg/apps/support/templates/support/chat/access_denied.html +21 -27
- django_cfg/apps/support/templates/support/chat/ticket_chat.html +183 -254
- django_cfg/apps/support/utils/support_email_service.py +1 -1
- django_cfg/apps/tasks/templates/tasks/layout/base.html +20 -115
- django_cfg/apps/tasks/utils/simulator.py +1 -1
- django_cfg/apps/tasks/views/dashboard.py +33 -3
- django_cfg/apps/urls.py +5 -1
- django_cfg/cli/README.md +57 -471
- django_cfg/cli/commands/create_project.py +140 -529
- django_cfg/cli/main.py +13 -10
- django_cfg/core/__init__.py +63 -6
- django_cfg/core/base/__init__.py +5 -0
- django_cfg/core/base/config_model.py +652 -0
- django_cfg/core/builders/__init__.py +11 -0
- django_cfg/core/builders/apps_builder.py +258 -0
- django_cfg/core/builders/middleware_builder.py +115 -0
- django_cfg/core/builders/security_builder.py +96 -0
- django_cfg/core/config.py +20 -892
- django_cfg/core/constants.py +69 -0
- django_cfg/core/environment/__init__.py +9 -0
- django_cfg/core/exceptions.py +45 -298
- django_cfg/core/generation/__init__.py +51 -0
- django_cfg/core/generation/core_generators/__init__.py +0 -0
- django_cfg/core/generation/core_generators/settings.py +90 -0
- django_cfg/core/generation/core_generators/static.py +82 -0
- django_cfg/core/generation/core_generators/templates.py +141 -0
- django_cfg/core/generation/data_generators/__init__.py +15 -0
- django_cfg/core/generation/data_generators/cache.py +132 -0
- django_cfg/core/generation/data_generators/database.py +117 -0
- django_cfg/core/generation/generation.py +92 -0
- django_cfg/core/generation/integration_generators/__init__.py +21 -0
- django_cfg/core/generation/integration_generators/api.py +237 -0
- django_cfg/core/generation/integration_generators/sessions.py +65 -0
- django_cfg/core/generation/integration_generators/tailwind.py +54 -0
- django_cfg/core/generation/integration_generators/tasks.py +92 -0
- django_cfg/core/generation/integration_generators/third_party.py +144 -0
- django_cfg/core/generation/orchestrator.py +285 -0
- django_cfg/core/generation/protocols.py +30 -0
- django_cfg/core/generation/security_generators/__init__.py +0 -0
- django_cfg/core/generation/utility_generators/__init__.py +24 -0
- django_cfg/core/generation/utility_generators/email.py +58 -0
- django_cfg/core/generation/utility_generators/i18n.py +66 -0
- django_cfg/core/generation/utility_generators/limits.py +58 -0
- django_cfg/core/generation/utility_generators/logging.py +66 -0
- django_cfg/core/generation/utility_generators/security.py +101 -0
- django_cfg/core/generation/utils/__init__.py +0 -0
- django_cfg/core/generation/utils/helpers.py +32 -0
- django_cfg/core/integration/__init__.py +18 -25
- django_cfg/core/integration/display/startup.py +146 -133
- django_cfg/core/integration/url_integration.py +13 -2
- django_cfg/core/services/__init__.py +5 -0
- django_cfg/core/services/config_service.py +121 -0
- django_cfg/core/state/__init__.py +9 -0
- django_cfg/core/state/registry.py +84 -0
- django_cfg/core/types/__init__.py +15 -0
- django_cfg/core/types/aliases.py +15 -0
- django_cfg/core/types/enums.py +49 -0
- django_cfg/dashboard/DEBUG_README.md +105 -0
- django_cfg/dashboard/REFACTORING_SUMMARY.md +237 -0
- django_cfg/dashboard/__init__.py +24 -0
- django_cfg/dashboard/components.py +308 -0
- django_cfg/dashboard/debug.py +176 -0
- django_cfg/dashboard/management/__init__.py +0 -0
- django_cfg/dashboard/management/commands/__init__.py +0 -0
- django_cfg/dashboard/management/commands/debug_dashboard.py +109 -0
- django_cfg/dashboard/sections/__init__.py +1 -0
- django_cfg/dashboard/sections/base.py +128 -0
- django_cfg/dashboard/sections/commands.py +32 -0
- django_cfg/dashboard/sections/overview.py +394 -0
- django_cfg/dashboard/sections/stats.py +48 -0
- django_cfg/dashboard/sections/system.py +73 -0
- django_cfg/management/commands/check_settings.py +6 -2
- django_cfg/management/commands/clear_constance.py +6 -1
- django_cfg/management/commands/create_token.py +5 -4
- django_cfg/management/commands/generate.py +5 -0
- django_cfg/management/commands/list_urls.py +7 -2
- django_cfg/management/commands/migrate_all.py +6 -2
- django_cfg/management/commands/migrator.py +6 -1
- django_cfg/management/commands/rundramatiq.py +6 -1
- django_cfg/management/commands/rundramatiq_simulator.py +11 -4
- django_cfg/management/commands/runserver_ngrok.py +9 -7
- django_cfg/management/commands/script.py +25 -21
- django_cfg/management/commands/show_config.py +6 -1
- django_cfg/management/commands/show_urls.py +8 -3
- django_cfg/management/commands/superuser.py +5 -4
- django_cfg/management/commands/task_clear.py +8 -3
- django_cfg/management/commands/task_status.py +8 -3
- django_cfg/management/commands/test_email.py +6 -1
- django_cfg/management/commands/test_telegram.py +6 -1
- django_cfg/management/commands/test_twilio.py +6 -1
- django_cfg/management/commands/tree.py +7 -4
- django_cfg/models/__init__.py +88 -3
- django_cfg/models/api/__init__.py +27 -0
- django_cfg/models/{api.py → api/config.py} +1 -1
- django_cfg/models/api/drf/__init__.py +21 -0
- django_cfg/models/api/drf/config.py +101 -0
- django_cfg/models/api/drf/redoc.py +31 -0
- django_cfg/models/api/drf/spectacular.py +129 -0
- django_cfg/models/api/drf/swagger.py +59 -0
- django_cfg/models/{api_keys.py → api/keys.py} +16 -6
- django_cfg/models/{limits.py → api/limits.py} +0 -1
- django_cfg/models/base/__init__.py +14 -0
- django_cfg/models/django/__init__.py +16 -0
- django_cfg/models/{constance.py → django/constance.py} +1 -1
- django_cfg/models/{environment.py → django/environment.py} +1 -1
- django_cfg/models/infrastructure/__init__.py +17 -0
- django_cfg/models/{cache.py → infrastructure/cache.py} +3 -2
- django_cfg/models/infrastructure/database/__init__.py +22 -0
- django_cfg/models/infrastructure/database/config.py +265 -0
- django_cfg/models/infrastructure/database/converters.py +91 -0
- django_cfg/models/infrastructure/database/parsers.py +96 -0
- django_cfg/models/infrastructure/database/routing.py +85 -0
- django_cfg/models/infrastructure/database/validators.py +170 -0
- django_cfg/models/{logging.py → infrastructure/logging.py} +1 -1
- django_cfg/models/{security.py → infrastructure/security.py} +2 -2
- django_cfg/models/ngrok/__init__.py +11 -0
- django_cfg/models/ngrok/auth.py +37 -0
- django_cfg/models/ngrok/config.py +77 -0
- django_cfg/models/ngrok/tunnel.py +35 -0
- django_cfg/models/payments/__init__.py +20 -0
- django_cfg/models/payments/api_keys.py +57 -0
- django_cfg/models/{payments.py → payments/config.py} +56 -154
- django_cfg/models/payments/providers/__init__.py +15 -0
- django_cfg/models/payments/providers/base.py +25 -0
- django_cfg/models/payments/providers/nowpayments.py +48 -0
- django_cfg/models/services/__init__.py +18 -0
- django_cfg/models/services/base.py +65 -0
- django_cfg/models/{email.py → services/email.py} +1 -1
- django_cfg/models/services/telegram.py +172 -0
- django_cfg/models/tasks/__init__.py +51 -0
- django_cfg/models/tasks/backends.py +250 -0
- django_cfg/models/tasks/config.py +314 -0
- django_cfg/models/tasks/utils.py +174 -0
- django_cfg/modules/base.py +18 -3
- django_cfg/modules/django_admin/decorators/actions.py +1 -1
- django_cfg/modules/django_admin/decorators/display.py +1 -1
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +1 -1
- django_cfg/modules/django_cfg_rpc_client/README.md +346 -0
- django_cfg/modules/django_cfg_rpc_client/__init__.py +51 -0
- django_cfg/modules/django_cfg_rpc_client/client.py +540 -0
- django_cfg/modules/django_cfg_rpc_client/config.py +207 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/README.md +517 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/UNFOLD_INTEGRATION.md +439 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/__init__.py +11 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/apps.py +22 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/monitor.py +435 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/static/django_cfg_rpc_dashboard/js/dashboard.js +373 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/templates/django_cfg_rpc_dashboard/base.html +76 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/templates/django_cfg_rpc_dashboard/dashboard.html +200 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/urls.py +22 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/urls_admin.py +9 -0
- django_cfg/modules/django_cfg_rpc_client/dashboard/views.py +251 -0
- django_cfg/modules/django_cfg_rpc_client/exceptions.py +201 -0
- django_cfg/modules/django_drf_theme/CHANGELOG.md +210 -0
- django_cfg/modules/django_drf_theme/EXAMPLE.md +465 -0
- django_cfg/modules/django_drf_theme/IMPLEMENTATION.md +232 -0
- django_cfg/modules/django_drf_theme/README.md +207 -0
- django_cfg/modules/django_drf_theme/TAILWIND_CDN_GUIDE.md +274 -0
- django_cfg/modules/django_drf_theme/__init__.py +23 -0
- django_cfg/modules/django_drf_theme/apps.py +15 -0
- django_cfg/modules/django_drf_theme/renderers.py +58 -0
- django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/api.html +375 -0
- django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/base.html +938 -0
- django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/filter_form.html +132 -0
- django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/raw_data_form.html +123 -0
- django_cfg/modules/django_drf_theme/templatetags/__init__.py +1 -0
- django_cfg/modules/django_drf_theme/templatetags/tailwind_tags.py +57 -0
- django_cfg/modules/django_email/__init__.py +14 -0
- django_cfg/modules/{django_email.py → django_email/service.py} +78 -113
- django_cfg/modules/django_email/utils.py +40 -0
- django_cfg/modules/django_health/__init__.py +9 -0
- django_cfg/modules/{django_health.py → django_health/service.py} +23 -21
- django_cfg/modules/django_llm/llm/client.py +155 -550
- django_cfg/modules/django_llm/llm/embeddings/__init__.py +13 -0
- django_cfg/modules/django_llm/llm/embeddings/mock_embedder.py +106 -0
- django_cfg/modules/django_llm/llm/embeddings/openai_embedder.py +79 -0
- django_cfg/modules/django_llm/llm/models_api/__init__.py +9 -0
- django_cfg/modules/django_llm/llm/models_api/models_query.py +163 -0
- django_cfg/modules/django_llm/llm/providers/__init__.py +15 -0
- django_cfg/modules/django_llm/llm/providers/config_builder.py +103 -0
- django_cfg/modules/django_llm/llm/providers/provider_manager.py +148 -0
- django_cfg/modules/django_llm/llm/providers/provider_selector.py +60 -0
- django_cfg/modules/django_llm/llm/requests/__init__.py +15 -0
- django_cfg/modules/django_llm/llm/requests/cache_manager.py +170 -0
- django_cfg/modules/django_llm/llm/requests/chat_handler.py +199 -0
- django_cfg/modules/django_llm/llm/requests/embedding_handler.py +113 -0
- django_cfg/modules/django_llm/llm/responses/__init__.py +9 -0
- django_cfg/modules/django_llm/llm/responses/response_builder.py +131 -0
- django_cfg/modules/django_llm/llm/stats/__init__.py +9 -0
- django_cfg/modules/django_llm/llm/stats/stats_manager.py +107 -0
- django_cfg/modules/django_llm/translator/detectors/__init__.py +13 -0
- django_cfg/modules/django_llm/translator/detectors/language_detector.py +90 -0
- django_cfg/modules/django_llm/translator/detectors/script_detector.py +153 -0
- django_cfg/modules/django_llm/translator/stats/__init__.py +11 -0
- django_cfg/modules/django_llm/translator/stats/stats_tracker.py +85 -0
- django_cfg/modules/django_llm/translator/translator.py +150 -603
- django_cfg/modules/django_llm/translator/translators/__init__.py +15 -0
- django_cfg/modules/django_llm/translator/translators/json_translator.py +316 -0
- django_cfg/modules/django_llm/translator/translators/text_translator.py +139 -0
- django_cfg/modules/django_llm/translator/utils/__init__.py +13 -0
- django_cfg/modules/django_llm/translator/utils/prompt_builder.py +110 -0
- django_cfg/modules/django_llm/translator/utils/text_utils.py +114 -0
- django_cfg/modules/django_logging/FIXES_SUMMARY.md +276 -0
- django_cfg/modules/django_logging/LOGGING_GUIDE.md +504 -0
- django_cfg/modules/django_logging/__init__.py +14 -0
- django_cfg/modules/{django_logger.py → django_logging/django_logger.py} +13 -13
- django_cfg/modules/{logger.py → django_logging/logger.py} +14 -4
- django_cfg/modules/django_ngrok/__init__.py +39 -0
- django_cfg/modules/{django_ngrok.py → django_ngrok/service.py} +14 -42
- django_cfg/modules/django_rpc_old/POETRY.md +344 -0
- django_cfg/modules/django_rpc_old/README.md +397 -0
- django_cfg/modules/django_rpc_old/TESTING.md +358 -0
- django_cfg/modules/django_rpc_old/__init__.py +39 -0
- django_cfg/modules/django_rpc_old/client.py +531 -0
- django_cfg/modules/django_rpc_old/config.py +279 -0
- django_cfg/modules/django_rpc_old/exceptions.py +172 -0
- django_cfg/modules/django_tailwind/README.md +478 -0
- django_cfg/modules/django_tailwind/__init__.py +7 -0
- django_cfg/modules/django_tailwind/apps.py +10 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/app.html +5 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +117 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/components/navbar.html +124 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/components/theme_toggle.html +54 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/components/user_menu.html +116 -0
- django_cfg/modules/django_tailwind/templates/django_tailwind/simple.html +46 -0
- django_cfg/modules/django_tailwind/templatetags/__init__.py +1 -0
- django_cfg/modules/django_tailwind/templatetags/tailwind_info.py +185 -0
- django_cfg/modules/django_tasks/__init__.py +29 -0
- django_cfg/modules/django_tasks/factory.py +127 -0
- django_cfg/modules/{django_tasks.py → django_tasks/service.py} +45 -274
- django_cfg/modules/django_tasks/settings.py +107 -0
- django_cfg/modules/django_telegram/__init__.py +29 -0
- django_cfg/modules/{django_telegram.py → django_telegram/service.py} +45 -113
- django_cfg/modules/django_telegram/utils.py +62 -0
- django_cfg/modules/django_twilio/__init__.py +54 -107
- django_cfg/modules/django_twilio/_imports.py +30 -0
- django_cfg/modules/django_twilio/base.py +192 -0
- django_cfg/modules/django_twilio/email_otp.py +227 -0
- django_cfg/modules/django_twilio/sendgrid_service.py +1 -1
- django_cfg/modules/django_twilio/simple_service.py +1 -2
- django_cfg/modules/django_twilio/sms.py +94 -0
- django_cfg/modules/django_twilio/twilio_service.py +2 -3
- django_cfg/modules/django_twilio/unified.py +310 -0
- django_cfg/modules/django_twilio/utils.py +190 -0
- django_cfg/modules/django_twilio/whatsapp.py +137 -0
- django_cfg/modules/django_unfold/callbacks/base.py +198 -7
- django_cfg/modules/django_unfold/callbacks/main.py +102 -10
- django_cfg/modules/django_unfold/dashboard.py +65 -43
- django_cfg/modules/django_unfold/models/config.py +13 -12
- django_cfg/modules/django_unfold/models/navigation.py +8 -3
- django_cfg/modules/django_unfold/models/tabs.py +2 -2
- django_cfg/modules/django_unfold/templates/unfold/helpers/app_list.html +102 -0
- django_cfg/registry/core.py +24 -26
- django_cfg/registry/modules.py +5 -2
- django_cfg/registry/services.py +20 -3
- django_cfg/registry/third_party.py +8 -8
- django_cfg/static/admin/css/dashboard.css +260 -0
- django_cfg/static/admin/js/commands.js +171 -0
- django_cfg/static/admin/js/dashboard.js +126 -0
- django_cfg/templates/admin/components/management_commands.js +375 -0
- django_cfg/templates/admin/components/progress_bar.html +18 -23
- django_cfg/templates/admin/index.html +48 -20
- django_cfg/templates/admin/index_new.html +106 -0
- django_cfg/templates/admin/layouts/base_dashboard.html +60 -0
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +1 -20
- django_cfg/templates/admin/sections/commands_section.html +626 -0
- django_cfg/templates/admin/sections/overview_section.html +112 -0
- django_cfg/templates/admin/sections/stats_section.html +35 -0
- django_cfg/templates/admin/sections/system_section.html +99 -0
- django_cfg/templates/admin/snippets/components/CHARTS_GUIDE.md +322 -0
- django_cfg/templates/admin/snippets/components/activity_tracker.html +85 -47
- django_cfg/templates/admin/snippets/components/charts_section.html +154 -64
- django_cfg/templates/admin/snippets/components/django_commands.html +3 -3
- django_cfg/templates/admin/snippets/components/recent_activity_improved.html +25 -0
- django_cfg/templates/admin/snippets/components/recent_users_table.html +1 -1
- django_cfg/templates/admin/snippets/components/system_metrics.html +179 -93
- django_cfg/templates/admin/snippets/zones/zones_table.html +2 -2
- django_cfg/templatetags/django_cfg.py +7 -1
- django_cfg/utils/smart_defaults.py +4 -4
- django_cfg-1.4.0.dist-info/METADATA +920 -0
- {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/RECORD +425 -196
- django_cfg/apps/accounts/utils/auth_email_service.py +0 -84
- django_cfg/apps/payments/services/providers/nowpayments/parsers.py +0 -879
- django_cfg/core/generation.py +0 -621
- django_cfg/management/commands/validate_config.py +0 -189
- django_cfg/models/database.py +0 -480
- django_cfg/models/drf.py +0 -272
- django_cfg/models/ngrok.py +0 -122
- django_cfg/models/services.py +0 -440
- django_cfg/models/tasks.py +0 -550
- django_cfg/modules/django_twilio/service.py +0 -942
- django_cfg/template_archive/django_sample.zip +0 -0
- django_cfg/templates/rest_framework/api.html +0 -12
- django_cfg/utils/toolkit.py +0 -703
- django_cfg-1.3.11.dist-info/METADATA +0 -1029
- /django_cfg/apps/accounts/management/commands/{test_otp.py → otp_test.py} +0 -0
- /django_cfg/core/{environment.py → environment/detector.py} +0 -0
- /django_cfg/models/{cors.py → api/cors.py} +0 -0
- /django_cfg/models/{jwt.py → api/jwt.py} +0 -0
- /django_cfg/models/{base.py → base/config.py} +0 -0
- /django_cfg/models/{cfg.py → base/module.py} +0 -0
- /django_cfg/models/{revolution.py → django/revolution.py} +0 -0
- /django_cfg/modules/{dramatiq_setup.py → django_tasks/dramatiq_setup.py} +0 -0
- {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.11.dist-info → django_cfg-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -3,27 +3,217 @@ Base utilities and helper functions for callbacks.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import logging
|
6
|
-
|
6
|
+
import inspect
|
7
|
+
from typing import Dict, Any, List, Set, Optional
|
7
8
|
from django.contrib.auth import get_user_model
|
8
9
|
from django.core.management import get_commands
|
10
|
+
from django.core.management.base import BaseCommand
|
9
11
|
import importlib
|
10
12
|
|
11
13
|
logger = logging.getLogger(__name__)
|
12
14
|
|
13
15
|
|
16
|
+
# Keywords in docstring/code that indicate command should not be in web UI
|
17
|
+
DANGEROUS_KEYWORDS: Set[str] = {
|
18
|
+
'questionary', 'input(', 'stdin', 'interactive', # Requires user input
|
19
|
+
'destructive', 'dangerous', 'irreversible', # Explicitly marked as dangerous
|
20
|
+
'runserver', 'testserver', # Dev servers
|
21
|
+
}
|
22
|
+
|
23
|
+
# Commands that should NEVER appear (absolute blacklist)
|
24
|
+
ABSOLUTE_BLACKLIST: Set[str] = {
|
25
|
+
# Destructive database commands
|
26
|
+
'flush', 'sqlflush', 'dbshell',
|
27
|
+
|
28
|
+
# Shell access (security risk)
|
29
|
+
'shell', 'shell_plus',
|
30
|
+
|
31
|
+
# Development server (not for web execution)
|
32
|
+
'runserver', 'testserver', 'runserver_ngrok',
|
33
|
+
|
34
|
+
# Project generation (not applicable in running app)
|
35
|
+
'startapp', 'startproject',
|
36
|
+
|
37
|
+
# SQL commands (direct SQL, potentially dangerous)
|
38
|
+
'sqlmigrate', 'sqlsequencereset',
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
def analyze_command_safety(command_class: BaseCommand, command_name: str) -> Dict[str, Any]:
|
43
|
+
"""
|
44
|
+
Analyze command to determine if it's safe for web execution.
|
45
|
+
|
46
|
+
Checks:
|
47
|
+
1. Explicit metadata (web_executable, requires_input, is_destructive)
|
48
|
+
2. Docstring analysis for dangerous keywords
|
49
|
+
3. Source code analysis for interactive input
|
50
|
+
4. Required arguments analysis
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
Dict with safety analysis results
|
54
|
+
"""
|
55
|
+
analysis = {
|
56
|
+
'is_safe': True,
|
57
|
+
'reasons': [],
|
58
|
+
'requires_input': False,
|
59
|
+
'is_destructive': False,
|
60
|
+
'web_executable': None,
|
61
|
+
}
|
62
|
+
|
63
|
+
# Check explicit metadata (highest priority)
|
64
|
+
if hasattr(command_class, 'web_executable'):
|
65
|
+
analysis['web_executable'] = command_class.web_executable
|
66
|
+
if not command_class.web_executable:
|
67
|
+
analysis['is_safe'] = False
|
68
|
+
analysis['reasons'].append('Command explicitly marked as not web-executable')
|
69
|
+
return analysis
|
70
|
+
|
71
|
+
if hasattr(command_class, 'requires_input'):
|
72
|
+
analysis['requires_input'] = command_class.requires_input
|
73
|
+
if command_class.requires_input:
|
74
|
+
analysis['is_safe'] = False
|
75
|
+
analysis['reasons'].append('Command requires interactive input')
|
76
|
+
return analysis
|
77
|
+
|
78
|
+
if hasattr(command_class, 'is_destructive'):
|
79
|
+
analysis['is_destructive'] = command_class.is_destructive
|
80
|
+
if command_class.is_destructive:
|
81
|
+
analysis['is_safe'] = False
|
82
|
+
analysis['reasons'].append('Command is marked as destructive')
|
83
|
+
return analysis
|
84
|
+
|
85
|
+
# Analyze docstring for dangerous keywords
|
86
|
+
docstring = (inspect.getdoc(command_class) or '').lower()
|
87
|
+
for keyword in DANGEROUS_KEYWORDS:
|
88
|
+
if keyword in docstring:
|
89
|
+
analysis['is_safe'] = False
|
90
|
+
analysis['reasons'].append(f'Docstring contains dangerous keyword: {keyword}')
|
91
|
+
return analysis
|
92
|
+
|
93
|
+
# Analyze source code for interactive input
|
94
|
+
try:
|
95
|
+
source = inspect.getsource(command_class)
|
96
|
+
if 'questionary' in source or 'input(' in source:
|
97
|
+
analysis['is_safe'] = False
|
98
|
+
analysis['requires_input'] = True
|
99
|
+
analysis['reasons'].append('Command requires interactive user input')
|
100
|
+
return analysis
|
101
|
+
except Exception:
|
102
|
+
# Can't analyze source, be safe
|
103
|
+
pass
|
104
|
+
|
105
|
+
return analysis
|
106
|
+
|
107
|
+
|
108
|
+
def is_command_allowed(command_name: str, app_name: str) -> bool:
|
109
|
+
"""
|
110
|
+
Check if command should be displayed in web interface.
|
111
|
+
|
112
|
+
Priority:
|
113
|
+
1. Custom blacklist from settings (DJANGO_CFG_COMMANDS_BLACKLIST)
|
114
|
+
2. Absolute blacklist - always exclude
|
115
|
+
3. Custom whitelist from settings (DJANGO_CFG_COMMANDS_WHITELIST)
|
116
|
+
4. Command metadata analysis (web_executable, requires_input, etc.)
|
117
|
+
5. django_cfg apps - analyze each command
|
118
|
+
6. Django core - be selective (only safe utility commands)
|
119
|
+
7. Third party - only if explicitly whitelisted
|
120
|
+
|
121
|
+
You can customize filtering in settings.py:
|
122
|
+
|
123
|
+
DJANGO_CFG_COMMANDS_BLACKLIST = {'my_dangerous_command'}
|
124
|
+
DJANGO_CFG_COMMANDS_WHITELIST = {'my_safe_command'}
|
125
|
+
|
126
|
+
Or add metadata to your Command class:
|
127
|
+
|
128
|
+
class Command(BaseCommand):
|
129
|
+
web_executable = True # Allow in web UI
|
130
|
+
requires_input = False # Doesn't need interactive input
|
131
|
+
is_destructive = False # Not destructive
|
132
|
+
"""
|
133
|
+
from django.conf import settings
|
134
|
+
|
135
|
+
# Custom blacklist from settings (highest priority)
|
136
|
+
custom_blacklist = getattr(settings, 'DJANGO_CFG_COMMANDS_BLACKLIST', set())
|
137
|
+
if command_name in custom_blacklist:
|
138
|
+
return False
|
139
|
+
|
140
|
+
# Absolute blacklist
|
141
|
+
if command_name in ABSOLUTE_BLACKLIST:
|
142
|
+
return False
|
143
|
+
|
144
|
+
# Custom whitelist from settings
|
145
|
+
custom_whitelist = getattr(settings, 'DJANGO_CFG_COMMANDS_WHITELIST', set())
|
146
|
+
if command_name in custom_whitelist:
|
147
|
+
return True
|
148
|
+
|
149
|
+
# Load and analyze command
|
150
|
+
try:
|
151
|
+
# Determine module path
|
152
|
+
if app_name == 'django_cfg':
|
153
|
+
module_path = f'django_cfg.management.commands.{command_name}'
|
154
|
+
elif app_name.startswith('django.'):
|
155
|
+
module_path = f'{app_name}.management.commands.{command_name}'
|
156
|
+
else:
|
157
|
+
module_path = f'{app_name}.management.commands.{command_name}'
|
158
|
+
|
159
|
+
command_module = importlib.import_module(module_path)
|
160
|
+
if hasattr(command_module, 'Command'):
|
161
|
+
command_class = command_module.Command
|
162
|
+
|
163
|
+
# Analyze command safety
|
164
|
+
analysis = analyze_command_safety(command_class, command_name)
|
165
|
+
|
166
|
+
# If command has explicit web_executable metadata, use it
|
167
|
+
if analysis['web_executable'] is not None:
|
168
|
+
return analysis['web_executable']
|
169
|
+
|
170
|
+
# If analysis says it's unsafe, exclude
|
171
|
+
if not analysis['is_safe']:
|
172
|
+
logger.debug(f"Command {command_name} excluded: {', '.join(analysis['reasons'])}")
|
173
|
+
return False
|
174
|
+
except Exception as e:
|
175
|
+
# Can't load/analyze command
|
176
|
+
logger.debug(f"Could not analyze command {command_name}: {e}")
|
177
|
+
# Be conservative - if we can't analyze, exclude unless from trusted source
|
178
|
+
pass
|
179
|
+
|
180
|
+
# Django CFG commands - include if analysis passed
|
181
|
+
if app_name == 'django_cfg':
|
182
|
+
return True
|
183
|
+
|
184
|
+
# Safe Django core commands (utility/read-only)
|
185
|
+
safe_django_core = {
|
186
|
+
'check', 'diffsettings', 'showmigrations',
|
187
|
+
'createcachetable', 'sendtestemail',
|
188
|
+
}
|
189
|
+
if app_name.startswith('django.') and command_name in safe_django_core:
|
190
|
+
return True
|
191
|
+
|
192
|
+
# Exclude other Django core by default
|
193
|
+
if app_name.startswith('django.'):
|
194
|
+
return False
|
195
|
+
|
196
|
+
# Third-party apps - only whitelisted
|
197
|
+
return False
|
198
|
+
|
199
|
+
|
14
200
|
def get_available_commands():
|
15
|
-
"""Get all available Django management commands."""
|
201
|
+
"""Get all available Django management commands (filtered for safety)."""
|
16
202
|
commands_dict = get_commands()
|
17
203
|
commands_list = []
|
18
|
-
|
204
|
+
|
19
205
|
for command_name, app_name in commands_dict.items():
|
206
|
+
# Filter out unsafe/unwanted commands
|
207
|
+
if not is_command_allowed(command_name, app_name):
|
208
|
+
continue
|
209
|
+
|
20
210
|
try:
|
21
211
|
# Try to get command description
|
22
212
|
if app_name == 'django_cfg':
|
23
213
|
module_path = f'django_cfg.management.commands.{command_name}'
|
24
214
|
else:
|
25
215
|
module_path = f'{app_name}.management.commands.{command_name}'
|
26
|
-
|
216
|
+
|
27
217
|
try:
|
28
218
|
command_module = importlib.import_module(module_path)
|
29
219
|
if hasattr(command_module, 'Command'):
|
@@ -33,7 +223,7 @@ def get_available_commands():
|
|
33
223
|
description = f'{command_name} command'
|
34
224
|
except ImportError:
|
35
225
|
description = f'{command_name} command'
|
36
|
-
|
226
|
+
|
37
227
|
commands_list.append({
|
38
228
|
'name': command_name,
|
39
229
|
'app': app_name,
|
@@ -41,10 +231,11 @@ def get_available_commands():
|
|
41
231
|
'is_core': app_name.startswith('django.'),
|
42
232
|
'is_custom': app_name == 'django_cfg',
|
43
233
|
})
|
44
|
-
except Exception:
|
234
|
+
except Exception as e:
|
45
235
|
# Skip problematic commands
|
236
|
+
logger.debug(f"Skipping command {command_name}: {e}")
|
46
237
|
continue
|
47
|
-
|
238
|
+
|
48
239
|
return commands_list
|
49
240
|
|
50
241
|
|
@@ -9,10 +9,10 @@ import json
|
|
9
9
|
from typing import Dict, Any
|
10
10
|
|
11
11
|
from django.utils import timezone
|
12
|
-
from django.conf import settings
|
13
12
|
|
14
13
|
from ...base import BaseCfgModule
|
15
14
|
from ..models.dashboard import DashboardData
|
15
|
+
from django_cfg.core.state import get_current_config
|
16
16
|
|
17
17
|
from .statistics import StatisticsCallbacks
|
18
18
|
from .system import SystemCallbacks
|
@@ -23,6 +23,13 @@ from .revolution import RevolutionCallbacks
|
|
23
23
|
from .users import UsersCallbacks
|
24
24
|
from .base import get_user_admin_urls
|
25
25
|
|
26
|
+
# Import new dashboard sections
|
27
|
+
from django_cfg.dashboard.sections.overview import OverviewSection
|
28
|
+
from django_cfg.dashboard.sections.stats import StatsSection
|
29
|
+
from django_cfg.dashboard.sections.system import SystemSection
|
30
|
+
from django_cfg.dashboard.sections.commands import CommandsSection
|
31
|
+
from django_cfg.dashboard.debug import save_section_render
|
32
|
+
|
26
33
|
logger = logging.getLogger(__name__)
|
27
34
|
|
28
35
|
|
@@ -50,13 +57,95 @@ class UnfoldCallbacks(
|
|
50
57
|
Returns all dashboard data as Pydantic models for type safety.
|
51
58
|
"""
|
52
59
|
try:
|
53
|
-
# Get
|
60
|
+
# Get current config for debug and environment settings
|
61
|
+
config = get_current_config()
|
62
|
+
|
63
|
+
# Log debug status
|
64
|
+
debug_enabled = config and config.debug
|
65
|
+
logger.info(f"[DEBUG MODE] Dashboard rendering with debug={debug_enabled} (config.debug={getattr(config, 'debug', 'N/A')})")
|
66
|
+
|
67
|
+
# Get dashboard data first
|
54
68
|
user_stats = self.get_user_statistics()
|
55
69
|
support_stats = self.get_support_statistics()
|
56
70
|
system_health = self.get_system_health()
|
57
71
|
quick_actions = self.get_quick_actions()
|
58
|
-
|
59
|
-
#
|
72
|
+
|
73
|
+
# Parse time range from query parameters (default: 7 days)
|
74
|
+
try:
|
75
|
+
time_range = int(request.GET.get('range', 7))
|
76
|
+
# Validate range
|
77
|
+
if time_range not in [7, 30, 90]:
|
78
|
+
time_range = 7
|
79
|
+
except (ValueError, TypeError):
|
80
|
+
time_range = 7
|
81
|
+
|
82
|
+
# Create navigation for time range filter
|
83
|
+
navigation = [
|
84
|
+
{
|
85
|
+
"title": "7 Days",
|
86
|
+
"link": "?range=7",
|
87
|
+
"active": time_range == 7,
|
88
|
+
"icon": "calendar_today"
|
89
|
+
},
|
90
|
+
{
|
91
|
+
"title": "30 Days",
|
92
|
+
"link": "?range=30",
|
93
|
+
"active": time_range == 30,
|
94
|
+
"icon": "date_range"
|
95
|
+
},
|
96
|
+
{
|
97
|
+
"title": "90 Days",
|
98
|
+
"link": "?range=90",
|
99
|
+
"active": time_range == 90,
|
100
|
+
"icon": "event"
|
101
|
+
},
|
102
|
+
]
|
103
|
+
|
104
|
+
# Render new dashboard sections
|
105
|
+
try:
|
106
|
+
# Create overview section and pass quick_actions + time_range + navigation
|
107
|
+
overview_sec = OverviewSection(request)
|
108
|
+
# Add quick_actions, time_range, and navigation to render context
|
109
|
+
overview_section = overview_sec.render(
|
110
|
+
quick_actions=[action.model_dump() for action in quick_actions],
|
111
|
+
time_range=time_range,
|
112
|
+
navigation=navigation
|
113
|
+
)
|
114
|
+
# Debug: save render (only in debug mode)
|
115
|
+
if config and config.debug:
|
116
|
+
save_section_render('overview', overview_section)
|
117
|
+
except Exception as e:
|
118
|
+
logger.error(f"Failed to render overview section: {e}", exc_info=True)
|
119
|
+
overview_section = None
|
120
|
+
|
121
|
+
try:
|
122
|
+
stats_section = StatsSection(request).render()
|
123
|
+
# Debug: save render (only in debug mode)
|
124
|
+
if config and config.debug:
|
125
|
+
save_section_render('stats', stats_section)
|
126
|
+
except Exception as e:
|
127
|
+
logger.error(f"Failed to render stats section: {e}", exc_info=True)
|
128
|
+
stats_section = None
|
129
|
+
|
130
|
+
try:
|
131
|
+
system_section = SystemSection(request).render()
|
132
|
+
# Debug: save render (only in debug mode)
|
133
|
+
if config and config.debug:
|
134
|
+
save_section_render('system', system_section)
|
135
|
+
except Exception as e:
|
136
|
+
logger.error(f"Failed to render system section: {e}", exc_info=True)
|
137
|
+
system_section = None
|
138
|
+
|
139
|
+
try:
|
140
|
+
commands_section = CommandsSection(request).render()
|
141
|
+
# Debug: save render (only in debug mode)
|
142
|
+
if config and config.debug:
|
143
|
+
save_section_render('commands', commands_section)
|
144
|
+
except Exception as e:
|
145
|
+
logger.error(f"Failed to render commands section: {e}", exc_info=True)
|
146
|
+
commands_section = None
|
147
|
+
|
148
|
+
# Combine all stat cards (data already loaded above)
|
60
149
|
all_stats = user_stats + support_stats
|
61
150
|
|
62
151
|
dashboard_data = DashboardData(
|
@@ -64,27 +153,30 @@ class UnfoldCallbacks(
|
|
64
153
|
system_health=system_health,
|
65
154
|
quick_actions=quick_actions,
|
66
155
|
last_updated=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
|
67
|
-
environment=getattr(
|
156
|
+
environment=getattr(config.environment, 'name', 'development') if config and hasattr(config, 'environment') else "development",
|
68
157
|
)
|
69
158
|
|
70
159
|
# Convert to template context (using to_dict for Unfold compatibility)
|
71
160
|
cards_data = [card.to_dict() for card in dashboard_data.stat_cards]
|
72
161
|
|
73
162
|
context.update({
|
163
|
+
# New dashboard sections (rendered HTML)
|
164
|
+
"overview_section": overview_section,
|
165
|
+
"stats_section": stats_section,
|
166
|
+
"system_section": system_section,
|
167
|
+
"commands_section": commands_section,
|
168
|
+
|
74
169
|
# Statistics cards
|
75
170
|
"cards": cards_data,
|
76
171
|
"user_stats": [card.to_dict() for card in user_stats],
|
77
172
|
"support_stats": [card.to_dict() for card in support_stats],
|
78
|
-
|
173
|
+
|
79
174
|
# System health (convert to dict for template)
|
80
175
|
"system_health": {
|
81
176
|
item.component + "_status": item.status
|
82
177
|
for item in dashboard_data.system_health
|
83
178
|
},
|
84
|
-
|
85
|
-
# System metrics
|
86
|
-
"system_metrics": self.get_system_metrics(),
|
87
|
-
|
179
|
+
|
88
180
|
# Quick actions
|
89
181
|
"quick_actions": [
|
90
182
|
action.model_dump() for action in dashboard_data.quick_actions
|
@@ -19,16 +19,33 @@ class DashboardManager(BaseCfgModule):
|
|
19
19
|
Dashboard configuration manager for Unfold.
|
20
20
|
"""
|
21
21
|
|
22
|
-
def __init__(self):
|
22
|
+
def __init__(self, config=None):
|
23
23
|
"""Initialize dashboard manager."""
|
24
24
|
super().__init__()
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
# Lazy load config to avoid circular import during settings generation
|
26
|
+
self._config = config
|
27
|
+
self._config_loaded = config is not None
|
28
|
+
|
29
|
+
@property
|
30
|
+
def config(self):
|
31
|
+
"""Lazy load config on first access."""
|
32
|
+
if not self._config_loaded:
|
33
|
+
try:
|
34
|
+
self._config = self.get_config()
|
35
|
+
except Exception:
|
36
|
+
# Config cannot be loaded (e.g., during settings generation)
|
37
|
+
# Set to None and mark as loaded to avoid repeated attempts
|
38
|
+
self._config = None
|
39
|
+
finally:
|
40
|
+
self._config_loaded = True
|
41
|
+
return self._config
|
42
|
+
|
43
|
+
@staticmethod
|
44
|
+
def _get_default_dropdown_items() -> List[Dict[str, Any]]:
|
28
45
|
"""Get default dropdown menu items for Unfold admin (lazy import to avoid circular imports)."""
|
29
46
|
from django_cfg.config import get_default_dropdown_items
|
30
47
|
dropdown_items = get_default_dropdown_items()
|
31
|
-
|
48
|
+
|
32
49
|
# Convert SiteDropdownItem objects to dictionaries for Unfold
|
33
50
|
return [item.to_dict() for item in dropdown_items]
|
34
51
|
|
@@ -47,6 +64,37 @@ class DashboardManager(BaseCfgModule):
|
|
47
64
|
]
|
48
65
|
),
|
49
66
|
]
|
67
|
+
|
68
|
+
# Add Operations section (System & Monitoring tools)
|
69
|
+
operations_items = []
|
70
|
+
|
71
|
+
# RPC Dashboard (if enabled)
|
72
|
+
if self.is_rpc_enabled():
|
73
|
+
operations_items.append(
|
74
|
+
NavigationItem(title="RPC Dashboard", icon=Icons.MONITOR_HEART, link="/cfg/admin/rpc/")
|
75
|
+
)
|
76
|
+
|
77
|
+
# Background Tasks (if enabled)
|
78
|
+
if self.should_enable_tasks():
|
79
|
+
operations_items.extend([
|
80
|
+
NavigationItem(title="Background Tasks", icon=Icons.TASK, link="/admin/django_dramatiq/task/"),
|
81
|
+
NavigationItem(title="Task Dashboard", icon=Icons.SETTINGS_APPLICATIONS, link="/cfg/admin/django_cfg_tasks/admin/dashboard/"),
|
82
|
+
])
|
83
|
+
|
84
|
+
# Maintenance Mode (if enabled)
|
85
|
+
if self.is_maintenance_enabled():
|
86
|
+
operations_items.append(
|
87
|
+
NavigationItem(title="Maintenance", icon=Icons.BUILD, link="/admin/maintenance/cloudflaresite/")
|
88
|
+
)
|
89
|
+
|
90
|
+
# Add Operations section if there are any items
|
91
|
+
if operations_items:
|
92
|
+
navigation_sections.append(NavigationSection(
|
93
|
+
title="Operations",
|
94
|
+
separator=True,
|
95
|
+
collapsible=True,
|
96
|
+
items=operations_items
|
97
|
+
))
|
50
98
|
|
51
99
|
# Add Accounts section if enabled
|
52
100
|
if self.is_accounts_enabled():
|
@@ -134,46 +182,20 @@ class DashboardManager(BaseCfgModule):
|
|
134
182
|
NavigationItem(title="Chat Messages", icon=Icons.MESSAGE, link="/admin/django_cfg_knowbase/chatmessage/"),
|
135
183
|
]
|
136
184
|
))
|
137
|
-
|
138
|
-
# Add Tasks section if knowbase or agents are enabled
|
139
|
-
if self.should_enable_tasks():
|
140
|
-
navigation_sections.append(NavigationSection(
|
141
|
-
title="Background Tasks",
|
142
|
-
separator=True,
|
143
|
-
collapsible=True,
|
144
|
-
items=[
|
145
|
-
NavigationItem(title="Task Queue", icon=Icons.QUEUE, link="/admin/django_dramatiq/task/"),
|
146
|
-
NavigationItem(title="Task Dashboard", icon=Icons.SETTINGS_APPLICATIONS, link="/cfg/admin/django_cfg_tasks/admin/dashboard/"),
|
147
|
-
]
|
148
|
-
))
|
149
|
-
|
150
|
-
# Add Maintenance section if enabled
|
151
|
-
if self.is_maintenance_enabled():
|
152
|
-
navigation_sections.append(NavigationSection(
|
153
|
-
title="Maintenance Mode",
|
154
|
-
separator=True,
|
155
|
-
collapsible=True,
|
156
|
-
items=[
|
157
|
-
NavigationItem(title="Cloudflare Sites", icon=Icons.CLOUD, link="/admin/maintenance/cloudflaresite/"),
|
158
|
-
NavigationItem(title="API Keys", icon=Icons.KEY, link="/admin/maintenance/cloudflareapikey/"),
|
159
|
-
NavigationItem(title="Maintenance Logs", icon=Icons.HISTORY, link="/admin/maintenance/maintenancelog/"),
|
160
|
-
NavigationItem(title="Scheduled Maintenance", icon=Icons.SCHEDULE, link="/admin/maintenance/scheduledmaintenance/"),
|
161
|
-
]
|
162
|
-
))
|
163
|
-
|
185
|
+
|
164
186
|
# Add Payments section if enabled
|
165
187
|
if self.is_payments_enabled():
|
166
188
|
try:
|
167
189
|
from django_cfg.models.payments import PaymentsConfig
|
168
190
|
config = PaymentsConfig.get_current_config()
|
169
|
-
|
191
|
+
|
170
192
|
payments_items = []
|
171
|
-
|
193
|
+
|
172
194
|
# Main dashboard (always show if payments app enabled)
|
173
195
|
payments_items.append(
|
174
196
|
NavigationItem(title="Payment Dashboard", icon=Icons.DASHBOARD, link="/cfg/admin/django_cfg_payments/admin/")
|
175
197
|
)
|
176
|
-
|
198
|
+
|
177
199
|
# Always show basic admin models (even if payments functionality is disabled)
|
178
200
|
payments_items.extend([
|
179
201
|
NavigationItem(title="Universal Payments", icon=Icons.ACCOUNT_BALANCE, link="/admin/payments/universalpayment/"),
|
@@ -181,7 +203,7 @@ class DashboardManager(BaseCfgModule):
|
|
181
203
|
NavigationItem(title="Networks", icon=Icons.LINK, link="/admin/payments/network/"),
|
182
204
|
NavigationItem(title="Provider Currencies", icon=Icons.ACCOUNT_CIRCLE, link="/admin/payments/providercurrency/"),
|
183
205
|
])
|
184
|
-
|
206
|
+
|
185
207
|
# Add advanced features only if payments functionality is enabled
|
186
208
|
if config.enabled:
|
187
209
|
# payments_items.append(
|
@@ -193,7 +215,7 @@ class DashboardManager(BaseCfgModule):
|
|
193
215
|
# payments_items.append(
|
194
216
|
# NavigationItem(title="Currency Converter", icon=Icons.CURRENCY_EXCHANGE, link="/cfg/admin/django_cfg_payments/admin/tools/converter/")
|
195
217
|
# )
|
196
|
-
|
218
|
+
|
197
219
|
# Show subscription features only if enabled
|
198
220
|
if config.show_subscription_management():
|
199
221
|
payments_items.extend([
|
@@ -201,39 +223,39 @@ class DashboardManager(BaseCfgModule):
|
|
201
223
|
NavigationItem(title="Tariffs", icon=Icons.PRICE_CHANGE, link="/admin/payments/tariff/"),
|
202
224
|
NavigationItem(title="Tariff Endpoint Groups", icon=Icons.GROUP, link="/admin/payments/tariffendpointgroup/"),
|
203
225
|
])
|
204
|
-
|
226
|
+
|
205
227
|
# Show API management only if enabled
|
206
228
|
if config.show_api_management():
|
207
229
|
payments_items.extend([
|
208
230
|
NavigationItem(title="API Keys", icon=Icons.KEY, link="/admin/payments/apikey/"),
|
209
231
|
NavigationItem(title="Endpoint Groups", icon=Icons.GROUP, link="/admin/payments/endpointgroup/"),
|
210
232
|
])
|
211
|
-
|
233
|
+
|
212
234
|
# Show balance/transaction features only if enabled
|
213
235
|
if config.show_balance_management():
|
214
236
|
payments_items.append(
|
215
237
|
NavigationItem(title="Balances", icon=Icons.ACCOUNT_BALANCE_WALLET, link="/admin/payments/userbalance/")
|
216
238
|
)
|
217
|
-
|
239
|
+
|
218
240
|
if config.show_transaction_history():
|
219
241
|
payments_items.append(
|
220
242
|
NavigationItem(title="Transactions", icon=Icons.RECEIPT_LONG, link="/admin/payments/transaction/")
|
221
243
|
)
|
222
|
-
|
244
|
+
|
223
245
|
except Exception:
|
224
246
|
# Fallback
|
225
247
|
payments_items = [
|
226
248
|
NavigationItem(title="Payment Dashboard", icon=Icons.DASHBOARD, link="/cfg/admin/django_cfg_payments/admin/"),
|
227
249
|
NavigationItem(title="Universal Payments", icon=Icons.ACCOUNT_BALANCE, link="/admin/payments/universalpayment/"),
|
228
250
|
]
|
229
|
-
|
251
|
+
|
230
252
|
navigation_sections.append(NavigationSection(
|
231
253
|
title="Payments",
|
232
254
|
separator=True,
|
233
255
|
collapsible=True,
|
234
256
|
items=payments_items
|
235
257
|
))
|
236
|
-
|
258
|
+
|
237
259
|
# Convert all NavigationSection objects to dictionaries
|
238
260
|
return [section.to_dict() for section in navigation_sections]
|
239
261
|
|
@@ -165,7 +165,7 @@ class UnfoldConfig(BaseModel):
|
|
165
165
|
|
166
166
|
# Site branding
|
167
167
|
site_title: str = Field(
|
168
|
-
default="
|
168
|
+
default="Django-CFG Admin",
|
169
169
|
description="Site title shown in admin"
|
170
170
|
)
|
171
171
|
|
@@ -423,19 +423,21 @@ class UnfoldConfig(BaseModel):
|
|
423
423
|
"show_all_applications": self.show_all_applications,
|
424
424
|
}
|
425
425
|
|
426
|
-
# Get default navigation from dashboard manager
|
426
|
+
# Get default navigation from dashboard manager first
|
427
|
+
nav_items = []
|
427
428
|
try:
|
428
429
|
from ..dashboard import DashboardManager
|
429
430
|
dashboard = DashboardManager()
|
430
431
|
nav_items = dashboard.get_navigation_config()
|
431
|
-
except
|
432
|
-
|
433
|
-
|
434
|
-
|
432
|
+
except Exception as e:
|
433
|
+
# Catch all exceptions including circular imports during settings generation
|
434
|
+
# During settings generation, config discovery may fail - use empty nav
|
435
|
+
pass
|
436
|
+
|
437
|
+
# Add custom navigation from project (if defined) - appears after default
|
435
438
|
if self.navigation:
|
436
|
-
# Project has custom navigation - add it first
|
437
439
|
nav_items.extend([group.to_dict() for group in self.navigation])
|
438
|
-
|
440
|
+
|
439
441
|
# Add legacy navigation_items if configured
|
440
442
|
if self.navigation_items:
|
441
443
|
nav_items.extend(self.navigation_items)
|
@@ -445,13 +447,12 @@ class UnfoldConfig(BaseModel):
|
|
445
447
|
|
446
448
|
# Add site dropdown - combine default from dashboard + project dropdown
|
447
449
|
dropdown_items = []
|
448
|
-
|
450
|
+
|
449
451
|
# First add default dropdown from dashboard manager
|
450
452
|
try:
|
451
453
|
from ..dashboard import DashboardManager
|
452
|
-
|
453
|
-
|
454
|
-
except ImportError:
|
454
|
+
dropdown_items.extend(DashboardManager._get_default_dropdown_items())
|
455
|
+
except (ImportError, Exception):
|
455
456
|
pass
|
456
457
|
|
457
458
|
# Then add project-specific dropdown items
|
@@ -55,19 +55,24 @@ class NavigationItem(BaseModel):
|
|
55
55
|
class NavigationSection(BaseModel):
|
56
56
|
"""Navigation section configuration."""
|
57
57
|
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
58
|
-
|
58
|
+
|
59
59
|
title: str = Field(..., min_length=1, description="Section title")
|
60
60
|
separator: bool = Field(default=True, description="Show separator")
|
61
61
|
collapsible: bool = Field(default=True, description="Section is collapsible")
|
62
|
+
open: bool = Field(default=False, description="Section is open by default")
|
62
63
|
items: List[NavigationItem] = Field(default_factory=list, description="Navigation items")
|
63
|
-
|
64
|
+
|
64
65
|
def to_dict(self) -> dict:
|
65
66
|
"""Convert to dictionary for Unfold admin."""
|
66
|
-
|
67
|
+
result = {
|
67
68
|
"title": self.title,
|
68
69
|
"separator": self.separator,
|
69
70
|
"collapsible": self.collapsible,
|
70
71
|
"items": [item.to_dict() for item in self.items],
|
71
72
|
}
|
73
|
+
# Add open only if True (to avoid breaking existing navigation)
|
74
|
+
if self.open:
|
75
|
+
result["open"] = True
|
76
|
+
return result
|
72
77
|
|
73
78
|
|