django-cfg 1.4.83__py3-none-any.whl → 1.4.84__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 (133) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/dashboard/__init__.py +8 -0
  3. django_cfg/apps/dashboard/api/__init__.py +27 -0
  4. django_cfg/apps/dashboard/api/serializers.py +165 -0
  5. django_cfg/apps/dashboard/api/viewsets.py +257 -0
  6. django_cfg/apps/dashboard/apps.py +23 -0
  7. django_cfg/apps/dashboard/services/__init__.py +11 -0
  8. django_cfg/apps/dashboard/services/statistics_service.py +235 -0
  9. django_cfg/apps/dashboard/services/system_health_service.py +280 -0
  10. django_cfg/apps/dashboard/urls.py +23 -0
  11. django_cfg/apps/frontend/views.py +5 -0
  12. django_cfg/apps/urls.py +2 -1
  13. django_cfg/core/builders/apps_builder.py +1 -0
  14. django_cfg/modules/django_client/core/parser/openapi30.py +12 -5
  15. django_cfg/modules/django_client/core/parser/openapi31.py +12 -5
  16. django_cfg/pyproject.toml +1 -1
  17. django_cfg/static/frontend/admin/404.html +1 -1
  18. django_cfg/static/frontend/admin/500.html +1 -1
  19. django_cfg/static/frontend/admin/_next/static/-Zk0eDB7OJOEFrFyR5BwZ/_buildManifest.js +1 -0
  20. django_cfg/static/frontend/admin/_next/static/chunks/{43076.55dd23b6cd68edb0.js → 20695.a7d37b6c40ad3f58.js} +1 -1
  21. django_cfg/static/frontend/admin/_next/static/chunks/{25033.d626f78bc99bc4a1.js → 25033.ee3e206d5a2877b6.js} +2 -2
  22. django_cfg/static/frontend/admin/_next/static/chunks/{25892.964150a58f94ce06.js → 25892.5cbed319f9226fdc.js} +1 -1
  23. django_cfg/static/frontend/admin/_next/static/chunks/{2d7a934f.dfef67639279d59d.js → 2d7a934f.329c61f23af1a7ec.js} +1 -1
  24. django_cfg/static/frontend/admin/_next/static/chunks/{30649.00c679812a56aee3.js → 30649.963cfb7268b5864a.js} +1 -1
  25. django_cfg/static/frontend/admin/_next/static/chunks/{30875.784491146c38dbcb.js → 30875.82c3741757b8aa32.js} +1 -1
  26. django_cfg/static/frontend/admin/_next/static/chunks/{32163.ab0ca435b3f26c04.js → 32163.109a03a7252f1508.js} +1 -1
  27. django_cfg/static/frontend/admin/_next/static/chunks/43076-4be6a9794e9c3e8b.js +1 -0
  28. django_cfg/static/frontend/admin/_next/static/chunks/{49978.fb8ba7ee52ffe666.js → 49978.db5a86a8eb233f35.js} +1 -1
  29. django_cfg/static/frontend/admin/_next/static/chunks/50314-79c02212788f1ec7.js +1 -0
  30. django_cfg/static/frontend/admin/_next/static/chunks/{50319.f786248384877960.js → 50319.fd78c7f7e3f1966e.js} +1 -1
  31. django_cfg/static/frontend/admin/_next/static/chunks/{52908.b690e323d8f8efdd.js → 52908.da5b850b0bc0970c.js} +1 -1
  32. django_cfg/static/frontend/admin/_next/static/chunks/{53710.80ca863525d137db.js → 53710.7176bbee6c7b78be.js} +1 -1
  33. django_cfg/static/frontend/admin/_next/static/chunks/{57982.251fed8d58adcf53.js → 57982.2c90b33b0934522a.js} +2 -2
  34. django_cfg/static/frontend/admin/_next/static/chunks/{60181.86e18057c4caaa97.js → 60181.c94d78d10eb5da37.js} +1 -1
  35. django_cfg/static/frontend/admin/_next/static/chunks/{60374.bde0ec1249aa79c6.js → 60374.5d80cfc45439b2b0.js} +1 -1
  36. django_cfg/static/frontend/admin/_next/static/chunks/{6884.7b1db804c88280ed.js → 6884.624d563508cf6db4.js} +1 -1
  37. django_cfg/static/frontend/admin/_next/static/chunks/{69436.9515b854cdf4b57a.js → 69436.be44021e3d7c99c7.js} +1 -1
  38. django_cfg/static/frontend/admin/_next/static/chunks/{70628.00cdd98f672e684f.js → 70628.58e8c38a66543d5e.js} +1 -1
  39. django_cfg/static/frontend/admin/_next/static/chunks/{73218.a826c2248612b37f.js → 73218.d712e7bd678e23a8.js} +1 -1
  40. django_cfg/static/frontend/admin/_next/static/chunks/{76334.64fbaa923d9ac293.js → 76334.f43f2d8b4bbf8dd6.js} +1 -1
  41. django_cfg/static/frontend/admin/_next/static/chunks/{7799.2b280f8ddf067d49.js → 7799.1575cc212bc750c7.js} +1 -1
  42. django_cfg/static/frontend/admin/_next/static/chunks/{80574.620a8a5b4eb91c25.js → 80574.92638dd7b9979664.js} +1 -1
  43. django_cfg/static/frontend/admin/_next/static/chunks/{81127.a0603c3394892d4e.js → 81127.3ead500eec887152.js} +1 -1
  44. django_cfg/static/frontend/admin/_next/static/chunks/82296-a2c8d38f62224be5.js +1 -0
  45. django_cfg/static/frontend/admin/_next/static/chunks/{8383.eb6188b22c453e14.js → 8383.e25a442df26b2e26.js} +1 -1
  46. django_cfg/static/frontend/admin/_next/static/chunks/{85833.35e6ca25ac32a7d2.js → 85833.b0dead4fbcbfdd1b.js} +1 -1
  47. django_cfg/static/frontend/admin/_next/static/chunks/{95365.fc9d7653a78839d0.js → 95365.2b430045fc2e5acf.js} +1 -1
  48. django_cfg/static/frontend/admin/_next/static/chunks/{96424.0793b94836eb13a6.js → 96424.11d76570e9a94b85.js} +1 -1
  49. django_cfg/static/frontend/admin/_next/static/chunks/pages/{_app-16701a4e1bc3e6ac.js → _app-f25bec36bbdc9625.js} +46 -46
  50. django_cfg/static/frontend/admin/_next/static/chunks/pages/index-d7bc30185f52cbca.js +1 -0
  51. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{cookies-bb5507a122775f30.js → cookies-b39c7f22c066e2c6.js} +1 -1
  52. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{privacy-f8a3d8db1a197be3.js → privacy-5aedad0cf3a4f80f.js} +1 -1
  53. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{security-aba50addd2179f8f.js → security-dbd854d0d5d483e2.js} +1 -1
  54. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{terms-4aa35cd30b5c08ad.js → terms-f3e1d2b9e5edf12f.js} +1 -1
  55. django_cfg/static/frontend/admin/_next/static/chunks/pages/private/centrifugo-22532c65971225eb.js +1 -0
  56. django_cfg/static/frontend/admin/_next/static/chunks/pages/private/ui-669e8f2a785beba2.js +1 -0
  57. django_cfg/static/frontend/admin/_next/static/chunks/pages/private-a8a9ba76f2c75354.js +1 -0
  58. django_cfg/static/frontend/admin/_next/static/chunks/{webpack-905bba30877f6490.js → webpack-92add5f95c66e349.js} +1 -1
  59. django_cfg/static/frontend/admin/_next/static/css/78d677ac1677c210.css +3 -0
  60. django_cfg/static/frontend/admin/auth.html +1 -1
  61. django_cfg/static/frontend/admin/index.html +1 -1
  62. django_cfg/static/frontend/admin/legal/cookies.html +1 -1
  63. django_cfg/static/frontend/admin/legal/privacy.html +1 -1
  64. django_cfg/static/frontend/admin/legal/security.html +1 -1
  65. django_cfg/static/frontend/admin/legal/terms.html +1 -1
  66. django_cfg/static/frontend/admin/private/centrifugo.html +1 -1
  67. django_cfg/static/frontend/admin/private/profile.html +1 -1
  68. django_cfg/static/frontend/admin/private/ui.html +1 -0
  69. django_cfg/static/frontend/admin/private.html +1 -1
  70. django_cfg/templates/admin/index.html +97 -63
  71. django_cfg/templates/admin_old/index.html +80 -0
  72. {django_cfg-1.4.83.dist-info → django_cfg-1.4.84.dist-info}/METADATA +1 -1
  73. {django_cfg-1.4.83.dist-info → django_cfg-1.4.84.dist-info}/RECORD +126 -113
  74. django_cfg/static/frontend/admin/_next/static/chunks/pages/index-88751d9f44a32105.js +0 -1
  75. django_cfg/static/frontend/admin/_next/static/chunks/pages/private/centrifugo-1c5f00c26c77a47b.js +0 -1
  76. django_cfg/static/frontend/admin/_next/static/chunks/pages/private-2f58633ddf63a5bc.js +0 -1
  77. django_cfg/static/frontend/admin/_next/static/chunks/pages/ui-0e6c0e35862789ec.js +0 -1
  78. django_cfg/static/frontend/admin/_next/static/css/806300fb98c42afb.css +0 -3
  79. django_cfg/static/frontend/admin/_next/static/ibMHm1p66p0UGKsKnDWxn/_buildManifest.js +0 -1
  80. django_cfg/static/frontend/admin/ui.html +0 -92
  81. /django_cfg/static/frontend/admin/_next/static/{ibMHm1p66p0UGKsKnDWxn → -Zk0eDB7OJOEFrFyR5BwZ}/_ssgManifest.js +0 -0
  82. /django_cfg/templates/{admin → admin_old}/components/action_grid.html +0 -0
  83. /django_cfg/templates/{admin → admin_old}/components/card.html +0 -0
  84. /django_cfg/templates/{admin → admin_old}/components/data_table.html +0 -0
  85. /django_cfg/templates/{admin → admin_old}/components/metric_card.html +0 -0
  86. /django_cfg/templates/{admin → admin_old}/components/modal.html +0 -0
  87. /django_cfg/templates/{admin → admin_old}/components/progress_bar.html +0 -0
  88. /django_cfg/templates/{admin → admin_old}/components/section_header.html +0 -0
  89. /django_cfg/templates/{admin → admin_old}/components/stat_item.html +0 -0
  90. /django_cfg/templates/{admin → admin_old}/components/stats_grid.html +0 -0
  91. /django_cfg/templates/{admin → admin_old}/components/status_badge.html +0 -0
  92. /django_cfg/templates/{admin → admin_old}/components/user_avatar.html +0 -0
  93. /django_cfg/templates/{admin → admin_old}/constance/change_list.html +0 -0
  94. /django_cfg/templates/{admin → admin_old}/constance/includes/default_value.html +0 -0
  95. /django_cfg/templates/{admin → admin_old}/constance/includes/fieldset_header.html +0 -0
  96. /django_cfg/templates/{admin → admin_old}/constance/includes/results_list.html +0 -0
  97. /django_cfg/templates/{admin → admin_old}/constance/includes/setting_row.html +0 -0
  98. /django_cfg/templates/{admin → admin_old}/constance/includes/table_headers.html +0 -0
  99. /django_cfg/templates/{admin → admin_old}/examples/component_class_example.html +0 -0
  100. /django_cfg/templates/{admin → admin_old}/import_export/change_list_export.html +0 -0
  101. /django_cfg/templates/{admin → admin_old}/import_export/change_list_import.html +0 -0
  102. /django_cfg/templates/{admin → admin_old}/import_export/change_list_import_export.html +0 -0
  103. /django_cfg/templates/{admin → admin_old}/index_new.html +0 -0
  104. /django_cfg/templates/{admin → admin_old}/layouts/base_dashboard.html +0 -0
  105. /django_cfg/templates/{admin → admin_old}/layouts/dashboard_with_tabs.html +0 -0
  106. /django_cfg/templates/{admin → admin_old}/sections/commands_section.html +0 -0
  107. /django_cfg/templates/{admin → admin_old}/sections/documentation_section.html +0 -0
  108. /django_cfg/templates/{admin → admin_old}/sections/overview_section.html +0 -0
  109. /django_cfg/templates/{admin → admin_old}/sections/stats_section.html +0 -0
  110. /django_cfg/templates/{admin → admin_old}/sections/system_section.html +0 -0
  111. /django_cfg/templates/{admin → admin_old}/sections/widgets_section.html +0 -0
  112. /django_cfg/templates/{admin → admin_old}/snippets/components/activity_tracker.html +0 -0
  113. /django_cfg/templates/{admin → admin_old}/snippets/components/charts_section.html +0 -0
  114. /django_cfg/templates/{admin → admin_old}/snippets/components/django_commands.html +0 -0
  115. /django_cfg/templates/{admin → admin_old}/snippets/components/quick_actions.html +0 -0
  116. /django_cfg/templates/{admin → admin_old}/snippets/components/recent_activity_improved.html +0 -0
  117. /django_cfg/templates/{admin → admin_old}/snippets/components/recent_users_table.html +0 -0
  118. /django_cfg/templates/{admin → admin_old}/snippets/components/stats_cards.html +0 -0
  119. /django_cfg/templates/{admin → admin_old}/snippets/components/stats_tiles.html +0 -0
  120. /django_cfg/templates/{admin → admin_old}/snippets/components/system_health.html +0 -0
  121. /django_cfg/templates/{admin → admin_old}/snippets/components/system_metrics.html +0 -0
  122. /django_cfg/templates/{admin → admin_old}/snippets/components/user_permissions.html +0 -0
  123. /django_cfg/templates/{admin → admin_old}/snippets/tabs/app_stats_tab.html +0 -0
  124. /django_cfg/templates/{admin → admin_old}/snippets/tabs/commands_tab.html +0 -0
  125. /django_cfg/templates/{admin → admin_old}/snippets/tabs/documentation_tab.html +0 -0
  126. /django_cfg/templates/{admin → admin_old}/snippets/tabs/overview_tab.html +0 -0
  127. /django_cfg/templates/{admin → admin_old}/snippets/tabs/stats_tab.html +0 -0
  128. /django_cfg/templates/{admin → admin_old}/snippets/tabs/users_tab.html +0 -0
  129. /django_cfg/templates/{admin → admin_old}/snippets/tabs/widgets_tab.html +0 -0
  130. /django_cfg/templates/{admin → admin_old}/snippets/zones/zones_table.html +0 -0
  131. {django_cfg-1.4.83.dist-info → django_cfg-1.4.84.dist-info}/WHEEL +0 -0
  132. {django_cfg-1.4.83.dist-info → django_cfg-1.4.84.dist-info}/entry_points.txt +0 -0
  133. {django_cfg-1.4.83.dist-info → django_cfg-1.4.84.dist-info}/licenses/LICENSE +0 -0
