core-framework 0.12.5__tar.gz → 0.12.6__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 (128) hide show
  1. {core_framework-0.12.5 → core_framework-0.12.6}/PKG-INFO +1 -1
  2. {core_framework-0.12.5 → core_framework-0.12.6}/core/__init__.py +1 -1
  3. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/__init__.py +15 -0
  4. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/backends.py +5 -5
  5. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/decorators.py +7 -6
  6. core_framework-0.12.6/core/auth/helpers.py +104 -0
  7. {core_framework-0.12.5 → core_framework-0.12.6}/core/cli/main.py +6 -4
  8. {core_framework-0.12.5 → core_framework-0.12.6}/core/dependencies.py +3 -1
  9. {core_framework-0.12.5 → core_framework-0.12.6}/core/permissions.py +8 -6
  10. {core_framework-0.12.5 → core_framework-0.12.6}/core/tenancy.py +3 -2
  11. {core_framework-0.12.5 → core_framework-0.12.6}/pyproject.toml +1 -1
  12. {core_framework-0.12.5 → core_framework-0.12.6}/.gitignore +0 -0
  13. {core_framework-0.12.5 → core_framework-0.12.6}/README.md +0 -0
  14. {core_framework-0.12.5 → core_framework-0.12.6}/core/app.py +0 -0
  15. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/base.py +0 -0
  16. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/hashers.py +0 -0
  17. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/middleware.py +0 -0
  18. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/models.py +0 -0
  19. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/permissions.py +0 -0
  20. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/schemas.py +0 -0
  21. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/tokens.py +0 -0
  22. {core_framework-0.12.5 → core_framework-0.12.6}/core/auth/views.py +0 -0
  23. {core_framework-0.12.5 → core_framework-0.12.6}/core/choices.py +0 -0
  24. {core_framework-0.12.5 → core_framework-0.12.6}/core/cli/__init__.py +0 -0
  25. {core_framework-0.12.5 → core_framework-0.12.6}/core/config.py +0 -0
  26. {core_framework-0.12.5 → core_framework-0.12.6}/core/database.py +0 -0
  27. {core_framework-0.12.5 → core_framework-0.12.6}/core/datetime.py +0 -0
  28. {core_framework-0.12.5 → core_framework-0.12.6}/core/deployment/__init__.py +0 -0
  29. {core_framework-0.12.5 → core_framework-0.12.6}/core/deployment/docker.py +0 -0
  30. {core_framework-0.12.5 → core_framework-0.12.6}/core/deployment/kubernetes.py +0 -0
  31. {core_framework-0.12.5 → core_framework-0.12.6}/core/deployment/pm2.py +0 -0
  32. {core_framework-0.12.5 → core_framework-0.12.6}/core/exceptions.py +0 -0
  33. {core_framework-0.12.5 → core_framework-0.12.6}/core/fields.py +0 -0
  34. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/__init__.py +0 -0
  35. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/avro.py +0 -0
  36. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/base.py +0 -0
  37. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/config.py +0 -0
  38. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/confluent/__init__.py +0 -0
  39. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/confluent/consumer.py +0 -0
  40. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/confluent/producer.py +0 -0
  41. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/decorators.py +0 -0
  42. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/kafka/__init__.py +0 -0
  43. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/kafka/admin.py +0 -0
  44. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/kafka/broker.py +0 -0
  45. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/kafka/consumer.py +0 -0
  46. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/kafka/producer.py +0 -0
  47. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/rabbitmq/__init__.py +0 -0
  48. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/rabbitmq/broker.py +0 -0
  49. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/rabbitmq/consumer.py +0 -0
  50. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/rabbitmq/producer.py +0 -0
  51. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/redis/__init__.py +0 -0
  52. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/redis/broker.py +0 -0
  53. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/redis/consumer.py +0 -0
  54. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/redis/producer.py +0 -0
  55. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/registry.py +0 -0
  56. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/topics.py +0 -0
  57. {core_framework-0.12.5 → core_framework-0.12.6}/core/messaging/workers.py +0 -0
  58. {core_framework-0.12.5 → core_framework-0.12.6}/core/middleware.py +0 -0
  59. {core_framework-0.12.5 → core_framework-0.12.6}/core/migrations/__init__.py +0 -0
  60. {core_framework-0.12.5 → core_framework-0.12.6}/core/migrations/analyzer.py +0 -0
  61. {core_framework-0.12.5 → core_framework-0.12.6}/core/migrations/cli.py +0 -0
  62. {core_framework-0.12.5 → core_framework-0.12.6}/core/migrations/engine.py +0 -0
  63. {core_framework-0.12.5 → core_framework-0.12.6}/core/migrations/migration.py +0 -0
  64. {core_framework-0.12.5 → core_framework-0.12.6}/core/migrations/operations.py +0 -0
  65. {core_framework-0.12.5 → core_framework-0.12.6}/core/migrations/state.py +0 -0
  66. {core_framework-0.12.5 → core_framework-0.12.6}/core/models.py +0 -0
  67. {core_framework-0.12.5 → core_framework-0.12.6}/core/querysets.py +0 -0
  68. {core_framework-0.12.5 → core_framework-0.12.6}/core/relations.py +0 -0
  69. {core_framework-0.12.5 → core_framework-0.12.6}/core/routing.py +0 -0
  70. {core_framework-0.12.5 → core_framework-0.12.6}/core/serializers.py +0 -0
  71. {core_framework-0.12.5 → core_framework-0.12.6}/core/tasks/__init__.py +0 -0
  72. {core_framework-0.12.5 → core_framework-0.12.6}/core/tasks/base.py +0 -0
  73. {core_framework-0.12.5 → core_framework-0.12.6}/core/tasks/config.py +0 -0
  74. {core_framework-0.12.5 → core_framework-0.12.6}/core/tasks/decorators.py +0 -0
  75. {core_framework-0.12.5 → core_framework-0.12.6}/core/tasks/registry.py +0 -0
  76. {core_framework-0.12.5 → core_framework-0.12.6}/core/tasks/scheduler.py +0 -0
  77. {core_framework-0.12.5 → core_framework-0.12.6}/core/tasks/worker.py +0 -0
  78. {core_framework-0.12.5 → core_framework-0.12.6}/core/validators.py +0 -0
  79. {core_framework-0.12.5 → core_framework-0.12.6}/core/views.py +0 -0
  80. {core_framework-0.12.5 → core_framework-0.12.6}/docs/01-quickstart.md +0 -0
  81. {core_framework-0.12.5 → core_framework-0.12.6}/docs/02-viewsets.md +0 -0
  82. {core_framework-0.12.5 → core_framework-0.12.6}/docs/03-authentication.md +0 -0
  83. {core_framework-0.12.5 → core_framework-0.12.6}/docs/04-messaging.md +0 -0
  84. {core_framework-0.12.5 → core_framework-0.12.6}/docs/05-multi-service.md +0 -0
  85. {core_framework-0.12.5 → core_framework-0.12.6}/docs/06-tasks.md +0 -0
  86. {core_framework-0.12.5 → core_framework-0.12.6}/docs/07-deployment.md +0 -0
  87. {core_framework-0.12.5 → core_framework-0.12.6}/docs/08-complete-example.md +0 -0
  88. {core_framework-0.12.5 → core_framework-0.12.6}/docs/09-settings.md +0 -0
  89. {core_framework-0.12.5 → core_framework-0.12.6}/docs/10-migrations.md +0 -0
  90. {core_framework-0.12.5 → core_framework-0.12.6}/docs/11-permissions.md +0 -0
  91. {core_framework-0.12.5 → core_framework-0.12.6}/docs/12-auth-backends.md +0 -0
  92. {core_framework-0.12.5 → core_framework-0.12.6}/docs/13-validators.md +0 -0
  93. {core_framework-0.12.5 → core_framework-0.12.6}/docs/14-querysets.md +0 -0
  94. {core_framework-0.12.5 → core_framework-0.12.6}/docs/15-routing.md +0 -0
  95. {core_framework-0.12.5 → core_framework-0.12.6}/docs/16-serializers.md +0 -0
  96. {core_framework-0.12.5 → core_framework-0.12.6}/docs/17-datetime.md +0 -0
  97. {core_framework-0.12.5 → core_framework-0.12.6}/docs/18-dependencies.md +0 -0
  98. {core_framework-0.12.5 → core_framework-0.12.6}/docs/19-views.md +0 -0
  99. {core_framework-0.12.5 → core_framework-0.12.6}/docs/20-fields.md +0 -0
  100. {core_framework-0.12.5 → core_framework-0.12.6}/docs/21-tenancy.md +0 -0
  101. {core_framework-0.12.5 → core_framework-0.12.6}/docs/22-replicas.md +0 -0
  102. {core_framework-0.12.5 → core_framework-0.12.6}/docs/23-soft-delete.md +0 -0
  103. {core_framework-0.12.5 → core_framework-0.12.6}/docs/24-relations.md +0 -0
  104. {core_framework-0.12.5 → core_framework-0.12.6}/docs/25-exceptions.md +0 -0
  105. {core_framework-0.12.5 → core_framework-0.12.6}/docs/26-choices.md +0 -0
  106. {core_framework-0.12.5 → core_framework-0.12.6}/docs/27-workers.md +0 -0
  107. {core_framework-0.12.5 → core_framework-0.12.6}/docs/28-avro.md +0 -0
  108. {core_framework-0.12.5 → core_framework-0.12.6}/docs/29-topics.md +0 -0
  109. {core_framework-0.12.5 → core_framework-0.12.6}/docs/30-changelog-0.12.2.md +0 -0
  110. {core_framework-0.12.5 → core_framework-0.12.6}/docs/31-middleware.md +0 -0
  111. {core_framework-0.12.5 → core_framework-0.12.6}/docs/32-migration-guide-0.12.2.md +0 -0
  112. {core_framework-0.12.5 → core_framework-0.12.6}/docs/33-changelog-0.12.3.md +0 -0
  113. {core_framework-0.12.5 → core_framework-0.12.6}/docs/99-faq-troubleshooting.md +0 -0
  114. {core_framework-0.12.5 → core_framework-0.12.6}/docs/GUIDE.md +0 -0
  115. {core_framework-0.12.5 → core_framework-0.12.6}/docs/README.md +0 -0
  116. {core_framework-0.12.5 → core_framework-0.12.6}/example/__init__.py +0 -0
  117. {core_framework-0.12.5 → core_framework-0.12.6}/example/app.py +0 -0
  118. {core_framework-0.12.5 → core_framework-0.12.6}/example/auth.py +0 -0
  119. {core_framework-0.12.5 → core_framework-0.12.6}/example/models.py +0 -0
  120. {core_framework-0.12.5 → core_framework-0.12.6}/example/schemas.py +0 -0
  121. {core_framework-0.12.5 → core_framework-0.12.6}/example/views.py +0 -0
  122. {core_framework-0.12.5 → core_framework-0.12.6}/libs/__init__.py +0 -0
  123. {core_framework-0.12.5 → core_framework-0.12.6}/main.py +0 -0
  124. {core_framework-0.12.5 → core_framework-0.12.6}/tests/__init__.py +0 -0
  125. {core_framework-0.12.5 → core_framework-0.12.6}/tests/conftest.py +0 -0
  126. {core_framework-0.12.5 → core_framework-0.12.6}/tests/test_models.py +0 -0
  127. {core_framework-0.12.5 → core_framework-0.12.6}/tests/test_querysets.py +0 -0
  128. {core_framework-0.12.5 → core_framework-0.12.6}/tests/test_serializers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-framework
