django-cfg 1.5.8__py3-none-any.whl → 1.5.20__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 (159) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/api/commands/serializers.py +152 -0
  3. django_cfg/apps/api/commands/views.py +32 -0
  4. django_cfg/apps/business/accounts/management/commands/otp_test.py +5 -2
  5. django_cfg/apps/business/accounts/serializers/profile.py +42 -0
  6. django_cfg/apps/business/agents/management/commands/create_agent.py +5 -194
  7. django_cfg/apps/business/agents/management/commands/load_agent_templates.py +205 -0
  8. django_cfg/apps/business/agents/management/commands/orchestrator_status.py +4 -2
  9. django_cfg/apps/business/knowbase/management/commands/knowbase_stats.py +4 -2
  10. django_cfg/apps/business/knowbase/management/commands/setup_knowbase.py +4 -2
  11. django_cfg/apps/business/newsletter/management/commands/test_newsletter.py +5 -2
  12. django_cfg/apps/business/payments/management/commands/check_payment_status.py +4 -2
  13. django_cfg/apps/business/payments/management/commands/create_payment.py +4 -2
  14. django_cfg/apps/business/payments/management/commands/sync_currencies.py +4 -2
  15. django_cfg/apps/business/support/serializers.py +3 -2
  16. django_cfg/apps/integrations/centrifugo/apps.py +2 -1
  17. django_cfg/apps/integrations/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +151 -12
  18. django_cfg/apps/integrations/centrifugo/management/commands/generate_centrifugo_clients.py +6 -6
  19. django_cfg/apps/integrations/centrifugo/serializers/__init__.py +2 -1
  20. django_cfg/apps/integrations/centrifugo/serializers/publishes.py +22 -2
  21. django_cfg/apps/integrations/centrifugo/services/__init__.py +6 -0
  22. django_cfg/apps/integrations/centrifugo/services/client/__init__.py +6 -1
  23. django_cfg/apps/integrations/centrifugo/services/client/direct_client.py +282 -0
  24. django_cfg/apps/integrations/centrifugo/services/publisher.py +371 -0
  25. django_cfg/apps/integrations/centrifugo/services/token_generator.py +122 -0
  26. django_cfg/apps/integrations/centrifugo/urls.py +8 -0
  27. django_cfg/apps/integrations/centrifugo/views/__init__.py +2 -0
  28. django_cfg/apps/integrations/centrifugo/views/monitoring.py +25 -40
  29. django_cfg/apps/integrations/centrifugo/views/testing_api.py +0 -79
  30. django_cfg/apps/integrations/centrifugo/views/token_api.py +101 -0
  31. django_cfg/apps/integrations/centrifugo/views/wrapper.py +257 -0
  32. django_cfg/apps/integrations/grpc/admin/__init__.py +7 -1
  33. django_cfg/apps/integrations/grpc/admin/config.py +113 -9
  34. django_cfg/apps/integrations/grpc/admin/grpc_api_key.py +129 -0
  35. django_cfg/apps/integrations/grpc/admin/grpc_request_log.py +72 -63
  36. django_cfg/apps/integrations/grpc/admin/grpc_server_status.py +236 -0
  37. django_cfg/apps/integrations/grpc/auth/__init__.py +11 -3
  38. django_cfg/apps/integrations/grpc/auth/api_key_auth.py +320 -0
  39. django_cfg/apps/integrations/grpc/centrifugo/__init__.py +29 -0
  40. django_cfg/apps/integrations/grpc/centrifugo/bridge.py +277 -0
  41. django_cfg/apps/integrations/grpc/centrifugo/config.py +167 -0
  42. django_cfg/apps/integrations/grpc/centrifugo/demo.py +626 -0
  43. django_cfg/apps/integrations/grpc/centrifugo/test_publish.py +229 -0
  44. django_cfg/apps/integrations/grpc/centrifugo/transformers.py +89 -0
  45. django_cfg/apps/integrations/grpc/interceptors/__init__.py +3 -1
  46. django_cfg/apps/integrations/grpc/interceptors/centrifugo.py +541 -0
  47. django_cfg/apps/integrations/grpc/interceptors/logging.py +17 -20
  48. django_cfg/apps/integrations/grpc/interceptors/metrics.py +15 -14
  49. django_cfg/apps/integrations/grpc/interceptors/request_logger.py +79 -59
  50. django_cfg/apps/integrations/grpc/management/commands/compile_proto.py +105 -0
  51. django_cfg/apps/integrations/grpc/management/commands/generate_protos.py +185 -0
  52. django_cfg/apps/integrations/grpc/management/commands/rungrpc.py +474 -95
  53. django_cfg/apps/integrations/grpc/management/commands/test_grpc_integration.py +75 -0
  54. django_cfg/apps/integrations/grpc/management/proto/__init__.py +3 -0
  55. django_cfg/apps/integrations/grpc/management/proto/compiler.py +194 -0
  56. django_cfg/apps/integrations/grpc/managers/__init__.py +2 -0
  57. django_cfg/apps/integrations/grpc/managers/grpc_api_key.py +192 -0
  58. django_cfg/apps/integrations/grpc/managers/grpc_server_status.py +19 -11
  59. django_cfg/apps/integrations/grpc/migrations/0005_grpcapikey.py +143 -0
  60. django_cfg/apps/integrations/grpc/migrations/0006_grpcrequestlog_api_key_and_more.py +34 -0
  61. django_cfg/apps/integrations/grpc/models/__init__.py +2 -0
  62. django_cfg/apps/integrations/grpc/models/grpc_api_key.py +198 -0
  63. django_cfg/apps/integrations/grpc/models/grpc_request_log.py +11 -0
  64. django_cfg/apps/integrations/grpc/models/grpc_server_status.py +39 -4
  65. django_cfg/apps/integrations/grpc/serializers/__init__.py +22 -6
  66. django_cfg/apps/integrations/grpc/serializers/api_keys.py +63 -0
  67. django_cfg/apps/integrations/grpc/serializers/charts.py +118 -120
  68. django_cfg/apps/integrations/grpc/serializers/config.py +65 -51
  69. django_cfg/apps/integrations/grpc/serializers/health.py +7 -7
  70. django_cfg/apps/integrations/grpc/serializers/proto_files.py +74 -0
  71. django_cfg/apps/integrations/grpc/serializers/requests.py +13 -7
  72. django_cfg/apps/integrations/grpc/serializers/service_registry.py +181 -112
  73. django_cfg/apps/integrations/grpc/serializers/services.py +14 -32
  74. django_cfg/apps/integrations/grpc/serializers/stats.py +50 -12
  75. django_cfg/apps/integrations/grpc/serializers/testing.py +66 -58
  76. django_cfg/apps/integrations/grpc/services/__init__.py +2 -0
  77. django_cfg/apps/integrations/grpc/services/discovery.py +7 -1
  78. django_cfg/apps/integrations/grpc/services/monitoring_service.py +149 -43
  79. django_cfg/apps/integrations/grpc/services/proto_files_manager.py +268 -0
  80. django_cfg/apps/integrations/grpc/services/service_registry.py +48 -46
  81. django_cfg/apps/integrations/grpc/services/testing_service.py +10 -15
  82. django_cfg/apps/integrations/grpc/urls.py +8 -0
  83. django_cfg/apps/integrations/grpc/utils/SERVER_LOGGING.md +164 -0
  84. django_cfg/apps/integrations/grpc/utils/__init__.py +4 -13
  85. django_cfg/apps/integrations/grpc/utils/integration_test.py +334 -0
  86. django_cfg/apps/integrations/grpc/utils/proto_gen.py +48 -8
  87. django_cfg/apps/integrations/grpc/utils/streaming_logger.py +378 -0
  88. django_cfg/apps/integrations/grpc/views/__init__.py +4 -0
  89. django_cfg/apps/integrations/grpc/views/api_keys.py +255 -0
  90. django_cfg/apps/integrations/grpc/views/charts.py +21 -14
  91. django_cfg/apps/integrations/grpc/views/config.py +8 -6
  92. django_cfg/apps/integrations/grpc/views/monitoring.py +51 -79
  93. django_cfg/apps/integrations/grpc/views/proto_files.py +214 -0
  94. django_cfg/apps/integrations/grpc/views/services.py +30 -21
  95. django_cfg/apps/integrations/grpc/views/testing.py +45 -43
  96. django_cfg/apps/integrations/rq/views/jobs.py +19 -9
  97. django_cfg/apps/integrations/rq/views/schedule.py +7 -3
  98. django_cfg/apps/system/dashboard/serializers/commands.py +25 -1
  99. django_cfg/apps/system/dashboard/serializers/config.py +95 -9
  100. django_cfg/apps/system/dashboard/serializers/statistics.py +9 -4
  101. django_cfg/apps/system/dashboard/services/commands_service.py +12 -1
  102. django_cfg/apps/system/frontend/views.py +87 -6
  103. django_cfg/apps/system/maintenance/management/commands/maintenance.py +5 -2
  104. django_cfg/apps/system/maintenance/management/commands/process_scheduled_maintenance.py +4 -2
  105. django_cfg/apps/system/maintenance/management/commands/sync_cloudflare.py +5 -2
  106. django_cfg/config.py +33 -0
  107. django_cfg/core/builders/security_builder.py +1 -0
  108. django_cfg/core/generation/integration_generators/api.py +2 -0
  109. django_cfg/core/generation/integration_generators/grpc_generator.py +30 -32
  110. django_cfg/management/commands/check_endpoints.py +2 -2
  111. django_cfg/management/commands/check_settings.py +3 -10
  112. django_cfg/management/commands/clear_constance.py +3 -10
  113. django_cfg/management/commands/create_token.py +4 -11
  114. django_cfg/management/commands/list_urls.py +4 -10
  115. django_cfg/management/commands/migrate_all.py +18 -12
  116. django_cfg/management/commands/migrator.py +4 -11
  117. django_cfg/management/commands/script.py +4 -10
  118. django_cfg/management/commands/show_config.py +8 -16
  119. django_cfg/management/commands/show_urls.py +5 -11
  120. django_cfg/management/commands/superuser.py +4 -11
  121. django_cfg/management/commands/tree.py +5 -10
  122. django_cfg/management/utils/README.md +402 -0
  123. django_cfg/management/utils/__init__.py +29 -0
  124. django_cfg/management/utils/mixins.py +176 -0
  125. django_cfg/middleware/pagination.py +53 -54
  126. django_cfg/models/api/grpc/__init__.py +15 -21
  127. django_cfg/models/api/grpc/config.py +155 -73
  128. django_cfg/models/ngrok/config.py +7 -6
  129. django_cfg/modules/django_client/core/generator/python/files_generator.py +5 -13
  130. django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +16 -4
  131. django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +2 -3
  132. django_cfg/modules/django_client/core/generator/typescript/files_generator.py +6 -5
  133. django_cfg/modules/django_client/core/generator/typescript/generator.py +26 -0
  134. django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +7 -1
  135. django_cfg/modules/django_client/core/generator/typescript/models_generator.py +5 -0
  136. django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +11 -0
  137. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +1 -0
  138. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/function.ts.jinja +29 -1
  139. django_cfg/modules/django_client/core/generator/typescript/templates/hooks/hooks.ts.jinja +4 -0
  140. django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +12 -8
  141. django_cfg/modules/django_client/core/ir/schema.py +15 -1
  142. django_cfg/modules/django_client/core/parser/base.py +126 -30
  143. django_cfg/modules/django_client/management/commands/generate_client.py +5 -2
  144. django_cfg/modules/django_client/management/commands/validate_openapi.py +5 -2
  145. django_cfg/modules/django_email/management/commands/test_email.py +4 -10
  146. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +16 -13
  147. django_cfg/modules/django_telegram/management/commands/test_telegram.py +4 -11
  148. django_cfg/modules/django_twilio/management/commands/test_twilio.py +4 -11
  149. django_cfg/modules/django_unfold/navigation.py +6 -18
  150. django_cfg/pyproject.toml +1 -1
  151. django_cfg/registry/modules.py +1 -4
  152. django_cfg/requirements.txt +52 -0
  153. django_cfg/static/frontend/admin.zip +0 -0
  154. {django_cfg-1.5.8.dist-info → django_cfg-1.5.20.dist-info}/METADATA +1 -1
  155. {django_cfg-1.5.8.dist-info → django_cfg-1.5.20.dist-info}/RECORD +158 -121
  156. django_cfg/apps/integrations/grpc/auth/jwt_auth.py +0 -295
  157. {django_cfg-1.5.8.dist-info → django_cfg-1.5.20.dist-info}/WHEEL +0 -0
  158. {django_cfg-1.5.8.dist-info → django_cfg-1.5.20.dist-info}/entry_points.txt +0 -0
  159. {django_cfg-1.5.8.dist-info → django_cfg-1.5.20.dist-info}/licenses/LICENSE +0 -0
