django-cfg 1.4.120__py3-none-any.whl → 1.5.2__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 (182) hide show
  1. django_cfg/__init__.py +8 -4
  2. django_cfg/apps/centrifugo/admin/centrifugo_log.py +33 -71
  3. django_cfg/apps/dashboard/TRANSACTION_FIX.md +73 -0
  4. django_cfg/apps/dashboard/serializers/__init__.py +0 -12
  5. django_cfg/apps/dashboard/serializers/activity.py +1 -1
  6. django_cfg/apps/dashboard/services/__init__.py +0 -2
  7. django_cfg/apps/dashboard/services/charts_service.py +4 -3
  8. django_cfg/apps/dashboard/services/statistics_service.py +11 -2
  9. django_cfg/apps/dashboard/services/system_health_service.py +64 -106
  10. django_cfg/apps/dashboard/urls.py +0 -2
  11. django_cfg/apps/dashboard/views/__init__.py +0 -2
  12. django_cfg/apps/dashboard/views/commands_views.py +3 -6
  13. django_cfg/apps/dashboard/views/overview_views.py +14 -13
  14. django_cfg/apps/grpc/__init__.py +9 -0
  15. django_cfg/apps/grpc/admin/__init__.py +11 -0
  16. django_cfg/apps/{tasks → grpc}/admin/config.py +32 -41
  17. django_cfg/apps/grpc/admin/grpc_request_log.py +252 -0
  18. django_cfg/apps/grpc/apps.py +28 -0
  19. django_cfg/apps/grpc/auth/__init__.py +9 -0
  20. django_cfg/apps/grpc/auth/jwt_auth.py +295 -0
  21. django_cfg/apps/grpc/interceptors/__init__.py +19 -0
  22. django_cfg/apps/grpc/interceptors/errors.py +241 -0
  23. django_cfg/apps/grpc/interceptors/logging.py +270 -0
  24. django_cfg/apps/grpc/interceptors/metrics.py +306 -0
  25. django_cfg/apps/grpc/interceptors/request_logger.py +515 -0
  26. django_cfg/apps/grpc/management/__init__.py +1 -0
  27. django_cfg/apps/grpc/management/commands/rungrpc.py +302 -0
  28. django_cfg/apps/grpc/managers/__init__.py +10 -0
  29. django_cfg/apps/grpc/managers/grpc_request_log.py +310 -0
  30. django_cfg/apps/grpc/migrations/0001_initial.py +69 -0
  31. django_cfg/apps/grpc/migrations/0002_rename_django_cfg__service_4c4a8e_idx_django_cfg__service_584308_idx_and_more.py +38 -0
  32. django_cfg/apps/grpc/models/__init__.py +9 -0
  33. django_cfg/apps/grpc/models/grpc_request_log.py +219 -0
  34. django_cfg/apps/grpc/serializers/__init__.py +23 -0
  35. django_cfg/apps/grpc/serializers/health.py +18 -0
  36. django_cfg/apps/grpc/serializers/requests.py +18 -0
  37. django_cfg/apps/grpc/serializers/services.py +50 -0
  38. django_cfg/apps/grpc/serializers/stats.py +22 -0
  39. django_cfg/apps/grpc/services/__init__.py +16 -0
  40. django_cfg/apps/grpc/services/base.py +375 -0
  41. django_cfg/apps/grpc/services/discovery.py +415 -0
  42. django_cfg/apps/grpc/urls.py +23 -0
  43. django_cfg/apps/grpc/utils/__init__.py +13 -0
  44. django_cfg/apps/grpc/utils/proto_gen.py +423 -0
  45. django_cfg/apps/grpc/views/__init__.py +9 -0
  46. django_cfg/apps/grpc/views/monitoring.py +497 -0
  47. django_cfg/apps/knowbase/apps.py +2 -2
  48. django_cfg/apps/maintenance/admin/api_key_admin.py +7 -9
  49. django_cfg/apps/maintenance/admin/site_admin.py +5 -4
  50. django_cfg/apps/newsletter/admin/newsletter_admin.py +12 -11
  51. django_cfg/apps/payments/admin/balance_admin.py +26 -36
  52. django_cfg/apps/payments/admin/payment_admin.py +65 -85
  53. django_cfg/apps/payments/admin/withdrawal_admin.py +65 -100
  54. django_cfg/apps/rq/__init__.py +9 -0
  55. django_cfg/apps/rq/apps.py +80 -0
  56. django_cfg/apps/rq/management/__init__.py +1 -0
  57. django_cfg/apps/rq/management/commands/__init__.py +1 -0
  58. django_cfg/apps/rq/management/commands/rqscheduler.py +31 -0
  59. django_cfg/apps/rq/management/commands/rqstats.py +33 -0
  60. django_cfg/apps/rq/management/commands/rqworker.py +31 -0
  61. django_cfg/apps/rq/management/commands/rqworker_pool.py +27 -0
  62. django_cfg/apps/rq/serializers/__init__.py +40 -0
  63. django_cfg/apps/rq/serializers/health.py +60 -0
  64. django_cfg/apps/rq/serializers/job.py +100 -0
  65. django_cfg/apps/rq/serializers/queue.py +80 -0
  66. django_cfg/apps/rq/serializers/schedule.py +178 -0
  67. django_cfg/apps/rq/serializers/testing.py +139 -0
  68. django_cfg/apps/rq/serializers/worker.py +58 -0
  69. django_cfg/apps/rq/services/__init__.py +25 -0
  70. django_cfg/apps/rq/services/config_helper.py +233 -0
  71. django_cfg/apps/rq/services/models/README.md +417 -0
  72. django_cfg/apps/rq/services/models/__init__.py +30 -0
  73. django_cfg/apps/rq/services/models/event.py +123 -0
  74. django_cfg/apps/rq/services/models/job.py +99 -0
  75. django_cfg/apps/rq/services/models/queue.py +92 -0
  76. django_cfg/apps/rq/services/models/worker.py +104 -0
  77. django_cfg/apps/rq/services/rq_converters.py +183 -0
  78. django_cfg/apps/rq/tasks/__init__.py +23 -0
  79. django_cfg/apps/rq/tasks/demo_tasks.py +284 -0
  80. django_cfg/apps/rq/urls.py +54 -0
  81. django_cfg/apps/rq/views/__init__.py +19 -0
  82. django_cfg/apps/rq/views/jobs.py +882 -0
  83. django_cfg/apps/rq/views/monitoring.py +248 -0
  84. django_cfg/apps/rq/views/queues.py +261 -0
  85. django_cfg/apps/rq/views/schedule.py +400 -0
  86. django_cfg/apps/rq/views/testing.py +761 -0
  87. django_cfg/apps/rq/views/workers.py +195 -0
  88. django_cfg/apps/urls.py +13 -8
  89. django_cfg/config.py +106 -0
  90. django_cfg/core/base/config_model.py +16 -26
  91. django_cfg/core/builders/apps_builder.py +7 -11
  92. django_cfg/core/generation/integration_generators/__init__.py +3 -6
  93. django_cfg/core/generation/integration_generators/django_rq.py +80 -0
  94. django_cfg/core/generation/integration_generators/grpc_generator.py +318 -0
  95. django_cfg/core/generation/orchestrator.py +15 -15
  96. django_cfg/core/integration/display/startup.py +6 -20
  97. django_cfg/mixins/__init__.py +2 -0
  98. django_cfg/mixins/superadmin_api.py +59 -0
  99. django_cfg/models/__init__.py +3 -3
  100. django_cfg/models/api/grpc/__init__.py +59 -0
  101. django_cfg/models/api/grpc/config.py +364 -0
  102. django_cfg/models/django/__init__.py +3 -3
  103. django_cfg/models/django/django_rq.py +621 -0
  104. django_cfg/models/django/revolution_legacy.py +1 -1
  105. django_cfg/modules/base.py +19 -6
  106. django_cfg/modules/django_admin/base/pydantic_admin.py +2 -2
  107. django_cfg/modules/django_admin/config/background_task_config.py +4 -4
  108. django_cfg/modules/django_admin/utils/__init__.py +41 -3
  109. django_cfg/modules/django_admin/utils/badges/__init__.py +13 -0
  110. django_cfg/modules/django_admin/utils/{badges.py → badges/status_badges.py} +3 -3
  111. django_cfg/modules/django_admin/utils/displays/__init__.py +13 -0
  112. django_cfg/modules/django_admin/utils/{displays.py → displays/data_displays.py} +2 -2
  113. django_cfg/modules/django_admin/utils/html/__init__.py +26 -0
  114. django_cfg/modules/django_admin/utils/html/badges.py +47 -0
  115. django_cfg/modules/django_admin/utils/html/base.py +167 -0
  116. django_cfg/modules/django_admin/utils/html/code.py +87 -0
  117. django_cfg/modules/django_admin/utils/html/composition.py +205 -0
  118. django_cfg/modules/django_admin/utils/html/formatting.py +231 -0
  119. django_cfg/modules/django_admin/utils/html/keyvalue.py +219 -0
  120. django_cfg/modules/django_admin/utils/html/markdown_integration.py +108 -0
  121. django_cfg/modules/django_admin/utils/html/progress.py +127 -0
  122. django_cfg/modules/django_admin/utils/html_builder.py +55 -408
  123. django_cfg/modules/django_admin/utils/markdown/__init__.py +21 -0
  124. django_cfg/modules/django_unfold/navigation.py +21 -18
  125. django_cfg/pyproject.toml +4 -6
  126. django_cfg/registry/core.py +4 -7
  127. django_cfg/registry/modules.py +6 -0
  128. django_cfg/static/frontend/admin.zip +0 -0
  129. django_cfg/templates/admin/constance/includes/results_list.html +73 -0
  130. django_cfg/templates/admin/index.html +187 -62
  131. django_cfg/templatetags/django_cfg.py +61 -1
  132. {django_cfg-1.4.120.dist-info → django_cfg-1.5.2.dist-info}/METADATA +12 -4
  133. {django_cfg-1.4.120.dist-info → django_cfg-1.5.2.dist-info}/RECORD +140 -96
  134. django_cfg/apps/dashboard/permissions.py +0 -48
  135. django_cfg/apps/dashboard/serializers/django_q2.py +0 -50
  136. django_cfg/apps/dashboard/services/django_q2_service.py +0 -159
  137. django_cfg/apps/dashboard/views/django_q2_views.py +0 -79
  138. django_cfg/apps/tasks/__init__.py +0 -64
  139. django_cfg/apps/tasks/admin/__init__.py +0 -4
  140. django_cfg/apps/tasks/admin/task_log.py +0 -265
  141. django_cfg/apps/tasks/apps.py +0 -15
  142. django_cfg/apps/tasks/filters/__init__.py +0 -10
  143. django_cfg/apps/tasks/filters/task_log.py +0 -121
  144. django_cfg/apps/tasks/migrations/0001_initial.py +0 -196
  145. django_cfg/apps/tasks/migrations/0002_delete_tasklog.py +0 -16
  146. django_cfg/apps/tasks/models/__init__.py +0 -4
  147. django_cfg/apps/tasks/models/task_log.py +0 -246
  148. django_cfg/apps/tasks/serializers/__init__.py +0 -28
  149. django_cfg/apps/tasks/serializers/task_log.py +0 -249
  150. django_cfg/apps/tasks/services/__init__.py +0 -10
  151. django_cfg/apps/tasks/services/client/__init__.py +0 -7
  152. django_cfg/apps/tasks/services/client/client.py +0 -234
  153. django_cfg/apps/tasks/services/config_helper.py +0 -63
  154. django_cfg/apps/tasks/services/sync.py +0 -204
  155. django_cfg/apps/tasks/urls.py +0 -16
  156. django_cfg/apps/tasks/views/__init__.py +0 -10
  157. django_cfg/apps/tasks/views/task_log.py +0 -41
  158. django_cfg/apps/tasks/views/task_log_base.py +0 -41
  159. django_cfg/apps/tasks/views/task_log_overview.py +0 -100
  160. django_cfg/apps/tasks/views/task_log_related.py +0 -41
  161. django_cfg/apps/tasks/views/task_log_stats.py +0 -91
  162. django_cfg/apps/tasks/views/task_log_timeline.py +0 -81
  163. django_cfg/core/generation/integration_generators/django_q2.py +0 -133
  164. django_cfg/core/generation/integration_generators/tasks.py +0 -88
  165. django_cfg/models/django/django_q2.py +0 -514
  166. django_cfg/models/tasks/__init__.py +0 -49
  167. django_cfg/models/tasks/backends.py +0 -122
  168. django_cfg/models/tasks/config.py +0 -209
  169. django_cfg/models/tasks/utils.py +0 -162
  170. django_cfg/modules/django_admin/utils/CODE_BLOCK_DOCS.md +0 -396
  171. django_cfg/modules/django_q2/README.md +0 -140
  172. django_cfg/modules/django_q2/__init__.py +0 -8
  173. django_cfg/modules/django_q2/apps.py +0 -107
  174. django_cfg/modules/django_q2/management/commands/__init__.py +0 -0
  175. django_cfg/modules/django_q2/management/commands/sync_django_q_schedules.py +0 -74
  176. /django_cfg/apps/{tasks/migrations → grpc/management/commands}/__init__.py +0 -0
  177. /django_cfg/{modules/django_q2/management → apps/grpc/migrations}/__init__.py +0 -0
  178. /django_cfg/modules/django_admin/utils/{mermaid_plugin.py → markdown/mermaid_plugin.py} +0 -0
  179. /django_cfg/modules/django_admin/utils/{markdown_renderer.py → markdown/renderer.py} +0 -0
  180. {django_cfg-1.4.120.dist-info → django_cfg-1.5.2.dist-info}/WHEEL +0 -0
  181. {django_cfg-1.4.120.dist-info → django_cfg-1.5.2.dist-info}/entry_points.txt +0 -0
  182. {django_cfg-1.4.120.dist-info → django_cfg-1.5.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,318 @@
1
+ """
2
+ gRPC framework generator.
3
+
4
+ Handles gRPC server, authentication, and proto configuration.
5
+ Size: ~250 lines (focused on gRPC framework)
6
+ """
7
+
8
+ import logging
9
+ from typing import TYPE_CHECKING, Any, Dict, List
10
+
11
+ if TYPE_CHECKING:
12
+ from ...base.config_model import DjangoConfig
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class GRPCSettingsGenerator:
18
+ """
19
+ Generates gRPC framework settings.
20
+
21
+ Responsibilities:
22
+ - Configure gRPC server settings
23
+ - Setup authentication and interceptors
24
+ - Configure proto generation
25
+ - Auto-detect if gRPC should be enabled
26
+ - Resolve handlers hook from ROOT_URLCONF
27
+
28
+ Example:
29
+ ```python
30
+ generator = GRPCSettingsGenerator(config)
31
+ settings = generator.generate()
32
+ ```
33
+ """
34
+
35
+ def __init__(self, config: "DjangoConfig"):
36
+ """
37
+ Initialize generator with configuration.
38
+
39
+ Args:
40
+ config: DjangoConfig instance
41
+ """
42
+ self.config = config
43
+
44
+ def generate(self) -> Dict[str, Any]:
45
+ """
46
+ Generate gRPC framework settings.
47
+
48
+ Returns:
49
+ Dictionary with gRPC configuration
50
+
51
+ Example:
52
+ >>> generator = GRPCSettingsGenerator(config)
53
+ >>> settings = generator.generate()
54
+ """
55
+ # Check if gRPC should be enabled
56
+ if not self._should_enable_grpc():
57
+ logger.debug("⏭️ gRPC disabled")
58
+ return {}
59
+
60
+ try:
61
+ return self._generate_grpc_settings()
62
+ except ImportError as e:
63
+ logger.warning(f"Failed to import gRPC dependencies: {e}")
64
+ logger.info("💡 Install with: pip install django-cfg[grpc]")
65
+ return {}
66
+ except Exception as e:
67
+ logger.error(f"Failed to generate gRPC settings: {e}")
68
+ return {}
69
+
70
+ def _should_enable_grpc(self) -> bool:
71
+ """
72
+ Check if gRPC should be enabled.
73
+
74
+ Returns:
75
+ True if gRPC should be enabled
76
+ """
77
+ # Check if grpc config exists and is enabled
78
+ if not hasattr(self.config, "grpc") or not self.config.grpc:
79
+ return False
80
+
81
+ if not self.config.grpc.enabled:
82
+ return False
83
+
84
+ # Check if gRPC feature is available
85
+ from django_cfg.config import is_feature_available
86
+ if not is_feature_available("grpc"):
87
+ logger.warning("gRPC enabled but dependencies not installed")
88
+ logger.info("💡 Install with: pip install django-cfg[grpc]")
89
+ return False
90
+
91
+ return True
92
+
93
+ def _generate_grpc_settings(self) -> Dict[str, Any]:
94
+ """
95
+ Generate gRPC-specific settings.
96
+
97
+ Returns:
98
+ Dictionary with gRPC configuration
99
+ """
100
+ settings = {}
101
+
102
+ # Generate GRPC_FRAMEWORK settings
103
+ grpc_framework = self._build_grpc_framework_settings()
104
+ if grpc_framework:
105
+ settings["GRPC_FRAMEWORK"] = grpc_framework
106
+
107
+ # Generate server-specific settings
108
+ grpc_server = self._build_grpc_server_settings()
109
+ if grpc_server:
110
+ settings["GRPC_SERVER"] = grpc_server
111
+
112
+ # Generate auth-specific settings
113
+ grpc_auth = self._build_grpc_auth_settings()
114
+ if grpc_auth:
115
+ settings["GRPC_AUTH"] = grpc_auth
116
+
117
+ # Generate proto-specific settings
118
+ grpc_proto = self._build_grpc_proto_settings()
119
+ if grpc_proto:
120
+ settings["GRPC_PROTO"] = grpc_proto
121
+
122
+ logger.info("✅ gRPC framework enabled")
123
+ logger.info(f" - Server: {self.config.grpc.server.host}:{self.config.grpc.server.port}")
124
+ logger.info(f" - Workers: {self.config.grpc.server.max_workers}")
125
+ logger.info(f" - Auth: {'enabled' if self.config.grpc.auth.enabled else 'disabled'}")
126
+ logger.info(f" - Reflection: {'enabled' if self.config.grpc.server.enable_reflection else 'disabled'}")
127
+
128
+ return settings
129
+
130
+ def _build_grpc_framework_settings(self) -> Dict[str, Any]:
131
+ """
132
+ Build GRPC_FRAMEWORK settings dictionary.
133
+
134
+ Returns:
135
+ Dictionary with framework-level gRPC settings
136
+ """
137
+ grpc_config = self.config.grpc
138
+
139
+ # Resolve handlers hook (replace {ROOT_URLCONF} placeholder)
140
+ handlers_hook = self._resolve_handlers_hook(grpc_config.handlers_hook)
141
+
142
+ # Build interceptors list
143
+ interceptors = self._build_interceptors()
144
+
145
+ framework_settings = {
146
+ "ROOT_HANDLERS_HOOK": handlers_hook,
147
+ "SERVER_INTERCEPTORS": interceptors,
148
+ }
149
+
150
+ # Add auto-registration settings
151
+ if grpc_config.auto_register_apps:
152
+ framework_settings["AUTO_REGISTER_APPS"] = grpc_config.enabled_apps
153
+
154
+ # Add custom services
155
+ if grpc_config.custom_services:
156
+ framework_settings["CUSTOM_SERVICES"] = grpc_config.custom_services
157
+
158
+ return framework_settings
159
+
160
+ def _build_grpc_server_settings(self) -> Dict[str, Any]:
161
+ """
162
+ Build GRPC_SERVER settings dictionary.
163
+
164
+ Returns:
165
+ Dictionary with server configuration
166
+ """
167
+ server_config = self.config.grpc.server
168
+
169
+ server_settings = {
170
+ "host": server_config.host,
171
+ "port": server_config.port,
172
+ "max_workers": server_config.max_workers,
173
+ "enable_reflection": server_config.enable_reflection,
174
+ "enable_health_check": server_config.enable_health_check,
175
+ "max_send_message_length": server_config.max_send_message_length,
176
+ "max_receive_message_length": server_config.max_receive_message_length,
177
+ "keepalive_time_ms": server_config.keepalive_time_ms,
178
+ "keepalive_timeout_ms": server_config.keepalive_timeout_ms,
179
+ }
180
+
181
+ # Add optional compression
182
+ if server_config.compression:
183
+ server_settings["compression"] = server_config.compression
184
+
185
+ # Add custom interceptors from config
186
+ if server_config.interceptors:
187
+ server_settings["custom_interceptors"] = server_config.interceptors
188
+
189
+ return server_settings
190
+
191
+ def _build_grpc_auth_settings(self) -> Dict[str, Any]:
192
+ """
193
+ Build GRPC_AUTH settings dictionary.
194
+
195
+ Returns:
196
+ Dictionary with authentication configuration
197
+ """
198
+ auth_config = self.config.grpc.auth
199
+
200
+ auth_settings = {
201
+ "enabled": auth_config.enabled,
202
+ "require_auth": auth_config.require_auth,
203
+ "token_header": auth_config.token_header,
204
+ "token_prefix": auth_config.token_prefix,
205
+ "jwt_algorithm": auth_config.jwt_algorithm,
206
+ "jwt_verify_exp": auth_config.jwt_verify_exp,
207
+ "jwt_leeway": auth_config.jwt_leeway,
208
+ "public_methods": auth_config.public_methods,
209
+ }
210
+
211
+ # Use JWT secret from auth config or fall back to Django SECRET_KEY
212
+ if auth_config.jwt_secret_key:
213
+ auth_settings["jwt_secret_key"] = auth_config.jwt_secret_key
214
+ else:
215
+ # Will be resolved from Django settings at runtime
216
+ auth_settings["jwt_secret_key"] = None # Signal to use Django SECRET_KEY
217
+
218
+ return auth_settings
219
+
220
+ def _build_grpc_proto_settings(self) -> Dict[str, Any]:
221
+ """
222
+ Build GRPC_PROTO settings dictionary.
223
+
224
+ Returns:
225
+ Dictionary with proto generation configuration
226
+ """
227
+ proto_config = self.config.grpc.proto
228
+
229
+ proto_settings = {
230
+ "auto_generate": proto_config.auto_generate,
231
+ "output_dir": proto_config.output_dir,
232
+ "package_prefix": proto_config.package_prefix,
233
+ "include_services": proto_config.include_services,
234
+ "field_naming": proto_config.field_naming,
235
+ }
236
+
237
+ return proto_settings
238
+
239
+ def _build_interceptors(self) -> List[str]:
240
+ """
241
+ Build list of server interceptors.
242
+
243
+ Interceptors are added in order:
244
+ 1. Request logger interceptor (always enabled for monitoring)
245
+ 2. Logging interceptor (if dev mode)
246
+ 3. Auth interceptor (if auth enabled)
247
+ 4. Metrics interceptor (if dev mode)
248
+ 5. Custom interceptors (from config)
249
+
250
+ Returns:
251
+ List of interceptor class paths
252
+ """
253
+ interceptors = []
254
+
255
+ # Check if we're in dev mode
256
+ is_dev = self.config.env_mode in ("local", "development", "dev")
257
+
258
+ # Add request logger interceptor (always enabled for DB logging)
259
+ interceptors.append(
260
+ "django_cfg.apps.grpc.interceptors.RequestLoggerInterceptor"
261
+ )
262
+
263
+ # Add logging interceptor in dev mode
264
+ if is_dev:
265
+ interceptors.append(
266
+ "django_cfg.apps.grpc.interceptors.LoggingInterceptor"
267
+ )
268
+
269
+ # Add auth interceptor if enabled
270
+ if self.config.grpc.auth.enabled:
271
+ interceptors.append(
272
+ "django_cfg.apps.grpc.auth.JWTAuthInterceptor"
273
+ )
274
+
275
+ # Add metrics interceptor in dev mode
276
+ if is_dev:
277
+ interceptors.append(
278
+ "django_cfg.apps.grpc.interceptors.MetricsInterceptor"
279
+ )
280
+
281
+ # Add custom interceptors from server config
282
+ if self.config.grpc.server.interceptors:
283
+ interceptors.extend(self.config.grpc.server.interceptors)
284
+
285
+ return interceptors
286
+
287
+ def _resolve_handlers_hook(self, handlers_hook: str) -> str:
288
+ """
289
+ Resolve handlers hook path.
290
+
291
+ Replaces {ROOT_URLCONF} placeholder with actual ROOT_URLCONF value.
292
+
293
+ Args:
294
+ handlers_hook: Handler hook path (may contain {ROOT_URLCONF})
295
+
296
+ Returns:
297
+ Resolved handler hook path
298
+
299
+ Example:
300
+ >>> self._resolve_handlers_hook("{ROOT_URLCONF}.grpc_handlers")
301
+ 'myproject.urls.grpc_handlers'
302
+ """
303
+ if "{ROOT_URLCONF}" in handlers_hook:
304
+ # Get ROOT_URLCONF from config
305
+ root_urlconf = getattr(self.config, "root_urlconf", None)
306
+ if not root_urlconf:
307
+ # Fall back to default Django pattern
308
+ root_urlconf = f"{self.config.project_name}.urls"
309
+ logger.debug(
310
+ f"ROOT_URLCONF not set, using default: {root_urlconf}"
311
+ )
312
+
313
+ handlers_hook = handlers_hook.replace("{ROOT_URLCONF}", root_urlconf)
314
+
315
+ return handlers_hook
316
+
317
+
318
+ __all__ = ["GRPCSettingsGenerator"]
@@ -77,8 +77,8 @@ class SettingsOrchestrator:
77
77
  settings.update(self._generate_session_settings())
78
78
  settings.update(self._generate_third_party_settings())
79
79
  settings.update(self._generate_api_settings())
80
- settings.update(self._generate_tasks_settings())
81
- settings.update(self._generate_django_q2_settings())
80
+ settings.update(self._generate_django_rq_settings())
81
+ settings.update(self._generate_grpc_settings())
82
82
  settings.update(self._generate_tailwind_settings())
83
83
 
84
84
  # Apply additional settings (user overrides)
@@ -215,26 +215,26 @@ class SettingsOrchestrator:
215
215
  except Exception as e:
216
216
  raise ConfigurationError(f"Failed to generate API settings: {e}") from e
217
217
 
218
- def _generate_tasks_settings(self) -> Dict[str, Any]:
219
- """Generate background tasks settings."""
218
+ def _generate_django_rq_settings(self) -> Dict[str, Any]:
219
+ """Generate Django-RQ task queue and scheduler settings."""
220
+ if not hasattr(self.config, "django_rq") or not self.config.django_rq:
221
+ return {}
222
+
220
223
  try:
221
- from .integration_generators.tasks import TasksSettingsGenerator
222
- generator = TasksSettingsGenerator(self.config)
224
+ from .integration_generators.django_rq import DjangoRQSettingsGenerator
225
+ generator = DjangoRQSettingsGenerator(self.config.django_rq, parent_config=self.config)
223
226
  return generator.generate()
224
227
  except Exception as e:
225
- raise ConfigurationError(f"Failed to generate tasks settings: {e}") from e
226
-
227
- def _generate_django_q2_settings(self) -> Dict[str, Any]:
228
- """Generate Django-Q2 task scheduling settings."""
229
- if not hasattr(self.config, "django_q2") or not self.config.django_q2:
230
- return {}
228
+ raise ConfigurationError(f"Failed to generate Django-RQ settings: {e}") from e
231
229
 
230
+ def _generate_grpc_settings(self) -> Dict[str, Any]:
231
+ """Generate gRPC framework settings."""
232
232
  try:
233
- from .integration_generators.django_q2 import DjangoQ2SettingsGenerator
234
- generator = DjangoQ2SettingsGenerator(self.config.django_q2, parent_config=self.config)
233
+ from .integration_generators.grpc_generator import GRPCSettingsGenerator
234
+ generator = GRPCSettingsGenerator(self.config)
235
235
  return generator.generate()
236
236
  except Exception as e:
237
- raise ConfigurationError(f"Failed to generate Django-Q2 settings: {e}") from e
237
+ raise ConfigurationError(f"Failed to generate gRPC settings: {e}") from e
238
238
 
239
239
  def _generate_tailwind_settings(self) -> Dict[str, Any]:
240
240
  """Generate Tailwind CSS settings."""
@@ -416,20 +416,20 @@ class StartupDisplayManager(BaseDisplayManager):
416
416
  task_table.add_column("Value", style="white")
417
417
 
418
418
  # Show real tasks status
419
- tasks_enabled = self.config.should_enable_tasks()
419
+ tasks_enabled = self.config.should_enable_rq()
420
420
  if tasks_enabled:
421
421
  task_table.add_row("Tasks Enabled", "[green]True[/green]")
422
422
  else:
423
423
  task_table.add_row("Tasks Enabled", "[yellow]False[/yellow]")
424
424
 
425
- if hasattr(self.config, 'tasks') and self.config.tasks:
426
- queue_name = getattr(self.config.tasks, 'queue_name', 'default')
427
- task_table.add_row("Queue", f"[yellow]{queue_name}[/yellow]")
425
+ if hasattr(self.config, 'django_rq') and self.config.django_rq:
426
+ queue_names = ', '.join(self.config.django_rq.get_queue_names())
427
+ task_table.add_row("Queues", f"[yellow]{queue_names}[/yellow]")
428
428
  else:
429
- task_table.add_row("Queue", "[yellow]default[/yellow]")
429
+ task_table.add_row("Queues", "[yellow]default[/yellow]")
430
430
 
431
431
  # Add worker command
432
- task_table.add_row("Start Workers", "[bright_blue]poetry run python manage.py runrearq[/bright_blue]")
432
+ task_table.add_row("Start Workers", "[bright_blue]poetry run python manage.py rqworker default[/bright_blue]")
433
433
 
434
434
  task_panel = self.create_full_width_panel(
435
435
  task_table,
@@ -465,13 +465,6 @@ class StartupDisplayManager(BaseDisplayManager):
465
465
  payments_count = 0
466
466
 
467
467
  config = self.config
468
- if config and config.should_enable_tasks():
469
- try:
470
- from django_cfg.modules.django_tasks import extend_constance_config_with_tasks
471
- tasks_fields = extend_constance_config_with_tasks()
472
- tasks_count = len(tasks_fields)
473
- except:
474
- pass
475
468
 
476
469
  if config and config.enable_knowbase:
477
470
  try:
@@ -623,13 +616,6 @@ class StartupDisplayManager(BaseDisplayManager):
623
616
 
624
617
  # Try to get individual app field counts
625
618
  config = self.config
626
- if config and config.should_enable_tasks():
627
- try:
628
- from django_cfg.modules.django_tasks import extend_constance_config_with_tasks
629
- tasks_fields = extend_constance_config_with_tasks()
630
- tasks_count = len(tasks_fields)
631
- except:
632
- pass
633
619
 
634
620
  if config and config.enable_knowbase:
635
621
  try:
@@ -5,8 +5,10 @@ Shared mixins for DRF views and viewsets.
5
5
  """
6
6
  from .admin_api import AdminAPIMixin
7
7
  from .client_api import ClientAPIMixin
8
+ from .superadmin_api import SuperAdminAPIMixin
8
9
 
9
10
  __all__ = [
10
11
  "AdminAPIMixin",
11
12
  "ClientAPIMixin",
13
+ "SuperAdminAPIMixin",
12
14
  ]
@@ -0,0 +1,59 @@
1
+ """
2
+ SuperAdmin API Mixin.
3
+
4
+ Common configuration for superuser-only API endpoints.
5
+ More restrictive than AdminAPIMixin - requires is_superuser flag.
6
+ """
7
+ from rest_framework.authentication import BasicAuthentication, SessionAuthentication
8
+ from rest_framework.permissions import BasePermission
9
+ from rest_framework_simplejwt.authentication import JWTAuthentication
10
+
11
+
12
+ class IsSuperUser(BasePermission):
13
+ """
14
+ Permission that allows access only to superusers.
15
+
16
+ More restrictive than IsAdminUser - requires is_superuser flag.
17
+ Use for sensitive operations like command execution.
18
+ """
19
+
20
+ def has_permission(self, request, view):
21
+ """Check if user is authenticated and is a superuser."""
22
+ return bool(
23
+ request.user and
24
+ request.user.is_authenticated and
25
+ request.user.is_superuser
26
+ )
27
+
28
+
29
+ class SuperAdminAPIMixin:
30
+ """
31
+ Mixin for superuser-only API endpoints.
32
+
33
+ Provides:
34
+ - JWT, Session, and Basic authentication
35
+ - IsSuperUser permission requirement (is_superuser=True)
36
+
37
+ Usage:
38
+ class MyViewSet(SuperAdminAPIMixin, viewsets.ModelViewSet):
39
+ queryset = MyModel.objects.all()
40
+ serializer_class = MySerializer
41
+
42
+ Authentication Methods:
43
+ 1. JWT Token (Bearer): For frontend SPA authentication
44
+ 2. Session: For Django admin integration
45
+ 3. Basic Auth: For testing and scripts
46
+
47
+ All endpoints require superuser privileges.
48
+ Only use this for sensitive operations like:
49
+ - Command execution
50
+ - System configuration changes
51
+ - Direct database operations
52
+ """
53
+
54
+ authentication_classes = [
55
+ JWTAuthentication, # JWT tokens (Bearer)
56
+ SessionAuthentication, # Django session (for admin)
57
+ BasicAuthentication, # HTTP Basic (for testing)
58
+ ]
59
+ permission_classes = [IsSuperUser]
@@ -35,7 +35,7 @@ from .base.module import BaseCfgAutoModule
35
35
  from .django.axes import AxesConfig
36
36
  from .django.constance import ConstanceConfig, ConstanceField
37
37
  from .django.crypto_fields import CryptoFieldsConfig
38
- from .django.django_q2 import DjangoQ2Config, DjangoQ2ScheduleConfig
38
+ from .django.django_rq import DjangoRQConfig, RQQueueConfig
39
39
  from .django.environment import EnvironmentConfig
40
40
  from .django.openapi import OpenAPIClientConfig
41
41
  from .infrastructure.cache import CacheConfig
@@ -80,8 +80,8 @@ __all__ = [
80
80
  "EnvironmentConfig",
81
81
  "ConstanceConfig",
82
82
  "ConstanceField",
83
- "DjangoQ2Config",
84
- "DjangoQ2ScheduleConfig",
83
+ "DjangoRQConfig",
84
+ "RQQueueConfig",
85
85
  "OpenAPIClientConfig",
86
86
  "UnfoldConfig",
87
87
  "AxesConfig",
@@ -0,0 +1,59 @@
1
+ """
2
+ gRPC configuration models.
3
+
4
+ Type-safe Pydantic v2 models for gRPC server, authentication, and proto generation.
5
+
6
+ Requires: pip install django-cfg[grpc]
7
+
8
+ Example:
9
+ >>> from django_cfg.models.api.grpc import GRPCConfig, GRPCServerConfig
10
+ >>> config = GRPCConfig(
11
+ ... enabled=True,
12
+ ... server=GRPCServerConfig(port=50051)
13
+ ... )
14
+ """
15
+
16
+ from typing import TYPE_CHECKING
17
+
18
+ if TYPE_CHECKING:
19
+ from .config import (
20
+ GRPCAuthConfig,
21
+ GRPCConfig,
22
+ GRPCProtoConfig,
23
+ GRPCServerConfig,
24
+ )
25
+
26
+ __all__ = [
27
+ "GRPCConfig",
28
+ "GRPCServerConfig",
29
+ "GRPCAuthConfig",
30
+ "GRPCProtoConfig",
31
+ ]
32
+
33
+
34
+ def __getattr__(name: str):
35
+ """Lazy import with helpful error message."""
36
+ if name in __all__:
37
+ try:
38
+ from .config import (
39
+ GRPCAuthConfig,
40
+ GRPCConfig,
41
+ GRPCProtoConfig,
42
+ GRPCServerConfig,
43
+ )
44
+
45
+ return {
46
+ "GRPCConfig": GRPCConfig,
47
+ "GRPCServerConfig": GRPCServerConfig,
48
+ "GRPCAuthConfig": GRPCAuthConfig,
49
+ "GRPCProtoConfig": GRPCProtoConfig,
50
+ }[name]
51
+
52
+ except ImportError as e:
53
+ raise ImportError(
54
+ f"gRPC support requires additional dependencies. "
55
+ f"Install with: pip install django-cfg[grpc]\n"
56
+ f"Missing module: {e.name}"
57
+ ) from e
58
+
59
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")