statezero 0.1.0b1__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 (45) hide show
  1. statezero/__init__.py +0 -0
  2. statezero/adaptors/__init__.py +0 -0
  3. statezero/adaptors/django/__init__.py +0 -0
  4. statezero/adaptors/django/apps.py +97 -0
  5. statezero/adaptors/django/config.py +99 -0
  6. statezero/adaptors/django/context_manager.py +12 -0
  7. statezero/adaptors/django/event_emitters.py +78 -0
  8. statezero/adaptors/django/exception_handler.py +98 -0
  9. statezero/adaptors/django/extensions/__init__.py +0 -0
  10. statezero/adaptors/django/extensions/custom_field_serializers/__init__.py +0 -0
  11. statezero/adaptors/django/extensions/custom_field_serializers/file_fields.py +141 -0
  12. statezero/adaptors/django/extensions/custom_field_serializers/money_field.py +75 -0
  13. statezero/adaptors/django/f_handler.py +312 -0
  14. statezero/adaptors/django/helpers.py +153 -0
  15. statezero/adaptors/django/middleware.py +10 -0
  16. statezero/adaptors/django/migrations/0001_initial.py +33 -0
  17. statezero/adaptors/django/migrations/0002_delete_modelviewsubscription.py +16 -0
  18. statezero/adaptors/django/migrations/__init__.py +0 -0
  19. statezero/adaptors/django/orm.py +915 -0
  20. statezero/adaptors/django/permissions.py +252 -0
  21. statezero/adaptors/django/query_optimizer.py +772 -0
  22. statezero/adaptors/django/schemas.py +324 -0
  23. statezero/adaptors/django/search_providers/__init__.py +0 -0
  24. statezero/adaptors/django/search_providers/basic_search.py +24 -0
  25. statezero/adaptors/django/search_providers/postgres_search.py +51 -0
  26. statezero/adaptors/django/serializers.py +554 -0
  27. statezero/adaptors/django/urls.py +14 -0
  28. statezero/adaptors/django/views.py +336 -0
  29. statezero/core/__init__.py +34 -0
  30. statezero/core/ast_parser.py +821 -0
  31. statezero/core/ast_validator.py +266 -0
  32. statezero/core/classes.py +167 -0
  33. statezero/core/config.py +263 -0
  34. statezero/core/context_storage.py +4 -0
  35. statezero/core/event_bus.py +175 -0
  36. statezero/core/event_emitters.py +60 -0
  37. statezero/core/exceptions.py +106 -0
  38. statezero/core/interfaces.py +492 -0
  39. statezero/core/process_request.py +184 -0
  40. statezero/core/types.py +63 -0
  41. statezero-0.1.0b1.dist-info/METADATA +252 -0
  42. statezero-0.1.0b1.dist-info/RECORD +45 -0
  43. statezero-0.1.0b1.dist-info/WHEEL +5 -0
  44. statezero-0.1.0b1.dist-info/licenses/license.md +117 -0
  45. statezero-0.1.0b1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,252 @@