3
- Version: 0.12.5
3
+ Version: 0.12.6
4
4
  Summary: Core Framework - Django-inspired, FastAPI-powered. Alta performance, baixo acoplamento, produtividade extrema.
5
5
  Project-URL: Homepage, https://github.com/SorPuti/core-framework
6
6
  Project-URL: Documentation, https://github.com/SorPuti/core-framework#readme
@@ -278,7 +278,7 @@ from core.exceptions import (
278
278
  MissingDependency,
279
279
  )
280
280
 
281
- __version__ = "0.12.5"
281
+ __version__ = "0.12.6"
282
282
  __all__ = [
283
283
  # Models
284
284
  "Model",
@@ -121,9 +121,18 @@ from core.auth.views import (
121
121
  from core.auth.middleware import (
122
122
  AuthenticationMiddleware,
123
123
  OptionalAuthenticationMiddleware,
124
+ JWTAuthBackend,
125
+ AuthenticatedUser,
124
126
  ensure_auth_middleware,
125
127
  )
126
128
 
129
+ # Helper functions for consistent user access
130
+ from core.auth.helpers import (
131
+ get_request_user,
132
+ is_authenticated,
133
+ set_request_user,
134
+ )
135
+
127
136
  __all__ = [
128
137
  # Base
129
138
  "AuthBackend",
@@ -196,5 +205,11 @@ __all__ = [
196
205
  # Middleware
197
206
  "AuthenticationMiddleware",
198
207
  "OptionalAuthenticationMiddleware",
208
+ "JWTAuthBackend",
209
+ "AuthenticatedUser",
199
210
  "ensure_auth_middleware",
211
+ # Helpers
212
+ "get_request_user",
213
+ "is_authenticated",
214
+ "set_request_user",
200
215
  ]
@@ -161,14 +161,14 @@ class ModelBackend(AuthBackend):
161
161
 
162
162
  async def login(self, request: "Request", user: Any) -> None:
163
163
  """Executa ações pós-login."""
164
- # Armazena usuário no request.state
165
- request.state.user = user
164
+ # Armazena usuário no request.state (for backward compatibility)
165
+ from core.auth.helpers import set_request_user
166
+ set_request_user(request, user)
166
167
 
167
168
  async def logout(self, request: "Request", user: Any) -> None:
168
169
  """Executa ações de logout."""
169
- # Remove usuário do request.state
170
- if hasattr(request.state, "user"):
171
- request.state.user = None
170
+ from core.auth.helpers import set_request_user
171
+ set_request_user(request, None)
172
172
 
173
173
 
174
174
  class TokenAuthBackend(AuthBackend):
@@ -24,6 +24,7 @@ from typing import Any, TYPE_CHECKING
24
24
  from fastapi import Depends, HTTPException, Request, status
25
25
 
26
26
  from core.permissions import Permission as PermissionBase
27
+ from core.auth.helpers import get_request_user
27
28
 
28
29
  if TYPE_CHECKING:
29
30
  pass
@@ -70,7 +71,7 @@ class HasPermission(PermissionBase):
70
71
  request: Request,
71
72
  view: Any = None,
72
73
  ) -> bool:
73
- user = getattr(request.state, "user", None)
74
+ user = get_request_user(request)
74
75
 
75
76
  if user is None:
76
77
  return False
@@ -135,7 +136,7 @@ class IsInGroup(PermissionBase):
135
136
  request: Request,
136
137
  view: Any = None,
137
138
  ) -> bool:
138
- user = getattr(request.state, "user", None)
139
+ user = get_request_user(request)
139
140
 
140
141
  if user is None:
141
142
  return False
@@ -179,7 +180,7 @@ class IsSuperuser(PermissionBase):
179
180
  request: Request,
180
181
  view: Any = None,
181
182
  ) -> bool:
