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
@@ -0,0 +1,308 @@
|
|
1
|
+
"""
|
2
|
+
Dashboard Component Classes
|
3
|
+
|
4
|
+
Uses Unfold's Component Class system for data preprocessing.
|
5
|
+
Separates business logic from presentation templates.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from typing import Dict, Any
|
9
|
+
from unfold.components import BaseComponent, register_component
|
10
|
+
|
11
|
+
|
12
|
+
@register_component
|
13
|
+
class SystemMetricsComponent(BaseComponent):
|
14
|
+
"""
|
15
|
+
System metrics component for dashboard.
|
16
|
+
|
17
|
+
Provides health metrics for database, cache, storage, and API.
|
18
|
+
"""
|
19
|
+
|
20
|
+
def get_context_data(self, **kwargs):
|
21
|
+
"""Prepare system metrics data."""
|
22
|
+
context = super().get_context_data(**kwargs)
|
23
|
+
context.update({
|
24
|
+
"data": self.get_system_metrics()
|
25
|
+
})
|
26
|
+
return context
|
27
|
+
|
28
|
+
def get_system_metrics(self) -> Dict[str, Any]:
|
29
|
+
"""Fetch system health metrics."""
|
30
|
+
from django.db import connection
|
31
|
+
from django.core.cache import cache
|
32
|
+
import shutil
|
33
|
+
|
34
|
+
metrics = {}
|
35
|
+
|
36
|
+
# Database Health
|
37
|
+
try:
|
38
|
+
with connection.cursor() as cursor:
|
39
|
+
cursor.execute("SELECT 1")
|
40
|
+
metrics["database"] = {
|
41
|
+
"value": 95,
|
42
|
+
"title": "Database Health",
|
43
|
+
"description": "Connection successful",
|
44
|
+
}
|
45
|
+
except Exception as e:
|
46
|
+
metrics["database"] = {
|
47
|
+
"value": 0,
|
48
|
+
"title": "Database Health",
|
49
|
+
"description": f"Error: {str(e)[:50]}",
|
50
|
+
}
|
51
|
+
|
52
|
+
# Cache Performance
|
53
|
+
try:
|
54
|
+
cache.set("health_check", "ok", 10)
|
55
|
+
if cache.get("health_check") == "ok":
|
56
|
+
metrics["cache"] = {
|
57
|
+
"value": 90,
|
58
|
+
"title": "Cache Performance",
|
59
|
+
"description": "Cache working properly",
|
60
|
+
}
|
61
|
+
else:
|
62
|
+
metrics["cache"] = {
|
63
|
+
"value": 50,
|
64
|
+
"title": "Cache Performance",
|
65
|
+
"description": "Cache response delayed",
|
66
|
+
}
|
67
|
+
except Exception as e:
|
68
|
+
metrics["cache"] = {
|
69
|
+
"value": 0,
|
70
|
+
"title": "Cache Performance",
|
71
|
+
"description": f"Error: {str(e)[:50]}",
|
72
|
+
}
|
73
|
+
|
74
|
+
# Storage Space
|
75
|
+
try:
|
76
|
+
total, used, free = shutil.disk_usage("/")
|
77
|
+
free_percentage = int((free / total) * 100)
|
78
|
+
usage_percentage = 100 - free_percentage
|
79
|
+
|
80
|
+
metrics["storage"] = {
|
81
|
+
"value": free_percentage,
|
82
|
+
"title": "Disk Space",
|
83
|
+
"description": f"{free_percentage}% free ({usage_percentage}% used)",
|
84
|
+
}
|
85
|
+
except Exception as e:
|
86
|
+
metrics["storage"] = {
|
87
|
+
"value": 0,
|
88
|
+
"title": "Disk Space",
|
89
|
+
"description": f"Error: {str(e)[:50]}",
|
90
|
+
}
|
91
|
+
|
92
|
+
# API Health
|
93
|
+
try:
|
94
|
+
from django.urls import get_resolver
|
95
|
+
resolver = get_resolver()
|
96
|
+
url_patterns = list(resolver.url_patterns)
|
97
|
+
|
98
|
+
metrics["api"] = {
|
99
|
+
"value": 100,
|
100
|
+
"title": "REST API",
|
101
|
+
"description": f"{len(url_patterns)} URL patterns",
|
102
|
+
}
|
103
|
+
except Exception as e:
|
104
|
+
metrics["api"] = {
|
105
|
+
"value": 50,
|
106
|
+
"title": "REST API",
|
107
|
+
"description": "Unable to count URLs",
|
108
|
+
}
|
109
|
+
|
110
|
+
return metrics
|
111
|
+
|
112
|
+
|
113
|
+
@register_component
|
114
|
+
class RecentUsersComponent(BaseComponent):
|
115
|
+
"""
|
116
|
+
Recent users table component.
|
117
|
+
|
118
|
+
Provides formatted table data for displaying recent user registrations.
|
119
|
+
"""
|
120
|
+
|
121
|
+
def get_context_data(self, **kwargs):
|
122
|
+
"""Prepare recent users table data."""
|
123
|
+
context = super().get_context_data(**kwargs)
|
124
|
+
|
125
|
+
from django.contrib.auth import get_user_model
|
126
|
+
User = get_user_model()
|
127
|
+
|
128
|
+
try:
|
129
|
+
recent_users = User.objects.order_by('-date_joined')[:10]
|
130
|
+
|
131
|
+
context.update({
|
132
|
+
"data": {
|
133
|
+
"headers": ["Username", "Email", "Status", "Staff", "Joined"],
|
134
|
+
"rows": [
|
135
|
+
[
|
136
|
+
user.username,
|
137
|
+
user.email,
|
138
|
+
"✅ Active" if user.is_active else "❌ Inactive",
|
139
|
+
"🛡️ Yes" if user.is_staff else "—",
|
140
|
+
user.date_joined.strftime('%Y-%m-%d %H:%M')
|
141
|
+
]
|
142
|
+
for user in recent_users
|
143
|
+
]
|
144
|
+
}
|
145
|
+
})
|
146
|
+
except Exception:
|
147
|
+
context.update({
|
148
|
+
"data": {
|
149
|
+
"headers": [],
|
150
|
+
"rows": []
|
151
|
+
}
|
152
|
+
})
|
153
|
+
|
154
|
+
return context
|
155
|
+
|
156
|
+
|
157
|
+
@register_component
|
158
|
+
class ChartsComponent(BaseComponent):
|
159
|
+
"""
|
160
|
+
Charts data component for analytics.
|
161
|
+
|
162
|
+
Provides chart data for user registrations and activity.
|
163
|
+
Supports time range filtering (7/30/90 days).
|
164
|
+
"""
|
165
|
+
|
166
|
+
def get_context_data(self, **kwargs):
|
167
|
+
"""Prepare charts data."""
|
168
|
+
context = super().get_context_data(**kwargs)
|
169
|
+
|
170
|
+
# Get time range from kwargs (default: 7 days)
|
171
|
+
days = kwargs.get('days', 7)
|
172
|
+
|
173
|
+
from django.contrib.auth import get_user_model
|
174
|
+
from datetime import datetime, timedelta
|
175
|
+
from django.utils import timezone
|
176
|
+
import json
|
177
|
+
|
178
|
+
User = get_user_model()
|
179
|
+
|
180
|
+
try:
|
181
|
+
# Get last N days
|
182
|
+
today = timezone.now().date()
|
183
|
+
dates = [(today - timedelta(days=i)).strftime('%Y-%m-%d')
|
184
|
+
for i in range(days-1, -1, -1)]
|
185
|
+
|
186
|
+
# User registrations
|
187
|
+
registrations = []
|
188
|
+
for date_str in dates:
|
189
|
+
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
|
190
|
+
count = User.objects.filter(date_joined__date=date_obj).count()
|
191
|
+
registrations.append(count)
|
192
|
+
|
193
|
+
# User activity (last login)
|
194
|
+
activity = []
|
195
|
+
for date_str in dates:
|
196
|
+
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
|
197
|
+
count = User.objects.filter(
|
198
|
+
last_login__date=date_obj
|
199
|
+
).count() if hasattr(User, 'last_login') else 0
|
200
|
+
activity.append(count)
|
201
|
+
|
202
|
+
# Format labels
|
203
|
+
day_labels = [d.split('-')[2] for d in dates]
|
204
|
+
|
205
|
+
# Chart data structures
|
206
|
+
user_reg_data = {
|
207
|
+
'labels': day_labels,
|
208
|
+
'datasets': [{
|
209
|
+
'label': 'New Users',
|
210
|
+
'data': registrations,
|
211
|
+
'backgroundColor': 'rgba(59, 130, 246, 0.5)',
|
212
|
+
'borderColor': 'rgb(59, 130, 246)',
|
213
|
+
'borderWidth': 2,
|
214
|
+
}]
|
215
|
+
}
|
216
|
+
|
217
|
+
user_activity_data = {
|
218
|
+
'labels': day_labels,
|
219
|
+
'datasets': [{
|
220
|
+
'label': 'Active Users',
|
221
|
+
'data': activity,
|
222
|
+
'backgroundColor': 'rgba(34, 197, 94, 0.5)',
|
223
|
+
'borderColor': 'rgb(34, 197, 94)',
|
224
|
+
'borderWidth': 2,
|
225
|
+
}]
|
226
|
+
}
|
227
|
+
|
228
|
+
context.update({
|
229
|
+
"data": {
|
230
|
+
"registrations": json.dumps(user_reg_data),
|
231
|
+
"activity": json.dumps(user_activity_data),
|
232
|
+
}
|
233
|
+
})
|
234
|
+
except Exception:
|
235
|
+
context.update({
|
236
|
+
"data": {}
|
237
|
+
})
|
238
|
+
|
239
|
+
return context
|
240
|
+
|
241
|
+
|
242
|
+
@register_component
|
243
|
+
class ActivityTrackerComponent(BaseComponent):
|
244
|
+
"""
|
245
|
+
Activity tracker component for GitHub-style heatmap.
|
246
|
+
|
247
|
+
Provides 365 days of user activity data with level indicators.
|
248
|
+
"""
|
249
|
+
|
250
|
+
def get_context_data(self, **kwargs):
|
251
|
+
"""Prepare activity tracker data."""
|
252
|
+
context = super().get_context_data(**kwargs)
|
253
|
+
|
254
|
+
from django.contrib.auth import get_user_model
|
255
|
+
from datetime import timedelta
|
256
|
+
from django.utils import timezone
|
257
|
+
|
258
|
+
User = get_user_model()
|
259
|
+
|
260
|
+
try:
|
261
|
+
today = timezone.now().date()
|
262
|
+
activity_data = []
|
263
|
+
|
264
|
+
for days_ago in range(364, -1, -1): # 365 days
|
265
|
+
date = today - timedelta(days=days_ago)
|
266
|
+
|
267
|
+
# Count registrations
|
268
|
+
registrations = User.objects.filter(
|
269
|
+
date_joined__date=date
|
270
|
+
).count()
|
271
|
+
|
272
|
+
# Count logins
|
273
|
+
logins = 0
|
274
|
+
if hasattr(User, 'last_login'):
|
275
|
+
logins = User.objects.filter(
|
276
|
+
last_login__date=date
|
277
|
+
).count()
|
278
|
+
|
279
|
+
total_activity = registrations + logins
|
280
|
+
|
281
|
+
activity_data.append({
|
282
|
+
'date': date.isoformat(),
|
283
|
+
'count': total_activity,
|
284
|
+
'level': self._get_activity_level(total_activity),
|
285
|
+
})
|
286
|
+
|
287
|
+
context.update({
|
288
|
+
"data": activity_data
|
289
|
+
})
|
290
|
+
except Exception:
|
291
|
+
context.update({
|
292
|
+
"data": []
|
293
|
+
})
|
294
|
+
|
295
|
+
return context
|
296
|
+
|
297
|
+
def _get_activity_level(self, count: int) -> int:
|
298
|
+
"""Convert activity count to level (0-4) for heatmap colors."""
|
299
|
+
if count == 0:
|
300
|
+
return 0
|
301
|
+
elif count <= 2:
|
302
|
+
return 1
|
303
|
+
elif count <= 5:
|
304
|
+
return 2
|
305
|
+
elif count <= 10:
|
306
|
+
return 3
|
307
|
+
else:
|
308
|
+
return 4
|
@@ -0,0 +1,176 @@
|
|
1
|
+
"""
|
2
|
+
Debug utilities for dashboard rendering.
|
3
|
+
|
4
|
+
Saves rendered HTML to disk for inspection and comparison.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import os
|
8
|
+
import json
|
9
|
+
from datetime import datetime
|
10
|
+
from pathlib import Path
|
11
|
+
from typing import Optional, Dict, Any
|
12
|
+
from django.conf import settings
|
13
|
+
|
14
|
+
|
15
|
+
class DashboardDebugger:
|
16
|
+
"""Save dashboard renders for debugging."""
|
17
|
+
|
18
|
+
def __init__(self, output_dir: Optional[Path] = None):
|
19
|
+
"""
|
20
|
+
Initialize debugger.
|
21
|
+
|
22
|
+
Args:
|
23
|
+
output_dir: Directory to save renders (default: django_cfg/debug/dashboard/)
|
24
|
+
"""
|
25
|
+
if output_dir is None:
|
26
|
+
# Use django_cfg package directory
|
27
|
+
django_cfg_root = Path(__file__).parent.parent
|
28
|
+
output_dir = django_cfg_root / 'debug' / 'dashboard'
|
29
|
+
|
30
|
+
self.output_dir = Path(output_dir)
|
31
|
+
self.output_dir.mkdir(parents=True, exist_ok=True)
|
32
|
+
|
33
|
+
def save_render(
|
34
|
+
self,
|
35
|
+
html: str,
|
36
|
+
name: str = 'dashboard',
|
37
|
+
context: Optional[Dict[str, Any]] = None,
|
38
|
+
metadata: Optional[Dict[str, Any]] = None
|
39
|
+
) -> Path:
|
40
|
+
"""
|
41
|
+
Save rendered HTML with metadata.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
html: Rendered HTML content
|
45
|
+
name: Base name for files
|
46
|
+
context: Template context data
|
47
|
+
metadata: Additional metadata
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
Path to saved HTML file
|
51
|
+
"""
|
52
|
+
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
53
|
+
base_name = f"{name}_{timestamp}"
|
54
|
+
|
55
|
+
# Save HTML
|
56
|
+
html_path = self.output_dir / f"{base_name}.html"
|
57
|
+
html_path.write_text(html, encoding='utf-8')
|
58
|
+
|
59
|
+
# Save context as JSON
|
60
|
+
if context:
|
61
|
+
context_path = self.output_dir / f"{base_name}_context.json"
|
62
|
+
# Convert context to JSON-serializable format
|
63
|
+
serializable_context = self._make_serializable(context)
|
64
|
+
context_path.write_text(
|
65
|
+
json.dumps(serializable_context, indent=2, ensure_ascii=False),
|
66
|
+
encoding='utf-8'
|
67
|
+
)
|
68
|
+
|
69
|
+
# Save metadata
|
70
|
+
meta = {
|
71
|
+
'timestamp': timestamp,
|
72
|
+
'name': name,
|
73
|
+
'html_size': len(html),
|
74
|
+
'html_lines': html.count('\n'),
|
75
|
+
}
|
76
|
+
|
77
|
+
if metadata:
|
78
|
+
meta.update(metadata)
|
79
|
+
|
80
|
+
meta_path = self.output_dir / f"{base_name}_meta.json"
|
81
|
+
meta_path.write_text(
|
82
|
+
json.dumps(meta, indent=2, ensure_ascii=False),
|
83
|
+
encoding='utf-8'
|
84
|
+
)
|
85
|
+
|
86
|
+
print(f"✅ Saved dashboard render: {html_path}")
|
87
|
+
print(f" Context: {context_path if context else 'N/A'}")
|
88
|
+
print(f" Metadata: {meta_path}")
|
89
|
+
|
90
|
+
return html_path
|
91
|
+
|
92
|
+
def _make_serializable(self, obj: Any) -> Any:
|
93
|
+
"""Convert object to JSON-serializable format."""
|
94
|
+
if isinstance(obj, dict):
|
95
|
+
return {k: self._make_serializable(v) for k, v in obj.items()}
|
96
|
+
elif isinstance(obj, (list, tuple)):
|
97
|
+
return [self._make_serializable(item) for item in obj]
|
98
|
+
elif isinstance(obj, (str, int, float, bool, type(None))):
|
99
|
+
return obj
|
100
|
+
else:
|
101
|
+
# For non-serializable objects, use string representation
|
102
|
+
return str(obj)
|
103
|
+
|
104
|
+
def save_section_render(
|
105
|
+
self,
|
106
|
+
section_name: str,
|
107
|
+
html: str,
|
108
|
+
section_data: Optional[Dict[str, Any]] = None
|
109
|
+
) -> Path:
|
110
|
+
"""
|
111
|
+
Save individual section render.
|
112
|
+
|
113
|
+
Args:
|
114
|
+
section_name: Name of section (overview, stats, etc.)
|
115
|
+
html: Rendered HTML
|
116
|
+
section_data: Section-specific data
|
117
|
+
|
118
|
+
Returns:
|
119
|
+
Path to saved file
|
120
|
+
"""
|
121
|
+
return self.save_render(
|
122
|
+
html=html,
|
123
|
+
name=f"section_{section_name}",
|
124
|
+
context=section_data,
|
125
|
+
metadata={'section': section_name}
|
126
|
+
)
|
127
|
+
|
128
|
+
def compare_with_archive(self, current_html: str, archive_path: Path) -> Dict[str, Any]:
|
129
|
+
"""
|
130
|
+
Compare current render with archived version.
|
131
|
+
|
132
|
+
Args:
|
133
|
+
current_html: Current rendered HTML
|
134
|
+
archive_path: Path to archived HTML
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
Comparison results
|
138
|
+
"""
|
139
|
+
if not archive_path.exists():
|
140
|
+
return {
|
141
|
+
'error': f"Archive not found: {archive_path}"
|
142
|
+
}
|
143
|
+
|
144
|
+
archive_html = archive_path.read_text(encoding='utf-8')
|
145
|
+
|
146
|
+
return {
|
147
|
+
'current_size': len(current_html),
|
148
|
+
'archive_size': len(archive_html),
|
149
|
+
'size_diff': len(current_html) - len(archive_html),
|
150
|
+
'current_lines': current_html.count('\n'),
|
151
|
+
'archive_lines': archive_html.count('\n'),
|
152
|
+
'lines_diff': current_html.count('\n') - archive_html.count('\n'),
|
153
|
+
'identical': current_html == archive_html,
|
154
|
+
}
|
155
|
+
|
156
|
+
|
157
|
+
# Global instance
|
158
|
+
_debugger: Optional[DashboardDebugger] = None
|
159
|
+
|
160
|
+
|
161
|
+
def get_debugger() -> DashboardDebugger:
|
162
|
+
"""Get or create global debugger instance."""
|
163
|
+
global _debugger
|
164
|
+
if _debugger is None:
|
165
|
+
_debugger = DashboardDebugger()
|
166
|
+
return _debugger
|
167
|
+
|
168
|
+
|
169
|
+
def save_dashboard_render(html: str, **kwargs) -> Path:
|
170
|
+
"""Convenience function to save dashboard render."""
|
171
|
+
return get_debugger().save_render(html, **kwargs)
|
172
|
+
|
173
|
+
|
174
|
+
def save_section_render(section_name: str, html: str, **kwargs) -> Path:
|
175
|
+
"""Convenience function to save section render."""
|
176
|
+
return get_debugger().save_section_render(section_name, html, **kwargs)
|
File without changes
|
File without changes
|
@@ -0,0 +1,109 @@
|
|
1
|
+
"""
|
2
|
+
Management command to debug dashboard rendering.
|
3
|
+
|
4
|
+
Renders all dashboard sections and saves them for inspection.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from django.core.management.base import BaseCommand
|
8
|
+
from django.test import RequestFactory
|
9
|
+
from django.contrib.auth import get_user_model
|
10
|
+
|
11
|
+
from django_cfg.dashboard.sections.overview import OverviewSection
|
12
|
+
from django_cfg.dashboard.sections.stats import StatsSection
|
13
|
+
from django_cfg.dashboard.sections.system import SystemSection
|
14
|
+
from django_cfg.dashboard.sections.commands import CommandsSection
|
15
|
+
from django_cfg.dashboard.debug import get_debugger
|
16
|
+
|
17
|
+
|
18
|
+
class Command(BaseCommand):
|
19
|
+
help = "Debug dashboard rendering - saves all sections to disk"
|
20
|
+
|
21
|
+
def add_arguments(self, parser):
|
22
|
+
parser.add_argument(
|
23
|
+
'--section',
|
24
|
+
type=str,
|
25
|
+
choices=['overview', 'stats', 'system', 'commands', 'all'],
|
26
|
+
default='all',
|
27
|
+
help='Which section to render (default: all)'
|
28
|
+
)
|
29
|
+
parser.add_argument(
|
30
|
+
'--user',
|
31
|
+
type=str,
|
32
|
+
help='Username to use for request (default: first superuser)'
|
33
|
+
)
|
34
|
+
|
35
|
+
def handle(self, *args, **options):
|
36
|
+
# Create mock request
|
37
|
+
factory = RequestFactory()
|
38
|
+
request = factory.get('/admin/')
|
39
|
+
|
40
|
+
# Get user for request
|
41
|
+
User = get_user_model()
|
42
|
+
username = options.get('user')
|
43
|
+
|
44
|
+
if username:
|
45
|
+
try:
|
46
|
+
user = User.objects.get(username=username)
|
47
|
+
except User.DoesNotExist:
|
48
|
+
self.stdout.write(
|
49
|
+
self.style.ERROR(f"User '{username}' not found")
|
50
|
+
)
|
51
|
+
return
|
52
|
+
else:
|
53
|
+
# Use first superuser
|
54
|
+
user = User.objects.filter(is_superuser=True).first()
|
55
|
+
if not user:
|
56
|
+
self.stdout.write(
|
57
|
+
self.style.WARNING("No superuser found, using anonymous request")
|
58
|
+
)
|
59
|
+
|
60
|
+
if user:
|
61
|
+
request.user = user
|
62
|
+
self.stdout.write(f"Using user: {user.username}")
|
63
|
+
|
64
|
+
# Get debugger
|
65
|
+
debugger = get_debugger()
|
66
|
+
self.stdout.write(f"Saving renders to: {debugger.output_dir}")
|
67
|
+
|
68
|
+
section_choice = options['section']
|
69
|
+
sections = {
|
70
|
+
'overview': OverviewSection,
|
71
|
+
'stats': StatsSection,
|
72
|
+
'system': SystemSection,
|
73
|
+
'commands': CommandsSection,
|
74
|
+
}
|
75
|
+
|
76
|
+
if section_choice == 'all':
|
77
|
+
sections_to_render = sections.items()
|
78
|
+
else:
|
79
|
+
sections_to_render = [(section_choice, sections[section_choice])]
|
80
|
+
|
81
|
+
# Render sections
|
82
|
+
for name, SectionClass in sections_to_render:
|
83
|
+
self.stdout.write(f"\nRendering {name} section...")
|
84
|
+
|
85
|
+
try:
|
86
|
+
section = SectionClass(request)
|
87
|
+
html = section.render()
|
88
|
+
|
89
|
+
# Save render
|
90
|
+
path = debugger.save_section_render(
|
91
|
+
section_name=name,
|
92
|
+
html=html,
|
93
|
+
section_data=section.get_context_data() if hasattr(section, 'get_context_data') else None
|
94
|
+
)
|
95
|
+
|
96
|
+
self.stdout.write(
|
97
|
+
self.style.SUCCESS(f"✅ {name}: {len(html)} bytes, saved to {path.name}")
|
98
|
+
)
|
99
|
+
|
100
|
+
except Exception as e:
|
101
|
+
self.stdout.write(
|
102
|
+
self.style.ERROR(f"❌ {name}: {e}")
|
103
|
+
)
|
104
|
+
import traceback
|
105
|
+
traceback.print_exc()
|
106
|
+
|
107
|
+
self.stdout.write(
|
108
|
+
self.style.SUCCESS(f"\n✅ Done! Check renders in: {debugger.output_dir}")
|
109
|
+
)
|
@@ -0,0 +1 @@
|
|
1
|
+
"""Dashboard sections package."""
|