django-cfg 1.4.119__py3-none-any.whl → 1.5.1__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 (84) hide show
  1. django_cfg/__init__.py +8 -4
  2. django_cfg/apps/centrifugo/admin/centrifugo_log.py +33 -71
  3. django_cfg/apps/grpc/__init__.py +9 -0
  4. django_cfg/apps/grpc/admin/__init__.py +11 -0
  5. django_cfg/apps/grpc/admin/config.py +89 -0
  6. django_cfg/apps/grpc/admin/grpc_request_log.py +252 -0
  7. django_cfg/apps/grpc/apps.py +28 -0
  8. django_cfg/apps/grpc/auth/__init__.py +9 -0
  9. django_cfg/apps/grpc/auth/jwt_auth.py +295 -0
  10. django_cfg/apps/grpc/interceptors/__init__.py +19 -0
  11. django_cfg/apps/grpc/interceptors/errors.py +241 -0
  12. django_cfg/apps/grpc/interceptors/logging.py +270 -0
  13. django_cfg/apps/grpc/interceptors/metrics.py +306 -0
  14. django_cfg/apps/grpc/interceptors/request_logger.py +515 -0
  15. django_cfg/apps/grpc/management/__init__.py +1 -0
  16. django_cfg/apps/grpc/management/commands/__init__.py +0 -0
  17. django_cfg/apps/grpc/management/commands/rungrpc.py +302 -0
  18. django_cfg/apps/grpc/managers/__init__.py +10 -0
  19. django_cfg/apps/grpc/managers/grpc_request_log.py +310 -0
  20. django_cfg/apps/grpc/migrations/0001_initial.py +69 -0
  21. django_cfg/apps/grpc/migrations/0002_rename_django_cfg__service_4c4a8e_idx_django_cfg__service_584308_idx_and_more.py +38 -0
  22. django_cfg/apps/grpc/migrations/__init__.py +0 -0
  23. django_cfg/apps/grpc/models/__init__.py +9 -0
  24. django_cfg/apps/grpc/models/grpc_request_log.py +219 -0
  25. django_cfg/apps/grpc/serializers/__init__.py +23 -0
  26. django_cfg/apps/grpc/serializers/health.py +18 -0
  27. django_cfg/apps/grpc/serializers/requests.py +18 -0
  28. django_cfg/apps/grpc/serializers/services.py +50 -0
  29. django_cfg/apps/grpc/serializers/stats.py +22 -0
  30. django_cfg/apps/grpc/services/__init__.py +16 -0
  31. django_cfg/apps/grpc/services/base.py +375 -0
  32. django_cfg/apps/grpc/services/discovery.py +415 -0
  33. django_cfg/apps/grpc/urls.py +23 -0
  34. django_cfg/apps/grpc/utils/__init__.py +13 -0
  35. django_cfg/apps/grpc/utils/proto_gen.py +423 -0
  36. django_cfg/apps/grpc/views/__init__.py +9 -0
  37. django_cfg/apps/grpc/views/monitoring.py +497 -0
  38. django_cfg/apps/maintenance/admin/api_key_admin.py +7 -8
  39. django_cfg/apps/maintenance/admin/site_admin.py +5 -4
  40. django_cfg/apps/payments/admin/balance_admin.py +26 -36
  41. django_cfg/apps/payments/admin/payment_admin.py +65 -85
  42. django_cfg/apps/payments/admin/withdrawal_admin.py +65 -100
  43. django_cfg/apps/tasks/admin/task_log.py +20 -47
  44. django_cfg/apps/urls.py +7 -1
  45. django_cfg/config.py +106 -0
  46. django_cfg/core/base/config_model.py +6 -0
  47. django_cfg/core/builders/apps_builder.py +3 -0
  48. django_cfg/core/generation/integration_generators/grpc_generator.py +318 -0
  49. django_cfg/core/generation/orchestrator.py +10 -0
  50. django_cfg/models/api/grpc/__init__.py +59 -0
  51. django_cfg/models/api/grpc/config.py +364 -0
  52. django_cfg/modules/base.py +15 -0
  53. django_cfg/modules/django_admin/__init__.py +2 -0
  54. django_cfg/modules/django_admin/base/pydantic_admin.py +2 -2
  55. django_cfg/modules/django_admin/config/__init__.py +2 -0
  56. django_cfg/modules/django_admin/config/field_config.py +24 -0
  57. django_cfg/modules/django_admin/utils/__init__.py +41 -3
  58. django_cfg/modules/django_admin/utils/badges/__init__.py +13 -0
  59. django_cfg/modules/django_admin/utils/{badges.py → badges/status_badges.py} +3 -3
  60. django_cfg/modules/django_admin/utils/displays/__init__.py +13 -0
  61. django_cfg/modules/django_admin/utils/{displays.py → displays/data_displays.py} +2 -2
  62. django_cfg/modules/django_admin/utils/html/__init__.py +26 -0
  63. django_cfg/modules/django_admin/utils/html/badges.py +47 -0
  64. django_cfg/modules/django_admin/utils/html/base.py +167 -0
  65. django_cfg/modules/django_admin/utils/html/code.py +87 -0
  66. django_cfg/modules/django_admin/utils/html/composition.py +198 -0
  67. django_cfg/modules/django_admin/utils/html/formatting.py +231 -0
  68. django_cfg/modules/django_admin/utils/html/keyvalue.py +219 -0
  69. django_cfg/modules/django_admin/utils/html/markdown_integration.py +108 -0
  70. django_cfg/modules/django_admin/utils/html/progress.py +127 -0
  71. django_cfg/modules/django_admin/utils/html_builder.py +55 -408
  72. django_cfg/modules/django_admin/utils/markdown/__init__.py +21 -0
  73. django_cfg/modules/django_admin/widgets/registry.py +42 -0
  74. django_cfg/modules/django_unfold/navigation.py +28 -0
  75. django_cfg/pyproject.toml +3 -5
  76. django_cfg/registry/modules.py +6 -0
  77. {django_cfg-1.4.119.dist-info → django_cfg-1.5.1.dist-info}/METADATA +10 -1
  78. {django_cfg-1.4.119.dist-info → django_cfg-1.5.1.dist-info}/RECORD +83 -34
  79. django_cfg/modules/django_admin/utils/CODE_BLOCK_DOCS.md +0 -396
  80. /django_cfg/modules/django_admin/utils/{mermaid_plugin.py → markdown/mermaid_plugin.py} +0 -0
  81. /django_cfg/modules/django_admin/utils/{markdown_renderer.py → markdown/renderer.py} +0 -0
  82. {django_cfg-1.4.119.dist-info → django_cfg-1.5.1.dist-info}/WHEEL +0 -0
  83. {django_cfg-1.4.119.dist-info → django_cfg-1.5.1.dist-info}/entry_points.txt +0 -0
  84. {django_cfg-1.4.119.dist-info → django_cfg-1.5.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,38 @@
1
+ # Generated by Django 5.2.7 on 2025-11-01 13:48
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("grpc", "0001_initial"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.RenameIndex(
14
+ model_name="grpcrequestlog",
15
+ new_name="django_cfg__service_584308_idx",
16
+ old_name="django_cfg__service_4c4a8e_idx",
17
+ ),
18
+ migrations.RenameIndex(
19
+ model_name="grpcrequestlog",
20
+ new_name="django_cfg__method__5e704d_idx",
21
+ old_name="django_cfg__method__8e1a7c_idx",
22
+ ),
23
+ migrations.RenameIndex(
24
+ model_name="grpcrequestlog",
25
+ new_name="django_cfg__status_a564a8_idx",
26
+ old_name="django_cfg__status_f3d9a1_idx",
27
+ ),
28
+ migrations.RenameIndex(
29
+ model_name="grpcrequestlog",
30
+ new_name="django_cfg__user_id_f2ada7_idx",
31
+ old_name="django_cfg__user_id_9c2b4f_idx",
32
+ ),
33
+ migrations.RenameIndex(
34
+ model_name="grpcrequestlog",
35
+ new_name="django_cfg__grpc_st_fea09f_idx",
36
+ old_name="django_cfg__grpc_st_a7e5c2_idx",
37
+ ),
38
+ ]
File without changes
@@ -0,0 +1,9 @@
1
+ """
2
+ Models for gRPC app.
3
+ """
4
+
5
+ from .grpc_request_log import GRPCRequestLog
6
+
7
+ __all__ = [
8
+ "GRPCRequestLog",
9
+ ]
@@ -0,0 +1,219 @@
1
+ """
2
+ gRPC Request Log Model.
3
+
4
+ Django model for tracking gRPC requests and responses.
5
+ Provides observability for debugging and monitoring.
6
+ """
7
+
8
+ from django.conf import settings
9
+ from django.db import models
10
+ from django.utils import timezone
11
+
12
+
13
+ class GRPCRequestLog(models.Model):
14
+ """
15
+ Log of gRPC requests and responses.
16
+
17
+ Tracks all gRPC method calls with status, timing, and error tracking.
18
+ Provides observability for debugging and monitoring.
19
+
20
+ Example:
21
+ >>> log = GRPCRequestLog.objects.create(
22
+ ... request_id="abc123",
23
+ ... service_name="myapp.UserService",
24
+ ... method_name="GetUser",
25
+ ... )
26
+ >>> log.mark_success(duration_ms=125)
27
+ """
28
+
29
+ # Custom manager
30
+ from ..managers.grpc_request_log import GRPCRequestLogManager
31
+
32
+ objects: GRPCRequestLogManager = GRPCRequestLogManager()
33
+
34
+ class StatusChoices(models.TextChoices):
35
+ """Status of gRPC request."""
36
+
37
+ PENDING = "pending", "Pending"
38
+ SUCCESS = "success", "Success"
39
+ ERROR = "error", "Error"
40
+ CANCELLED = "cancelled", "Cancelled"
41
+ TIMEOUT = "timeout", "Timeout"
42
+
43
+ # Identity
44
+ request_id = models.CharField(
45
+ max_length=100,
46
+ unique=True,
47
+ db_index=True,
48
+ help_text="Unique request identifier (UUID)",
49
+ )
50
+
51
+ # gRPC details
52
+ service_name = models.CharField(
53
+ max_length=200,
54
+ db_index=True,
55
+ help_text="gRPC service name (e.g., myapp.UserService)",
56
+ )
57
+
58
+ method_name = models.CharField(
59
+ max_length=200,
60
+ db_index=True,
61
+ help_text="gRPC method name (e.g., GetUser)",
62
+ )
63
+
64
+ full_method = models.CharField(
65
+ max_length=400,
66
+ db_index=True,
67
+ help_text="Full method path (e.g., /myapp.UserService/GetUser)",
68
+ )
69
+
70
+ # Request/Response data
71
+ request_size = models.IntegerField(
72
+ null=True,
73
+ blank=True,
74
+ help_text="Request size in bytes",
75
+ )
76
+
77
+ response_size = models.IntegerField(
78
+ null=True,
79
+ blank=True,
80
+ help_text="Response size in bytes",
81
+ )
82
+
83
+ request_data = models.JSONField(
84
+ null=True,
85
+ blank=True,
86
+ help_text="Request data (if logged)",
87
+ )
88
+
89
+ response_data = models.JSONField(
90
+ null=True,
91
+ blank=True,
92
+ help_text="Response data (if logged)",
93
+ )
94
+
95
+ # Status tracking
96
+ status = models.CharField(
97
+ max_length=20,
98
+ choices=StatusChoices.choices,
99
+ default=StatusChoices.PENDING,
100
+ db_index=True,
101
+ help_text="Current status of request",
102
+ )
103
+
104
+ grpc_status_code = models.CharField(
105
+ max_length=50,
106
+ null=True,
107
+ blank=True,
108
+ db_index=True,
109
+ help_text="gRPC status code (OK, CANCELLED, INVALID_ARGUMENT, etc.)",
110
+ )
111
+
112
+ error_message = models.TextField(
113
+ null=True,
114
+ blank=True,
115
+ help_text="Error message if failed",
116
+ )
117
+
118
+ error_details = models.JSONField(
119
+ null=True,
120
+ blank=True,
121
+ help_text="Additional error details",
122
+ )
123
+
124
+ # Performance
125
+ duration_ms = models.IntegerField(
126
+ null=True,
127
+ blank=True,
128
+ help_text="Total duration in milliseconds",
129
+ )
130
+
131
+ # User context
132
+ user = models.ForeignKey(
133
+ settings.AUTH_USER_MODEL,
134
+ on_delete=models.SET_NULL,
135
+ null=True,
136
+ blank=True,
137
+ related_name="grpc_request_logs",
138
+ help_text="Authenticated user (if applicable)",
139
+ )
140
+
141
+ is_authenticated = models.BooleanField(
142
+ default=False,
143
+ db_index=True,
144
+ help_text="Whether request was authenticated",
145
+ )
146
+
147
+ # Client metadata
148
+ client_ip = models.GenericIPAddressField(
149
+ null=True,
150
+ blank=True,
151
+ help_text="Client IP address",
152
+ )
153
+
154
+ user_agent = models.TextField(
155
+ null=True,
156
+ blank=True,
157
+ help_text="User agent from metadata",
158
+ )
159
+
160
+ peer = models.CharField(
161
+ max_length=200,
162
+ null=True,
163
+ blank=True,
164
+ help_text="gRPC peer information",
165
+ )
166
+
167
+ # Timestamps
168
+ created_at = models.DateTimeField(
169
+ auto_now_add=True,
170
+ db_index=True,
171
+ help_text="When request was received",
172
+ )
173
+
174
+ completed_at = models.DateTimeField(
175
+ null=True,
176
+ blank=True,
177
+ db_index=True,
178
+ help_text="When request completed (success/error)",
179
+ )
180
+
181
+ class Meta:
182
+ db_table = "django_cfg_grpc_request_log"
183
+ ordering = ["-created_at"]
184
+ indexes = [
185
+ models.Index(fields=["service_name", "-created_at"]),
186
+ models.Index(fields=["method_name", "-created_at"]),
187
+ models.Index(fields=["status", "-created_at"]),
188
+ models.Index(fields=["user", "-created_at"]),
189
+ models.Index(fields=["grpc_status_code", "-created_at"]),
190
+ ]
191
+ verbose_name = "gRPC Request Log"
192
+ verbose_name_plural = "gRPC Request Logs"
193
+
194
+ def __str__(self) -> str:
195
+ """String representation."""
196
+ return f"{self.full_method} ({self.request_id[:8]}...) - {self.status}"
197
+
198
+ @property
199
+ def is_completed(self) -> bool:
200
+ """Check if request is completed (any terminal status)."""
201
+ return self.status in [
202
+ self.StatusChoices.SUCCESS,
203
+ self.StatusChoices.ERROR,
204
+ self.StatusChoices.CANCELLED,
205
+ self.StatusChoices.TIMEOUT,
206
+ ]
207
+
208
+ @property
209
+ def is_successful(self) -> bool:
210
+ """Check if request was successful."""
211
+ return self.status == self.StatusChoices.SUCCESS
212
+
213
+ @property
214
+ def success_rate(self) -> float:
215
+ """Calculate success rate (for compatibility with stats)."""
216
+ return 1.0 if self.is_successful else 0.0
217
+
218
+
219
+ __all__ = ["GRPCRequestLog"]
@@ -0,0 +1,23 @@
1
+ """
2
+ Pydantic serializers for gRPC monitoring API.
3
+ """
4
+
5
+ from .health import HealthCheckSerializer
6
+ from .requests import RecentRequestsSerializer
7
+ from .services import (
8
+ MethodListSerializer,
9
+ MethodStatsSerializer,
10
+ ServiceListSerializer,
11
+ ServiceStatsSerializer,
12
+ )
13
+ from .stats import OverviewStatsSerializer
14
+
15
+ __all__ = [
16
+ "HealthCheckSerializer",
17
+ "OverviewStatsSerializer",
18
+ "RecentRequestsSerializer",
19
+ "ServiceStatsSerializer",
20
+ "ServiceListSerializer",
21
+ "MethodStatsSerializer",
22
+ "MethodListSerializer",
23
+ ]
@@ -0,0 +1,18 @@
1
+ """
2
+ Health check serializer for gRPC monitoring API.
3
+ """
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class HealthCheckSerializer(BaseModel):
9
+ """Health check response."""
10
+
11
+ status: str = Field(description="Health status: healthy or unhealthy")
12
+ server_host: str = Field(description="Configured gRPC server host")
13
+ server_port: int = Field(description="Configured gRPC server port")
14
+ enabled: bool = Field(description="Whether gRPC is enabled")
15
+ timestamp: str = Field(description="Current timestamp")
16
+
17
+
18
+ __all__ = ["HealthCheckSerializer"]
@@ -0,0 +1,18 @@
1
+ """
2
+ Requests serializers for gRPC monitoring API.
3
+ """
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class RecentRequestsSerializer(BaseModel):
9
+ """Recent gRPC requests list."""
10
+
11
+ requests: list[dict] = Field(description="List of recent requests")
12
+ count: int = Field(description="Number of requests returned")
13
+ total_available: int = Field(description="Total requests available")
14
+ offset: int = Field(default=0, description="Current offset for pagination")
15
+ has_more: bool = Field(default=False, description="Whether more results are available")
16
+
17
+
18
+ __all__ = ["RecentRequestsSerializer"]
@@ -0,0 +1,50 @@
1
+ """
2
+ Services serializers for gRPC monitoring API.
3
+ """
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class ServiceStatsSerializer(BaseModel):
9
+ """Statistics for a single gRPC service."""
10
+
11
+ service_name: str = Field(description="Service name")
12
+ total: int = Field(description="Total requests")
13
+ successful: int = Field(description="Successful requests")
14
+ errors: int = Field(description="Error requests")
15
+ avg_duration_ms: float = Field(description="Average duration")
16
+ last_activity_at: str | None = Field(description="Last activity timestamp")
17
+
18
+
19
+ class ServiceListSerializer(BaseModel):
20
+ """List of gRPC services with statistics."""
21
+
22
+ services: list[ServiceStatsSerializer] = Field(description="Service statistics")
23
+ total_services: int = Field(description="Total number of services")
24
+
25
+
26
+ class MethodStatsSerializer(BaseModel):
27
+ """Statistics for a single gRPC method."""
28
+
29
+ method_name: str = Field(description="Method name")
30
+ service_name: str = Field(description="Service name")
31
+ total: int = Field(description="Total requests")
32
+ successful: int = Field(description="Successful requests")
33
+ errors: int = Field(description="Error requests")
34
+ avg_duration_ms: float = Field(description="Average duration")
35
+ last_activity_at: str | None = Field(description="Last activity timestamp")
36
+
37
+
38
+ class MethodListSerializer(BaseModel):
39
+ """List of gRPC methods with statistics."""
40
+
41
+ methods: list[MethodStatsSerializer] = Field(description="Method statistics")
42
+ total_methods: int = Field(description="Total number of methods")
43
+
44
+
45
+ __all__ = [
46
+ "ServiceStatsSerializer",
47
+ "ServiceListSerializer",
48
+ "MethodStatsSerializer",
49
+ "MethodListSerializer",
50
+ ]
@@ -0,0 +1,22 @@
1
+ """
2
+ Statistics serializers for gRPC monitoring API.
3
+ """
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class OverviewStatsSerializer(BaseModel):
9
+ """Overview statistics for gRPC requests."""
10
+
11
+ total: int = Field(description="Total requests in period")
12
+ successful: int = Field(description="Successful requests")
13
+ errors: int = Field(description="Error requests")
14
+ cancelled: int = Field(description="Cancelled requests")
15
+ timeout: int = Field(description="Timeout requests")
16
+ success_rate: float = Field(description="Success rate percentage")
17
+ avg_duration_ms: float = Field(description="Average duration in milliseconds")
18
+ p95_duration_ms: float | None = Field(description="95th percentile duration in milliseconds")
19
+ period_hours: int = Field(description="Statistics period in hours")
20
+
21
+
22
+ __all__ = ["OverviewStatsSerializer"]
@@ -0,0 +1,16 @@
1
+ """
2
+ gRPC services utilities.
3
+
4
+ Provides service discovery and base classes for gRPC services.
5
+ """
6
+
7
+ from .base import AuthRequiredService, BaseService, ReadOnlyService
8
+ from .discovery import ServiceDiscovery, discover_and_register_services
9
+
10
+ __all__ = [
11
+ "BaseService",
12
+ "ReadOnlyService",
13
+ "AuthRequiredService",
14
+ "ServiceDiscovery",
15
+ "discover_and_register_services",
16
+ ]