182
- user = getattr(request.state, "user", None)
183
+ user = get_request_user(request)
183
184
 
184
185
  if user is None:
185
186
  return False
@@ -207,7 +208,7 @@ class IsStaff(PermissionBase):
207
208
  request: Request,
208
209
  view: Any = None,
209
210
  ) -> bool:
210
- user = getattr(request.state, "user", None)
211
+ user = get_request_user(request)
211
212
 
212
213
  if user is None:
213
214
  return False
@@ -235,7 +236,7 @@ class IsActive(PermissionBase):
235
236
  request: Request,
236
237
  view: Any = None,
237
238
  ) -> bool:
238
- user = getattr(request.state, "user", None)
239
+ user = get_request_user(request)
239
240
 
240
241
  if user is None:
241
242
  return False
@@ -371,7 +372,7 @@ def login_required():
371
372
  ...
372
373
  """
373
374
  async def check(request: Request):
374
- user = getattr(request.state, "user", None)
375
+ user = get_request_user(request)
375
376
 
376
377
  if user is None:
377
378
  raise HTTPException(
@@ -0,0 +1,104 @@
1
+ """
2
+ Helper functions for authentication.
3
+
4
+ Provides consistent user access across the framework, supporting both:
5
+ - request.user (Starlette AuthenticationMiddleware pattern - preferred)
6
+ - request.state.user (legacy pattern - backward compatibility)
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import logging
12
+ from typing import Any, TYPE_CHECKING
13
+
14
+ if TYPE_CHECKING:
15
+ from starlette.requests import Request
16
+
17
+ logger = logging.getLogger("core.auth")
18
+
19
+
20
+ def get_request_user(request: "Request") -> Any | None:
21
+ """
22
+ Get authenticated user from request.
23
+
24
+ Checks both patterns for compatibility:
25
+ 1. request.user (Starlette AuthenticationMiddleware - preferred)
26
+ 2. request.state.user (legacy pattern)
27
+
28
+ Args:
29
+ request: The Starlette/FastAPI request object
30
+
31
+ Returns:
32
+ The authenticated user model or None if not authenticated
33
+
34
+ Example:
35
+ from core.auth.helpers import get_request_user
36
+
37
+ async def my_view(request: Request):
38
+ user = get_request_user(request)
39
+ if user is None:
40
+ raise HTTPException(401, "Not authenticated")
41
+ """
42
+ # Pattern 1: request.user (Starlette AuthenticationMiddleware)
43
+ user = getattr(request, "user", None)
44
+ if user is not None:
45
+ # Check if it's an authenticated user (has is_authenticated = True)
46
+ if getattr(user, "is_authenticated", False):
47
+ # If it's our AuthenticatedUser wrapper, return the underlying model
48
+ if hasattr(user, "_user"):
49
+ return user._user
50
+ return user
51
+
52
+ # Pattern 2: request.state.user (legacy)
53
+ user = getattr(request.state, "user", None) if hasattr(request, "state") else None
54
+
55
+ return user
56
+
57
+
58
+ def is_authenticated(request: "Request") -> bool:
59
+ """
60
+ Check if request has an authenticated user.
61
+
62
+ Args:
63
+ request: The Starlette/FastAPI request object
64
+
65
+ Returns:
66
+ True if authenticated, False otherwise
67
+ """
68
+ # Pattern 1: request.user with is_authenticated
69
+ user = getattr(request, "user", None)
70
+ if user is not None and getattr(user, "is_authenticated", False):
71
+ return True
72
+
73
+ # Pattern 2: request.state.user
74
+ if hasattr(request, "state"):
75
+ user = getattr(request.state, "user", None)
76
+ if user is not None:
77
+ return True
78
+
79
+ return False
80
+
81
+
82
+ def set_request_user(request: "Request", user: Any | None) -> None:
83
+ """
84
+ Set the authenticated user on the request.
85
+
86
+ Sets both patterns for maximum compatibility:
87
+ - request.state.user (for dependencies and legacy code)
88
+
89
+ Note: request.user is set by Starlette's AuthenticationMiddleware
90
+ via scope["user"] and cannot be set directly.
91
+
92
+ Args:
93
+ request: The Starlette/FastAPI request object
94
+ user: The user model or None
95
+ """
96
+ if hasattr(request, "state"):
97
+ request.state.user = user
98
+
99
+
100
+ __all__ = [
101
+ "get_request_user",
102
+ "is_authenticated",
103
+ "set_request_user",
104
+ ]
@@ -1039,9 +1039,10 @@ class AuthViewSet(ModelViewSet):
1039
1039
  Returns:
1040
1040
  Current user data
1041
1041
  """
1042
- # User is available via request.state.user (populated by auth middleware)
1042
+ # User is available via request.user (Starlette pattern) or request.state.user (legacy)
1043
1043
  # permission_classes=[IsAuthenticated] ensures user is authenticated
1044
- user = request.state.user
1044
+ from core.auth.helpers import get_request_user
1045
+ user = get_request_user(request)
1045
1046
 
1046
1047
  if user is None:
1047
1048
  raise HTTPException(status_code=401, detail="Authentication required")
@@ -1065,9 +1066,10 @@ class AuthViewSet(ModelViewSet):
1065
1066
  body = await request.json()
1066
1067
  data = ChangePasswordInput.model_validate(body)
1067
1068
 
1068
- # User is available via request.state.user (populated by auth middleware)
1069
+ # User is available via request.user (Starlette pattern) or request.state.user (legacy)
1069
1070
  # permission_classes=[IsAuthenticated] ensures user is authenticated
1070
- user = request.state.user
1071
+ from core.auth.helpers import get_request_user
1072
+ user = get_request_user(request)
1071
1073
 
1072
1074
  if user is None:
1073
1075
  raise HTTPException(status_code=401, detail="Authentication required")
@@ -395,12 +395,14 @@ async def get_request_context(request: Request) -> dict[str, Any]:
395
395
 
396
396
  Útil para logging e auditoria.
397
397
  """
