crudadmin 0.3.0__tar.gz → 0.3.2__tar.gz

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 (65) hide show
  1. {crudadmin-0.3.0 → crudadmin-0.3.2}/PKG-INFO +41 -22
  2. {crudadmin-0.3.0 → crudadmin-0.3.2}/README.md +33 -14
  3. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/crud_admin.py +15 -10
  4. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/core/db.py +4 -4
  5. crudadmin-0.3.2/crudadmin/session/schemas.py +153 -0
  6. {crudadmin-0.3.0 → crudadmin-0.3.2}/pyproject.toml +14 -13
  7. crudadmin-0.3.0/crudadmin/session/schemas.py +0 -128
  8. {crudadmin-0.3.0 → crudadmin-0.3.2}/.gitignore +0 -0
  9. {crudadmin-0.3.0 → crudadmin-0.3.2}/LICENSE +0 -0
  10. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/__init__.py +0 -0
  11. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/__init__.py +0 -0
  12. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/admin_site.py +0 -0
  13. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/auth.py +0 -0
  14. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/helper.py +0 -0
  15. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/middleware/__init__.py +0 -0
  16. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/middleware/auth.py +0 -0
  17. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/middleware/https.py +0 -0
  18. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/middleware/ip_restriction.py +0 -0
  19. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/model_view.py +0 -0
  20. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_interface/typing.py +0 -0
  21. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_user/__init__.py +0 -0
  22. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_user/models.py +0 -0
  23. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_user/schemas.py +0 -0
  24. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/admin_user/service.py +0 -0
  25. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/core/__init__.py +0 -0
  26. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/core/auth.py +0 -0
  27. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/core/exceptions.py +0 -0
  28. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/core/rate_limiter.py +0 -0
  29. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/core/schemas/__init__.py +0 -0
  30. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/core/schemas/timestamp.py +0 -0
  31. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/event/__init__.py +0 -0
  32. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/event/decorators.py +0 -0
  33. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/event/integration.py +0 -0
  34. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/event/models.py +0 -0
  35. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/event/schemas.py +0 -0
  36. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/event/service.py +0 -0
  37. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/py.typed +0 -0
  38. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/__init__.py +0 -0
  39. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/backends/__init__.py +0 -0
  40. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/backends/database.py +0 -0
  41. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/backends/hybrid.py +0 -0
  42. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/backends/memcached.py +0 -0
  43. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/backends/memory.py +0 -0
  44. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/backends/redis.py +0 -0
  45. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/manager.py +0 -0
  46. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/models.py +0 -0
  47. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/storage.py +0 -0
  48. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/session/user_agents_types.py +0 -0
  49. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/static/favicon.png +0 -0
  50. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/static/htmx.min.js +0 -0
  51. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/dashboard/dashboard.html +0 -0
  52. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/dashboard/dashboard_content.html +0 -0
  53. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/management/events.html +0 -0
  54. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/management/events_content.html +0 -0
  55. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/management/health.html +0 -0
  56. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/management/health_content.html +0 -0
  57. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/model/components/list_content.html +0 -0
  58. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/model/components/pagination.html +0 -0
  59. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/model/components/table_content.html +0 -0
  60. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/model/create.html +0 -0
  61. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/model/list.html +0 -0
  62. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/admin/model/update.html +0 -0
  63. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/auth/login.html +0 -0
  64. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/base/base.html +0 -0
  65. {crudadmin-0.3.0 → crudadmin-0.3.2}/crudadmin/templates/shared/utils/refresh.html +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crudadmin
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: FastAPI-based admin interface with authentication, event logging and CRUD operations
5
- Project-URL: Homepage, https://github.com/igorbenav/crudadmin
6
- Project-URL: Documentation, https://igorbenav.github.io/crudadmin
7
- Project-URL: Repository, https://github.com/igorbenav/crudadmin
8
- Project-URL: Issues, https://github.com/igorbenav/crudadmin/issues
9
- Project-URL: Changelog, https://github.com/igorbenav/crudadmin/releases
5
+ Project-URL: Homepage, https://github.com/benavlabs/crudadmin
6
+ Project-URL: Documentation, https://benavlabs.github.io/crudadmin
7
+ Project-URL: Repository, https://github.com/benavlabs/crudadmin
8
+ Project-URL: Issues, https://github.com/benavlabs/crudadmin/issues
9
+ Project-URL: Changelog, https://github.com/benavlabs/crudadmin/releases
10
10
  Author-email: Igor Benav <igor.magalhaes.r@gmail.com>
