fastapi-admin-kit 0.1.0__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.
Files changed (163) hide show
  1. fastapi_admin_kit/__init__.py +73 -0
  2. fastapi_admin_kit/actions/__init__.py +63 -0
  3. fastapi_admin_kit/actions/base.py +68 -0
  4. fastapi_admin_kit/actions/registry.py +43 -0
  5. fastapi_admin_kit/admin/__init__.py +17 -0
  6. fastapi_admin_kit/admin/admin_config.py +95 -0
  7. fastapi_admin_kit/admin/admin_database.py +138 -0
  8. fastapi_admin_kit/admin/admin_router.py +74 -0
  9. fastapi_admin_kit/admin/admin_template.py +203 -0
  10. fastapi_admin_kit/admin/builtin_models.py +284 -0
  11. fastapi_admin_kit/admin/core.py +1036 -0
  12. fastapi_admin_kit/admin/decorators.py +70 -0
  13. fastapi_admin_kit/admin/state.py +76 -0
  14. fastapi_admin_kit/admin.py +728 -0
  15. fastapi_admin_kit/api/__init__.py +44 -0
  16. fastapi_admin_kit/api/auth.py +342 -0
  17. fastapi_admin_kit/api/crud.py +128 -0
  18. fastapi_admin_kit/api/deps.py +79 -0
  19. fastapi_admin_kit/api/roles.py +128 -0
  20. fastapi_admin_kit/api/schema_generator.py +171 -0
  21. fastapi_admin_kit/api/schemas.py +81 -0
  22. fastapi_admin_kit/api/search.py +132 -0
  23. fastapi_admin_kit/audit/__init__.py +36 -0
  24. fastapi_admin_kit/audit/context.py +62 -0
  25. fastapi_admin_kit/audit/diff.py +77 -0
  26. fastapi_admin_kit/audit/event_bus.py +96 -0
  27. fastapi_admin_kit/audit/events.py +48 -0
  28. fastapi_admin_kit/audit/listener.py +159 -0
  29. fastapi_admin_kit/audit/logger.py +28 -0
  30. fastapi_admin_kit/audit/middleware.py +39 -0
  31. fastapi_admin_kit/audit/models.py +53 -0
  32. fastapi_admin_kit/audit/sqlalchemy_logger.py +58 -0
  33. fastapi_admin_kit/auth/__init__.py +34 -0
  34. fastapi_admin_kit/auth/backend.py +95 -0
  35. fastapi_admin_kit/auth/csrf.py +240 -0
  36. fastapi_admin_kit/auth/dependencies.py +150 -0
  37. fastapi_admin_kit/auth/identity.py +181 -0
  38. fastapi_admin_kit/auth/models.py +246 -0
  39. fastapi_admin_kit/auth/password.py +35 -0
  40. fastapi_admin_kit/auth/permissions.py +205 -0
  41. fastapi_admin_kit/auth/protocol.py +22 -0
  42. fastapi_admin_kit/auth/ratelimit.py +88 -0
  43. fastapi_admin_kit/auth/router.py +10 -0
  44. fastapi_admin_kit/auth/session.py +79 -0
  45. fastapi_admin_kit/auth/totp.py +83 -0
  46. fastapi_admin_kit/auth/views.py +165 -0
  47. fastapi_admin_kit/cli.py +229 -0
  48. fastapi_admin_kit/config/__init__.py +19 -0
  49. fastapi_admin_kit/config/audit.py +18 -0
  50. fastapi_admin_kit/config/auth.py +54 -0
  51. fastapi_admin_kit/config/behavior.py +27 -0
  52. fastapi_admin_kit/config/nav.py +32 -0
  53. fastapi_admin_kit/config/storage.py +22 -0
  54. fastapi_admin_kit/config/theme.py +215 -0
  55. fastapi_admin_kit/config/ui.py +147 -0
  56. fastapi_admin_kit/dashboard/__init__.py +64 -0
  57. fastapi_admin_kit/db.py +133 -0
  58. fastapi_admin_kit/exceptions.py +5 -0
  59. fastapi_admin_kit/field_types.py +81 -0
  60. fastapi_admin_kit/filters/__init__.py +21 -0
  61. fastapi_admin_kit/filters/base.py +170 -0
  62. fastapi_admin_kit/filters/registry.py +68 -0
  63. fastapi_admin_kit/flash.py +45 -0
  64. fastapi_admin_kit/form/__init__.py +1 -0
  65. fastapi_admin_kit/form/pipeline.py +106 -0
  66. fastapi_admin_kit/inspection/__init__.py +117 -0
  67. fastapi_admin_kit/inspection/registry.py +253 -0
  68. fastapi_admin_kit/inspection.py +115 -0
  69. fastapi_admin_kit/modeladmin.py +375 -0
  70. fastapi_admin_kit/models/__init__.py +7 -0
  71. fastapi_admin_kit/models/base.py +7 -0
  72. fastapi_admin_kit/nav.py +208 -0
  73. fastapi_admin_kit/pagination/__init__.py +14 -0
  74. fastapi_admin_kit/pagination/base.py +40 -0
  75. fastapi_admin_kit/pagination/cursor.py +97 -0
  76. fastapi_admin_kit/pagination/dynamic.py +48 -0
  77. fastapi_admin_kit/pagination/offset.py +42 -0
  78. fastapi_admin_kit/plugins/__init__.py +1 -0
  79. fastapi_admin_kit/py.typed +0 -0
  80. fastapi_admin_kit/registry/__init__.py +5 -0
  81. fastapi_admin_kit/registry/core.py +287 -0
  82. fastapi_admin_kit/registry/validation.py +107 -0
  83. fastapi_admin_kit/registry.py +15 -0
  84. fastapi_admin_kit/router.py +335 -0
  85. fastapi_admin_kit/static/css/admin.css +4736 -0
  86. fastapi_admin_kit/static/css/presets.css +317 -0
  87. fastapi_admin_kit/static/css/tokens.css +217 -0
  88. fastapi_admin_kit/static/css/variables.css +74 -0
  89. fastapi_admin_kit/static/icons/heroicons.svg +160 -0
  90. fastapi_admin_kit/static/js/admin.js +692 -0
  91. fastapi_admin_kit/static/js/htmx-config.js +42 -0
  92. fastapi_admin_kit/storage/__init__.py +6 -0
  93. fastapi_admin_kit/storage/base.py +48 -0
  94. fastapi_admin_kit/storage/local.py +73 -0
  95. fastapi_admin_kit/templates/base.html +142 -0
  96. fastapi_admin_kit/templates/macros/form_fields.html +660 -0
  97. fastapi_admin_kit/templates/macros/icons.html +50 -0
  98. fastapi_admin_kit/templates/macros/table.html +108 -0
  99. fastapi_admin_kit/templates/macros/widgets.html +159 -0
  100. fastapi_admin_kit/templates/pages/2fa/setup.html +122 -0
  101. fastapi_admin_kit/templates/pages/2fa/verify.html +55 -0
  102. fastapi_admin_kit/templates/pages/audit_detail.html +122 -0
  103. fastapi_admin_kit/templates/pages/audit_log.html +102 -0
  104. fastapi_admin_kit/templates/pages/dashboard.html +295 -0
  105. fastapi_admin_kit/templates/pages/detail.html +183 -0
  106. fastapi_admin_kit/templates/pages/form.html +119 -0
  107. fastapi_admin_kit/templates/pages/list.html +277 -0
  108. fastapi_admin_kit/templates/pages/login.html +85 -0
  109. fastapi_admin_kit/templates/pages/profile/password.html +78 -0
  110. fastapi_admin_kit/templates/pages/profile/profile.html +73 -0
  111. fastapi_admin_kit/templates/pages/role_form.html +75 -0
  112. fastapi_admin_kit/templates/pages/roles/form.html +117 -0
  113. fastapi_admin_kit/templates/pages/roles/list.html +69 -0
  114. fastapi_admin_kit/templates/pages/roles.html +77 -0
  115. fastapi_admin_kit/templates/pages/settings/theme.html +255 -0
  116. fastapi_admin_kit/templates/pages/users/form.html +229 -0
  117. fastapi_admin_kit/templates/pages/users/list.html +83 -0
  118. fastapi_admin_kit/templates/partials/command_palette.html +52 -0
  119. fastapi_admin_kit/templates/partials/field_wrapper.html +2 -0
  120. fastapi_admin_kit/templates/partials/flash_messages.html +39 -0
  121. fastapi_admin_kit/templates/partials/head.html +21 -0
  122. fastapi_admin_kit/templates/partials/head_minimal.html +18 -0
  123. fastapi_admin_kit/templates/partials/list_table.html +178 -0
  124. fastapi_admin_kit/templates/partials/mobile_backdrop.html +2 -0
  125. fastapi_admin_kit/templates/partials/pagination.html +82 -0
  126. fastapi_admin_kit/templates/partials/permission_widget.html +86 -0
  127. fastapi_admin_kit/templates/partials/scripts.html +13 -0
  128. fastapi_admin_kit/templates/partials/sidebar.html +94 -0
  129. fastapi_admin_kit/templates/partials/topbar.html +95 -0
  130. fastapi_admin_kit/types.py +145 -0
  131. fastapi_admin_kit/validation.py +43 -0
  132. fastapi_admin_kit/views/__init__.py +78 -0
  133. fastapi_admin_kit/views/audit.py +134 -0
  134. fastapi_admin_kit/views/bulk.py +28 -0
  135. fastapi_admin_kit/views/class_views.py +1040 -0
  136. fastapi_admin_kit/views/context.py +588 -0
  137. fastapi_admin_kit/views/dashboard.py +162 -0
  138. fastapi_admin_kit/views/delete.py +31 -0
  139. fastapi_admin_kit/views/extra.py +65 -0
  140. fastapi_admin_kit/views/factory.py +667 -0
  141. fastapi_admin_kit/views/form.py +159 -0
  142. fastapi_admin_kit/views/list.py +28 -0
  143. fastapi_admin_kit/views/profile.py +219 -0
  144. fastapi_admin_kit/views/protocols.py +54 -0
  145. fastapi_admin_kit/views/renderers.py +634 -0
  146. fastapi_admin_kit/views/roles.py +230 -0
  147. fastapi_admin_kit/views/search.py +31 -0
  148. fastapi_admin_kit/views/settings.py +31 -0
  149. fastapi_admin_kit/views/sidebar.py +101 -0
  150. fastapi_admin_kit/views/totp.py +249 -0
  151. fastapi_admin_kit/views/users.py +347 -0
  152. fastapi_admin_kit/views.py +117 -0
  153. fastapi_admin_kit/widgets/__init__.py +44 -0
  154. fastapi_admin_kit/widgets/base.py +44 -0
  155. fastapi_admin_kit/widgets/inputs.py +363 -0
  156. fastapi_admin_kit/widgets/registry.py +110 -0
  157. fastapi_admin_kit/widgets/relation.py +70 -0
  158. fastapi_admin_kit/widgets/resolver.py +102 -0
  159. fastapi_admin_kit-0.1.0.dist-info/METADATA +210 -0
  160. fastapi_admin_kit-0.1.0.dist-info/RECORD +163 -0
  161. fastapi_admin_kit-0.1.0.dist-info/WHEEL +4 -0
  162. fastapi_admin_kit-0.1.0.dist-info/entry_points.txt +3 -0
  163. fastapi_admin_kit-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,134 @@