django_cfg/__init__.py CHANGED
@@ -32,7 +32,7 @@ Example:
32
32
  default_app_config = "django_cfg.apps.DjangoCfgConfig"
33
33
 
34
34
  # Version information
35
- __version__ = "1.4.83"
35
+ __version__ = "1.4.84"
36
36
  __license__ = "MIT"
37
37
 
38
38
  # Import registry for organized lazy loading
@@ -0,0 +1,8 @@
1
+ """
2
+ Dashboard Application
3
+
4
+ Provides RESTful API endpoints for dashboard statistics and metrics.
5
+ Designed to work with Next.js frontend without ORM dependencies.
6
+ """
7
+
8
+ default_app_config = 'django_cfg.apps.dashboard.apps.DashboardConfig'
@@ -0,0 +1,27 @@
1
+ """
2
+ Dashboard API
3
+
4
+ RESTful API endpoints for dashboard data.
5
+ """
6
+
7
+ from .serializers import (
8
+ ActivityEntrySerializer,
9
+ DashboardOverviewSerializer,
10
+ QuickActionSerializer,
11
+ StatCardSerializer,
12
+ SystemHealthItemSerializer,
13
+ SystemHealthSerializer,
14
+ SystemMetricsSerializer,
15
+ )
16
+ from .viewsets import DashboardViewSet
17
+
18
+ __all__ = [
19
+ 'DashboardViewSet',
20
+ 'StatCardSerializer',
21
+ 'SystemHealthItemSerializer',
22
+ 'SystemHealthSerializer',
23
+ 'QuickActionSerializer',
24
+ 'ActivityEntrySerializer',
25
+ 'SystemMetricsSerializer',
26
+ 'DashboardOverviewSerializer',
27
+ ]
@@ -0,0 +1,165 @@
1
+ """
2
+ Dashboard API Serializers
3
+
4
+ Simple serializers for dashboard endpoints - no nested serializers to avoid allOf.
5
+ Returns plain dict structures for TypeScript generation.
6
+ """
7
+
8
+ from rest_framework import serializers
9
+
10
+
11
+ class StatCardSerializer(serializers.Serializer):
12
+ """
13
+ Serializer for dashboard statistics cards.
14
+
15
+ Maps to StatCard Pydantic model.
16
+ """
17
+
18
+ title = serializers.CharField(help_text="Card title")
19
+ value = serializers.CharField(help_text="Main value to display")
20
+ icon = serializers.CharField(help_text="Material icon name")
21
+ change = serializers.CharField(required=False, allow_null=True, help_text="Change indicator (e.g., '+12%')")
22
+ change_type = serializers.ChoiceField(
23
+ choices=['positive', 'negative', 'neutral'],
24
+ default='neutral',
25
+ help_text="Change type"
26
+ )
27
+ description = serializers.CharField(required=False, allow_null=True, help_text="Additional description")
28
+ color = serializers.CharField(default='primary', help_text="Card color theme")
29
+
30
+
31
+ class SystemHealthItemSerializer(serializers.Serializer):
32
+ """
33
+ Serializer for system health status items.
34
+
35
+ Maps to SystemHealthItem Pydantic model.
36
+ """
37
+
38
+ component = serializers.CharField(help_text="Component name")
39
+ status = serializers.ChoiceField(
40
+ choices=['healthy', 'warning', 'error', 'unknown'],
41
+ help_text="Health status"
42
+ )
43
+ description = serializers.CharField(help_text="Status description")
44
+ last_check = serializers.CharField(help_text="Last check time (ISO format)")
45
+ health_percentage = serializers.IntegerField(
46
+ required=False,
47
+ allow_null=True,
48
+ min_value=0,
49
+ max_value=100,
50
+ help_text="Health percentage (0-100)"
51
+ )
52
+
53
+
54
+ class SystemHealthSerializer(serializers.Serializer):
55
+ """Serializer for overall system health status."""
56
+
57
+ overall_status = serializers.ChoiceField(
58
+ choices=['healthy', 'warning', 'error', 'unknown'],
59
+ help_text="Overall system health status"
60
+ )
61
+ overall_health_percentage = serializers.IntegerField(
62
+ min_value=0,
63
+ max_value=100,
64
+ help_text="Overall health percentage"
65
+ )
66
+ components = SystemHealthItemSerializer(many=True, help_text="Health status of individual components")
67
+ timestamp = serializers.CharField(help_text="Check timestamp (ISO format)")
68
+
69
+
70
+ class QuickActionSerializer(serializers.Serializer):
71
+ """
72
+ Serializer for quick action buttons.
73
+
74
+ Maps to QuickAction Pydantic model.
75
+ """
76
+
77
+ title = serializers.CharField(help_text="Action title")
78
+ description = serializers.CharField(help_text="Action description")
79
+ icon = serializers.CharField(help_text="Material icon name")
80
+ link = serializers.CharField(help_text="Action URL")
81
+ color = serializers.ChoiceField(
82
+ choices=['primary', 'success', 'warning', 'danger', 'secondary'],
83
+ default='primary',
84
+ help_text="Button color theme"
85
+ )
86
+ category = serializers.CharField(default='general', help_text="Action category")
87
+
88
+
89
+ class ActivityEntrySerializer(serializers.Serializer):
90
+ """Serializer for recent activity entries."""
91
+
92
+ id = serializers.IntegerField(help_text="Activity ID")
93
+ user = serializers.CharField(help_text="User who performed the action")
94
+ action = serializers.CharField(help_text="Action type (created, updated, deleted, etc.)")
95
+ resource = serializers.CharField(help_text="Resource affected")
96
+ timestamp = serializers.CharField(help_text="Activity timestamp (ISO format)")
97
+ icon = serializers.CharField(help_text="Material icon name")
98
+ color = serializers.CharField(help_text="Icon color")
99
+
100
+
101
+ class SystemMetricsSerializer(serializers.Serializer):
102
+ """Serializer for system performance metrics."""
103
+
104
+ cpu_usage = serializers.FloatField(help_text="CPU usage percentage")
105
+ memory_usage = serializers.FloatField(help_text="Memory usage percentage")
106
+ disk_usage = serializers.FloatField(help_text="Disk usage percentage")
107
+ network_in = serializers.CharField(help_text="Network incoming bandwidth")
108
+ network_out = serializers.CharField(help_text="Network outgoing bandwidth")
109
+ response_time = serializers.CharField(help_text="Average response time")
110
+ uptime = serializers.CharField(help_text="System uptime")
111
+
112
+
113
+ class UserStatisticsSerializer(serializers.Serializer):
114
+ """Serializer for user statistics."""
115
+
116
+ total_users = serializers.IntegerField(help_text="Total number of users")
117
+ active_users = serializers.IntegerField(help_text="Active users (last 30 days)")
118
+ new_users = serializers.IntegerField(help_text="New users (last 7 days)")
119
+ superusers = serializers.IntegerField(help_text="Number of superusers")
120
+
121
+
122
+ class AppStatisticsSerializer(serializers.Serializer):
123
+ """Serializer for application-specific statistics."""
124
+
125
+ app_name = serializers.CharField(help_text="Application name")
126
+ statistics = serializers.DictField(
127
+ child=serializers.IntegerField(),
128
+ help_text="Application statistics"
129
+ )
130
+
131
+
132
+ class DashboardOverviewSerializer(serializers.Serializer):
133
+ """
134
+ Main serializer for dashboard overview endpoint.
135
+ Uses DictField to avoid allOf generation in OpenAPI.
136
+ """
137
+
138
+ stat_cards = serializers.ListField(
139
+ child=serializers.DictField(),
140
+ help_text="Dashboard statistics cards"
141
+ )
142
+ system_health = serializers.ListField(
143
+ child=serializers.DictField(),
144
+ help_text="System health status"
145
+ )
146
+ quick_actions = serializers.ListField(
147
+ child=serializers.DictField(),
148
+ help_text="Quick action buttons"
149
+ )
150
+ recent_activity = serializers.ListField(
151
+ child=serializers.DictField(),
152
+ help_text="Recent activity entries"
153
+ )
154
+ system_metrics = serializers.DictField(help_text="System performance metrics")
155
+ user_statistics = serializers.DictField(help_text="User statistics")
156
+ timestamp = serializers.CharField(help_text="Data timestamp (ISO format)")
157
+
158
+
159
+ class APIResponseSerializer(serializers.Serializer):
160
+ """Standard API response wrapper."""
161
+
162
+ success = serializers.BooleanField(help_text="Operation success status")
163
+ message = serializers.CharField(required=False, help_text="Success message")
164
+ error = serializers.CharField(required=False, help_text="Error message")
165
+ data = serializers.DictField(required=False, help_text="Response data")
@@ -0,0 +1,257 @@
1
+ """
2
+ Dashboard API ViewSets
3
+
4
+ Provides RESTful endpoints for dashboard data.
5
+ No ORM dependencies - uses services for data collection.
6
+ """
7
+
8
+ import logging
9
+ from datetime import datetime
10
+ from typing import Any, Dict
11
+
12
+ from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema, inline_serializer
13
+ from drf_spectacular.types import OpenApiTypes
14
+ from rest_framework import serializers, status, viewsets
15
+ from rest_framework.authentication import BasicAuthentication, SessionAuthentication
16
+ from rest_framework.decorators import action
17
+ from rest_framework.permissions import IsAdminUser
18
+ from rest_framework.response import Response
19
+
20
+ from ..services import StatisticsService, SystemHealthService
21
+ from .serializers import (
22
+ ActivityEntrySerializer,
23
+ APIResponseSerializer,
24
+ AppStatisticsSerializer,
25
+ DashboardOverviewSerializer,
26
+ QuickActionSerializer,
27
+ StatCardSerializer,
28
+ SystemHealthItemSerializer,
29
+ SystemHealthSerializer,
30
+ SystemMetricsSerializer,
31
+ UserStatisticsSerializer,
32
+ )
33
+
34
+ logger = logging.getLogger(__name__)
35
+
36
+
37
+ class DashboardViewSet(viewsets.GenericViewSet):
38
+ """
39
+ Dashboard Data ViewSet
40
+
41
+ Provides comprehensive dashboard endpoints for Next.js frontend.
42
+ All data is collected via services without ORM dependencies.
43
+
44
+ %%PRIORITY:HIGH%%
45
+ %%AI_HINT: Main entry point for dashboard API%%
46
+
47
+ TAGS: dashboard, api, viewset
48
+ USED_BY: Next.js admin panel
49
+ """
50
+
51
+ authentication_classes = [SessionAuthentication, BasicAuthentication]
52
+ permission_classes = [IsAdminUser]
53
+ serializer_class = DashboardOverviewSerializer
54
+
55
+ @action(detail=False, methods=['get'], url_path='overview')
56
+ @extend_schema(
57
+ summary="Get dashboard overview",
58
+ description="Retrieve complete dashboard data including stats, health, actions, and metrics",
59
+ responses={200: DashboardOverviewSerializer},
60
+ tags=["Dashboard"]
61
+ )
62
+ def overview(self, request):
63
+ """
64
+ Get complete dashboard overview.
65
+
66
+ Returns all dashboard data in a single request:
67
+ - Statistics cards
68
+ - System health status
69
+ - Quick actions
70
+ - Recent activity
71
+ - System metrics
72
+ - User statistics
73
+ """
74
+ try:
75
+ stats_service = StatisticsService()
76
+ health_service = SystemHealthService()
77
+
78
+ data = {
79
+ 'stat_cards': stats_service.get_stat_cards(),
80
+ 'system_health': health_service.get_all_health_checks(),
81
+ 'quick_actions': health_service.get_quick_actions(),
82
+ 'recent_activity': stats_service.get_recent_activity(limit=10),
83
+ 'system_metrics': stats_service.get_system_metrics(),
84
+ 'user_statistics': stats_service.get_user_statistics(),
85
+ 'timestamp': datetime.now().isoformat(),
86
+ }
87
+
88
+ return Response(data)
89
+
90
+ except Exception as e:
91
+ logger.error(f"Dashboard overview API error: {e}", exc_info=True)
92
+ return Response({
93
+ 'error': str(e)
94
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
95
+
96
+ @extend_schema(
97
+ summary="Get statistics cards",
98
+ description="Retrieve dashboard statistics cards with key metrics",
99
+ responses=StatCardSerializer(many=True),
100
+ tags=["dashboard"]
101
+ )
102
+ @action(detail=False, methods=['get'], url_path='stats/cards', pagination_class=None, serializer_class=StatCardSerializer)
103
+ def stat_cards(self, request):
104
+ """Get dashboard statistics cards."""
105
+ try:
106
+ stats_service = StatisticsService()
107
+ cards = stats_service.get_stat_cards()
108
+
109
+ return Response(cards)
110
+
111
+ except Exception as e:
112
+ logger.error(f"Stat cards API error: {e}")
113
+ return Response({
114
+ 'error': str(e)
115
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
116
+
117
+ @extend_schema(
118
+ summary="Get system health status",
119
+ description="Retrieve overall system health including all component checks",
120
+ responses={200: SystemHealthSerializer},
121
+ tags=["dashboard"]
122
+ )
123
+ @action(detail=False, methods=['get'], url_path='health', serializer_class=SystemHealthSerializer)
124
+ def system_health(self, request):
125
+ """Get overall system health status."""
126
+ try:
127
+ health_service = SystemHealthService()
128
+ health_data = health_service.get_overall_health_status()
129
+
130
+ return Response(health_data)
131
+
132
+ except Exception as e:
133
+ logger.error(f"System health API error: {e}")
134
+ return Response({
135
+ 'error': str(e)
136
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
137
+
138
+ @extend_schema(
139
+ summary="Get quick actions",
140
+ description="Retrieve quick action buttons for dashboard",
141
+ responses=QuickActionSerializer(many=True),
142
+ tags=["Dashboard"]
143
+ )
144
+ @action(detail=False, methods=['get'], url_path='actions', pagination_class=None, serializer_class=QuickActionSerializer)
145
+ def quick_actions(self, request):
146
+ """Get quick action buttons."""
147
+ try:
148
+ health_service = SystemHealthService()
149
+ actions = health_service.get_quick_actions()
150
+
151
+ return Response(actions)
152
+
153
+ except Exception as e:
154
+ logger.error(f"Quick actions API error: {e}")
155
+ return Response({
156
+ 'error': str(e)
157
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
158
+
159
+ @extend_schema(
160
+ summary="Get recent activity",
161
+ description="Retrieve recent system activity entries",
162
+ parameters=[
163
+ OpenApiParameter(
164
+ name='limit',
165
+ description='Maximum number of entries to return',
166
+ required=False,
167
+ type=int,
168
+ default=10
169
+ ),
170
+ ],
171
+ responses=ActivityEntrySerializer(many=True),
172
+ tags=["dashboard"]
173
+ )
174
+ @action(detail=False, methods=['get'], url_path='activity', pagination_class=None, serializer_class=ActivityEntrySerializer)
175
+ def recent_activity(self, request):
176
+ """Get recent activity entries."""
177
+ try:
178
+ limit = int(request.query_params.get('limit', 10))
179
+ stats_service = StatisticsService()
180
+ activity = stats_service.get_recent_activity(limit=limit)
181
+
182
+ return Response(activity)
183
+
184
+ except Exception as e:
185
+ logger.error(f"Recent activity API error: {e}")
186
+ return Response({
187
+ 'error': str(e)
188
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
189
+
190
+ @extend_schema(
191
+ summary="Get system metrics",
192
+ description="Retrieve system performance metrics (CPU, memory, disk, etc.)",
193
+ responses={200: SystemMetricsSerializer},
194
+ tags=["dashboard"]
195
+ )
196
+ @action(detail=False, methods=['get'], url_path='metrics', serializer_class=SystemMetricsSerializer)
197
+ def system_metrics(self, request):
198
+ """Get system performance metrics."""
199
+ try:
200
+ stats_service = StatisticsService()
201
+ metrics = stats_service.get_system_metrics()
202
+
203
+ return Response(metrics)
204
+
205
+ except Exception as e:
206
+ logger.error(f"System metrics API error: {e}")
207
+ return Response({
208
+ 'error': str(e)
209
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
210
+
211
+ @extend_schema(
212
+ summary="Get user statistics",
213
+ description="Retrieve user-related statistics",
214
+ responses={200: UserStatisticsSerializer},
215
+ tags=["dashboard"]
216
+ )
217
+ @action(detail=False, methods=['get'], url_path='stats/users', serializer_class=UserStatisticsSerializer)
218
+ def user_statistics(self, request):
219
+ """Get user statistics."""
220
+ try:
221
+ stats_service = StatisticsService()
222
+ user_stats = stats_service.get_user_statistics()
223
+
224
+ return Response(user_stats)
225
+
226
+ except Exception as e:
227
+ logger.error(f"User statistics API error: {e}")
228
+ return Response({
229
+ 'error': str(e)
230
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
231
+
232
+ @extend_schema(
233
+ summary="Get application statistics",
234
+ description="Retrieve statistics for all enabled django-cfg applications",
235
+ responses=AppStatisticsSerializer(many=True),
236
+ tags=["dashboard"]
237
+ )
238
+ @action(detail=False, methods=['get'], url_path='stats/apps', pagination_class=None, serializer_class=AppStatisticsSerializer)
239
+ def app_statistics(self, request):
240
+ """Get application-specific statistics."""
241
+ try:
242
+ stats_service = StatisticsService()
243
+ app_stats = stats_service.get_app_statistics()
244
+
245
+ # Convert dict to list of {app_name, statistics} objects
246
+ data = [
247
+ {'app_name': app_name, 'statistics': stats}
248
+ for app_name, stats in app_stats.items()
249
+ ]
250
+
251
+ return Response(data)
252
+
253
+ except Exception as e:
254
+ logger.error(f"App statistics API error: {e}")
255
+ return Response({
256
+ 'error': str(e)
257
+ }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@@ -0,0 +1,23 @@
1
+ """
2
+ Dashboard App Configuration
3
+ """
4
+
5
+ from django.apps import AppConfig
6
+
7
+
8
+ class DashboardConfig(AppConfig):
9
+ """Configuration for Dashboard application."""
10
+
11
+ default_auto_field = 'django.db.models.BigAutoField'
12
+ name = 'django_cfg.apps.dashboard'
13
+ label = 'dashboard'
14
+ verbose_name = 'Dashboard'
15
+
16
+ def ready(self):
17
+ """
18
+ Application initialization.
19
+
20
+ Called when Django starts. Import signals or perform
21
+ other initialization tasks here.
22
+ """
23
+ pass
@@ -0,0 +1,11 @@
1
+ """
2
+ Dashboard Services
3
+
4
+ Business logic for collecting and aggregating dashboard data.
5
+ Services are separated from views/API layer for better testability and reusability.
6
+ """
7
+
8
+ from .statistics_service import StatisticsService
9
+ from .system_health_service import SystemHealthService
10
+
11
+ __all__ = ['StatisticsService', 'SystemHealthService']