django-cfg 1.4.87__py3-none-any.whl → 1.4.89__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 (177) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/centrifugo/views/__init__.py +0 -2
  3. django_cfg/apps/dashboard/permissions.py +48 -0
  4. django_cfg/apps/dashboard/serializers/__init__.py +8 -1
  5. django_cfg/apps/dashboard/serializers/commands.py +29 -0
  6. django_cfg/apps/dashboard/services/__init__.py +2 -0
  7. django_cfg/{modules/django_unfold/callbacks/base.py → apps/dashboard/services/commands_security.py} +28 -90
  8. django_cfg/apps/dashboard/services/commands_service.py +208 -9
  9. django_cfg/apps/dashboard/services/overview_service.py +205 -0
  10. django_cfg/apps/dashboard/views/commands_views.py +92 -4
  11. django_cfg/apps/frontend/test_routing.py +134 -0
  12. django_cfg/apps/frontend/views.py +73 -28
  13. django_cfg/apps/urls.py +0 -1
  14. django_cfg/core/builders/apps_builder.py +0 -58
  15. django_cfg/modules/django_unfold/__init__.py +5 -24
  16. django_cfg/modules/django_unfold/models/__init__.py +0 -23
  17. django_cfg/modules/django_unfold/models/config.py +11 -65
  18. django_cfg/modules/django_unfold/{dashboard.py → navigation.py} +21 -152
  19. django_cfg/modules/django_unfold/tailwind.py +2 -4
  20. django_cfg/pyproject.toml +1 -1
  21. django_cfg/registry/third_party.py +0 -9
  22. django_cfg/routing/callbacks.py +1 -43
  23. django_cfg/static/frontend/admin/404/index.html +1 -1
  24. django_cfg/static/frontend/admin/404.html +1 -1
  25. django_cfg/static/frontend/admin/500/index.html +1 -1
  26. django_cfg/static/frontend/admin/_next/static/{ZJZBgOL9mO1koHrgaaLEV → 0sN9ktsgXH48ygtGSrhfu}/_buildManifest.js +1 -1
  27. django_cfg/static/frontend/admin/_next/static/chunks/{19430.fe7bff7372f8a256.js → 19430.c4c95603c23c17fe.js} +1 -1
  28. django_cfg/static/frontend/admin/_next/static/chunks/50314-9443faa6df24aebf.js +1 -0
  29. django_cfg/static/frontend/admin/_next/static/chunks/94141-bc6d47f419b26b21.js +1 -0
  30. django_cfg/static/frontend/admin/_next/static/chunks/pages/{_app-c336f254967dd101.js → _app-c7dcd3aa616fab68.js} +6 -6
  31. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{cookies-b39c7f22c066e2c6.js → cookies-97d279800f12aab4.js} +1 -1
  32. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{privacy-5aedad0cf3a4f80f.js → privacy-1d5e6cd94689247e.js} +1 -1
  33. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{security-dbd854d0d5d483e2.js → security-55e49700e7a01f5a.js} +1 -1
  34. django_cfg/static/frontend/admin/_next/static/chunks/pages/legal/{terms-f3e1d2b9e5edf12f.js → terms-14c02bb2d3198352.js} +1 -1
  35. django_cfg/static/frontend/admin/_next/static/chunks/pages/private/{centrifugo-22532c65971225eb.js → centrifugo-f9ecbc3ae0052a03.js} +1 -1
  36. django_cfg/static/frontend/admin/_next/static/chunks/pages/private-d4ccbe1265cbd853.js +1 -0
  37. django_cfg/static/frontend/admin/_next/static/chunks/{webpack-da114020a6b940f5.js → webpack-5a92f81363b62aa7.js} +1 -1
  38. django_cfg/static/frontend/admin/_next/static/css/3063068f0d5a8a00.css +3 -0
  39. django_cfg/static/frontend/admin/_next/static/media/19cfc7226ec3afaa-s.woff2 +0 -0
  40. django_cfg/static/frontend/admin/_next/static/media/21350d82a1f187e9-s.p.woff2 +0 -0
  41. django_cfg/static/frontend/admin/_next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
  42. django_cfg/static/frontend/admin/_next/static/media/ba9851c3c22cd980-s.woff2 +0 -0
  43. django_cfg/static/frontend/admin/_next/static/media/c5fe6dc8356a8c31-s.woff2 +0 -0
  44. django_cfg/static/frontend/admin/_next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
  45. django_cfg/static/frontend/admin/_next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
  46. django_cfg/static/frontend/admin/auth/index.html +1 -1
  47. django_cfg/static/frontend/admin/index.html +1 -1
  48. django_cfg/static/frontend/admin/legal/cookies/index.html +1 -1
  49. django_cfg/static/frontend/admin/legal/privacy/index.html +1 -1
  50. django_cfg/static/frontend/admin/legal/security/index.html +1 -1
  51. django_cfg/static/frontend/admin/legal/terms/index.html +1 -1
  52. django_cfg/static/frontend/admin/private/centrifugo/index.html +1 -1
  53. django_cfg/static/frontend/admin/private/index.html +1 -1
  54. django_cfg/static/frontend/admin/private/profile/index.html +1 -1
  55. django_cfg/static/frontend/admin/private/ui/index.html +2 -2
  56. django_cfg/templates/admin/index.html +1 -1
  57. {django_cfg-1.4.87.dist-info → django_cfg-1.4.89.dist-info}/METADATA +1 -1
  58. {django_cfg-1.4.87.dist-info → django_cfg-1.4.89.dist-info}/RECORD +62 -163
  59. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/css/dashboard.css +0 -260
  60. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_channels.mjs +0 -313
  61. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_testing.mjs +0 -803
  62. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/main.mjs +0 -341
  63. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/overview.mjs +0 -432
  64. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/testing.mjs +0 -33
  65. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/websocket.mjs +0 -210
  66. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/channels_content.html +0 -46
  67. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/live_channels_content.html +0 -123
  68. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/overview_content.html +0 -45
  69. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/publishes_content.html +0 -84
  70. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/stat_cards.html +0 -53
  71. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/system_status.html +0 -91
  72. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/tab_navigation.html +0 -29
  73. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +0 -415
  74. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/layout/base.html +0 -61
  75. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/pages/dashboard.html +0 -58
  76. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/tags/connection_script.html +0 -48
  77. django_cfg/apps/centrifugo/templatetags/__init__.py +0 -1
  78. django_cfg/apps/centrifugo/templatetags/centrifugo_tags.py +0 -81
  79. django_cfg/apps/centrifugo/urls_admin.py +0 -20
  80. django_cfg/apps/centrifugo/views/dashboard.py +0 -28
  81. django_cfg/modules/django_dashboard/__init__.py +0 -23
  82. django_cfg/modules/django_dashboard/components.py +0 -312
  83. django_cfg/modules/django_dashboard/debug.py +0 -174
  84. django_cfg/modules/django_dashboard/management/__init__.py +0 -0
  85. django_cfg/modules/django_dashboard/management/commands/__init__.py +0 -0
  86. django_cfg/modules/django_dashboard/management/commands/debug_dashboard.py +0 -109
  87. django_cfg/modules/django_dashboard/sections/__init__.py +0 -1
  88. django_cfg/modules/django_dashboard/sections/base.py +0 -129
  89. django_cfg/modules/django_dashboard/sections/commands.py +0 -33
  90. django_cfg/modules/django_dashboard/sections/documentation.py +0 -393
  91. django_cfg/modules/django_dashboard/sections/overview.py +0 -398
  92. django_cfg/modules/django_dashboard/sections/stats.py +0 -48
  93. django_cfg/modules/django_dashboard/sections/system.py +0 -74
  94. django_cfg/modules/django_dashboard/sections/widgets.py +0 -222
  95. django_cfg/modules/django_unfold/callbacks/__init__.py +0 -9
  96. django_cfg/modules/django_unfold/callbacks/actions.py +0 -51
  97. django_cfg/modules/django_unfold/callbacks/apizones.py +0 -122
  98. django_cfg/modules/django_unfold/callbacks/charts.py +0 -223
  99. django_cfg/modules/django_unfold/callbacks/commands.py +0 -40
  100. django_cfg/modules/django_unfold/callbacks/main.py +0 -322
  101. django_cfg/modules/django_unfold/callbacks/statistics.py +0 -240
  102. django_cfg/modules/django_unfold/callbacks/system.py +0 -180
  103. django_cfg/modules/django_unfold/callbacks/users.py +0 -65
  104. django_cfg/modules/django_unfold/models/dashboard.py +0 -207
  105. django_cfg/modules/django_unfold/models/tabs.py +0 -26
  106. django_cfg/modules/django_unfold/models.py +0 -98
  107. django_cfg/modules/django_unfold/templates/unfold/helpers/app_list.html +0 -102
  108. django_cfg/static/frontend/admin/_next/static/chunks/23004-faae121bbfecc163.js +0 -1
  109. django_cfg/static/frontend/admin/_next/static/chunks/50314-48bd5701f62faf27.js +0 -1
  110. django_cfg/static/frontend/admin/_next/static/chunks/pages/private-fe9faa86ecdb0ce6.js +0 -1
  111. django_cfg/static/frontend/admin/_next/static/css/5f9a37b6e6a72303.css +0 -3
  112. django_cfg/static/frontend/admin/_next/static/media/438aa629764e75f3-s.woff2 +0 -0
  113. django_cfg/static/frontend/admin/_next/static/media/4c9affa5bc8f420e-s.p.woff2 +0 -0
  114. django_cfg/static/frontend/admin/_next/static/media/51251f8b9793cdb3-s.woff2 +0 -0
  115. django_cfg/static/frontend/admin/_next/static/media/875ae681bfde4580-s.p.woff2 +0 -0
  116. django_cfg/static/frontend/admin/_next/static/media/cc978ac5ee68c2b6-s.woff2 +0 -0
  117. django_cfg/static/frontend/admin/_next/static/media/e857b654a2caa584-s.woff2 +0 -0
  118. django_cfg/templates/admin/sections/commands_section.html +0 -5
  119. django_cfg/templates/admin/sections/documentation_section.html +0 -5
  120. django_cfg/templates/admin/sections/overview_section.html +0 -5
  121. django_cfg/templates/admin/sections/stats_section.html +0 -5
  122. django_cfg/templates/admin/sections/system_section.html +0 -5
  123. django_cfg/templates/admin/sections/widgets_section.html +0 -11
  124. django_cfg/templates/admin_old/components/action_grid.html +0 -49
  125. django_cfg/templates/admin_old/components/card.html +0 -50
  126. django_cfg/templates/admin_old/components/data_table.html +0 -67
  127. django_cfg/templates/admin_old/components/metric_card.html +0 -39
  128. django_cfg/templates/admin_old/components/modal.html +0 -58
  129. django_cfg/templates/admin_old/components/progress_bar.html +0 -20
  130. django_cfg/templates/admin_old/components/section_header.html +0 -26
  131. django_cfg/templates/admin_old/components/stat_item.html +0 -32
  132. django_cfg/templates/admin_old/components/stats_grid.html +0 -72
  133. django_cfg/templates/admin_old/components/status_badge.html +0 -28
  134. django_cfg/templates/admin_old/components/user_avatar.html +0 -27
  135. django_cfg/templates/admin_old/constance/change_list.html +0 -74
  136. django_cfg/templates/admin_old/constance/includes/default_value.html +0 -24
  137. django_cfg/templates/admin_old/constance/includes/fieldset_header.html +0 -15
  138. django_cfg/templates/admin_old/constance/includes/results_list.html +0 -16
  139. django_cfg/templates/admin_old/constance/includes/setting_row.html +0 -50
  140. django_cfg/templates/admin_old/constance/includes/table_headers.html +0 -10
  141. django_cfg/templates/admin_old/examples/component_class_example.html +0 -156
  142. django_cfg/templates/admin_old/import_export/change_list_export.html +0 -24
  143. django_cfg/templates/admin_old/import_export/change_list_import.html +0 -24
  144. django_cfg/templates/admin_old/import_export/change_list_import_export.html +0 -34
  145. django_cfg/templates/admin_old/index.html +0 -80
  146. django_cfg/templates/admin_old/index_new.html +0 -119
  147. django_cfg/templates/admin_old/layouts/base_dashboard.html +0 -62
  148. django_cfg/templates/admin_old/layouts/dashboard_with_tabs.html +0 -176
  149. django_cfg/templates/admin_old/sections/commands_section.html +0 -549
  150. django_cfg/templates/admin_old/sections/documentation_section.html +0 -152
  151. django_cfg/templates/admin_old/sections/overview_section.html +0 -112
  152. django_cfg/templates/admin_old/sections/stats_section.html +0 -35
  153. django_cfg/templates/admin_old/sections/system_section.html +0 -99
  154. django_cfg/templates/admin_old/sections/widgets_section.html +0 -129
  155. django_cfg/templates/admin_old/snippets/components/activity_tracker.html +0 -70
  156. django_cfg/templates/admin_old/snippets/components/charts_section.html +0 -113
  157. django_cfg/templates/admin_old/snippets/components/django_commands.html +0 -270
  158. django_cfg/templates/admin_old/snippets/components/quick_actions.html +0 -66
  159. django_cfg/templates/admin_old/snippets/components/recent_activity_improved.html +0 -25
  160. django_cfg/templates/admin_old/snippets/components/recent_users_table.html +0 -102
  161. django_cfg/templates/admin_old/snippets/components/stats_cards.html +0 -4
  162. django_cfg/templates/admin_old/snippets/components/stats_tiles.html +0 -92
  163. django_cfg/templates/admin_old/snippets/components/system_health.html +0 -22
  164. django_cfg/templates/admin_old/snippets/components/system_metrics.html +0 -199
  165. django_cfg/templates/admin_old/snippets/components/user_permissions.html +0 -57
  166. django_cfg/templates/admin_old/snippets/tabs/app_stats_tab.html +0 -201
  167. django_cfg/templates/admin_old/snippets/tabs/commands_tab.html +0 -114
  168. django_cfg/templates/admin_old/snippets/tabs/documentation_tab.html +0 -42
  169. django_cfg/templates/admin_old/snippets/tabs/overview_tab.html +0 -116
  170. django_cfg/templates/admin_old/snippets/tabs/stats_tab.html +0 -89
  171. django_cfg/templates/admin_old/snippets/tabs/users_tab.html +0 -51
  172. django_cfg/templates/admin_old/snippets/tabs/widgets_tab.html +0 -38
  173. django_cfg/templates/admin_old/snippets/zones/zones_table.html +0 -176
  174. /django_cfg/static/frontend/admin/_next/static/{ZJZBgOL9mO1koHrgaaLEV → 0sN9ktsgXH48ygtGSrhfu}/_ssgManifest.js +0 -0
  175. {django_cfg-1.4.87.dist-info → django_cfg-1.4.89.dist-info}/WHEEL +0 -0
  176. {django_cfg-1.4.87.dist-info → django_cfg-1.4.89.dist-info}/entry_points.txt +0 -0
  177. {django_cfg-1.4.87.dist-info → django_cfg-1.4.89.dist-info}/licenses/LICENSE +0 -0
