django-cfg 1.5.8__py3-none-any.whl → 1.5.14__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 (119) 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/agents/management/commands/create_agent.py +5 -194
  6. django_cfg/apps/business/agents/management/commands/load_agent_templates.py +205 -0
  7. django_cfg/apps/business/agents/management/commands/orchestrator_status.py +4 -2
  8. django_cfg/apps/business/knowbase/management/commands/knowbase_stats.py +4 -2
  9. django_cfg/apps/business/knowbase/management/commands/setup_knowbase.py +4 -2
  10. django_cfg/apps/business/newsletter/management/commands/test_newsletter.py +5 -2
  11. django_cfg/apps/business/payments/management/commands/check_payment_status.py +4 -2
  12. django_cfg/apps/business/payments/management/commands/create_payment.py +4 -2
  13. django_cfg/apps/business/payments/management/commands/sync_currencies.py +4 -2
  14. django_cfg/apps/integrations/centrifugo/management/commands/generate_centrifugo_clients.py +5 -5
  15. django_cfg/apps/integrations/centrifugo/serializers/__init__.py +2 -1
  16. django_cfg/apps/integrations/centrifugo/serializers/publishes.py +22 -2
  17. django_cfg/apps/integrations/centrifugo/views/monitoring.py +25 -40
  18. django_cfg/apps/integrations/grpc/admin/__init__.py +7 -1
  19. django_cfg/apps/integrations/grpc/admin/config.py +113 -9
  20. django_cfg/apps/integrations/grpc/admin/grpc_api_key.py +129 -0
  21. django_cfg/apps/integrations/grpc/admin/grpc_request_log.py +72 -63
  22. django_cfg/apps/integrations/grpc/admin/grpc_server_status.py +236 -0
  23. django_cfg/apps/integrations/grpc/auth/__init__.py +11 -3
  24. django_cfg/apps/integrations/grpc/auth/api_key_auth.py +320 -0
  25. django_cfg/apps/integrations/grpc/interceptors/logging.py +17 -20
  26. django_cfg/apps/integrations/grpc/interceptors/metrics.py +15 -14
  27. django_cfg/apps/integrations/grpc/interceptors/request_logger.py +79 -59
  28. django_cfg/apps/integrations/grpc/management/commands/generate_protos.py +130 -0
  29. django_cfg/apps/integrations/grpc/management/commands/rungrpc.py +171 -96
  30. django_cfg/apps/integrations/grpc/management/commands/test_grpc_integration.py +75 -0
  31. django_cfg/apps/integrations/grpc/managers/__init__.py +2 -0
  32. django_cfg/apps/integrations/grpc/managers/grpc_api_key.py +192 -0
  33. django_cfg/apps/integrations/grpc/managers/grpc_server_status.py +19 -11
  34. django_cfg/apps/integrations/grpc/migrations/0005_grpcapikey.py +143 -0
  35. django_cfg/apps/integrations/grpc/migrations/0006_grpcrequestlog_api_key_and_more.py +34 -0
  36. django_cfg/apps/integrations/grpc/models/__init__.py +2 -0
  37. django_cfg/apps/integrations/grpc/models/grpc_api_key.py +198 -0
  38. django_cfg/apps/integrations/grpc/models/grpc_request_log.py +11 -0
  39. django_cfg/apps/integrations/grpc/models/grpc_server_status.py +39 -4
  40. django_cfg/apps/integrations/grpc/serializers/__init__.py +22 -6
  41. django_cfg/apps/integrations/grpc/serializers/api_keys.py +63 -0
  42. django_cfg/apps/integrations/grpc/serializers/charts.py +118 -120
  43. django_cfg/apps/integrations/grpc/serializers/config.py +65 -51
  44. django_cfg/apps/integrations/grpc/serializers/health.py +7 -7
  45. django_cfg/apps/integrations/grpc/serializers/proto_files.py +74 -0
  46. django_cfg/apps/integrations/grpc/serializers/requests.py +13 -7
  47. django_cfg/apps/integrations/grpc/serializers/service_registry.py +181 -112
  48. django_cfg/apps/integrations/grpc/serializers/services.py +14 -32
  49. django_cfg/apps/integrations/grpc/serializers/stats.py +50 -12
  50. django_cfg/apps/integrations/grpc/serializers/testing.py +66 -58
  51. django_cfg/apps/integrations/grpc/services/__init__.py +2 -0
  52. django_cfg/apps/integrations/grpc/services/monitoring_service.py +149 -43
  53. django_cfg/apps/integrations/grpc/services/proto_files_manager.py +268 -0
  54. django_cfg/apps/integrations/grpc/services/service_registry.py +48 -46
  55. django_cfg/apps/integrations/grpc/services/testing_service.py +10 -15
  56. django_cfg/apps/integrations/grpc/urls.py +8 -0
  57. django_cfg/apps/integrations/grpc/utils/__init__.py +4 -13
  58. django_cfg/apps/integrations/grpc/utils/integration_test.py +334 -0
  59. django_cfg/apps/integrations/grpc/utils/proto_gen.py +48 -8
  60. django_cfg/apps/integrations/grpc/utils/streaming_logger.py +177 -0
  61. django_cfg/apps/integrations/grpc/views/__init__.py +4 -0
  62. django_cfg/apps/integrations/grpc/views/api_keys.py +255 -0
  63. django_cfg/apps/integrations/grpc/views/charts.py +21 -14
  64. django_cfg/apps/integrations/grpc/views/config.py +8 -6
  65. django_cfg/apps/integrations/grpc/views/monitoring.py +51 -79
  66. django_cfg/apps/integrations/grpc/views/proto_files.py +214 -0
  67. django_cfg/apps/integrations/grpc/views/services.py +30 -21
  68. django_cfg/apps/integrations/grpc/views/testing.py +45 -43
  69. django_cfg/apps/integrations/rq/views/jobs.py +19 -9
  70. django_cfg/apps/integrations/rq/views/schedule.py +7 -3
  71. django_cfg/apps/system/dashboard/serializers/commands.py +25 -1
  72. django_cfg/apps/system/dashboard/services/commands_service.py +12 -1
  73. django_cfg/apps/system/maintenance/management/commands/maintenance.py +5 -2
  74. django_cfg/apps/system/maintenance/management/commands/process_scheduled_maintenance.py +4 -2
  75. django_cfg/apps/system/maintenance/management/commands/sync_cloudflare.py +5 -2
  76. django_cfg/config.py +33 -0
  77. django_cfg/core/generation/integration_generators/grpc_generator.py +30 -32
  78. django_cfg/management/commands/check_endpoints.py +2 -2
  79. django_cfg/management/commands/check_settings.py +3 -10
  80. django_cfg/management/commands/clear_constance.py +3 -10
  81. django_cfg/management/commands/create_token.py +4 -11
  82. django_cfg/management/commands/list_urls.py +4 -10
  83. django_cfg/management/commands/migrate_all.py +18 -12
  84. django_cfg/management/commands/migrator.py +4 -11
  85. django_cfg/management/commands/script.py +4 -10
  86. django_cfg/management/commands/show_config.py +8 -16
  87. django_cfg/management/commands/show_urls.py +5 -11
  88. django_cfg/management/commands/superuser.py +4 -11
  89. django_cfg/management/commands/tree.py +5 -10
  90. django_cfg/management/utils/README.md +402 -0
  91. django_cfg/management/utils/__init__.py +29 -0
  92. django_cfg/management/utils/mixins.py +176 -0
  93. django_cfg/middleware/pagination.py +53 -54
  94. django_cfg/models/api/grpc/__init__.py +15 -21
  95. django_cfg/models/api/grpc/config.py +155 -73
  96. django_cfg/models/ngrok/config.py +7 -6
  97. django_cfg/modules/django_client/core/generator/python/files_generator.py +5 -13
  98. django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +16 -4
  99. django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +2 -3
  100. django_cfg/modules/django_client/core/generator/typescript/files_generator.py +6 -5
  101. django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +12 -8
  102. django_cfg/modules/django_client/core/parser/base.py +114 -30
  103. django_cfg/modules/django_client/management/commands/generate_client.py +5 -2
  104. django_cfg/modules/django_client/management/commands/validate_openapi.py +5 -2
  105. django_cfg/modules/django_email/management/commands/test_email.py +4 -10
  106. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +16 -13
  107. django_cfg/modules/django_telegram/management/commands/test_telegram.py +4 -11
  108. django_cfg/modules/django_twilio/management/commands/test_twilio.py +4 -11
  109. django_cfg/modules/django_unfold/navigation.py +6 -18
  110. django_cfg/pyproject.toml +1 -1
  111. django_cfg/registry/modules.py +1 -4
  112. django_cfg/requirements.txt +52 -0
  113. django_cfg/static/frontend/admin.zip +0 -0
  114. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/METADATA +1 -1
  115. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/RECORD +118 -97
  116. django_cfg/apps/integrations/grpc/auth/jwt_auth.py +0 -295
  117. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/WHEEL +0 -0
  118. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/entry_points.txt +0 -0
  119. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/licenses/LICENSE +0 -0