@@ -1,295 +0,0 @@
1
- """
2
- JWT Authentication Interceptor for gRPC.
3
-
4
- Handles JWT token verification and Django user authentication for gRPC requests.
5
- """
6
-
7
- import logging
8
- from typing import Any, Callable, Optional
9
-
10
- import grpc
11
- from django.conf import settings
12
- from django.contrib.auth import get_user_model
13
-
14
- logger = logging.getLogger(__name__)
15
-
16
- User = get_user_model()
17
-
18
-
19
- class JWTAuthInterceptor(grpc.ServerInterceptor):
20
- """
21
- gRPC interceptor for JWT authentication.
22
-
23
- Features:
24
- - Extracts JWT token from metadata
25
- - Verifies token signature and expiration
26
- - Loads Django user from token
27
- - Sets user on request context
28
- - Supports public methods whitelist
29
- - Handles authentication errors gracefully
30
-
31
- Example:
32
- ```python
33
- # In Django settings (auto-configured by django-cfg)
34
- GRPC_FRAMEWORK = {
35
- "SERVER_INTERCEPTORS": [
36
- "django_cfg.apps.integrations.grpc.auth.JWTAuthInterceptor",
37
- ]
38
- }
39
- ```
40
-
41
- Token Format:
42
- Authorization: Bearer <jwt_token>
43
- """
44
-
45
- def __init__(self):
46
- """Initialize JWT authentication interceptor."""
47
- self.grpc_auth_config = getattr(settings, "GRPC_AUTH", {})
48
- self.enabled = self.grpc_auth_config.get("enabled", True)
49
- self.require_auth = self.grpc_auth_config.get("require_auth", True)
50
- self.token_header = self.grpc_auth_config.get("token_header", "authorization")
51
- self.token_prefix = self.grpc_auth_config.get("token_prefix", "Bearer")
52
- self.public_methods = self.grpc_auth_config.get("public_methods", [
53
- "/grpc.health.v1.Health/Check",
54
- "/grpc.health.v1.Health/Watch",
55
- ])
56
-
57
- # JWT settings
58
- self.jwt_secret_key = self.grpc_auth_config.get("jwt_secret_key") or settings.SECRET_KEY
59
- self.jwt_algorithm = self.grpc_auth_config.get("jwt_algorithm", "HS256")
60
- self.jwt_verify_exp = self.grpc_auth_config.get("jwt_verify_exp", True)
61
- self.jwt_leeway = self.grpc_auth_config.get("jwt_leeway", 0)
62
-
63
- def intercept_service(self, continuation: Callable, handler_call_details: grpc.HandlerCallDetails) -> grpc.RpcMethodHandler:
64
- """
65
- Intercept gRPC service call for authentication.
66
-
67
- Args:
68
- continuation: Function to invoke the next interceptor or handler
69
- handler_call_details: Details about the RPC call
70
-
71
- Returns:
72
- RPC method handler (possibly wrapped with auth)
73
- """
74
- # Skip if auth is disabled
75
- if not self.enabled:
76
- return continuation(handler_call_details)
77
-
78
- # Check if method is public
79
- method_name = handler_call_details.method
80
- if method_name in self.public_methods:
81
- logger.debug(f"Public method accessed: {method_name}")
82
- return continuation(handler_call_details)
83
-
84
- # Extract token from metadata
85
- token = self._extract_token(handler_call_details.invocation_metadata)
86
-
87
- # If no token and auth is required, abort
88
- if not token:
89
- if self.require_auth:
90
- logger.warning(f"Missing authentication token for {method_name}")
91
- return self._abort_unauthenticated(
92
- "Authentication token is required"
93
- )
94
- else:
95
- # Allow anonymous access
96
- logger.debug(f"No token provided for {method_name}, allowing anonymous access")
97
- return continuation(handler_call_details)
98
-
99
- # Verify token and get user
100
- user = self._verify_token(token)
101
-
102
- if not user:
103
- if self.require_auth:
104
- logger.warning(f"Invalid authentication token for {method_name}")
105
- return self._abort_unauthenticated(
106
- "Invalid or expired authentication token"
107
- )
108
- else:
109
- # Allow anonymous access even with invalid token
110
- return continuation(handler_call_details)
111
-
112
- # Add user to context and continue
113
- logger.debug(f"Authenticated user {user.id} for {method_name}")
114
- return self._continue_with_user(continuation, handler_call_details, user)
115
-
116
- def _extract_token(self, metadata: tuple) -> Optional[str]:
117
- """
118
- Extract JWT token from gRPC metadata.
119
-
120
- Args:
121
- metadata: gRPC invocation metadata
122
-
123
- Returns:
124
- JWT token string or None
125
- """
126
- if not metadata:
127
- return None
128
-
129
- # Convert metadata to dict
130
- metadata_dict = dict(metadata)
131
-
132
- # Get authorization header (case-insensitive)
133
- auth_header = None
134
- for key, value in metadata_dict.items():
135
- if key.lower() == self.token_header.lower():
136
- auth_header = value
137
- break
138
-
139
- if not auth_header:
140
- return None
141
-
142
- # Extract token from "Bearer <token>" format
143
- if auth_header.startswith(f"{self.token_prefix} "):
144
- return auth_header[len(self.token_prefix) + 1:]
145
- elif self.token_prefix == "":
146
- # No prefix expected
147
- return auth_header
148
- else:
149
- # Invalid format
150
- logger.warning(f"Invalid authorization header format: {auth_header[:20]}...")
151
- return None
152
-
153
- def _verify_token(self, token: str) -> Optional[User]:
154
- """
155
- Verify JWT token and return user.
156
-
157
- Args:
158
- token: JWT token string
159
-
160
- Returns:
161
- Django User instance or None
162
- """
163
- try:
164
- import jwt
165
-
166
- # Decode JWT token
167
- payload = jwt.decode(
168
- token,
169
- self.jwt_secret_key,
170
- algorithms=[self.jwt_algorithm],
171
- options={
172
- "verify_exp": self.jwt_verify_exp,
173
- },
174
- leeway=self.jwt_leeway,
175
- )
176
-
177
- # Extract user ID from payload
178
- user_id = payload.get("user_id")
179
- if not user_id:
180
- logger.warning("Token missing user_id claim")
181
- return None
182
-
183
- # Load user from database
184
- try:
185
- user = User.objects.get(pk=user_id)
186
- if not user.is_active:
187
- logger.warning(f"Inactive user {user_id} attempted to authenticate")
188
- return None
189
- return user
190
- except User.DoesNotExist:
191
- logger.warning(f"User {user_id} from token does not exist")
192
- return None
193
-
194
- except jwt.ExpiredSignatureError:
195
- logger.warning("JWT token has expired")
196
- return None
197
- except jwt.InvalidTokenError as e:
198
- logger.warning(f"Invalid JWT token: {e}")
199
- return None
200
- except ImportError:
201
- logger.error("PyJWT library not installed. Install with: pip install PyJWT")
202
- return None
203
- except Exception as e:
204
- logger.error(f"Unexpected error verifying token: {e}")
205
- return None
206
-
207
- def _continue_with_user(
208
- self,
209
- continuation: Callable,
210
- handler_call_details: grpc.HandlerCallDetails,
211
- user: User,
212
- ) -> grpc.RpcMethodHandler:
213
- """
214
- Continue RPC with authenticated user in context.
215
-
216
- Args:
217
- continuation: Function to invoke next interceptor or handler
218
- handler_call_details: Details about the RPC call
219
- user: Authenticated Django user
220
-
221
- Returns:
222
- RPC method handler with user context
223
- """
224
- # Get the handler
225
- handler = continuation(handler_call_details)
226
-
227
- if handler is None:
228
- return None
229
-
230
- # Wrap the handler to inject user into context
231
- def wrapped_unary_unary(request, context):
232
- # Set user on context for access in service methods
233
- context.user = user
234
- return handler.unary_unary(request, context)
235
-
236
- def wrapped_unary_stream(request, context):
237
- context.user = user
238
- return handler.unary_stream(request, context)
239
-
240
- def wrapped_stream_unary(request_iterator, context):
241
- context.user = user
242
- return handler.stream_unary(request_iterator, context)
243
-
244
- def wrapped_stream_stream(request_iterator, context):
245
- context.user = user
246
- return handler.stream_stream(request_iterator, context)
247
-
248
- # Return wrapped handler based on type
249
- return grpc.unary_unary_rpc_method_handler(
250
- wrapped_unary_unary,
251
- request_deserializer=handler.request_deserializer,
252
- response_serializer=handler.response_serializer,
253
- ) if handler.unary_unary else (
254
- grpc.unary_stream_rpc_method_handler(
255
- wrapped_unary_stream,
256
- request_deserializer=handler.request_deserializer,
257
- response_serializer=handler.response_serializer,
258
- ) if handler.unary_stream else (
259
- grpc.stream_unary_rpc_method_handler(
260
- wrapped_stream_unary,
261
- request_deserializer=handler.request_deserializer,
262
- response_serializer=handler.response_serializer,
263
- ) if handler.stream_unary else (
264
- grpc.stream_stream_rpc_method_handler(
265
- wrapped_stream_stream,
266
- request_deserializer=handler.request_deserializer,
267
- response_serializer=handler.response_serializer,
268
- ) if handler.stream_stream else None
269
- )
270
- )
271
- )
272
-
273
- def _abort_unauthenticated(self, message: str) -> grpc.RpcMethodHandler:
274
- """
275
- Return handler that aborts with UNAUTHENTICATED status.
276
-
277
- Args:
278
- message: Error message
279
-
280
- Returns:
281
- RPC method handler that aborts
282
- """
283
- def abort(*args, **kwargs):
284
- context = args[1] if len(args) > 1 else None
285
- if context:
286
- context.abort(grpc.StatusCode.UNAUTHENTICATED, message)
287
-
288
- return grpc.unary_unary_rpc_method_handler(
289
- abort,
290
- request_deserializer=lambda x: x,
291
- response_serializer=lambda x: x,
292
- )
293
-
294
-
295
- __all__ = ["JWTAuthInterceptor"]