django-cfg 1.4.61__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.

Files changed (179) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/services/otp_service.py +3 -14
  3. django_cfg/apps/centrifugo/__init__.py +57 -0
  4. django_cfg/apps/centrifugo/admin/__init__.py +13 -0
  5. django_cfg/apps/centrifugo/admin/centrifugo_log.py +249 -0
  6. django_cfg/apps/centrifugo/admin/config.py +82 -0
  7. django_cfg/apps/centrifugo/apps.py +31 -0
  8. django_cfg/apps/centrifugo/codegen/IMPLEMENTATION_SUMMARY.md +475 -0
  9. django_cfg/apps/centrifugo/codegen/README.md +242 -0
  10. django_cfg/apps/centrifugo/codegen/USAGE.md +616 -0
  11. django_cfg/apps/centrifugo/codegen/__init__.py +19 -0
  12. django_cfg/apps/centrifugo/codegen/discovery.py +246 -0
  13. django_cfg/apps/centrifugo/codegen/generators/go_thin/__init__.py +5 -0
  14. django_cfg/apps/centrifugo/codegen/generators/go_thin/generator.py +174 -0
  15. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/README.md.j2 +182 -0
  16. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/client.go.j2 +64 -0
  17. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/go.mod.j2 +10 -0
  18. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2 +300 -0
  19. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2.old +267 -0
  20. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/types.go.j2 +16 -0
  21. django_cfg/apps/centrifugo/codegen/generators/python_thin/__init__.py +7 -0
  22. django_cfg/apps/centrifugo/codegen/generators/python_thin/generator.py +241 -0
  23. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/README.md.j2 +128 -0
  24. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/__init__.py.j2 +22 -0
  25. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/client.py.j2 +73 -0
  26. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/models.py.j2 +19 -0
  27. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/requirements.txt.j2 +8 -0
  28. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/rpc_client.py.j2 +193 -0
  29. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/__init__.py +5 -0
  30. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/generator.py +124 -0
  31. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/README.md.j2 +38 -0
  32. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/client.ts.j2 +25 -0
  33. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/index.ts.j2 +12 -0
  34. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/package.json.j2 +13 -0
  35. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +137 -0
  36. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/tsconfig.json.j2 +14 -0
  37. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/types.ts.j2 +9 -0
  38. django_cfg/apps/centrifugo/codegen/utils/__init__.py +37 -0
  39. django_cfg/apps/centrifugo/codegen/utils/naming.py +155 -0
  40. django_cfg/apps/centrifugo/codegen/utils/type_converter.py +349 -0
  41. django_cfg/apps/centrifugo/decorators.py +137 -0
  42. django_cfg/apps/centrifugo/management/__init__.py +1 -0
  43. django_cfg/apps/centrifugo/management/commands/__init__.py +1 -0
  44. django_cfg/apps/centrifugo/management/commands/generate_centrifugo_clients.py +254 -0
  45. django_cfg/apps/centrifugo/managers/__init__.py +12 -0
  46. django_cfg/apps/centrifugo/managers/centrifugo_log.py +264 -0
  47. django_cfg/apps/centrifugo/migrations/0001_initial.py +164 -0
  48. django_cfg/apps/centrifugo/migrations/__init__.py +3 -0
  49. django_cfg/apps/centrifugo/models/__init__.py +11 -0
  50. django_cfg/apps/centrifugo/models/centrifugo_log.py +210 -0
  51. django_cfg/apps/centrifugo/registry.py +106 -0
  52. django_cfg/apps/centrifugo/router.py +125 -0
  53. django_cfg/apps/centrifugo/serializers/__init__.py +40 -0
  54. django_cfg/apps/centrifugo/serializers/admin_api.py +264 -0
  55. django_cfg/apps/centrifugo/serializers/channels.py +26 -0
  56. django_cfg/apps/centrifugo/serializers/health.py +17 -0
  57. django_cfg/apps/centrifugo/serializers/publishes.py +16 -0
  58. django_cfg/apps/centrifugo/serializers/stats.py +21 -0
  59. django_cfg/apps/centrifugo/services/__init__.py +12 -0
  60. django_cfg/apps/centrifugo/services/client/__init__.py +29 -0
  61. django_cfg/apps/centrifugo/services/client/client.py +577 -0
  62. django_cfg/apps/centrifugo/services/client/config.py +228 -0
  63. django_cfg/apps/centrifugo/services/client/exceptions.py +212 -0
  64. django_cfg/apps/centrifugo/services/config_helper.py +63 -0
  65. django_cfg/apps/centrifugo/services/dashboard_notifier.py +157 -0
  66. django_cfg/apps/centrifugo/services/logging.py +677 -0
  67. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/css/dashboard.css +260 -0
  68. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_channels.mjs +313 -0
  69. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_testing.mjs +803 -0
  70. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/main.mjs +333 -0
  71. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/overview.mjs +432 -0
  72. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/testing.mjs +33 -0
  73. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/websocket.mjs +210 -0
  74. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/channels_content.html +46 -0
  75. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/live_channels_content.html +123 -0
  76. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/overview_content.html +45 -0
  77. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/publishes_content.html +84 -0
  78. django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/stat_cards.html +23 -20
  79. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/system_status.html +91 -0
  80. django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/tab_navigation.html +15 -15
  81. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +415 -0
  82. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/layout/base.html +61 -0
  83. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/pages/dashboard.html +58 -0
  84. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/tags/connection_script.html +48 -0
  85. django_cfg/apps/centrifugo/templatetags/__init__.py +1 -0
  86. django_cfg/apps/centrifugo/templatetags/centrifugo_tags.py +81 -0
  87. django_cfg/apps/centrifugo/urls.py +31 -0
  88. django_cfg/apps/{ipc → centrifugo}/urls_admin.py +4 -4
  89. django_cfg/apps/centrifugo/views/__init__.py +15 -0
  90. django_cfg/apps/centrifugo/views/admin_api.py +374 -0
  91. django_cfg/apps/centrifugo/views/dashboard.py +15 -0
  92. django_cfg/apps/centrifugo/views/monitoring.py +286 -0
  93. django_cfg/apps/centrifugo/views/testing_api.py +422 -0
  94. django_cfg/apps/support/utils/support_email_service.py +5 -18
  95. django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -2
  96. django_cfg/apps/urls.py +5 -5
  97. django_cfg/core/base/config_model.py +4 -44
  98. django_cfg/core/builders/apps_builder.py +2 -2
  99. django_cfg/core/generation/integration_generators/third_party.py +8 -8
  100. django_cfg/core/utils/__init__.py +5 -0
  101. django_cfg/core/utils/url_helpers.py +73 -0
  102. django_cfg/modules/base.py +7 -7
  103. django_cfg/modules/django_client/core/__init__.py +2 -1
  104. django_cfg/modules/django_client/core/config/config.py +8 -0
  105. django_cfg/modules/django_client/core/generator/__init__.py +42 -2
  106. django_cfg/modules/django_client/core/generator/go/__init__.py +14 -0
  107. django_cfg/modules/django_client/core/generator/go/client_generator.py +124 -0
  108. django_cfg/modules/django_client/core/generator/go/files_generator.py +133 -0
  109. django_cfg/modules/django_client/core/generator/go/generator.py +203 -0
  110. django_cfg/modules/django_client/core/generator/go/models_generator.py +304 -0
  111. django_cfg/modules/django_client/core/generator/go/naming.py +193 -0
  112. django_cfg/modules/django_client/core/generator/go/operations_generator.py +134 -0
  113. django_cfg/modules/django_client/core/generator/go/templates/Makefile.j2 +38 -0
  114. django_cfg/modules/django_client/core/generator/go/templates/README.md.j2 +55 -0
  115. django_cfg/modules/django_client/core/generator/go/templates/client.go.j2 +122 -0
  116. django_cfg/modules/django_client/core/generator/go/templates/enums.go.j2 +49 -0
  117. django_cfg/modules/django_client/core/generator/go/templates/errors.go.j2 +182 -0
  118. django_cfg/modules/django_client/core/generator/go/templates/go.mod.j2 +6 -0
  119. django_cfg/modules/django_client/core/generator/go/templates/main_client.go.j2 +60 -0
  120. django_cfg/modules/django_client/core/generator/go/templates/middleware.go.j2 +388 -0
  121. django_cfg/modules/django_client/core/generator/go/templates/models.go.j2 +28 -0
  122. django_cfg/modules/django_client/core/generator/go/templates/operations_client.go.j2 +142 -0
  123. django_cfg/modules/django_client/core/generator/go/templates/validation.go.j2 +217 -0
  124. django_cfg/modules/django_client/core/generator/go/type_mapper.py +380 -0
  125. django_cfg/modules/django_client/management/commands/generate_client.py +53 -3
  126. django_cfg/modules/django_client/system/generate_mjs_clients.py +3 -1
  127. django_cfg/modules/django_client/system/schema_parser.py +5 -1
  128. django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +1 -0
  129. django_cfg/modules/django_twilio/sendgrid_service.py +7 -4
  130. django_cfg/modules/django_unfold/dashboard.py +25 -19
  131. django_cfg/pyproject.toml +1 -1
  132. django_cfg/registry/core.py +2 -0
  133. django_cfg/registry/modules.py +2 -2
  134. django_cfg/static/js/api/centrifugo/client.mjs +164 -0
  135. django_cfg/static/js/api/centrifugo/index.mjs +13 -0
  136. django_cfg/static/js/api/index.mjs +5 -5
  137. django_cfg/static/js/api/types.mjs +89 -26
  138. {django_cfg-1.4.61.dist-info → django_cfg-1.4.63.dist-info}/METADATA +1 -1
  139. {django_cfg-1.4.61.dist-info → django_cfg-1.4.63.dist-info}/RECORD +142 -68
  140. django_cfg/apps/ipc/README.md +0 -346
  141. django_cfg/apps/ipc/RPC_LOGGING.md +0 -321
  142. django_cfg/apps/ipc/TESTING.md +0 -539
  143. django_cfg/apps/ipc/__init__.py +0 -60
  144. django_cfg/apps/ipc/admin.py +0 -212
  145. django_cfg/apps/ipc/apps.py +0 -28
  146. django_cfg/apps/ipc/migrations/0001_initial.py +0 -137
  147. django_cfg/apps/ipc/migrations/__init__.py +0 -0
  148. django_cfg/apps/ipc/models.py +0 -221
  149. django_cfg/apps/ipc/serializers/__init__.py +0 -29
  150. django_cfg/apps/ipc/serializers/serializers.py +0 -343
  151. django_cfg/apps/ipc/services/__init__.py +0 -7
  152. django_cfg/apps/ipc/services/client/__init__.py +0 -23
  153. django_cfg/apps/ipc/services/client/client.py +0 -621
  154. django_cfg/apps/ipc/services/client/config.py +0 -214
  155. django_cfg/apps/ipc/services/client/exceptions.py +0 -201
  156. django_cfg/apps/ipc/services/logging.py +0 -239
  157. django_cfg/apps/ipc/services/monitor.py +0 -466
  158. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/main.mjs +0 -269
  159. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/overview.mjs +0 -259
  160. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/testing.mjs +0 -375
  161. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard.mjs.old +0 -441
  162. django_cfg/apps/ipc/templates/django_cfg_ipc/components/methods_content.html +0 -22
  163. django_cfg/apps/ipc/templates/django_cfg_ipc/components/notifications_content.html +0 -9
  164. django_cfg/apps/ipc/templates/django_cfg_ipc/components/overview_content.html +0 -9
  165. django_cfg/apps/ipc/templates/django_cfg_ipc/components/requests_content.html +0 -23
  166. django_cfg/apps/ipc/templates/django_cfg_ipc/components/system_status.html +0 -47
  167. django_cfg/apps/ipc/templates/django_cfg_ipc/components/testing_tools.html +0 -184
  168. django_cfg/apps/ipc/templates/django_cfg_ipc/layout/base.html +0 -71
  169. django_cfg/apps/ipc/templates/django_cfg_ipc/pages/dashboard.html +0 -56
  170. django_cfg/apps/ipc/urls.py +0 -23
  171. django_cfg/apps/ipc/views/__init__.py +0 -13
  172. django_cfg/apps/ipc/views/dashboard.py +0 -15
  173. django_cfg/apps/ipc/views/monitoring.py +0 -251
  174. django_cfg/apps/ipc/views/testing.py +0 -285
  175. django_cfg/static/js/api/ipc/client.mjs +0 -114
  176. django_cfg/static/js/api/ipc/index.mjs +0 -13
  177. {django_cfg-1.4.61.dist-info → django_cfg-1.4.63.dist-info}/WHEEL +0 -0
  178. {django_cfg-1.4.61.dist-info → django_cfg-1.4.63.dist-info}/entry_points.txt +0 -0
  179. {django_cfg-1.4.61.dist-info → django_cfg-1.4.63.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,193 @@
1
+ """
2
+ Naming conventions for Go code generation.
3
+
4
+ Handles conversions between Python/OpenAPI naming and Go naming conventions:
5
+ - snake_case → PascalCase (for exports)
6
+ - snake_case → camelCase (for unexported)
7
+ - Proper Go identifier sanitization
8
+ """
9
+
10
+ import re
11
+
12
+
13
+ def to_pascal_case(snake_str: str) -> str:
14
+ """
15
+ Convert snake_case to PascalCase.
16
+
17
+ Args:
18
+ snake_str: snake_case string
19
+
20
+ Returns:
21
+ PascalCase string
22
+
23
+ Examples:
24
+ >>> to_pascal_case("user_profile")
25
+ 'UserProfile'
26
+ >>> to_pascal_case("api_key_id")
27
+ 'APIKeyID'
28
+ >>> to_pascal_case("http_response")
29
+ 'HTTPResponse'
30
+ """
31
+ if not snake_str:
32
+ return ""
33
+
34
+ # Handle special acronyms that should be uppercase
35
+ acronyms = {'id', 'api', 'http', 'https', 'url', 'uri', 'json', 'xml', 'html', 'css', 'sql', 'uuid'}
36
+
37
+ # Split by underscore
38
+ parts = snake_str.split('_')
39
+
40
+ # Capitalize each part, with special handling for acronyms
41
+ result_parts = []
42
+ for part in parts:
43
+ if not part:
44
+ continue
45
+
46
+ # If entire part is an acronym, uppercase it
47
+ if part.lower() in acronyms:
48
+ result_parts.append(part.upper())
49
+ else:
50
+ # Check if part ends with an acronym
51
+ found_acronym = False
52
+ for acronym in acronyms:
53
+ if part.lower().endswith(acronym):
54
+ # Split off the acronym
55
+ prefix = part[:-len(acronym)]
56
+ if prefix:
57
+ result_parts.append(prefix.capitalize())
58
+ result_parts.append(acronym.upper())
59
+ found_acronym = True
60
+ break
61
+
62
+ if not found_acronym:
63
+ result_parts.append(part.capitalize())
64
+
65
+ return ''.join(result_parts)
66
+
67
+
68
+ def to_camel_case(snake_str: str) -> str:
69
+ """
70
+ Convert snake_case to camelCase (unexported).
71
+
72
+ Args:
73
+ snake_str: snake_case string
74
+
75
+ Returns:
76
+ camelCase string
77
+
78
+ Examples:
79
+ >>> to_camel_case("user_profile")
80
+ 'userProfile'
81
+ >>> to_camel_case("http_client")
82
+ 'httpClient'
83
+ """
84
+ pascal = to_pascal_case(snake_str)
85
+ if not pascal:
86
+ return ""
87
+
88
+ # Lowercase the first character
89
+ return pascal[0].lower() + pascal[1:]
90
+
91
+
92
+ def sanitize_go_identifier(name: str) -> str:
93
+ """
94
+ Sanitize string to valid Go identifier.
95
+
96
+ Args:
97
+ name: Raw identifier name
98
+
99
+ Returns:
100
+ Valid Go identifier
101
+
102
+ Examples:
103
+ >>> sanitize_go_identifier("user-profile")
104
+ 'UserProfile'
105
+ >>> sanitize_go_identifier("2users")
106
+ 'N2users'
107
+ >>> sanitize_go_identifier("class")
108
+ 'Class'
109
+ """
110
+ # Replace hyphens with underscores
111
+ name = name.replace('-', '_')
112
+
113
+ # Remove invalid characters
114
+ name = re.sub(r'[^a-zA-Z0-9_]', '', name)
115
+
116
+ # If starts with digit, prefix with 'N'
117
+ if name and name[0].isdigit():
118
+ name = f'N{name}'
119
+
120
+ # Convert to PascalCase
121
+ return to_pascal_case(name) if name else 'Unknown'
122
+
123
+
124
+ def to_snake_case(camel_str: str) -> str:
125
+ """
126
+ Convert PascalCase/camelCase to snake_case.
127
+
128
+ Args:
129
+ camel_str: PascalCase or camelCase string
130
+
131
+ Returns:
132
+ snake_case string
133
+
134
+ Examples:
135
+ >>> to_snake_case("UserProfile")
136
+ 'user_profile'
137
+ >>> to_snake_case("APIKey")
138
+ 'api_key'
139
+ >>> to_snake_case("HTTPSConnection")
140
+ 'https_connection'
141
+ """
142
+ # Insert underscore before uppercase letters (except first)
143
+ s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', camel_str)
144
+ # Insert underscore before uppercase letters followed by lowercase
145
+ return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
146
+
147
+
148
+ def get_go_field_name(field_name: str) -> str:
149
+ """
150
+ Get Go struct field name (exported PascalCase).
151
+
152
+ Args:
153
+ field_name: Original field name (snake_case)
154
+
155
+ Returns:
156
+ Go field name (PascalCase)
157
+
158
+ Examples:
159
+ >>> get_go_field_name("user_id")
160
+ 'UserID'
161
+ >>> get_go_field_name("created_at")
162
+ 'CreatedAt'
163
+ """
164
+ return to_pascal_case(field_name)
165
+
166
+
167
+ def get_go_package_name(name: str) -> str:
168
+ """
169
+ Get valid Go package name (lowercase, no underscores).
170
+
171
+ Args:
172
+ name: Package name
173
+
174
+ Returns:
175
+ Valid Go package name
176
+
177
+ Examples:
178
+ >>> get_go_package_name("api_client")
179
+ 'apiclient'
180
+ >>> get_go_package_name("UserService")
181
+ 'userservice'
182
+ """
183
+ # Convert to lowercase
184
+ name = name.lower()
185
+
186
+ # Remove invalid characters (keep only letters and digits)
187
+ name = re.sub(r'[^a-z0-9]', '', name)
188
+
189
+ # Must not start with digit
190
+ if name and name[0].isdigit():
191
+ name = f'pkg{name}'
192
+
193
+ return name or 'client'
@@ -0,0 +1,134 @@
1
+ """
2
+ Operations Generator - Generates Go client methods from IR operations.
3
+
4
+ Handles generation of type-safe client methods for each API operation.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ from .naming import to_pascal_case
12
+
13
+ if TYPE_CHECKING:
14
+ from jinja2 import Environment
15
+
16
+ from ...ir import IRContext, IROperationObject
17
+ from .generator import GoGenerator
18
+
19
+
20
+ class OperationsGenerator:
21
+ """Generates Go client operation methods from IR operations."""
22
+
23
+ def __init__(
24
+ self,
25
+ jinja_env: Environment,
26
+ context: IRContext,
27
+ generator: GoGenerator,
28
+ ):
29
+ """
30
+ Initialize operations generator.
31
+
32
+ Args:
33
+ jinja_env: Jinja2 environment
34
+ context: IRContext from parser
35
+ generator: Parent GoGenerator instance
36
+ """
37
+ self.jinja_env = jinja_env
38
+ self.context = context
39
+ self.generator = generator
40
+
41
+ def generate_operation_method(
42
+ self,
43
+ operation: IROperationObject,
44
+ remove_tag_prefix: bool = False,
45
+ ) -> dict:
46
+ """
47
+ Generate Go method definition for an operation.
48
+
49
+ Args:
50
+ operation: IROperationObject to generate
51
+ remove_tag_prefix: Remove tag prefix from operation name
52
+
53
+ Returns:
54
+ Dictionary with operation method info
55
+ """
56
+ # Get method name
57
+ op_id = operation.operation_id
58
+ if remove_tag_prefix and operation.tags:
59
+ op_id = self.generator.remove_tag_prefix(op_id, operation.tags[0])
60
+
61
+ method_name = to_pascal_case(op_id)
62
+
63
+ # Get request/response types
64
+ request_type = None
65
+ if operation.request_body and operation.request_body.schema_name:
66
+ request_type = operation.request_body.schema_name
67
+ # Handle inline request bodies (multipart/form-data, etc.)
68
+ if request_type == "InlineRequestBody":
69
+ request_type = "map[string]interface{}"
70
+
71
+ response_type = "interface{}"
72
+ if operation.responses.get("200") and operation.responses["200"].schema_name:
73
+ response_type = operation.responses["200"].schema_name
74
+ elif operation.responses.get("201") and operation.responses["201"].schema_name:
75
+ response_type = operation.responses["201"].schema_name
76
+
77
+ # Build parameters
78
+ params = []
79
+
80
+ # Path parameters
81
+ for param in operation.parameters:
82
+ if param.location == "path":
83
+ params.append({
84
+ "name": param.name,
85
+ "type": self._get_param_go_type(param.schema_type),
86
+ "location": "path",
87
+ })
88
+
89
+ # Query parameters struct (if any)
90
+ query_params = [p for p in operation.parameters if p.location == "query"]
91
+ query_params_struct = None
92
+ if query_params:
93
+ params_struct_name = f"{method_name}Params"
94
+ params.append({
95
+ "name": "params",
96
+ "type": f"*{params_struct_name}",
97
+ "location": "query",
98
+ })
99
+
100
+ # Build query params struct definition
101
+ query_params_struct = {
102
+ "name": params_struct_name,
103
+ "fields": [
104
+ {
105
+ "name": to_pascal_case(p.name),
106
+ "type": self._get_param_go_type(p.schema_type),
107
+ "json_name": p.name,
108
+ "required": p.required,
109
+ }
110
+ for p in query_params
111
+ ]
112
+ }
113
+
114
+ return {
115
+ "name": method_name,
116
+ "http_method": operation.http_method.upper(),
117
+ "path": operation.path,
118
+ "parameters": params,
119
+ "request_type": request_type,
120
+ "response_type": response_type,
121
+ "description": operation.summary or operation.description or f"{method_name} operation",
122
+ "operation_id": operation.operation_id,
123
+ "query_params_struct": query_params_struct,
124
+ }
125
+
126
+ def _get_param_go_type(self, schema_type: str) -> str:
127
+ """Get Go type for parameter schema type."""
128
+ type_map = {
129
+ "string": "string",
130
+ "integer": "int64",
131
+ "number": "float64",
132
+ "boolean": "bool",
133
+ }
134
+ return type_map.get(schema_type, "string")
@@ -0,0 +1,38 @@
1
+ # Code generated by django-cfg/django_client - DO NOT EDIT.
2
+ # Generated at: {{ generated_at }}
3
+
4
+ .PHONY: deps build test fmt lint clean all
5
+
6
+ # Download dependencies
7
+ deps:
8
+ go mod download
9
+ go mod tidy
10
+
11
+ # Build (if there's a cmd/)
12
+ build:
13
+ @if [ -d "cmd" ]; then \
14
+ go build -o bin/ ./cmd/...; \
15
+ else \
16
+ echo "No cmd/ directory found, skipping build"; \
17
+ fi
18
+
19
+ # Run tests
20
+ test:
21
+ go test -v -race -cover ./...
22
+
23
+ # Format code
24
+ fmt:
25
+ go fmt ./...
26
+ goimports -w .
27
+
28
+ # Run linter
29
+ lint:
30
+ golangci-lint run
31
+
32
+ # Clean build artifacts
33
+ clean:
34
+ rm -rf bin/
35
+ go clean
36
+
37
+ # Run all checks
38
+ all: fmt lint test
@@ -0,0 +1,55 @@
1
+ # {{ api_title }} - Go Client
2
+
3
+ Auto-generated Go client for {{ api_title }} (v{{ api_version }}).
4
+
5
+ Generated at: {{ generated_at }}
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ go get {{ module_name }}
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```go
16
+ package main
17
+
18
+ import (
19
+ "context"
20
+ "fmt"
21
+ "log"
22
+
23
+ "{{ module_name }}"
24
+ )
25
+
26
+ func main() {
27
+ // Create client
28
+ client := {{ module_name }}.NewClient(
29
+ "https://api.example.com",
30
+ {{ module_name }}.WithToken("your-api-token"),
31
+ )
32
+
33
+ // Make requests
34
+ ctx := context.Background()
35
+
36
+ // Example: List users
37
+ // users, err := client.UsersList(ctx, nil)
38
+ // if err != nil {
39
+ // log.Fatal(err)
40
+ // }
41
+ // fmt.Printf("Users: %+v\n", users)
42
+ }
43
+ ```
44
+
45
+ ## Features
46
+
47
+ - ✅ Type-safe Go structs
48
+ - ✅ Context-aware requests
49
+ - ✅ Bearer token authentication
50
+ - ✅ Comprehensive error handling
51
+ - ✅ Auto-generated from OpenAPI spec
52
+
53
+ ## Documentation
54
+
55
+ See the OpenAPI specification for full API documentation.
@@ -0,0 +1,122 @@
1
+ // Code generated by django-cfg/django_client - DO NOT EDIT.
2
+ // Generated at: {{ generated_at }}
3
+
4
+ package {{ package_name }}
5
+
6
+ import (
7
+ "bytes"
8
+ "context"
9
+ "encoding/json"
10
+ "fmt"
11
+ "io"
12
+ "net/http"
13
+ "net/url"
14
+ )
15
+
16
+ // Client is the HTTP API client.
17
+ type Client struct {
18
+ BaseURL string
19
+ HTTPClient *http.Client
20
+ Token string // Bearer token for authentication
21
+ }
22
+
23
+ // Option is a functional option for configuring the Client.
24
+ type Option func(*Client)
25
+
26
+ // WithHTTPClient sets a custom HTTP client.
27
+ func WithHTTPClient(client *http.Client) Option {
28
+ return func(c *Client) {
29
+ c.HTTPClient = client
30
+ }
31
+ }
32
+
33
+ // WithToken sets the authentication token.
34
+ func WithToken(token string) Option {
35
+ return func(c *Client) {
36
+ c.Token = token
37
+ }
38
+ }
39
+
40
+ // NewClient creates a new API client.
41
+ func NewClient(baseURL string, options ...Option) *Client {
42
+ client := &Client{
43
+ BaseURL: baseURL,
44
+ HTTPClient: &http.Client{},
45
+ }
46
+
47
+ for _, opt := range options {
48
+ opt(client)
49
+ }
50
+
51
+ return client
52
+ }
53
+
54
+ // doRequest performs HTTP request with error handling.
55
+ func (c *Client) doRequest(ctx context.Context, method, path string, body interface{}, response interface{}) error {
56
+ var reqBody io.Reader
57
+
58
+ if body != nil {
59
+ data, err := json.Marshal(body)
60
+ if err != nil {
61
+ return fmt.Errorf("failed to marshal request body: %w", err)
62
+ }
63
+ reqBody = bytes.NewReader(data)
64
+ }
65
+
66
+ req, err := http.NewRequestWithContext(ctx, method, c.BaseURL+path, reqBody)
67
+ if err != nil {
68
+ return fmt.Errorf("failed to create request: %w", err)
69
+ }
70
+
71
+ req.Header.Set("Content-Type", "application/json")
72
+ if c.Token != "" {
73
+ req.Header.Set("Authorization", "Bearer "+c.Token)
74
+ }
75
+
76
+ resp, err := c.HTTPClient.Do(req)
77
+ if err != nil {
78
+ return fmt.Errorf("HTTP request failed: %w", err)
79
+ }
80
+ defer resp.Body.Close()
81
+
82
+ if resp.StatusCode >= 400 {
83
+ var apiErr APIError
84
+ apiErr.StatusCode = resp.StatusCode
85
+ if err := json.NewDecoder(resp.Body).Decode(&apiErr); err != nil {
86
+ apiErr.Message = resp.Status
87
+ }
88
+ return &apiErr
89
+ }
90
+
91
+ if response != nil {
92
+ if err := json.NewDecoder(resp.Body).Decode(response); err != nil {
93
+ return fmt.Errorf("failed to decode response: %w", err)
94
+ }
95
+ }
96
+
97
+ return nil
98
+ }
99
+
100
+ {% for operation in operations %}
101
+ // {{ operation.name }} - {{ operation.description }}
102
+ func (c *Client) {{ operation.name }}(ctx context.Context{% for param in operation.parameters %}, {{ param.name }} {{ param.type }}{% endfor %}{% if operation.request_type %}, req *{{ operation.request_type }}{% endif %}) ({% if operation.response_type != 'interface{}' %}*{{ operation.response_type }}{% else %}interface{}{% endif %}, error) {
103
+ {% if operation.response_type != 'interface{}' %}var response {{ operation.response_type }}{% endif %}
104
+
105
+ path := "{{ operation.path }}"
106
+ {% if operation.parameters %}
107
+ // TODO: Build path with parameters and query string
108
+ {% endif %}
109
+
110
+ err := c.doRequest(ctx, "{{ operation.http_method }}", path, {% if operation.request_type %}req{% else %}nil{% endif %}, {% if operation.response_type != 'interface{}' %}&response{% else %}nil{% endif %})
111
+ if err != nil {
112
+ return nil, err
113
+ }
114
+
115
+ {% if operation.response_type != 'interface{}' %}
116
+ return &response, nil
117
+ {% else %}
118
+ return nil, nil
119
+ {% endif %}
120
+ }
121
+
122
+ {% endfor %}
@@ -0,0 +1,49 @@
1
+ // Code generated by django-cfg/django_client - DO NOT EDIT.
2
+ // Generated at: {{ generated_at }}
3
+
4
+ package {{ package_name }}
5
+
6
+ import (
7
+ "encoding/json"
8
+ "fmt"
9
+ )
10
+
11
+ {% for enum in enums %}
12
+ // {{ (enum.doc or enum.name) | replace('\n', '\n// ') }}
13
+ type {{ enum.name }} {{ enum.base_type }}
14
+
15
+ const (
16
+ {% for value in enum['values'] %}
17
+ // {{ (value.description or value.name) | replace('\n', '\n\t// ') }}
18
+ {{ value.name }} {{ enum.name }} = {{ value.value if not enum.is_string_enum else '"%s"' % value.value }}
19
+ {% endfor %}
20
+ )
21
+
22
+ // String returns string representation of {{ enum.name }}.
23
+ func (e {{ enum.name }}) String() string {
24
+ switch e {
25
+ {% for value in enum['values'] %}
26
+ case {{ value.name }}:
27
+ return "{{ value.name }}"
28
+ {% endfor %}
29
+ default:
30
+ return fmt.Sprintf("{{ enum.name }}(%v)", {{ enum.base_type }}(e))
31
+ }
32
+ }
33
+
34
+ // MarshalJSON implements json.Marshaler.
35
+ func (e {{ enum.name }}) MarshalJSON() ([]byte, error) {
36
+ return json.Marshal({{ enum.base_type }}(e))
37
+ }
38
+
39
+ // UnmarshalJSON implements json.Unmarshaler.
40
+ func (e *{{ enum.name }}) UnmarshalJSON(data []byte) error {
41
+ var v {{ enum.base_type }}
42
+ if err := json.Unmarshal(data, &v); err != nil {
43
+ return err
44
+ }
45
+ *e = {{ enum.name }}(v)
46
+ return nil
47
+ }
48
+
49
+ {% endfor %}