@@ -3,17 +3,19 @@ Knowledge Base statistics command.
3
3
  """
4
4
 
5
5
  from django.contrib.auth import get_user_model
6
- from django.core.management.base import BaseCommand
7
6
  from django.db import models
8
7
  from django.db.models import Avg, Count, ExpressionWrapper, F, Q, Sum
9
8
  from django.db.models.functions import Extract
10
9
 
10
+ from django_cfg.management.utils import SafeCommand
11
+
11
12
  User = get_user_model()
12
13
 
13
14
 
14
- class Command(BaseCommand):
15
+ class Command(SafeCommand):
15
16
  """Display Knowledge Base statistics."""
16
17
 
18
+ command_name = 'knowbase_stats'
17
19
  help = 'Display Knowledge Base usage statistics'
18
20
 
19
21
  def add_arguments(self, parser):
@@ -2,13 +2,15 @@
2
2
  Setup command for Knowledge Base application.
3
3
  """
4
4
 
5
- from django.core.management.base import BaseCommand
6
5
  from django.db import connection
7
6
 
7
+ from django_cfg.management.utils import AdminCommand
8
8
 
9
- class Command(BaseCommand):
9
+
10
+ class Command(AdminCommand):
10
11
  """Setup Knowledge Base with pgvector extension and initial data."""