11
11
  License-File: LICENSE
12
12
  Classifier: Development Status :: 3 - Alpha
@@ -27,11 +27,11 @@ Classifier: Topic :: Internet :: WWW/HTTP
27
27
  Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
28
28
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
29
29
  Classifier: Typing :: Typed
30
- Requires-Python: >=3.9
30
+ Requires-Python: >=3.9.2
31
31
  Requires-Dist: aiosqlite>=0.20.0
32
32
  Requires-Dist: bcrypt>=4.2.1
33
33
  Requires-Dist: fastapi>=0.115.6
34
- Requires-Dist: fastcrud>=0.15.5
34
+ Requires-Dist: fastcrud>=0.15.12
35
35
  Requires-Dist: greenlet>=3.1.1
36
36
  Requires-Dist: jinja2>=3.1.5
37
37
  Requires-Dist: pydantic-settings>=2.6.1
@@ -88,7 +88,7 @@ Description-Content-Type: text/markdown
88
88
  # CRUDAdmin
89
89
 
90
90
  <p align="center">
91
- <a href="https://igorbenav.github.io/crudadmin/">
91
+ <a href="https://benavlabs.github.io/crudadmin/">
92
92
  <img src="docs/assets/CRUDAdmin.png" alt="CRUDAdmin logo" width="45%" height="auto">
93
93
  </a>
94
94
  </p>
@@ -98,8 +98,8 @@ Description-Content-Type: text/markdown
98
98
  </p>
99
99
 
100
100
  <p align="center">
101
- <a href="https://github.com/igorbenav/crudadmin/actions/workflows/tests.yml">
102
- <img src="https://github.com/igorbenav/crudadmin/actions/workflows/tests.yml/badge.svg" alt="Tests"/>
101
+ <a href="https://github.com/benavlabs/crudadmin/actions/workflows/tests.yml">
102
+ <img src="https://github.com/benavlabs/crudadmin/actions/workflows/tests.yml/badge.svg" alt="Tests"/>
103
103
  </a>
104
104
  <a href="https://pypi.org/project/crudadmin/">
105
105
  <img src="https://img.shields.io/pypi/v/crudadmin?color=%2334D058&label=pypi%20package" alt="PyPi Version"/>
@@ -113,7 +113,7 @@ Description-Content-Type: text/markdown
113
113
 
