django-cfg 1.3.13__py3-none-any.whl → 1.4.3__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/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/agents/examples/__init__.py +3 -0
- django_cfg/apps/agents/examples/simple_example.py +161 -0
- 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/examples/__init__.py +3 -0
- django_cfg/apps/knowbase/examples/external_data_usage.py +191 -0
- 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/examples/vehicle_model_example.py +199 -0
- 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_currency/examples/__init__.py +3 -0
- django_cfg/modules/django_currency/examples/example_database_usage.py +144 -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_ipc_client/README.md +346 -0
- django_cfg/modules/django_ipc_client/__init__.py +51 -0
- django_cfg/modules/django_ipc_client/client.py +540 -0
- django_cfg/modules/django_ipc_client/config.py +207 -0
- django_cfg/modules/django_ipc_client/dashboard/README.md +517 -0
- django_cfg/modules/django_ipc_client/dashboard/UNFOLD_INTEGRATION.md +439 -0
- django_cfg/modules/django_ipc_client/dashboard/__init__.py +11 -0
- django_cfg/modules/django_ipc_client/dashboard/apps.py +22 -0
- django_cfg/modules/django_ipc_client/dashboard/monitor.py +435 -0
- django_cfg/modules/django_ipc_client/dashboard/static/django_ipc_dashboard/js/dashboard.js +373 -0
- django_cfg/modules/django_ipc_client/dashboard/templates/django_ipc_dashboard/base.html +76 -0
- django_cfg/modules/django_ipc_client/dashboard/templates/django_ipc_dashboard/dashboard.html +200 -0
- django_cfg/modules/django_ipc_client/dashboard/urls.py +22 -0
- django_cfg/modules/django_ipc_client/dashboard/urls_admin.py +9 -0
- django_cfg/modules/django_ipc_client/dashboard/views.py +251 -0
- django_cfg/modules/django_ipc_client/exceptions.py +201 -0
- 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/examples/component_class_example.html +156 -0
- 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.3.dist-info/METADATA +533 -0
- {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/RECORD +432 -195
- 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.13.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.13.dist-info → django_cfg-1.4.3.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,128 @@
|
|
1
|
+
"""
|
2
|
+
Base dashboard section classes.
|
3
|
+
|
4
|
+
Provides foundation for dashboard sections following Unfold's pattern.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from typing import Dict, Any, Optional
|
8
|
+
from django.http import HttpRequest
|
9
|
+
from django.template.loader import render_to_string
|
10
|
+
|
11
|
+
|
12
|
+
class DashboardSection:
|
13
|
+
"""
|
14
|
+
Base class for dashboard sections.
|
15
|
+
|
16
|
+
Each section is responsible for:
|
17
|
+
- Data collection
|
18
|
+
- Context preparation
|
19
|
+
- Template rendering
|
20
|
+
|
21
|
+
Usage:
|
22
|
+
class MySection(DashboardSection):
|
23
|
+
template_name = "admin/sections/my_section.html"
|
24
|
+
|
25
|
+
def get_context_data(self, **kwargs):
|
26
|
+
context = super().get_context_data(**kwargs)
|
27
|
+
context['custom_data'] = self.get_custom_data()
|
28
|
+
return context
|
29
|
+
"""
|
30
|
+
|
31
|
+
template_name: Optional[str] = None
|
32
|
+
title: Optional[str] = None
|
33
|
+
icon: Optional[str] = None
|
34
|
+
|
35
|
+
def __init__(self, request: HttpRequest) -> None:
|
36
|
+
"""Initialize section with request context."""
|
37
|
+
self.request = request
|
38
|
+
|
39
|
+
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
40
|
+
"""
|
41
|
+
Get context data for template rendering.
|
42
|
+
|
43
|
+
Override this method to add custom context.
|
44
|
+
"""
|
45
|
+
context = {
|
46
|
+
'request': self.request,
|
47
|
+
'section': self,
|
48
|
+
}
|
49
|
+
|
50
|
+
if self.title:
|
51
|
+
context['title'] = self.title
|
52
|
+
|
53
|
+
if self.icon:
|
54
|
+
context['icon'] = self.icon
|
55
|
+
|
56
|
+
context.update(kwargs)
|
57
|
+
return context
|
58
|
+
|
59
|
+
def render(self, **kwargs) -> str:
|
60
|
+
"""
|
61
|
+
Render the section template.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
**kwargs: Additional context to pass to template
|
65
|
+
|
66
|
+
Returns:
|
67
|
+
Rendered HTML string
|
68
|
+
"""
|
69
|
+
if not self.template_name:
|
70
|
+
raise NotImplementedError(
|
71
|
+
f"{self.__class__.__name__} must define 'template_name' or override render()"
|
72
|
+
)
|
73
|
+
|
74
|
+
context = self.get_context_data(**kwargs)
|
75
|
+
return render_to_string(self.template_name, context=context, request=self.request)
|
76
|
+
|
77
|
+
def __str__(self) -> str:
|
78
|
+
"""String representation."""
|
79
|
+
return self.title or self.__class__.__name__
|
80
|
+
|
81
|
+
|
82
|
+
class DataSection(DashboardSection):
|
83
|
+
"""
|
84
|
+
Section that provides data-driven content.
|
85
|
+
|
86
|
+
Extend this for sections that need to fetch and process data.
|
87
|
+
"""
|
88
|
+
|
89
|
+
def get_data(self) -> Any:
|
90
|
+
"""
|
91
|
+
Get section data.
|
92
|
+
|
93
|
+
Override this to provide section-specific data.
|
94
|
+
"""
|
95
|
+
raise NotImplementedError(
|
96
|
+
f"{self.__class__.__name__} must implement get_data()"
|
97
|
+
)
|
98
|
+
|
99
|
+
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
100
|
+
"""Add data to context."""
|
101
|
+
context = super().get_context_data(**kwargs)
|
102
|
+
context['data'] = self.get_data()
|
103
|
+
return context
|
104
|
+
|
105
|
+
|
106
|
+
class CardSection(DashboardSection):
|
107
|
+
"""
|
108
|
+
Section rendered as a card component.
|
109
|
+
|
110
|
+
Automatically wraps content in card template.
|
111
|
+
"""
|
112
|
+
|
113
|
+
template_name = "admin/components/card.html"
|
114
|
+
content_template: Optional[str] = None
|
115
|
+
|
116
|
+
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
117
|
+
"""Add card-specific context."""
|
118
|
+
context = super().get_context_data(**kwargs)
|
119
|
+
|
120
|
+
# Render content if content_template is provided
|
121
|
+
if self.content_template:
|
122
|
+
context['content'] = render_to_string(
|
123
|
+
self.content_template,
|
124
|
+
context=context,
|
125
|
+
request=self.request
|
126
|
+
)
|
127
|
+
|
128
|
+
return context
|
@@ -0,0 +1,32 @@
|
|
1
|
+
"""Commands section for dashboard."""
|
2
|
+
|
3
|
+
from typing import Dict, Any, List
|
4
|
+
from .base import DataSection
|
5
|
+
|
6
|
+
|
7
|
+
class CommandsSection(DataSection):
|
8
|
+
"""
|
9
|
+
Management commands section.
|
10
|
+
"""
|
11
|
+
|
12
|
+
template_name = "admin/sections/commands_section.html"
|
13
|
+
title = "Management Commands"
|
14
|
+
icon = "terminal"
|
15
|
+
|
16
|
+
def get_data(self) -> Dict[str, Any]:
|
17
|
+
"""Get commands data."""
|
18
|
+
from django_cfg.modules.django_unfold.callbacks.base import (
|
19
|
+
get_available_commands,
|
20
|
+
get_commands_by_category
|
21
|
+
)
|
22
|
+
|
23
|
+
commands = get_available_commands()
|
24
|
+
categorized = get_commands_by_category()
|
25
|
+
|
26
|
+
return {
|
27
|
+
'commands': commands,
|
28
|
+
'categories': categorized,
|
29
|
+
'total_commands': len(commands),
|
30
|
+
'core_commands': len([cmd for cmd in commands if cmd.get('is_core')]),
|
31
|
+
'custom_commands': len([cmd for cmd in commands if cmd.get('is_custom')]),
|
32
|
+
}
|
@@ -0,0 +1,394 @@
|
|
1
|
+
"""Overview section for dashboard."""
|
2
|
+
|
3
|
+
from typing import Dict, Any, List
|
4
|
+
from .base import DataSection
|
5
|
+
|
6
|
+
|
7
|
+
class OverviewSection(DataSection):
|
8
|
+
"""
|
9
|
+
Overview section showing key metrics and system status.
|
10
|
+
"""
|
11
|
+
|
12
|
+
template_name = "admin/sections/overview_section.html"
|
13
|
+
title = "System Overview"
|
14
|
+
icon = "dashboard"
|
15
|
+
|
16
|
+
def get_data(self) -> Dict[str, Any]:
|
17
|
+
"""Get overview data."""
|
18
|
+
from django_cfg.core.config import get_current_config
|
19
|
+
|
20
|
+
config = get_current_config()
|
21
|
+
|
22
|
+
return {
|
23
|
+
'stats': self.get_key_stats(),
|
24
|
+
'system_health': self.get_system_health(),
|
25
|
+
'recent_activity': self.get_recent_activity(),
|
26
|
+
}
|
27
|
+
|
28
|
+
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
29
|
+
"""Add additional context for includes."""
|
30
|
+
import json
|
31
|
+
from django.utils.safestring import mark_safe
|
32
|
+
|
33
|
+
context = super().get_context_data(**kwargs)
|
34
|
+
|
35
|
+
# Get time range from kwargs (default: 7 days)
|
36
|
+
time_range = kwargs.get('time_range', 7)
|
37
|
+
|
38
|
+
# Add data needed by included components
|
39
|
+
context['system_metrics'] = self.get_system_metrics()
|
40
|
+
context['recent_users'] = self.get_recent_users()
|
41
|
+
context['recent_users_table'] = self.get_recent_users_table()
|
42
|
+
|
43
|
+
# Convert activity tracker to JSON for JavaScript
|
44
|
+
activity_data = self.get_activity_tracker()
|
45
|
+
context['activity_tracker'] = mark_safe(json.dumps(activity_data))
|
46
|
+
|
47
|
+
context['charts'] = self.get_charts_data(days=time_range)
|
48
|
+
|
49
|
+
# Quick actions come from kwargs (passed from callbacks)
|
50
|
+
if 'quick_actions' in kwargs:
|
51
|
+
context['quick_actions'] = kwargs['quick_actions']
|
52
|
+
|
53
|
+
# Navigation for time range filter
|
54
|
+
if 'navigation' in kwargs:
|
55
|
+
context['navigation'] = kwargs['navigation']
|
56
|
+
|
57
|
+
return context
|
58
|
+
|
59
|
+
def get_key_stats(self) -> Dict[str, Any]:
|
60
|
+
"""Get key statistics."""
|
61
|
+
from django.contrib.auth import get_user_model
|
62
|
+
from django.db import connection
|
63
|
+
|
64
|
+
User = get_user_model()
|
65
|
+
|
66
|
+
# Get database count
|
67
|
+
db_count = len(connection.settings_dict.get('DATABASES', {})) if hasattr(connection, 'settings_dict') else 1
|
68
|
+
|
69
|
+
# Get app count
|
70
|
+
from django.apps import apps
|
71
|
+
app_count = len(apps.get_app_configs())
|
72
|
+
|
73
|
+
return {
|
74
|
+
'users': User.objects.count(),
|
75
|
+
'databases': db_count,
|
76
|
+
'apps': app_count,
|
77
|
+
}
|
78
|
+
|
79
|
+
def get_system_health(self) -> Dict[str, Any]:
|
80
|
+
"""Get system health metrics."""
|
81
|
+
import sys
|
82
|
+
import psutil
|
83
|
+
|
84
|
+
return {
|
85
|
+
'python_version': f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
|
86
|
+
'cpu_percent': psutil.cpu_percent(interval=0.1),
|
87
|
+
'memory_percent': psutil.virtual_memory().percent,
|
88
|
+
'disk_percent': psutil.disk_usage('/').percent,
|
89
|
+
}
|
90
|
+
|
91
|
+
def get_recent_activity(self) -> list:
|
92
|
+
"""Get recent activity items."""
|
93
|
+
# TODO: Implement activity tracking
|
94
|
+
return []
|
95
|
+
|
96
|
+
def get_system_metrics(self) -> Dict[str, Any]:
|
97
|
+
"""Get system metrics for progress bars."""
|
98
|
+
from django.db import connection
|
99
|
+
from django.core.cache import cache
|
100
|
+
|
101
|
+
metrics = {}
|
102
|
+
|
103
|
+
# Database metrics
|
104
|
+
try:
|
105
|
+
with connection.cursor() as cursor:
|
106
|
+
cursor.execute("SELECT 1")
|
107
|
+
metrics["database"] = {
|
108
|
+
"status": "healthy",
|
109
|
+
"type": connection.settings_dict.get('ENGINE', 'Unknown').split('.')[-1],
|
110
|
+
"health_percentage": 95,
|
111
|
+
"description": "Connection successful",
|
112
|
+
}
|
113
|
+
except Exception as e:
|
114
|
+
metrics["database"] = {
|
115
|
+
"status": "error",
|
116
|
+
"type": "Database",
|
117
|
+
"health_percentage": 0,
|
118
|
+
"description": f"Connection failed: {str(e)[:50]}",
|
119
|
+
}
|
120
|
+
|
121
|
+
# Cache metrics
|
122
|
+
try:
|
123
|
+
cache.set("health_check", "ok", 10)
|
124
|
+
cache_result = cache.get("health_check")
|
125
|
+
if cache_result == "ok":
|
126
|
+
metrics["cache"] = {
|
127
|
+
"status": "healthy",
|
128
|
+
"type": "Memory Cache",
|
129
|
+
"health_percentage": 90,
|
130
|
+
"description": "Cache working properly",
|
131
|
+
}
|
132
|
+
else:
|
133
|
+
metrics["cache"] = {
|
134
|
+
"status": "warning",
|
135
|
+
"type": "Memory Cache",
|
136
|
+
"health_percentage": 50,
|
137
|
+
"description": "Cache response delayed",
|
138
|
+
}
|
139
|
+
except Exception as e:
|
140
|
+
metrics["cache"] = {
|
141
|
+
"status": "error",
|
142
|
+
"type": "Memory Cache",
|
143
|
+
"health_percentage": 0,
|
144
|
+
"description": f"Cache error: {str(e)[:50]}",
|
145
|
+
}
|
146
|
+
|
147
|
+
# Storage metrics
|
148
|
+
try:
|
149
|
+
import shutil
|
150
|
+
total, used, free = shutil.disk_usage("/")
|
151
|
+
usage_percentage = (used / total) * 100
|
152
|
+
free_percentage = 100 - usage_percentage
|
153
|
+
|
154
|
+
# Status based on free space
|
155
|
+
if free_percentage > 20:
|
156
|
+
status = "healthy"
|
157
|
+
elif free_percentage > 10:
|
158
|
+
status = "warning"
|
159
|
+
else:
|
160
|
+
status = "error"
|
161
|
+
|
162
|
+
metrics["storage"] = {
|
163
|
+
"status": status,
|
164
|
+
"type": "Disk Space",
|
165
|
+
"health_percentage": int(free_percentage), # Show free space percentage
|
166
|
+
"description": f"{free_percentage:.1f}% free ({usage_percentage:.1f}% used)",
|
167
|
+
}
|
168
|
+
except Exception as e:
|
169
|
+
metrics["storage"] = {
|
170
|
+
"status": "error",
|
171
|
+
"type": "Disk Space",
|
172
|
+
"health_percentage": 0,
|
173
|
+
"description": f"Check failed: {str(e)[:50]}",
|
174
|
+
}
|
175
|
+
|
176
|
+
# API metrics
|
177
|
+
try:
|
178
|
+
from django.urls import get_resolver
|
179
|
+
resolver = get_resolver()
|
180
|
+
url_patterns = list(resolver.url_patterns)
|
181
|
+
|
182
|
+
metrics["api"] = {
|
183
|
+
"status": "healthy",
|
184
|
+
"type": "REST API",
|
185
|
+
"health_percentage": 100,
|
186
|
+
"description": f"{len(url_patterns)} URL patterns",
|
187
|
+
}
|
188
|
+
except Exception as e:
|
189
|
+
metrics["api"] = {
|
190
|
+
"status": "warning",
|
191
|
+
"type": "REST API",
|
192
|
+
"health_percentage": 50,
|
193
|
+
"description": "Unable to count URLs",
|
194
|
+
}
|
195
|
+
|
196
|
+
return metrics
|
197
|
+
|
198
|
+
def get_recent_users(self) -> List[Dict[str, Any]]:
|
199
|
+
"""Get recent users for activity section."""
|
200
|
+
from django.contrib.auth import get_user_model
|
201
|
+
|
202
|
+
User = get_user_model()
|
203
|
+
|
204
|
+
try:
|
205
|
+
recent_users = User.objects.order_by('-date_joined')[:5]
|
206
|
+
return list(recent_users.values(
|
207
|
+
'id', 'username', 'email', 'is_active', 'date_joined'
|
208
|
+
))
|
209
|
+
except Exception:
|
210
|
+
return []
|
211
|
+
|
212
|
+
def get_recent_users_table(self) -> Dict[str, Any]:
|
213
|
+
"""Get recent users in table format for Unfold table component."""
|
214
|
+
from django.contrib.auth import get_user_model
|
215
|
+
|
216
|
+
User = get_user_model()
|
217
|
+
|
218
|
+
try:
|
219
|
+
recent_users = User.objects.order_by('-date_joined')[:10]
|
220
|
+
|
221
|
+
return {
|
222
|
+
"headers": ["Username", "Email", "Status", "Staff", "Joined"],
|
223
|
+
"rows": [
|
224
|
+
[
|
225
|
+
user.username,
|
226
|
+
user.email,
|
227
|
+
"✅ Active" if user.is_active else "❌ Inactive",
|
228
|
+
"🛡️ Yes" if user.is_staff else "—",
|
229
|
+
user.date_joined.strftime('%Y-%m-%d %H:%M')
|
230
|
+
]
|
231
|
+
for user in recent_users
|
232
|
+
]
|
233
|
+
}
|
234
|
+
except Exception:
|
235
|
+
return {"headers": [], "rows": []}
|
236
|
+
|
237
|
+
def get_activity_tracker(self) -> List[Dict[str, Any]]:
|
238
|
+
"""
|
239
|
+
Get activity tracker data for GitHub-style heatmap.
|
240
|
+
|
241
|
+
Returns list of dicts with date and count for last 365 days.
|
242
|
+
"""
|
243
|
+
from django.contrib.auth import get_user_model
|
244
|
+
from datetime import datetime, timedelta
|
245
|
+
from django.utils import timezone
|
246
|
+
|
247
|
+
User = get_user_model()
|
248
|
+
|
249
|
+
try:
|
250
|
+
# Get activity for last 365 days
|
251
|
+
today = timezone.now().date()
|
252
|
+
activity_data = []
|
253
|
+
|
254
|
+
for days_ago in range(364, -1, -1): # 365 days, newest last
|
255
|
+
date = today - timedelta(days=days_ago)
|
256
|
+
|
257
|
+
# Count user registrations on this day
|
258
|
+
registrations = User.objects.filter(
|
259
|
+
date_joined__date=date
|
260
|
+
).count()
|
261
|
+
|
262
|
+
# Count logins on this day (if last_login exists)
|
263
|
+
logins = 0
|
264
|
+
if hasattr(User, 'last_login'):
|
265
|
+
logins = User.objects.filter(
|
266
|
+
last_login__date=date
|
267
|
+
).count()
|
268
|
+
|
269
|
+
# Total activity for the day
|
270
|
+
total_activity = registrations + logins
|
271
|
+
|
272
|
+
activity_data.append({
|
273
|
+
'date': date.isoformat(),
|
274
|
+
'count': total_activity,
|
275
|
+
'level': self._get_activity_level(total_activity),
|
276
|
+
})
|
277
|
+
|
278
|
+
return activity_data
|
279
|
+
|
280
|
+
except Exception as e:
|
281
|
+
# Return empty on error
|
282
|
+
return []
|
283
|
+
|
284
|
+
def _get_activity_level(self, count: int) -> int:
|
285
|
+
"""
|
286
|
+
Convert activity count to level (0-4) for heatmap colors.
|
287
|
+
|
288
|
+
0 = no activity (gray)
|
289
|
+
1 = low (light green)
|
290
|
+
2 = medium (green)
|
291
|
+
3 = high (dark green)
|
292
|
+
4 = very high (darkest green)
|
293
|
+
"""
|
294
|
+
if count == 0:
|
295
|
+
return 0
|
296
|
+
elif count <= 2:
|
297
|
+
return 1
|
298
|
+
elif count <= 5:
|
299
|
+
return 2
|
300
|
+
elif count <= 10:
|
301
|
+
return 3
|
302
|
+
else:
|
303
|
+
return 4
|
304
|
+
|
305
|
+
def get_charts_data(self, days: int = 7) -> Dict[str, Any]:
|
306
|
+
"""Get charts data for Analytics Overview.
|
307
|
+
|
308
|
+
Args:
|
309
|
+
days: Number of days to include in charts (default: 7)
|
310
|
+
"""
|
311
|
+
from django.contrib.auth import get_user_model
|
312
|
+
from datetime import datetime, timedelta
|
313
|
+
from django.utils import timezone
|
314
|
+
from django.utils.safestring import mark_safe
|
315
|
+
import json
|
316
|
+
|
317
|
+
User = get_user_model()
|
318
|
+
|
319
|
+
try:
|
320
|
+
# Get last N days of user registrations
|
321
|
+
today = timezone.now().date()
|
322
|
+
dates = [(today - timedelta(days=i)).strftime('%Y-%m-%d') for i in range(days-1, -1, -1)]
|
323
|
+
|
324
|
+
# Count users registered each day
|
325
|
+
registrations = []
|
326
|
+
for date_str in dates:
|
327
|
+
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
|
328
|
+
count = User.objects.filter(
|
329
|
+
date_joined__date=date_obj
|
330
|
+
).count()
|
331
|
+
registrations.append(count)
|
332
|
+
|
333
|
+
# Count active users each day (last login)
|
334
|
+
activity = []
|
335
|
+
for date_str in dates:
|
336
|
+
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
|
337
|
+
# Count users who logged in that day
|
338
|
+
count = User.objects.filter(
|
339
|
+
last_login__date=date_obj
|
340
|
+
).count() if hasattr(User, 'last_login') else 0
|
341
|
+
activity.append(count)
|
342
|
+
|
343
|
+
# Format for charts
|
344
|
+
day_labels = [d.split('-')[2] for d in dates] # Just day numbers
|
345
|
+
|
346
|
+
# Prepare chart data structures
|
347
|
+
user_reg_data = {
|
348
|
+
'labels': day_labels,
|
349
|
+
'datasets': [{
|
350
|
+
'label': 'New Users',
|
351
|
+
'data': registrations,
|
352
|
+
'backgroundColor': 'rgba(59, 130, 246, 0.5)',
|
353
|
+
'borderColor': 'rgb(59, 130, 246)',
|
354
|
+
'borderWidth': 2,
|
355
|
+
}]
|
356
|
+
}
|
357
|
+
|
358
|
+
user_activity_data = {
|
359
|
+
'labels': day_labels,
|
360
|
+
'datasets': [{
|
361
|
+
'label': 'Active Users',
|
362
|
+
'data': activity,
|
363
|
+
'backgroundColor': 'rgba(34, 197, 94, 0.5)',
|
364
|
+
'borderColor': 'rgb(34, 197, 94)',
|
365
|
+
'borderWidth': 2,
|
366
|
+
}]
|
367
|
+
}
|
368
|
+
|
369
|
+
return {
|
370
|
+
# User Registrations chart
|
371
|
+
'user_registrations': {
|
372
|
+
'labels': day_labels,
|
373
|
+
'datasets': [{
|
374
|
+
'label': 'New Users',
|
375
|
+
'data': registrations,
|
376
|
+
}]
|
377
|
+
},
|
378
|
+
# JSON string for Unfold chart component (NO mark_safe - let Django escape quotes)
|
379
|
+
'user_registrations_json': json.dumps(user_reg_data),
|
380
|
+
|
381
|
+
# User Activity chart
|
382
|
+
'user_activity': {
|
383
|
+
'labels': day_labels,
|
384
|
+
'datasets': [{
|
385
|
+
'label': 'Active Users',
|
386
|
+
'data': activity,
|
387
|
+
}]
|
388
|
+
},
|
389
|
+
# JSON string for Unfold chart component (NO mark_safe - let Django escape quotes)
|
390
|
+
'user_activity_json': json.dumps(user_activity_data),
|
391
|
+
}
|
392
|
+
except Exception as e:
|
393
|
+
# Return empty chart data
|
394
|
+
return {}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
"""Statistics section for dashboard."""
|
2
|
+
|
3
|
+
from typing import Dict, Any, List
|
4
|
+
from .base import DataSection
|
5
|
+
|
6
|
+
|
7
|
+
class StatsSection(DataSection):
|
8
|
+
"""
|
9
|
+
Statistics section showing detailed metrics.
|
10
|
+
"""
|
11
|
+
|
12
|
+
template_name = "admin/sections/stats_section.html"
|
13
|
+
title = "Statistics"
|
14
|
+
icon = "analytics"
|
15
|
+
|
16
|
+
def get_data(self) -> Dict[str, Any]:
|
17
|
+
"""Get statistics data."""
|
18
|
+
return {
|
19
|
+
'app_stats': self.get_app_stats(),
|
20
|
+
'time_series': self.get_time_series(),
|
21
|
+
}
|
22
|
+
|
23
|
+
def get_app_stats(self) -> List[Dict[str, Any]]:
|
24
|
+
"""Get per-app statistics."""
|
25
|
+
from django.apps import apps
|
26
|
+
from django.contrib.contenttypes.models import ContentType
|
27
|
+
|
28
|
+
stats = []
|
29
|
+
|
30
|
+
for app_config in apps.get_app_configs():
|
31
|
+
if app_config.name.startswith('django.'):
|
32
|
+
continue
|
33
|
+
|
34
|
+
# Count models in app
|
35
|
+
models = [m for m in apps.get_models() if m._meta.app_label == app_config.label]
|
36
|
+
|
37
|
+
stats.append({
|
38
|
+
'name': app_config.verbose_name,
|
39
|
+
'label': app_config.label,
|
40
|
+
'models_count': len(models),
|
41
|
+
})
|
42
|
+
|
43
|
+
return stats
|
44
|
+
|
45
|
+
def get_time_series(self) -> Dict[str, Any]:
|
46
|
+
"""Get time series data for charts."""
|
47
|
+
# TODO: Implement time series data
|
48
|
+
return {}
|
@@ -0,0 +1,73 @@
|
|
1
|
+
"""System section for dashboard."""
|
2
|
+
|
3
|
+
from typing import Dict, Any
|
4
|
+
from .base import DataSection
|
5
|
+
|
6
|
+
|
7
|
+
class SystemSection(DataSection):
|
8
|
+
"""
|
9
|
+
System management section.
|
10
|
+
"""
|
11
|
+
|
12
|
+
template_name = "admin/sections/system_section.html"
|
13
|
+
title = "System Management"
|
14
|
+
icon = "settings"
|
15
|
+
|
16
|
+
def get_data(self) -> Dict[str, Any]:
|
17
|
+
"""Get system data."""
|
18
|
+
return {
|
19
|
+
'health': self.get_health_check(),
|
20
|
+
'services': self.get_services_status(),
|
21
|
+
'configuration': self.get_configuration(),
|
22
|
+
}
|
23
|
+
|
24
|
+
def get_health_check(self) -> Dict[str, Any]:
|
25
|
+
"""Get health check status."""
|
26
|
+
import psutil
|
27
|
+
|
28
|
+
return {
|
29
|
+
'status': 'healthy',
|
30
|
+
'checks': {
|
31
|
+
'database': self.check_database(),
|
32
|
+
'cache': self.check_cache(),
|
33
|
+
'disk_space': psutil.disk_usage('/').percent < 90,
|
34
|
+
'memory': psutil.virtual_memory().percent < 90,
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
def check_database(self) -> bool:
|
39
|
+
"""Check database connectivity."""
|
40
|
+
from django.db import connection
|
41
|
+
|
42
|
+
try:
|
43
|
+
connection.ensure_connection()
|
44
|
+
return True
|
45
|
+
except Exception:
|
46
|
+
return False
|
47
|
+
|
48
|
+
def check_cache(self) -> bool:
|
49
|
+
"""Check cache availability."""
|
50
|
+
from django.core.cache import cache
|
51
|
+
|
52
|
+
try:
|
53
|
+
cache.set('health_check', True, 1)
|
54
|
+
return cache.get('health_check') is True
|
55
|
+
except Exception:
|
56
|
+
return False
|
57
|
+
|
58
|
+
def get_services_status(self) -> Dict[str, Any]:
|
59
|
+
"""Get services status."""
|
60
|
+
# TODO: Implement services status check
|
61
|
+
return {}
|
62
|
+
|
63
|
+
def get_configuration(self) -> Dict[str, Any]:
|
64
|
+
"""Get system configuration."""
|
65
|
+
from django_cfg.core.config import get_current_config
|
66
|
+
|
67
|
+
config = get_current_config()
|
68
|
+
|
69
|
+
return {
|
70
|
+
'debug': config.debug,
|
71
|
+
'env_mode': config.env_mode,
|
72
|
+
'project_name': config.project_name,
|
73
|
+
}
|