11
12
 
13
+ command_name = 'setup_knowbase'
12
14
  help = 'Setup Knowledge Base with pgvector extension and run migrations'
13
15
 
14
16
  def add_arguments(self, parser):
@@ -3,7 +3,9 @@ Management command to test newsletter sending functionality.
3
3
  """
4
4
 
5
5
  from django.contrib.auth import get_user_model
6
- from django.core.management.base import BaseCommand, CommandError
6
+ from django.core.management.base import CommandError
7
+
8
+ from django_cfg.management.utils import SafeCommand
7
9
 
8
10
  from django_cfg.apps.business.newsletter.models import Newsletter, NewsletterCampaign, NewsletterSubscription
9
11
  from django_cfg.apps.business.newsletter.services.email_service import NewsletterEmailService
@@ -11,7 +13,8 @@ from django_cfg.apps.business.newsletter.services.email_service import Newslette
11
13
  User = get_user_model()
12
14
 
13
15
 
14
- class Command(BaseCommand):
16
+ class Command(SafeCommand):
17
+ command_name = 'test_newsletter'
15
18
  help = 'Test newsletter sending functionality'
16
19
 
17
20
  def add_arguments(self, parser):
@@ -7,11 +7,12 @@ Uses questionary for interactive selection or accepts payment ID as argument.
7
7
  from uuid import UUID
8
8
 
9
9
  import questionary
10
- from django.core.management.base import BaseCommand
11
10
  from rich.console import Console
12
11
  from rich.panel import Panel
13
12
  from rich.table import Table
14
13
 
14
+ from django_cfg.management.utils import InteractiveCommand
15
+
15
16
  from django_cfg.apps.business.payments.models import Payment
16
17
  from django_cfg.apps.business.payments.services import PaymentService, CheckStatusRequest
17
18
  from django_cfg.apps.business.payments.api.views import get_nowpayments_provider
@@ -19,7 +20,8 @@ from django_cfg.apps.business.payments.api.views import get_nowpayments_provider
19
20
  console = Console()
20
21
 
21
22
 
22
- class Command(BaseCommand):
23
+ class Command(InteractiveCommand):
24
+ command_name = 'check_payment_status'
23
25
  help = 'Check payment status interactively or by payment ID'
24
26
 
25
27
  def add_arguments(self, parser):
@@ -8,11 +8,12 @@ from decimal import Decimal, InvalidOperation
8
8
 
9
9
  import questionary
10
10
  from django.contrib.auth import get_user_model
11
- from django.core.management.base import BaseCommand
12
11
  from rich.console import Console
13
12
  from rich.panel import Panel
14
13
  from rich.table import Table
15
14
 
15
+ from django_cfg.management.utils import InteractiveCommand
16
+
16
17
  from django_cfg.apps.business.payments.models import Currency, Payment
17
18
  from django_cfg.apps.business.payments.services import PaymentService, CreatePaymentRequest
18
19
  from django_cfg.apps.business.payments.api.views import get_nowpayments_provider
@@ -21,7 +22,8 @@ User = get_user_model()
21
22
  console = Console()
22
23
 
23
24
 
24
- class Command(BaseCommand):
25
+ class Command(InteractiveCommand):
26
+ command_name = 'create_payment'
25
27
  help = 'Create a payment interactively using questionary wizard'
26
28
 
27
29
  def add_arguments(self, parser):
@@ -5,19 +5,21 @@ Fetches available currencies from NowPayments and updates local database.
5
5
  """