114
114
  **CRUDAdmin** is a robust admin interface generator for **FastAPI** applications, offering secure authentication, comprehensive event tracking, and essential monitoring features. Built with [FastCRUD](https://github.com/benavlabs/fastcrud) and HTMX, it helps you create production-ready admin panels with minimal configuration.
115
115
 
116
- **Documentation**: [https://igorbenav.github.io/crudadmin/](https://igorbenav.github.io/crudadmin/)
116
+ **Documentation**: [https://benavlabs.github.io/crudadmin/](https://benavlabs.github.io/crudadmin/)
117
117
 
118
118
  > [!WARNING]
119
119
  > CRUDAdmin is still experimental. While actively developed and tested, APIs may change between versions. Upgrade with caution in production environments, always carefuly reading the changelog.
@@ -127,6 +127,16 @@ Description-Content-Type: text/markdown
127
127
  - **🔍 Advanced Filtering**: Type-aware field filtering, search, and pagination with bulk operations
128
128
  - **🌗 Modern UI**: Clean, responsive interface built with HTMX and [FastCRUD](https://github.com/benavlabs/fastcrud)
129
129
 
130
+ ## Video Preview
131
+
132
+ <p align="center">To see what CRUDAdmin dashboard actually looks like in practice, watch the video demo on youtube:</p>
133
+ <p align="center">
134
+ <a href="https://www.youtube.com/watch?v=THLdUbDQ9yM">
135
+ <img src="docs/assets/youtube-preview.png" alt="Watch CRUDAdmin Dashboard Demo on Youtube" width="75%" height="auto"/>
136
+ </a>
137
+ </p>
138
+ <br>
139
+
130
140
  ## Quick Start
131
141
 
132
142
  ### Installation
@@ -161,11 +171,15 @@ from .user import (
161
171
 
162
172
  # Database setup
163
173
  engine = create_async_engine("sqlite+aiosqlite:///app.db")
164
- session = AsyncSession(engine)
174
+
175
+ # Create database session dependency
176
+ async def get_session():
177
+ async with AsyncSession(engine) as session:
178
+ yield session
165
179
 
166
180
  # Create admin interface
167
181
  admin = CRUDAdmin(
168
- session=session,
182
+ session=get_session,
169
183
  SECRET_KEY="your-secret-key-here",
170
184
  initial_admin={
171
185
  "username": "admin",
@@ -208,12 +222,12 @@ Navigate to `/admin` to access your admin interface with:
208
222
 
209
223
  ### Development (Default)
210
224
  ```python
211
- admin = CRUDAdmin(session=session, SECRET_KEY="key") # Memory backend
225
+ admin = CRUDAdmin(session=get_session, SECRET_KEY="key") # Memory backend
212
226
  ```
213
227
 
214
228
  ### Production with Redis
215
229
  ```python
216
- admin = CRUDAdmin(session=session, SECRET_KEY="key").use_redis_sessions(
230
+ admin = CRUDAdmin(session=get_session, SECRET_KEY="key").use_redis_sessions(
217
231
  redis_url="redis://localhost:6379"
218
232
  )
219
233
  ```
@@ -221,7 +235,7 @@ admin = CRUDAdmin(session=session, SECRET_KEY="key").use_redis_sessions(
221
235
  ### Production with Security Features
222
236
  ```python
223
237
  admin = CRUDAdmin(
224
- session=session,
238
+ session=get_session,
225
239
  SECRET_KEY=SECRET_KEY,
226
240
  # Security features
227
241
  allowed_ips=["10.0.0.1"],
@@ -260,11 +274,16 @@ admin = CRUDAdmin(
260
274
 
261
275
  ## Documentation
262
276
 
263
- - **[Quick Start](https://igorbenav.github.io/crudadmin/quick-start/)**: Get up and running in 5 minutes
264
- - **[Usage Guide](https://igorbenav.github.io/crudadmin/usage/overview/)**: Complete usage documentation
265
- - **[API Reference](https://igorbenav.github.io/crudadmin/api/overview/)**: Full API documentation
266
- - **[Advanced Topics](https://igorbenav.github.io/crudadmin/advanced/overview/)**: Production features and configurations
277
+ - **[Quick Start](https://benavlabs.github.io/crudadmin/quick-start/)**: Get up and running in 5 minutes
278
+ - **[Usage Guide](https://benavlabs.github.io/crudadmin/usage/overview/)**: Complete usage documentation
279
+ - **[API Reference](https://benavlabs.github.io/crudadmin/api/overview/)**: Full API documentation
280
+ - **[Advanced Topics](https://benavlabs.github.io/crudadmin/advanced/overview/)**: Production features and configurations
267
281
 
268
282
  ## License
269
283
 
270
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
284
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
285
+
286
+ <hr>
287
+ <a href="https://benav.io">
288
+ <img src="docs/assets/benav_labs_banner.png" alt="Powered by Benav Labs - benav.io"/>
289
+ </a>
@@ -1,7 +1,7 @@
1
1
  # CRUDAdmin
2
2
 
3
3
  <p align="center">
4
- <a href="https://igorbenav.github.io/crudadmin/">
4
+ <a href="https://benavlabs.github.io/crudadmin/">
5
5
  <img src="docs/assets/CRUDAdmin.png" alt="CRUDAdmin logo" width="45%" height="auto">
6
6
  </a>
7
7
  </p>
@@ -11,8 +11,8 @@
11
11
  </p>
12
12
 
13
13
  <p align="center">
14
- <a href="https://github.com/igorbenav/crudadmin/actions/workflows/tests.yml">
15
- <img src="https://github.com/igorbenav/crudadmin/actions/workflows/tests.yml/badge.svg" alt="Tests"/>
14
+ <a href="https://github.com/benavlabs/crudadmin/actions/workflows/tests.yml">
15
+ <img src="https://github.com/benavlabs/crudadmin/actions/workflows/tests.yml/badge.svg" alt="Tests"/>
16
16
  </a>
17
17
  <a href="https://pypi.org/project/crudadmin/">
18
18
  <img src="https://img.shields.io/pypi/v/crudadmin?color=%2334D058&label=pypi%20package" alt="PyPi Version"/>
@@ -26,7 +26,7 @@
26
26
 
27
27
  **CRUDAdmin** is a robust admin interface generator for **FastAPI** applications, offering secure authentication, comprehensive event tracking, and essential monitoring features. Built with [FastCRUD](https://github.com/benavlabs/fastcrud) and HTMX, it helps you create production-ready admin panels with minimal configuration.
28
28
 
29
- **Documentation**: [https://igorbenav.github.io/crudadmin/](https://igorbenav.github.io/crudadmin/)
29
+ **Documentation**: [https://benavlabs.github.io/crudadmin/](https://benavlabs.github.io/crudadmin/)
30
30
 
31
31
  > [!WARNING]
32
32
  > CRUDAdmin is still experimental. While actively developed and tested, APIs may change between versions. Upgrade with caution in production environments, always carefuly reading the changelog.
@@ -40,6 +40,16 @@
40
40
  - **🔍 Advanced Filtering**: Type-aware field filtering, search, and pagination with bulk operations
41
41
  - **🌗 Modern UI**: Clean, responsive interface built with HTMX and [FastCRUD](https://github.com/benavlabs/fastcrud)
42
42
 
43
+ ## Video Preview
44
+
45
+ <p align="center">To see what CRUDAdmin dashboard actually looks like in practice, watch the video demo on youtube:</p>
46
+ <p align="center">
47
+ <a href="https://www.youtube.com/watch?v=THLdUbDQ9yM">
48
+ <img src="docs/assets/youtube-preview.png" alt="Watch CRUDAdmin Dashboard Demo on Youtube" width="75%" height="auto"/>
49
+ </a>
50
+ </p>
51
+ <br>
52
+
43
53
  ## Quick Start
44
54
 
45
55
  ### Installation
@@ -74,11 +84,15 @@ from .user import (
74
84
 
75
85
  # Database setup
76
86
  engine = create_async_engine("sqlite+aiosqlite:///app.db")
77
- session = AsyncSession(engine)
87
+
88
+ # Create database session dependency
89
+ async def get_session():
90
+ async with AsyncSession(engine) as session:
91
+ yield session
78
92
 
79
93
  # Create admin interface
80
94
  admin = CRUDAdmin(
81
- session=session,
95
+ session=get_session,
82
96
  SECRET_KEY="your-secret-key-here",
83
97
  initial_admin={
84
98
  "username": "admin",
@@ -121,12 +135,12 @@ Navigate to `/admin` to access your admin interface with:
121
135
 
122
136
  ### Development (Default)
123
137
  ```python
124
- admin = CRUDAdmin(session=session, SECRET_KEY="key") # Memory backend
138
+ admin = CRUDAdmin(session=get_session, SECRET_KEY="key") # Memory backend
125
139
  ```
126
140
 
127
141
  ### Production with Redis
128
142
  ```python
129
- admin = CRUDAdmin(session=session, SECRET_KEY="key").use_redis_sessions(
143
+ admin = CRUDAdmin(session=get_session, SECRET_KEY="key").use_redis_sessions(
130
144
  redis_url="redis://localhost:6379"
131
145
  )
132
146
  ```
@@ -134,7 +148,7 @@ admin = CRUDAdmin(session=session, SECRET_KEY="key").use_redis_sessions(
134
148
  ### Production with Security Features
135
149
  ```python
136
150
  admin = CRUDAdmin(
137
- session=session,
151
+ session=get_session,
138
152
  SECRET_KEY=SECRET_KEY,
139
153
  # Security features
140
154
  allowed_ips=["10.0.0.1"],
@@ -173,11 +187,16 @@ admin = CRUDAdmin(
173
187
 
174
188
  ## Documentation
175
189
 
176
- - **[Quick Start](https://igorbenav.github.io/crudadmin/quick-start/)**: Get up and running in 5 minutes
177
- - **[Usage Guide](https://igorbenav.github.io/crudadmin/usage/overview/)**: Complete usage documentation
178
- - **[API Reference](https://igorbenav.github.io/crudadmin/api/overview/)**: Full API documentation
179
- - **[Advanced Topics](https://igorbenav.github.io/crudadmin/advanced/overview/)**: Production features and configurations
190
+ - **[Quick Start](https://benavlabs.github.io/crudadmin/quick-start/)**: Get up and running in 5 minutes
191
+ - **[Usage Guide](https://benavlabs.github.io/crudadmin/usage/overview/)**: Complete usage documentation
192
+ - **[API Reference](https://benavlabs.github.io/crudadmin/api/overview/)**: Full API documentation
193
+ - **[Advanced Topics](https://benavlabs.github.io/crudadmin/advanced/overview/)**: Production features and configurations
180
194
 
181
195
  ## License
182
196
 
183
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
197
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
198
+
199
+ <hr>
200
+ <a href="https://benav.io">
201
+ <img src="docs/assets/benav_labs_banner.png" alt="Powered by Benav Labs - benav.io"/>
202
+ </a>
@@ -5,6 +5,7 @@ from collections.abc import Awaitable, Callable
5
5
  from datetime import UTC, datetime, timedelta
6
6
  from typing import (
7
7
  Any,
8
+ AsyncGenerator,
8
9
  Dict,
9
10
  List,
10
11
  Optional,
@@ -84,7 +85,7 @@ class CRUDAdmin:
84
85
  - Token-based authentication
85
86
 
86
87
  Args:
87
- session: Async SQLAlchemy session for database operations
88
+ session: Async SQLAlchemy session dependency function that yields sessions
88
89
  SECRET_KEY: Secret key for session management and cookie signing. Generate securely using:
89
90
  **Python one-liner (recommended)**
90
91
  python -c "import secrets; print(secrets.token_urlsafe(32))"
@@ -151,11 +152,15 @@ class CRUDAdmin:
151
152
 
152
153
  # Setup database
153
154
  engine = create_async_engine("sqlite+aiosqlite:///app.db")
154
- session = AsyncSession(engine)
155
+
156
+ # Create database session dependency
157
+ async def get_session():
158
+ async with AsyncSession(engine) as session:
159
+ yield session
155
160
 
156
161
  # Create admin interface
157
162
  admin = CRUDAdmin(
158
- session=session,
163
+ session=get_session,
159
164
  SECRET_KEY=SECRET_KEY,
160
165
  initial_admin={
161
166
  "username": "admin",
@@ -167,7 +172,7 @@ class CRUDAdmin:
167
172
  Production setup with security features:
168
173
  ```python
169
174
  admin = CRUDAdmin(
170
- session=session,
175
+ session=get_session,
171
176
  SECRET_KEY=SECRET_KEY,
172
177
  # Security features
173
178
  allowed_ips=["10.0.0.1", "10.0.0.2"],
@@ -187,7 +192,7 @@ class CRUDAdmin:
187
192
  Session management configuration:
188
193
  ```python
189
194
  admin = CRUDAdmin(
190
- session=session,
195
+ session=get_session,
191
196
  SECRET_KEY=SECRET_KEY,
192
197
  # Session management settings
193
198
  max_sessions_per_user=5,
@@ -269,7 +274,7 @@ class CRUDAdmin:
269
274
  Event tracking and audit logs:
270
275
  ```python
271
276
  admin = CRUDAdmin(
272
- session=session,
277
+ session=get_session,
273
278
  SECRET_KEY=SECRET_KEY,
274
279
  track_events=True, # Enable event tracking
275
280
  # Custom admin database for logs
@@ -286,7 +291,7 @@ class CRUDAdmin:
286
291
 
287
292
  def __init__(
288
293
  self,
289
- session: AsyncSession,
294
+ session: Callable[[], AsyncGenerator[AsyncSession, None]],
290
295
  SECRET_KEY: str,
291
296
  mount_path: Optional[str] = "/admin",
292
297
  theme: Optional[str] = "dark-theme",
@@ -446,7 +451,7 @@ class CRUDAdmin:
446
451
  Manual initialization:
447
452
  ```python
448
453
  admin = CRUDAdmin(
449
- session=async_session,
454
+ session=get_session,
450
455
  SECRET_KEY="key",
451
456
  setup_on_initialization=False
452
457
  )
@@ -789,8 +794,8 @@ class CRUDAdmin:
789
794
  model: Type[DeclarativeBase],
790
795
  create_schema: Type[BaseModel],
791
796
  update_schema: Type[BaseModel],
792
- update_internal_schema: Optional[Type[BaseModel]],
793
- delete_schema: Optional[Type[BaseModel]],
797
+ update_internal_schema: Optional[Type[BaseModel]] = None,
798
+ delete_schema: Optional[Type[BaseModel]] = None,
794
799
  include_in_models: bool = True,
795
800
  allowed_actions: Optional[set[str]] = None,
796
801
  password_transformer: Optional[Any] = None,
@@ -59,7 +59,7 @@ class DatabaseConfig:
59
59
  def __init__(
60
60
  self,
61
61
  base: Type[DeclarativeBase],
62
- session: AsyncSession,
62
+ session: Callable[[], AsyncGenerator[AsyncSession, None]],
63
63
  admin_db_url: Optional[str] = None,
64
64
  admin_db_path: Optional[str] = None,
65
65
  admin_user: Optional[Type[DeclarativeBase]] = None,
@@ -88,7 +88,7 @@ class DatabaseConfig:
88
88
  ] = None,
89
89
  ) -> None:
90
90
  self.base: Type[DeclarativeBase] = base
91
- self.session: AsyncSession = session
91
+ self.session: Callable[[], AsyncGenerator[AsyncSession, None]] = session
92
92
 
93
93
  if admin_db_url is None:
94
94
  if admin_db_path is None:
@@ -197,8 +197,8 @@ class DatabaseConfig:
197
197
  """Get a session for the admin database."""
198
198
  return self.admin_session
199
199
 
200
- def get_app_session(self) -> AsyncSession:
201
- """Get a session for the main application database."""
200
+ def get_app_session(self) -> Callable[[], AsyncGenerator[AsyncSession, None]]:
201
+ """Get a session dependency for the main application database."""
202
202
  return self.session
203
203
 
204
204
  def get_primary_key(self, model: Type[DeclarativeBase]) -> Optional[str]:
@@ -0,0 +1,153 @@
1
+ from datetime import UTC, datetime
2
+ from enum import Enum
3
+ from typing import Any, Optional
4
+ from uuid import uuid4
5
+
6
+ from pydantic import BaseModel, Field, field_validator
7
+
8
+ from ..core.schemas.timestamp import TimestampSchema
9
+
10
+
11
+ class DeviceType(str, Enum):
12
+ """Device type enumeration"""
13
+
14
+ MOBILE = "mobile"
15
+ TABLET = "tablet"
16
+ DESKTOP = "desktop"
17
+ UNKNOWN = "unknown"
18
+
19
+
20
+ class BaseSession(BaseModel):
21
+ """Common base fields for all session types."""
22
+
23
+ user_id: int = Field(
24
+ ..., description="The ID of the user associated with the session."
25
+ )
26
+
27
+ session_id: str = Field(
28
+ default_factory=lambda: str(uuid4()), description="Unique session identifier"
29
+ )
30
+ ip_address: str = Field(..., description="Client IP address")
31
+ user_agent: str = Field(..., description="Client user agent string")
32
+ device_info: dict[str, Any] = Field(
33
+ default_factory=dict, description="Additional device information"
34
+ )
35
+ is_active: bool = Field(default=True, description="Whether session is active")
36
+
37
+ @field_validator("ip_address")
38
+ @classmethod
39
+ def validate_ip_address(cls, ip: str) -> str:
40
+ """Validate IP address format."""
41
+ import ipaddress
42
+
43
+ try:
44
+ ipaddress.ip_address(ip)
45
+ except ValueError as err:
46
+ raise ValueError("Invalid IP Address format") from err
47
+ return ip
48
+
49
+
50
+ class SessionData(BaseSession):
51
+ """Common session data for any user session."""
52
+
53
+ metadata: dict[str, Any] = Field(
54
+ default_factory=dict, description="Additional session metadata"
55
+ )
56
+ created_at: datetime = Field(
57
+ default_factory=lambda: datetime.now(UTC),
58
+ description="Session creation timestamp",
59
+ )
60
+ last_activity: datetime = Field(
61
+ default_factory=lambda: datetime.now(UTC), description="Last activity timestamp"
62
+ )
63
+
64
+
65
+ class SessionCreate(SessionData):
66
+ """Schema for creating a new session."""
67
+
68
+ pass
69
+
70
+
71
+ class SessionUpdate(BaseModel):
72
+ """Schema for updating a session."""
73
+
74
+ last_activity: Optional[datetime] = None
75
+ is_active: Optional[bool] = None
76
+ metadata: Optional[dict[str, Any]] = None
77
+
78
+
79
+ class UserAgentInfo(BaseModel):
80
+ """User agent information parsed from the User-Agent header."""
81
+
82
+ browser: str = Field(..., description="Browser name")
83
+ browser_version: str = Field(..., description="Browser version")
84
+ os: str = Field(..., description="Operating System")
85
+ device: str
86
+ is_mobile: bool
87
+ is_tablet: bool
88
+ is_pc: bool
89
+
90
+
91
+ class CSRFToken(BaseModel):
92
+ """CSRF token data."""
93
+
94
+ token: str
95
+ user_id: int
96
+ session_id: str
97
+ created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
98
+ expires_at: datetime
99
+
100
+
101
+ class AdminSession(TimestampSchema, BaseSession):
102
+ """Full AdminSession schema with all fields."""
103
+
104
+ id: int
105
+ session_metadata: dict[str, Any] = Field(
106
+ default_factory=dict, description="admin specific session metadata"
107
+ )
108
+
109
+
110
+ class AdminSessionRead(BaseSession):
111
+ """Schema for reading AdminSession data."""
112
+
113
+ id: int
114
+ session_metadata: dict[str, Any]
115
+ created_at: datetime
116
+ last_activity: datetime
117
+ is_active: bool
118
+
119
+
120
+ class AdminSessionCreate(BaseSession):
121
+ """Schema for creating AdminSession in database."""
122
+
123
+ created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
124
+ last_activity: datetime = Field(default_factory=lambda: datetime.now(UTC))
125
+ session_metadata: dict[str, Any] = Field(default_factory=dict)
126
+
127
+
128
+ class AdminSessionUpdate(BaseModel):
129
+ """Schema for updating AdminSession."""
130
+
131
+ last_activity: Optional[datetime] = None
132
+ is_active: Optional[bool] = None
133
+ session_metadata: Optional[dict[str, Any]] = None
134
+
135
+
136
+ class AdminSessionUpdateInternal(AdminSessionUpdate):
137
+ """Internal schema for AdminSession updates."""
138
+
139
+ updated_at: Optional[datetime] = Field(default_factory=lambda: datetime.now(UTC))
140
+
141
+
142
+ __all__ = [
143
+ "SessionData",
144
+ "SessionCreate",
145
+ "SessionUpdate",
146
+ "UserAgentInfo",
147
+ "CSRFToken",
148
+ "AdminSession",
149
+ "AdminSessionRead",
150
+ "AdminSessionCreate",
151
+ "AdminSessionUpdate",
152
+ "AdminSessionUpdateInternal",
153
+ ]
@@ -1,9 +1,9 @@
1
1
  [project]
2
2
  name = "crudadmin"
3
- version = "0.3.0"
3
+ version = "0.3.2"
4
4
  description = "FastAPI-based admin interface with authentication, event logging and CRUD operations"
5
5
  readme = "README.md"
6
- requires-python = ">=3.9"
6
+ requires-python = ">=3.9.2"
7
7
  authors = [
8
8
  { name = "Igor Benav", email = "igor.magalhaes.r@gmail.com" }
9
9
  ]
@@ -30,7 +30,6 @@ classifiers = [
30
30
  dependencies = [
31
31
  "bcrypt>=4.2.1",
32
32
  "fastapi>=0.115.6",
33
- "fastcrud>=0.15.5",
34
33
  "jinja2>=3.1.5",
35
34
  "pydantic[email]>=2.10.4",
36
35
  "pydantic-settings>=2.6.1",
@@ -40,6 +39,7 @@ dependencies = [
40
39
  "user-agents>=2.2.0",
41
40
  "aiosqlite>=0.20.0",
42
41
  "greenlet>=3.1.1",
42
+ "fastcrud>=0.15.12",
43
43
  ]
44
44
 
45
45
  [tool.hatch.build.targets.sdist]
@@ -52,17 +52,12 @@ include = ["crudadmin/", "LICENSE"]
52
52
  requires = ["hatchling"]
53
53
  build-backend = "hatchling.build"
54
54
 
55
- [dependency-groups]
56
- dev = [
57
- "types-redis>=4.6.0.20241004",
58
- ]
59
-
60
55
  [project.urls]
61
- Homepage = "https://github.com/igorbenav/crudadmin"
62
- Documentation = "https://igorbenav.github.io/crudadmin"
63
- Repository = "https://github.com/igorbenav/crudadmin"
64
- Issues = "https://github.com/igorbenav/crudadmin/issues"
65
- Changelog = "https://github.com/igorbenav/crudadmin/releases"
56
+ Homepage = "https://github.com/benavlabs/crudadmin"
57
+ Documentation = "https://benavlabs.github.io/crudadmin"
58
+ Repository = "https://github.com/benavlabs/crudadmin"
59
+ Issues = "https://github.com/benavlabs/crudadmin/issues"
60
+ Changelog = "https://github.com/benavlabs/crudadmin/releases"
66
61
 
67
62
  [project.optional-dependencies]
68
63
  standard = [
@@ -113,6 +108,12 @@ test = [
113
108
  "redis>=6.2.0",
114
109
  ]
115
110
 
111
+ [dependency-groups]
112
+ dev = [
113
+ "crudadmin",
114
+ "crudadmin[standard,redis,memcached,postgres,mysql,dev]"
115
+ ]
116
+
116
117
  [tool.pytest.ini_options]
117
118
  minversion = "6.0"
118
119
  addopts = "-ra -q --strict-markers --strict-config"
@@ -1,128 +0,0 @@
1
- from datetime import UTC, datetime
2
- from typing import Any, Optional
3
- from uuid import uuid4
4
-
5
- from pydantic import BaseModel, Field
6
-
7
- from ..core.schemas.timestamp import TimestampSchema
8
-
9
-
10
- class SessionData(BaseModel):
11
- """Common base data for any user session."""
12
-
13
- user_id: int
14
- session_id: str = Field(default_factory=lambda: str(uuid4()))
15
- ip_address: str
16
- user_agent: str
17
- device_info: dict[str, Any] = Field(default_factory=dict)
18
- created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
19
- last_activity: datetime = Field(default_factory=lambda: datetime.now(UTC))
20
- is_active: bool = True
21
- metadata: dict[str, Any] = Field(default_factory=dict)
22
-
23
-
24
- class SessionCreate(SessionData):
25
- """Schema for creating a new session."""
26
-
27
- pass
28
-
29
-
30
- class SessionUpdate(BaseModel):
31
- """Schema for updating a session."""
32
-
33
- last_activity: Optional[datetime] = None
34
- is_active: Optional[bool] = None
35
- metadata: Optional[dict[str, Any]] = None
36
-
37
-
38
- class UserAgentInfo(BaseModel):
39
- """User agent information parsed from the User-Agent header."""
40
-
41
- browser: str
42
- browser_version: str
43
- os: str
44
- device: str
45
- is_mobile: bool
46
- is_tablet: bool
47
- is_pc: bool
48
-
49
-
50
- class CSRFToken(BaseModel):
51
- """CSRF token data."""
52
-
53
- token: str
54
- user_id: int
55
- session_id: str
56
- created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
57
- expires_at: datetime
58
-
59
-
60
- class AdminSessionBase(BaseModel):
61
- """Base schema for AdminSession."""
62
-
63
- user_id: int
64
- session_id: str
65
- ip_address: str
66
- user_agent: str
67
- device_info: dict[str, Any] = Field(default_factory=dict)
68
- session_metadata: dict[str, Any] = Field(default_factory=dict)
69
- is_active: bool = True
70
-
71
-
72
- class AdminSession(TimestampSchema, AdminSessionBase):
73
- """Full AdminSession schema with all fields."""
74
-
75
- id: int
76
- created_at: datetime
77
- last_activity: datetime
78
-
79
-
80
- class AdminSessionRead(BaseModel):
81
- """Schema for reading AdminSession data."""
82
-
83
- id: int
84
- user_id: int
85
- session_id: str
86
- ip_address: str
87
- user_agent: str
88
- device_info: dict[str, Any]
89
- session_metadata: dict[str, Any]
90
- created_at: datetime
91
- last_activity: datetime
92
- is_active: bool
93
-
94
-
95
- class AdminSessionCreate(AdminSessionBase):
96
- """Schema for creating AdminSession in database."""
97
-
98
- created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
99
- last_activity: datetime = Field(default_factory=lambda: datetime.now(UTC))
100
-
101
-
102
- class AdminSessionUpdate(BaseModel):
103
- """Schema for updating AdminSession."""
104
-
105
- last_activity: Optional[datetime] = None
106
- is_active: Optional[bool] = None
107
- session_metadata: Optional[dict[str, Any]] = None
108
-
109
-
110
- class AdminSessionUpdateInternal(AdminSessionUpdate):
111
- """Internal schema for AdminSession updates."""
112
-
113
- updated_at: Optional[datetime] = Field(default_factory=lambda: datetime.now(UTC))
114
-
115
-
116
- __all__ = [
117
- "SessionData",
118
- "SessionCreate",
119
- "SessionUpdate",
120
- "UserAgentInfo",
121
- "CSRFToken",
122
- "AdminSessionBase",
123
- "AdminSession",
124
- "AdminSessionRead",
125
- "AdminSessionCreate",
126
- "AdminSessionUpdate",
127
- "AdminSessionUpdateInternal",
128
- ]
File without changes
File without changes
File without changes