django-cfg 1.4.10__py3-none-any.whl → 1.4.13__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/apps/agents/management/commands/create_agent.py +1 -1
- django_cfg/apps/agents/management/commands/orchestrator_status.py +3 -3
- django_cfg/apps/newsletter/serializers.py +40 -3
- django_cfg/apps/newsletter/views/campaigns.py +12 -3
- django_cfg/apps/newsletter/views/emails.py +14 -3
- django_cfg/apps/newsletter/views/subscriptions.py +12 -2
- django_cfg/apps/payments/views/api/currencies.py +49 -6
- django_cfg/apps/payments/views/api/webhooks.py +72 -7
- django_cfg/apps/payments/views/overview/serializers.py +34 -1
- django_cfg/apps/payments/views/overview/views.py +2 -1
- django_cfg/apps/payments/views/serializers/payments.py +6 -6
- django_cfg/apps/urls.py +106 -45
- django_cfg/core/base/config_model.py +2 -2
- django_cfg/core/constants.py +1 -1
- django_cfg/core/generation/integration_generators/__init__.py +1 -1
- django_cfg/core/generation/integration_generators/api.py +73 -49
- django_cfg/core/integration/display/startup.py +30 -22
- django_cfg/core/integration/url_integration.py +15 -16
- django_cfg/management/commands/check_endpoints.py +11 -160
- django_cfg/management/commands/check_settings.py +13 -348
- django_cfg/management/commands/clear_constance.py +13 -201
- django_cfg/management/commands/create_token.py +13 -321
- django_cfg/management/commands/generate_clients.py +23 -0
- django_cfg/management/commands/list_urls.py +13 -306
- django_cfg/management/commands/migrate_all.py +13 -126
- django_cfg/management/commands/migrator.py +13 -396
- django_cfg/management/commands/rundramatiq.py +15 -247
- django_cfg/management/commands/rundramatiq_simulator.py +12 -429
- django_cfg/management/commands/runserver_ngrok.py +15 -160
- django_cfg/management/commands/script.py +12 -488
- django_cfg/management/commands/show_config.py +12 -215
- django_cfg/management/commands/show_urls.py +12 -342
- django_cfg/management/commands/superuser.py +15 -295
- django_cfg/management/commands/task_clear.py +14 -217
- django_cfg/management/commands/task_status.py +13 -248
- django_cfg/management/commands/test_email.py +15 -86
- django_cfg/management/commands/test_telegram.py +14 -61
- django_cfg/management/commands/test_twilio.py +15 -105
- django_cfg/management/commands/tree.py +13 -383
- django_cfg/management/commands/validate_openapi.py +10 -0
- django_cfg/middleware/README.md +1 -1
- django_cfg/middleware/user_activity.py +3 -3
- django_cfg/models/__init__.py +2 -2
- django_cfg/models/api/drf/spectacular.py +6 -6
- django_cfg/models/django/__init__.py +2 -2
- django_cfg/models/django/openapi.py +162 -0
- django_cfg/modules/django_admin/management/commands/check_endpoints.py +169 -0
- django_cfg/modules/django_admin/management/commands/check_settings.py +355 -0
- django_cfg/modules/django_admin/management/commands/clear_constance.py +208 -0
- django_cfg/modules/django_admin/management/commands/create_token.py +328 -0
- django_cfg/modules/django_admin/management/commands/list_urls.py +313 -0
- django_cfg/modules/django_admin/management/commands/migrate_all.py +133 -0
- django_cfg/modules/django_admin/management/commands/migrator.py +403 -0
- django_cfg/modules/django_admin/management/commands/script.py +496 -0
- django_cfg/modules/django_admin/management/commands/show_config.py +225 -0
- django_cfg/modules/django_admin/management/commands/show_urls.py +361 -0
- django_cfg/modules/django_admin/management/commands/superuser.py +302 -0
- django_cfg/modules/django_admin/management/commands/tree.py +390 -0
- django_cfg/modules/django_client/__init__.py +20 -0
- django_cfg/modules/django_client/apps.py +35 -0
- django_cfg/modules/django_client/core/__init__.py +56 -0
- django_cfg/modules/django_client/core/archive/__init__.py +11 -0
- django_cfg/modules/django_client/core/archive/manager.py +134 -0
- django_cfg/modules/django_client/core/cli/__init__.py +12 -0
- django_cfg/modules/django_client/core/cli/main.py +235 -0
- django_cfg/modules/django_client/core/config/__init__.py +18 -0
- django_cfg/modules/django_client/core/config/config.py +208 -0
- django_cfg/modules/django_client/core/config/group.py +101 -0
- django_cfg/modules/django_client/core/config/service.py +209 -0
- django_cfg/modules/django_client/core/generator/__init__.py +115 -0
- django_cfg/modules/django_client/core/generator/base.py +838 -0
- django_cfg/modules/django_client/core/generator/python/__init__.py +16 -0
- django_cfg/modules/django_client/core/generator/python/async_client_gen.py +174 -0
- django_cfg/modules/django_client/core/generator/python/files_generator.py +180 -0
- django_cfg/modules/django_client/core/generator/python/generator.py +182 -0
- django_cfg/modules/django_client/core/generator/python/models_generator.py +318 -0
- django_cfg/modules/django_client/core/generator/python/operations_generator.py +278 -0
- django_cfg/modules/django_client/core/generator/python/sync_client_gen.py +102 -0
- django_cfg/modules/django_client/core/generator/python/templates/__init__.py.jinja +9 -0
- django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +153 -0
- django_cfg/modules/django_client/core/generator/python/templates/app_init.py.jinja +6 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/app_client.py.jinja +18 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/flat_client.py.jinja +38 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/main_client.py.jinja +68 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/main_client_file.py.jinja +14 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/operation_method.py.jinja +9 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sub_client.py.jinja +18 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sync_main_client.py.jinja +50 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sync_operation_method.py.jinja +9 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sync_sub_client.py.jinja +18 -0
- django_cfg/modules/django_client/core/generator/python/templates/client_file.py.jinja +13 -0
- django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +52 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/app_models.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/enum_class.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/enums.py.jinja +8 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/models.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/schema_class.py.jinja +21 -0
- django_cfg/modules/django_client/core/generator/python/templates/pyproject.toml.jinja +55 -0
- django_cfg/modules/django_client/core/generator/python/templates/utils/logger.py.jinja +255 -0
- django_cfg/modules/django_client/core/generator/python/templates/utils/retry.py.jinja +271 -0
- django_cfg/modules/django_client/core/generator/python/templates/utils/schema.py.jinja +12 -0
- django_cfg/modules/django_client/core/generator/typescript/__init__.py +14 -0
- django_cfg/modules/django_client/core/generator/typescript/client_generator.py +165 -0
- django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +428 -0
- django_cfg/modules/django_client/core/generator/typescript/files_generator.py +207 -0
- django_cfg/modules/django_client/core/generator/typescript/generator.py +432 -0
- django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +536 -0
- django_cfg/modules/django_client/core/generator/typescript/models_generator.py +245 -0
- django_cfg/modules/django_client/core/generator/typescript/operations_generator.py +298 -0
- django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +329 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/api_instance.ts.jinja +131 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/app_index.ts.jinja +2 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/app_client.ts.jinja +18 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/client.ts.jinja +403 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/flat_client.ts.jinja +109 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/main_client_file.ts.jinja +10 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/operation.ts.jinja +61 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/sub_client.ts.jinja +15 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client_file.ts.jinja +9 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +45 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/index.ts.jinja +30 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/index.ts.jinja +5 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +268 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/models/app_models.ts.jinja +8 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/models/enums.ts.jinja +4 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/models/models.ts.jinja +8 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/package.json.jinja +52 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/schemas/index.ts.jinja +21 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/schemas/schema.ts.jinja +24 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/tsconfig.json.jinja +20 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/errors.ts.jinja +116 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/http.ts.jinja +98 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/logger.ts.jinja +259 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/retry.ts.jinja +175 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/schema.ts.jinja +7 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/storage.ts.jinja +158 -0
- django_cfg/modules/django_client/core/groups/__init__.py +13 -0
- django_cfg/modules/django_client/core/groups/detector.py +178 -0
- django_cfg/modules/django_client/core/groups/manager.py +314 -0
- django_cfg/modules/django_client/core/ir/__init__.py +57 -0
- django_cfg/modules/django_client/core/ir/context.py +387 -0
- django_cfg/modules/django_client/core/ir/operation.py +518 -0
- django_cfg/modules/django_client/core/ir/schema.py +353 -0
- django_cfg/modules/django_client/core/parser/__init__.py +74 -0
- django_cfg/modules/django_client/core/parser/base.py +648 -0
- django_cfg/modules/django_client/core/parser/models/__init__.py +74 -0
- django_cfg/modules/django_client/core/parser/models/base.py +212 -0
- django_cfg/modules/django_client/core/parser/models/components.py +160 -0
- django_cfg/modules/django_client/core/parser/models/openapi.py +203 -0
- django_cfg/modules/django_client/core/parser/models/operation.py +207 -0
- django_cfg/modules/django_client/core/parser/models/schema.py +266 -0
- django_cfg/modules/django_client/core/parser/openapi30.py +56 -0
- django_cfg/modules/django_client/core/parser/openapi31.py +64 -0
- django_cfg/modules/django_client/core/validation/__init__.py +22 -0
- django_cfg/modules/django_client/core/validation/checker.py +134 -0
- django_cfg/modules/django_client/core/validation/fixer.py +216 -0
- django_cfg/modules/django_client/core/validation/reporter.py +480 -0
- django_cfg/modules/django_client/core/validation/rules/__init__.py +11 -0
- django_cfg/modules/django_client/core/validation/rules/base.py +96 -0
- django_cfg/modules/django_client/core/validation/rules/type_hints.py +288 -0
- django_cfg/modules/django_client/core/validation/safety.py +266 -0
- django_cfg/modules/django_client/management/__init__.py +3 -0
- django_cfg/modules/django_client/management/commands/__init__.py +3 -0
- django_cfg/modules/django_client/management/commands/generate_client.py +427 -0
- django_cfg/modules/django_client/management/commands/validate_openapi.py +343 -0
- django_cfg/modules/django_client/pytest.ini +30 -0
- django_cfg/modules/django_client/spectacular/__init__.py +10 -0
- django_cfg/modules/django_client/spectacular/async_detection.py +187 -0
- django_cfg/modules/django_client/spectacular/enum_naming.py +192 -0
- django_cfg/modules/django_client/urls.py +72 -0
- django_cfg/{dashboard → modules/django_dashboard}/DEBUG_README.md +2 -2
- django_cfg/{dashboard → modules/django_dashboard}/REFACTORING_SUMMARY.md +1 -1
- django_cfg/modules/django_dashboard/management/__init__.py +0 -0
- django_cfg/modules/django_dashboard/management/commands/__init__.py +0 -0
- django_cfg/{dashboard → modules/django_dashboard}/management/commands/debug_dashboard.py +5 -5
- django_cfg/modules/django_dashboard/sections/documentation.py +391 -0
- django_cfg/modules/django_email/management/__init__.py +0 -0
- django_cfg/modules/django_email/management/commands/__init__.py +0 -0
- django_cfg/modules/django_email/management/commands/test_email.py +93 -0
- django_cfg/modules/django_logging/LOGGING_GUIDE.md +1 -1
- django_cfg/modules/django_logging/django_logger.py +6 -6
- django_cfg/modules/django_ngrok/management/__init__.py +0 -0
- django_cfg/modules/django_ngrok/management/commands/__init__.py +0 -0
- django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +167 -0
- django_cfg/modules/django_tasks/management/__init__.py +0 -0
- django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
- django_cfg/modules/django_tasks/management/commands/rundramatiq.py +254 -0
- django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +437 -0
- django_cfg/modules/django_tasks/management/commands/task_clear.py +226 -0
- django_cfg/modules/django_tasks/management/commands/task_status.py +257 -0
- django_cfg/modules/django_telegram/management/__init__.py +0 -0
- django_cfg/modules/django_telegram/management/commands/__init__.py +0 -0
- django_cfg/modules/django_telegram/management/commands/test_telegram.py +68 -0
- django_cfg/modules/django_twilio/management/__init__.py +0 -0
- django_cfg/modules/django_twilio/management/commands/__init__.py +0 -0
- django_cfg/modules/django_twilio/management/commands/test_twilio.py +112 -0
- django_cfg/modules/django_unfold/callbacks/main.py +21 -10
- django_cfg/modules/django_unfold/callbacks/revolution.py +41 -36
- django_cfg/pyproject.toml +2 -6
- django_cfg/registry/third_party.py +5 -7
- django_cfg/routing/callbacks.py +1 -1
- django_cfg/static/admin/css/prose-unfold.css +666 -0
- django_cfg/templates/admin/index.html +8 -0
- django_cfg/templates/admin/index_new.html +13 -0
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +15 -3
- django_cfg/templates/admin/sections/documentation_section.html +172 -0
- django_cfg/templates/admin/snippets/tabs/documentation_tab.html +231 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/METADATA +2 -2
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/RECORD +224 -74
- django_cfg/management/commands/generate.py +0 -107
- /django_cfg/models/django/{revolution.py → revolution_legacy.py} +0 -0
- /django_cfg/{dashboard → modules/django_admin}/management/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_admin}/management/commands/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/components.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/debug.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/base.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/commands.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/overview.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/stats.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/system.py +0 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
"""
|
2
|
+
Django management command for checking task system status.
|
3
|
+
|
4
|
+
This command provides comprehensive status information about the
|
5
|
+
Dramatiq task system, including queue statistics, worker status,
|
6
|
+
and configuration details.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from django.core.management.base import BaseCommand, CommandError
|
10
|
+
from django.conf import settings
|
11
|
+
from typing import Any, Dict, List
|
12
|
+
import json
|
13
|
+
import logging
|
14
|
+
from django_cfg.modules.django_logging import get_logger
|
15
|
+
|
16
|
+
logger = get_logger('task_status')
|
17
|
+
|
18
|
+
|
19
|
+
class Command(BaseCommand):
|
20
|
+
"""
|
21
|
+
Display comprehensive task system status.
|
22
|
+
|
23
|
+
Shows information about:
|
24
|
+
- Task system configuration
|
25
|
+
- Redis connection status
|
26
|
+
- Queue statistics
|
27
|
+
- Worker status
|
28
|
+
- Discovered task modules
|
29
|
+
"""
|
30
|
+
|
31
|
+
# Web execution metadata
|
32
|
+
web_executable = True
|
33
|
+
requires_input = False
|
34
|
+
is_destructive = False
|
35
|
+
|
36
|
+
help = "Display task system status and statistics"
|
37
|
+
|
38
|
+
def add_arguments(self, parser):
|
39
|
+
"""Add command line arguments."""
|
40
|
+
parser.add_argument(
|
41
|
+
"--format",
|
42
|
+
choices=["text", "json"],
|
43
|
+
default="text",
|
44
|
+
help="Output format (default: text)",
|
45
|
+
)
|
46
|
+
parser.add_argument(
|
47
|
+
"--verbose",
|
48
|
+
action="store_true",
|
49
|
+
help="Show detailed information",
|
50
|
+
)
|
51
|
+
|
52
|
+
def handle(self, *args, **options):
|
53
|
+
"""Handle the command execution."""
|
54
|
+
logger.info("Starting task_status command")
|
55
|
+
try:
|
56
|
+
# Import here to avoid issues if dramatiq is not installed
|
57
|
+
from django_cfg.modules.django_tasks import get_task_service
|
58
|
+
|
59
|
+
# Get task service
|
60
|
+
task_service = get_task_service()
|
61
|
+
|
62
|
+
# Get comprehensive health status
|
63
|
+
status = task_service.get_health_status()
|
64
|
+
|
65
|
+
# Format and display output
|
66
|
+
if options["format"] == "json":
|
67
|
+
self._output_json(status)
|
68
|
+
else:
|
69
|
+
self._output_text(status, options["verbose"])
|
70
|
+
|
71
|
+
except ImportError:
|
72
|
+
raise CommandError(
|
73
|
+
"Dramatiq dependencies not installed. "
|
74
|
+
"Install with: pip install django-cfg[tasks]"
|
75
|
+
)
|
76
|
+
except Exception as e:
|
77
|
+
logger.exception("Failed to get task status")
|
78
|
+
raise CommandError(f"Failed to get status: {e}")
|
79
|
+
|
80
|
+
def _output_json(self, status: Dict[str, Any]):
|
81
|
+
"""Output status in JSON format."""
|
82
|
+
self.stdout.write(json.dumps(status, indent=2, default=str))
|
83
|
+
|
84
|
+
def _output_text(self, status: Dict[str, Any], verbose: bool):
|
85
|
+
"""Output status in human-readable text format."""
|
86
|
+
# Header
|
87
|
+
self.stdout.write(
|
88
|
+
self.style.SUCCESS("=== Django-CFG Task System Status ===")
|
89
|
+
)
|
90
|
+
self.stdout.write()
|
91
|
+
|
92
|
+
# Basic status
|
93
|
+
enabled = status.get("enabled", False)
|
94
|
+
if enabled:
|
95
|
+
self.stdout.write(
|
96
|
+
self.style.SUCCESS("✓ Task system is ENABLED")
|
97
|
+
)
|
98
|
+
else:
|
99
|
+
self.stdout.write(
|
100
|
+
self.style.ERROR("✗ Task system is DISABLED")
|
101
|
+
)
|
102
|
+
return
|
103
|
+
|
104
|
+
# Redis connection
|
105
|
+
redis_ok = status.get("redis_connection", False)
|
106
|
+
if redis_ok:
|
107
|
+
self.stdout.write(
|
108
|
+
self.style.SUCCESS("✓ Redis connection is OK")
|
109
|
+
)
|
110
|
+
else:
|
111
|
+
self.stdout.write(
|
112
|
+
self.style.ERROR("✗ Redis connection FAILED")
|
113
|
+
)
|
114
|
+
|
115
|
+
# Configuration validation
|
116
|
+
config_valid = status.get("configuration_valid", False)
|
117
|
+
if config_valid:
|
118
|
+
self.stdout.write(
|
119
|
+
self.style.SUCCESS("✓ Configuration is VALID")
|
120
|
+
)
|
121
|
+
else:
|
122
|
+
self.stdout.write(
|
123
|
+
self.style.ERROR("✗ Configuration is INVALID")
|
124
|
+
)
|
125
|
+
|
126
|
+
self.stdout.write()
|
127
|
+
|
128
|
+
# Configuration details (if verbose)
|
129
|
+
if verbose:
|
130
|
+
self._show_configuration_details()
|
131
|
+
|
132
|
+
# Queue statistics
|
133
|
+
queues = status.get("queues", [])
|
134
|
+
if queues:
|
135
|
+
self.stdout.write(
|
136
|
+
self.style.SUCCESS("=== Queue Statistics ===")
|
137
|
+
)
|
138
|
+
for queue in queues:
|
139
|
+
name = queue.get("name", "unknown")
|
140
|
+
pending = queue.get("pending", 0)
|
141
|
+
running = queue.get("running", 0)
|
142
|
+
completed = queue.get("completed", 0)
|
143
|
+
failed = queue.get("failed", 0)
|
144
|
+
|
145
|
+
self.stdout.write(f"Queue: {name}")
|
146
|
+
self.stdout.write(f" Pending: {pending}")
|
147
|
+
self.stdout.write(f" Running: {running}")
|
148
|
+
self.stdout.write(f" Completed: {completed}")
|
149
|
+
self.stdout.write(f" Failed: {failed}")
|
150
|
+
self.stdout.write()
|
151
|
+
|
152
|
+
# Worker status
|
153
|
+
workers = status.get("workers", [])
|
154
|
+
if workers:
|
155
|
+
self.stdout.write(
|
156
|
+
self.style.SUCCESS("=== Worker Status ===")
|
157
|
+
)
|
158
|
+
for worker in workers:
|
159
|
+
worker_id = worker.get("id", "unknown")
|
160
|
+
worker_status = worker.get("status", "unknown")
|
161
|
+
current_task = worker.get("current_task")
|
162
|
+
processed = worker.get("processed_tasks", 0)
|
163
|
+
|
164
|
+
status_style = (
|
165
|
+
self.style.SUCCESS if worker_status == "active"
|
166
|
+
else self.style.WARNING if worker_status == "idle"
|
167
|
+
else self.style.ERROR
|
168
|
+
)
|
169
|
+
|
170
|
+
self.stdout.write(f"Worker: {worker_id}")
|
171
|
+
self.stdout.write(f" Status: {status_style(worker_status)}")
|
172
|
+
if current_task:
|
173
|
+
self.stdout.write(f" Current Task: {current_task}")
|
174
|
+
self.stdout.write(f" Processed: {processed}")
|
175
|
+
self.stdout.write()
|
176
|
+
else:
|
177
|
+
self.stdout.write(
|
178
|
+
self.style.WARNING("No active workers found")
|
179
|
+
)
|
180
|
+
|
181
|
+
# Discovered modules
|
182
|
+
modules = status.get("discovered_modules", [])
|
183
|
+
if modules:
|
184
|
+
self.stdout.write(
|
185
|
+
self.style.SUCCESS("=== Discovered Task Modules ===")
|
186
|
+
)
|
187
|
+
for module in modules:
|
188
|
+
self.stdout.write(f" - {module}")
|
189
|
+
self.stdout.write()
|
190
|
+
else:
|
191
|
+
self.stdout.write(
|
192
|
+
self.style.WARNING("No task modules discovered")
|
193
|
+
)
|
194
|
+
|
195
|
+
# Error information
|
196
|
+
if "error" in status:
|
197
|
+
self.stdout.write(
|
198
|
+
self.style.ERROR(f"Error: {status['error']}")
|
199
|
+
)
|
200
|
+
|
201
|
+
def _show_configuration_details(self):
|
202
|
+
"""Show detailed configuration information."""
|
203
|
+
try:
|
204
|
+
from django_cfg.modules.django_tasks import get_task_service
|
205
|
+
|
206
|
+
task_service = get_task_service()
|
207
|
+
config = task_service.config
|
208
|
+
|
209
|
+
if not config:
|
210
|
+
self.stdout.write(
|
211
|
+
self.style.WARNING("Configuration not available")
|
212
|
+
)
|
213
|
+
return
|
214
|
+
|
215
|
+
self.stdout.write(
|
216
|
+
self.style.SUCCESS("=== Configuration Details ===")
|
217
|
+
)
|
218
|
+
|
219
|
+
# Basic settings
|
220
|
+
self.stdout.write(f"Backend: {config.backend}")
|
221
|
+
self.stdout.write(f"Enabled: {config.enabled}")
|
222
|
+
self.stdout.write(f"Auto-discover: {config.auto_discover_tasks}")
|
223
|
+
self.stdout.write()
|
224
|
+
|
225
|
+
# Dramatiq settings
|
226
|
+
dramatiq = config.dramatiq
|
227
|
+
self.stdout.write("Dramatiq Configuration:")
|
228
|
+
self.stdout.write(f" Redis DB: {dramatiq.redis_db}")
|
229
|
+
self.stdout.write(f" Max Retries: {dramatiq.max_retries}")
|
230
|
+
self.stdout.write(f" Processes: {dramatiq.processes}")
|
231
|
+
self.stdout.write(f" Threads: {dramatiq.threads}")
|
232
|
+
self.stdout.write(f" Queues: {', '.join(dramatiq.queues)}")
|
233
|
+
self.stdout.write(f" Time Limit: {dramatiq.time_limit_seconds}s")
|
234
|
+
self.stdout.write(f" Max Age: {dramatiq.max_age_seconds}s")
|
235
|
+
self.stdout.write()
|
236
|
+
|
237
|
+
# Worker settings
|
238
|
+
worker = config.worker
|
239
|
+
self.stdout.write("Worker Configuration:")
|
240
|
+
self.stdout.write(f" Log Level: {worker.log_level}")
|
241
|
+
self.stdout.write(f" Shutdown Timeout: {worker.shutdown_timeout}s")
|
242
|
+
self.stdout.write(f" Health Check: {worker.health_check_enabled}")
|
243
|
+
if worker.max_memory_mb:
|
244
|
+
self.stdout.write(f" Memory Limit: {worker.max_memory_mb}MB")
|
245
|
+
self.stdout.write()
|
246
|
+
|
247
|
+
# Middleware
|
248
|
+
if dramatiq.middleware:
|
249
|
+
self.stdout.write("Middleware Stack:")
|
250
|
+
for middleware in dramatiq.middleware:
|
251
|
+
self.stdout.write(f" - {middleware}")
|
252
|
+
self.stdout.write()
|
253
|
+
|
254
|
+
except Exception as e:
|
255
|
+
self.stdout.write(
|
256
|
+
self.style.ERROR(f"Failed to show configuration: {e}")
|
257
|
+
)
|
File without changes
|
File without changes
|
@@ -0,0 +1,68 @@
|
|
1
|
+
"""
|
2
|
+
Test Telegram Command
|
3
|
+
|
4
|
+
Tests Telegram notification functionality using django_cfg configuration.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from django.core.management.base import BaseCommand
|
8
|
+
from django_cfg.modules.django_logging import get_logger
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
logger = get_logger('test_telegram')
|
13
|
+
|
14
|
+
class Command(BaseCommand):
|
15
|
+
"""Command to test Telegram functionality."""
|
16
|
+
|
17
|
+
# Web execution metadata
|
18
|
+
web_executable = True
|
19
|
+
requires_input = False
|
20
|
+
is_destructive = False
|
21
|
+
|
22
|
+
help = "Test Telegram notification functionality"
|
23
|
+
|
24
|
+
def add_arguments(self, parser):
|
25
|
+
parser.add_argument(
|
26
|
+
"--message",
|
27
|
+
type=str,
|
28
|
+
help="Message to send",
|
29
|
+
default="Test message from UnrealON"
|
30
|
+
)
|
31
|
+
|
32
|
+
def handle(self, *args, **options):
|
33
|
+
logger.info("Starting test_telegram command")
|
34
|
+
message = options["message"]
|
35
|
+
|
36
|
+
self.stdout.write("🚀 Testing Telegram notification service")
|
37
|
+
|
38
|
+
# Get telegram service from django-cfg (автоматически настроен!)
|
39
|
+
try:
|
40
|
+
from django_cfg.modules.django_telegram import DjangoTelegram
|
41
|
+
telegram_service = DjangoTelegram()
|
42
|
+
|
43
|
+
self.stdout.write("\n📱 Sending test messages...")
|
44
|
+
|
45
|
+
# Send info message (модуль сам знает настройки!)
|
46
|
+
self.stdout.write("\n1️⃣ Sending info message...")
|
47
|
+
telegram_service.send_info(
|
48
|
+
message,
|
49
|
+
{
|
50
|
+
"Type": "System Test",
|
51
|
+
"Status": "Running",
|
52
|
+
"Environment": "Development"
|
53
|
+
}
|
54
|
+
)
|
55
|
+
self.stdout.write(self.style.SUCCESS("✅ Info message sent!"))
|
56
|
+
|
57
|
+
# Send success message
|
58
|
+
self.stdout.write("\n2️⃣ Sending success message...")
|
59
|
+
telegram_service.send_success(
|
60
|
+
"Test completed successfully!",
|
61
|
+
{"Message": message}
|
62
|
+
)
|
63
|
+
self.stdout.write(self.style.SUCCESS("✅ Success message sent!"))
|
64
|
+
|
65
|
+
self.stdout.write(self.style.SUCCESS("\n✅ All test messages sent successfully!"))
|
66
|
+
|
67
|
+
except Exception as e:
|
68
|
+
self.stdout.write(self.style.ERROR(f"\n❌ Failed to send Telegram messages: {e}"))
|
File without changes
|
File without changes
|
@@ -0,0 +1,112 @@
|
|
1
|
+
"""
|
2
|
+
Test Twilio Command
|
3
|
+
|
4
|
+
Tests Twilio messaging functionality using django_cfg configuration.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from django.core.management.base import BaseCommand
|
8
|
+
from django_cfg.modules.django_logging import get_logger
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
logger = get_logger('test_twilio')
|
13
|
+
|
14
|
+
class Command(BaseCommand):
|
15
|
+
"""Command to test Twilio functionality."""
|
16
|
+
|
17
|
+
# Web execution metadata
|
18
|
+
web_executable = True
|
19
|
+
requires_input = False
|
20
|
+
is_destructive = False
|
21
|
+
|
22
|
+
help = "Test Twilio messaging functionality"
|
23
|
+
|
24
|
+
def add_arguments(self, parser):
|
25
|
+
parser.add_argument(
|
26
|
+
"--to",
|
27
|
+
type=str,
|
28
|
+
help="Phone number to send test message to",
|
29
|
+
default="+6281339646301"
|
30
|
+
)
|
31
|
+
parser.add_argument(
|
32
|
+
"--message",
|
33
|
+
type=str,
|
34
|
+
help="Message to send",
|
35
|
+
default="Test message from Django CFG Twilio"
|
36
|
+
)
|
37
|
+
parser.add_argument(
|
38
|
+
"--whatsapp",
|
39
|
+
action="store_true",
|
40
|
+
help="Send WhatsApp message (default: SMS)"
|
41
|
+
)
|
42
|
+
parser.add_argument(
|
43
|
+
"--content-sid",
|
44
|
+
type=str,
|
45
|
+
help="Content template SID for WhatsApp (optional)"
|
46
|
+
)
|
47
|
+
|
48
|
+
def handle(self, *args, **options):
|
49
|
+
logger.info("Starting test_twilio command")
|
50
|
+
to_number = options["to"]
|
51
|
+
message = options["message"]
|
52
|
+
is_whatsapp = options["whatsapp"]
|
53
|
+
content_sid = options.get("content_sid")
|
54
|
+
|
55
|
+
self.stdout.write("🚀 Testing Twilio messaging service")
|
56
|
+
|
57
|
+
try:
|
58
|
+
from django_cfg.modules.django_twilio import SimpleTwilioService
|
59
|
+
twilio_service = SimpleTwilioService()
|
60
|
+
|
61
|
+
if is_whatsapp:
|
62
|
+
self.stdout.write(f"\n📱 Sending WhatsApp message to {to_number}...")
|
63
|
+
|
64
|
+
if content_sid:
|
65
|
+
# Send with template
|
66
|
+
result = twilio_service.send_whatsapp_message(
|
67
|
+
to=to_number,
|
68
|
+
body="", # Not used with templates
|
69
|
+
content_sid=content_sid,
|
70
|
+
content_variables={"1": "12/1", "2": "3pm"}
|
71
|
+
)
|
72
|
+
self.stdout.write(self.style.SUCCESS("✅ WhatsApp template message sent!"))
|
73
|
+
else:
|
74
|
+
# Send regular message
|
75
|
+
result = twilio_service.send_whatsapp_message(
|
76
|
+
to=to_number,
|
77
|
+
body=message
|
78
|
+
)
|
79
|
+
self.stdout.write(self.style.SUCCESS("✅ WhatsApp message sent!"))
|
80
|
+
else:
|
81
|
+
self.stdout.write(f"\n📱 Sending SMS to {to_number}...")
|
82
|
+
result = twilio_service.send_sms_message(
|
83
|
+
to=to_number,
|
84
|
+
body=message
|
85
|
+
)
|
86
|
+
self.stdout.write(self.style.SUCCESS("✅ SMS message sent!"))
|
87
|
+
|
88
|
+
# Show result details
|
89
|
+
self.stdout.write(f"\n📊 Message Details:")
|
90
|
+
self.stdout.write(f" SID: {result['sid']}")
|
91
|
+
self.stdout.write(f" Status: {result['status']}")
|
92
|
+
self.stdout.write(f" To: {result['to']}")
|
93
|
+
self.stdout.write(f" From: {result['from']}")
|
94
|
+
self.stdout.write(f" Created: {result['date_created']}")
|
95
|
+
|
96
|
+
if result.get('price'):
|
97
|
+
self.stdout.write(f" Price: {result['price']} {result['price_unit']}")
|
98
|
+
|
99
|
+
self.stdout.write(self.style.SUCCESS("\n✅ Twilio test completed successfully!"))
|
100
|
+
|
101
|
+
except ImportError as e:
|
102
|
+
self.stdout.write(self.style.ERROR(f"\n❌ Twilio dependencies not installed: {e}"))
|
103
|
+
self.stdout.write("💡 Install with: pip install twilio")
|
104
|
+
|
105
|
+
except Exception as e:
|
106
|
+
self.stdout.write(self.style.ERROR(f"\n❌ Failed to send message: {e}"))
|
107
|
+
self.stdout.write("\n💡 Troubleshooting:")
|
108
|
+
self.stdout.write(" 1. Check your Twilio credentials in config.dev.yaml")
|
109
|
+
self.stdout.write(" 2. Ensure account_sid starts with 'AC' and is 34 characters")
|
110
|
+
self.stdout.write(" 3. Verify auth_token is 32 characters")
|
111
|
+
self.stdout.write(" 4. For WhatsApp: use sandbox number +14155238886")
|
112
|
+
self.stdout.write(" 5. For SMS: ensure your number is verified")
|
@@ -19,16 +19,17 @@ from .system import SystemCallbacks
|
|
19
19
|
from .actions import ActionsCallbacks
|
20
20
|
from .charts import ChartsCallbacks
|
21
21
|
from .commands import CommandsCallbacks
|
22
|
-
from .revolution import
|
22
|
+
from .revolution import OpenAPIClientCallbacks
|
23
23
|
from .users import UsersCallbacks
|
24
24
|
from .base import get_user_admin_urls
|
25
25
|
|
26
26
|
# Import new dashboard sections
|
27
|
-
from django_cfg.
|
28
|
-
from django_cfg.
|
29
|
-
from django_cfg.
|
30
|
-
from django_cfg.
|
31
|
-
from django_cfg.
|
27
|
+
from django_cfg.modules.django_dashboard.sections.overview import OverviewSection
|
28
|
+
from django_cfg.modules.django_dashboard.sections.stats import StatsSection
|
29
|
+
from django_cfg.modules.django_dashboard.sections.system import SystemSection
|
30
|
+
from django_cfg.modules.django_dashboard.sections.commands import CommandsSection
|
31
|
+
from django_cfg.modules.django_dashboard.sections.documentation import DocumentationSection
|
32
|
+
from django_cfg.modules.django_dashboard.debug import save_section_render
|
32
33
|
|
33
34
|
logger = logging.getLogger(__name__)
|
34
35
|
|
@@ -40,7 +41,7 @@ class UnfoldCallbacks(
|
|
40
41
|
ActionsCallbacks,
|
41
42
|
ChartsCallbacks,
|
42
43
|
CommandsCallbacks,
|
43
|
-
|
44
|
+
OpenAPIClientCallbacks,
|
44
45
|
UsersCallbacks
|
45
46
|
):
|
46
47
|
"""
|
@@ -145,6 +146,15 @@ class UnfoldCallbacks(
|
|
145
146
|
logger.error(f"Failed to render commands section: {e}", exc_info=True)
|
146
147
|
commands_section = None
|
147
148
|
|
149
|
+
try:
|
150
|
+
documentation_section = DocumentationSection(request).render()
|
151
|
+
# Debug: save render (only in debug mode)
|
152
|
+
if config and config.debug:
|
153
|
+
save_section_render('documentation', documentation_section)
|
154
|
+
except Exception as e:
|
155
|
+
logger.error(f"Failed to render documentation section: {e}", exc_info=True)
|
156
|
+
documentation_section = None
|
157
|
+
|
148
158
|
# Combine all stat cards (data already loaded above)
|
149
159
|
all_stats = user_stats + support_stats
|
150
160
|
|
@@ -165,6 +175,7 @@ class UnfoldCallbacks(
|
|
165
175
|
"stats_section": stats_section,
|
166
176
|
"system_section": system_section,
|
167
177
|
"commands_section": commands_section,
|
178
|
+
"documentation_section": documentation_section,
|
168
179
|
|
169
180
|
# Statistics cards
|
170
181
|
"cards": cards_data,
|
@@ -198,8 +209,8 @@ class UnfoldCallbacks(
|
|
198
209
|
for action in dashboard_data.quick_actions
|
199
210
|
if action.category == "system"
|
200
211
|
],
|
201
|
-
|
202
|
-
#
|
212
|
+
|
213
|
+
# OpenAPI Client groups
|
203
214
|
"zones_table": {
|
204
215
|
"headers": [
|
205
216
|
{"label": "Zone"},
|
@@ -209,7 +220,7 @@ class UnfoldCallbacks(
|
|
209
220
|
{"label": "Status"},
|
210
221
|
{"label": "Actions"},
|
211
222
|
],
|
212
|
-
"rows":
|
223
|
+
"rows": OpenAPIClientCallbacks().get_openapi_groups_data()[0],
|
213
224
|
},
|
214
225
|
|
215
226
|
# Recent users
|
@@ -1,5 +1,5 @@
|
|
1
1
|
"""
|
2
|
-
Django
|
2
|
+
Django Client (OpenAPI) integration callbacks.
|
3
3
|
"""
|
4
4
|
|
5
5
|
import logging
|
@@ -10,67 +10,72 @@ from django.conf import settings
|
|
10
10
|
logger = logging.getLogger(__name__)
|
11
11
|
|
12
12
|
|
13
|
-
class
|
14
|
-
"""Django
|
15
|
-
|
16
|
-
def
|
17
|
-
"""Get Django
|
13
|
+
class OpenAPIClientCallbacks:
|
14
|
+
"""Django Client (OpenAPI) integration callbacks."""
|
15
|
+
|
16
|
+
def get_openapi_groups_data(self) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]:
|
17
|
+
"""Get Django Client (OpenAPI) groups data."""
|
18
18
|
try:
|
19
|
-
# Try to get
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
# Try to get openapi_client config from Django settings
|
20
|
+
openapi_config = getattr(settings, "OPENAPI_CLIENT", {})
|
21
|
+
if isinstance(openapi_config, dict):
|
22
|
+
groups_list = openapi_config.get("groups", [])
|
23
|
+
api_prefix = openapi_config.get("api_prefix", "api")
|
24
|
+
else:
|
25
|
+
# Handle Pydantic model instance
|
26
|
+
groups_list = getattr(openapi_config, "groups", [])
|
27
|
+
api_prefix = getattr(openapi_config, "api_prefix", "api")
|
23
28
|
|
24
|
-
|
29
|
+
groups_data = []
|
25
30
|
total_apps = 0
|
26
31
|
total_endpoints = 0
|
27
32
|
|
28
|
-
for
|
33
|
+
for group in groups_list:
|
29
34
|
# Handle both dict and object access
|
30
|
-
if isinstance(
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
auth_required = zone_config.get("auth_required", True)
|
35
|
+
if isinstance(group, dict):
|
36
|
+
group_name = group.get("name", "unknown")
|
37
|
+
title = group.get("title", group_name.title())
|
38
|
+
description = group.get("description", f"{group_name} group")
|
39
|
+
apps = group.get("apps", [])
|
36
40
|
else:
|
37
|
-
# Handle object access (for
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
auth_required = getattr(zone_config, "auth_required", True)
|
41
|
+
# Handle object access (for OpenAPIGroupConfig instances)
|
42
|
+
group_name = getattr(group, "name", "unknown")
|
43
|
+
title = getattr(group, "title", group_name.title())
|
44
|
+
description = getattr(group, "description", f"{group_name} group")
|
45
|
+
apps = getattr(group, "apps", [])
|
43
46
|
|
44
47
|
# Count actual endpoints by checking URL patterns (simplified estimate)
|
45
48
|
endpoint_count = len(apps) * 3 # Conservative estimate
|
46
49
|
|
47
|
-
|
48
|
-
"name":
|
50
|
+
groups_data.append({
|
51
|
+
"name": group_name,
|
49
52
|
"title": title,
|
50
53
|
"description": description,
|
51
54
|
"app_count": len(apps),
|
52
55
|
"endpoint_count": endpoint_count,
|
53
56
|
"status": "active",
|
54
|
-
"
|
55
|
-
"
|
56
|
-
"
|
57
|
-
"
|
58
|
-
"redoc_url": f"/schema/{zone_name}/redoc/",
|
59
|
-
"api_url": f"/{api_prefix}/{zone_name}/",
|
57
|
+
"schema_url": f"/schema/{group_name}/",
|
58
|
+
"swagger_url": f"/schema/{group_name}/swagger/",
|
59
|
+
"redoc_url": f"/schema/{group_name}/redoc/",
|
60
|
+
"api_url": f"/{api_prefix}/{group_name}/",
|
60
61
|
})
|
61
62
|
|
62
63
|
total_apps += len(apps)
|
63
64
|
total_endpoints += endpoint_count
|
64
65
|
|
65
|
-
return
|
66
|
+
return groups_data, {
|
66
67
|
"total_apps": total_apps,
|
67
68
|
"total_endpoints": total_endpoints,
|
68
|
-
"
|
69
|
+
"total_groups": len(groups_list),
|
69
70
|
}
|
70
71
|
except Exception as e:
|
71
|
-
logger.error(f"Error getting
|
72
|
+
logger.error(f"Error getting OpenAPI groups: {e}")
|
72
73
|
return [], {
|
73
74
|
"total_apps": 0,
|
74
75
|
"total_endpoints": 0,
|
75
|
-
"
|
76
|
+
"total_groups": 0,
|
76
77
|
}
|
78
|
+
|
79
|
+
|
80
|
+
# Keep backward compatibility alias
|
81
|
+
RevolutionCallbacks = OpenAPIClientCallbacks
|