6
6
 
7
7
  import questionary
8
- from django.core.management.base import BaseCommand
9
8
  from rich.console import Console
10
9
  from rich.panel import Panel
11
10
  from rich.progress import Progress, SpinnerColumn, TextColumn
12
11
  from rich.table import Table
13
12
 
13
+ from django_cfg.management.utils import AdminCommand
14
+
14
15
  from django_cfg.apps.business.payments.models import Currency
15
16
  from django_cfg.apps.business.payments.api.views import get_nowpayments_provider
16
17
 
17
18
  console = Console()
18
19
 
19
20
 
20
- class Command(BaseCommand):
21
+ class Command(AdminCommand):
22
+ command_name = 'sync_currencies'
21
23
  help = 'Sync currencies from NowPayments provider'
22
24
 
23
25
  def add_arguments(self, parser):
@@ -6,25 +6,25 @@ Usage:
6
6
  python manage.py generate_centrifugo_clients -o ./clients --python --verbose
7
7
  """
8
8
 
9
- import logging
10
9
  from pathlib import Path
11
10
  from typing import List
12
11
 
13
- from django.core.management.base import BaseCommand, CommandError
12
+ from django.core.management.base import CommandError
14
13
  from django.utils.termcolors import colorize
15
14
 
15
+ from django_cfg.management.utils import AdminCommand
16
+
16
17
  from django_cfg.apps.integrations.centrifugo.codegen.discovery import discover_rpc_methods_from_router
17
18
  from django_cfg.apps.integrations.centrifugo.codegen.generators.python_thin import PythonThinGenerator
18
19
  from django_cfg.apps.integrations.centrifugo.codegen.generators.typescript_thin import TypeScriptThinGenerator
19
20
  from django_cfg.apps.integrations.centrifugo.codegen.generators.go_thin import GoThinGenerator
20
21
  from django_cfg.apps.integrations.centrifugo.router import get_global_router
21
22
 
22
- logger = logging.getLogger(__name__)
23
-
24
23
 
25
- class Command(BaseCommand):
24
+ class Command(AdminCommand):
26
25
  """Generate type-safe client SDKs for Centrifugo WebSocket RPC."""
27
26
 
27
+ command_name = 'generate_centrifugo_clients'
28
28
  help = "Generate type-safe client SDKs for Centrifugo WebSocket RPC from @websocket_rpc handlers"
29
29
 
30
30
  def add_arguments(self, parser):
@@ -16,13 +16,14 @@ from .admin_api import (
16
16
  )
17
17
  from .channels import ChannelListSerializer, ChannelStatsSerializer
18
18
  from .health import HealthCheckSerializer
19
- from .publishes import RecentPublishesSerializer
19
+ from .publishes import PublishSerializer, RecentPublishesSerializer
20
20
  from .stats import CentrifugoOverviewStatsSerializer
21
21
 
22
22
  __all__ = [
23
23
  # Monitoring API (Django logs)
24
24
  "HealthCheckSerializer",
25
25
  "CentrifugoOverviewStatsSerializer",
26
+ "PublishSerializer",
26
27
  "RecentPublishesSerializer",
27
28
  "ChannelStatsSerializer",
28
29
  "ChannelListSerializer",
@@ -2,11 +2,31 @@
2
2
  Publishes serializers for Centrifugo monitoring API.
3
3
  """