1
+ """Audit log views — list and detail."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import date, datetime
6
+
7
+ from fastapi import APIRouter, Depends, HTTPException, Query, Request
8
+ from sqlalchemy import desc, select
9
+
10
+ from fastapi_admin_kit.audit.models import AuditLog
11
+ from fastapi_admin_kit.auth.dependencies import get_current_admin_user
12
+ from fastapi_admin_kit.auth.protocol import AdminUserProtocol
13
+ from fastapi_admin_kit.db import get_db_session
14
+ from fastapi_admin_kit.views.sidebar import inject_sidebar_context
15
+
16
+ router = APIRouter()
17
+
18
+
19
+ async def _require_superuser(
20
+ user: AdminUserProtocol = Depends(get_current_admin_user),
21
+ ) -> AdminUserProtocol:
22
+ if not getattr(user, "is_superuser", False):
23
+ raise HTTPException(status_code=403, detail="Superuser access required.")
24
+ return user
25
+
26
+
27
+ @router.get("/audit")
28
+ async def audit_list_view(
29
+ request: Request,
30
+ model: str | None = Query(None, description="Filter by model name"),
31
+ user_id: int | None = Query(None),
32
+ action: str | None = Query(None, regex="^(CREATE|UPDATE|DELETE)$"),
33
+ from_date: date | None = Query(None),
34
+ to_date: date | None = Query(None),
35
+ object_id: str | None = Query(None),
36
+ page: int = Query(1, ge=1),
37
+ _: AdminUserProtocol = Depends(_require_superuser),
38
+ ):
39
+ """List audit log entries with filters."""
40
+ templates = request.app.state.admin_jinja_env
41
+ session = get_db_session(request)
42
+
43
+ query = select(AuditLog)
44
+
45
+ if model:
46
+ query = query.where(AuditLog.table_name == model)
47
+ if user_id:
48
+ query = query.where(AuditLog.user_id == user_id)
49
+ if action:
50
+ query = query.where(AuditLog.action == action)
51
+ if from_date:
52
+ query = query.where(AuditLog.timestamp >= datetime.combine(from_date, datetime.min.time()))
53
+ if to_date:
54
+ query = query.where(AuditLog.timestamp <= datetime.combine(to_date, datetime.max.time()))
55
+ if object_id:
56
+ query = query.where(AuditLog.object_id == object_id)
57
+
58
+ query = query.order_by(desc(AuditLog.timestamp))
59
+ per_page = 25
60
+ offset = (page - 1) * per_page
61
+ total_query = select(AuditLog)
62
+ if model:
63
+ total_query = total_query.where(AuditLog.table_name == model)
64
+ if user_id:
65
+ total_query = total_query.where(AuditLog.user_id == user_id)
66
+ if action:
67
+ total_query = total_query.where(AuditLog.action == action)
68
+ if from_date:
69
+ total_query = total_query.where(
70
+ AuditLog.timestamp >= datetime.combine(from_date, datetime.min.time())
71
+ )
72
+ if to_date:
73
+ total_query = total_query.where(
74
+ AuditLog.timestamp <= datetime.combine(to_date, datetime.max.time())
75
+ )
76
+ if object_id:
77
+ total_query = total_query.where(AuditLog.object_id == object_id)
78
+
79
+ total_result = await session.execute(total_query)
80
+ total = len(total_result.scalars().all())
81
+ entries = (await session.execute(query.offset(offset).limit(per_page))).scalars().all()
82
+
83
+ admin_path = request.app.state.admin_config["admin_path"]
84
+
85
+ return templates.TemplateResponse(
86
+ request,
87
+ "pages/audit_log.html",
88
+ await inject_sidebar_context(request, {
89
+ "entries": entries,
90
+ "page": page,
91
+ "per_page": per_page,
92
+ "total_items": total,
93
+ "total_pages": max(1, (total + per_page - 1) // per_page),
94
+ "admin_path": admin_path,
95
+ "search": "",
96
+ "action_filter": action or "",
97
+ "model_filter": model or "",
98
+ "model_names": [m.table_name for m in request.app.state.admin_registry.all()],
99
+ "filters": {
100
+ "model": model or "",
101
+ "user_id": user_id or "",
102
+ "action": action or "",
103
+ "from_date": from_date or "",
104
+ "to_date": to_date or "",
105
+ "object_id": object_id or "",
106
+ },
107
+ }),
108
+ )
109
+
110
+
111
+ @router.get("/audit/{entry_id}")
112
+ async def audit_detail_view(
113
+ request: Request,
114
+ entry_id: int,
115
+ _: AdminUserProtocol = Depends(_require_superuser),
116
+ ):
117
+ """Show detailed audit entry with diff snapshot."""
118
+ templates = request.app.state.admin_jinja_env
119
+ session = get_db_session(request)
120
+
121
+ entry = await session.get(AuditLog, entry_id)
122
+ if entry is None:
123
+ raise HTTPException(status_code=404, detail="Audit entry not found")
124
+
125
+ admin_path = request.app.state.admin_config["admin_path"]
126
+
127
+ return templates.TemplateResponse(
128
+ request,
129
+ "pages/audit_detail.html",
130
+ await inject_sidebar_context(request, {
131
+ "entry": entry,
132
+ "admin_path": admin_path,
133
+ }),
134
+ )
@@ -0,0 +1,28 @@
1
+ """Bulk action handler factory for registered models.
2
+
3
+ Backward-compatible wrapper — delegates to BulkView class.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from typing import Any
9
+
10
+ from fastapi import Request
11
+
12
+ from fastapi_admin_kit.registry import RegisteredModel
13
+
14
+
15
+ def bulk_factory(registered: RegisteredModel):
16
+ """Create a bulk action handler — delegates to BulkView.html_response."""
17
+ from fastapi_admin_kit.views.class_views import BulkView, _resolve_view_class
18
+
19
+ view_class = _resolve_view_class(
20
+ registered.admin, "bulk_view_class", BulkView
21
+ )
22
+ view_instance = view_class(registered)
23
+
24
+ async def _handler(request: Request, **kwargs: Any):
25
+ return await view_instance.html_response(request, **kwargs)
26
+
27
+ _handler.__name__ = f"bulk_{registered.table_name}"
28
+ return _handler