django-cfg 1.4.62__py3-none-any.whl → 1.4.63__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.
Potentially problematic release.
This version of django-cfg might be problematic. Click here for more details.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/services/otp_service.py +3 -14
- django_cfg/apps/centrifugo/__init__.py +57 -0
- django_cfg/apps/centrifugo/admin/__init__.py +13 -0
- django_cfg/apps/centrifugo/admin/centrifugo_log.py +249 -0
- django_cfg/apps/centrifugo/admin/config.py +82 -0
- django_cfg/apps/centrifugo/apps.py +31 -0
- django_cfg/apps/centrifugo/codegen/IMPLEMENTATION_SUMMARY.md +475 -0
- django_cfg/apps/centrifugo/codegen/README.md +242 -0
- django_cfg/apps/centrifugo/codegen/USAGE.md +616 -0
- django_cfg/apps/centrifugo/codegen/__init__.py +19 -0
- django_cfg/apps/centrifugo/codegen/discovery.py +246 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/__init__.py +5 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/generator.py +174 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/README.md.j2 +182 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/client.go.j2 +64 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/go.mod.j2 +10 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2 +300 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2.old +267 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/types.go.j2 +16 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/__init__.py +7 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/generator.py +241 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/README.md.j2 +128 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/__init__.py.j2 +22 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/client.py.j2 +73 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/models.py.j2 +19 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/requirements.txt.j2 +8 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/rpc_client.py.j2 +193 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/__init__.py +5 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/generator.py +124 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/README.md.j2 +38 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/client.ts.j2 +25 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/index.ts.j2 +12 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/package.json.j2 +13 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +137 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/tsconfig.json.j2 +14 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/types.ts.j2 +9 -0
- django_cfg/apps/centrifugo/codegen/utils/__init__.py +37 -0
- django_cfg/apps/centrifugo/codegen/utils/naming.py +155 -0
- django_cfg/apps/centrifugo/codegen/utils/type_converter.py +349 -0
- django_cfg/apps/centrifugo/decorators.py +137 -0
- django_cfg/apps/centrifugo/management/__init__.py +1 -0
- django_cfg/apps/centrifugo/management/commands/__init__.py +1 -0
- django_cfg/apps/centrifugo/management/commands/generate_centrifugo_clients.py +254 -0
- django_cfg/apps/centrifugo/managers/__init__.py +12 -0
- django_cfg/apps/centrifugo/managers/centrifugo_log.py +264 -0
- django_cfg/apps/centrifugo/migrations/0001_initial.py +164 -0
- django_cfg/apps/centrifugo/migrations/__init__.py +3 -0
- django_cfg/apps/centrifugo/models/__init__.py +11 -0
- django_cfg/apps/centrifugo/models/centrifugo_log.py +210 -0
- django_cfg/apps/centrifugo/registry.py +106 -0
- django_cfg/apps/centrifugo/router.py +125 -0
- django_cfg/apps/centrifugo/serializers/__init__.py +40 -0
- django_cfg/apps/centrifugo/serializers/admin_api.py +264 -0
- django_cfg/apps/centrifugo/serializers/channels.py +26 -0
- django_cfg/apps/centrifugo/serializers/health.py +17 -0
- django_cfg/apps/centrifugo/serializers/publishes.py +16 -0
- django_cfg/apps/centrifugo/serializers/stats.py +21 -0
- django_cfg/apps/centrifugo/services/__init__.py +12 -0
- django_cfg/apps/centrifugo/services/client/__init__.py +29 -0
- django_cfg/apps/centrifugo/services/client/client.py +577 -0
- django_cfg/apps/centrifugo/services/client/config.py +228 -0
- django_cfg/apps/centrifugo/services/client/exceptions.py +212 -0
- django_cfg/apps/centrifugo/services/config_helper.py +63 -0
- django_cfg/apps/centrifugo/services/dashboard_notifier.py +157 -0
- django_cfg/apps/centrifugo/services/logging.py +677 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/css/dashboard.css +260 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_channels.mjs +313 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_testing.mjs +803 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/main.mjs +333 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/overview.mjs +432 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/testing.mjs +33 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/websocket.mjs +210 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/channels_content.html +46 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/live_channels_content.html +123 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/overview_content.html +45 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/publishes_content.html +84 -0
- django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/stat_cards.html +23 -20
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/system_status.html +91 -0
- django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/tab_navigation.html +15 -15
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +415 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/layout/base.html +61 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/pages/dashboard.html +58 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/tags/connection_script.html +48 -0
- django_cfg/apps/centrifugo/templatetags/__init__.py +1 -0
- django_cfg/apps/centrifugo/templatetags/centrifugo_tags.py +81 -0
- django_cfg/apps/centrifugo/urls.py +31 -0
- django_cfg/apps/{ipc → centrifugo}/urls_admin.py +4 -4
- django_cfg/apps/centrifugo/views/__init__.py +15 -0
- django_cfg/apps/centrifugo/views/admin_api.py +374 -0
- django_cfg/apps/centrifugo/views/dashboard.py +15 -0
- django_cfg/apps/centrifugo/views/monitoring.py +286 -0
- django_cfg/apps/centrifugo/views/testing_api.py +422 -0
- django_cfg/apps/support/utils/support_email_service.py +5 -18
- django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -2
- django_cfg/apps/urls.py +5 -5
- django_cfg/core/base/config_model.py +4 -44
- django_cfg/core/builders/apps_builder.py +2 -2
- django_cfg/core/generation/integration_generators/third_party.py +8 -8
- django_cfg/core/utils/__init__.py +5 -0
- django_cfg/core/utils/url_helpers.py +73 -0
- django_cfg/modules/base.py +7 -7
- django_cfg/modules/django_client/core/__init__.py +2 -1
- django_cfg/modules/django_client/core/config/config.py +8 -0
- django_cfg/modules/django_client/core/generator/__init__.py +42 -2
- django_cfg/modules/django_client/core/generator/go/__init__.py +14 -0
- django_cfg/modules/django_client/core/generator/go/client_generator.py +124 -0
- django_cfg/modules/django_client/core/generator/go/files_generator.py +133 -0
- django_cfg/modules/django_client/core/generator/go/generator.py +203 -0
- django_cfg/modules/django_client/core/generator/go/models_generator.py +304 -0
- django_cfg/modules/django_client/core/generator/go/naming.py +193 -0
- django_cfg/modules/django_client/core/generator/go/operations_generator.py +134 -0
- django_cfg/modules/django_client/core/generator/go/templates/Makefile.j2 +38 -0
- django_cfg/modules/django_client/core/generator/go/templates/README.md.j2 +55 -0
- django_cfg/modules/django_client/core/generator/go/templates/client.go.j2 +122 -0
- django_cfg/modules/django_client/core/generator/go/templates/enums.go.j2 +49 -0
- django_cfg/modules/django_client/core/generator/go/templates/errors.go.j2 +182 -0
- django_cfg/modules/django_client/core/generator/go/templates/go.mod.j2 +6 -0
- django_cfg/modules/django_client/core/generator/go/templates/main_client.go.j2 +60 -0
- django_cfg/modules/django_client/core/generator/go/templates/middleware.go.j2 +388 -0
- django_cfg/modules/django_client/core/generator/go/templates/models.go.j2 +28 -0
- django_cfg/modules/django_client/core/generator/go/templates/operations_client.go.j2 +142 -0
- django_cfg/modules/django_client/core/generator/go/templates/validation.go.j2 +217 -0
- django_cfg/modules/django_client/core/generator/go/type_mapper.py +380 -0
- django_cfg/modules/django_client/management/commands/generate_client.py +53 -3
- django_cfg/modules/django_client/system/generate_mjs_clients.py +3 -1
- django_cfg/modules/django_client/system/schema_parser.py +5 -1
- django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +1 -0
- django_cfg/modules/django_twilio/sendgrid_service.py +7 -4
- django_cfg/modules/django_unfold/dashboard.py +25 -19
- django_cfg/pyproject.toml +1 -1
- django_cfg/registry/core.py +2 -0
- django_cfg/registry/modules.py +2 -2
- django_cfg/static/js/api/centrifugo/client.mjs +164 -0
- django_cfg/static/js/api/centrifugo/index.mjs +13 -0
- django_cfg/static/js/api/index.mjs +5 -5
- django_cfg/static/js/api/types.mjs +89 -26
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/METADATA +1 -1
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/RECORD +142 -70
- django_cfg/apps/ipc/README.md +0 -346
- django_cfg/apps/ipc/RPC_LOGGING.md +0 -321
- django_cfg/apps/ipc/TESTING.md +0 -539
- django_cfg/apps/ipc/__init__.py +0 -60
- django_cfg/apps/ipc/admin.py +0 -232
- django_cfg/apps/ipc/apps.py +0 -98
- django_cfg/apps/ipc/migrations/0001_initial.py +0 -137
- django_cfg/apps/ipc/migrations/0002_rpclog_is_event.py +0 -23
- django_cfg/apps/ipc/migrations/__init__.py +0 -0
- django_cfg/apps/ipc/models.py +0 -229
- django_cfg/apps/ipc/serializers/__init__.py +0 -29
- django_cfg/apps/ipc/serializers/serializers.py +0 -343
- django_cfg/apps/ipc/services/__init__.py +0 -7
- django_cfg/apps/ipc/services/client/__init__.py +0 -23
- django_cfg/apps/ipc/services/client/client.py +0 -621
- django_cfg/apps/ipc/services/client/config.py +0 -214
- django_cfg/apps/ipc/services/client/exceptions.py +0 -201
- django_cfg/apps/ipc/services/logging.py +0 -239
- django_cfg/apps/ipc/services/monitor.py +0 -466
- django_cfg/apps/ipc/services/rpc_log_consumer.py +0 -330
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/main.mjs +0 -269
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/overview.mjs +0 -259
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/testing.mjs +0 -375
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard.mjs.old +0 -441
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/methods_content.html +0 -22
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/notifications_content.html +0 -9
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/overview_content.html +0 -9
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/requests_content.html +0 -23
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/system_status.html +0 -47
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/testing_tools.html +0 -184
- django_cfg/apps/ipc/templates/django_cfg_ipc/layout/base.html +0 -71
- django_cfg/apps/ipc/templates/django_cfg_ipc/pages/dashboard.html +0 -56
- django_cfg/apps/ipc/urls.py +0 -23
- django_cfg/apps/ipc/views/__init__.py +0 -13
- django_cfg/apps/ipc/views/dashboard.py +0 -15
- django_cfg/apps/ipc/views/monitoring.py +0 -251
- django_cfg/apps/ipc/views/testing.py +0 -285
- django_cfg/static/js/api/ipc/client.mjs +0 -114
- django_cfg/static/js/api/ipc/index.mjs +0 -13
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,6 +6,7 @@ import logging
|
|
|
6
6
|
|
|
7
7
|
from django.contrib.auth import get_user_model
|
|
8
8
|
|
|
9
|
+
from django_cfg.core.utils import get_ticket_url
|
|
9
10
|
from django_cfg.modules.django_email import DjangoEmailService
|
|
10
11
|
|
|
11
12
|
User = get_user_model()
|
|
@@ -18,20 +19,6 @@ class SupportEmailService:
|
|
|
18
19
|
def __init__(self, user: User):
|
|
19
20
|
self.user = user
|
|
20
21
|
|
|
21
|
-
def _get_ticket_url(self, ticket_uuid: str) -> str:
|
|
22
|
-
"""Get ticket URL from configuration."""
|
|
23
|
-
try:
|
|
24
|
-
from django_cfg.core.state import get_current_config
|
|
25
|
-
config = get_current_config()
|
|
26
|
-
if config and hasattr(config, 'get_ticket_url'):
|
|
27
|
-
return config.get_ticket_url(str(ticket_uuid))
|
|
28
|
-
else:
|
|
29
|
-
# Fallback URL if config is not available
|
|
30
|
-
return f"#ticket-{ticket_uuid}"
|
|
31
|
-
except Exception as e:
|
|
32
|
-
logger.warning(f"Could not generate ticket URL: {e}")
|
|
33
|
-
return f"#ticket-{ticket_uuid}"
|
|
34
|
-
|
|
35
22
|
def _send_email(
|
|
36
23
|
self,
|
|
37
24
|
subject: str,
|
|
@@ -72,7 +59,7 @@ class SupportEmailService:
|
|
|
72
59
|
main_html_content=f'<div style="background: #e8f5e8; padding: 15px; border-left: 4px solid #28a745; margin: 15px 0;"><strong>Ticket #{ticket.uuid.hex[:8]}</strong><br><strong>Subject:</strong> {ticket.subject}</div>',
|
|
73
60
|
secondary_text="You will receive email notifications when our support team replies to your ticket.",
|
|
74
61
|
button_text="View Ticket",
|
|
75
|
-
button_url=
|
|
62
|
+
button_url=get_ticket_url(str(ticket.uuid)),
|
|
76
63
|
)
|
|
77
64
|
|
|
78
65
|
def send_support_reply_email(self, message):
|
|
@@ -89,7 +76,7 @@ class SupportEmailService:
|
|
|
89
76
|
main_html_content=f'<div style="background: #f8f9fa; padding: 15px; border-left: 4px solid #007bff; margin: 15px 0;"><strong>Support Reply:</strong><br>{message.text}</div>',
|
|
90
77
|
secondary_text="Please reply to continue the conversation. We're here to help!",
|
|
91
78
|
button_text="View & Reply",
|
|
92
|
-
button_url=
|
|
79
|
+
button_url=get_ticket_url(str(ticket.uuid)),
|
|
93
80
|
)
|
|
94
81
|
|
|
95
82
|
def send_ticket_status_changed_email(self, ticket, old_status, new_status):
|
|
@@ -109,7 +96,7 @@ class SupportEmailService:
|
|
|
109
96
|
main_html_content=f'<div style="background: #f8f9fa; padding: 15px; border-left: 4px solid {color}; margin: 15px 0;"><strong>Status Update:</strong><br>From: <span style="color: #6c757d;">{old_status}</span><br>To: <span style="color: {color}; font-weight: bold;">{new_status}</span></div>',
|
|
110
97
|
secondary_text="If you have any questions about this status change, please reply to your ticket.",
|
|
111
98
|
button_text="View Ticket",
|
|
112
|
-
button_url=
|
|
99
|
+
button_url=get_ticket_url(str(ticket.uuid)),
|
|
113
100
|
)
|
|
114
101
|
|
|
115
102
|
def send_ticket_resolved_email(self, ticket):
|
|
@@ -120,5 +107,5 @@ class SupportEmailService:
|
|
|
120
107
|
main_html_content='<div style="background: #e8f5e8; padding: 15px; border-left: 4px solid #28a745; margin: 15px 0;"><strong>✅ Ticket Resolved</strong><br>Your issue has been successfully resolved by our support team.</div>',
|
|
121
108
|
secondary_text="If you're satisfied with the resolution, no further action is needed. If you need additional help, feel free to reply to reopen the ticket.",
|
|
122
109
|
button_text="View Resolution",
|
|
123
|
-
button_url=
|
|
110
|
+
button_url=get_ticket_url(str(ticket.uuid)),
|
|
124
111
|
)
|
|
@@ -12,8 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
{% block extra_head %}
|
|
14
14
|
{{ block.super }}
|
|
15
|
-
<!-- Material Icons -->
|
|
16
|
-
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
17
15
|
|
|
18
16
|
<!-- Custom CSS -->
|
|
19
17
|
<link rel="stylesheet" href="{% static 'tasks/css/dashboard.css' %}">
|
django_cfg/apps/urls.py
CHANGED
|
@@ -50,8 +50,8 @@ def get_enabled_cfg_apps() -> List[str]:
|
|
|
50
50
|
if base_module.is_payments_enabled():
|
|
51
51
|
enabled_apps.append("django_cfg.apps.payments")
|
|
52
52
|
|
|
53
|
-
if base_module.
|
|
54
|
-
enabled_apps.append("django_cfg.apps.
|
|
53
|
+
if base_module.is_centrifugo_enabled():
|
|
54
|
+
enabled_apps.append("django_cfg.apps.centrifugo")
|
|
55
55
|
|
|
56
56
|
return enabled_apps
|
|
57
57
|
|
|
@@ -166,9 +166,9 @@ APP_URL_MAP = {
|
|
|
166
166
|
("cfg/payments/", "django_cfg.apps.payments.urls"),
|
|
167
167
|
# Payments v2.0: No separate urls_admin (uses Django Admin only)
|
|
168
168
|
],
|
|
169
|
-
"django_cfg.apps.
|
|
170
|
-
("cfg/
|
|
171
|
-
("cfg/
|
|
169
|
+
"django_cfg.apps.centrifugo": [
|
|
170
|
+
("cfg/centrifugo/", "django_cfg.apps.centrifugo.urls"),
|
|
171
|
+
("cfg/centrifugo/admin/", "django_cfg.apps.centrifugo.urls_admin"),
|
|
172
172
|
],
|
|
173
173
|
}
|
|
174
174
|
|
|
@@ -15,7 +15,7 @@ from typing import Any, Dict, List, Optional
|
|
|
15
15
|
|
|
16
16
|
from pydantic import BaseModel, Field, PrivateAttr, field_validator, model_validator
|
|
17
17
|
|
|
18
|
-
from ...apps.
|
|
18
|
+
from ...apps.centrifugo.services.client.config import DjangoCfgCentrifugoConfig
|
|
19
19
|
from ...models import (
|
|
20
20
|
ApiKeys,
|
|
21
21
|
AxesConfig,
|
|
@@ -165,16 +165,6 @@ class DjangoConfig(BaseModel):
|
|
|
165
165
|
description="Backend API URL",
|
|
166
166
|
)
|
|
167
167
|
|
|
168
|
-
ticket_url: str = Field(
|
|
169
|
-
default="{site_url}/support/ticket/{uuid}",
|
|
170
|
-
description="Support ticket URL template. Use {site_url} and {uuid} placeholders",
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
otp_url: str = Field(
|
|
174
|
-
default="{site_url}/auth/otp/{code}",
|
|
175
|
-
description="OTP verification URL template. Use {site_url} and {code} placeholders",
|
|
176
|
-
)
|
|
177
|
-
|
|
178
168
|
# === Core Django Settings ===
|
|
179
169
|
secret_key: str = Field(
|
|
180
170
|
...,
|
|
@@ -316,10 +306,10 @@ class DjangoConfig(BaseModel):
|
|
|
316
306
|
description="Background task processing configuration (Dramatiq)",
|
|
317
307
|
)
|
|
318
308
|
|
|
319
|
-
# ===
|
|
320
|
-
|
|
309
|
+
# === Centrifugo Configuration ===
|
|
310
|
+
centrifugo: Optional[DjangoCfgCentrifugoConfig] = Field(
|
|
321
311
|
default=None,
|
|
322
|
-
description="
|
|
312
|
+
description="Centrifugo pub/sub configuration (WebSocket notifications with ACK tracking)",
|
|
323
313
|
)
|
|
324
314
|
|
|
325
315
|
# === API Configuration ===
|
|
@@ -568,36 +558,6 @@ class DjangoConfig(BaseModel):
|
|
|
568
558
|
|
|
569
559
|
return self._django_settings
|
|
570
560
|
|
|
571
|
-
def get_ticket_url(self, ticket_uuid: str) -> str:
|
|
572
|
-
"""
|
|
573
|
-
Generate ticket URL using the configured template.
|
|
574
|
-
|
|
575
|
-
Args:
|
|
576
|
-
ticket_uuid: UUID of the support ticket
|
|
577
|
-
|
|
578
|
-
Returns:
|
|
579
|
-
Complete URL to the ticket
|
|
580
|
-
"""
|
|
581
|
-
return self.ticket_url.format(
|
|
582
|
-
site_url=self.site_url,
|
|
583
|
-
uuid=ticket_uuid,
|
|
584
|
-
)
|
|
585
|
-
|
|
586
|
-
def get_otp_url(self, otp_code: str) -> str:
|
|
587
|
-
"""
|
|
588
|
-
Generate OTP verification URL using the configured template.
|
|
589
|
-
|
|
590
|
-
Args:
|
|
591
|
-
otp_code: OTP verification code
|
|
592
|
-
|
|
593
|
-
Returns:
|
|
594
|
-
Complete URL to the OTP verification page
|
|
595
|
-
"""
|
|
596
|
-
return self.otp_url.format(
|
|
597
|
-
site_url=self.site_url,
|
|
598
|
-
code=otp_code,
|
|
599
|
-
)
|
|
600
|
-
|
|
601
561
|
def invalidate_cache(self) -> None:
|
|
602
562
|
"""
|
|
603
563
|
Invalidate cached Django settings.
|
|
@@ -133,8 +133,8 @@ class InstalledAppsBuilder:
|
|
|
133
133
|
if self.config.payments and self.config.payments.enabled:
|
|
134
134
|
apps.append("django_cfg.apps.payments")
|
|
135
135
|
|
|
136
|
-
if self.config.
|
|
137
|
-
apps.append("django_cfg.apps.
|
|
136
|
+
if self.config.centrifugo and self.config.centrifugo.enabled:
|
|
137
|
+
apps.append("django_cfg.apps.centrifugo")
|
|
138
138
|
|
|
139
139
|
return apps
|
|
140
140
|
|
|
@@ -60,7 +60,7 @@ class ThirdPartyIntegrationsGenerator:
|
|
|
60
60
|
settings.update(self._generate_telegram_settings())
|
|
61
61
|
settings.update(self._generate_unfold_settings())
|
|
62
62
|
settings.update(self._generate_constance_settings())
|
|
63
|
-
settings.update(self.
|
|
63
|
+
settings.update(self._generate_centrifugo_settings())
|
|
64
64
|
|
|
65
65
|
# Track enabled integrations
|
|
66
66
|
if self.integrations:
|
|
@@ -116,20 +116,20 @@ class ThirdPartyIntegrationsGenerator:
|
|
|
116
116
|
|
|
117
117
|
return constance_settings
|
|
118
118
|
|
|
119
|
-
def
|
|
119
|
+
def _generate_centrifugo_settings(self) -> Dict[str, Any]:
|
|
120
120
|
"""
|
|
121
|
-
Generate
|
|
121
|
+
Generate Centrifugo settings.
|
|
122
122
|
|
|
123
123
|
Returns:
|
|
124
|
-
Dictionary with
|
|
124
|
+
Dictionary with Centrifugo configuration
|
|
125
125
|
"""
|
|
126
|
-
if not hasattr(self.config, "
|
|
126
|
+
if not hasattr(self.config, "centrifugo") or not self.config.centrifugo:
|
|
127
127
|
return {}
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
self.integrations.append("
|
|
129
|
+
centrifugo_settings = self.config.centrifugo.to_django_settings()
|
|
130
|
+
self.integrations.append("centrifugo")
|
|
131
131
|
|
|
132
|
-
return
|
|
132
|
+
return centrifugo_settings
|
|
133
133
|
|
|
134
134
|
def get_enabled_integrations(self) -> List[str]:
|
|
135
135
|
"""
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
URL generation utilities for django-cfg.
|
|
3
|
+
|
|
4
|
+
Provides helper functions to generate URLs dynamically from site_url configuration.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_ticket_url(ticket_uuid: str, fallback: str = "#ticket") -> str:
|
|
14
|
+
"""
|
|
15
|
+
Generate support ticket URL on the fly from site_url.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
ticket_uuid: UUID of the support ticket
|
|
19
|
+
fallback: Fallback URL if config is not available (default: "#ticket")
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Complete URL to the ticket
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
>>> get_ticket_url("abc-123-def")
|
|
26
|
+
"https://yoursite.com/support/ticket/abc-123-def"
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
from django_cfg.core.state import get_current_config
|
|
30
|
+
config = get_current_config()
|
|
31
|
+
|
|
32
|
+
if config and hasattr(config, 'site_url'):
|
|
33
|
+
return f"{config.site_url}/support/ticket/{ticket_uuid}"
|
|
34
|
+
else:
|
|
35
|
+
logger.warning("Config or site_url not available for ticket URL generation")
|
|
36
|
+
return f"{fallback}-{ticket_uuid}"
|
|
37
|
+
|
|
38
|
+
except Exception as e:
|
|
39
|
+
logger.warning(f"Could not generate ticket URL: {e}")
|
|
40
|
+
return f"{fallback}-{ticket_uuid}"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_otp_url(otp_code: str, fallback: str = "#otp") -> str:
|
|
44
|
+
"""
|
|
45
|
+
Generate OTP verification URL on the fly from site_url.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
otp_code: OTP verification code
|
|
49
|
+
fallback: Fallback URL if config is not available (default: "#otp")
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Complete URL to the OTP verification page
|
|
53
|
+
|
|
54
|
+
Example:
|
|
55
|
+
>>> get_otp_url("123456")
|
|
56
|
+
"https://yoursite.com/auth/?otp=123456"
|
|
57
|
+
"""
|
|
58
|
+
try:
|
|
59
|
+
from django_cfg.core.state import get_current_config
|
|
60
|
+
config = get_current_config()
|
|
61
|
+
|
|
62
|
+
if config and hasattr(config, 'site_url'):
|
|
63
|
+
return f"{config.site_url}/auth/?otp={otp_code}"
|
|
64
|
+
else:
|
|
65
|
+
logger.warning("Config or site_url not available for OTP URL generation")
|
|
66
|
+
return f"{fallback}-{otp_code}"
|
|
67
|
+
|
|
68
|
+
except Exception as e:
|
|
69
|
+
logger.warning(f"Could not generate OTP URL: {e}")
|
|
70
|
+
return f"{fallback}-{otp_code}"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
__all__ = ["get_ticket_url", "get_otp_url"]
|
django_cfg/modules/base.py
CHANGED
|
@@ -191,18 +191,18 @@ class BaseCfgModule(ABC):
|
|
|
191
191
|
|
|
192
192
|
return False
|
|
193
193
|
|
|
194
|
-
def
|
|
194
|
+
def is_centrifugo_enabled(self) -> bool:
|
|
195
195
|
"""
|
|
196
|
-
Check if django-cfg
|
|
196
|
+
Check if django-cfg Centrifugo is enabled.
|
|
197
197
|
|
|
198
198
|
Returns:
|
|
199
|
-
True if
|
|
199
|
+
True if Centrifugo is enabled, False otherwise
|
|
200
200
|
"""
|
|
201
|
-
|
|
201
|
+
centrifugo_config = self._get_config_key('centrifugo', None)
|
|
202
202
|
|
|
203
|
-
#
|
|
204
|
-
if
|
|
205
|
-
return
|
|
203
|
+
# Check if centrifugo config exists and is enabled
|
|
204
|
+
if centrifugo_config and hasattr(centrifugo_config, 'enabled'):
|
|
205
|
+
return centrifugo_config.enabled
|
|
206
206
|
|
|
207
207
|
return False
|
|
208
208
|
|
|
@@ -19,7 +19,7 @@ from .config import (
|
|
|
19
19
|
)
|
|
20
20
|
|
|
21
21
|
# Generators
|
|
22
|
-
from .generator import PythonGenerator, TypeScriptGenerator
|
|
22
|
+
from .generator import GoGenerator, PythonGenerator, TypeScriptGenerator
|
|
23
23
|
|
|
24
24
|
# Groups
|
|
25
25
|
from .groups import GroupDetector, GroupManager
|
|
@@ -52,4 +52,5 @@ __all__ = [
|
|
|
52
52
|
"OpenAPI31Parser",
|
|
53
53
|
"PythonGenerator",
|
|
54
54
|
"TypeScriptGenerator",
|
|
55
|
+
"GoGenerator",
|
|
55
56
|
]
|
|
@@ -188,6 +188,10 @@ class OpenAPIConfig(BaseModel):
|
|
|
188
188
|
"""Get TypeScript clients directory path."""
|
|
189
189
|
return self.get_clients_dir() / "typescript"
|
|
190
190
|
|
|
191
|
+
def get_go_clients_dir(self) -> Path:
|
|
192
|
+
"""Get Go clients directory path."""
|
|
193
|
+
return self.get_clients_dir() / "go"
|
|
194
|
+
|
|
191
195
|
def get_archive_dir(self) -> Path:
|
|
192
196
|
"""Get archive directory path."""
|
|
193
197
|
return self.get_output_path() / "archive"
|
|
@@ -204,6 +208,10 @@ class OpenAPIConfig(BaseModel):
|
|
|
204
208
|
"""Get TypeScript client directory for a group."""
|
|
205
209
|
return self.get_typescript_clients_dir() / group_name
|
|
206
210
|
|
|
211
|
+
def get_group_go_dir(self, group_name: str) -> Path:
|
|
212
|
+
"""Get Go client directory for a group."""
|
|
213
|
+
return self.get_go_clients_dir() / group_name
|
|
214
|
+
|
|
207
215
|
|
|
208
216
|
__all__ = [
|
|
209
217
|
"OpenAPIConfig",
|
|
@@ -24,15 +24,18 @@ from typing import Literal
|
|
|
24
24
|
|
|
25
25
|
from ..ir import IRContext
|
|
26
26
|
from .base import GeneratedFile
|
|
27
|
+
from .go import GoGenerator
|
|
27
28
|
from .python import PythonGenerator
|
|
28
29
|
from .typescript import TypeScriptGenerator
|
|
29
30
|
|
|
30
31
|
__all__ = [
|
|
31
32
|
"PythonGenerator",
|
|
32
33
|
"TypeScriptGenerator",
|
|
34
|
+
"GoGenerator",
|
|
33
35
|
"GeneratedFile",
|
|
34
36
|
"generate_python",
|
|
35
37
|
"generate_typescript",
|
|
38
|
+
"generate_go",
|
|
36
39
|
"generate_client",
|
|
37
40
|
]
|
|
38
41
|
|
|
@@ -87,18 +90,52 @@ def generate_typescript(context: IRContext, output_dir: Path | None = None) -> l
|
|
|
87
90
|
return files
|
|
88
91
|
|
|
89
92
|
|
|
93
|
+
def generate_go(context: IRContext, output_dir: Path | None = None, **kwargs) -> list[GeneratedFile]:
|
|
94
|
+
"""
|
|
95
|
+
Generate Go client from IR.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
context: IRContext from parser
|
|
99
|
+
output_dir: Optional output directory (saves files if provided)
|
|
100
|
+
**kwargs: Additional options (client_structure, package_config, etc.)
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
List of GeneratedFile objects
|
|
104
|
+
|
|
105
|
+
Examples:
|
|
106
|
+
>>> files = generate_go(context)
|
|
107
|
+
>>> # Or save directly
|
|
108
|
+
>>> files = generate_go(context, output_dir=Path("./generated/go"))
|
|
109
|
+
>>> # With custom package config
|
|
110
|
+
>>> files = generate_go(
|
|
111
|
+
... context,
|
|
112
|
+
... package_config={"module_name": "github.com/user/api-client"},
|
|
113
|
+
... generate_package_files=True
|
|
114
|
+
... )
|
|
115
|
+
"""
|
|
116
|
+
generator = GoGenerator(context, **kwargs)
|
|
117
|
+
files = generator.generate()
|
|
118
|
+
|
|
119
|
+
if output_dir:
|
|
120
|
+
generator.save_files(files, output_dir)
|
|
121
|
+
|
|
122
|
+
return files
|
|
123
|
+
|
|
124
|
+
|
|
90
125
|
def generate_client(
|
|
91
126
|
context: IRContext,
|
|
92
|
-
language: Literal["python", "typescript"],
|
|
127
|
+
language: Literal["python", "typescript", "go"],
|
|
93
128
|
output_dir: Path | None = None,
|
|
129
|
+
**kwargs,
|
|
94
130
|
) -> list[GeneratedFile]:
|
|
95
131
|
"""
|
|
96
132
|
Generate client for specified language.
|
|
97
133
|
|
|
98
134
|
Args:
|
|
99
135
|
context: IRContext from parser
|
|
100
|
-
language: Target language ('python' or '
|
|
136
|
+
language: Target language ('python', 'typescript', or 'go')
|
|
101
137
|
output_dir: Optional output directory
|
|
138
|
+
**kwargs: Additional language-specific options
|
|
102
139
|
|
|
103
140
|
Returns:
|
|
104
141
|
List of GeneratedFile objects
|
|
@@ -106,10 +143,13 @@ def generate_client(
|
|
|
106
143
|
Examples:
|
|
107
144
|
>>> files = generate_client(context, "python")
|
|
108
145
|
>>> files = generate_client(context, "typescript", Path("./generated"))
|
|
146
|
+
>>> files = generate_client(context, "go", Path("./generated"), generate_package_files=True)
|
|
109
147
|
"""
|
|
110
148
|
if language == "python":
|
|
111
149
|
return generate_python(context, output_dir)
|
|
112
150
|
elif language == "typescript":
|
|
113
151
|
return generate_typescript(context, output_dir)
|
|
152
|
+
elif language == "go":
|
|
153
|
+
return generate_go(context, output_dir, **kwargs)
|
|
114
154
|
else:
|
|
115
155
|
raise ValueError(f"Unsupported language: {language}")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Go Generator - Generates Go client (net/http).
|
|
3
|
+
|
|
4
|
+
This generator creates a complete Go API client from IR:
|
|
5
|
+
- Go structs (Request/Response/Patch splits)
|
|
6
|
+
- Enum types with constants
|
|
7
|
+
- net/http client for HTTP requests
|
|
8
|
+
- Type-safe operations
|
|
9
|
+
- Context-aware requests
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from .generator import GoGenerator
|
|
13
|
+
|
|
14
|
+
__all__ = ['GoGenerator']
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Client Generator - Generates Go HTTP client with operations.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from .naming import to_pascal_case
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from jinja2 import Environment
|
|
14
|
+
|
|
15
|
+
from ...ir import IRContext
|
|
16
|
+
from ..base import GeneratedFile
|
|
17
|
+
from .generator import GoGenerator
|
|
18
|
+
from .operations_generator import OperationsGenerator
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ClientGenerator:
|
|
22
|
+
"""Generates Go HTTP client code."""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
jinja_env: Environment,
|
|
27
|
+
context: IRContext,
|
|
28
|
+
generator: GoGenerator,
|
|
29
|
+
operations_gen: OperationsGenerator,
|
|
30
|
+
):
|
|
31
|
+
"""Initialize client generator."""
|
|
32
|
+
self.jinja_env = jinja_env
|
|
33
|
+
self.context = context
|
|
34
|
+
self.generator = generator
|
|
35
|
+
self.operations_gen = operations_gen
|
|
36
|
+
|
|
37
|
+
def generate_client_file(self) -> GeneratedFile:
|
|
38
|
+
"""Generate client.go with HTTP client and all operations."""
|
|
39
|
+
template = self.jinja_env.get_template("client.go.j2")
|
|
40
|
+
|
|
41
|
+
# Generate all operation methods
|
|
42
|
+
operations = []
|
|
43
|
+
for op_id, operation in sorted(self.context.operations.items()):
|
|
44
|
+
op_method = self.operations_gen.generate_operation_method(operation)
|
|
45
|
+
operations.append(op_method)
|
|
46
|
+
|
|
47
|
+
content = template.render(
|
|
48
|
+
package_name=self.generator.package_name,
|
|
49
|
+
operations=operations,
|
|
50
|
+
generated_at=datetime.now().isoformat(),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return self.generator._create_generated_file(
|
|
54
|
+
path="client.go",
|
|
55
|
+
content=content,
|
|
56
|
+
description="HTTP API client"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def generate_main_client_file(self, ops_by_tag: dict) -> GeneratedFile:
|
|
60
|
+
"""Generate main client.go for namespaced structure."""
|
|
61
|
+
template = self.jinja_env.get_template("main_client.go.j2")
|
|
62
|
+
|
|
63
|
+
subclients = []
|
|
64
|
+
for tag in sorted(ops_by_tag.keys()):
|
|
65
|
+
folder_name = self.generator.tag_and_app_to_folder_name(tag, ops_by_tag[tag])
|
|
66
|
+
subclients.append({
|
|
67
|
+
"name": to_pascal_case(folder_name),
|
|
68
|
+
"package": folder_name,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
content = template.render(
|
|
72
|
+
package_name=self.generator.package_name,
|
|
73
|
+
module_name=self.generator.package_config.get("module_name", "apiclient"),
|
|
74
|
+
subclients=subclients,
|
|
75
|
+
generated_at=datetime.now().isoformat(),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
return self.generator._create_generated_file(
|
|
79
|
+
path="client.go",
|
|
80
|
+
content=content,
|
|
81
|
+
description="Main API client"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def generate_subpackage_client_file(self, tag: str, operations: list) -> GeneratedFile:
|
|
85
|
+
"""Generate client.go for a specific subpackage with its operations."""
|
|
86
|
+
template = self.jinja_env.get_template("operations_client.go.j2")
|
|
87
|
+
|
|
88
|
+
# Get folder name for this tag
|
|
89
|
+
folder_name = self.generator.tag_and_app_to_folder_name(tag, operations)
|
|
90
|
+
|
|
91
|
+
# Generate operation methods for this tag
|
|
92
|
+
operation_methods = []
|
|
93
|
+
has_request_body = False
|
|
94
|
+
has_query_params = False
|
|
95
|
+
has_path_params = False
|
|
96
|
+
|
|
97
|
+
for operation in sorted(operations, key=lambda op: op.operation_id):
|
|
98
|
+
op_method = self.operations_gen.generate_operation_method(operation, remove_tag_prefix=True)
|
|
99
|
+
operation_methods.append(op_method)
|
|
100
|
+
|
|
101
|
+
# Check what imports we need
|
|
102
|
+
if op_method.get("request_type"):
|
|
103
|
+
has_request_body = True
|
|
104
|
+
if any(p.get("location") == "query" for p in op_method.get("parameters", [])):
|
|
105
|
+
has_query_params = True
|
|
106
|
+
if any(p.get("location") == "path" for p in op_method.get("parameters", [])):
|
|
107
|
+
has_path_params = True
|
|
108
|
+
|
|
109
|
+
content = template.render(
|
|
110
|
+
package_name=folder_name,
|
|
111
|
+
module_name=self.generator.package_config.get("module_name", "apiclient"),
|
|
112
|
+
parent_package=self.generator.package_name,
|
|
113
|
+
operations=operation_methods,
|
|
114
|
+
has_request_body=has_request_body,
|
|
115
|
+
has_query_params=has_query_params,
|
|
116
|
+
has_path_params=has_path_params,
|
|
117
|
+
generated_at=datetime.now().isoformat(),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
return self.generator._create_generated_file(
|
|
121
|
+
path=f"{folder_name}/client.go",
|
|
122
|
+
content=content,
|
|
123
|
+
description=f"HTTP client for {tag}"
|
|
124
|
+
)
|