4
4
 
5
+ from datetime import datetime
6
+ from typing import Optional
7
+
5
8
  from pydantic import BaseModel, Field
9
+ from rest_framework import serializers
10
+
11
+
12
+ class PublishSerializer(serializers.Serializer):
13
+ """Single publish item for DRF pagination."""
14
+
15
+ message_id = serializers.CharField()
16
+ channel = serializers.CharField()
17
+ status = serializers.CharField()
18
+ wait_for_ack = serializers.BooleanField()
19
+ acks_received = serializers.IntegerField()
20
+ acks_expected = serializers.IntegerField()
21
+ duration_ms = serializers.FloatField(allow_null=True)
22
+ created_at = serializers.DateTimeField()
23
+ completed_at = serializers.DateTimeField(allow_null=True)
24
+ error_code = serializers.CharField(allow_null=True)
25
+ error_message = serializers.CharField(allow_null=True)
6
26
 
7
27
 
8
28
  class RecentPublishesSerializer(BaseModel):
9
- """Recent publishes list."""
29
+ """Recent publishes list (DEPRECATED - use DRF pagination instead)."""
10
30
 
11
31
  publishes: list[dict] = Field(description="List of recent publishes")
12
32
  count: int = Field(description="Number of publishes returned")
@@ -15,4 +35,4 @@ class RecentPublishesSerializer(BaseModel):
15
35
  has_more: bool = Field(default=False, description="Whether more results are available")
16
36
 
17
37
 
18
- __all__ = ["RecentPublishesSerializer"]
38
+ __all__ = ["PublishSerializer", "RecentPublishesSerializer"]
@@ -23,6 +23,7 @@ from ..serializers import (
23
23
  ChannelListSerializer,
24
24
  ChannelStatsSerializer,
25
25
  HealthCheckSerializer,
26
+ PublishSerializer,
26
27
  RecentPublishesSerializer,
27
28
  )
28
29
  from ..services import get_centrifugo_config
@@ -30,18 +31,20 @@ from ..services import get_centrifugo_config
30
31
  logger = get_logger("centrifugo.monitoring")
31
32
 
32
33
 
33
- class CentrifugoMonitorViewSet(AdminAPIMixin, viewsets.ViewSet):
34
+ class CentrifugoMonitorViewSet(AdminAPIMixin, viewsets.GenericViewSet):
34
35
  """
35
36
  ViewSet for Centrifugo monitoring and statistics.
36
37
 
37
38
  Provides comprehensive monitoring data for Centrifugo publishes including:
38
39
  - Health checks
39
40
  - Overview statistics
40
- - Recent publishes
41
+ - Recent publishes (with DRF pagination)
41
42
  - Channel-level statistics
42
43
  Requires admin authentication (JWT, Session, or Basic Auth).
43
44
  """
