django-cfg 1.3.7__py3-none-any.whl ā 1.3.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/admin/__init__.py +24 -8
- django_cfg/apps/accounts/admin/activity_admin.py +146 -0
- django_cfg/apps/accounts/admin/filters.py +98 -22
- django_cfg/apps/accounts/admin/group_admin.py +86 -0
- django_cfg/apps/accounts/admin/inlines.py +42 -13
- django_cfg/apps/accounts/admin/otp_admin.py +115 -0
- django_cfg/apps/accounts/admin/registration_admin.py +173 -0
- django_cfg/apps/accounts/admin/resources.py +123 -19
- django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
- django_cfg/apps/accounts/admin/user_admin.py +362 -0
- django_cfg/apps/agents/admin/__init__.py +17 -4
- django_cfg/apps/agents/admin/execution_admin.py +204 -183
- django_cfg/apps/agents/admin/registry_admin.py +230 -255
- django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
- django_cfg/apps/agents/core/__init__.py +1 -1
- django_cfg/apps/agents/core/django_agent.py +221 -0
- django_cfg/apps/agents/core/exceptions.py +14 -0
- django_cfg/apps/agents/core/orchestrator.py +18 -3
- django_cfg/apps/knowbase/admin/__init__.py +1 -1
- django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
- django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
- django_cfg/apps/knowbase/admin/document_admin.py +269 -262
- django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
- django_cfg/apps/knowbase/config/settings.py +21 -4
- django_cfg/apps/knowbase/views/chat_views.py +3 -0
- django_cfg/apps/leads/admin/__init__.py +3 -1
- django_cfg/apps/leads/admin/leads_admin.py +235 -35
- django_cfg/apps/maintenance/admin/__init__.py +2 -2
- django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
- django_cfg/apps/maintenance/admin/log_admin.py +143 -61
- django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
- django_cfg/apps/maintenance/admin/site_admin.py +213 -352
- django_cfg/apps/newsletter/admin/__init__.py +29 -2
- django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
- django_cfg/apps/payments/admin/__init__.py +18 -27
- django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
- django_cfg/apps/payments/admin/balance_admin.py +166 -632
- django_cfg/apps/payments/admin/currencies_admin.py +235 -607
- django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
- django_cfg/apps/payments/admin/filters.py +83 -3
- django_cfg/apps/payments/admin/networks_admin.py +258 -0
- django_cfg/apps/payments/admin/payments_admin.py +171 -461
- django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
- django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +105 -34
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +12 -16
- django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +13 -18
- django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
- django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
- django_cfg/apps/payments/middleware/api_access.py +32 -6
- django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +26 -0
- django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +28 -0
- django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +30 -0
- django_cfg/apps/payments/models/balance.py +12 -0
- django_cfg/apps/payments/models/currencies.py +106 -32
- django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
- django_cfg/apps/payments/services/core/currency_service.py +35 -28
- django_cfg/apps/payments/services/core/payment_service.py +1 -1
- django_cfg/apps/payments/services/providers/__init__.py +3 -0
- django_cfg/apps/payments/services/providers/base.py +95 -39
- django_cfg/apps/payments/services/providers/models/__init__.py +40 -0
- django_cfg/apps/payments/services/providers/models/base.py +122 -0
- django_cfg/apps/payments/services/providers/models/providers.py +87 -0
- django_cfg/apps/payments/services/providers/models/universal.py +48 -0
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
- django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
- django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
- django_cfg/apps/payments/services/providers/{nowpayments.py ā nowpayments/provider.py} +240 -209
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
- django_cfg/apps/payments/services/providers/registry.py +4 -32
- django_cfg/apps/payments/services/providers/sync_service.py +277 -0
- django_cfg/apps/payments/static/payments/js/api-client.js +23 -5
- django_cfg/apps/payments/static/payments/js/payment-form.js +65 -8
- django_cfg/apps/payments/tasks/__init__.py +39 -0
- django_cfg/apps/payments/tasks/types.py +73 -0
- django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
- django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
- django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
- django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
- django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
- django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
- django_cfg/apps/payments/urls_admin.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +5 -5
- django_cfg/apps/payments/views/overview/services.py +2 -2
- django_cfg/apps/payments/views/serializers/currencies.py +4 -3
- django_cfg/apps/support/admin/__init__.py +10 -1
- django_cfg/apps/support/admin/support_admin.py +338 -141
- django_cfg/apps/tasks/admin/__init__.py +11 -0
- django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +10 -5
- django_cfg/core/generation.py +1 -1
- django_cfg/management/commands/__init__.py +13 -1
- django_cfg/management/commands/app_agent_diagnose.py +470 -0
- django_cfg/management/commands/app_agent_generate.py +342 -0
- django_cfg/management/commands/app_agent_info.py +308 -0
- django_cfg/management/commands/migrate_all.py +9 -3
- django_cfg/management/commands/migrator.py +11 -6
- django_cfg/management/commands/rundramatiq.py +3 -2
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/models/api_keys.py +115 -0
- django_cfg/modules/django_admin/__init__.py +64 -0
- django_cfg/modules/django_admin/decorators/__init__.py +13 -0
- django_cfg/modules/django_admin/decorators/actions.py +106 -0
- django_cfg/modules/django_admin/decorators/display.py +106 -0
- django_cfg/modules/django_admin/mixins/__init__.py +14 -0
- django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
- django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
- django_cfg/modules/django_admin/models/__init__.py +20 -0
- django_cfg/modules/django_admin/models/action_models.py +33 -0
- django_cfg/modules/django_admin/models/badge_models.py +20 -0
- django_cfg/modules/django_admin/models/base.py +26 -0
- django_cfg/modules/django_admin/models/display_models.py +31 -0
- django_cfg/modules/django_admin/utils/badges.py +159 -0
- django_cfg/modules/django_admin/utils/displays.py +247 -0
- django_cfg/modules/django_app_agent/__init__.py +87 -0
- django_cfg/modules/django_app_agent/agents/__init__.py +40 -0
- django_cfg/modules/django_app_agent/agents/base/__init__.py +24 -0
- django_cfg/modules/django_app_agent/agents/base/agent.py +354 -0
- django_cfg/modules/django_app_agent/agents/base/context.py +236 -0
- django_cfg/modules/django_app_agent/agents/base/executor.py +430 -0
- django_cfg/modules/django_app_agent/agents/generation/__init__.py +12 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +15 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +147 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +99 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +32 -0
- django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +290 -0
- django_cfg/modules/django_app_agent/agents/interfaces.py +376 -0
- django_cfg/modules/django_app_agent/core/__init__.py +33 -0
- django_cfg/modules/django_app_agent/core/config.py +300 -0
- django_cfg/modules/django_app_agent/core/exceptions.py +359 -0
- django_cfg/modules/django_app_agent/models/__init__.py +71 -0
- django_cfg/modules/django_app_agent/models/base.py +283 -0
- django_cfg/modules/django_app_agent/models/context.py +496 -0
- django_cfg/modules/django_app_agent/models/enums.py +481 -0
- django_cfg/modules/django_app_agent/models/requests.py +500 -0
- django_cfg/modules/django_app_agent/models/responses.py +585 -0
- django_cfg/modules/django_app_agent/pytest.ini +6 -0
- django_cfg/modules/django_app_agent/services/__init__.py +42 -0
- django_cfg/modules/django_app_agent/services/app_generator/__init__.py +30 -0
- django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +133 -0
- django_cfg/modules/django_app_agent/services/app_generator/context.py +40 -0
- django_cfg/modules/django_app_agent/services/app_generator/main.py +202 -0
- django_cfg/modules/django_app_agent/services/app_generator/structure.py +316 -0
- django_cfg/modules/django_app_agent/services/app_generator/validation.py +125 -0
- django_cfg/modules/django_app_agent/services/base.py +437 -0
- django_cfg/modules/django_app_agent/services/context_builder/__init__.py +34 -0
- django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +141 -0
- django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +276 -0
- django_cfg/modules/django_app_agent/services/context_builder/main.py +272 -0
- django_cfg/modules/django_app_agent/services/context_builder/models.py +40 -0
- django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +85 -0
- django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +31 -0
- django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +311 -0
- django_cfg/modules/django_app_agent/services/project_scanner/main.py +221 -0
- django_cfg/modules/django_app_agent/services/project_scanner/models.py +59 -0
- django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +94 -0
- django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +28 -0
- django_cfg/modules/django_app_agent/services/questioning_service/main.py +273 -0
- django_cfg/modules/django_app_agent/services/questioning_service/models.py +111 -0
- django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +251 -0
- django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +347 -0
- django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +356 -0
- django_cfg/modules/django_app_agent/services/report_service.py +332 -0
- django_cfg/modules/django_app_agent/services/template_manager/__init__.py +18 -0
- django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +236 -0
- django_cfg/modules/django_app_agent/services/template_manager/main.py +159 -0
- django_cfg/modules/django_app_agent/services/template_manager/models.py +36 -0
- django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +100 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +105 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +31 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +44 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +81 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +107 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +139 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +91 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +195 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +35 -0
- django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +211 -0
- django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +200 -0
- django_cfg/modules/django_app_agent/services/validation_service/__init__.py +25 -0
- django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +333 -0
- django_cfg/modules/django_app_agent/services/validation_service/main.py +242 -0
- django_cfg/modules/django_app_agent/services/validation_service/models.py +66 -0
- django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +352 -0
- django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +272 -0
- django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +203 -0
- django_cfg/modules/django_app_agent/ui/__init__.py +25 -0
- django_cfg/modules/django_app_agent/ui/cli.py +419 -0
- django_cfg/modules/django_app_agent/ui/rich_components.py +622 -0
- django_cfg/modules/django_app_agent/utils/__init__.py +38 -0
- django_cfg/modules/django_app_agent/utils/logging.py +360 -0
- django_cfg/modules/django_app_agent/utils/validation.py +417 -0
- django_cfg/modules/django_currency/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
- django_cfg/modules/django_currency/core/converter.py +12 -12
- django_cfg/modules/django_currency/database/__init__.py +2 -2
- django_cfg/modules/django_currency/database/database_loader.py +93 -42
- django_cfg/modules/django_llm/llm/client.py +10 -2
- django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
- django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
- django_cfg/modules/django_unfold/dashboard.py +14 -13
- django_cfg/modules/django_unfold/models/config.py +1 -1
- django_cfg/registry/core.py +3 -0
- django_cfg/registry/third_party.py +2 -2
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.7.dist-info ā django_cfg-1.3.9.dist-info}/METADATA +2 -1
- {django_cfg-1.3.7.dist-info ā django_cfg-1.3.9.dist-info}/RECORD +223 -117
- django_cfg/apps/accounts/admin/activity.py +0 -96
- django_cfg/apps/accounts/admin/group.py +0 -17
- django_cfg/apps/accounts/admin/otp.py +0 -59
- django_cfg/apps/accounts/admin/registration_source.py +0 -97
- django_cfg/apps/accounts/admin/twilio_response.py +0 -227
- django_cfg/apps/accounts/admin/user.py +0 -300
- django_cfg/apps/agents/core/agent.py +0 -281
- django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
- django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
- django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
- django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
- django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
- django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
- django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
- django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
- django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
- django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
- django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
- django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
- django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
- django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
- django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
- django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
- django_cfg/apps/tasks/admin.py +0 -320
- django_cfg/middleware/static_nocache.py +0 -55
- django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
- /django_cfg/modules/{django_unfold ā django_admin}/icons/README.md +0 -0
- /django_cfg/modules/{django_unfold ā django_admin}/icons/__init__.py +0 -0
- /django_cfg/modules/{django_unfold ā django_admin}/icons/constants.py +0 -0
- /django_cfg/modules/{django_unfold ā django_admin}/icons/generate_icons.py +0 -0
- {django_cfg-1.3.7.dist-info ā django_cfg-1.3.9.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.7.dist-info ā django_cfg-1.3.9.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.7.dist-info ā django_cfg-1.3.9.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,470 @@
|
|
1
|
+
"""
|
2
|
+
Django management command for project diagnosis.
|
3
|
+
|
4
|
+
This command provides AI-powered diagnosis of Django/Django-cfg projects
|
5
|
+
to help identify and solve common problems.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
import sys
|
10
|
+
from pathlib import Path
|
11
|
+
from typing import List, Optional
|
12
|
+
|
13
|
+
from django.core.management.base import BaseCommand, CommandError
|
14
|
+
from django.conf import settings
|
15
|
+
|
16
|
+
try:
|
17
|
+
from django_cfg.modules.django_app_agent.services import (
|
18
|
+
ProjectScannerService,
|
19
|
+
ContextBuilderService
|
20
|
+
)
|
21
|
+
from django_cfg.modules.django_app_agent.models.requests import (
|
22
|
+
ProjectScanRequest,
|
23
|
+
ContextBuildRequest
|
24
|
+
)
|
25
|
+
from django_cfg.modules.django_app_agent.core.exceptions import DjangoAppAgentError
|
26
|
+
from django_cfg.modules.django_app_agent.core.config import AgentConfig
|
27
|
+
from django_cfg.modules.django_app_agent.utils.logging import get_logger
|
28
|
+
from django_cfg.modules.django_app_agent.ui.rich_components import (
|
29
|
+
RichProgressTracker,
|
30
|
+
InteractiveQuestioningUI
|
31
|
+
)
|
32
|
+
except ImportError as e:
|
33
|
+
print(f"Error importing django_app_agent module: {e}")
|
34
|
+
print("Make sure the django_app_agent module is properly installed.")
|
35
|
+
sys.exit(1)
|
36
|
+
|
37
|
+
|
38
|
+
class Command(BaseCommand):
|
39
|
+
"""Django management command for project diagnosis."""
|
40
|
+
|
41
|
+
help = "Diagnose problems in Django/Django-cfg projects using AI (Django App Agent)"
|
42
|
+
|
43
|
+
def add_arguments(self, parser):
|
44
|
+
"""Add command line arguments."""
|
45
|
+
|
46
|
+
parser.add_argument(
|
47
|
+
'--app',
|
48
|
+
type=str,
|
49
|
+
help='Specific application name to diagnose'
|
50
|
+
)
|
51
|
+
|
52
|
+
parser.add_argument(
|
53
|
+
'--category',
|
54
|
+
choices=[
|
55
|
+
'database', 'views', 'templates', 'static',
|
56
|
+
'admin', 'auth', 'performance', 'deployment',
|
57
|
+
'config', 'security', 'testing', 'other'
|
58
|
+
],
|
59
|
+
help='Problem category to focus on'
|
60
|
+
)
|
61
|
+
|
62
|
+
parser.add_argument(
|
63
|
+
'--description',
|
64
|
+
type=str,
|
65
|
+
help='Description of the problem you are experiencing'
|
66
|
+
)
|
67
|
+
|
68
|
+
parser.add_argument(
|
69
|
+
'--severity',
|
70
|
+
choices=['low', 'medium', 'high', 'critical'],
|
71
|
+
default='medium',
|
72
|
+
help='Problem severity level (default: medium)'
|
73
|
+
)
|
74
|
+
|
75
|
+
parser.add_argument(
|
76
|
+
'--interactive',
|
77
|
+
action='store_true',
|
78
|
+
default=True,
|
79
|
+
help='Enable interactive diagnosis mode (default: True)'
|
80
|
+
)
|
81
|
+
|
82
|
+
parser.add_argument(
|
83
|
+
'--non-interactive',
|
84
|
+
action='store_true',
|
85
|
+
help='Disable interactive mode'
|
86
|
+
)
|
87
|
+
|
88
|
+
parser.add_argument(
|
89
|
+
'--scan-only',
|
90
|
+
action='store_true',
|
91
|
+
help='Only scan the project without AI diagnosis'
|
92
|
+
)
|
93
|
+
|
94
|
+
parser.add_argument(
|
95
|
+
'--output-format',
|
96
|
+
choices=['text', 'json', 'markdown'],
|
97
|
+
default='text',
|
98
|
+
help='Output format for diagnosis results (default: text)'
|
99
|
+
)
|
100
|
+
|
101
|
+
parser.add_argument(
|
102
|
+
'--save-report',
|
103
|
+
type=str,
|
104
|
+
help='Save diagnosis report to specified file'
|
105
|
+
)
|
106
|
+
|
107
|
+
parser.add_argument(
|
108
|
+
'--verbose',
|
109
|
+
action='store_true',
|
110
|
+
help='Enable verbose output'
|
111
|
+
)
|
112
|
+
|
113
|
+
def handle(self, *args, **options):
|
114
|
+
"""Handle the command execution."""
|
115
|
+
|
116
|
+
try:
|
117
|
+
# Initialize logger
|
118
|
+
logger = get_logger("management.commands.diagnose_project")
|
119
|
+
|
120
|
+
# Determine interactive mode
|
121
|
+
interactive = options.get('interactive', True) and not options.get('non_interactive', False)
|
122
|
+
|
123
|
+
# Show welcome message
|
124
|
+
self.stdout.write(
|
125
|
+
self.style.SUCCESS("š Django Project Diagnostic Tool")
|
126
|
+
)
|
127
|
+
self.stdout.write("Analyzing your project for potential issues...\n")
|
128
|
+
|
129
|
+
# Run diagnosis
|
130
|
+
if interactive and not options.get('description'):
|
131
|
+
return self._run_interactive_diagnosis(options)
|
132
|
+
else:
|
133
|
+
return self._run_direct_diagnosis(options)
|
134
|
+
|
135
|
+
except DjangoAppAgentError as e:
|
136
|
+
logger.error(f"Diagnosis failed: {e}")
|
137
|
+
raise CommandError(f"Diagnosis failed: {e}")
|
138
|
+
except Exception as e:
|
139
|
+
logger.error(f"Unexpected error: {e}")
|
140
|
+
raise CommandError(f"Unexpected error: {e}")
|
141
|
+
|
142
|
+
def _run_interactive_diagnosis(self, options):
|
143
|
+
"""Run interactive diagnosis with user prompts."""
|
144
|
+
try:
|
145
|
+
self.stdout.write("š¤ Starting interactive diagnosis...\n")
|
146
|
+
|
147
|
+
# Gather information interactively
|
148
|
+
problem_info = self._gather_problem_info()
|
149
|
+
|
150
|
+
# Merge with command line options
|
151
|
+
diagnosis_options = {**options, **problem_info}
|
152
|
+
|
153
|
+
# Run diagnosis
|
154
|
+
return self._run_diagnosis_process(diagnosis_options)
|
155
|
+
|
156
|
+
except KeyboardInterrupt:
|
157
|
+
self.stdout.write("\nš Diagnosis cancelled by user")
|
158
|
+
except Exception as e:
|
159
|
+
raise CommandError(f"Interactive diagnosis failed: {e}")
|
160
|
+
|
161
|
+
def _run_direct_diagnosis(self, options):
|
162
|
+
"""Run diagnosis with provided parameters."""
|
163
|
+
return self._run_diagnosis_process(options)
|
164
|
+
|
165
|
+
def _gather_problem_info(self):
|
166
|
+
"""Gather problem information interactively."""
|
167
|
+
problem_info = {}
|
168
|
+
|
169
|
+
# Ask for problem description
|
170
|
+
self.stdout.write("š Please describe the problem you're experiencing:")
|
171
|
+
description = input("Description: ").strip()
|
172
|
+
if description:
|
173
|
+
problem_info['description'] = description
|
174
|
+
|
175
|
+
# Ask for category
|
176
|
+
self.stdout.write("\nš What category best describes your problem?")
|
177
|
+
categories = [
|
178
|
+
'database', 'views', 'templates', 'static',
|
179
|
+
'admin', 'auth', 'performance', 'deployment',
|
180
|
+
'config', 'security', 'testing', 'other'
|
181
|
+
]
|
182
|
+
|
183
|
+
for i, category in enumerate(categories, 1):
|
184
|
+
self.stdout.write(f" {i}. {category}")
|
185
|
+
|
186
|
+
try:
|
187
|
+
choice = input("\nEnter number (or press Enter to skip): ").strip()
|
188
|
+
if choice and choice.isdigit():
|
189
|
+
idx = int(choice) - 1
|
190
|
+
if 0 <= idx < len(categories):
|
191
|
+
problem_info['category'] = categories[idx]
|
192
|
+
except (ValueError, IndexError):
|
193
|
+
pass
|
194
|
+
|
195
|
+
# Ask for specific app
|
196
|
+
self.stdout.write("\nšÆ Is this problem specific to a particular app?")
|
197
|
+
app_name = input("App name (or press Enter to skip): ").strip()
|
198
|
+
if app_name:
|
199
|
+
problem_info['app'] = app_name
|
200
|
+
|
201
|
+
# Ask for severity
|
202
|
+
self.stdout.write("\nā ļø How severe is this problem?")
|
203
|
+
severities = ['low', 'medium', 'high', 'critical']
|
204
|
+
for i, severity in enumerate(severities, 1):
|
205
|
+
self.stdout.write(f" {i}. {severity}")
|
206
|
+
|
207
|
+
try:
|
208
|
+
choice = input("\nEnter number (default: 2 for medium): ").strip()
|
209
|
+
if choice and choice.isdigit():
|
210
|
+
idx = int(choice) - 1
|
211
|
+
if 0 <= idx < len(severities):
|
212
|
+
problem_info['severity'] = severities[idx]
|
213
|
+
else:
|
214
|
+
problem_info['severity'] = 'medium'
|
215
|
+
except (ValueError, IndexError):
|
216
|
+
problem_info['severity'] = 'medium'
|
217
|
+
|
218
|
+
return problem_info
|
219
|
+
|
220
|
+
def _run_diagnosis_process(self, options):
|
221
|
+
"""Run the actual diagnosis process."""
|
222
|
+
try:
|
223
|
+
# Initialize configuration
|
224
|
+
config = AgentConfig()
|
225
|
+
logger = get_logger("management.commands.diagnose_project")
|
226
|
+
|
227
|
+
# Show current configuration
|
228
|
+
if options.get('verbose'):
|
229
|
+
self.stdout.write(f"š§ Project root: {settings.BASE_DIR}")
|
230
|
+
if options.get('app'):
|
231
|
+
self.stdout.write(f"šÆ Target app: {options['app']}")
|
232
|
+
if options.get('category'):
|
233
|
+
self.stdout.write(f"š Category: {options['category']}")
|
234
|
+
if options.get('description'):
|
235
|
+
self.stdout.write(f"š Problem: {options['description']}")
|
236
|
+
self.stdout.write("")
|
237
|
+
|
238
|
+
# Step 1: Scan project
|
239
|
+
self.stdout.write("š Step 1: Scanning project structure...")
|
240
|
+
scan_result = self._scan_project(options)
|
241
|
+
|
242
|
+
if options.get('scan_only'):
|
243
|
+
return self._display_scan_results(scan_result, options)
|
244
|
+
|
245
|
+
# Step 2: Build context
|
246
|
+
self.stdout.write("š§ Step 2: Building project context...")
|
247
|
+
context = self._build_context(scan_result, options)
|
248
|
+
|
249
|
+
# Step 3: AI Diagnosis (placeholder for now)
|
250
|
+
self.stdout.write("š¤ Step 3: Running AI diagnosis...")
|
251
|
+
diagnosis = self._run_ai_diagnosis(context, options)
|
252
|
+
|
253
|
+
# Step 4: Display results
|
254
|
+
self.stdout.write("š Step 4: Generating diagnosis report...")
|
255
|
+
return self._display_diagnosis_results(diagnosis, options)
|
256
|
+
|
257
|
+
except Exception as e:
|
258
|
+
raise CommandError(f"Diagnosis process failed: {e}")
|
259
|
+
|
260
|
+
def _scan_project(self, options):
|
261
|
+
"""Scan the project structure."""
|
262
|
+
try:
|
263
|
+
# Initialize scanner service
|
264
|
+
config = AgentConfig()
|
265
|
+
logger = get_logger("project_scanner")
|
266
|
+
|
267
|
+
scanner = ProjectScannerService(config, logger)
|
268
|
+
|
269
|
+
# Create scan request
|
270
|
+
request = ProjectScanRequest(
|
271
|
+
project_root=str(settings.BASE_DIR),
|
272
|
+
target_app=options.get('app'),
|
273
|
+
scan_depth=3,
|
274
|
+
include_tests=True,
|
275
|
+
include_migrations=True
|
276
|
+
)
|
277
|
+
|
278
|
+
# Run scan (async)
|
279
|
+
if sys.platform == 'win32':
|
280
|
+
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
|
281
|
+
|
282
|
+
result = asyncio.run(scanner.process(request))
|
283
|
+
return result
|
284
|
+
|
285
|
+
except Exception as e:
|
286
|
+
raise CommandError(f"Project scan failed: {e}")
|
287
|
+
|
288
|
+
def _build_context(self, scan_result, options):
|
289
|
+
"""Build project context for diagnosis."""
|
290
|
+
try:
|
291
|
+
# Initialize context builder
|
292
|
+
config = AgentConfig()
|
293
|
+
logger = get_logger("context_builder")
|
294
|
+
|
295
|
+
builder = ContextBuilderService(config, logger)
|
296
|
+
|
297
|
+
# Create context request
|
298
|
+
request = ContextBuildRequest(
|
299
|
+
project_root=str(settings.BASE_DIR),
|
300
|
+
scan_result=scan_result,
|
301
|
+
focus_area=options.get('category'),
|
302
|
+
target_app=options.get('app')
|
303
|
+
)
|
304
|
+
|
305
|
+
# Build context (async)
|
306
|
+
result = asyncio.run(builder.process(request))
|
307
|
+
return result
|
308
|
+
|
309
|
+
except Exception as e:
|
310
|
+
raise CommandError(f"Context building failed: {e}")
|
311
|
+
|
312
|
+
def _run_ai_diagnosis(self, context, options):
|
313
|
+
"""Run AI-powered diagnosis (placeholder implementation)."""
|
314
|
+
# This is a placeholder implementation
|
315
|
+
# In the real implementation, this would use AI agents
|
316
|
+
|
317
|
+
diagnosis = {
|
318
|
+
'status': 'completed',
|
319
|
+
'findings': [
|
320
|
+
{
|
321
|
+
'category': options.get('category', 'general'),
|
322
|
+
'severity': options.get('severity', 'medium'),
|
323
|
+
'title': 'Project Structure Analysis',
|
324
|
+
'description': 'Basic project structure appears to be well-organized.',
|
325
|
+
'recommendations': [
|
326
|
+
'Consider adding more comprehensive tests',
|
327
|
+
'Review security settings for production deployment',
|
328
|
+
'Optimize database queries for better performance'
|
329
|
+
]
|
330
|
+
}
|
331
|
+
],
|
332
|
+
'summary': 'Project analysis completed. No critical issues found.',
|
333
|
+
'confidence': 0.75
|
334
|
+
}
|
335
|
+
|
336
|
+
return diagnosis
|
337
|
+
|
338
|
+
def _display_scan_results(self, scan_result, options):
|
339
|
+
"""Display project scan results."""
|
340
|
+
self.stdout.write(self.style.SUCCESS("\nš Project Scan Results"))
|
341
|
+
self.stdout.write("=" * 50)
|
342
|
+
|
343
|
+
if hasattr(scan_result, 'project_info'):
|
344
|
+
info = scan_result.project_info
|
345
|
+
self.stdout.write(f"Project Name: {info.get('name', 'Unknown')}")
|
346
|
+
self.stdout.write(f"Django Version: {info.get('django_version', 'Unknown')}")
|
347
|
+
self.stdout.write(f"Total Apps: {info.get('total_apps', 0)}")
|
348
|
+
|
349
|
+
if hasattr(scan_result, 'apps') and scan_result.apps:
|
350
|
+
self.stdout.write(f"\nš± Applications ({len(scan_result.apps)}):")
|
351
|
+
for app in scan_result.apps:
|
352
|
+
self.stdout.write(f" ⢠{app.name} ({app.path})")
|
353
|
+
|
354
|
+
self.stdout.write(f"\nā
Scan completed successfully!")
|
355
|
+
|
356
|
+
def _display_diagnosis_results(self, diagnosis, options):
|
357
|
+
"""Display diagnosis results."""
|
358
|
+
self.stdout.write(self.style.SUCCESS("\nšÆ Diagnosis Results"))
|
359
|
+
self.stdout.write("=" * 50)
|
360
|
+
|
361
|
+
# Summary
|
362
|
+
self.stdout.write(f"Status: {diagnosis['status']}")
|
363
|
+
self.stdout.write(f"Summary: {diagnosis['summary']}")
|
364
|
+
self.stdout.write(f"Confidence: {diagnosis['confidence']:.0%}")
|
365
|
+
|
366
|
+
# Findings
|
367
|
+
if diagnosis.get('findings'):
|
368
|
+
self.stdout.write(f"\nš Findings ({len(diagnosis['findings'])}):")
|
369
|
+
|
370
|
+
for i, finding in enumerate(diagnosis['findings'], 1):
|
371
|
+
severity_style = {
|
372
|
+
'low': self.style.SUCCESS,
|
373
|
+
'medium': self.style.WARNING,
|
374
|
+
'high': self.style.ERROR,
|
375
|
+
'critical': self.style.ERROR
|
376
|
+
}.get(finding['severity'], self.style.WARNING)
|
377
|
+
|
378
|
+
self.stdout.write(f"\n{i}. {finding['title']}")
|
379
|
+
self.stdout.write(severity_style(f" Severity: {finding['severity'].upper()}"))
|
380
|
+
self.stdout.write(f" Category: {finding['category']}")
|
381
|
+
self.stdout.write(f" Description: {finding['description']}")
|
382
|
+
|
383
|
+
if finding.get('recommendations'):
|
384
|
+
self.stdout.write(" Recommendations:")
|
385
|
+
for rec in finding['recommendations']:
|
386
|
+
self.stdout.write(f" ⢠{rec}")
|
387
|
+
|
388
|
+
# Save report if requested
|
389
|
+
if options.get('save_report'):
|
390
|
+
self._save_diagnosis_report(diagnosis, options)
|
391
|
+
|
392
|
+
self.stdout.write(f"\nā
Diagnosis completed!")
|
393
|
+
|
394
|
+
def _save_diagnosis_report(self, diagnosis, options):
|
395
|
+
"""Save diagnosis report to file."""
|
396
|
+
try:
|
397
|
+
report_path = Path(options['save_report'])
|
398
|
+
|
399
|
+
# Generate report content based on format
|
400
|
+
format_type = options.get('output_format', 'text')
|
401
|
+
|
402
|
+
if format_type == 'json':
|
403
|
+
import json
|
404
|
+
content = json.dumps(diagnosis, indent=2)
|
405
|
+
elif format_type == 'markdown':
|
406
|
+
content = self._generate_markdown_report(diagnosis)
|
407
|
+
else: # text
|
408
|
+
content = self._generate_text_report(diagnosis)
|
409
|
+
|
410
|
+
# Write to file
|
411
|
+
report_path.write_text(content, encoding='utf-8')
|
412
|
+
|
413
|
+
self.stdout.write(f"š Report saved to: {report_path}")
|
414
|
+
|
415
|
+
except Exception as e:
|
416
|
+
self.stdout.write(
|
417
|
+
self.style.WARNING(f"Failed to save report: {e}")
|
418
|
+
)
|
419
|
+
|
420
|
+
def _generate_markdown_report(self, diagnosis):
|
421
|
+
"""Generate markdown format report."""
|
422
|
+
content = f"""# Project Diagnosis Report
|
423
|
+
|
424
|
+
## Summary
|
425
|
+
- **Status**: {diagnosis['status']}
|
426
|
+
- **Confidence**: {diagnosis['confidence']:.0%}
|
427
|
+
- **Summary**: {diagnosis['summary']}
|
428
|
+
|
429
|
+
## Findings
|
430
|
+
"""
|
431
|
+
|
432
|
+
for i, finding in enumerate(diagnosis.get('findings', []), 1):
|
433
|
+
content += f"""
|
434
|
+
### {i}. {finding['title']}
|
435
|
+
- **Severity**: {finding['severity'].upper()}
|
436
|
+
- **Category**: {finding['category']}
|
437
|
+
- **Description**: {finding['description']}
|
438
|
+
|
439
|
+
**Recommendations**:
|
440
|
+
"""
|
441
|
+
for rec in finding.get('recommendations', []):
|
442
|
+
content += f"- {rec}\n"
|
443
|
+
|
444
|
+
return content
|
445
|
+
|
446
|
+
def _generate_text_report(self, diagnosis):
|
447
|
+
"""Generate plain text report."""
|
448
|
+
content = f"""PROJECT DIAGNOSIS REPORT
|
449
|
+
{'=' * 50}
|
450
|
+
|
451
|
+
STATUS: {diagnosis['status']}
|
452
|
+
CONFIDENCE: {diagnosis['confidence']:.0%}
|
453
|
+
SUMMARY: {diagnosis['summary']}
|
454
|
+
|
455
|
+
FINDINGS:
|
456
|
+
"""
|
457
|
+
|
458
|
+
for i, finding in enumerate(diagnosis.get('findings', []), 1):
|
459
|
+
content += f"""
|
460
|
+
{i}. {finding['title']}
|
461
|
+
Severity: {finding['severity'].upper()}
|
462
|
+
Category: {finding['category']}
|
463
|
+
Description: {finding['description']}
|
464
|
+
|
465
|
+
Recommendations:
|
466
|
+
"""
|
467
|
+
for rec in finding.get('recommendations', []):
|
468
|
+
content += f" ⢠{rec}\n"
|
469
|
+
|
470
|
+
return content
|