1
+ import logging
2
+ from typing import Any, Set, Type
3
+
4
+ from django.contrib.auth import get_user_model
5
+ from django.conf import settings
6
+ from django.contrib.auth.models import AnonymousUser
7
+ from django.utils.module_loading import import_string
8
+ from rest_framework.permissions import AllowAny, BasePermission
9
+
10
+
11
+ from statezero.core.interfaces import AbstractPermission
12
+ from statezero.core.types import ActionType, ORMModel, RequestType
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ User = get_user_model()
17
+
18
+ class AllowAllPermission(AbstractPermission):
19
+ def filter_queryset(self, request: RequestType, queryset: Any) -> Any:
20
+ return queryset
21
+
22
+ def allowed_actions(self, request: RequestType, model: Type[ORMModel]) -> Set[ActionType]: # type: ignore
23
+ return {
24
+ ActionType.CREATE,
25
+ ActionType.DELETE,
26
+ ActionType.READ,
27
+ ActionType.UPDATE,
28
+ }
29
+
30
+ def allowed_object_actions(self, request, obj, model: Type[ORMModel]) -> Set[ActionType]: # type: ignore
31
+ return {
32
+ ActionType.CREATE,
33
+ ActionType.DELETE,
34
+ ActionType.READ,
35
+ ActionType.UPDATE,
36
+ }
37
+
38
+ def _get_user_fields(self) -> Set[str]:
39
+ return {"id", "username"}
40
+
41
+ def visible_fields(self, request: RequestType, model: Type) -> Set[str]:
42
+ if model is User:
43
+ return self._get_user_fields()
44
+ return "__all__"
45
+
46
+ def editable_fields(self, request: RequestType, model: Type) -> Set[str]:
47
+ if model is User:
48
+ return self._get_user_fields()
49
+ return "__all__"
50
+
51
+ def create_fields(self, request: RequestType, model: Type) -> Set[str]:
52
+ if model is User:
53
+ return self._get_user_fields()
54
+ return "__all__"
55
+
56
+ class IsAuthenticatedPermission(AbstractPermission):
57
+ """
58
+ Permission class that allows access only to authenticated users.
59
+ If the user is not authenticated, the queryset is emptied and no actions or fields are allowed.
60
+ """
61
+
62
+ def filter_queryset(self, request: RequestType, queryset: Any) -> Any:
63
+ if not request.user.is_authenticated:
64
+ return queryset.none()
65
+ return queryset
66
+
67
+ def allowed_actions(
68
+ self, request: RequestType, model: Type[ORMModel]
69
+ ) -> Set[ActionType]:
70
+ if not request.user.is_authenticated:
71
+ return set()
72
+ return {
73
+ ActionType.CREATE,
74
+ ActionType.DELETE,
75
+ ActionType.READ,
76
+ ActionType.UPDATE,
77
+ }
78
+
79
+ def allowed_object_actions(
80
+ self, request, obj, model: Type[ORMModel]
81
+ ) -> Set[ActionType]:
82
+ if not request.user.is_authenticated:
83
+ return set()
84
+ return {
85
+ ActionType.CREATE,
86
+ ActionType.DELETE,
87
+ ActionType.READ,
88
+ ActionType.UPDATE,
89
+ }
90
+
91
+ def _get_user_fields(self) -> Set[str]:
92
+ return {"id", "username"}
93
+
94
+ def visible_fields(self, request: RequestType, model: Type) -> Set[str]:
95
+ if not request.user.is_authenticated:
96
+ return set()
97
+ if model is User:
98
+ return self._get_user_fields()
99
+ return "__all__"
100
+
101
+ def editable_fields(self, request: RequestType, model: Type) -> Set[str]:
102
+ if not request.user.is_authenticated:
103
+ return set()
104
+ if model is User:
105
+ return self._get_user_fields()
106
+ return "__all__"
107
+
108
+ def create_fields(self, request: RequestType, model: Type) -> Set[str]:
109
+ if not request.user.is_authenticated:
110
+ return set()
111
+ if model is User:
112
+ return self._get_user_fields()
113
+ return "__all__"
114
+
115
+
116
+ class IsStaffPermission(AbstractPermission):
117
+ """
118
+ Permission class that allows access only to staff users.
119
+ The user must be both authenticated and marked as staff. Otherwise, access is denied.
120
+ """
121
+
122
+ def filter_queryset(self, request: RequestType, queryset: Any) -> Any:
123
+ if not (request.user.is_authenticated and request.user.is_staff):
124
+ return queryset.none()
125
+ return queryset
126
+
127
+ def allowed_actions(
128
+ self, request: RequestType, model: Type[ORMModel]
129
+ ) -> Set[ActionType]:
130
+ if not (request.user.is_authenticated and request.user.is_staff):
131
+ return set()
132
+ return {
133
+ ActionType.CREATE,
134
+ ActionType.DELETE,
135
+ ActionType.READ,
136
+ ActionType.UPDATE,
137
+ }
138
+
139
+ def allowed_object_actions(
140
+ self, request, obj, model: Type[ORMModel]
141
+ ) -> Set[ActionType]:
142
+ if not (request.user.is_authenticated and request.user.is_staff):
143
+ return set()
144
+ return {
145
+ ActionType.CREATE,
146
+ ActionType.DELETE,
147
+ ActionType.READ,
148
+ ActionType.UPDATE,
149
+ }
150
+
151
+ def _get_user_fields(self) -> Set[str]:
152
+ return {"id", "username", "email", "first_name", "last_name"}
153
+
154
+ def visible_fields(self, request: RequestType, model: Type) -> Set[str]:
155
+ if not (request.user.is_authenticated and request.user.is_staff):
156
+ return set()
157
+ if model is User:
158
+ return self._get_user_fields()
159
+ return "__all__"
160
+
161
+ def editable_fields(self, request: RequestType, model: Type) -> Set[str]:
162
+ if not (request.user.is_authenticated and request.user.is_staff):
163
+ return set()
164
+ if model is User:
165
+ return self._get_user_fields()
166
+ return "__all__"
167
+
168
+ def create_fields(self, request: RequestType, model: Type) -> Set[str]:
169
+ if not (request.user.is_authenticated and request.user.is_staff):
170
+ return set()
171
+ if model is User:
172
+ return self._get_user_fields()
173
+ return "__all__"
174
+
175
+
176
+ class ORMBridgeViewAccessGate(BasePermission):
177
+ """
178
+ Gate access only for ModelList and schema endpoints.
179
+ In local dev (DEBUG=True), optionally set a default user if provided.
180
+ If no default user is provided or an error occurs, set the user to AnonymousUser
181
+ and return has_permission = True.
182
+ In production, strictly use the configured permission class.
183
+ """
184
+
185
+ def __init__(self):
186
+ access_class_path = getattr(
187
+ settings,
188
+ "STATEZERO_VIEW_ACCESS_CLASS",
189
+ "rest_framework.permissions.AllowAny",
190
+ )
191
+ try:
192
+ self.view_access = import_string(access_class_path)()
193
+ logger.debug("Using view access class: %s", access_class_path)
194
+ except Exception as e:
195
+ logger.error(
196
+ "Error importing view access class '%s': %s", access_class_path, str(e)
197
+ )
198
+ self.view_access = AllowAny()
199
+
200
+ def has_permission(self, request, view):
201
+ logger.debug("Evaluating has_permission for path: %s", request.path)
202
+
203
+ # Only apply custom access for schema and model list endpoints.
204
+ if request.path.startswith("/statezero/"):
205
+ logger.debug("Path matches statezero endpoints. DEBUG=%s", settings.DEBUG)
206
+ if settings.DEBUG:
207
+ # In development mode, try to set a default user if one is provided.
208
+ default_user_func_path = getattr(
209
+ settings, "STATEZERO_DEFAULT_USER_FUNC", None
210
+ )
211
+ if default_user_func_path:
212
+ logger.debug(
213
+ "Default user function specified: %s", default_user_func_path
214
+ )
215
+ try:
216
+ default_user_func = import_string(default_user_func_path)
217
+ request.user = default_user_func(request)
218
+ logger.debug("Default user set to: %s", request.user)
219
+ except Exception as e:
220
+ logger.error(
221
+ "Error setting default user using '%s': %s",
222
+ default_user_func_path,
223
+ str(e),
224
+ )
225
+ request.user = AnonymousUser()
226
+ else:
227
+ logger.debug(
228
+ "No default user function specified; setting user to AnonymousUser"
229
+ )
230
+ request.user = AnonymousUser()
231
+ logger.debug(
232
+ "Returning True for DEBUG mode on endpoint: %s", request.path
233
+ )
234
+ return True
235
+ else:
236
+ # In production, strictly use the configured permission class.
237
+ logger.debug(
238
+ "Production mode: delegating permission check to %s",
239
+ self.view_access.__class__.__name__,
240
+ )
241
+ permission = self.view_access.has_permission(request, view)
242
+ logger.debug("Production mode permission result: %s", permission)
243
+ return permission
244
+
245
+ # For endpoints outside our gate's scope, delegate to the default permission logic.
246
+ logger.debug(
247
+ "Path does not match statezero endpoints; delegating permission check to %s",
248
+ self.view_access.__class__.__name__,
249
+ )
250
+ permission = self.view_access.has_permission(request, view)
251
+ logger.debug("Non-statezero endpoint permission result: %s", permission)
252
+ return permission