398
+ from core.auth.helpers import get_request_user
399
+
398
400
  return {
399
401
  "method": request.method,
400
402
  "url": str(request.url),
401
403
  "client_ip": request.client.host if request.client else None,
402
404
  "user_agent": request.headers.get("user-agent"),
403
- "user": getattr(request.state, "user", None),
405
+ "user": get_request_user(request),
404
406
  }
405
407
 
406
408
 
@@ -15,6 +15,8 @@ from typing import Any, TYPE_CHECKING
15
15
 
16
16
  from fastapi import HTTPException, Request, status
17
17
 
18
+ from core.auth.helpers import get_request_user
19
+
18
20
  if TYPE_CHECKING:
19
21
  from core.views import APIView
20
22
 
@@ -32,7 +34,7 @@ class Permission(ABC):
32
34
  request: Request,
33
35
  view: APIView | None = None,
34
36
  ) -> bool:
35
- user = getattr(request.state, "user", None)
37
+ user = get_request_user(request)
36
38
  return user is not None and user.is_admin
37
39
  """
38
40
 
@@ -214,7 +216,7 @@ class IsAuthenticated(Permission):
214
216
  request: Request,
215
217
  view: "APIView | None" = None,
216
218
  ) -> bool:
217
- user = getattr(request.state, "user", None)
219
+ user = get_request_user(request)
218
220
  return user is not None
219
221
 
220
222
 
@@ -236,7 +238,7 @@ class IsAuthenticatedOrReadOnly(Permission):
236
238
  if request.method in self.SAFE_METHODS:
237
239
  return True
238
240
 
239
- user = getattr(request.state, "user", None)
241
+ user = get_request_user(request)
240
242
  return user is not None
241
243
 
242
244
 
@@ -250,7 +252,7 @@ class IsAdmin(Permission):
250
252
  request: Request,
251
253
  view: "APIView | None" = None,
252
254
  ) -> bool:
253
- user = getattr(request.state, "user", None)
255
+ user = get_request_user(request)
254
256
  if user is None:
255
257
  return False
256
258
 
@@ -285,7 +287,7 @@ class IsOwner(Permission):
285
287
  if obj is None:
286
288
  return True
287
289
 
288
- user = getattr(request.state, "user", None)
290
+ user = get_request_user(request)
289
291
  if user is None:
290
292
  return False
291
293
 
@@ -318,7 +320,7 @@ class HasRole(Permission):
318
320
  request: Request,
319
321
  view: "APIView | None" = None,
320
322
  ) -> bool:
321
- user = getattr(request.state, "user", None)
323
+ user = get_request_user(request)
322
324
  if user is None:
323
325
  return False
324
326
 
@@ -231,8 +231,9 @@ async def extract_tenant_from_request(
231
231
 
232
232
  Checks user, header, and query param in order.
233
233
  """
234
- # tenant_id = await extract_tenant_from_request(request)
235
- user = getattr(request.state, "user", None)
234
+ from core.auth.helpers import get_request_user
235
+
236
+ user = get_request_user(request)
236
237
  if user is not None:
237
238
  tenant_id = getattr(user, user_tenant_attr, None)
238
239
  if tenant_id is not None:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "core-framework"
3
- version = "0.12.5"
3
+ version = "0.12.6"
4
4
  description = "Core Framework - Django-inspired, FastAPI-powered. Alta performance, baixo acoplamento, produtividade extrema."
5
5
  requires-python = ">=3.10,<4.0"
6
6
  readme = "README.md"
File without changes