@@ -1,398 +0,0 @@
1
- """Overview section for dashboard."""
2
-
3
- from typing import Any, Dict, List
4
-
5
- from .base import DataSection
6
-
7
-
8
- class OverviewSection(DataSection):
9
- """
10
- Overview section showing key metrics and system status.
11
- """
12
-
13
- template_name = "admin/sections/overview_section.html"
14
- title = "System Overview"
15
- icon = "dashboard"
16
-
17
- def get_data(self) -> Dict[str, Any]:
18
- """Get overview data."""
19
- from django_cfg.core.config import get_current_config
20
-
21
- config = get_current_config()
22
-
23
- return {
24
- 'stats': self.get_key_stats(),
25
- 'system_health': self.get_system_health(),
26
- 'recent_activity': self.get_recent_activity(),
27
- }
28
-
29
- def get_context_data(self, **kwargs) -> Dict[str, Any]:
30
- """Add additional context for includes."""
31
- import json
32
-
33
- from django.utils.safestring import mark_safe
34
-
35
- context = super().get_context_data(**kwargs)
36
-
37
- # Get time range from kwargs (default: 7 days)
38
- time_range = kwargs.get('time_range', 7)
39
-
40
- # Add data needed by included components
41
- context['system_metrics'] = self.get_system_metrics()
42
- context['recent_users'] = self.get_recent_users()
43
- context['recent_users_table'] = self.get_recent_users_table()
44
-
45
- # Convert activity tracker to JSON for JavaScript
46
- activity_data = self.get_activity_tracker()
47
- context['activity_tracker'] = mark_safe(json.dumps(activity_data))
48
-
49
- context['charts'] = self.get_charts_data(days=time_range)
50
-
51
- # Quick actions come from kwargs (passed from callbacks)
52
- if 'quick_actions' in kwargs:
53
- context['quick_actions'] = kwargs['quick_actions']
54
-
55
- # Navigation for time range filter
56
- if 'navigation' in kwargs:
57
- context['navigation'] = kwargs['navigation']
58
-
59
- return context
60
-
61
- def get_key_stats(self) -> Dict[str, Any]:
62
- """Get key statistics."""
63
- from django.contrib.auth import get_user_model
64
- from django.db import connection
65
-
66
- User = get_user_model()
67
-
68
- # Get database count
69
- db_count = len(connection.settings_dict.get('DATABASES', {})) if hasattr(connection, 'settings_dict') else 1
70
-
71
- # Get app count
72
- from django.apps import apps
73
- app_count = len(apps.get_app_configs())
74
-
75
- return {
76
- 'users': User.objects.count(),
77
- 'databases': db_count,
78
- 'apps': app_count,
79
- }
80
-
81
- def get_system_health(self) -> Dict[str, Any]:
82
- """Get system health metrics."""
83
- import sys
84
-
85
- import psutil
86
-
87
- return {
88
- 'python_version': f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
89
- 'cpu_percent': psutil.cpu_percent(interval=0.1),
90
- 'memory_percent': psutil.virtual_memory().percent,
91
- 'disk_percent': psutil.disk_usage('/').percent,
92
- }
93
-
94
- def get_recent_activity(self) -> list:
95
- """Get recent activity items."""
96
- # TODO: Implement activity tracking
97
- return []
98
-
99
- def get_system_metrics(self) -> Dict[str, Any]:
100
- """Get system metrics for progress bars."""
101
- from django.core.cache import cache
102
- from django.db import connection
103
-
104
- metrics = {}
105
-
106
- # Database metrics
107
- try:
108
- with connection.cursor() as cursor:
109
- cursor.execute("SELECT 1")
110
- metrics["database"] = {
111
- "status": "healthy",
112
- "type": connection.settings_dict.get('ENGINE', 'Unknown').split('.')[-1],
113
- "health_percentage": 95,
114
- "description": "Connection successful",
115
- }
116
- except Exception as e:
117
- metrics["database"] = {
118
- "status": "error",
119
- "type": "Database",
120
- "health_percentage": 0,
121
- "description": f"Connection failed: {str(e)[:50]}",
122
- }
123
-
124
- # Cache metrics
125
- try:
126
- cache.set("health_check", "ok", 10)
127
- cache_result = cache.get("health_check")
128
- if cache_result == "ok":
129
- metrics["cache"] = {
130
- "status": "healthy",
131
- "type": "Memory Cache",
132
- "health_percentage": 90,
133
- "description": "Cache working properly",
134
- }
135
- else:
136
- metrics["cache"] = {
137
- "status": "warning",
138
- "type": "Memory Cache",
139
- "health_percentage": 50,
140
- "description": "Cache response delayed",
141
- }
142
- except Exception as e:
143
- metrics["cache"] = {
144
- "status": "error",
145
- "type": "Memory Cache",
146
- "health_percentage": 0,
147
- "description": f"Cache error: {str(e)[:50]}",
148
- }
149
-
150
- # Storage metrics
151
- try:
152
- import shutil
153
- total, used, free = shutil.disk_usage("/")
154
- usage_percentage = (used / total) * 100
155
- free_percentage = 100 - usage_percentage
156
-
157
- # Status based on free space
158
- if free_percentage > 20:
159
- status = "healthy"
160
- elif free_percentage > 10:
161
- status = "warning"
162
- else:
163
- status = "error"
164
-
165
- metrics["storage"] = {
166
- "status": status,
167
- "type": "Disk Space",
168
- "health_percentage": int(free_percentage), # Show free space percentage
169
- "description": f"{free_percentage:.1f}% free ({usage_percentage:.1f}% used)",
170
- }
171
- except Exception as e:
172
- metrics["storage"] = {
173
- "status": "error",
174
- "type": "Disk Space",
175
- "health_percentage": 0,
176
- "description": f"Check failed: {str(e)[:50]}",
177
- }
178
-
179
- # API metrics
180
- try:
181
- from django.urls import get_resolver
182
- resolver = get_resolver()
183
- url_patterns = list(resolver.url_patterns)
184
-
185
- metrics["api"] = {
186
- "status": "healthy",
187
- "type": "REST API",
188
- "health_percentage": 100,
189
- "description": f"{len(url_patterns)} URL patterns",
190
- }
191
- except Exception:
192
- metrics["api"] = {
193
- "status": "warning",
194
- "type": "REST API",
195
- "health_percentage": 50,
196
- "description": "Unable to count URLs",
197
- }
198
-
199
- return metrics
200
-
201
- def get_recent_users(self) -> List[Dict[str, Any]]:
202
- """Get recent users for activity section."""
203
- from django.contrib.auth import get_user_model
204
-
205
- User = get_user_model()
206
-
207
- try:
208
- recent_users = User.objects.order_by('-date_joined')[:5]
209
- return list(recent_users.values(
210
- 'id', 'username', 'email', 'is_active', 'date_joined'
211
- ))
212
- except Exception:
213
- return []
214
-
215
- def get_recent_users_table(self) -> Dict[str, Any]:
216
- """Get recent users in table format for Unfold table component."""
217
- from django.contrib.auth import get_user_model
218
-
219
- User = get_user_model()
220
-
221
- try:
222
- recent_users = User.objects.order_by('-date_joined')[:10]
223
-
224
- return {
225
- "headers": ["Username", "Email", "Status", "Staff", "Joined"],
226
- "rows": [
227
- [
228
- user.username,
229
- user.email,
230
- "✅ Active" if user.is_active else "❌ Inactive",
231
- "🛡️ Yes" if user.is_staff else "—",
232
- user.date_joined.strftime('%Y-%m-%d %H:%M')
233
- ]
234
- for user in recent_users
235
- ]
236
- }
237
- except Exception:
238
- return {"headers": [], "rows": []}
239
-
240
- def get_activity_tracker(self) -> List[Dict[str, Any]]:
241
- """
242
- Get activity tracker data for GitHub-style heatmap.
243
-
244
- Returns list of dicts with date and count for last 365 days.
245
- """
246
- from datetime import timedelta
247
-
248
- from django.contrib.auth import get_user_model
249
- from django.utils import timezone
250
-
251
- User = get_user_model()
252
-
253
- try:
254
- # Get activity for last 365 days
255
- today = timezone.now().date()
256
- activity_data = []
257
-
258
- for days_ago in range(364, -1, -1): # 365 days, newest last
259
- date = today - timedelta(days=days_ago)
260
-
261
- # Count user registrations on this day
262
- registrations = User.objects.filter(
263
- date_joined__date=date
264
- ).count()
265
-
266
- # Count logins on this day (if last_login exists)
267
- logins = 0
268
- if hasattr(User, 'last_login'):
269
- logins = User.objects.filter(
270
- last_login__date=date
271
- ).count()
272
-
273
- # Total activity for the day
274
- total_activity = registrations + logins
275
-
276
- activity_data.append({
277
- 'date': date.isoformat(),
278
- 'count': total_activity,
279
- 'level': self._get_activity_level(total_activity),
280
- })
281
-
282
- return activity_data
283
-
284
- except Exception:
285
- # Return empty on error
286
- return []
287
-
288
- def _get_activity_level(self, count: int) -> int:
289
- """
290
- Convert activity count to level (0-4) for heatmap colors.
291
-
292
- 0 = no activity (gray)
293
- 1 = low (light green)
294
- 2 = medium (green)
295
- 3 = high (dark green)
296
- 4 = very high (darkest green)
297
- """
298
- if count == 0:
299
- return 0
300
- elif count <= 2:
301
- return 1
302
- elif count <= 5:
303
- return 2
304
- elif count <= 10:
305
- return 3
306
- else:
307
- return 4
308
-
309
- def get_charts_data(self, days: int = 7) -> Dict[str, Any]:
310
- """Get charts data for Analytics Overview.
311
-
312
- Args:
313
- days: Number of days to include in charts (default: 7)
314
- """
315
- import json
316
- from datetime import datetime, timedelta
317
-
318
- from django.contrib.auth import get_user_model
319
- from django.utils import timezone
320
-
321
- User = get_user_model()
322
-
323
- try:
324
- # Get last N days of user registrations
325
- today = timezone.now().date()
326
- dates = [(today - timedelta(days=i)).strftime('%Y-%m-%d') for i in range(days-1, -1, -1)]
327
-
328
- # Count users registered each day
329
- registrations = []
330
- for date_str in dates:
331
- date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
332
- count = User.objects.filter(
333
- date_joined__date=date_obj
334
- ).count()
335
- registrations.append(count)
336
-
337
- # Count active users each day (last login)
338
- activity = []
339
- for date_str in dates:
340
- date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
341
- # Count users who logged in that day
342
- count = User.objects.filter(
343
- last_login__date=date_obj
344
- ).count() if hasattr(User, 'last_login') else 0
345
- activity.append(count)
346
-
347
- # Format for charts
348
- day_labels = [d.split('-')[2] for d in dates] # Just day numbers
349
-
350
- # Prepare chart data structures
351
- user_reg_data = {
352
- 'labels': day_labels,
353
- 'datasets': [{
354
- 'label': 'New Users',
355
- 'data': registrations,
356
- 'backgroundColor': 'rgba(59, 130, 246, 0.5)',
357
- 'borderColor': 'rgb(59, 130, 246)',
358
- 'borderWidth': 2,
359
- }]
360
- }
361
-
362
- user_activity_data = {
363
- 'labels': day_labels,
364
- 'datasets': [{
365
- 'label': 'Active Users',
366
- 'data': activity,
367
- 'backgroundColor': 'rgba(34, 197, 94, 0.5)',
368
- 'borderColor': 'rgb(34, 197, 94)',
369
- 'borderWidth': 2,
370
- }]
371
- }
372
-
373
- return {
374
- # User Registrations chart
375
- 'user_registrations': {
376
- 'labels': day_labels,
377
- 'datasets': [{
378
- 'label': 'New Users',
379
- 'data': registrations,
380
- }]
381
- },
382
- # JSON string for Unfold chart component (NO mark_safe - let Django escape quotes)
383
- 'user_registrations_json': json.dumps(user_reg_data),
384
-
385
- # User Activity chart
386
- 'user_activity': {
387
- 'labels': day_labels,
388
- 'datasets': [{
389
- 'label': 'Active Users',
390
- 'data': activity,
391
- }]
392
- },
393
- # JSON string for Unfold chart component (NO mark_safe - let Django escape quotes)
394
- 'user_activity_json': json.dumps(user_activity_data),
395
- }
396
- except Exception:
397
- # Return empty chart data
398
- return {}
@@ -1,48 +0,0 @@
1
- """Statistics section for dashboard."""
2
-
3
- from typing import Any, Dict, List
4
-
5
- from .base import DataSection
6
-
7
-
8
- class StatsSection(DataSection):
9
- """
10
- Statistics section showing detailed metrics.
11
- """
12
-
13
- template_name = "admin/sections/stats_section.html"
14
- title = "Statistics"
15
- icon = "analytics"
16
-
17
- def get_data(self) -> Dict[str, Any]:
18
- """Get statistics data."""
19
- return {
20
- 'app_stats': self.get_app_stats(),
21
- 'time_series': self.get_time_series(),
22
- }
23
-
24
- def get_app_stats(self) -> List[Dict[str, Any]]:
25
- """Get per-app statistics."""
26
- from django.apps import apps
27
-
28
- stats = []
29
-
30
- for app_config in apps.get_app_configs():
31
- if app_config.name.startswith('django.'):
32
- continue
33
-
34
- # Count models in app
35
- models = [m for m in apps.get_models() if m._meta.app_label == app_config.label]
36
-
37
- stats.append({
38
- 'name': app_config.verbose_name,
39
- 'label': app_config.label,
40
- 'models_count': len(models),
41
- })
42
-
43
- return stats
44
-
45
- def get_time_series(self) -> Dict[str, Any]:
46
- """Get time series data for charts."""
47
- # TODO: Implement time series data
48
- return {}
@@ -1,74 +0,0 @@
1
- """System section for dashboard."""
2
-
3
- from typing import Any, Dict
4
-
5
- from .base import DataSection
6
-
7
-
8
- class SystemSection(DataSection):
9
- """
10
- System management section.
11
- """
12
-
13
- template_name = "admin/sections/system_section.html"
14
- title = "System Management"
15
- icon = "settings"
16
-
17
- def get_data(self) -> Dict[str, Any]:
18
- """Get system data."""
19
- return {
20
- 'health': self.get_health_check(),
21
- 'services': self.get_services_status(),
22
- 'configuration': self.get_configuration(),
23
- }
24
-
25
- def get_health_check(self) -> Dict[str, Any]:
26
- """Get health check status."""
27
- import psutil
28
-
29
- return {
30
- 'status': 'healthy',
31
- 'checks': {
32
- 'database': self.check_database(),
33
- 'cache': self.check_cache(),
34
- 'disk_space': psutil.disk_usage('/').percent < 90,
35
- 'memory': psutil.virtual_memory().percent < 90,
36
- }
37
- }
38
-
39
- def check_database(self) -> bool:
40
- """Check database connectivity."""
41
- from django.db import connection
42
-
43
- try:
44
- connection.ensure_connection()
45
- return True
46
- except Exception:
47
- return False
48
-
49
- def check_cache(self) -> bool:
50
- """Check cache availability."""
51
- from django.core.cache import cache
52
-
53
- try:
54
- cache.set('health_check', True, 1)
55
- return cache.get('health_check') is True
56
- except Exception:
57
- return False
58
-
59
- def get_services_status(self) -> Dict[str, Any]:
60
- """Get services status."""
61
- # TODO: Implement services status check
62
- return {}
63
-
64
- def get_configuration(self) -> Dict[str, Any]:
65
- """Get system configuration."""
66
- from django_cfg.core.config import get_current_config
67
-
68
- config = get_current_config()
69
-
70
- return {
71
- 'debug': config.debug,
72
- 'env_mode': config.env_mode,
73
- 'project_name': config.project_name,
74
- }