44
45
 
46
+ serializer_class = PublishSerializer
47
+
45
48
  @extend_schema(
46
49
  tags=["Centrifugo Monitoring"],
47
50
  summary="Get Centrifugo health status",
@@ -126,13 +129,20 @@ class CentrifugoMonitorViewSet(AdminAPIMixin, viewsets.ViewSet):
126
129
  @extend_schema(
127
130
  tags=["Centrifugo Monitoring"],
128
131
  summary="Get recent publishes",
129
- description="Returns a list of recent Centrifugo publishes with their details.",
132
+ description="Returns a paginated list of recent Centrifugo publishes with their details. Uses standard DRF pagination.",
130
133
  parameters=[
131
134
  OpenApiParameter(
132
- name="count",
135
+ name="page",
133
136
  type=OpenApiTypes.INT,
134
137
  location=OpenApiParameter.QUERY,
135
- description="Number of publishes to return (default: 50, max: 200)",
138
+ description="Page number",
139
+ required=False,
140
+ ),
141
+ OpenApiParameter(
142
+ name="page_size",
143
+ type=OpenApiTypes.INT,
144
+ location=OpenApiParameter.QUERY,
145
+ description="Items per page (default: 10, max: 100)",
136
146
  required=False,
137
147
  ),
138
148
  OpenApiParameter(
@@ -149,16 +159,9 @@ class CentrifugoMonitorViewSet(AdminAPIMixin, viewsets.ViewSet):
149
159
  description="Filter by status (success, failed, timeout, pending, partial)",
150
160
  required=False,
151
161
  ),
152
- OpenApiParameter(
153
- name="offset",
154
- type=OpenApiTypes.INT,
155
- location=OpenApiParameter.QUERY,
156
- description="Offset for pagination (default: 0)",
157
- required=False,
158
- ),
159
162
  ],
160
163
  responses={
161
- 200: RecentPublishesSerializer,
164
+ 200: PublishSerializer(many=True),
162
165
  400: {"description": "Invalid parameters"},
163
166
  },
164
167
  )
@@ -166,28 +169,23 @@ class CentrifugoMonitorViewSet(AdminAPIMixin, viewsets.ViewSet):
166
169
  def publishes(self, request):
167
170
  """Get recent Centrifugo publishes."""
168
171
  try:
169
- count = int(request.GET.get("count", 50))
170
- count = min(count, 200) # Max 200
171
-
172
172
  channel = request.GET.get("channel")
173
- status_filter = request.GET.get("status") # NEW: status filter
174
- offset = int(request.GET.get("offset", 0)) # NEW: offset for pagination
173
+ status_filter = request.GET.get("status")
175
174
 
176
175
  queryset = CentrifugoLog.objects.all()
177
176
 
178
177
  if channel:
179
178
  queryset = queryset.filter(channel=channel)
180
179
 
181
- # NEW: Filter by status
180
+ # Filter by status
182
181
  if status_filter and status_filter in ["success", "failed", "timeout", "pending", "partial"]:
183
182
  queryset = queryset.filter(status=status_filter)
184
183
 
185
- # Get total count before slicing
186
- total = queryset.count()
184
+ queryset = queryset.order_by("-created_at")
187
185
 
188
- # NEW: Apply offset and limit
186
+ # Convert queryset to list of dicts for serialization
189
187
  publishes_list = list(
190
- queryset.order_by("-created_at")[offset:offset + count].values(
188
+ queryset.values(
191
189
  "message_id",
192
190
  "channel",
193
191
  "status",
@@ -202,23 +200,10 @@ class CentrifugoMonitorViewSet(AdminAPIMixin, viewsets.ViewSet):
202
200
  )
203
201
  )
204
202
 
205
- # Convert datetime to ISO format
206
- for pub in publishes_list:
207
- if pub["created_at"]:
208
- pub["created_at"] = pub["created_at"].isoformat()
209
- if pub["completed_at"]:
210
- pub["completed_at"] = pub["completed_at"].isoformat()
211
-
212
- response_data = {
213
- "publishes": publishes_list,
214
- "count": len(publishes_list),
215
- "total_available": total,
216
- "offset": offset, # NEW: for pagination
217
- "has_more": (offset + count) < total, # NEW: pagination helper
218
- }
219
-
220
- serializer = RecentPublishesSerializer(**response_data)
221
- return Response(serializer.model_dump())
203
+ # Use DRF pagination
204
+ page = self.paginate_queryset(publishes_list)
205
+ serializer = PublishSerializer(page, many=True)
206
+ return self.get_paginated_response(serializer.data)
222
207
 
223
208
  except ValueError as e:
224
209
  logger.warning(f"Recent publishes validation error: {e}")
@@ -2,10 +2,16 @@
2
2
  Admin interface for gRPC app.
3
3
  """
4
4
 
5
- from .config import grpcrequestlog_config
5
+ from .config import grpcapikey_config, grpcrequestlog_config, grpcserverstatus_config
6
+ from .grpc_api_key import GrpcApiKeyAdmin
6
7
  from .grpc_request_log import GRPCRequestLogAdmin
8
+ from .grpc_server_status import GRPCServerStatusAdmin
7
9
 
8
10
  __all__ = [
11
+ "GrpcApiKeyAdmin",
9
12
  "GRPCRequestLogAdmin",
13
+ "GRPCServerStatusAdmin",
14
+ "grpcapikey_config",
10
15
  "grpcrequestlog_config",
16
+ "grpcserverstatus_config",
11
17
  ]
@@ -7,31 +7,33 @@ Declarative AdminConfig using PydanticAdmin patterns.
7
7
  from django_cfg.modules.django_admin import (
8
8
  AdminConfig,
9
9
  BadgeField,
10
+ BooleanField,
10
11
  DateTimeField,
12
+ FieldsetConfig,
11
13
  Icons,
14
+ TextField,
12
15
  UserField,
13
16
  )
14
17
 
15
- from ..models import GRPCRequestLog, GRPCServerStatus
18
+ from ..models import GRPCRequestLog, GRPCServerStatus, GrpcApiKey
16
19
 
17
20
 
18
21
  # Declarative configuration for GRPCRequestLog
19
22
  grpcrequestlog_config = AdminConfig(
20
23
  model=GRPCRequestLog,
21
24
  # Performance optimization
22
- select_related=["user"],
25
+ select_related=["user", "api_key"],
23
26
 
24
27
  # List display
25
28
  list_display=[
26
- "full_method",
27
29
  "service_badge",
28
30
  "method_badge",
29
31
  "status",
30
32
  "grpc_status_code_display",
31
33
  "user",
34
+ "api_key_display",
32
35
  "duration_display",
33
36
  "created_at",
34
- "completed_at"
35
37
  ],
36
38
 
37
39
  # Auto-generated display methods
@@ -54,7 +56,7 @@ grpcrequestlog_config = AdminConfig(
54
56
  DateTimeField(name="completed_at", title="Completed", ordering="completed_at"),
55
57
  ],
56
58
  # Filters
57
- list_filter=["status", "grpc_status_code", "service_name", "method_name", "is_authenticated", "created_at"],
59
+ list_filter=["status", "grpc_status_code", "service_name", "method_name", "is_authenticated", "api_key", "created_at"],
58
60
  search_fields=[
59
61
  "request_id",
60
62
  "service_name",
@@ -62,11 +64,13 @@ grpcrequestlog_config = AdminConfig(
62
64
  "full_method",
63
65
  "user__username",
64
66
  "user__email",
67
+ "api_key__name",
68
+ "api_key__key",
65
69
  "error_message",
66
70
  "client_ip",
67
71
  ],
68
- # Autocomplete for user field
69
- autocomplete_fields=["user"],
72
+ # Autocomplete for user and api_key fields
73
+ autocomplete_fields=["user", "api_key"],
70
74
  # Readonly fields
71
75
  readonly_fields=[
72
76
  "id",
@@ -94,7 +98,7 @@ grpcserverstatus_config = AdminConfig(
94
98
  list_display=[
95
99
  "instance_id",
96
100
  "address",
97
- "status_badge",
101
+ "status",
98
102
  "pid",
99
103
  "hostname",
100
104
  "uptime_display",
@@ -141,6 +145,11 @@ grpcserverstatus_config = AdminConfig(
141
145
  "updated_at",
142
146
  "uptime_display",
143
147
  "is_running",
148
+ "server_config_display",
149
+ "process_info_display",
150
+ "registered_services_display",
151
+ "error_display",
152
+ "lifecycle_display",
144
153
  ],
145
154
 
146
155
  # Date hierarchy
@@ -154,4 +163,99 @@ grpcserverstatus_config = AdminConfig(
154
163
  )
155
164
 
156
165
 
157
- __all__ = ["grpcrequestlog_config", "grpcserverstatus_config"]
166
+ # Declarative configuration for GrpcApiKey
167
+ grpcapikey_config = AdminConfig(
168
+ model=GrpcApiKey,
169
+
170
+ # Performance optimization
171
+ select_related=["user", "created_by"],
172
+
173
+ # List display
174
+ list_display=[
175
+ "status_indicator",
176
+ "name",
177
+ "key_type",
178
+ "user",
179
+ "masked_key_display",
180
+ "request_count_display",
181
+ "last_used_at",
182
+ "expires_display",
183
+ "created_at",
184
+ ],
185
+
186
+ # Auto-generated display methods
187
+ display_fields=[
188
+ TextField(name="name", title="Name", ordering="name"),
189
+ BadgeField(
190
+ name="key_type",
191
+ title="Type",
192
+ label_map={
193
+ "service": "info",
194
+ "cli": "primary",
195
+ "webhook": "warning",
196
+ "internal": "secondary",
197
+ "development": "danger",
198
+ },
199
+ ),
200
+ UserField(name="user", title="User", header=True, ordering="user__username"),
201
+ DateTimeField(name="last_used_at", title="Last Used", ordering="last_used_at"),
202
+ DateTimeField(name="created_at", title="Created", ordering="created_at"),
203
+ ],
204
+
205
+ # Filters
206
+ list_filter=["is_active", "key_type", "created_at", "expires_at", "user"],
207
+ search_fields=["name", "description", "user__username", "user__email", "key"],
208
+
209
+ # Readonly fields
210
+ readonly_fields=[
211
+ "key_display",
212
+ "masked_key",
213
+ "request_count",
214
+ "last_used_at",
215
+ "created_at",
216
+ "updated_at",
217
+ "created_by",
218
+ ],
219
+
220
+ # Fieldsets
221
+ fieldsets=[
222
+ FieldsetConfig(
223
+ title="Basic Information",
224
+ fields=["name", "description", "key_type", "is_active"],
225
+ ),
226
+ FieldsetConfig(
227
+ title="API Key",
228
+ fields=["key_display", "masked_key"],
229
+ ),
230
+ FieldsetConfig(
231
+ title="User Association",
232
+ fields=["user", "created_by"],
233
+ ),
234
+ FieldsetConfig(
235
+ title="Expiration",
236
+ fields=["expires_at"],
237
+ ),
238
+ FieldsetConfig(
239
+ title="Usage Statistics",
240
+ fields=["request_count", "last_used_at"],
241
+ collapsed=True,
242
+ ),
243
+ FieldsetConfig(
244
+ title="Timestamps",
245
+ fields=["created_at", "updated_at"],
246
+ collapsed=True,
247
+ ),
248
+ ],
249
+
250
+ # Autocomplete for user field
251
+ autocomplete_fields=["user"],
252
+
253
+ # Ordering
254
+ ordering=["-created_at"],
255
+
256
+ # Per page
257
+ list_per_page=50,
258
+ )
259
+
260
+
261
+ __all__ = ["grpcrequestlog_config", "grpcserverstatus_config", "grpcapikey_config"]